Repository navigation
Conversation
…replace one The caller-permissions answer gains configurationSecretsOperateDeniedBindings: the Configuration binding names whose bound Secret the caller may not operate. A Configuration save is authorized on the Secrets it submits, so the channel Secrets panel and the Channels drawer stay editable when every such name is a Slack token name, and a save that keeps one is refused before any request.
…cret Integration: the per-binding answer is unreported without Configuration update, names each binding whose Secret the caller may not operate, and matches the real PATCH (keeping one is refused, replacing them saves). Browser: the channel Secrets panel and the Channels drawer refuse a save that keeps the Secret up front and save one that replaces it; a binding channel saves keep leaves them read-only. The draft is not called read-only while channel saves can succeed.
The permission answer describes the bindings the panel was built with. After the panel saves a listed name to another Secret, neither the hint nor the up-front refusal applies to it until the page reads the answer again.
A Configuration save needs operate on each Secret it keeps bound. The guide and flow say that channel saves stay editable when each unoperable Secret is a Slack token, which the save must replace, and that a save keeping one is refused before the request. Storybook gains the replace-the-bot-token state.
|
🦞👀 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. |
…3630 Those two stories change in the recovery fix; an omitted per-binding list is an unlisted answer, which keeps today's rule. Keeps the two PRs mergeable in either order.
Review follow-ups (findings 2457, 2458). A panel save rereads the answer, so the Channels drawer no longer refuses a save after the panel rebound a listed token; the panel's local workaround goes. Tests: the drawer saves after a panel replacement, the Configuration editor stays read-only for the replace persona, and an IAM failure on a Secret operate decision answers 503. The flow doc splits the update and operate cases; the recovery stories from #3630 carry the new field.
|
Codex review: needs changes before merge. What this changesThis PR adds per-binding permission hints so channel editors can replace bound Secrets the caller cannot operate. Example: SLACK_BOT_TOKEN binds Secret A, while the member can operate replacement Secret C and the existing app-token Secret B.
Review scores
ProductKind: Bug fix · Worth it: Yes · Fix scope: Complete Regression provenancePossible regression — suspected (reviewed change). No predecessor PR is attributed. Merge readiness⛔ Needs changes before merge - 1 item remains Keep this PR open: it repairs a real Console restriction, but one stale-permission bug still blocks valid channel saves after replacing a Secret in Credentials. Priority: P2 Before merge
Findings
Tests
Agent review detailsHow this fits togetherThe Console reads advisory Agent permissions from the Controller, stages Configuration bindings, and submits saves through OCC, which authorizes each submitted Secret before writing. flowchart LR
Member[Namespace member] --> Console[Console channel editors]
Console --> Permissions[Controller permission summary]
Permissions --> IAM[Selected IAM Driver]
Console --> Save[Configuration PATCH]
Save --> OCC[OCC authorization and mutation]
OCC --> IAM
OCC --> Storage[Configuration storage]
Technical reviewBest possible solution: Keep denied bindings associated with the Configuration snapshot they describe, and refresh or reconcile that shared answer after a successful Credentials replacement. Do we have a high-confidence way to reproduce the issue? Source establishes both the original overly broad restriction and the introduced cross-tab stale-list failure; supplied screenshots corroborate the original restriction and replacement UI, but no target code was run during this review. Is this the best way to solve the issue? Per-binding hints fit the existing permission-summary owner and preserve server authorization, but their lifetime must follow successful binding changes across both editors. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against d959564d0b9b. Provenance checked
TestingProof path: shipped entry point. SecurityNone. EvidenceAcceptance criteria:
What I checked:
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 25, 2026, 9:38 AM ET / 13:38 UTC. |
Problem
Since #3611,
configurationSecretsOperateisfalsewhen the caller lacks Secretoperateon any Secret the Agent's Configuration binds, and the console then makes the channel Secrets panel and the Channels drawer read-only. ButupdateConfigurationauthorizesoperateonly on thesecretBindingsa save submits (or on every bound Secret when the save omits them). It does not check the Secrets a save replaces.Scenario: the Configuration binds
SLACK_BOT_TOKENto an administrator's Secret A (the member has nooperateon it) andSLACK_APP_TOKENto Secret B (the member hasoperate). The member has Configuration read and update andoperateon their own Secret C. Picking C for the bot token saves (the API checks C and B), but the console locked the panel, and its copy said a save needsoperateon "each Secret the Configuration binds", which is not what the API checks.The panel cannot submit only the changed keys:
secretBindingsin a Configuration PATCH replaces the whole map, so a partial map would drop the other bindings. The console needs a per-binding answer.Change
GET /namespaces/{namespaceId}/agents/{agentId}/permissionsreturnsconfigurationSecretsOperateDeniedBindings: the sorted binding names whose bound Secret the caller lacks Secretoperateon. It uses the same checkauthorizeBindingsmakes (Secretoperateon the exact source), shares IAM decisions with the existing bits (one call per distinct Secret), and writes no audit row. It is reported only to a caller with Configuration read and update, the same gate asconfigurationSecretsOperate; otherwise it is empty. It names bindings only, which a Configuration reader already sees; it names no Secret.configurationSecretsOperateis now "reported and the list is empty", which is the same value as before.getConfigurationSecretSourcesbecomesgetConfigurationSecretBindingSources(name to source).SLACK_APP_TOKEN,SLACK_BOT_TOKEN), the channel Secrets panel and the Channels drawer stay editable. The panel shows a note that names the token to replace, and the drawer notice says the same. A save that keeps a listed token on its current Secret is refused before any request, and the message names the binding. A listed name that channel saves keep (any other key) leaves both read-only, and the note names that key. An unknown or unlisted answer keeps today's read-only rule. The Configuration editor submits no bindings, so it keeps the fix(console): say up front when a configuration save needs secret operate on its bound secrets #3611 rule. While channel saves can succeed, the draft is not called read-only. A panel save rereads the permission answer, so the drawer and the panel stop asking to replace a binding the save rebound.Components/Credentials→ "Slack tokens, editor must replace the bot token Secret", shows the state.Verification
tests/integration/console-api.test.mjs: a new test, "the per-binding Secret answer names the bindings a Configuration save must replace". Without Configuration update (Agent update only) the answer is empty. With update and partialoperate, both names that bind the unoperable Secret are listed, sorted, and no denial is audited. A real PATCH that keeps a listed name answers 403. A PATCH that rebinds every listed name to the member's Secret answers 200, and the answer is then empty. An IAM failure on a Secret operate decision answers 503 for the whole answer. The exact-shape asserts include the new field.tests/browser/console-agent-detail.test.mjs:draftReadOnly, the hint hidden, no reread after a panel save, the JSON editor following the channel rule.console-api.test.mjsandconsole-agent-detail.test.mjspass (14/14 and 63/63). Pins at 2 CPUs: the 4 changed browser tests and the 3 integration tests passed 20/20.tscfor the console, root and tests projects; eslint and prettier on the touched files;openapi:check; docs build check (294 pages, links); real docs word counter: agent-editing.md is 2483 words (was 2484).Media (real app with a local fixture: real API and IAM, simulated runtime). The Secrets are disposable.
Before (main): the panel is read-only and names a grant the API does not check.


After: the panel is editable and names the token to replace. A save that keeps the token is refused before any request. Replacing the token saves. The drawer notice says the same. The 390-wide view and the Storybook story follow.






Walkthrough video (refusal, then replacement and save): after-walkthrough.webm
Not verified: deployment of the saved bindings and a live Slack connection. They are outside this change.
Risks