Skip to content

test: pin that a guest request reaches create hooks as a named caller - #30179

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/sec-hardening-g2
Nov 4, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/sec-hardening-g2

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

维护者速读

  • 改了什么:只加测试,三处钉住同一条规则——经访客入口进来的请求,在创建钩子看来始终是"有调用者"的请求,不会被当成内核内部的无上下文调用。
  • 为什么改:这条规则此前只靠阅读成立,没有任何测试守住;访客信封里那个让引擎生成会话的字段一旦在重构中丢掉,不会有测试变红。
  • 风险与回滚:零运行时改动(三个 *.test.ts,发布产物字节不变);回滚即 revert 本 PR。
  • 先看:packages/objectql/src/engine-execution-plumbing.session-locale.test.ts(会话那一跳的钉子)、packages/services/service-storage/src/attachment-access-hooks.test.ts(整机引擎创建被拒)、packages/core/src/security/assemble-execution-context.test.ts(信封端)。
  • 两分钟验证:pnpm --filter @objectstack/service-storage exec vitest run src/attachment-access-hooks.test.ts -t "guest request",预期 2 passed。
  • 需要你做的:无,席位落地。

What changes

Test-only. One rule, pinned at three layers: a request served through the guest entry reaches create hooks as a named caller, so it is never read as a context-less (bare-kernel) engine call.

  • @objectstack/core — the guest envelope keeps the guest position under every input a face can pass for an anonymous request (no tenant / no grants, and guest-anchor grants in an organization).
  • @objectstack/objectql — buildSession of the envelope the real assembleExecutionContextOrGuest produces is defined and names no user (and is not the system arm); a control pins that an envelope naming nothing the session copies yields no session.
  • @objectstack/service-storage — through the wired engine (real ObjectQL + the installed attachment hooks), a create of sys_attachment under the real guest envelope is refused 403 RECORD_NOT_ACCESSIBLE and writes no row; control: the same create by a signed-in caller resolves and stamps that caller as the uploader.

New pins are top-level describe blocks in each component's existing test file. No product code changes, so skip-changeset: none of the three packages' files[] (dist, README.md, CHANGELOG.md) changes — the new test titles have zero hits in the three dist/ trees while assembleExecutionContextOrGuest (positive control) hits packages/core/dist/index.js.

Tests

All on head 36bffe5b4c.

Changed files and package suites
  • Changed files, one worker each: core assemble-execution-context.test.ts 212/212, objectql engine-execution-plumbing.session-locale.test.ts 5/5, service-storage attachment-access-hooks.test.ts 153/153; each new test confirmed by name under --reporter=verbose.
  • Package suites under os-verify-lock.sh: core 133 files / 2974 tests passed; service-storage 71 / 1329 passed; objectql 548 / 10846 passed; each exit 0.
  • typecheck for core, objectql, service-storage: exit 0 (each package's check:test-typecheck OK).
One-shot ablation: drop the guest position from the guest envelope

Mutation via scripts/ablation-replace.mjs on packages/core/src/security/assemble-execution-context.ts: the guest arm of positions replaced with an expression that evaluates to undefined (anchor 1 to 0, blob 442040f156df to 0039cf95db86). core rebuilt under the lock; ablation-dist-preflight found the marker in dist/index.js and dist/index.cjs.

  • core (source): exit 1, both new pins red, alongside the existing frozen-transcription parity pins.
  • service-storage (core aliased to source): exit 1, exactly the new refusal pin red; its control stayed green.
  • objectql (core through dist/): exit 1, exactly the new session pin red (expected undefined to be defined); its control stayed green.

Restore: blob equals HEAD, git diff HEAD empty; core rebuilt, --absent preflight clean over 14 built files, objectql file green again (5/5).

Acceptance notes

  • buildSession treats an empty positions: [] as present (its presence test is !== undefined), so the identification hinges on the key being emitted at all, not on its contents; the pins assert the guest value, which is the declared vocabulary.
  • The existing core parity pin (toEqual on the guest envelope) already went red under the ablation; the new pin names the rule so the reason survives a future edit of that frozen transcription.

Verification

Gate derivation and reconciliation

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 57 commands for the 3 changed paths. All 57 run, exit codes captured before any pipe; --ran reconciliation: "57 derived famil(ies) accounted for — 55 run, 2 NOT-MEASURED".

  • 55 exit 0.
  • NOT MEASURED (exit 3, PREREQUISITE NOT MET): pnpm check:dual-build-cjs-loads (needs every package's dist/) and pnpm check:i18n (needs the CLI build closure). Neither reads test files; CI's Lint & Repo Gates runs both on a full build.
  • Repo-wide scans and test:repo are left to CI.

Generated by Claude Code

The guest entry's envelope must keep a caller field the engine's session
hop copies, so a create hook that skips context-less engine calls never
reads an anonymous request as one. Three pins, test-only:

- core: the guest envelope keeps the guest position under every face input;
- objectql: buildSession of the real guest envelope is a session naming no
  user, with a control that an envelope naming nothing yields none;
- service-storage: through the wired engine, a guest-context create of an
  attachment is refused 403 RECORD_NOT_ACCESSIBLE and writes no row.

Claude-Session: https://claude.ai/code/session_01QSeKYn5CmmdShCJifm6WYj
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 4, 2026
@github-actions github-actions Bot added the size/m label Nov 4, 2026
@github-actions

github-actions Bot commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 59e64635f4a6bf03ecbe17afb63b8af5908eb2f9 → packageMentionDocs.

@github-actions github-actions Bot added the tests label Nov 4, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

security#1 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj

席位核对

ACCEPT · head 36bffe5b4c24a66574bd11b5ac9a558a8eeafd6d · 2026-11-04T21:25Z

  • Shape: 3 files, +128, test-only. Not governed. skip-changeset.
  • What it pins: a guest request reaches create hooks carrying a session, so an anonymous create is never handled as a bare-kernel call.
    • buildSession of the real guest envelope is defined and carries no user.
    • The guest envelope keeps its session-bearing field for every face.
    • A guest create of sys_attachment through the wired engine is refused, and no row is written.
    • Controls: an envelope with only principalKind gives no session, and a signed-in create still stamps.
  • Review: the seat's own read at TIER_DEFAULT. No contract face, no product code.
  • Evidence:
    • Touched packages' full suites green: core 2974, objectql 10846, service-storage 1329.
    • One-shot ablation dropping the guest position: each new pin goes red in its package and its control stays green. Restored and verified.
    • dispatch-gates --ran: 57 derived, 55 run, 2 NOT MEASURED, both covered by CI's Lint & Repo Gates.
  • Check-runs at this head (latest per name): 9 skipped, 54 success. mergeable_state: clean.
  • Landing: ready, then auto-merge.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 4, 2026 21:27
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 4, 2026
Merged via the queue into main with commit 968d645 Nov 4, 2026
69 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/sec-hardening-g2 branch November 4, 2026 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant