Repository navigation
[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
Description
Activity
Triage:
domain:spec(the two schemas arepackages/specacceptance 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 — whetherExternalDataSourceSchema.authenticationandMessageQueueConfigSchema.sasl.passwordare reachable from asys_metadatapublish door (metadata-type binding, stack collection, or/metaroute) and persisted.Outcome fork, pre-agreed at triage so the dev does not have to guess:
- (a) reachable + persisted ⇒ report back with file:line evidence and STOP — that is the "third measured artefact-type surface" reopen trigger for the maintainer's parked Option-B boundary-guard ruling ([security]
sys_metadata.metadatais a general cleartext sink: any authored artefact whose schema permits an inline credential lands it there (datasourceconfig.password, connectorauthentication) #7990 comment 5266068845). Reopening that ruling is the maintainer's, not ours; the card flips toneeds-user-decisionwith the evidence attached. - (b) unreachable / no persisting consumer ⇒ ADR-0049 enforce-or-remove applies; report with the zero-consumer evidence and the card gets re-scoped to the retirement route (spec seat,
claude-fable-5per the mandatory tiering clause, since removal changes the acceptance surface).
premise_still_valid: falsewith evidence is a fully successful run here. Mandatory model note for the claiming seat: this isdomain:specsemantic lane ⇒ dispatch atclaude-fable-5(measurement may collapse into an acceptance-surface change; do not tier down).本评论来自分诊座位 Routine。
Generated by Claude Code
- (a) reachable + persisted ⇒ report back with file:line evidence and STOP — that is the "third measured artefact-type surface" reopen trigger for the maintainer's parked Option-B boundary-guard ruling ([security]
huangyiirene commented
on Aug 12, 2026 CollaboratorAuthorMore actionsClaim: PM loop round 2 (spec seat, seat post #6017) — measurement only, per the triage scope
Session:session_0123k4cam2jEAkPmbJeoaY3r
Branch: none expected (pr: nullis 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 ofExternalDataSourceSchema.authenticationandMessageQueueConfigSchema.sasl.passwordagainst thesys_metadatapublish 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
huangyiirene commented
on Aug 12, 2026 CollaboratorAuthorMore actions{ "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
huangyiirene commented
on Aug 12, 2026 CollaboratorAuthorMore actionsACCEPT (measurement) — report verified per step 7: marker comment present; the PM independently re-ran the zero-consumer grep with a corpus-reach control (
DatasourceSchemareturns hits under the identical exclusions; the two subject schemas return none) — concurs. Verdict recorded: both schemas land on fork (b) — exported-but-unconsumed, nosys_metadatadoor 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) holdscontracts/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-
clientSecretexample falls out with the regeneration.
Generated by Claude Code
- added a commit that references this issue
on Aug 12, 2026 huangyiirene commented
on Aug 12, 2026 CollaboratorAuthorMore actions{ "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
huangyiirene commented
on Aug 12, 2026 CollaboratorAuthorMore actionsACCEPT (phase 2 — retirement) — PR #8230 (draft), reviewed per step 7 against GitHub.
- Scope verified on the diff (53 files, +827/−1793): the two retired modules + barrels, 8
RETIRED_DEFS_BY_MAJOR[17]entry files + the D3 semantic migration + registry, the shared/mapping.zod.ts 的 javascript 变换 describe 推荐 dialect="js",而 ExpressionDialect 只有 cel/cron/template —— 照着写会被拒 #5552 retired-keys subsumption (same unreleased major, precedent honored,shared/FieldMappingtombstone + D2 conversion untouched), generated faces regenerated wholesale, and hand-written mechanical fallout each justified by a gate that would otherwise refuse (PROTOCOL_MAP link test, strictness-ledger file-existence check, ADR-0122 pin count with receipt). The one non-obvious hunk (integration/connector.zod.ts) personally verified: a docblock tense update recording the retirement — nothing behavioral. - Route 3 justified from the ACCEPTed measurement (nothing parses it ⇒ no tombstone, no D2 — a prescription nobody can receive); the dispatch-template deviation is stated plainly and substituted honestly: zero-holder pins by resolved symbol identity across all 22 names, neighbor-survivor pins for everything a too-wide sweep would take, file-deletion probes with anti-vacuity controls, and two security-face pins (
object.externalstrict-rejects inlineauthentication; liveEventMessageQueueConfigstrips a smuggledsaslblock). - Ratchet directions are the proof of work: api-surface −22 (pure removals, verified by diff), authorable-surface −39, manifest −8, export-origins −22 — a removal that moved no instrument would have been fake. 10150/10150 on the merged tree; 72/72 workspace build; examples ×3;
check:generated13/13; ADR-0087 marker gate green.content/docs/releases/**correctly NOT touched (filed [docs] releases/implementation-status.mdx still lists external-lookup as a pending data protocol after the #8075 retirement #8165 instead — verified existing, already triagedpm:blocked; Observation: build-docs.ts integration category lists 9 page names with no emitting module — onlyconnectorproduces a page #8166 verified existing, already picked up by spec-tooling). - Changeset
@objectstack/specmajor with FROM→TO (datasource 账本判定的 20 条死键至今无人处置:三个块整块无人读,其中 readOnly 让一个 shipped 示例的「只读副本」可写(ADR-0049 enforce-or-remove) #4583/feat(spec)!: refuse inline credentials at publish — driver config + connector authoring door (#7990, spec half) #8078 precedent) — maintainer's standing veto window noted in the round report.
Landing: os-regen faces ride ⇒ flip only after re-verifying main hasn't moved a spec face past this branch's merge point (
a5dcb74at 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 writemigrations/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
- Scope verified on the diff (53 files, +827/−1793): the two retired modules + barrels, 8
- added a commit that references this issue
on Aug 12, 2026 - added 3 commits that reference this issue
on Aug 17, 2026
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, connectorauthentication) and parked the class-levelsys_metadatawrite-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)packages/spec/src/data/external-lookup.zod.ts—ExternalDataSourceSchema.authenticationis{ type: 'oauth2' | 'api-key' | 'basic' | 'none', config: … }whose module docblock's own example writes"clientSecret": "..."inline (~L23). The schema accepts inline secrets inauthentication.config.packages/spec/src/system/message-queue.zod.ts:60-65—MessageQueueConfigSchema.sasldeclarespassword: z.string().describe('SASL password')— a required inline broker credential whensaslis present.What was NOT measured (the grading question)
Whether either schema is reachable from a
sys_metadatapublish door (metadata-type binding, stack collection, or/metaroute) — i.e. whether these are cleartext-at-rest sinks like #7990's ①-c/①-d, or dormant declared shapes with no persisting consumer.ExternalDataSourceSchemasits indata/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
sys_metadata.metadatais a general cleartext sink: any authored artefact whose schema permits an inline credential lands it there (datasourceconfig.password, connectorauthentication) #7990 — the ruled per-artefact closure (driver config + connector authoring door), spec half in PR (branchclaude/issue-7990-inline-credential-refusal).sys_sso_provider.oidc_configcarries the OIDCclientSecretin a cleartext JSON textarea, by its own field description #8009 — sibling:sys_sso_provider.oidc_configclientSecret.Generated by Claude Code