Skip to content

feat(security): enforce OWD posture on the runtime write path (#3050) + flip 10 verified ADR statuses#3052

Merged
os-zhuang merged 2 commits into
mainfrom
claude/auth-model-design-eval-xxgzcl
Jul 16, 2026
Merged

feat(security): enforce OWD posture on the runtime write path (#3050) + flip 10 verified ADR statuses#3052
os-zhuang merged 2 commits into
mainfrom
claude/auth-model-design-eval-xxgzcl

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Summary

Two commits, both follow-ups from the #2557 re-evaluation session:

1. OWD posture authoring gate — closes #3050

The two OWD posture rules were CLI-lint-only (validateSecurityPosture runs at os compile/os lint, never on saveMetaItem), leaving the runtime write path unguarded (ADR-0049 violation):

  • With OS_METADATA_WRITABLE=object, an environment overlay could widen a packaged object's sharingModel from private to public_read_write with zero validation.
  • externalSharingModel ≤ sharingModel (ADR-0090 D11) existed only as .describe() prose + a lint rule — never enforced at runtime.

Fix, at the right layers:

  • metadata-protocol — implements the ADR-0094-addendum registerAuthoringGate(type, gate) seam: an awaited, throwing pre-persistence hook inside saveMetaItem (after the ADR-0005 overlay/runtime-create authorization and spec validation; both draft and publish-mode saves; environment writes only). publishMetaItem promotes an already-gated draft body, so no second gate.
  • plugin-security — registers the object posture gate (object-posture-gate.ts, feature-detected like the ADR-0094 projector wiring):
    • R1 env-tighten-only (ADR-0086 D1): an env overlay of an artifact-backed object may not set sharingModel/externalSharingModel wider than the packaged declaration → 403 owd_widening_forbidden with a fix-it pointing at the package publish pipeline (ADR-0090 D7).
    • R2 external ≤ internal (ADR-0090 D11) on every runtime object write → 403 owd_external_wider.
  • Write-path only: no zod refine — stored/grandfathered metadata keeps loading unchanged (the ADR-0090 D1 lesson). controlled_by_parent excluded from ordering on either side, mirroring lint's OWD_WIDTH.

Tests: 6 new seam-contract tests (mutation-listeners.test.ts — dispatch, plural normalization, throw propagation, artifact-baseline resolution, replace-on-reregister) + 18 posture-gate unit tests. Full metadata-protocol suite (29) and plugin-security targeted suites green; ESLint clean. Changeset included (minor × 2).

2. ADR status hygiene — flip 10 verified-implemented Proposed ADRs

Continuation of #3032, same per-decision code+test verification method as the ADR-0086 re-evaluation:

  • → Accepted with one-line landing evidence: 0047, 0049, 0053, 0056, 0058, 0062, 0066, 0068, 0081.
  • 0057 (ERP authz) → Accepted in part: D1–D3/D8 landed (scope depth, BU tree, conformance); D4–D7 sys_role/role_and_subordinates decisions superseded by ADR-0090 D3/ADR-0095 (flat positions, rollup on the BU tree) — its own implementation-status table predates that supersession.
  • 0025 stays Proposed with an honest partial note: build/sign/publish CLI landed, install flow + sys_plugin_* registry missing.
  • 0056's status also flags its addendum's stale D6 claim (RoleGraphService never shipped).

Notes for reviewers

  • The gate deliberately does NOT fire for control-plane bootstrap writes (environmentId === undefined) — that channel is the package author's own, mirroring the existing ADR-0005 gate scoping.
  • Protocols predating registerAuthoringGate (minimal embeddings, unit-test stubs) keep legacy behavior — CLI lint remains their only guard, same fallback stance as ADR-0094's projector.

Closes #3050.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 2 commits July 16, 2026 11:47
…write path (#3050)

Implements the ADR-0094-addendum registerAuthoringGate seam — an awaited,
THROWING pre-persistence hook in saveMetaItem (draft + publish-mode saves,
environment writes only; control-plane bootstrap bypasses like the ADR-0005
gate) — and registers plugin-security's object posture gate on it:

- R1 env-tighten-only (ADR-0086 D1, ADR-0049): an environment overlay of a
  packaged object may not widen sharingModel/externalSharingModel beyond the
  packaged declaration. Closes the OS_METADATA_WRITABLE=object hole where the
  escape hatch admitted unvalidated OWD widening (private ->
  public_read_write) with zero checks.
- R2 external<=internal (ADR-0090 D11): previously .describe() prose + CLI
  lint only; now rejected at save time on every runtime authoring surface.

Write-path only: no zod refine, stored/grandfathered metadata keeps loading
(the ADR-0090 D1 lesson). controlled_by_parent excluded from ordering on
either side, mirroring lint's OWD_WIDTH. publishMetaItem promotes an
already-gated draft body, so no second gate. Protocols predating the seam
keep legacy behavior (feature-detected wiring).

Tests: authoring-gate seam contract (metadata-protocol, 6 new) + posture gate
unit suite (plugin-security, 18).
…notate 0057/0025

Per-decision code+test verification (2026-07-16 audit, same method as the
ADR-0086 re-evaluation): 0047, 0049, 0053, 0056, 0058, 0062, 0066, 0068,
0081 flip to Accepted with one-line landing evidence. 0057 (ERP authz)
becomes Accepted-in-part: D1-D3/D8 landed, D4-D7 sys_role/role-hierarchy
decisions superseded by ADR-0090 D3/ADR-0095 positions. 0025 stays Proposed
with an honest partial-implementation note (install flow + sys_plugin_*
registry missing). 0056's status notes its addendum's stale D6
RoleGraphService claim.
@vercel

vercel Bot commented Jul 16, 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 16, 2026 12:02pm

Request Review

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata-protocol, @objectstack/plugin-security.

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

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authorization.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security)
  • content/docs/plugins/index.mdx (via @objectstack/plugin-security)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-security)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-security)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security)

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 16, 2026 12:34
@os-zhuang
os-zhuang merged commit 7f9a795 into main Jul 16, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/auth-model-design-eval-xxgzcl branch July 16, 2026 12:34
os-zhuang pushed a commit that referenced this pull request Jul 16, 2026
…partial/cloud-owned ADRs

Per-decision code+test verification (same method as #3052's round 1) of the
14 remaining medium/low-density Proposed ADRs:

- Flip to Accepted: 0037 (Live Canvas — all four phases landed incl.
  preview-evaluator + objectui surfaces), 0065 (SDUI styling — envelope,
  scoped-styles compiler + 4-property test, token lint; cloud half noted).
- Honest partial notes, keep Proposed: 0080 (save-time compile->store not
  wired), 0078 (core shared completeness predicate + lint absent), 0052
  (context decomposition undone), 0067 (Decision-2 turn-atomicity missing),
  0022 (Slack channel->connector delegation unbuilt), 0051 (render side
  absent), 0076 (D3 unbuilt, D12 runtime enforcement missing), 0061 (Tier 1
  claim verified TRUE; own conformance bar unmet), 0028 (NOT STARTED).
- Cloud-owned banners verified accurate, framework slices noted: 0038, 0063,
  0064 (service-ai genuinely absent from framework).
os-zhuang added a commit that referenced this pull request Jul 16, 2026
…atus verification (#3061)

* docs(permissions): document the runtime OWD posture gate (#3050) in the governance section

* docs(adr): round-2 status verification — flip 0037/0065, annotate 12 partial/cloud-owned ADRs

Per-decision code+test verification (same method as #3052's round 1) of the
14 remaining medium/low-density Proposed ADRs:

- Flip to Accepted: 0037 (Live Canvas — all four phases landed incl.
  preview-evaluator + objectui surfaces), 0065 (SDUI styling — envelope,
  scoped-styles compiler + 4-property test, token lint; cloud half noted).
- Honest partial notes, keep Proposed: 0080 (save-time compile->store not
  wired), 0078 (core shared completeness predicate + lint absent), 0052
  (context decomposition undone), 0067 (Decision-2 turn-atomicity missing),
  0022 (Slack channel->connector delegation unbuilt), 0051 (render side
  absent), 0076 (D3 unbuilt, D12 runtime enforcement missing), 0061 (Tier 1
  claim verified TRUE; own conformance bar unmet), 0028 (NOT STARTED).
- Cloud-owned banners verified accurate, framework slices noted: 0038, 0063,
  0064 (service-ai genuinely absent from framework).

---------

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/l tests tooling

Projects

None yet

2 participants