Skip to content

fix(authz): carry derived posture rung on ExecutionContext (#2947) - #2956

Merged
os-zhuang merged 1 commit into
mainfrom
claude/authz-2947-posture-plumb
Jul 15, 2026
Merged

fix(authz): carry derived posture rung on ExecutionContext (#2947)#2956
os-zhuang merged 1 commit into
mainfrom
claude/authz-2947-posture-plumb

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

目的

关闭 #2947 —— B2/B4 posture 阶梯(ADR-0095 D2:PLATFORM_ADMIN > TENANT_ADMIN > MEMBER > EXTERNAL)由共享 authz 解析器从 capability 授予派生(resolve-authz-context.ts:303),但两个构建 ExecutionContext 的入口都把它丢弃了,导致 enforcement 侧任何读 context.posture 的代码永远拿到 undefined(也是 explain 层不得不自己重算 posture、#2949 修补的那处分叉的根因)。

改动(全部加法、行为不变)

  • specExecutionContextSchema 新增可选 posture 字段(复用 AuthzPostureSchema,无循环依赖)。api-surface 无变化(schema 作为 const 导出,字段不计入表面)。
  • restrest-server.ts 构建 ctx 时携带 authz.posture(present 时)。
  • runtimeresolveExecutionContext 同样透传(guest → 不设,符合「仅认证主体有 rung」)。
  • testsresolve-execution-context.test.ts 断言 PLATFORM_ADMIN / MEMBER 被携带、guest 保持 unset(29 passed)。

为什么安全

行为完全保持:当前没有任何 enforcement 裁决消费 posture——是否让热路径「按 posture 裁决」是更大的 ADR 级决策,本 PR 不涉及。这里只是停止丢弃已算好的值,让 enforcement 与 explain 读到同一个派生 rung,为后续把 #2946 的「平台专属能力探针」收敛成直接读 ctx.posture 铺路。

验证

  • @objectstack/spec build ✓ · api-surface --check unchanged ✓
  • @objectstack/runtime + @objectstack/rest build(tsc typecheck)✓
  • resolve-execution-context.test.ts — 29 passed ✓
  • check:role-word ✓ · ESLint(改动文件)✓

changeset:spec: minor(新增公共字段)+ runtime/rest: patch。非破坏,无需 allow-major

关联:ADR-0095 D2 · #2949(explain 侧分叉)· #2946(未来收敛点)· tracking #2920

🤖 Generated with Claude Code

https://claude.ai/code/session_019QRUvVfpvSycAHMMF2xTxs


Generated by Claude Code

The ADR-0095 D2 posture ladder is derived once by the shared authz resolver
from capability grants, but both entry points that build the ExecutionContext
(rest-server, runtime resolveExecutionContext) dropped it — so any
enforcement-side reader of context.posture always saw undefined (the same drop
that forced the explain layer to re-derive it, #2949).

- spec: ExecutionContextSchema gains an optional `posture` field (reuses
  AuthzPostureSchema; no api-surface change — schema tracked as a const).
- rest + runtime: plumb authz.posture through when present.
- tests: assert PLATFORM_ADMIN / MEMBER are carried and guest stays unset.

Additive and behavior-preserving: no enforcement decision consumes posture yet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019QRUvVfpvSycAHMMF2xTxs
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 15, 2026 9:49am

Request Review

@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tests tooling labels Jul 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/rest, @objectstack/runtime, @objectstack/spec.

105 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/rest, @objectstack/runtime, @objectstack/spec)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/rest, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/rest, @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/rest, @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 15, 2026 09:56
@os-zhuang
os-zhuang merged commit c11e24b into main Jul 15, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/authz-2947-posture-plumb branch July 15, 2026 09:56
os-zhuang added a commit that referenced this pull request Jul 17, 2026
…nt path, no explicit deny (#3109)

Follow-through on ADR-0095: the derived posture rung is carried on the
ExecutionContext since #2956 but no enforcement decision reads it — each tier
decision re-derives principal tier from capability bits at its own site, the
divergence class behind #2946 Finding 2 (org admin crossed the tenant wall)
and #2949 (explain/enforcement posture split).

- D1: posture becomes the single tier-adjudication input (Layer 0 exemption,
  Layer 1 short-circuit tier, explain); capability probe demoted to narrowing
  fallback; behavior-preserving behind an equivalence gate in the authz matrix.
- D2: normative posture → layer action map with six invariants (TENANT_ADMIN
  never crosses Layer 0; enforcement and explain read the same carried value;
  posture selects tier, never side; never bypasses system-only write guards).
- D3: EXTERNAL rung activation chain (audience:'external' → derivePosture →
  explicit-shares-only injection), matrix cells land now, implementation
  demand-gated on an external principal type (portal track).
- D4: explicit deny/muting rejected as an adjudication primitive; needs mapped
  to capability gates / FLS / admission / validity windows; assembly-time
  muting reserved to a future permission-set-groups ADR.

Composes with ADR-0096 (admission vs tiering — orthogonal axes). Number 0099
verified free of open-PR claims before push.


Claude-Session: https://claude.ai/code/session_019QRUvVfpvSycAHMMF2xTxs

Co-authored-by: Claude <noreply@anthropic.com>
os-zhuang added a commit that referenced this pull request Jul 18, 2026
…ture rung (#3211 M2) (#3226)

The Layer 0 cross-tenant exemption gate in computeLayeredRlsFilter now
reads the carried ctx.posture rung (#2956) as authoritative: crossing the
tenant wall requires PLATFORM_ADMIN. The hasPlatformAdminPosture capability
probe demotes to a fallback for resolver-less contexts (delegated-admin
bridge, sharing service, getReadFilter consumers), where behavior is
byte-for-byte unchanged. Read and write (insert/update post-image) tenant
checks share the one decision, so they cannot drift. A probe/rung
disagreement logs an [authz/ADR-0099] defect breadcrumb and enforces the
narrower rung verdict. Retires the stale 'posture not plumbed' comment.

Security narrowing (multi-org / @objectstack/organizations only, the G1-
adjudicated deltas): a scoped admin_full_access grant (a) and a piecemeal
platform-capability grant (b) resolve below PLATFORM_ADMIN and are now
walled to their own org on private / platform-global / better-auth objects,
where the posture-blind probe used to exempt them. Fail-safe (rung is a
strict subset of the probe, ADR-0099 I3); recover with an unscoped
admin_full_access grant. Single-org / env-per-database unaffected.

authz-matrix-gate.test.ts: new ADR-0099 P1 describe (narrowing read/write,
PLATFORM_ADMIN stays exempt, TENANT_ADMIN stays walled per I1, resolver-less
fallback preserved, defect-breadcrumb on disagreement / silence on
agreement). dogfood multi-tenant-exemption-posture ledger note updated.
Docs: authorization.mdx records the unscoped-grant rule.

Verified: plugin-security 503 passed, dogfood 296 passed, build 71/71, tsc +
check:role-word + check:doc-authoring clean.

Refs #3211 · ADR-0099 / #3109 · #2946 Finding 2 · #2956


Claude-Session: https://claude.ai/code/session_01DAHp4K7FvyMPBY1DPNkmRu

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants