Skip to content

fix(console): grant Agent access to accepted Configuration Secrets - #2255

Open
miguelbranco80 wants to merge 11 commits into
openclaw:mainfrom
raw-labs:codex/configuration-secret-access
Open

miguelbranco80 wants to merge 11 commits into
openclaw:mainfrom
raw-labs:codex/configuration-secret-access

Conversation

@miguelbranco80

@miguelbranco80 miguelbranco80 commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Ordinary Console draft creation can save inherited Configuration Secret bindings without granting the Agent access, causing deployment admission to fail. Enumerate the accepted saved Configuration’s same-Namespace environment Secret bindings, deduplicate their sources, and create exact operate grants through the existing IAM operation.

Installation-admin delegation remains required. A failed grant retains the saved Agent and Configuration for explicit retry without duplicate writes. Supported queued provisioning keeps its worker-owned path. The existing live integration test also covers denied grant writes and revocation before worker delivery.

Fixes #2254. Fork tracking PR: raw-labs/openclaw-enterprise#13. Both use raw-labs/openclaw-enterprise:codex/configuration-secret-access.

Verification — October 20 refresh

Tested head: 7917bb951d8c7360bddcbbf3e4898445cc7e08ed, incorporating upstream main at a77594a92203b9da12690591554b385d9970d904 (57 upstream commits since the previous base). Published history is preserved with a normal fast-forward push; both PRs remain open, non-draft, with auto-merge off.

Preserved upstream's member permission gating, creation preflight, Credential Sources, Namespace polling, and Console changes. The parent Console flow now matches upstream exactly; the Configuration Secret grant trace follows upstream's move into docs/flows/platform-console/agent-creation.md. Both consolidated changelog inventories and Manual Notes are preserved. Unrelated reference wording was restored. The remaining feature delta is nine files, +336/-50.

One existing regression setup now revokes delegation after the page admits the administrator, matching upstream's retry scenario. A known non-admin still receives upstream's no-retry guidance. Real Native IAM denial, exact deduplicated grants, retained resource IDs, and revocation/admission assertions remain intact.

Local verification using matching prepared dependencies without installing anything:

  • 239 browser cases passed, zero failures/skips, including Preset grants/denial/retry, member creation, drawers/mobile navigation, ordinary/dedicated creation, OAuth, retained drafts, Namespace readiness, and draft guards.
  • 130 API cases passed, zero failures/skips: Console, Presets, creation validation, OCC, and Secret APIs.
  • The focused inherited-Secret regression passed with the fix and failed against exact unpatched upstream a77594a9 because the inherited tool Secret grant was missing.
  • Lint, formatting, typecheck, workspace isolation, OpenAPI, docs/link/length checks, CI suite audit, flow validation, rebuilt Storybook, and diff checks passed.
  • Independent isolated local review with GPT-6 Astra, high reasoning, completed both passes over the final branch diff and related source context: no actionable P0–P2 findings (scoped-clean). The reviewer performed source review; test execution is reported separately above.

Fresh hosted CI run 39407133353 is pending on this exact head. CodeQL and hosted Storybook have also started. Maintainer approval remains pending.

This refresh does not repeat live PostgreSQL/Kubernetes procedures. Their evidence remains scoped to earlier revisions below. Current media proves simulated Storybook UI behavior; it does not establish backend persistence, credential delivery, runtime readiness, or model execution.

Current Storybook evidence

Rebuilt and exercised Pages/Create Agent → Preset Secret access retry (pages-create-agent--create-bound-secrets-grant-denied) on head 7917bb951, macOS ARM64, Node.js 24.3.0. The actual retry opens the same saved Agent and Configuration. Both native screenshots opened at 1265×712; the uploaded H.264 recording decoded and played to completion (8.04 seconds).

Denied grant retains saved resources

Retry opens the retained Agent draft

retry-walkthrough.mp4

Historical refresh 81ce5d06: 220 browser and 37 API cases passed; hosted CI subsequently passed. Its denial screenshot, recovery screenshot, and video remain historical.

Earlier refresh 3cc28047: 119 browser and 37 API cases passed locally. Its inherited-Secret regression failed on exact unpatched upstream f3a74292. Its denial screenshot, recovery screenshot, and video remain historical.

Earlier live Console creation and admission

The remaining review request was exercised on 1d7772d11b2874ae7fb1f5253a998bd0463395b2 using the actual loopback Console and HTTP listener, PostgreSQL application role, Native IAM, Kubernetes Configuration/Secret Drivers and controller worker. Setup provisioned a Namespace, a saved Embedded OpenClaw Preset and distinct synthetic model/tool Secrets. It did not seed an Agent or Agent Secret grant. The browser signed in, selected the Preset, entered name/model, selected Use Preset, Create Agent, then Deploy new version. No UI responses, State or IAM were mocked.

Recorded real Console creation/admission output confirms:

  • The accepted Configuration retains TOOL_TOKEN and SECOND_TOOL_TOKEN bound to the tool Secret.
  • An independent PostgreSQL query finds exactly two Agent Secret operate bindings: one distinct model source and one inherited tool source, deduplicated across both destinations.
  • Real browser HTTP writes return Configuration 201, Agent 201, two exact binding writes 201, and deployment admission 202. This exercises create.mjs enumeration through the ordinary draft path; queued provisioning was not substituted.
  • The unchanged Console source SHA-256 is recorded with the tested commit.

Created draft (real Console/State/IAM):

Real Console-created draft

UI-admitted revision (real deployment record):

Real Console deployment admission

9.4-second recording of actual UI deployment admission:

live-console-deployment.mp4

Limit: An extra activation probe timed out; the worker recorded DEPENDENCY_UNAVAILABLE before workload creation, and its cause was not diagnosed. This trace proves Console creation, exact inherited grants and admission; it does not establish runtime readiness. The separate four-case live fixture authority/delivery proof below remains passing. No genuine model turn or Helm-installed production deployment is claimed. The trace retains the activation failure, and only inspected, credential-free logs/media were uploaded. Owned fixtures have been removed. No repository/source changes were made for this follow-up.

Earlier real-runtime verification

Tested head: 1d7772d11b2874ae7fb1f5253a998bd0463395b2. macOS ARM64, Node.js 24.3.0, pnpm 11.15.1, matching prepared dependencies, owned disposable PostgreSQL and loopback K3s fixtures with enforcing NetworkPolicies.

All four live Kubernetes fixture cases passed, with zero failures/skips. Recorded authority proof and test output:

  • A real cookie-authenticated Installation reader’s grant POST returns 403. An independent PostgreSQL query observes zero exact Agent/Secret bindings. The authorized administrator then persists the grant through the same API.
  • Stop the real worker, admit deployment (202), revoke the Agent’s generic Configuration Secret grant (204), and independently confirm the work remains queued. Restart the worker: work fails permanently with AUTHORIZATION_DENIED; the Agent has no active revision, Deployments or Pods, and no new Agent-owned Secrets are delivered in either execution or gateway placement.
  • Restore only the exact grant, deploy again, and observe the original synthetic BOUND_SENTINEL value inside the ready real gateway Pod. This includes the existing immutable revision, identity, isolation and teardown workflow.
  • Companion cases cover Driver lifecycle/isolation, externally managed Namespace preservation, and API/worker provisioning handoff.

Commands: node --env-file=<owned-fixture.env> --test tests/integration/kubernetes-compute-real.test.mjs and node --env-file=<owned-provisioning.env> --test tests/integration/kubernetes-compute-provisioning-real.test.mjs tests/integration/kubernetes-compute-driver-real.test.mjs. Repository CI preparation migrates owned databases as occ_migrator; API/worker execution uses occ_app. The migrator seeds only the reader’s initial Role. Owned resources were cleaned up.

These tests exercise actual Fastify routes through injection, OCC, Native IAM, PostgreSQL, the controller worker, and Kubernetes Drivers/API using development composition and a fixture gateway/Harness image. Synthetic values establish Secret delivery and refusal; they do not prove a genuine model turn, Slack connection or Helm-installed production deployment.

At the preceding head e0ec6627, 93 Console browser and 54 API/OCC cases passed without failures/skips. The inherited-Secret regression failed against exact unpatched upstream Console and passed with the fix. This follow-up changes only the existing Kubernetes test; all application, browser-test, documentation and Storybook source is unchanged. Typecheck, OpenAPI and docs checks passed at that preceding head. Lint, formatting, workspace isolation and diff checks also pass at the new head. Existing reference/flow documentation remains accurate; no new runtime behavior or image version was introduced.

Earlier UI evidence

Rebuilt and inspected Pages/Create Agent → Preset Secret access retry (pages-create-agent--create-bound-secrets-grant-denied). The captures use UI source byte-identical to the tested head. Denial retains saved IDs and locks fields; selecting Retry credential access opens the same saved Agent draft. This is simulated Storybook UI proof, separate from the live authority proof above.

Denied grant and saved-resource recovery:

Earlier Secret grant denial

Recovered retained Agent:

Earlier retained Agent after retry

10-second recording of the live browser interaction; uploaded H.264 MP4 decoded and played successfully:

retry-walkthrough.mp4

The earlier evidence addresses the grant-persistence, post-admission revocation and media requests. Independent review comments are retained in the PR discussion. Keep both PRs open and auto-merge disabled; neither PR has been merged.

@clawsweeper

clawsweeper Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Oct 12, 2026
@clawsweeper

clawsweeper Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

What this changes

This PR grants a newly created Agent exact access to every distinct Secret referenced by its accepted saved Configuration.

Example: An Embedded OpenClaw Preset binds a distinct tool Secret to both TOOL_TOKEN and SECOND_TOOL_TOKEN.

  • Before: Console creation saves the bindings but omits the tool Secret grant, so deployment admission rejects the Agent.
  • After: Creation grants the tool Secret once, preserves the separate model grant, and permits deployment admission.

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) A focused contract repair with shipped Console evidence, meaningful regression coverage, and final-effect authority proof; no introduced correctness or security finding remains.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (logs): The actual loopback Console browser flow exercised ordinary draft creation through real PostgreSQL, Native IAM, and Kubernetes Drivers, recording two distinct persisted grants and admission 202; separate real-cluster traces prove reader denial, queued revocation before delivery, and exact-grant recovery. The subsequent merge changes queued-provisioning recovery rather than the proven ordinary grant path. Inspected screenshots support creation/admission and simulated Storybook recovery; recordings could not be inspected because ffprobe and browser playback were unavailable. The manual activation timeout establishes no runtime readiness, model turn, or Helm-installed production result.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Product

Kind: Bug fix · Worth it: Yes · Fix scope: Complete
User problem: Creating an Agent from a Preset can leave a saved draft unable to deploy because inherited tool Secrets lack Agent access.
Reason: The repair restores the existing accepted-binding authorization contract and adds no permission, public API, configuration option, or alternative grant mechanism.

Merge readiness

✅ Ready for maintainer review

Keep this PR open: it repairs a current Console grant omission without changing the authorization contract. No actionable introduced defect was found, and GitHub no longer reports the earlier merge conflict.

Priority: P2
Reviewed head: 6690b557210a079a47541289fafd64e31f36a46c

Before merge

None.

Findings

None.

Agent review details

How this fits together

The Console saves Configuration and Agent resources through OpenClaw Control Plane, then delegates Secret access through existing IAM APIs; deployment admission and the worker independently enforce authorization before Kubernetes delivery.

flowchart TD
  Preset[Preset bindings] --> Console[Console creation]
  Console --> State[Saved Configuration and Agent]
  Console --> IAM[Exact Secret grants]
  State --> Admission[Deployment admission]
  IAM --> Admission
  Admission --> Worker[Worker reauthorization]
  Worker --> Kubernetes[Kubernetes Secret delivery]
Loading

Technical review

Best possible solution:

Land the focused saved-Configuration grant repair with existing IAM authorization and retained-Agent recovery intact.

Do we have a high-confidence way to reproduce the issue?

Current-main source retains inherited Configuration bindings but grants only staged channel selections, so a distinct inherited tool Secret lacks the Agent permission required by deployment admission; the contributor also records the regression failing against the unpatched Console.

Is this the best way to solve the issue?

Enumerating the accepted saved Configuration repairs the omission at its existing Console owner and reuses the established exact-grant operation without changing queued provisioning.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against fdde125f5e2a.

Provenance checked

Testing

Proof path: shipped entry point.

Security

None.

Evidence

What I checked:

Likely related people:

  • stevenlee-oai: Raw commit 4a11696 adds apps/controller/src/console/agents/secret-access.mjs:28 relative to its recorded parents. This identifies author metadata, not feature responsibility or a PR merger. (role: source-line author; confidence: high; commits: 4a116967368a; files: apps/controller/src/console/agents/secret-access.mjs)

Review metrics

Metric Value Why it matters
Change allocation Production +17/-22; tests and helper +269/-23; Storybook +54/-0; documentation +21/-9. Production scope shrinks while existing browser and Kubernetes scenarios gain distinct-source, denial, retry, revocation, and delivery coverage.

Root-cause cluster

Relationship: fixed_by_candidate
Canonical: #2254
Summary: The linked issue describes the same missing inherited-Secret enumeration repaired by this PR.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Labels

Label changes:

  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.
  • remove status: ⏳ waiting on author: Current PR status label is status: 👀 ready for maintainer look.

Label justifications:

  • P2: A bounded ordinary-draft workflow rejects deployment when an administrator-prepared Preset inherits a distinct tool Secret; no broad outage is established.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR.
  • proof: sufficient: Contributor real behavior proof is sufficient.

Rating scale

6/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.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

History

Review history (4 earlier review cycles)
  • reviewed 2026-10-12T19:09:11.685Z sha e0ec662 :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-12T20:55:46.448Z sha 1d7772d :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-12T21:02:54.685Z sha 1d7772d :: needs real behavior proof before merge. :: none
  • reviewed 2026-10-13T12:17:50.869Z sha 1d7772d :: needs changes before merge. :: none

Reviewed October 13, 2026, 9:21 AM ET / 13:21 UTC (Revision 5).

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. labels Oct 12, 2026
@miguelbranco80
miguelbranco80 marked this pull request as ready for review October 13, 2026 12:10
@miguelbranco80
miguelbranco80 requested a review from a team as a code owner October 13, 2026 12:10
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Oct 13, 2026
@clawsweeper clawsweeper Bot added status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Oct 13, 2026
@freeqaz-openai

Copy link
Copy Markdown
Collaborator

Independent source review of 6690b557210a079a47541289fafd64e31f36a46c: no confirmed correctness or security finding in the reviewed change. One non-blocking contract question is worth recording for the maintainer:

Should a Retry credential access grant reflect the Configuration accepted when the Agent was created, or the Configuration's current bindings at retry? The form retains the original create response (create.mjs). If an authorized actor replaces Secret A with B before a delayed grant or retry, this path can grant A and omit B; deployment admission still requires the current B grant. The grant caller must pass the current Installation-admin and Secret-read checks.

The existing staged-channel path already uses the same saved snapshot; this PR extends that behavior to inherited and other prebound sources. I did not find a contract requiring Configuration membership to remain current when the IAM binding commits, or requiring existing grants to be revoked on a later Configuration edit. If the accepted snapshot is intended, no change follows from this observation. If current membership is intended, a pre-grant GET alone would still leave a race; the server-side transaction and retry contract would need to define the boundary.

This is a source-derived scenario, not a demonstrated exploit or runtime failure. I did not independently rerun the browser, PostgreSQL, cluster, or provider evidence. The existing Maintainers review request remains in place.

@freeqaz-openai

freeqaz-openai commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Free's clanker here. Update for 7917bb95: CI Required passed. The red result below belongs to the previous head. I verified both browser artifact digests and the tested merge 6f04fbd5 (base a77594a9 + this head): 459 + 458 passed, none failed or skipped.

Two useful recovery cases actually ran. When delegation was denied before a grant write, retry kept the one Agent and Configuration, granted exactly the model and bound tool Secrets, and left an unrelated Secret denied. The adjacent test covers the opposite ambiguity: a grant POST committed (201), its response was lost, and retry found the existing grant without creating another Agent. These are browser-fixture results, not a claim that a live Agent received a credential.

The previously failing drawer-focus case also passed. No rerun needed for this check, no claim that the earlier flake is fixed, and auto-merge remains off as requested.


Earlier result, head 3cc28047 (retained for context):
Thanks for the sync, Miguel. On head 3cc28047, the new credential-grant test passed; CI Required is still red. I checked the artifact digests and the actual tested merge (47ac662d = base f3a74292 + this head).

  • Browser shard containing this PR’s regression: 417 passed, none failed or skipped. That includes “Embedded Preset grants all bound Secrets and retries denied access without duplicate writes.” This is browser-fixture evidence, not a claim about live credential access.
  • Failing browser shard: 375 passed, one failed. At console.test.mjs:846, the reopened drawer’s Agents link did not have focus before the held response was released. The result doesn’t say what held focus. The test, navigation.mjs, and shell.mjs matched the passing base run byte for byte; that narrows the failure, not its cause.

PR #2938 already addresses the missing focus diagnostic for this exact failure. No need to copy that change here. I didn’t rerun CI, push to your branch, mark this ready, or enable auto-merge.

Update: #2938 landed on main at 7afa66cb. A rerun of the failed job would still test the old assertion. On your next sync, please take the landed test as-is: it gives opening focus up to one second to settle, names the actual focused element on failure, and keeps the post-load check strict. This improves the next observation; it does not explain or waive the old failure.

I checked the nine changed paths against that main: seven base files were unchanged; the two that moved (agents/create.mjs and Storybook’s scenarios.mjs) each merged cleanly in a local three-way check. I did not push to your fork or run tests on that proposed combination. A fresh merge result, not a cherry-pick of #2938 or a retry of the old job, would give the useful CI signal.

@freeqaz

freeqaz commented Oct 20, 2026

Copy link
Copy Markdown
Collaborator

Free's clanker here (an AI agent working on Free's behalf).

One more review pass on head 7917bb95. I found no bugs.

What it changes: when the Console creates an Agent from an accepted saved Configuration, it now grants the Agent operate on every distinct Secret bound in that Configuration, including Preset-inherited bindings, not only the channel Secrets picked in the form. Grants are deduplicated and the separate model grant is kept.

Why I think it is safe

  • The server validates every Secret binding before it saves the Configuration. The creator must already hold operate on each Secret, and cross-Namespace references are rejected. So the Console only passes on access the creator already has.
  • Writing grants still needs Installation administration. Members are stopped before any IAM request.
  • The worker-owned provisioning path already authorizes the same set of Secrets, so this aligns the ordinary Console path with it rather than widening access.
  • The rewritten browser test covers the denial, the retry, exactly two deduplicated grants, an unbound Secret staying denied, and admission moving from 403 to 202.

Risk: it is still an IAM grant change on the create path, which is why I'm flagging it rather than calling it routine.

Nits (non-blocking)

  • create.mjs ~L1755: the new "unsupported Secret binding" error is thrown after the Agent is saved, so a retry fails the same way. Real server data can't reach it.
  • docs/reference/console/create-and-deploy.md says "model Secret". With Credential Sources configured, that grant is on a Credential Source.
  • The history entries cite branch commit SHAs that won't exist on main after a squash.
  • The browser test moved from the Codex/Dedicated Preset to the Embedded OpenClaw Preset, so the prebound-model-Secret case on the Codex path no longer has its own test.

Compatibility with the pending Credential Proxy work: it merges cleanly, and that work doesn't touch create.mjs or the grant helpers.

@freeqaz-openai flagging this one for your review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Console draft creation omits Agent grants for inherited Configuration Secrets

3 participants