Repository navigation
feat(cli,plugin-audit): os migrate audit-mail-bodies masks the mail bodies that pre-#24688 audit and activity copies still hold in clear - #24722
Conversation
…ity copies Claude-Session: https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo Co-authored-by: Claude <noreply@anthropic.com>
…in restores the fixture's activity view Claude-Session: https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo Co-authored-by: Claude <noreply@anthropic.com>
…sent-database families; docs, checklist, changeset Claude-Session: https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo Co-authored-by: Claude <noreply@anthropic.com>
…t-audit census; the test double honours the caller's bound Claude-Session: https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 28 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 10 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 35 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 ca686f2f58cafb01ad906edd1d7b3a132880d2c2 && git checkout ca686f2f58cafb01ad906edd1d7b3a132880d2c2
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d20bf9b09b8084c64e021e9ba8d77c03fe6195e0 ee7a0710319eb6dea05e3dddbee251f557526fad && git checkout -B drift-repro d20bf9b09b8084c64e021e9ba8d77c03fe6195e0 && git merge --no-ff ee7a0710319eb6dea05e3dddbee251f557526fad
node scripts/docs-audit/affected-docs.mjs --json d20bf9b09b8084c64e021e9ba8d77c03fe6195e0
|
Contract reviewServed-tier: ① Derived judgmentsFace: the paths decide none; the changeset 1. Correctness and completeness — holds.
2. Idempotence and safety — holds.
3. Interaction with PR #24681 (head
4. Tests — adequate; small gaps, none blocking.
5. R1–R4. As reported by the dev before and after the 6. CLI surface — conforms. Flags are 7. Dev note (b), 8. CI check-runs on the head at review time. Blocking items
② Semver level
③ Boundary flags
Implemented-by: VERDICT: FAIL |
…binator and operator it does not implement Claude-Session: https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo Co-authored-by: Claude <noreply@anthropic.com>
Seat re-review ·
|
Closes #24693
Clause-②: yes
Residual R2 of the contract review of PR #24688. Before #24688 the audit writer copied
sys_email/sys_identity_emailrows intosys_audit_logandsys_activitywithbody_text/body_htmlin clear. Those bodies carry reset, verification, magic-link and invitation links. #24688 masks new copies only. This PR adds the one-time, idempotent cleanup for the copies written before it.Measured first: its own
os migratecommand, not a ceremony stepsys_emailcopies. After it, the activity copies that feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681's step 5b re-points tosys_identity_emailare masked the same way, andsys_audit_logkeeps the object name it was written under either way (feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681 does not rewrite the ledger).os migrate audit-metadata-bodiesis the same family of fix as its own command: dry run by default, nosys_migrationflag.Measured on the 18.0 upgrade-harness fixture (
packages/qa/dogfood/test/upgrade-harness/fixture-18.0/, based1173825b): 2sys_audit_logrows and 2sys_activityrows (create sides) hold a clear mail body. Counts only; no value was printed.What changed
@objectstack/plugin-auditmail-log-body-mask.ts:maskMailLogBodyCopy, the one mask. A set body becomesSECRET_MASK, an unset one staysnull, and no column is invented.ledgerViewinaudit-writers.tsnow calls it instead of its inline loop, so the writer and the cleanup share one helper. The object names and body columns are still fix(platform-objects,plugin-audit,plugin-approvals)!: mail bodies are read only with manage_platform_settings, and the audit mirrors never copy them in clear #24688'sMAIL_LOG_OBJECTS/MAIL_LOG_BODY_FIELDS/isMailLogObject, and the mask value is stillSECRET_MASK; none is re-spelled.mail-log-body-migration.ts:planMailLogBodyAuditRowPatch(fornew_value/old_value) andplanMailLogBodyActivityRowPatch(for both halves ofmetadata, keeping the pair's other keys);migrateMailLogBodyCopies, that keyset-pages both tables byid(500 rows a page) withobject_name $in MAIL_LOG_OBJECTSand writes only the copy column;preserveAuditwith the row's storedupdated_at, the shapecomment-parent-pair-backfill.tstakes, so no other column of the row moves;@objectstack/cli:os migrate audit-mail-bodiestakesaudit-metadata-bodies's flags one for one (--database-url,--apply,--yes,--force,--json), its read-only dry-run boot, and itsabsentTableReadsview. It is enrolled in the one-shot family table, the--jsonstdout-purity family and the absent-database roster (with control rows).cli.mdxdata-migration table and a section. The platform checklist itemcli.migrate-plan-apply-jsongoes to revision 6 (variant added, 18 → 19 subcommands). The tenant-audit census was regenerated (--write) for the runner's one new write call site, and the census page's hand-written figures were moved to match (230 → 231, 74 → 75, 129 → 130).24693-audit-mail-bodies.md:minorfor plugin-audit and cli, withClause-②: yesas measured: a new operator command and new exports, and no accept set narrowed for an author.Pins
plugin-audit/src/mail-log-body-migration.test.ts(13): the mask, both planners and the paged runner, over 18.0-shaped rows on all four snapshot sides. It covers dry run, apply leaving 0 clear copies, non-body columns byte-identical, other objects untouched, a re-run that is a no-op, bounded pages, a failed read counted, thepreserveAuditcontext, and no log line naming a body.qa/dogfood/test/audit-mail-bodies.dogfood.test.ts(4) runs the realosbinary over a fresh copy of the 18.0 fixture:--applyleaves 0 clear copies. A rewritten row differs only in its copy column, and there only in the body keys, which now read the mask. Every other column (updated_atincluded) and every other row is byte-identical;test-budget: 20(measured 12.84 s locally).scripts/ablation-replace.mjs; the fix was committed first). The rewrite's mask call was made a no-op, plugin-audit rebuilt, and the dist preflight showed the marker live:blob == HEAD, rebuilt,--absentpreflight clean, tree clean; then 13/13 and 4/4 green again.Proof (18.x line)
pnpm dev -- --freshon a random port): health 200, seeded-admin sign-in 200, 0 error lines, server stopped.upgrade-18x-harness.dogfood.test.tspasses, together withidentity-mail-read-gateand the new pin: 3 files, 32 passed.cli serve-walled-posture-refusal.test.ts: 5 passed.Tests and gates
@objectstack/plugin-audit: 59 files, 953 passed. typecheck exit 0 (plugin-audit, cli, dogfood).@objectstack/cliunit tier: 314 files, 4,643 passed.data-commands.absent-database,schema-migrate.one-shot-family): 2 files, 151 passed.json-stdout-purity.e2e(nightly tier): 64 of 65 pass, including the family-equality case with the new member. The 1 red isos migrate organization-ownership --json's stderr-diagnostics case, a command this diff does not touch. NOT MEASURED on base.node scripts/pm/dispatch-gates.mjs --commandsderived 104 commands (105 after the census files joined the diff). Exit codes were captured before any pipe:check-tenant-audit-censusand its--self-test(the new write call site), andcheck:objectql-double-limit(the test double now applies the caller's bound by presence).check-plugin-teardown-shape --self-test(shallow clone), speccheck:skill-examplesandcheck:dual-build-cjs-loads(both need a full-workspace build). CI runs them.check:merge-driver(new in the second derivation) exit 0.--ranreconciled 105 of 105.check-governed-merges --branch: 0 of 13 paths on the register, not governed. 1,130 changed lines.main(head6da0543a, clean merge;mainbrought one plugin-audit change,sys-audit-log.object.ts): rebuilt the dogfood closure. plugin-audit: 59 files, 959 passed. Dogfood (audit-mail-bodies,upgrade-18x-harness,identity-mail-read-gate): 3 files, 32 passed.check-tenant-audit-census: exit 0.Acceptance notes
sys_activityview (the rotation's read view over its shards). Any read-only boot over it, which creates nothing, reads no activity rows. The new pin puts the view back as the server left it, and says so. A real 18.0 database carries the view, so this is fixture fidelity, not a command defect. It affects any read-only command test on that fixture.docs/adr/**,content/docs/releases/, every ceremony file of feat(cli,runtime)!: the upgrade ceremony opens — v17 and 18.0 databases take it, and a server serves only a database it created or one the ceremony certified (18.x steps 5 and 6) #24681.🤖 Generated with Claude Code
https://claude.ai/code/session_01VHugC2zLtDQFNVzioMiUBo
Generated by Claude Code