Record parseSlots exemption and fix stale package doc comments
Documents why parseSlots skips repeat-key rejection, corrects two drifted doc lines (naming-rule count, Malformed-after-header header validity), and records two forward obligations for import_plan in CLAUDE.md.
This commit is contained in:
@@ -25,9 +25,10 @@ landing after the format.
|
||||
header (so the refusal can name the writer's semver and version) and nothing
|
||||
else — no manifest, no layout, no half-success. The fields through the writer
|
||||
semver are FROZEN for all future versions to keep that refusal producible.
|
||||
- **Every name and path in the format is validated on encode AND decode**,
|
||||
because a package can arrive from anywhere. Three rules, all in
|
||||
`package_format`, whose doc comments are the itemized authority:
|
||||
- **Every name and path in the format is validated on encode AND decode, to
|
||||
the extent stated below**, because a package can arrive from anywhere.
|
||||
Three rules, all in `package_format`, whose doc comments are the itemized
|
||||
authority:
|
||||
- `isValidEntryName` — a payload's name is a bare file name (no separators,
|
||||
no `..` component, no drive/UNC/rooted form, no control bytes, no
|
||||
Windows-reserved character, no trailing dot/space, no DOS device name,
|
||||
@@ -40,7 +41,13 @@ landing after the format.
|
||||
design, and is the one field here that can express one. It refuses a `..`
|
||||
component and every absolute form; `BankModel::add` checks only the latter,
|
||||
so traversal would otherwise reach a future `import_plan` inside a record
|
||||
the format vouched for.
|
||||
the format vouched for. **Scope is traversal and absolute-form only** — no
|
||||
UTF-8 well-formedness check (unlike `isValidEntryName`), no device-name
|
||||
check, no case-fold dedup on `relativePath` (unlike `sameEntryName` on the
|
||||
entry name). Correct for what this field is — a *record* field, not a
|
||||
filesystem destination; `BankModel::add` owns the rest. Forward contract
|
||||
for `import_plan`: **the destination file is derived from the entry name,
|
||||
never from `relativePath`.**
|
||||
- **Framing only, never a payload.** `bank_package` produces header bytes and
|
||||
an ordered `{name, offset, length}` layout; it never holds, copies, or hashes
|
||||
an entry's audio. `decodePackage` proves prefix + payload lengths equal the
|
||||
@@ -126,6 +133,15 @@ landing after the format.
|
||||
collision class as the ASCII case fold, which `sameEntryName` does catch. A
|
||||
table-free fix does not exist, and restricting names to ASCII would be
|
||||
genuinely over-strict for non-English users. Left open knowingly.
|
||||
- **`duplicateName` is O(n²) over `entries` on the decode path** — pre-existing
|
||||
shape (the double loop is unchanged since `af35fc5`; only the comparator
|
||||
changed). Under the `kMaxManifestBytes` cap (64 MB) a minimal entry is
|
||||
~100 bytes, so a hostile package can declare ~670k entries — ~2×10¹¹ pair
|
||||
comparisons, a multi-minute hang on import. It signals an error rather than
|
||||
UB, so the hostile-input invariant above still holds, but it sits against
|
||||
this module's "a forged header cannot demand gigabytes" posture. Forward
|
||||
obligation for `import_plan`: fold this into a sorted vector or hash set
|
||||
when that track lands; not changed here.
|
||||
- **Cross-module contract with `src/shell/package`:** a genuinely zero-length
|
||||
entry cannot round-trip through the filesystem seam there (`appendPayload`
|
||||
refuses an empty payload — an empty buffer signals an upstream read failure,
|
||||
|
||||
Reference in New Issue
Block a user