v3.29.2: the strict row rule for the outfile import
The format is positional: an empty value drops its token, so the parser now requires every data row to have exactly the header's column count. That catches an empty value anywhere - including a middle one, which would otherwise shift the following columns (a missing ADM made the KIC columns read the KIK values: valid hex, wrong preset) - and a KICn/KIDn pair declared in the header must carry a usable hex value in every row (a placeholder fails). A violation makes the whole file invalid: the report's error names the line, no presets are returned, and an import (mode) answers 400 - it is never partially imported. The PWA disables the Import button while the report carries an error and guards the call. Unchanged per-row reports: a non-hex PIN/PUK/ADM/PSK value (dropped, the card kept), an unsupported key size (that keyset skipped), a card whose remaining keysets are unusable (skipped). All three real samples satisfy the rule exactly (11/11, 18/18, 18/18). Docs: help EN/RU, api.md, the repo AGENTS. Tests: the short/long row and the placeholder-keyset file errors, the valid-file round trip, the endpoint's refusal (nothing stored), the PWA's disabled button. 926 frontend + 945 Python; sw cache simple-v449.
This commit is contained in:
@@ -966,6 +966,19 @@ class PresetStoreHttpTests(unittest.TestCase):
|
||||
'text': text, 'tars': [{'tar': '000000', 'msl': '16', 'keyset': 99}]})
|
||||
self.assertEqual(status, 400, resp)
|
||||
self.assertIn('keyset', resp['error'])
|
||||
# an invalid file (a row with a missing value, v3.29.2): the preview
|
||||
# shows the error, the import refuses it - never a partial import
|
||||
bad = ('ICCID KIC1 KID1\n' + '8970119000004600098F 00112233445566778899AABBCCDDEEFF\n')
|
||||
status, resp = self._post('/api/presets/import-outfile', {'text': bad})
|
||||
self.assertEqual(status, 200, resp)
|
||||
self.assertEqual(resp['presets'], [])
|
||||
self.assertIn('the header declares 3 columns', resp['report']['error'])
|
||||
before = len(self.store.list())
|
||||
status, resp = self._post('/api/presets/import-outfile', {
|
||||
'text': bad, 'mode': 'merge'})
|
||||
self.assertEqual(status, 400, resp)
|
||||
self.assertIn('the file is invalid', resp['error'])
|
||||
self.assertEqual(len(self.store.list()), before)
|
||||
# a non-list TAR table is the caller's error, never a silent fallback
|
||||
status, resp = self._post('/api/presets/import-outfile', {
|
||||
'text': text, 'tars': 'nope'})
|
||||
|
||||
Reference in New Issue
Block a user