Repository navigation
Conversation
Implement the first RFC-0026 slice. Migration 0065 adds the immutable built-in Default User, Namespace member, and Namespace owner Roles, the Default users Group, the built-in binding-shape constraint, deletable Group memberships, and namespaces.created_by. Installation administrators add and remove Default users through /iam/default-users. A member's POST /namespaces counts against defaultUser.namespaceLimit under a per-creator lock, records createdBy, and binds the creator as owner before the default Presets. A deploy allowed by a built-in Namespace Role writes the Agent's missing exact operate grants in the deploy transaction; deploys allowed only by custom Roles change no grant. The IAM Driver gains optional Group membership and Namespace owner binding members (RFC-0026, PR #4207).
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs real behavior proof before merge. What this changesThis PR adds administrator-managed Default users, owned Namespaces with a creation limit, and automatic Agent credential grants at deployment. Example: An administrator adds Alice to Default users with namespaceLimit set to 1.
Review scores
ProductKind: Feature · Worth it: Needs a maintainer decision · Fix scope: Complete Merge readiness⛔ Blocked before merge - 10 items remain Keep this draft open for maintainer triage: it addresses a real capability gap, but two revocation races block merging. Priority: P2 Decision needed
Before merge
Findings
Provenance
Tests
Agent review detailsHow this fits togetherThe controller authenticates HTTP callers, asks the selected IAM Driver for permission, and commits Namespace ownership, Agent grants, deployment work, and audit records to PostgreSQL. flowchart TD
A[Authenticated caller] --> B[Controller HTTP API]
B --> C[Selected IAM Driver]
C --> D[Platform transaction]
D --> E[Namespace ownership and Agent grants]
D --> F[Audit and queued deployment]
F --> G[Worker and runtime Drivers]
Technical reviewBest possible solution: Extend the existing IAM authority protocol to automatic grants, serialize membership revocation with creation, and settle the shared delegation contract before landing. Do we have a high-confidence way to reproduce the issue? Source establishes both races: delay creation on its creator lock while removing membership, or delay an automatic-grant request while revoking its session; neither path reestablishes the missing authority before committing grants. Is this the best way to solve the issue? Using existing IAM Roles, repositories and deployment transactions is coherent, but the automatic writers must inherit the existing revocation protections rather than relying on admission-time decisions. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 912ae8433eb5. Provenance checked
TestingProof path: in-process harness. SecurityNeeds attention: Automatic ownership and Agent grants can persist beyond the authority that admitted their creation. EvidenceSecurity concerns:
What I checked:
Likely related people:
LabelsLabel changes:
Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment Reviewed October 30, 2026, 2:10 PM ET / 18:10 UTC. |
|
Free's clanker here (an AI agent working on Free's behalf). Heads-up: #4098 landed |
…into feat/default-users-agent-grants # Conflicts: # migrations/meta/_canonical-history.json # migrations/meta/_journal.json # packages/occ/src/index.ts
…ators owners Rework the first RFC-0026 slice after the design review on #4207. Migration 0066 (renumbered after main's 0065) seeds the immutable Agent Creator, Namespace Creator, Owner, and Namespace member Roles and the Default users Group, lets an Installation Group be bound inside a Namespace, and binds Default users to Agent Creator in an existing default Namespace. OCC writes that binding when it creates the Namespace named default. Every create of a Namespace, Agent, Configuration, Secret, credential source, Preset, or ServiceAccount, and each guided provisioning request, binds the creator to the Owner Role in the same unit: Namespace-wide for a Namespace, exact otherwise. Built-in bindings are written only when the Native IAM Driver reads policy from the controller's own State. defaultUser.namespaceCreate replaces defaultUser.namespaceLimit: OCC writes or deletes the Namespace Creator binding at startup and after bootstrap. The Namespace limit, its lock, and namespaces.created_by are removed. Deploy-time grants now follow the Owner or Namespace member Role. The IAM Driver's createNamespaceOwnerBinding becomes createOwnerBinding and setDefaultUsersBinding.
…ep IAM negative controls reachable Add a k3d-model case where an ordinary account, added only to Default users, creates its model Secret, Configuration, and Agent in the default Namespace and deploys with no other grant. The helper asserts the caller's Owner bindings and the deploy-written Agent grant and audit, then the case runs a real model turn. It runs first so it gets the fresh Installation's default Namespace. Creators now own what they create, so the scoped caller owns its Secrets and Agent. The actor Secret negative control now uses an administrator-owned Secret, and the deploy step asserts the grants the owner's deploy writes instead of a refusal no creator can reach. The PostgreSQL Default users test keeps the custom-Role refusal. Also record that an Agent owner cannot yet read its deployment status, and update the Default users route summaries for the default Namespace design.
…ox policy RFC-0026 parent checks, moved into the first Default users slice so an owner can follow its own deploys. AuthorizationRequest gains an optional parentAgentId for agent_revision and sandbox_policy checks. OCC names the Agent from stored state, or from the route where the later lookup is scoped to that Agent, and derives a sandbox policy's parent from its ID, which the database ties to the Agent ID. The native IAM Driver then matches an exact binding on that Agent and keeps those permissions for identity access coverage. The PostgreSQL Default users test reads the owner's revision, deployment status, and sandbox policy, refuses another member, and shows that a revision of another Agent behind the owner's route is not found. The k3d Default user case reads its real deployment status. The native IAM reference oracle and occ-read fixtures follow the new matching rule.
…into feat/default-users-agent-grants # Conflicts: # packages/occ/src/index.ts # tests/helpers/harness-topology-k3d-real.mjs
…n the fixture lane Administrators own what they create, so the fixture's deploys now write the Agent ServicePrincipal's Secret grants instead of being refused first. Assert those grants for the model and bound Secrets; the PostgreSQL Default users test keeps the custom-Role refusal. Also keep the Kubernetes testing guide within the length limit after the merge from main.
Problem
Every OCE capability starts with an Installation administrator. Only an administrator can create Namespaces, Agents, and Secrets for other people, and only an administrator can give an Agent's ServicePrincipal
operateon its Secrets and credential sources (MEMBER_GRANT_REFUSED). RFC-0026 proposes Default users who create Agents in a shareddefaultNamespace, with creators owning what they create. This PR implements its first slice (TASK-0050 slice 1).This revision follows the RFC-0026 design update discussed on #4207. Members create Agents in
defaultby default. Creating Namespaces is an opt-in Installation setting. Every creator owns what it creates. The Namespace limit was removed and moved to a separate quota RFC.Change
0066_default_users).createon Agents, Configurations, Secrets, and credential sources;readon the Namespace and Presets), Namespace Creator (namespace:create), Owner (every Namespace action plusnamespace:delete), and Namespace member (Owner withoutnamespace:delete). They matchBUILT_IN_ROLESinpackages/contracts.iam_access_bindings_built_in_role_shapelimits each built-in Role to one binding shape:default. A trigger makes that binding immutable.default(Installation bootstrap), it also writes the Agent Creator binding for Default users, audited withreason: default_namespace.binding_owner_<resource-id>, audited withreason: creator. Guided provisioning binds the requester to its Agent and Configuration. This also applies to administrators and ServiceAccounts.defaultUser.namespaceCreate(falsewhen absent) controls the Namespace Creator binding. OCC writes or deletes it at API startup and right after Installation bootstrap, with the Installation as the actor andreason: installation_configuration.listGroupMembers,addGroupMember,removeGroupMember,createOwnerBinding, andsetDefaultUsersBinding, and the optionalparentAgentIdonauthorizerequests.IAMPolicyRepositorymethods, includingcreateBuiltInBindinganddeleteBuiltInBinding.503.GET,PUT, andDELETE /iam/default-users/{principalId}, for Installation administrators. Each write is audited withgroupId,principalId, andchanged. Removal stops new creates and keeps everything the person created.AuthorizationRequestgains an optionalparentAgentIdforagent_revisionandsandbox_policychecks, so an owner can read the revisions, deployment status, and sandbox policy of its own Agent. OCC takes the Agent from stored state, or from the route where the later lookup accepts only that Agent's revision, and derives a sandbox policy's parent from its ID (the database ties it to the Agent ID). The native Driver then matches an exact binding on that Agent, and identity access coverage counts those permissions. This moved here from slice 2.agent:deploy, deploy writes the Agent ServicePrincipal's missing exactoperategrants, in the deploy transaction, audited withreason: agent_deploy. It writes a grant only for each Secret or credential source the Agent references where a built-in Role also allows the calleroperate; indefault, that is a source the caller owns. Deploys allowed only by custom Roles write nothing and are refused as before.409,namespaces.created_byandNamespace.createdBy(the Owner binding replaces them), and the "Default User" Role. The Namespace create refusal text is the same as on main again.docs/reference/authorization/default-users.md, rewritten for the new design.docs/guides/topics/iam.md.namespace-iam-policyflow.Not in this PR (later slices in TASK-0050):
Verification
Tested at
fb3b5a1c2unless noted, locally on Fedora with Node 24.22.1, tools pinned bymise.toml, and disposable PostgreSQL databases and k3d clusters fromscripts/ci/prepare.mjs.tests/integration/postgres-default-users.test.ts(postgres-platformlane) runs the real Fastify app on PostgreSQL with password accounts that sign in.default:defaultUser.namespaceCreate: with the setting on, a member creates and owns a Namespace. A second controller started on the same database with the setting off deletes the binding, audited with the Installation as actor. The running app then refuses new Namespaces, and the member keeps the one they own.k3d-modellane (realgpt-6.1-sol). New case "production Default user deploys embedded OpenClaw in the default Namespace with owner grants": an account the administrator only added to Default users creates its model Secret, Configuration, and Agent indefaultand deploys. The helper asserts its Owner bindings and the deploy-written grant and audit. The owner then reads its deployment status (succeeded), and the Agent answers a real model turn.local-first-agent-real.clientstate mount (fix(compute): preserve native Gateway state across restarts #3041), theprepare-embedded-gateway-ownerinit container (feat(runtime): apply Gateway tool policy to dedicated OCE deployments #2633), and the deployment-statuscleanupfield (feat(kubernetes): run OAuth bootstrap as a bounded Job #1994). The same five fail identically at036b7da9con main without this PR. Draft test(k3d): match the k3d-model topology assertions to current runtime resources #4446 fixes the stale assertions; that turns the two startup-failure cases green, and the other three then fail on runtime and Secret API questions listed there. Every case passes this PR's IAM setup, deploy, and activation before those assertions.occ dev up, Kubernetes control plane, at74d79cc09). Run by hand: an administrator adds two accounts to Default users. Alice creates a Secret, Configuration, and embedded Agent indefaultand deploys, and the deploy writes the Agent's grant. The Agent answers a real model turn. Bob is refused every read, deploy, delete, and rotate on Alice's resources. Removing Alice stops her creates and keeps her Agent running. Database rows and audit events match. This run found that owners could not read their deployment status, which the parent checks fix.postgres-platform: 56 of 56 files pass. The provisioning file passed on its own after its last test fix.postgres-application: 15 of 15.postgres-auth: 23 of 23, including the Playwright browser cases (atdae3172e3).checks-baseline-1: 129 of 129, including the docs-site, docs-length, plugin-installation, andgh-pinned conformance cases. The IAM conformance oracle and generator now include parent checks; with the parent rule removed from the Driver, the seeded differential fails.checks-baseline-2: all files pass.postgreslane (atdae3172e3): passed in full before the last change, which limits built-in binding writes to Drivers that read OCC's State.postgres-migration-compatibilitypassed again after that change. The canonical-history digests and restore catalogs were measured on PostgreSQL. The populated-upgrade check seeds adefaultNamespace before 0066, excludes the seeded built-in rows from the data comparison, and asserts that they exist.administerpath. The IAM conformance invalid-state case now uses a Namespace Group bound in another Namespace, because an Installation Group in a Namespace is now valid.pnpm format:check(bun fmt),openapi:check,openapi:lint,check:workspace,docs:check,docs:check-length, anddocs:buildpass.authorization.md(2,496 words) andconfiguration.md(2,500) are just under the hard limit. Pages in the 1,500–2,500 review band:docs/testing/kubernetes.md(2,483), thenamespace-iam-policyflow (2,427),docs/guides/topics/iam.md(2,127), andnamespaces.md(1,742). Each covers one coherent topic.Risks
defaultNamespace. Members share one Kubernetes namespace and its ResourceQuota. Lists show each member only what they can read, and NetworkPolicies keep Agents apart. OCC has no per-person limit yet; quotas are a separate RFC.agent_revisionandsandbox_policypermissions to that Agent's revisions and policy. A Role that should not read revisions must not include that permission.