Repository navigation
feat(cli): backend-signed approval webhooks with submit-and-poll - #1879
Merged
Merged
Conversation
Add `auth: "platform"` to webhook approval backends
- Sign every approval request with the enrollment key (`nono-request-v1`),
stamping the six `X-Nono-*` headers the platform verifies.
- Derive `<platform_url>/api/v1/approvals` from enrollment state when `url`
is omitted; require https or loopback http for signed requests.
- Follow the platform contract: submit, then poll
`GET /api/v1/approvals/{request_id}` until a decision or `timeout_secs`.
- Send `X-Nono-Timeout-Secs` on every webhook request (signed or not) so
the backend hold for the client's actual patience.
- Report elapsed time, not the configured timeout, in HTTP error denials.
- Reject `auth` on terminal and chain backends; keep the legacy single
blocking POST for unsigned webhooks unchanged.
Signed-off-by: Luke Hinds <lukehinds@gmail.com>
…l webhooks Two review findings on the platform-signed approval backend: - The HTTP agent followed redirects, including HTTPS to HTTP, carrying the signed X-Nono-* headers to whatever host the redirect named, which could then answer `granted`. Approval webhooks now never follow redirects; a 3xx surfaces as a non-2xx status and is treated as a denial. This applies to plain webhooks too, since a decision must always come from the configured URL. - Each poll hop used the whole configured timeout as its HTTP timeout and a grant was accepted whenever it arrived. Each hop is now bounded by the remaining budget, and the deadline is re-checked after every reply so a decision that lands after `timeout_secs` resolves as Timeout. Signed-off-by: Luke Hinds <lukehinds@gmail.com>
Document the contract the way audit delivery and remote attach are documented: - docs/protocols/approval-webhook-v1.md specifies both variants of the unsigned single POST any HTTP service can answer, and the signed submit-and-poll exchange for enrolled workloads (headers, canonical string, status body, hold semantics, deadline rules, and server requirements). - tests/fixtures/approval-status-v1.json and approval-poll-request-v1.json pin the documented response and the bodiless GET digest. - The Tool Sandbox guide now documents `approval_backends` entries including `auth: "platform"`. Signed-off-by: Luke Hinds <lukehinds@gmail.com>
Contributor
PR Review SummarySize
Affected crates
Blast radius — BroadThis PR touches: source code,documentation,configuration / policy files Updated automatically on each push to this PR. |
SequeI
approved these changes
Sep 14, 2026
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
nono-request-v1),stamping the six
X-Nono-*headers a backend verifies.<backend_url>/api/v1/approvalsfrom enrollment state whenurlis omitted; require https or loopback http for signed requests.
GET /api/v1/approvals/{request_id}until a decision ortimeout_secs.X-Nono-Timeout-Secson every webhook request (signed or not) sothe backend hold for the client's actual patience.
authon terminal and chain backends; keep the legacy singleblocking POST for unsigned webhooks unchanged.
Checklist