Skip to content

feat(security)!: ADR-0090 P3 — security publish linter (D7), delegated administration (D12), BU assignment anchor#2711

Merged
os-zhuang merged 2 commits into
mainfrom
claude/adr-0090-p3-linter-delegated-admin
Jul 9, 2026
Merged

feat(security)!: ADR-0090 P3 — security publish linter (D7), delegated administration (D12), BU assignment anchor#2711
os-zhuang merged 2 commits into
mainfrom
claude/adr-0090-p3-linter-delegated-admin

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Summary

Third wave of ADR-0090 (Permission Model v2): the D7 security-domain publish linter and D12 delegated administration, plus the Addendum's assignment-level BU anchor and a D3 vocabulary sweep. Follows #2695 (ADR), #2697 (P1), #2708 (P2).

D7 — security publish linter (@objectstack/lintos compile / os lint)

validateSecurityPosture(stack) — pure, spec-only, shared shape with every other lint rule. Error rules gate os compile; each mirrors a runtime enforcement point (ADR-0049: no advisory security):

Rule Origin
security-owd-unset (error) objectui#2348 leave_request incident
security-owd-alias (error, fix-it) D4 canonical enum
security-external-wider-than-internal (error) D11 external ≤ internal
security-wildcard-vama (error) ADR-0066 superuser wildcard
security-anchor-high-privilege (error) D5/D9 — isDefault (everyone-suggested) sets held to the anchor tier
security-role-word (error) D3 vocabulary freeze (ARIA/page roles exempt)
security-private-no-readscope (info) admin-intent mismatch class

The linter immediately paid for itself: it caught examples/app-crm shipping six objects with no OWD, two more in app-showcase, a role field on showcase_project_membership, and undeclared OWD across the CLI's golden AI-authoring corpus — all fixed here (grandfather stamps per the P1 pattern; roleengagement).

D12 — delegated administration (DelegatedAdminGate, plugin-security)

  • New spec shape PermissionSetSchema.adminScope (businessUnit + includeSubtree + manageAssignments/manageBindings/authorEnvironmentSets + assignablePermissionSets[]), persisted as sys_permission_set.admin_scope, hydrated by the dbLoader and both seed paths.
  • Writes to sys_user_position / sys_position_permission_set / sys_user_permission_set / sys_permission_set are now governed: tenant-level admins (ADR-0066 wildcard) pass through to ordinary CRUD/RLS; delegates need a covering scope; plain CRUD on RBAC tables no longer makes a permission administrator (fail closed).
  • Delegate rules: assignments must be anchored inside the subtree (business_unit_id), every set reached must be allowlisted (to others AND themselves), bindings require the position's full blast radius inside the subtree, single-row writes only, granted_by auto-stamped.
  • Strict containment: granting or authoring a set that itself carries an adminScope requires a held scope that strictly contains it — handing your own exact scope to a peer is refused (no lateral propagation).
  • everyone/guest stay tenant-level only; stored assignments to an anchor are rejected for every caller (anchors are implicit).

Addendum — assignment-level BU anchor

sys_user_position.business_unit_id (+ index) with its three sanctioned consumers: D12 boundary (enforced here), audit fact, and the depth-anchor contract documented on IHierarchyScopeResolver for enterprise resolver implementations. Capability bits are never BU-scoped.

D9 tightening + D3 sweep

  • describeHighPrivilegeBits moved to @objectstack/spec/security (single definition for lint + runtime; re-exported from plugin-security); new describeAnchorForbiddenBitsguest bindings now also reject edit bits (read-only tier; create stays the case-by-case exception).
  • One-step renames (no aliases, pre-launch): SysRoleSysPosition, SysUserRoleSysUserPosition, SysRolePermissionSetSysPositionPermissionSet; sys_position actions/list views/labels de-roled; sys_business_unit_member.role_in_business_unitfunction_in_business_unit (+ 4-locale label updates).

Out of scope (deliberate)

  • D6 explain engine + access-matrix snapshot gate and the human-approval publish workflow → P4.
  • D10 agent assignment-time ceilings → needs principal-linked user rows (P4; ai_seat is request-time synthesized today).
  • Enterprise hierarchy-scope-resolver depth-anchor implementation lives in the cloud repo (contract documented here).

Verification

  • New: lint 17/17, delegated-admin gate 24/24, anchor tiers 8/8, spec AdminScope 27/27
  • Suites: plugin-security 225, core 315, runtime 463, plugin-sharing 75, platform-objects 71, cli 466 (golden corpus re-baselined with OWD), objectql 804, metadata-core 100, downstream-contract 14
  • Dogfood 39 files / 191 tests green; example-crm + example-showcase + app-todo + embed-objectql compile with the linter active
  • check:liveness ✓ (adminScope entry, stale isProfile entry removed) · check:api-surface ✓ · changeset: major (plugin-security, platform-objects) / minor (spec, lint, cli)

🤖 Generated with Claude Code

https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H


Generated by Claude Code

…d administration (D12), BU assignment anchor

D7 — validateSecurityPosture in @objectstack/lint, gating os compile and
reported by os lint. Seven rules, each with a failing fixture: unset OWD on
custom objects (the objectui#2348 leave_request shape), retired OWD aliases
(fix-it), external dial wider than internal (D11), wildcard VAMA outside the
platform admin set (ADR-0066), high-privilege everyone-suggested sets, the
reserved word 'role' in security identifiers/labels (D3), and advisory
private-object-read-without-depth. The linter immediately caught real gaps:
app-crm shipped six objects with no OWD, app-showcase two, plus a 'role'
field on showcase_project_membership and the CLI golden corpus — all fixed
in this commit (grandfather stamps + engagement rename), proving the rule
set against its own repo.

D12 — DelegatedAdminGate in plugin-security. PermissionSetSchema.adminScope
(persisted as sys_permission_set.admin_scope) declares WHERE (BU subtree),
WHAT (manageAssignments / manageBindings / authorEnvironmentSets) and WHICH
sets a delegate may hand out (allowlist). Writes to sys_user_position,
sys_position_permission_set, sys_user_permission_set and sys_permission_set
are now governed: tenant admins (superuser wildcard) pass to ordinary
CRUD/RLS; delegates need a covering scope — subtree-anchored assignments,
allowlisted sets only (to others AND themselves), single-row writes,
granted_by audit stamping; plain CRUD holders with no scope are denied.
Granting/authoring a set that carries an adminScope requires strict
containment. everyone/guest anchors stay tenant-level only, and stored
assignments to an anchor are rejected for every caller.

ADR-0090 Addendum — sys_user_position.business_unit_id lands with its three
consumers: D12 delegation boundary (enforced), audit fact, and the
depth-anchor contract documented on IHierarchyScopeResolver for enterprise
resolvers.

D9 tightening — describeHighPrivilegeBits moved to @objectstack/spec/security
(shared by lint + runtime, re-exported from plugin-security) plus new
describeAnchorForbiddenBits: guest bindings now also reject edit bits.

D3 sweep — SysRole→SysPosition, SysUserRole→SysUserPosition,
SysRolePermissionSet→SysPositionPermissionSet (one-step, no aliases);
sys_position actions/list views/labels de-roled;
sys_business_unit_member.role_in_business_unit→function_in_business_unit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H
@vercel

vercel Bot commented Jul 9, 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 9, 2026 6:21am

Request Review

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 5 package(s): @objectstack/cli, @objectstack/lint, @objectstack/platform-objects, @objectstack/plugin-security, @objectstack/spec.

100 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 packages/cli, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/cli, 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/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @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/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli, @objectstack/plugin-security, @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/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/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, 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/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint, packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/profiles.mdx (via @objectstack/spec)
  • content/docs/permissions/roles.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security, @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/plugin-security, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, @objectstack/platform-objects, @objectstack/plugin-security, @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/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/objectos/realtime-protocol.mdx (via @objectstack/cli)
  • 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 packages/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/cli, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/releases/index.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/plugin-security, @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/role-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/setup-app.mdx (via @objectstack/platform-objects, @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.

Comment thread packages/plugins/plugin-security/src/security-plugin.ts Fixed
… (CodeQL)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012oLzaP8n7A3YKFmgaHWC8H
@os-zhuang
os-zhuang marked this pull request as ready for review July 9, 2026 06:30
@os-zhuang
os-zhuang merged commit b271691 into main Jul 9, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/adr-0090-p3-linter-delegated-admin branch July 9, 2026 06:30
os-zhuang added a commit that referenced this pull request Jul 9, 2026
…on Model v2 vocabulary (ADR-0090) (#2717)

- roles.mdx → positions.mdx: flat positions (岗位), assignment BU anchor,
  built-in identity positions, everyone/guest audience anchors; the
  hierarchy narrative moves to business units.
- profiles.mdx → migration tombstone: the Profile concept was removed
  (D2); maps each former use to everyone-anchor bindings, isDefault
  suggestions, and position-bound sets.
- permission-sets.mdx: rewritten as the single capability container —
  union semantics, access depth (moved here from profiles), capabilities,
  built-in sets (additive member_default baseline), governed assignment
  tables, isDefault suggestion, adminScope delegated administration,
  package provenance.
- sharing-rules.mdx: OWD default corrected to fail-closed private (D1 —
  the page previously documented the pre-v2 fail-open default), canonical
  four values only, externalSharingModel dial (D11), recipient types
  position / unit_and_subordinates / team.
- authorization.mdx: position vocabulary, D1/D11 in the enforcement
  chain, delegated-admin gate in anti-escalation, new explain-engine
  section (D6), D7 linter + access-matrix snapshot added to governance,
  ADR-0090 in the index.
- permissions-matrix.mdx: role-hierarchy section replaced with
  business-unit hierarchy & positions; isProfile removed from samples;
  position recipients.
- permission-metadata.mdx: isProfile → isDefault/adminScope in the field
  table; union-semantics section replaces Profile-vs-Set;
  current_user.positions.
- index.mdx: five-concepts overview, v2 implementation-status callout,
  best practices and example updated.
- access-recipes.mdx / field-level-security.mdx: link + heading fixes.

Authoritative reference: docs/design/permission-model.md; decision
record: ADR-0090 (P1 #2697, P2 #2708, P3 #2711, P4 #2716).


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

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants