Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
# drive-plugin-chunks-inline-sig
## Why
DTP-25 (carved out of `drive-template-v1`) requires that
`FileLocation.storageHints` entries with `kind: 'inline'` carry an
Ed25519 signature over `fileId ‖ bytes`. Without the sig, an attacker
who can write to drive storage (or who can MITM a peer-to-peer drive
hand-off) could replace the inline body of a small file with arbitrary
bytes; the read-side has no other mechanism to detect tamper because
inline files do not flow through the chunk-by-chunk
sign / verify pipeline.
The change ships the surface in `@suaveplan/drive-plugin-chunks` so
the chunks plugin owns both flows for small files (chunked path and
inline path). Backward compatibility ships in the same change: legacy
inline hints (no `sig` field) read with a `drive:inline:legacy`
warning and rewrite-with-sig on the next write.
## What Changes
- Add `INLINE_SIG_INVALID` to `CHUNKS_CODES` in
`packages/drive/drive-plugin-chunks/src/error-codes.ts`.
- Add `src/inline/` module: `inline-hint.ts` + `inline-hint.md` +
`index.ts` exporting `InlineHint`, `LegacyInlineHint`,
`AnyInlineHint`, `StorageHint`, `FileLocation`, `signInlineHint`,
`verifyInlineHint`, `isLegacyInlineHint`,
`upgradeLegacyInlineHint`, `inlineSigningInput`, `VerifyEd25519Fn`.
- Wire the new surface into `src/index.ts`.
- Add `tests/inline-file-sig.test.ts` covering the three required
spec test names plus tamper, fileId-replay, key-mismatch,
signing-input canonicalisation, and the catch-arm-via-injectable-
verifier paths.
- Update `error-codes.md` to mention the twelfth code.
- The `verifyInlineHint` verifier is injectable (defaults to
`@noble/curves` Ed25519) so the catch arm — wrapping a throwing
native verifier — is testable without `istanbul ignore`
annotations.
## Impact
- Public API addition — no existing consumers depend on inline-hint
surface yet (drive-template / drive consumers will adopt this in a
follow-up wiring change once they begin emitting `FileLocation`).
- Wire format: legacy inline hints (`{ kind, bytes }`) remain readable
and are rewritten with sig on next write, so on-disk drives are
forward-compat.
- Error registry grows from eleven to twelve codes.
- 100% coverage gate maintained (74 tests, all passing); docs
coverage 17/17.

View File

@@ -0,0 +1,57 @@
# drive-plugin-chunks spec delta — DTP-25 (inline-sig)
## ADDED Requirements
### Requirement: Inline hint signed over fileId ‖ bytes
`FileLocation.storageHints` entries with `kind: 'inline'` SHALL be
`{ kind: 'inline'; bytes: Uint8Array; sig: Uint8Array }` where
`sig = Ed25519-sign(driveSecretKey, fileId ‖ bytes)`. The drive
SHALL verify the signature before returning `bytes`; failure SHALL
throw `CHUNKS.INLINE_SIG_INVALID`.
The verifier SHALL be Ed25519 over the canonical concatenation
exposed by `inlineSigningInput(fileId, bytes)`. A tampered signature,
tampered bytes, replay onto a different `fileId`, or signature
produced under a different key SHALL all reject with
`CHUNKS.INLINE_SIG_INVALID`.
The `verifyInlineHint` function SHALL accept an optional
`VerifyEd25519Fn` parameter so engine-substitution scenarios where a
native verifier throws (rather than returning false) compose cleanly.
When the injected verifier throws, the implementation SHALL wrap the
exception as `CHUNKS.INLINE_SIG_INVALID` with the original error
attached as `cause`.
**Verified by:** `tests/inline-file-sig.test.ts`::"inline file with
valid sig reads successfully" AND "inline file with bad sig throws
INLINE_SIG_INVALID" AND "sig bound to fileId — replay onto a
different fileId rejects" AND "byte tamper rejects with
INLINE_SIG_INVALID" AND "rejects under a different public key" AND
"verify catch arm wraps a throwing verifier".
### Requirement: Legacy inline hints accepted with rewrite-on-write
Drives reading old-format inline entries (no `sig` field) SHALL
accept them via the `LegacyInlineHint` shape and SHALL emit a
`drive:inline:legacy` warning event. `isLegacyInlineHint(hint)` SHALL
discriminate the two wire shapes (legacy vs signed). On the next
write that touches such a hint, `upgradeLegacyInlineHint(legacy,
fileId, driveSecretKey)` SHALL produce a signed `InlineHint` so the
upgrade lands at-rest and subsequent reads no longer trigger the
legacy warning.
**Verified by:** `tests/inline-file-sig.test.ts`::"old-format inline
reads with warning AND rewrites with sig on next write" AND
"isLegacyInlineHint distinguishes signed from legacy hints".
### Requirement: Canonical signing input exposed
`inlineSigningInput(fileId: Uint8Array, bytes: Uint8Array)` SHALL
return `concat(fileId, bytes)` as a freshly-allocated `Uint8Array`.
Any consumer that wants to re-derive the bytes that are signed (for
auditing, alternate-keypath signing, or cross-checking against a
hardware signer) SHALL use this function.
**Verified by:** `tests/inline-file-sig.test.ts`::"inlineSigningInput
is the canonical fileId ‖ bytes concatenation".

View File

@@ -0,0 +1,38 @@
# tasks — drive-plugin-chunks-inline-sig
## 1. Error registry
- [x] 1.1 Add `INLINE_SIG_INVALID` to `CHUNKS_CODES`.
- [x] 1.2 Update `error-codes.md` (count + DTP-25 rationale).
## 2. Inline-hint module
- [x] 2.1 Create `src/inline/inline-hint.ts` with `InlineHint`,
`LegacyInlineHint`, `AnyInlineHint`, `StorageHint`, `FileLocation`,
`inlineSigningInput`, `signInlineHint`, `verifyInlineHint`
(injectable verifier), `isLegacyInlineHint`,
`upgradeLegacyInlineHint`.
- [x] 2.2 Create `src/inline/inline-hint.md` (≥200-word doc with all
six required sections).
- [x] 2.3 Create `src/inline/index.ts` barrel.
- [x] 2.4 Wire exports through `src/index.ts`.
## 3. Tests
- [x] 3.1 Required: `inline file with valid sig reads successfully`.
- [x] 3.2 Required: `inline file with bad sig throws INLINE_SIG_INVALID`.
- [x] 3.3 Required: `old-format inline reads with warning AND
rewrites with sig on next write`.
- [x] 3.4 fileId-replay rejection.
- [x] 3.5 byte-tamper rejection.
- [x] 3.6 wrong-public-key rejection.
- [x] 3.7 signing-input canonicalisation property.
- [x] 3.8 catch-arm via injectable throwing verifier.
- [x] 3.9 `isLegacyInlineHint` discrimination including
`sig: undefined` ambiguous case.
## 4. Gates
- [x] 4.1 `bunx turbo lint typecheck test --filter=@suaveplan/drive-plugin-chunks` green.
- [x] 4.2 `bunx turbo test:coverage --filter=@suaveplan/drive-plugin-chunks` at 100/100/100/100.
- [x] 4.3 `bun run docs:check` reports 17/17 files.