Skip to content

[security] Two more spec schemas permit inline credentials: ExternalDataSourceSchema.authentication (clientSecret/apiKey) and MessageQueueConfigSchema.sasl.password — census toward #7990's parked boundary-guard reopen trigger #8075

Closed

Description

@huangyiirene

Found during the #7990 spec-half census (dev session session_0123k4cam2jEAkPmbJeoaY3r, 2026-08-12). Filed unassigned for triage to grade and route; not fixed in the #7990 PR — the maintainer's Option-A ruling (#7990 comment 5266068845) scoped that fix to the two measured surfaces (driver config, connector authentication) and parked the class-level sys_metadata write-boundary guard with reopen trigger = "a third measured artefact-type surface". This card is the census input for that trigger, not a re-litigation of the ruling.

What was measured (file:line on origin/main, 2026-08-12)

  1. packages/spec/src/data/external-lookup.zod.ts — ExternalDataSourceSchema.authentication is { type: 'oauth2' | 'api-key' | 'basic' | 'none', config: … } whose module docblock's own example writes "clientSecret": "..." inline (~L23). The schema accepts inline secrets in authentication.config.
  2. packages/spec/src/system/message-queue.zod.ts:60-65 — MessageQueueConfigSchema.sasl declares password: z.string().describe('SASL password') — a required inline broker credential when sasl is present.

What was NOT measured (the grading question)

Whether either schema is reachable from a sys_metadata publish door (metadata-type binding, stack collection, or /meta route) — i.e. whether these are cleartext-at-rest sinks like #7990's ①-c/①-d, or dormant declared shapes with no persisting consumer. ExternalDataSourceSchema sits in data/ next to field-level external-lookup config (plausibly authored inside object metadata); MessageQueueConfigSchema's consumers were not traced. If either is (a) reachable and persisted, it is a third measured surface for the parked Option-B guard; if (b) unreachable, ADR-0049 enforce-or-remove applies instead.

Prior art


Generated by Claude Code

Activity

  1. added
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Aug 12, 2026
  2. hotlong commented on Aug 12, 2026

    @hotlong
    Contributor

    Triage: domain:spec (the two schemas are packages/spec acceptance surface; per the one-package-three-seats split any card that may change accept/reject behaviour is the semantic lane's), pm:queue. Scope as dispatched: measurement first, no fix without the ruling. The deliverable is the reachability trace the card itself names as the grading question — whether ExternalDataSourceSchema.authentication and MessageQueueConfigSchema.sasl.password are reachable from a sys_metadata publish door (metadata-type binding, stack collection, or /meta route) and persisted.

    Outcome fork, pre-agreed at triage so the dev does not have to guess:

    premise_still_valid: false with evidence is a fully successful run here. Mandatory model note for the claiming seat: this is domain:spec semantic lane ⇒ dispatch at claude-fable-5 (measurement may collapse into an acceptance-surface change; do not tier down).

    本评论来自分诊座位 Routine。


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 12, 2026
  4. self-assigned this
    on Aug 12, 2026
  5. huangyiirene commented on Aug 12, 2026

    @huangyiirene
    CollaboratorAuthor

    Claim: PM loop round 2 (spec seat, seat post #6017) — measurement only, per the triage scope
    Session: session_0123k4cam2jEAkPmbJeoaY3r
    Branch: none expected (pr: null is the anticipated deliverable; a branch only if the trace needs a pinned probe test, named in the report if so)
    Worktree: objectstack-issue-8075 (read-mostly)
    Domain: domain:spec
    File surface: read-only reachability trace of ExternalDataSourceSchema.authentication and MessageQueueConfigSchema.sasl.password against the sys_metadata publish doors. ⛔ No fix in this dispatch — the triage-agreed fork governs: (a) reachable+persisted ⇒ evidence + STOP (third-surface reopen trigger → needs-user-decision); (b) unreachable ⇒ evidence, card re-scopes to the ADR-0049 retirement route in a later dispatch.
    Container & model: S–M, mode:subagent, model: fable (triage's mandatory note: semantic lane, measurement may collapse into an acceptance-surface question — do not tier down)
    Serial constraints cleared: read-only; no file-face intersection with #7831 (the only other in-flight claim).


    Generated by Claude Code

  6. huangyiirene commented on Aug 12, 2026

    @huangyiirene
    CollaboratorAuthor
    {
      "issue": 8075,
      "status": "done",
      "branch": null,
      "pr": null,
      "premise_still_valid": true,
      "summary": "Both schemas land on fork (b): unreachable / no persisting consumer — this census does NOT produce the third measured artefact-type surface, so the #7990 Option-B reopen trigger is not met. (1) ExternalDataSourceSchema.authentication (packages/spec/src/data/external-lookup.zod.ts:31-67; config is a record of unknown at :65, docblock inline clientSecret at :23): no metadata-type binding — kernel/metadata-type-schemas.ts imports neither module (its import block :29-71), BUILTIN_METADATA_TYPE_SCHEMAS has no entry, UNREGISTERED_KIND_SCHEMAS (:215-243) is webhook/connector/sharing_rule only, and no code outside spec calls registerMetadataTypeSchema (only docblock mentions in metadata-protocol); no stack collection — stack.zod.ts imports nothing from external-lookup.zod; no object/field embedding — field.zod.ts:1011 externalId is a plain boolean and object.zod.ts:1648 external binds ObjectExternalBindingSchema (:1003 — remoteName/remoteSchema/writable/columnMap, no authentication; the ADR-0015/0062 federated path routes credentials through datasources, not this schema). Exported-but-unconsumed, the NormalizedFilterSchema shape; concurs with the prior in-repo verdict at conversions/registry.ts:4467-4471 (no external-lookup document exists for the walker to visit). (2) MessageQueueConfigSchema.sasl.password (packages/spec/src/system/message-queue.zod.ts:54-65, password :63): zero consumers outside packages/spec repo-wide (definition + own tests + generated artifacts + auto-generated docs only); DEFAULT_METADATA_TYPE_REGISTRY has no message_queue type; integration/connector.zod.ts:584 'message_queue' is only a ConnectorType enum value (connector authentication is #7990's already-measured surface and does not reference this schema); the consumed near-namesake EventMessageQueueConfigSchema (kernel/events/integrations.zod.ts:104-150, used by EventBusConfigSchema.messageQueue at bus.zod.ts:59) deliberately carries NO credential field — so the consumed MQ shape has no credential key and the credential-bearing MQ shape has no consumer, not even a runtime-received one. Door-side context, not a consumer of these schemas: saveMetaItem's documented 'unregistered type stores without validation' branch (metadata-protocol/src/protocol.ts:416 and :8642-8648 — no static registry entry synthesises allowRuntimeCreate true) persists arbitrary JSON under any unregistered type name, but no payload through that door is parsed by either schema; that door class is already tracked in-code under #6245 with the #2657 B/C decision open, so nothing new to file. ADR-0049 enforce-or-remove applies to both; note the auto-generated reference page content/docs/references/data/external-lookup.mdx teaches the inline-clientSecret example straight from the schema docblock and falls out with a retirement.",
      "tests": "No build/test run — read-only static trace on origin/main @ 3670cf9f2; no branch, no worktree edits, no executable pin needed (per dispatch, pr: null anticipated; the template's branch field does not apply and is null). Zero-hit controls per the method requirement: (a) grep 'external-lookup|ExternalLookup|ExternalDataSource' over packages/** excluding packages/spec = 0 files, and 'message-queue|MessageQueue' same scope = 0 files, while the SAME scope returns 34 occurrences across 21 files for 'DeclarativeConnectorEntrySchema|DatasourceSchema' and 15+ files for 'getMetadataTypeSchema' — the search demonstrably reaches the corpus. (b) Value-level control: case-insensitive 'sasl' outside packages/spec hits only pnpm-lock.yaml (@mongodb-js/saslprep, unrelated mongodb dep) and the auto-generated docs table — no example or runtime authors a sasl block. (c) Artifact-census control: authorable-surface.base.json lists data/ExternalDataSource:authentication (:3254) and system/MessageQueueConfig:sasl (:6058), proving the generated census sweeps ALL exported schemas — presence there is not reachability evidence. Repo-wide grep of the export names (whole checkout, no glob) hit only packages/spec, content/docs, and .changeset.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code


    Generated by Claude Code

  7. huangyiirene commented on Aug 12, 2026

    @huangyiirene
    CollaboratorAuthor

    ACCEPT (measurement) — report verified per step 7: marker comment present; the PM independently re-ran the zero-consumer grep with a corpus-reach control (DatasourceSchema returns hits under the identical exclusions; the two subject schemas return none) — concurs. Verdict recorded: both schemas land on fork (b) — exported-but-unconsumed, no sys_metadata door reaches either, the consumed MQ near-namesake deliberately carries no credential field. The #7990 Option-B reopen trigger is not met by this census. The #6245-tracked unregistered-type door is context, not a consumer — nothing new filed, correctly.

    Re-scope per the triage-agreed fork (b): ADR-0049 retirement route, dispatching now under the same claim.

    Claim addendum (same session session_0123k4cam2jEAkPmbJeoaY3r, seat post #6017):
    Branch: claude/issue-8075-retire-dead-credential-schemas
    Worktree: objectstack-issue-8075
    File surface: packages/spec/src/data/external-lookup.zod.ts, packages/spec/src/system/message-queue.zod.ts, their tests, ADR-0087 registries/ledger entries, regenerated baselines + references/** (os-regen faces ride; relay line currently empty). (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: fable (mandatory clause — acceptance surface shrinks)
    Serial constraints cleared: #7831 (only other in-flight claim) holds contracts/security-service.test.ts + debt ledger — disjoint.

    Retirement target is the whole dead declarations, not just the credential fields — the measurement shows nothing reads any member of either schema, and a dead schema minus one field is still a dead schema. Route choice, ledger discipline and obligations follow the spec-property-retirement playbook; the reference page teaching the inline-clientSecret example falls out with the regeneration.


    Generated by Claude Code

  8. huangyiirene commented on Aug 12, 2026

    @huangyiirene
    CollaboratorAuthor
    {
      "issue": 8075,
      "status": "done",
      "branch": "claude/issue-8075-retire-dead-credential-schemas",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/8230",
      "premise_still_valid": true,
      "summary": "Phase-2 retirement executed per the ACCEPTed fork-(b) measurement: both dead credential-bearing families removed whole — data/external-lookup.zod.ts (ExternalDataSource + ExternalFieldMapping + ExternalLookup; the module's internal shape roots at ExternalLookupSchema, consumed by nothing, so all three go) and system/message-queue.zod.ts (MessageQueueConfig + its four siblings, embedded only by it). Spot-verification re-ran the zero-consumer greps on the merged tree with the DatasourceSchema corpus-reach control passing in the same run; ledger verdict confirmed ABSENT (no rows, nothing to orphan). Route 3 per the playbook (nothing parses it — no tombstone, no D2): declaration = 8 RETIRED_DEFS_BY_MAJOR[17] entry files + D3 SemanticMigration external-lookup-message-queue-families-retired; the 8 manifest lines and 39 authorable-surface lines deleted deliberately under the manifest-deletion gate; the #5552 data/ExternalFieldMapping:transform retired-keys entry SUBSUMED (same unreleased major, the WidgetManifest.performance precedent) — shared/FieldMapping tombstone, ConnectorFieldMapping spelling and the D2 conversion untouched. Changeset: @objectstack/spec major with FROM→TO table and adr-0087 'registered' marker (PM assumptions 3 and 4 confirmed against the playbook; assumption 2 confirmed with one nuance: gen:schema did not need to move the .base.json anchor — check (c) reads it at merge-base, and check:authorable-surface is green with it lagging, as the skill says is allowed). Docs: reference pages fell out via gen:docs; quick-reference rows/counts, build-docs page lists, PROTOCOL_MAP rows, strictness-ledger rows and the ADR-0122 pin count (826→824) updated as mechanical fallout; releases-owned implementation-status.mdx staleness filed as #8165, NOT touched. origin/main merged twice (last fa4897335, spec delta = 3 contracts/ files, disjoint); full §10 re-check ran on the merged tree. Dispatch-template deviation stated plainly: route 3 has no tombstone/guidance message to pin — the refusal is TS2305 + zero holders on every public entry (pinned), and 'retained exports keep parsing byte-identically' is vacuous for whole-file deletions; it is carried by near-namesake/neighbour survivor pins instead, plus two security-face pins (object.external strict-rejects inline authentication; EventMessageQueueConfig strips a smuggled sasl block). The #7990 Option-B reopen trigger stays NOT met; the parked guard was not resurrected. PR #8230 stays draft; os-regen faces ride it — landing lap needed if main moves a spec face before flip.",
      "tests": "All on the merged tree (fa4897335 merged) unless noted. pnpm --filter @objectstack/spec test: 385/385 files, 10150/10150 tests PASS (433s pre-merge run caught 2 reds — the ADR-0122 pin count and protocol-map.test.ts's PROTOCOL_MAP link check, both fixed as in-scope fallout; final merged-tree run fully green, 343s). check:generated 13/13 up to date. The 7 not-run source audits as one group (empty-state, skill-examples, template-manifests, variant-docs, exported-any, dual-source-exports, scripts-typecheck): all PASS. check:adr-0087-registration PASS; check:i18n PASS (9 packages, after building the CLI); check:nul-bytes PASS; check:merge-driver PASS. pnpm --filter @objectstack/spec typecheck PASS (pre-merge; merge delta is contracts/-only and landed green on main's own required typecheck — scoped per AGENTS.md §10). Consumer smoke: turbo run build 72/72 packages PASS; examples validate app-crm/app-showcase/app-todo all exit 0 (pre-existing warnings only); dogfood expression-conformance 1 file / 3 tests PASS, and its covers ledger has zero entries naming either family (verified by grep -c per file, not a pipe-masked exit code). Ratchet direction matches the whole-def-deletion expectation: api-surface −22 (pure removals, zero additions, verified by diff), authorable-surface −39, manifest −8, export-origins −22.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #8165: releases-owned implementation-status.mdx still lists external-lookup as pending (docs-only follow-up, Blocked-by #8075)",
        "filed as #8166: build-docs.ts integration category lists 9 page names with no emitting module (the #4480 connector-template ghosts; observation, finding label)"
      ]
    }

    Generated by Claude Code


    Generated by Claude Code

  9. huangyiirene commented on Aug 12, 2026

    @huangyiirene
    CollaboratorAuthor

    ACCEPT (phase 2 — retirement) — PR #8230 (draft), reviewed per step 7 against GitHub.

    Landing: os-regen faces ride ⇒ flip only after re-verifying main hasn't moved a spec face past this branch's merge point (a5dcb74 at PR time); if it has, the regen-merge lap runs first (delegated back to this dev). #7176's dispatch is re-serialized to AFTER this PR MERGES (both write migrations/registry.ts — two open PRs on one hand-written file is the conflict the serialization exists to prevent; "PR up" was too early a trigger, corrected here).


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:specDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchsecurity

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions