Skip to content

service-storage: decide who owns sys_file's reference columns (ref_*, released_ref_*), which stay writable through the data door after #27399 #27767

Closed

Description

@objectstack-fleet

domain:server#2 · os-sales · session_01L6bhgUCizoYWQVJWjhdR6F

Ruled: 6545931776 · letter A · 2026-10-31T16:18Z
Ruling-ref: 6545931776

Found by the dev of #27399 (PR #27765, os-dev-report 6510110320, out-of-scope findings). Read from the code only; no door was measured. Out of that card's scope.

What may be wrong

#27765 makes the five columns of sys_file that the storage service owns (key, mime_type, size, status, etag) unwritable outside the storage service. The reference columns that record which record and field a file belongs to (ref_object, ref_id, ref_field) and which one released it (released_ref_object, released_ref_id) are still plain fields. A caller that may write sys_file can set them through the data door. The file-reference lifecycle maintains them as the system context, and other code may trust them as the file's ownership.

Expected

Triage decides whether these columns are owned by the file-reference lifecycle like the five storage columns (readonly on the object and the same create-side guard as #27765, no new refusal), and whether anything that trusts them for access needs re-checking. Grading, including whether this is a security card, is triage's.

Re-check after #27765 merges.

Filed without domain:*; grading is triage's.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

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

    Triage: p1 · domain:server · area:access · security · 2026-10-29T22:54Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    domain:serverDomain lane — seat card indexed by label:pm:seat
    priority:p1High: required for production / M2
    on Oct 29, 2026
  3. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Claim: PM loop round 2 · 2026-10-30T01:48Z · fold head (rider: #27778, p3, which triage 6511387772 rides on the next service-storage PR after #27765) · unlocked from pm:blocked (the PR it waited on has merged)
    Session: session_016WV4cwp5DZ4B7udhhHmHzx (card thread; seat session_016WV4d1Np3hU7RQnA13YZcL)
    Account: os-elon-musk
    Branch: claude/project-thread-54508p (the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread reported it)
    Worktree: objectstack-issue-27767
    Domain: domain:server
    Seat: domain:server#4
    File surface: step 1: a read-only audit of what reads ref_object / ref_id / ref_field / released_ref_object / released_ref_id for an access or release decision (reported at rule level only, per the security dispatch rule); step 2: packages/services/service-storage/src/objects/system-file.object.ts (the reference columns readonly, and the header statement #27778 item 1 asks for), the #27765 create-side guard in packages/services/service-storage/src/sys-file-storage-owned-columns.ts (extended to the reference columns; #27778 item 2 trims its unused export), their tests, .changeset/*; ⛔ no packages/spec, no governed path, no new refusal — stop on breach and explain in the report
    Container & model: L (security audit + fix), mode:thread, model: default (TIER_DEFAULT; dispatch-gates --tier: no path-derived mandate), effort: xhigh; a CONTRACT_REVIEW_TIER review is owed before approval if the PR declares a narrowing
    Clause-②: no (narrowing — a non-system caller's write to the reference columns is taken back out, as #27765 did for the five storage columns; the dev confirms the arm from the diff)
    Metadata-protocol: none
    Responsibility: service-storage's sys_file object leaves the file-reference columns caller-writable through the data door; the platform path that covers it is #27765's readonly + create-side guard for the storage-owned columns; reached by any caller that may write sys_file.
    Thread-read: 6510433159
    Premise: holds (system-file.object.ts on origin/main ddab8b99: ref_object and released_ref_object are plain Field.text, not readonly, beside the five readonly storage columns)
    Serial constraints cleared: PR #27765 (#27399, same file) merged; no open PR touches service-storage/src/objects/system-file.object.ts or the guard; in-flight #27399 is closed. #27778 rides this PR (no behaviour change).

  4. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Waiting on the maintainer · 2026-10-30T02:03Z · ⛔ rule-level only

    Step 1 (the audit) is done and measured: readers do use the reference columns for an access decision, and the audit found no legitimate non-system writer. Under the security dispatch rule the mechanism and the options went to the maintainer through the seat, not to this board. Step 2 waits on the maintainer's word; the card thread is preparing it without pushing. The claim (6512952705) stands; the waiting party is the maintainer, since 2026-10-30T02:03Z.

  5. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#4 · os-elon-musk · session_016WV4d1Np3hU7RQnA13YZcL

    Release: session_016WV4d1Np3hU7RQnA13YZcL · 2026-10-31T05:38Z · seat 4 signs off by maintainer order; the claim (6512952705) ends here, and the card goes to the decision inbox (needs-user-decision) because step 2 waits on the maintainer's word since 2026-10-30T02:03Z (6513143786). ⛔ Rule-level only on this surface: the mechanism and the options went to the maintainer privately.
    Resume-from: the step-2 change for the recommended option is held off GitHub on purpose (security card): a patch on claude/project-thread-54508p @ 71fe17dd, kept with the seat's private materials in the maintainer's project. The resuming seat reads it there, re-reads the maintainer's ruling, merges main, re-runs the gates, and opens the PR with rule-level text only. Rider #27778 (p3) still rides the next service-storage PR.

    State: pm:dispatched → needs-user-decision; assignee cleared in this stroke.

  6. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3

    Brief-claimed-by: session_01L9qibxdiybU8ehPKBroYE3 · batch #434 · 2026-10-31T15:59Z

    Director seat (the maintainer's decisions thread, 2026-10-31). Presented to the maintainer in batch #434 (five items: #27767, #28345, #28313, #28367, and the any / or key question on PR #28380) 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.

  7. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3

    Ruling: batch #434 item 1 · letter A · maintainer 「同意」 2026-10-31T16:14Z

    Director seat (the maintainer's decisions thread). Presented in batch #434 (brief-claimed on this card at 6545756136; detailed letter in the project's decision doc, batch 3, at rule level). The maintainer answered the batch at 2026-10-31T16:12Z, verbatim: 「同意」 = every item at the seat's recommendation, which for this card is A.

    What the ruling binds (letter A, rule level only — the mechanism stays with the maintainer's private materials, per the security dispatch rule): the five file-reference columns of sys_file (ref_object, ref_id, ref_field, released_ref_object, released_ref_id) are owned by the file-reference lifecycle, exactly as #27765 ruled for the five storage-owned columns: readonly on the object and the same create-side guard extended to them; system contexts maintain them as today; no new refusal code, no spec key, no governed path. This is triage step 2 (6510433159) taken as written, now that the step-1 audit (6513143786) found readers using the columns for an access decision and no legitimate non-system writer. Not taken: B (per-reader re-checks while the columns stay writable), C (record only).

    Workload: domain:server · 1 PR · S (the step-2 patch is prepared, see the release record 6539653511) · Clause-②: no (narrowing) ⇒ one contract-review-tier review before the queue · Metadata-protocol: none · precedent #27765 (same file, same form). Rider #27778 (p3) rides the PR.

    Execution: server seat 1 (this project) resumes the card: reads the prepared patch and the maintainer's ruling from the seat-4 materials in the maintainer's project, merges main, re-runs the gates, opens the PR with rule-level text only, contract review, queue. Ruling-ref: names this comment; needs-user-decision → pm:queue is the dispatching seat's stroke.

  8. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-tesla · session_01L9qibz3ZUbZ8Qcn1rDw9yc

    Claim: resume under ruling A · card thread · 2026-10-31T16:21Z
    Session: session_01L9qibz3ZUbZ8Qcn1rDw9yc (the seat); the card thread is session_01L9qibwQbgGE61XZrK6xRjM
    Account: os-tesla (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-6wjq4y (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: 6545931776 (letter A, Tesla 「同意」 2026-10-31T16:12Z, batch #434 item 1). Triage step 2 is 6510433159 as written.
    File surface: service-storage's sys_file object and its column guard (the #27765 precedent's two files and the plugin wiring), their tests, rider #27778's invariant and unused export, and a .changeset/27767-*.md. ⛔ No packages/spec, no objectql/src/engine.ts.
    Container & model: S, mode:thread, model: opus, effort high; contract-review tier before the queue
    Clause-②: no (narrowing)
    Metadata-protocol: none
    Thread-read: 6545931776
    Premise: the dev re-measures on origin/main before any code. Public text stays at rule level.
    Serial constraints cleared: no in-flight PR of this seat touches service-storage
    Resume-from: seat 4's held patch (release 6539653511) is not on the remote. The dev re-derives it from the #27765 precedent, fresh from origin/main 630b4078d.
    Rider: #27778 rides this PR (Fixes #27778)
    Order: /mnt/project-files/server-seat-1/r2026-10-31/dispatch-27767.md (project file, not public)

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

  9. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-tesla · session_01L9qibwQbgGE61XZrK6xRjM

    os-dev-report

    {
      "issue": 27767,
      "status": "done",
      "branch": "claude/project-thread-6wjq4y",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28454",
      "session": "session_01L9qibwQbgGE61XZrK6xRjM",
      "premise_still_valid": true,
      "summary": "Ruling A taken as written: sys_file's five file-reference columns are readonly on the object, and the #27765 create-side guard drops them from a non-system create (form: a second constant SYS_FILE_REFERENCE_COLUMNS beside SYS_FILE_STORAGE_OWNED_COLUMNS, read together by one guard list, because the two lists have different owners and each keeps its own exact-five pin). No new refusal code, no spec key, no governed path, no wiring change. Rider #27778: the object header states key/status presence is the storage writers' invariant (declaration unchanged), and the guard's unused helper export is trimmed. Premise re-measured on origin/main 5517005d: 9 new narrowing cases red, lifecycle/system/#27778 pins green; the measurement stays in the seat's project files.",
      "tests": "head 7fc7033d (source identical to 2d5586fc). Targeted integration file 24/24; service-storage vitest Test Files 71/71, Tests 1326/1326; typecheck exit 0; 8 new pins. Ablations via scripts/ablation-replace.mjs, each restored to blob == HEAD: A1 readonly off ref_id => 3 red; A2 guard list without reference columns => 2 red; A3 lifecycle claim without system context => 8 red; A4 guard system early return deleted => 17 red (first try with an empty replacement was refused by the tool, re-run with --delete); A5 field copy key null => 1 red. No dist leg: the rig imports the package source.",
      "gates": "dispatch-gates --commands: 62 derived, 62 run, all exit 0, --ran reconciliation exit 0 (0 NOT-MEASURED). Four needed a prerequisite first: check-plugin-teardown-shape --self-test (exit 3 until 621a4876 fetched), check:dual-build-cjs-loads and check:i18n (exit 3 until a full dts build), check-empty-changeset (exit 1 on an edit of the pending #27399 note, edit reverted). Scoped eslint --no-inline-config on the three touched source files exit 0. CI check-runs: in_progress at report time.",
      "dogfood_battery": "7fc7033d · os-verify-lock VERDICT command-exit 0 (20m50s) · Test Files 361 passed, 3 skipped (364) · Tests 2917 passed, 28 skipped (2945) · no failures",
      "line_budget": "4 files, +211 / -9 (220 changed lines, under the 3000 threshold)",
      "files_changed": [
        ".changeset/27767-sys-file-reference-columns.md",
        "packages/services/service-storage/src/objects/system-file.object.ts",
        "packages/services/service-storage/src/sys-file-storage-owned-columns.ts",
        "packages/services/service-storage/src/sys-file-storage-owned-columns.integration.test.ts"
      ],
      "deviations": [
        "storage-service-plugin.ts untouched: no wiring change was needed.",
        "Rider #27778 rides this PR as ordered; Clause-② no (narrowing) => contract-review tier owed before the queue."
      ],
      "mcp_calls": "5 — mcp__github__issue_read x5 (27767 get + get_comments x2, 27778 get + get_comments); 0 write tools",
      "api_writes": "2 — fleet-write relay pr_create (objectstack-ai/objectstack#28454), post-stamped comment on #27767 (this report)",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: seat · noted, not filed — the pending #27399 changeset lists ownership among columns still written through the data door; if read as the reference columns, this PR's changeset supersedes it in the same release. A rewrite of that note is a release decision (check-empty-changeset), so it is left unedited.",
        "carrier: none · noted, not filed — content/docs/permissions/system-context.mdx row 47g names only the storage-owned columns for the guard's system early return; still true, incomplete."
      ]
    }
  10. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-tesla · session_01L9qibz3ZUbZ8Qcn1rDw9yc

    Landing record · #27767 (+ rider #27778) · PR #28454

    domain:server seat 1 · session_01L9qibz3ZUbZ8Qcn1rDw9yc · 2026-10-31T18:18Z

    Reading Probe Result
    Merged GET pulls/28454 merged, 7e1089e7
    Ancestry git merge-base --is-ancestor 7e1089e7 origin/main yes
    Content git grep -c SYS_FILE_REFERENCE_COLUMNS in system-file.object.ts on origin/main present (2)

    Release: claim 6546009563 (session_01L9qibz3ZUbZ8Qcn1rDw9yc, branch claude/project-thread-6wjq4y) · landed, cards 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:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain: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