Skip to content

feat: scheduled grants with nodkey preapprove (part 1 of #108) - #112

Merged
groupsky merged 1 commit into
mainfrom
feat/preapprove-108
Oct 28, 2026
Merged

groupsky merged 1 commit into
mainfrom
feat/preapprove-108

Conversation

@groupsky

Copy link
Copy Markdown
Contributor

Refs #108. This is part 1 of 2. It does not close the issue.

What it does

A tap can now approve a planned use of a secret or an SSH key: from a start time to an end time, for N uses. A job that runs later uses the grant without a tap.

  • One grant record in the approval core holds all grants (the one grant core from the 2026-10-27 comment on feat: website logins from a shared Bitwarden collection, with TOTP codes made on the broker #103). "Approve N min" and ssh-grant grants use the same record with no use limit, so they do not change. There is room for a login scope later; nothing for logins is built.
  • Command: nodkey preapprove (--secret NAME ... | --key K --user U --host H ...) --from T --until T --uses N [--reason TEXT], and nodkey preapprove --cancel ID (only the same client; an unknown ID and an ID of another client get the same answer).
  • Config: preapprove = true on a rule (off by default, refused on ask = "never"), and [preapprove] limits: max_ahead (7 days), max_open (8 h), max_uses (10), max_grants (5 per client).
  • Use: one grant must cover the whole request (no mix with other grants or rules). Each use sends the silent notice and counts toward the notice limits; if the notice fails, the use is denied. For a key, each SSH login takes one use.
  • End: when the uses run out, at the end time (on both clocks), on cancel, on a later Deny, or on a broker stop. One grant_ended audit entry with the cause and the uses left. grant_used has a new via, scheduled.
  • API: /v1/preapprove and /v1/preapprove/cancel, strict decoding with caps.
  • Docs: DESIGN.md (sections 7, 8, 9, 10, 14, 15) records the answers to open questions 1-6. THREAT-MODEL.md has the new threat (a planned grant used by something else on the same client). docs/setup.md shows a nightly job, and says that a tool with many SSH connections needs ControlPersist or more uses.

Part 2 (next pull request)

The Revoke button on the message, the change of the message after a later Deny, the "not used" notice, and the stop notice. The core already ends grants for these causes; part 2 adds what the phone shows.

Security review

The security-reviewer agent reviewed the change, then each round of fixes. No critical or high findings. All findings were fixed:

  1. The client lost the grant ID when a signal came with the answer. Now it cancels the grant; if that fails, it prints how to cancel it.
  2. The broker kept a grant when it could not write or flush the answer. Now it cancels it and writes grant_ended.
  3. A grant could start after the broker stopped. Now it does not, and the broker answers 503 with approver_failed.
  4. The docs said the wrong order of grant_ended. Fixed.
  5. Follow-ups: the client says "a grant may have started" with the short code for any lost answer (signal, broken connection, timeout, a bad 200). A signal wins over a bad answer, as in ssh-grant. The cancel waits at most 30 s. Tests do not hang when they fail. Tests for each fix.

Tests

  • CI=true go test -race ./... passes on Go 1.27.1 and Go 1.26.0.
  • go vet ./... and golangci-lint run --build-tags e2e are clean.
  • The new tests pass with -count=20 -cpu 1,2,4.
  • I did not run the e2e test.

No new dependencies.

A tap now can approve a planned use of a secret or an SSH key: from a
start time to an end time, for N uses. One grant record in the approval
core holds all grants; "Approve N min" and ssh-grant grants use it with
no use limit, so they do not change.

- nodkey preapprove (--secret ... | --key --user --host ...) --from
  --until --uses, and nodkey preapprove --cancel ID
- per-rule preapprove = true (off by default, refused on never rules)
  and the [preapprove] limits: max_ahead, max_open, max_uses, max_grants
- each use sends the silent notice and counts toward the notice limits
- grant_ended audit entry; grant_used via scheduled
- DESIGN.md records the answers to open questions 1-6 of #108

Part 2 (Revoke button, message after a later Deny, not-used notice,
stop notice) comes in a later pull request.

Refs #108
@groupsky
groupsky merged commit 102d0bf into main Oct 28, 2026
7 checks passed
@groupsky
groupsky deleted the feat/preapprove-108 branch October 28, 2026 20:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant