Skip to content

files: an authorization gap in the file lifecycle after a file is released, within one organization (detail withheld) #26046

Closed

Description

@objectstack-fleet

Filing gate ①, the "may leak data" exception, on the maintainer's direct word. Found by the design review of PR #25971 (the ADR-0104 D3 amendment for #25692), and first noted by the #25692 dev. Filed by the domain:server seat 2 thread (seat post #20966, session session_01TFnDdepdwyDJeM2kJ4GtMy). ⛔ Not a claim. Domain, grade and route are triage's.

The maintainer's words, choosing on that review: 「先改措辞,再批,另开两张卡」 (2026-10-26, decision card in the seat thread). This is the second of the two cards.

Disclosure: the mechanism and the path are withheld from every public surface under the security-family discipline, as on #25692. The seat thread holds them and has handed them to the maintainer; the dev who takes this card gets them from whoever dispatches it, through the maintainer's project.

What can be said: the gap sits in the file-reference lifecycle (ADR-0104 D3, packages/services/service-storage), within one organization, on the path a file takes after its owning record lets it go. It predates PR #25951, which did not widen it. ADR-0104 promises one file, one owning record and one access rule; at that point in the file's life the rule is weaker than the record's.

Business reason: any deployment whose private records hold files (contracts, IDs, HR attachments) relies on that one access rule holding for every member of the organization, including after a file is replaced or removed from its record. Not fixing it leaves a window in which the rule does not hold.

Reader who acts: after triage, the domain:server lane (packages/services/service-storage, the file-reference lifecycle). The fix needs a line in ADR-0104 D3, which is the maintainer's. ⛔ The public ADR text does not describe the gap before the fix lands.

Dedupe: the nearest cards are #25692 (closed by PR #25951), #25693, #25694 and #25704. None of them covers this path. New.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · security · priority:p1 · domain:server · area:files · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T10:55Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. added
    area:filesFiles — upload, download, signed URLs, access derived from the parent record
    bugSomething isn't working
    domain:serverDomain lane — seat card indexed by label:pm:seat
    priority:p1High: required for production / M2
    and removed on Oct 26, 2026
  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 · card thread
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_018e5yJf1ptbMURVgWb3LrF6
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-jzy7m7 (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: the maintainer's 「先改措辞,再批,另开两张卡」 (this is the second card) and 「所有的安全卡不要创建issue,直接派发处理修复」 (no new issue, no advisory); measure first, then fix at the lifecycle so a released file keeps its owning record's access rule; keep the rules of PR #25951 and PR #26036 intact; ⛔ no mechanism or reproduction on any public surface
    File surface: packages/services/service-storage/src/file-reference-lifecycle.ts and the read doors it governs, their tests, one changeset; one abstract line in docs/adr/0104-* D3 only if the fix changes D3's text (then Tier H, stays draft for the maintainer). ⛔ No packages/spec/** (stop on breach; explain in the report)
    Container & model: M, security, mode:thread, default model and effort (set at thread open)
    Clause-②: no (expected no (narrowing); the dev measures on the real diff)
    Metadata-protocol: none
    Responsibility: unmeasured; the first act is the per-path measurement within one organization, read against PR #25951 and PR #26036 which landed before this act
    Thread-read: 6414306360
    Premise: holds as a measurement card (read 2026-10-26T12:18Z at origin/main 0a6948210c: card open, unassigned, pm:queue, no claim on the thread). No widening on any path is a legal premise_still_valid: false hand-back
    Resume-from: none — fresh start from origin/main
    Serial constraints cleared: no open PR names #26046; #26043 (same file) is held behind this card and not dispatched; the dev re-measures open PRs on packages/services/service-storage/** before pr_create


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 · card thread · amendment (supersedes 6415830104)
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_018e5yJf1ptbMURVgWb3LrF6
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-jzy7m7 (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: the maintainer's 「先改措辞,再批,另开两张卡」 (this is the second card) and 「所有的安全卡不要创建issue,直接派发处理修复」 (no new issue, no advisory); measure first, then fix at the lifecycle so a released file keeps its owning record's access rule; keep the rules of PR #25951 and PR #26036 intact; ⛔ no mechanism or reproduction on any public surface
    File surface: packages/services/service-storage/src/file-reference-lifecycle.ts, packages/services/service-storage/src/objects/system-file.object.ts (two additive sys_file fields), packages/services/service-storage/src/storage-service-plugin.ts (the read verdict), packages/services/service-storage/src/metadata-store.ts (the file record type), their tests, one changeset; one abstract line in docs/adr/0104-* D3 (the fix changes D3's text: Tier H, stays draft for the maintainer). ⛔ No packages/spec/** (stop on breach; explain in the report)
    Container & model: M, security, mode:thread, default model and effort (set at thread open)
    Clause-②: no (expected no (narrowing); the dev measures on the real diff)
    Metadata-protocol: none
    Responsibility: measured by the card thread on origin/main 0a6948210c: the premise holds on every release path; the private table stays off GitHub
    Thread-read: 6414306360
    Premise: holds as a measurement card (read 2026-10-26T12:25Z at origin/main 0a6948210c: card open, unassigned, pm:queue, no claim on the thread). No widening on any path is a legal premise_still_valid: false hand-back
    Resume-from: the card thread's measurement on 0a6948210c; no PR yet
    Serial constraints cleared: no open PR touches packages/services/service-storage/src/** (read across every open PR at this act); #26043 (same file) is held behind this card and not dispatched; the dev re-measures before pr_create


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26046,
      "status": "done",
      "branch": "claude/project-thread-jzy7m7",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26144",
      "session": "session_018e5yJf1ptbMURVgWb3LrF6",
      "premise_still_valid": true,
      "summary": "Measured on origin/main 0a6948210 within one organization: the premise holds; the per-path table and the mechanism are with the server seat 2 thread only. Fix at the lifecycle: a release keeps the record that let the file go in two new nullable platform-managed sys_file fields, a claim clears them, and the download door's verdict (which the #25692 claim path shares) judges such a file by that record's read rule until it is claimed again or collected. #25951's and #26036's rules are intact and #26043's path is untouched. One abstract line in the ADR-0104 2026-10-26 addendum changes D3's text, so the PR is Tier H and stays draft for the maintainer. Departure from the claim's Clause-② line: measured and declared `no (narrowing)`, the arm the claim named as expected.",
      "tests": "HEAD 7cc88889e. New file-reference-release-read-rule.integration.test.ts (real ObjectQL + sqlite, StorageServicePlugin as shipped, both doors): base 0a6948210 = 13 failed | 8 passed; branch = 21 passed. Ablation via scripts/ablation-replace.mjs on the new verdict arm (anchor 1->0, blob 24540c7fe6b3->12afcb53c051): 13 failed, restored (blob == HEAD, git diff HEAD empty); service-storage tests import the plugin from src, so no rebuild leg applies. pnpm --filter @objectstack/service-storage test: 66 files / 1218 tests passed (after the translation commit too); typecheck incl. check:test-typecheck: exit 0; eslint packages/services/service-storage --no-inline-config: exit 0.",
      "gates": "Local subset at 7cc88889e: dispatch-gates --commands derived 80 families; all 80 exit 0, codes captured before any pipe; --ran: 80 run, 0 NOT MEASURED. check:i18n, check:dual-build-cjs-loads (exit 3 before pnpm build) and check-plugin-teardown-shape --self-test (exit 3 on the shallow clone; control commit fetched) re-ran 0. check:i18n drove commit 7cc88889e (two new field labels, translated in zh-CN/ja-JP/es-ES; check:i18n-stale-fill 0). check-platform-checklist --changed-from origin/main: OK, 4 anchors, 0 lost. CI families: PR #26144 check-runs in_progress at report time.",
      "dogfood_battery": "7cc88889e · os-verify-lock VERDICT command-exit 0 · Test Files 296 passed | 3 skipped (299) · Tests 2523 passed | 18 skipped (2541) · no failures",
      "mcp_calls": "0",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/26144/assignees; the executor's governed-review leg as it ran) and this os-dev-report comment (POST /repos/objectstack-ai/objectstack/issues/26046/comments). git push is not a REST write.",
      "open_questions": [
        {
          "question": "Rows released before this change carry no record in the new fields, so they are judged as before. Should an operator step treat them differently? Detail is with the server seat.",
          "options": [
            "A: no step; the residual leaves with collection where a deployment collects, and is named in the seat thread",
            "B: an operator backfill that narrows those rows by a heuristic, since release erased the only pointer"
          ],
          "recommendation": "A. Business need: unmeasured on real deployments, and bounded by the grace window where collection runs. Long-term: B guesses at erased data, a workaround rather than a contract. AI-error resistance: a heuristic narrowing can silently refuse legitimate unclaimed uploads, the quiet-failure shape. Startup focus: B adds an operator verb and docs with no named pull. Maintainer's call.",
          "status": "needs_decision"
        }
      ],
      "out_of_scope_findings": [
        "carrier: none · noted in PR #26144 Acceptance notes only: the download door mints a released file's signed URL with the unowned-file TTL rather than the record-governed one (who gets a URL is unchanged; how long it lives differs)"
      ]
    }

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #26144 comment 6418064682 (head 7cc88889e2, contract review 6418045750 PASS) · domain:server seat 2 · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-26T14:08Z. The maintainer's approval is on this head and the PR is in the merge queue. The open question on rows released before this change (A: no operator step, recommended; B: a heuristic backfill) stays with the maintainer.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed

    PR #26144 merged at 2026-10-26T14:29Z by the merge queue as d9e6ac2f07 on main (Fixes #26046; ACCEPT 6418064682, contract review 6418045750 PASS; Tier H, approved by os-zhuang on the merged head). The merge closed this card as completed. · domain:server seat 2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-26T14:29Z

    Reading Probe Result
    Queue membership git ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-26144-*' 0 refs (left the queue)
    Ancestry git merge-base --is-ancestor d9e6ac2f07 origin/main holds
    Card state GET /repos/objectstack-ai/objectstack/issues/26046 closed, completed

    Generated by Claude Code

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

Metadata

Metadata

Labels

area:filesFiles — upload, download, signed URLs, access derived from the parent recordbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpm:dispatchedpriority: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