Repository navigation
feat(spec,driver-turso)!: retire turso config.encryptionKey, which never encrypted anything - #25153
Conversation
Claude-Session: https://claude.ai/code/session_01B2EeooonSXrANpkpgUSfFZ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EeooonSXrANpkpgUSfFZ Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EeooonSXrANpkpgUSfFZ Co-authored-by: Claude <noreply@anthropic.com>
…ption, runtime pin re-homed Claude-Session: https://claude.ai/code/session_01B2EeooonSXrANpkpgUSfFZ Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 3 package(s): 7 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 8 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 147 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7be84dfaf4d46e640076cb1664d9ad732d35a574 && git checkout 7be84dfaf4d46e640076cb1664d9ad732d35a574
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 37ccd5f2cf1daf02d16772e10182698da0bbeb4d a15132cc4c85f93cd298cf9b1daba5bf95cdb092 && git checkout -B drift-repro 37ccd5f2cf1daf02d16772e10182698da0bbeb4d && git merge --no-ff a15132cc4c85f93cd298cf9b1daba5bf95cdb092
node scripts/docs-audit/affected-docs.mjs --json 37ccd5f2cf1daf02d16772e10182698da0bbeb4d
|
Contract reviewServed-tier: Inputs: card #25050 (body, the triage unlock 6313284617, the claim 6328120971, the dev report 6330083449), PR #25153 (body, 55-file list, the net diff against ① Derived judgmentsEvery accept-set and public-surface change the diff implies, named right or wrong:
Check-runs on ② Semver level
③ Boundary flagsDev report 6330083449:
Card and rulings: Route A (triage's 6313284617 reads it as an 18.x retirement with no staged window; the claim fixed Route A) is carried out item by item — tombstone, Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对ACCEPT ·
Generated by Claude Code |
Requested by Bill · project thread
Fixes #25050
Clause-②: no (narrowing)
Metadata-protocol: narrowed
What changes
BREAKING. Turso
config.encryptionKeyis removed (Route A, retire the key, ADR-0049 enforce-or-remove). It never encrypted anything, in any mode:After #25020 the key still parsed on a remote datasource, did nothing there, and was the last credential-shaped key a datasource could write in plain text.
@objectstack/specTursoConfigSchema.encryptionKeyretiredKey()tombstone: atscerror, and a parse error atconfig.encryptionKeyin every mode with any value (''included), carrying the prescription. It is the only issue reported on that config.encryption_key/encryptionkeyget the same prescription@objectstack/driver-tursomirrorTursoConfigSchemaz.never()with the same prescription text, byte for bytenew TursoDriver()/createTursoDriver()TursoDriverConfig.encryptionKey?: never. A defined value is refused withVALIDATION_ERROR/ 400 as the constructor's first check, in every mode@objectstack/service-datasourceTursoDriverConfigInput.encryptionKeystringnever. The shared loader still forwards a declared value, so a legacy stored row reaches the constructor's refusal and does not boot in silencedatasource-credential-redaction.ts)STILL_WRITABLE_CREDENTIAL_KEYS = { turso: ['encryptionKey'] }RETIRED_CREDENTIAL_KEYS, same content: a stored legacy value is still withheld on read and named inredactedConfigKeysFROM → TO
url: 'libsql://my-db.turso.io', encryptionKey: '…'(alsohttps://,ws(s)://)encryptionKey. A remote database's storage encryption is configured on the Turso serverencryptionKey: ''(or any unset value)encryptionKeyurl: 'file:./data/app.db', encryptionKey: '…'(also:memory:, or a replica besidesyncUrl)encryptionKey, and put the file on an encrypted disk or volume if it must be encrypted at restThe one-line fix: delete
encryptionKeyfrom every turso datasource.ADR-0087 disposition
turso-config-encryption-key-removed(retiredFromLoadPath: true,retiredAfter: '18.0.0') deletes the key when its value is unset (any non-string, or'') or when it sits beside a remote url (libsql://,https://,http://,ws://,wss://, in any case, url trimmed). It emits one notice per key.turso-config-encryption-key-retired.RETIRED_KEYS_BY_MAJOR[18]gainsdata/TursoConfig:encryptionKey. TheSTEP18_RATIONALEfragment has order 107..changeset/25050-retire-turso-encryption-key.mdcarries the one marker, both declaration lines, BREAKING, FROM → TO and the one-line fix. Grades:@objectstack/specminor,@objectstack/driver-tursominor,@objectstack/service-datasourceminor.Decision: the partial conversion (four axes)
The question was whether the D2 conversion deletes every stored
encryptionKey, or only the ones it can prove were inert.Measured assumptions (one disproved)
encryptionKeyonce it is tombstoned." It does not. The schema-derived credential list excludesretiredKey()tombstones by their[REMOVED]prefix ([#14478 stack 5/6]data/·ui/·ai/·integration/: the 7 remaining duration keys carry their unit in the key name — ADR-0087 conversions with readers #15680), and the derived turso list (authToken) is non-empty, so the canonical fallback never applies.RETIRED_CREDENTIAL_KEYS(the renamedSTILL_WRITABLE_CREDENTIAL_KEYS).datasource-credential-redaction.test.ts("a RETIRED credential tombstone … is excluded from the derivation, yet still redacted") and by the service-datasource admin-door test on a local-url legacy row.turso-encryption-key-retirement.test.ts, radiuspackages examples skills content scripts) now holds it, with every exclusion named.encryptionKeyas their sentinel credential. 14 now use tursoauthToken, which is refused inline and redacted. The runtime reader-contexts pin seeds through the production writer, which refuses both primary slots, so it now uses mongodboptions.proxyPassword, which is writable and redacted. The metadata-protocol legacy-row redaction test keepsencryptionKeyon purpose, as a real retired-key row.Reverse verification (once, no permanent test)
Run with
scripts/ablation-replace.mjson the committed head. Each mutation landed (anchor 1 → 0, blob moved) and was restored (blob equals HEAD,git diff HEADempty).refuseIgnoredSyncKey(ENCRYPTION_KEY_RETIRED_REFUSAL)): driver-tursoturso-driver-encryption-key-retired.test.tsandturso-config-constructor-parity.test.tswent red, 36 failed across both files.turso: []): specdatasource-credential-redaction.test.tsandmetadata-type-redaction.test.tswent red, 7 failed.Verification
@objectstack/spec: build 0,pnpm test(after fixing the ledger total, which the first run caught) 0, typecheck 0. The repo-project absence pin passes, 10 tests.@objectstack/driver-turso: build 0,pnpm test0 (after measuring theSYNC_KEY_REFUSALSfloor at 20), typecheck 0.@objectstack/service-datasource: build 0,pnpm test0, typecheck 0.@objectstack/cli: typecheck 0. The three touched test files pass. Onestorage-driver.test.tscase timed out at 5 s under a shared-box batch, then passed in isolation (225 passed).--commandson this diff (heada15132cc4): all 127 derived commands run, exit codes recorded before any pipe.--ranreports 127 run, 0 NOT-MEASURED, 0 UNRUN.check-engine-split-ratioexit 2,check-plugin-teardown-shape --self-testexit 3) and dist output that was not built (check:skill-examples,check:dual-build-cjs-loads,check:i18n-coverage, each exit 3).git fetch --shallow-sinceand a fullpnpm build.pnpm --filter @objectstack/dogfood testona15132cc4, lock-wrapped: lock VERDICT command-exit 0. Test Files 287 passed, 3 skipped (290). Tests 2395 passed, 18 skipped (2413).The contract-review-tier review belongs to the seat. This PR stays a draft.
Generated by Claude Code