Skip to content

feat(cli): backend-signed approval webhooks with submit-and-poll - #1879

Merged
lukehinds merged 3 commits into
mainfrom
approval-backend-auth
Sep 14, 2026
Merged

lukehinds merged 3 commits into
mainfrom
approval-backend-auth

Conversation

@lukehinds

Copy link
Copy Markdown
Contributor
  • Sign every approval request with the enrollment key (nono-request-v1),
    stamping the six X-Nono-* headers a backend verifies.
  • Derive <backend_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.

Checklist

  • An issue exists and is linked above
  • All commits are signed-off, using DCO
  • All new code follows the project's coding standards (CLAUDE.md) and is covered by tests
  • Public-facing changes are paired with documentation updates
  • If this PR introduces a major feature, capability, or security-relevant change, a corresponding NEP has been opened or accepted and is linked

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>
@github-actions

Copy link
Copy Markdown
Contributor

PR Review Summary

Size

Metric Value
Lines added +1082
Lines removed -54
Total changed 1136
Classification Large (> 300 lines)

Affected crates

  • crates/nono-cli — CLI changes. Verify argument parsing, flag documentation, and UX behaviour across supported platforms.

Blast radius — Broad

This PR touches: source code,documentation,configuration / policy files


Updated automatically on each push to this PR.

@nogent-nolabs-ai nogent-nolabs-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nogent code review

No blocking issues; 0 findings.

Findings: none flagged in scope.

Automated code + security review. CI already covers clippy, rustfmt, tests, cargo-audit and commit-lint.

@lukehinds
lukehinds merged commit 9dbaa36 into main Sep 14, 2026
18 checks passed
@lukehinds
lukehinds deleted the approval-backend-auth branch September 14, 2026 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants