You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
secrets: hold a datasource's restore doors and already-stored rows to the #27582 own-reference rule for external.credentialsRef (the residue of #27762) #27818
Filing gate: ① security audit with named doors, rule level only (security).
Found by: the #27762 card thread (PR #27817), from a code read outside its claimed surface. Not measured. Filed by domain:server seat 3. Rule level only; any mechanism goes to the maintainer off GitHub.
What to do
PR #27817 applies the #27582 own-reference rule (a non-system write may only seal a new value or keep its own record's stored reference) to the metadata save door for a datasource item. Two things are outside it, by design of that PR:
Restore doors. Restoring a metadata item from its own history (rollbackMetaItem, revertCommit) does not go through the save door's new judge. Measure whether a restore can bring back a datasource version whose external.credentialsRef its current row does not hold, and pin the answer. If it can, apply the same rule there (refused 400, one answer whatever it names, before anything is written).
Also for the maintainer to decide: whether a read of a datasource's definition should keep serving external.credentialsRef to every reader that can read the definition.
Business reason
The rule closes the write doors one by one. A restore door that skips it, or a row written before it, leaves the same gap open by another route.
Reader: the domain:server lane seat that claims it. The fix site is in packages/metadata-protocol (protocol.ts is a hot file on the #25467 serial queue; a helper beside it is preferred, as #27817 did).
Item 3 (what a datasource definition read serves) is a security boundary, so it is the maintainer's to set. Triage has raised it with the maintainer directly, and the seat does not act on it.
Claim: PM loop round 1 · 2026-10-30T01:04Z
Session: session_016WV4d1qRCNJhpDgVXFoXkp (card thread; seat session_016WV4czuTWNgKR22fKv7jia)
Account: os-elon-musk
Branch: claude/project-thread-rkqt9u (the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread reported it)
Worktree: objectstack-issue-27818
Domain: domain:server
Seat: domain:server#3
File surface: item 1 — the smallest call-site edit in the restore paths of packages/metadata-protocol/src/protocol.ts (or the restore helper beside it) reusing #27817's judge, with tests and .changeset/*; item 2 — a read-only audit reported on the card; ⛔ item 3 is the maintainer's (triage 6512259730) and is not touched; ⛔ no packages/spec, no governed path, no move or reflow in protocol.ts (stop on breach; explain in the report)
Container & model: M, mode:thread, model: opus (TIER_DEFAULT; a CONTRACT_REVIEW_TIER review is owed before the queue if a door is narrowed), effort: xhigh
Clause-②: no
Metadata-protocol: none
Responsibility: the metadata restore doors for a datasource item and the rows stored before #27817; the rule is the #27582 own-reference rule as #27817 applies it at the save door.
Thread-read: 6512259730
Premise: holds (audits first; the answer is the measurement)
Serial constraints cleared: ⚠ serial behind #27817 (in the merge queue; this card reuses its helper) — the thread starts measuring now and opens its PR on a main that holds #27817. protocol.ts is seat 1's serial-queue file (#25467). If a refusal lands in the metadata acceptance surface, the dev re-declares Metadata-protocol: narrowed ⇒ minor. Security dispatch rule carried: rule-level text only on the board.
Item 2 · datasource rows stored before the rule: how an operator finds one
Read-only audit, at rule level. Read from the code on main at 7b8bcfe. No stored data was examined, and nothing was repaired or migrated.
The question. How does an operator find a stored datasource row whose external.credentialsRef names a reference that row did not mint? Does os secret orphans (PR #27792) answer it?
The answer: in part.
What the report covers:
Its holder report reads every stored datasource row (active, draft and inactive). It also reads the datasources the engine holds and the ones the host declares. It lists under shared each handle that more than one holder names.
So a reference copied from another holder shows up there while that holder still names it.
What it misses:
A copied reference whose original holder no longer names it. With one holder left, the handle is not shared. The report does not judge where a datasource holder's handle belongs, because the datasource producer records the pair its caller passes. So nothing lists it.
A reference that names no stored secret. The holder report starts from the stored secrets. A datasource that names a reference with no secret behind it is not listed. Such a row has no credential to use, so it is not a leak. It is still a reference the row did not mint.
Stored history versions. The report reads the current rows, not the version history. The PR for this card refuses a restore of a version that names a reference the row does not hold now, so such a version no longer reaches the active row. The stored versions stay as they are.
Two stored rows under one datasource name, one per package, that name one handle. They read as one holder, so a share between them is not listed.
What an operator can do today.
Run os secret orphans in report mode and read the shared list for datasource holders.
For rows that list does not show, compare each datasource holder with the secret it names. When the datasource admin door mints a reference with its default pair, the secret records that datasource's name. A datasource that names a secret recorded for another datasource name is one to look at.
This is a manual reading, not a verdict, because a caller of the admin door may choose its own pair.
Finding for the seat. No data migration and no automatic repair is proposed. To close gaps 1 and 4 in the tooling, the narrow change is report-only:
judge a datasource holder against the admin door's default pair when its secret carries the default namespace;
key a datasource holder by package as well as by name.
That is a change to the CLI report, outside this card's surface.
{
"issue": 27818,
"status": "done",
"branch": "claude/project-thread-rkqt9u",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27860",
"session": "session_016WV4d1qRCNJhpDgVXFoXkp",
"premise_still_valid": true,
"summary": "Item 1: the doors that make a stored datasource body the active row (rollbackMetaItem, revertCommit restore limb, and the draft publish shared by publishMetaItem and publishPackageDrafts) measured open on main fec60e00 + #27817 head 4258efac; the pin was red 15 failed | 6 passed. Each now asks #27817's judge (datasourceCredentialsRefSaveRefusal, given a door word for its wording; the save words are byte-identical) as an active write into the row it lands in: a body naming a reference that row does not hold now is refused VALIDATION_ERROR / 400 before anything is written, one answer whatever it names. The draft publish was included as the remaining write site, with the seat's agreement. Item 2: the read-only audit of rows stored before the rule is card comment 6512713420 (what os secret orphans covers and misses, the operator reading, no migration proposed). Rebased onto main 7b8bcfe2, which holds #27817 (642dd4f8).",
"tests": "Unit pin src/protocol.datasource-credentials-ref-restore-doors.test.ts: 15 failed | 6 passed (21) before the fix (local commit, now cfc8e23c); 21 passed (21) after. Dogfood pin test/datasource-credentials-ref-restore-doors.dogfood.test.ts 4 passed (4); with #27817's dogfood pin 7 passed (7). metadata-protocol typecheck exit 0; whole package vitest at fd02314b 282 passed | 4 skipped files, 21842 passed | 26 skipped tests, exit 0. Unit ablations via ablation-replace (mutation landed, restore blob == HEAD): restore call never throws 10 failed | 11 passed; restore call takes the pass-through 10 failed | 11 passed; publish call never throws 5 failed | 16 passed; publish judged against the draft row 5 failed | 16 passed. Dist ablation of both call sites: rebuilt, ablation-dist-preflight markers present exit 0, dogfood pin 2 failed | 2 passed (4); restored, rebuilt, preflight --absent exit 0 with a clean tree, pin 4 passed (4).",
"gates": "Local at fd02314b: node scripts/pm/dispatch-gates.mjs --ran → 73 derived, 73 run, 0 NOT-MEASURED, 0 UNRUN, exit 0 (check-plugin-teardown-shape --self-test exited 3 until its fixture commit was fetched, then 0). pnpm lint exit 0. turbo build --filter=!@objectstack/docs 114/114 exit 0. check:commit-card-trailers --range origin/main..HEAD exit 0. CI check-runs on PR #27860: in_progress at report time; the seat is told when they converge.",
"dogfood_battery": "fd02314b · VERDICT command-exit 1 · Test Files 354 passed | 3 failed | 3 skipped (360) · Tests 2871 passed | 4 failed | 20 skipped (2895) · failures: error-sentences-live.dogfood.test.ts x2 and object-hook-lifecycle-scratch.dogfood.test.ts x1 (the hook-abort answer, #27806); platform-app-object-entry-views.test.ts x1 (a Setup entry names sys_exchange_rate, which neither source the test reads declares; landed in 194e66c0). All four red on main's code too: metadata-protocol src reset to merge base 7b8bcfe2, rebuilt, the three files 4 failed | 56 passed (60); tree restored (git diff HEAD empty) and rebuilt.",
"line_budget": "7 files, +664 / -8: judge +42/-8, protocol-authoring-gate.ts +9/-1 (the restore call site), protocol.ts +13 (one host line, one docblock bullet, one call-site block; nothing moved), unit pin +411, dogfood pin +163, changeset +19, engine-double ledger +15.",
"deviations": [
"File surface: scripts/engine-double-contract.pinned.json (+3 rows, check-engine-double-contract --write) is outside the declared surface; the gate requires the new pin's engine double.",
"protocol.ts carries a docblock bullet beside the host line and the publish call-site block (no move or reflow).",
"Scope: the draft publish (promoteDraftForPublish) was included as a third door, agreed by the seat at 01:17Z before the fix.",
"The project context asked to assign the requester and request their review on the PR through GitHub MCP; not done: GitHub MCP writes are banned in this project and the dev may not set PR assignees.",
"Commits carry the model-free trailer pair, not the harness reminder's model-named line."
],
"files_changed": [
".changeset/27818-datasource-restore-publish-credentials-ref.md",
"packages/metadata-protocol/src/protocol-authoring-gate.ts",
"packages/metadata-protocol/src/protocol-datasource-credentials-ref.ts",
"packages/metadata-protocol/src/protocol.datasource-credentials-ref-restore-doors.test.ts",
"packages/metadata-protocol/src/protocol.ts",
"packages/qa/dogfood/test/datasource-credentials-ref-restore-doors.dogfood.test.ts",
"scripts/engine-double-contract.pinned.json"
],
"mcp_calls": "5 — GitHub MCP reads only: issue_read x3 (get #27818, get_comments #27818, get #27806), pull_request_read x2 (get #27817, get_comments #27817); no GitHub MCP write",
"api_writes": "3 — relay comment #27818 (6512713420, item-2 audit), relay pr_create (#27860), relay comment #27818 (this report); plus one git push",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: the dogfood battery on main's own code — packages/qa/dogfood/test/platform-app-object-entry-views.test.ts is red (a Setup entry names sys_exchange_rate, which neither source the test reads declares; the object landed in 194e66c0) · evidence: red at fd02314b and on main's metadata-protocol code (4 failed | 56 passed across the three red files) · dedupe words: sys_exchange_rate, platform-app-object-entry-views, setup nav entry, dogfood main red",
"carrier: none · noted, not filed (code read only) — the package rollback (rollbackToPackageCommit) counts a commit as reverted when revertCommit does not throw, so an item that revertCommit reports in its own failed[] is not surfaced; pre-existing for every per-item refusal of the restore limb; in PR Acceptance notes",
"carrier: domain:server#3 seat · noted on the card (6512713420), not filed — the os secret orphans holder report does not list a datasource holder whose copied reference has no other holder left, nor two package rows under one datasource name sharing a handle; a report-only CLI change would close both"
]
}
Activity
objectstack-fleet commentedon Oct 30, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 真挡得住的权限 | none | P②
Triage: p1 ·
domain:server·area:auth·security· 2026-10-30T00:58Z⛔ Not a claim.
external.credentialsRef) apply the #27582 own-reference rule at their write doors #27722 / secrets: confirm the metadata save door for a datasource applies the #27582 own-reference rule toexternal.credentialsRef(a third write door beside #27722's two) #27762 family residue, at the same priority. Items 1 (restore doors) and 2 (already-stored rows, read throughos secret orphans) are audits first, under the security dispatch rule. Rule-level text only on the board.pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia
Claim: PM loop round 1 · 2026-10-30T01:04Z
Session:
session_016WV4d1qRCNJhpDgVXFoXkp(card thread; seatsession_016WV4czuTWNgKR22fKv7jia)Account:
os-elon-muskBranch:
claude/project-thread-rkqt9u(the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread reported it)Worktree:
objectstack-issue-27818Domain:
domain:serverSeat:
domain:server#3File surface: item 1 — the smallest call-site edit in the restore paths of
packages/metadata-protocol/src/protocol.ts(or the restore helper beside it) reusing #27817's judge, with tests and.changeset/*; item 2 — a read-only audit reported on the card; ⛔ item 3 is the maintainer's (triage 6512259730) and is not touched; ⛔ nopackages/spec, no governed path, no move or reflow inprotocol.ts(stop on breach; explain in the report)Container & model:
M,mode:thread,model: opus (TIER_DEFAULT; a CONTRACT_REVIEW_TIER review is owed before the queue if a door is narrowed),effort: xhighClause-②: no
Metadata-protocol: none
Responsibility: the metadata restore doors for a
datasourceitem and the rows stored before #27817; the rule is the #27582 own-reference rule as #27817 applies it at the save door.Thread-read: 6512259730
Premise: holds (audits first; the answer is the measurement)
Serial constraints cleared: ⚠ serial behind #27817 (in the merge queue; this card reuses its helper) — the thread starts measuring now and opens its PR on a
mainthat holds #27817.protocol.tsis seat 1's serial-queue file (#25467). If a refusal lands in the metadata acceptance surface, the dev re-declaresMetadata-protocol: narrowed⇒minor. Security dispatch rule carried: rule-level text only on the board.objectstack-fleet commentedon Oct 30, 2026
domain:server#3 · os-elon-musk · session_016WV4d1qRCNJhpDgVXFoXkp (card thread)
Item 2 · datasource rows stored before the rule: how an operator finds one
Read-only audit, at rule level. Read from the code on
mainat 7b8bcfe. No stored data was examined, and nothing was repaired or migrated.The question. How does an operator find a stored
datasourcerow whoseexternal.credentialsRefnames a reference that row did not mint? Doesos secret orphans(PR #27792) answer it?The answer: in part.
What the report covers:
datasourcerow (active, draft and inactive). It also reads the datasources the engine holds and the ones the host declares. It lists under shared each handle that more than one holder names.What it misses:
What an operator can do today.
os secret orphansin report mode and read the shared list for datasource holders.Finding for the seat. No data migration and no automatic repair is proposed. To close gaps 1 and 4 in the tooling, the narrow change is report-only:
That is a change to the CLI report, outside this card's surface.
Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
os-dev-report
{ "issue": 27818, "status": "done", "branch": "claude/project-thread-rkqt9u", "pr": "https://github.com/objectstack-ai/objectstack/pull/27860", "session": "session_016WV4d1qRCNJhpDgVXFoXkp", "premise_still_valid": true, "summary": "Item 1: the doors that make a stored datasource body the active row (rollbackMetaItem, revertCommit restore limb, and the draft publish shared by publishMetaItem and publishPackageDrafts) measured open on main fec60e00 + #27817 head 4258efac; the pin was red 15 failed | 6 passed. Each now asks #27817's judge (datasourceCredentialsRefSaveRefusal, given a door word for its wording; the save words are byte-identical) as an active write into the row it lands in: a body naming a reference that row does not hold now is refused VALIDATION_ERROR / 400 before anything is written, one answer whatever it names. The draft publish was included as the remaining write site, with the seat's agreement. Item 2: the read-only audit of rows stored before the rule is card comment 6512713420 (what os secret orphans covers and misses, the operator reading, no migration proposed). Rebased onto main 7b8bcfe2, which holds #27817 (642dd4f8).", "tests": "Unit pin src/protocol.datasource-credentials-ref-restore-doors.test.ts: 15 failed | 6 passed (21) before the fix (local commit, now cfc8e23c); 21 passed (21) after. Dogfood pin test/datasource-credentials-ref-restore-doors.dogfood.test.ts 4 passed (4); with #27817's dogfood pin 7 passed (7). metadata-protocol typecheck exit 0; whole package vitest at fd02314b 282 passed | 4 skipped files, 21842 passed | 26 skipped tests, exit 0. Unit ablations via ablation-replace (mutation landed, restore blob == HEAD): restore call never throws 10 failed | 11 passed; restore call takes the pass-through 10 failed | 11 passed; publish call never throws 5 failed | 16 passed; publish judged against the draft row 5 failed | 16 passed. Dist ablation of both call sites: rebuilt, ablation-dist-preflight markers present exit 0, dogfood pin 2 failed | 2 passed (4); restored, rebuilt, preflight --absent exit 0 with a clean tree, pin 4 passed (4).", "gates": "Local at fd02314b: node scripts/pm/dispatch-gates.mjs --ran → 73 derived, 73 run, 0 NOT-MEASURED, 0 UNRUN, exit 0 (check-plugin-teardown-shape --self-test exited 3 until its fixture commit was fetched, then 0). pnpm lint exit 0. turbo build --filter=!@objectstack/docs 114/114 exit 0. check:commit-card-trailers --range origin/main..HEAD exit 0. CI check-runs on PR #27860: in_progress at report time; the seat is told when they converge.", "dogfood_battery": "fd02314b · VERDICT command-exit 1 · Test Files 354 passed | 3 failed | 3 skipped (360) · Tests 2871 passed | 4 failed | 20 skipped (2895) · failures: error-sentences-live.dogfood.test.ts x2 and object-hook-lifecycle-scratch.dogfood.test.ts x1 (the hook-abort answer, #27806); platform-app-object-entry-views.test.ts x1 (a Setup entry names sys_exchange_rate, which neither source the test reads declares; landed in 194e66c0). All four red on main's code too: metadata-protocol src reset to merge base 7b8bcfe2, rebuilt, the three files 4 failed | 56 passed (60); tree restored (git diff HEAD empty) and rebuilt.", "line_budget": "7 files, +664 / -8: judge +42/-8, protocol-authoring-gate.ts +9/-1 (the restore call site), protocol.ts +13 (one host line, one docblock bullet, one call-site block; nothing moved), unit pin +411, dogfood pin +163, changeset +19, engine-double ledger +15.", "deviations": [ "File surface: scripts/engine-double-contract.pinned.json (+3 rows, check-engine-double-contract --write) is outside the declared surface; the gate requires the new pin's engine double.", "protocol.ts carries a docblock bullet beside the host line and the publish call-site block (no move or reflow).", "Scope: the draft publish (promoteDraftForPublish) was included as a third door, agreed by the seat at 01:17Z before the fix.", "The project context asked to assign the requester and request their review on the PR through GitHub MCP; not done: GitHub MCP writes are banned in this project and the dev may not set PR assignees.", "Commits carry the model-free trailer pair, not the harness reminder's model-named line." ], "files_changed": [ ".changeset/27818-datasource-restore-publish-credentials-ref.md", "packages/metadata-protocol/src/protocol-authoring-gate.ts", "packages/metadata-protocol/src/protocol-datasource-credentials-ref.ts", "packages/metadata-protocol/src/protocol.datasource-credentials-ref-restore-doors.test.ts", "packages/metadata-protocol/src/protocol.ts", "packages/qa/dogfood/test/datasource-credentials-ref-restore-doors.dogfood.test.ts", "scripts/engine-double-contract.pinned.json" ], "mcp_calls": "5 — GitHub MCP reads only: issue_read x3 (get #27818, get_comments #27818, get #27806), pull_request_read x2 (get #27817, get_comments #27817); no GitHub MCP write", "api_writes": "3 — relay comment #27818 (6512713420, item-2 audit), relay pr_create (#27860), relay comment #27818 (this report); plus one git push", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: the dogfood battery on main's own code — packages/qa/dogfood/test/platform-app-object-entry-views.test.ts is red (a Setup entry names sys_exchange_rate, which neither source the test reads declares; the object landed in 194e66c0) · evidence: red at fd02314b and on main's metadata-protocol code (4 failed | 56 passed across the three red files) · dedupe words: sys_exchange_rate, platform-app-object-entry-views, setup nav entry, dogfood main red", "carrier: none · noted, not filed (code read only) — the package rollback (rollbackToPackageCommit) counts a commit as reverted when revertCommit does not throw, so an item that revertCommit reports in its own failed[] is not surfaced; pre-existing for every per-item refusal of the restore limb; in PR Acceptance notes", "carrier: domain:server#3 seat · noted on the card (6512713420), not filed — the os secret orphans holder report does not list a datasource holder whose copied reference has no other holder left, nor two package rows under one datasource name sharing a handle; a report-only CLI change would close both" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia
ACCEPT → PR #27860 comment 6513611231 · 2026-10-30T02:40Z · contract review PASS 6513450055 · ready + auto-merge armed through the relay. Item 3 (the maintainer's) continues on #27884.