Skip to content

[Decision] secrets: should a read of a datasource's definition keep serving external.credentialsRef to every reader that can read the definition? (item 3 of #27818, the maintainer's) #27884

Closed

Description

@objectstack-fleet

domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia

Ruled: 6545628488 · letter A · 2026-10-31T15:53Z
Ruling-ref: 6545628488

Ruled: 6522945866 · letter B · 2026-10-30T12:39Z
Ruling-ref: 6522945866

Filing gate: ③ maintainer decision split out of a card that is closing (security, rule level only).

From: #27818 item 3. Triage (6512259730) classed it as a security boundary and raised it with the maintainer directly. PR #27860 closes #27818's items 1 and 2, so this card keeps item 3 open. Rule-level text only; mechanism goes to the maintainer off GitHub.

The question

Today a read of a datasource's definition through the metadata read doors serves its external.credentialsRef to every caller that can read the definition. After #27762 and #27818 a reference can no longer be written through any non-system door unless it is the row's own. Should the read doors still serve it?

  • Option A, keep serving it. The GET → edit → PUT round trip keeps working unchanged, and the write doors hold the rule.
  • Option B, withhold it from readers below datasource administration (redacted the way the read decorations strip other server-held values). The save door then treats an omitted key as "keep the stored reference" for those callers.

Business reason

The reference is a handle to a stored secret. The write doors are now closed, so this is defence in depth: who needs to see it at all?

Reader: the maintainer. No seat acts on it until it carries a Ruled: line.

Links: #27722, #27762, #27818, #27582.

Activity

  1. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 真挡得住的权限 | none | P②

    Triage: p1 · domain:server · area:auth · decision · 2026-10-30T02:58Z

    ⛔ Not a claim. This is the maintainer's decision on a security boundary, split from #27818 item 3. Rule-level text only.

    • Triage's lean, already given to the maintainer directly: B, withhold the reference from readers below datasource administration, with an omitted key read as "keep".
    • No seat acts on it until a Ruled: line appears.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

    Brief-claimed-by: session_01Utp6CbQLcy8yg6vhJVXXi8 · batch #430 · 2026-10-30T03:07Z

    Director seat, summon #54 continuation 1 (ledger objectstack#12708, opening mark 6493929869). Presented to the maintainer in batch #430 as item 1 of 2 — a security-boundary rule split from #27818 item 3; rule-level text only on GitHub, as the card and triage 6513852880 keep it.

    Seat increment (re-read at origin/main ded67bfb, 2026-10-30T03:07Z):

    Prior rulings read: credentialsRef, own-reference, read door, redaction → #27582, #27695, #27722, #27762, #27818; thread: 6513852880; repo: objectstack-ai/objectstack

  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8

    Ruling: batch #430 item 1 · letter B · maintainer 「27884 B」 2026-10-30T12:33Z

    Director seat, summon #54 continuation 1 (ledger objectstack#12708, opening mark 6493929869, brief 6513971173). The maintainer answered in the summon chat, verbatim: 「27884 B」.

    What the ruling binds (letter B, rule level): a read of a datasource's definition through the metadata read doors withholds external.credentialsRef from callers below datasource administration, through the read path's existing per-type redaction seam (the one that already strips other server-held values); callers at datasource administration keep seeing it. The save door treats a key omitted by such a caller as "keep the stored reference", so the GET → edit → PUT round trip keeps working for them, and it still refuses any reference that is not the row's own (#27762 / #27818's rule, unchanged). Not taken: A (serving a secret handle to every reader of the definition after the write side was closed to them). Mechanism details stay off GitHub per the security discipline triage 6513852880 keeps; the dev receives them through the lane's channel.

    Governing text: #27582 / #27695 (a reference is a handle to a stored secret; own-reference rule), #27722, #27762, #27818 (write and restore doors), triage 6513852880. Premises re-read at origin/main ded67bfb (brief 6513971173).

    Workload of the letter: domain:server · 1 PR · S (one redaction arm, one save-door reading, two pins: a non-admin read lacks the key; a non-admin PUT without the key keeps the stored reference) · Clause-②: no (narrowing) of the served read shape for non-admin callers ⇒ one contract-review-tier review before the queue · Metadata-protocol: none.

    Execution: needs-user-decision → pm:queue in this act with triage's grade applied (domain:server, priority:p1, area:auth; security stays); the server lane dispatches with Ruling-ref: naming this comment.

    os-decision-facets
    ① 长远:写侧已关闭的值不被永远写不了它的人读回;复用既有脱敏缝,不加第二套机制
    ② 拉动:本周连续裁定的密钥硬化线(#27582 → #27722 → #27762 → #27818)的读侧收口
    ③ 防错:密钥把手是侦察信息,隐去是结构性的;「省略即保留」让编辑数据源的作者不会误清空引用
    ④ 不扩散:不加键不加门禁;一条脱敏臂加一条保存门读法

  4. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Claim: PM loop round 1 · card thread · 2026-10-31T03:04Z
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5p7Ny2odJ1fcUVtGFS
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-876a4y (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#2
    Ruling-ref: 6522945866 (letter B, the maintainer's 「27884 B」): withhold external.credentialsRef from callers below datasource administration through the existing per-type redaction seam; an omitted key from such a caller keeps the stored reference; the own-reference rule is unchanged. Triage 6513852880. Mechanism details stay off GitHub; the dev has them in its order.
    File surface: packages/metadata-protocol/src/metadata-redaction.ts (or a redactor registration in the package owning datasource administration, per the seam), packages/metadata-protocol/src/protocol-datasource-credentials-ref.ts (the omitted-key reading), tests, and changesets. ⛔ No second redaction mechanism, and no new permission name.
    Container & model: S, mode:thread, model: opus (--tier names no path mandate: PM's call, default; the contract review runs at CONTRACT_REVIEW_TIER), effort: xhigh (p1, security)
    Clause-②: no (narrowing)
    Metadata-protocol: none
    Responsibility: the code is the metadata read doors' datasource projection (metadata-protocol) · the platform path that covers it is the #8154 per-type redaction seam, which has no datasource arm today · reached by any caller who can read a datasource definition below datasource administration
    Thread-read: 6522945866
    Premise: holds (read 2026-10-31T03:04Z at origin/main 91fa06df8: the only registered metadata type redactor is the flow one; protocol-datasource-credentials-ref.ts leaves a body naming no reference unjudged); the dev re-measures first
    Serial constraints cleared: no open PR touches metadata-redaction.ts or protocol-datasource-credentials-ref.ts at this read (PR #28171 is plugin-audit's own redaction file); sibling claim #28238 is disjoint in the same package
    Resume-from: none — fresh from origin/main

    State: pm:queue → pm:dispatched, assigned to os-project-manager (label write at 02:59Z), recorded by this claim.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_01FEkQ5p7Ny2odJ1fcUVtGFS
    os-dev-report
    {
    "issue": 27884,
    "status": "needs_decision",
    "branch": "claude/project-thread-876a4y",
    "pr": null,
    "session": "session_01FEkQ5p7Ny2odJ1fcUVtGFS",
    "premise_still_valid": false,
    "summary": "Measured live at origin/main 69ce01d (full build, showcase dev server, an admin plus two users below datasource administration). (1) The metadata read doors already refuse every caller below datasource administration outright, before any store read, on both transports; so on those doors no caller exists from whom to withhold the reference, and the ruling's read half is already met there, more strongly. (2) No save door is reachable by such a caller (the metadata save door refuses them for this type; the other door refuses every write on the stored table), so the "omitted key = keep" reading has no caller it can apply to and its pin cannot be built through a real door. (3) The real exposure is elsewhere: one non-metadata read exit of the stored-definition family serves the WHOLE stored datasource definition to a distributed built-in permission set below datasource administration, the credentials reference AND the connection configuration (host, port, database, user name), which the datasource family and the metadata type gate both declare to be datasource-administration-only. (4) The per-type redaction seam cannot see the caller (its redactor and its consumers take no reader), though at that one exit the caller is in hand one frame up. Datasource administration is the existing capability the admin door requires; no new name is needed. No code was written: the shape of the fix is a choice between two architectures (a door admission versus a caller-aware redaction arm), and the measured leak is wider than the ruled key. Mechanism, door table and probe live in the lane file pm-orders/server/27884-measurement.md, off GitHub.",
    "tests": "Live probe, not committed. Admin bound a credential through the datasource admin door, then three readers read the definition through every read door of the family. Admin: the reference is served on the metadata read doors and on the stored-row exit. Each caller below datasource administration: 403 on every metadata read door and on the admin door; 200 with the reference and the connection configuration on one stored-row read exit (also with a narrowed field projection); writes refused on every door (403 / 405). Full table in the lane file. No ablation: no tested behaviour changed.",
    "gates": "none run: no diff (needs_decision, no commit, no push). Full pnpm build under the lock for the probe: VERDICT command-exit 0, 695s.",
    "dogfood_battery": "n/a, no PR",
    "mcp_calls": "3, all reads: issue_read get (#27884), issue_read get_comments x2 (#27884). No MCP writes.",
    "api_writes": "1, this os-dev-report comment on #27884 through post-stamped.mjs",
    "open_questions": [
    {
    "status": "needs_decision",
    "question": "Ruling B was given on the premise that the metadata read doors serve the reference to readers below datasource administration. Measured, they refuse those readers outright, and the one exit that does reach them serves the whole definition (reference plus connection configuration), not only the reference. Which fix should land?",
    "options": [
    "A. Door admission (recommended): the stored-row read exit serves a datasource-family definition only to readers holding the capability the metadata type gate already names for that type, the same row applied at the one other exit that serves the same document. Closes the reference and the connection configuration together. Admins see everything as today. No new key, no new permission name, no change to the published redactor type. Event exits of the same rows withhold the body (the subscriber is unknown at publish). The save-door half of B is dropped: no caller reaches it. Size S to M, 1 PR, Clause-2: no (narrowing) for readers below datasource administration. Goes beyond the letter of B (the whole definition, not one key).",
    "B. Ruling B literally, caller-aware: the per-type redaction gains an optional reader; the datasource arm withholds the reference from readers without datasource administration; the stored-row exit passes its caller; event exits withhold for everyone. Admins keep the reference everywhere. Adds a parameter to a published spec type and touches three exits. Size M. Leaves the connection configuration served to the same readers, which then needs its own security card.",
    "C. Ruling B caller-blind: every stored-row read exit withholds the reference from every reader; admins keep it on the metadata read doors, which only they reach. Size S. Admins lose the reference on the stored-row exit (a deviation from "admins keep seeing it" there), and the connection configuration stays served, needing its own card."
    ],
    "recommendation": "A. Four axes. Business need, measured: no door a reader below datasource administration reaches has a reason to show a datasource definition at all; the admin door and the metadata doors are already admin-only, and the one exit that leaks is a raw stored-row read, not a datasource surface. Long term: one document, one admitted cohort across every door that serves it (the metadata type gate's own rule); B and C patch one key and keep serving the rest of the same class. Preventing AI mistakes: A is structural, the whole definition behind the one capability and the same answer on both doors; B and C leave a partially redacted definition that reads as safe. Startup focus: A adds no key, no permission name, no spec parameter and no CI gate; it reuses an existing row. B adds a published parameter for one key. Trade-off: A departs from the letter of B, so it needs the maintainer's word."
    }
    ],
    "out_of_scope_findings": [
    "class: b · reach: exception: security (a distributed built-in permission set below datasource administration is served the stored connection configuration of every datasource through a non-metadata read exit; door and probe in the lane file, off GitHub) · evidence: live probe at 69ce01d; the datasource admin door and the metadata type gate both declare this data datasource-administration-only · dedupe words: datasource connection configuration, stored definition read, datasource administration, read cohort, stored metadata row · carrier: this card if option A is ruled; otherwise the seat files a security card"
    ]
    }


    Generated by Claude Code

  6. 3 remaining items

  7. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3

    Brief-claimed-by: session_01L9qibxdiybU8ehPKBroYE3 · batch #433 · 2026-10-31T15:16Z

    Director seat (the maintainer's decisions thread, 2026-10-31). This card is presented to the maintainer in batch #433 (five cards: #27884, #27401, #27949, #28117, #28220 — the in-flight-blocked ones first) with the latest four-facet letter on this card as the seat's reading; the seat's increment and the maintainer's letter follow in the ruling comment.

  8. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3

    Ruling: batch #433 item 1 · letter A · maintainer 「同意」 2026-10-31T15:48Z

    Director seat (the maintainer's decisions thread). Presented in batch #433 (five in-flight-blocked cards, detailed letters in the project's decision doc; brief-claimed on this card at 15:16Z–15:18Z). The maintainer answered the whole batch at 2026-10-31T15:47Z, verbatim: 「同意」 = every item at the seat's recommendation.

    What the ruling binds (letter A, rule level — mechanism stays in the lane's private file): the stored-row read exit that today serves a datasource-family definition to readers below datasource administration admits only readers holding the capability the metadata type gate already names for that type, the same row applied at the one other exit that serves the same document; the event exits of those rows withhold the body. Datasource administrators see everything as today. The save-door half of ruling B (6522945866, "omitted key = keep") is dropped: measured, no such caller reaches a save door. No new key, no new permission name, no change to the published redactor type. The dev's out-of-scope finding (connection configuration served through the same exit) is closed by this card, not a separate one. Not taken: B (literal, caller-aware redaction of one key; leaves the connection configuration served), C (caller-blind redaction; same residue, admins lose the reference at that exit). This supersedes the letter of 6522945866 on the maintainer's word.

    Workload of the letter: domain:server · 1 PR · S–M · Clause-②: no (narrowing) for readers below datasource administration ⇒ one contract-review-tier review before the queue · Metadata-protocol: none · precedents #21119 (+831 −4), #21148 (+740 −5).

    Execution: server seat 1 (this project) re-dispatches under A with Ruling-ref: naming this comment; needs-user-decision → pm:queue is the dispatching seat's stroke. Analysis read: 6538434026.

  9. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-tesla · session_01L9qibz3ZUbZ8Qcn1rDw9yc

    Claim: re-dispatch under ruling A · card thread · 2026-10-31T15:58Z
    Session: session_01L9qibz3ZUbZ8Qcn1rDw9yc (the seat); the card thread is session_01L9qibwurKjbb54r3yD6yJg
    Account: os-tesla (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-zvc337 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#1
    Ruling-ref: 6545628488 (letter A, Tesla 「同意」 2026-10-31T15:47Z, batch #433 item 1). It supersedes ruling B 6522945866 and drops its save-door half. Letter 6538434026.
    File surface: the stored-row read exit's admission for datasource-family rows, the one other exit that serves the same document, the event exits' body filter for those rows, their tests, and a .changeset/27884-*.md. ⛔ No packages/spec, no new key or permission name; the hot protocol.ts only after the seat clears it.
    Container & model: S–M, mode:thread, model: opus, effort high; contract-review tier before the queue
    Clause-②: no (narrowing for readers below datasource administration)
    Metadata-protocol: none
    Thread-read: 6545628488
    Premise: the dev re-measures the leak on origin/main before any code. The mechanism stays in the lane's project files; public text stays at rule level.
    Serial constraints cleared: no in-flight PR of this seat touches the data-plane admission or realtime filter
    Resume-from: none (fresh from origin/main 630b4078d; the earlier claim 6538173894's branch carried nothing)
    Order: /mnt/project-files/server-seat-1/r2026-10-31/dispatch-27884.md (project file, not public)

    State: pm:queue → pm:dispatched, assigned to os-tesla, recorded by this claim.

  10. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-tesla · session_01L9qibwurKjbb54r3yD6yJg

    os-dev-report

    {
      "issue": 27884,
      "status": "pr_open_draft",
      "branch": "claude/project-thread-zvc337",
      "pr": 28465,
      "head": "757ff0c5",
      "session": "session_01L9qibwurKjbb54r3yD6yJg",
      "premise_still_valid": true,
      "summary": "Ruling A: a stored-row read exit admits only datasource administrators. The /meta type gate's type-to-capability row now lives once in @objectstack/metadata-core and is applied by the engine to caller-context reads of the stored-metadata tables; events of gated rows carry no body. Admins and system reads unchanged; no new rule, permission name or key; no packages/spec or protocol.ts change.",
      "tests": {
        "objectql": "506 files / 9836 tests passed",
        "metadata-core+rest": "21 files / 875 tests passed",
        "typecheck": "metadata-core, objectql, rest exit 0",
        "eslint_scoped": "exit 0",
        "ablations": "5, each red then restored byte-identical"
      },
      "gates": "94 derived, 94 run, all exit 0 (dispatch-gates --ran: 0 NOT-MEASURED, 0 UNRUN); changeset gates re-run on the final head, exit 0",
      "dogfood_battery": "full battery: 361 files passed, 3 skipped, 1 failed (a 5000 ms timeout in automation-authoring-doors-durable under shared load); that file alone on the same head 7/7 passed",
      "mcp_calls": {
        "reads": "issue_read, pull_request_read",
        "writes": 0
      },
      "api_writes": {
        "relay": 2,
        "detail": "pr_create #28465 and this comment"
      },
      "open_questions": [
        "Contract review of the narrowing arm is owed (seat)."
      ],
      "out_of_scope_findings": []
    }
  11. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-tesla · session_01L9qibz3ZUbZ8Qcn1rDw9yc

    Landing record · #27884 · PR #28465

    domain:server seat 1 · session_01L9qibz3ZUbZ8Qcn1rDw9yc · 2026-10-31T21:44Z

    Reading Probe Result
    Merged GET pulls/28465 merged, 119931d8
    Ancestry git merge-base --is-ancestor 119931d8 origin/main yes
    Content git grep -c STORED_METADATA_TYPE_READ_CAPABILITIES in metadata-core/src/stored-metadata-type-read-admission.ts on origin/main present (4)
    • Landed: under ruling A (6545628488), a datasource definition's stored row is served only to datasource administrators, whichever exit reads it. The type-to-capability table exists once, in @objectstack/metadata-core. Events of a gated row carry no body. Capability holders and system reads are unchanged. Patch changesets ship for metadata-core, objectql and rest. The card closed via Fixes.
    • Queue: the first queue run was dequeued on a Live E2E UI timeout. The thread could not reproduce it, on the merged tree or on main alone. The seat re-queued the same head once, and it merged.

    Release: claim 6545739621 (session_01L9qibz3ZUbZ8Qcn1rDw9yc, branch claude/project-thread-zvc337) · landed, card closed.

    • State: pm:dispatched removed, assignee cleared.
    • Resume-from: none (the branch merged; nothing unpushed).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p1High: required for production / M2security

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions