Skip to content

feat(spec): per-type metadata redaction seam in kernel, one credential-key definition in data (#8300) - #8530

Merged
qq9340100 merged 4 commits into
mainfrom
claude/issue-8300-metadata-redaction-seam
Aug 13, 2026
Merged

feat(spec): per-type metadata redaction seam in kernel, one credential-key definition in data (#8300)#8530
qq9340100 merged 4 commits into
mainfrom
claude/issue-8300-metadata-redaction-seam

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Fixes#8300

#8154 (the consumer card, Blocked-by: this one) unblocks on merge: the metadata read exits can resolve getMetadataTypeRedactor(type) and apply it per item; the write-path carry-forward and the read-exit application both stay on #8154, per the card's fence.

What this delivers

1. The per-type redaction seam — packages/spec/src/kernel/metadata-type-redaction.ts.registerMetadataTypeRedactor / getMetadataTypeRedactor / listMetadataTypeRedactorTypes, the same built-in-map + runtime-overlay registry pattern as its siblings registerMetadataTypeSchema and registerMetadataTypeActions, exported beside them from @objectstack/spec/kernel. The redactor contract is minimal: a pure (item) => { item, redactedKeys } where redactedKeys: [] means "ran, nothing to hide" and an undefined lookup means "no redactor registered" — the absence-vs-empty distinction #8154's consumer depends on. The module header states the two consumer ordering rules #8154 measured (diagnostics computed on the raw body BEFORE redaction; the stored record never mutated).

2. One definition of "what is a credential key" — packages/spec/src/data/datasource-credential-redaction.ts. The derivation half of service-datasource's datasource-config-redaction.ts (PR #8126), moved verbatim: refused keys derived from each driver's own z.never() contract, plus the pre-#8078 alias list, plus turso's still-writable encryptionKey; and the read-path redaction built on it (redactUrlPassword, redactDatasourceConfig). service-datasource now re-exports these names from @objectstack/spec/data (every existing consumer compiles unchanged) and keeps restoreRedactedConfig, the admin service's write-path inverse.

3. Registration wiring: datasource is a BUILT-IN, not a plugin registration. The card's fail-open measurement is the constraint: DatasourceAdminServicePlugin.init is opt-in while sys_metadata rows and the /meta read exits exist without it, so plugin-init registration would serve cleartext while looking protected. The derivation's ownership is this same package, so the honest non-opt-in site is a built-in map entry — present the moment @objectstack/spec/kernel loads, on every composition that can serve a datasource row. Nothing is left for #8154 to register.

Verified premises (re-tested, not re-derived)

Coverage

  • Seam round trip (kernel/metadata-type-redaction.test.ts): register/lookup, replace-on-re-register, registered-overrides-builtin.
  • Fail-closed guard: getMetadataTypeRedactor('datasource') resolves with ZERO registration calls; end-to-end redaction of a legacy stored row (config.password + URL-embedded password dropped, _diagnostics passed through by reference, stored body untouched).
  • Derivation pin (data/datasource-credential-redaction.test.ts): per-driver literal arrays pinning the exact key set the service-datasource original derived — byte-equal, insertion order included — for postgres/mysql/mongodb/turso, the credential-less drivers' canonical fallback, and the unknown-driver fallback. Plus the write-door alignment property: redactUrlPassword's output always passes urlUserinfoPassword (the [Decision] URL-embedded credentials (user:password@host in driver config.url) remain a live cleartext door after #7990 — refuse at publish, or accept as residual risk? #8082 write-door parse), and write-door-accepted URLs come back byte-for-byte.
  • Absence vs empty: unregistered type → undefined; clean config → redactedKeys: [].
  • Re-export shim: the untouched service-datasource suite (376 tests, including the 8126 redaction pins) passes through the re-export.

Verification

  • @objectstack/spec: full vitest suite 395 files / 10465 tests passed; pnpm typecheck clean (tsc + test-layer ledger unchanged).
  • @objectstack/service-datasource: 16 files / 376 tests passed; pnpm typecheck clean.
  • Reverse verification, both predicted red: with the built-in datasource entry removed, the fail-closed suite went red (6 tests); with the pwd alias dropped from the moved derivation, the byte-equal pin went red. Both restored from the committed state; 18/18 green after restore.
  • check:generated: all 13 artifacts up to date after gen:api-surface + gen:export-origins (the two it proved stale — new exports on the data and kernel entries).
  • Gate families (dispatch-derived + implicated): nul-bytes, adr-anchors, driver-conformance, test-source-alias, type-source-resolution, spec-parsed-alias, merge-driver, changeset-gate-self-tests, query-options-erasure, i18n (after CLI build), docs-audit-scope, release-body, objectui-changeset, type-check-coverage, adr-0087-registration, empty-changeset, changeset-no-major, changeset-fixed, cross-package-test-inputs, doc-formula-expressions — all OK. Two local reds are environmental, not this diff: check:dev-prereqs (12 unrelated packages have no local dist — only affected closures were built here; CI builds fresh) and check:objectui-pin-fresh (.objectui-sha staleness, a release-time fact independent of this diff).

Changeset

@objectstack/specminor (new public seam + moved exports), @objectstack/service-datasourcepatch (re-export, behaviour unchanged); adr-0087 not-required (no-migration-prescription) — additive exports plus a same-name re-export move, nothing for an upgrader to migrate.

Out of scope, untouched: content/docs/releases/**, packages/spec/src/api/error-code-ledger.zod.ts, packages/spec/src/system/i18n-resolver.ts, packages/spec/src/ui/component.zod.ts, packages/spec/src/contracts/**.


Generated by Claude Code

…al-key definition in data (#8300)
- kernel/metadata-type-redaction.ts: registerMetadataTypeRedactor /
getMetadataTypeRedactor / listMetadataTypeRedactorTypes, mirroring the
registerMetadataTypeSchema registry pattern; the datasource redactor is
wired as a BUILT-IN (plugin-init registration is measured fail-open).
- data/datasource-credential-redaction.ts: the credential-key derivation and
read-path redaction moved from service-datasource (z.never() contract +
pre-#8078 aliases + turso encryptionKey), pinned byte-equal by test.
- service-datasource re-exports the moved names and keeps
restoreRedactedConfig (write-path inverse).
- api-surface/ + export-origins/ regenerated for the new exports.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
@vercel

vercelBot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 13, 2026 8:26pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/service-datasource, @objectstack/spec.

106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx(via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx(via @objectstack/spec)
  • content/docs/ai/skills.mdx(via @objectstack/spec)
  • content/docs/api/client-sdk.mdx(via @objectstack/spec)
  • content/docs/api/environment-routing.mdx(via @objectstack/spec)
  • content/docs/api/error-catalog.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx(via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx(via @objectstack/spec)
  • content/docs/api/index.mdx(via @objectstack/spec)
  • content/docs/automation/approvals.mdx(via @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/spec)
  • content/docs/automation/flows.mdx(via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx(via packages/spec)
  • content/docs/automation/hooks.mdx(via @objectstack/spec)
  • content/docs/automation/index.mdx(via @objectstack/spec)
  • content/docs/automation/webhooks.mdx(via @objectstack/spec)
  • content/docs/automation/workflows.mdx(via @objectstack/spec)
  • content/docs/concepts/architecture.mdx(via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx(via packages/spec)
  • content/docs/concepts/index.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx(via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx(via packages/spec)
  • content/docs/concepts/north-star.mdx(via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx(via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx(via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx(via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx(via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx(via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx(via @objectstack/spec)
  • content/docs/data-modeling/index.mdx(via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx(via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx(via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx(via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx(via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx(via @objectstack/spec)
  • content/docs/deployment/cli.mdx(via @objectstack/spec)
  • content/docs/deployment/tenancy-modes.mdx(via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx(via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx(via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx(via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx(via @objectstack/spec)
  • content/docs/getting-started/examples.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx(via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx(via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx(via @objectstack/spec)
  • content/docs/kernel/cluster.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx(via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx(via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/spec)
  • content/docs/kernel/services.mdx(via @objectstack/spec)
  • content/docs/permissions/authorization.mdx(via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx(via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx(via @objectstack/spec)
  • content/docs/permissions/positions.mdx(via @objectstack/spec)
  • content/docs/permissions/rls.mdx(via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx(via @objectstack/spec)
  • content/docs/permissions/system-context.mdx(via packages/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx(via @objectstack/spec)
  • content/docs/plugins/development.mdx(via @objectstack/spec)
  • content/docs/plugins/index.mdx(via @objectstack/spec)
  • content/docs/plugins/packages.mdx(via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx(via @objectstack/spec)
  • content/docs/protocol/diagram.mdx(via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx(via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx(via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx(via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx(via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx(via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx(via @objectstack/spec)
  • content/docs/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/apps.mdx(via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx(via @objectstack/spec)
  • content/docs/ui/dashboards.mdx(via @objectstack/spec)
  • content/docs/ui/field-grouping-and-order.mdx(via @objectstack/spec)
  • content/docs/ui/forms.mdx(via @objectstack/spec)
  • content/docs/ui/index.mdx(via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx(via @objectstack/spec)
  • content/docs/ui/setup-app.mdx(via @objectstack/spec)
  • content/docs/ui/translations.mdx(via @objectstack/spec)
  • content/docs/ui/views.mdx(via @objectstack/spec)

7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/spec)
  • content/docs/releases/v13.mdx(via @objectstack/spec)
  • content/docs/releases/v16.mdx(via @objectstack/spec)
  • content/docs/releases/v17.mdx(via @objectstack/spec)
  • content/docs/releases/v9.mdx(via @objectstack/spec)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…ee (#8300 relay)
Post-merge regeneration on a known-good base per scripts/pm/os-regen-merge.sh:
the merge commit took origin/main's side of the os-regen artifacts; this
commit re-derives them from the merged source (5074 exports, data + kernel
shards), discharging the pre-commit deferral.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationprotocol:datasize/xlteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A per-type metadata redaction seam belongs in @objectstack/spec/kernel — no service package can reach a registry in metadata-protocol

2 participants

@qq9340100@claude