Files
rclone/docs/plans/001-protondrive-tier1-workspace/final-fix-brief.md
T
2026-11-12 15:12:51 +01:00

6.0 KiB

Final fix wave — brief (controller rulings)

Findings files (read the cited entries in full; file:line refers to HEAD 29ad26944):

  • final-review-crypto.md (C1, C2, I1, I2, I3)
  • final-review-transfer.md (I-1, I-2)
  • final-review-auth.md (I-1, I-2)
  • final-review-tests.md (I-1, I-2 only; I-3..I-5 are the controller's) All in /home/user/rclone/.superpowers/sdd/001-protondrive-tier1/.

Work order: Critical first, one commit per finding (or tightly related group), each with a regression test written first and seen failing (the reviewers' reproductions are described in the files; reuse them). Commit prefix protondrive: (CI: ci: is fine), messages user-readable per AGENTS.md.

Rulings

crypto C1 — unsigned/invalid content key packet signature. Verify ContentKeyPacketSignature (as the SDK defines it; check the reference checkout ~/.cache/protondrive-sdk-ref read-only) on every use of a file's content key: reads (full and ranged) and Update. A missing or invalid signature makes the file unverified, exactly like an unverified node key (ruling 18/22): reads and writes refused unless ignore_signature_errors; with the flag, proceed and log an ERROR once per node and operation. Integrity checks are never disabled. This is stricter than the SDK; record it in docs/DECISIONS.md and as handoff ruling 29.

crypto C2 — Argon2 parameters from the server. Before running any S2K/KDF on key material that came from the server or another user (node keys, share keys, anything not the account's own locally verified keys), check the S2K parameters against fixed caps and refuse (integrity error, not overridable by the flag) above them. Choose the caps from what Proton's clients actually generate (gopenpgp v3 and go-crypto defaults; the SDK) with modest headroom, and document them. Also bound iterated-salted S2K counts if the library does not. Add a fuzz/unit test.

crypto I1 — unverified hash key used for writes. A hash key whose signature is missing/invalid makes the folder unverified for writes (same as ruling 18: creating, uploading, renaming, moving into it refused without the flag; ERROR with the flag).

crypto I2 — rename/move reusing a name session key whose signature failed. Never reuse a session key from a name that did not verify; generate a fresh one (if the name verified, keep current behaviour).

crypto I3 — unsigned xattrs trusted. Follow spec 6.4: xattrs whose signature is missing/invalid are not used for modtime/size/SHA1 unless ignore_signature_errors (then used with an ERROR once per node). Without them, fall back as the code already does when xattrs are absent (check what that fallback is and that rclone behaves sanely, e.g. ModTime from the revision create time, no SHA1). Do not make the file unreadable just for this.

transfer I-1 — draft_client_uid not persisted for env/connection-string remotes. When the value cannot be persisted (or no value exists), derive a stable one deterministically instead of random per run, e.g. from the account's user ID and the remote name through a hash, so the same remote on the same account gets the same UID across runs; keep saving it when the config can store it. No package state.

transfer I-2 — quadratic multi-thread reads of files without recorded block sizes. Find a fix that keeps returned bytes always correct and every block verified. Preferred: compute each block's plaintext size from the block list without downloading, if and only if it can be done exactly for the packet formats involved (verify against the golden fixtures and the fake's shapes; if compression or variable framing makes it inexact, do not use it). Otherwise a bounded per-Fs cache (not package state) of plaintext block sizes learned per revision as blocks are decrypted, so later chunks seek directly. Measure with a test counting block fetches for an N-chunk multi-thread read. Update the docs page and TODO.

auth I-1 — error-code mapping. Map Proton's bad-app-version codes (5003, 5001; confirm in the SDK reference) to the fatal "upgrade rclone" error. Code 2000 becomes a plain fserrors.NoRetryError keeping Proton's message (not fatal). Code 2028: treat as Proton's documented meaning (check the SDK); if it can mean rate limiting, make it retryable via the pacer, not fatal. Update spec section 6.6 note via a DECISIONS entry and handoff ruling 30. Tests for each code.

auth I-2 — x-pm-drive-requirements. Log those response headers at debug level when present, as spec 6.6 says (once per value change, not per request).

tests I-1 — CI race timeout. Add -timeout 45m (or fitting the job timeout) to the CI go test -race step; consider -p/-parallel limits for the slow runner.

tests I-2 — CI Go version / govulncheck. Pin Go to the 1.27 line the code was verified with (go-version: '1.27.x' or exact 1.27.4) instead of go.mod's minimum, and pin govulncheck to a fixed version instead of @latest.

Minors from all four files: fix the ones that are cheap and local to code you are already touching; list every other Minor in docs/TODO.md under a single "final review minors (2026-11-12)" heading with file references, so nothing is lost.

Rules

Read implementer-common.md (its rule about the old protondrive.go is obsolete) and global-constraints.md first. RCLONE_CONFIG=/notfound on every go test; never contact Proton; never read ~/.config/rclone/rclone.conf or ~/proton_*password; never pass -remote/-capture-remote. No dependency changes. Do not edit docs/plans/001-protondrive-tier1-HANDOFF.md, docs/plans/001-protondrive-tier1-workspace/, or docs/specs/001-protondrive-tier1.md section 13 (the controller edits those in parallel); you may append rulings text to the controller via your report instead. Done = go build ./..., go vet ./backend/protondrive/..., golangci-lint run ./backend/protondrive/... (0 issues), full race suite once at the end, TestGoldenFixtures passing. No sudo, no force-push, no git reset --hard, no git clean, no recursive rm, never push, never switch branches. End commits with: Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com