feat(cmd): add CommandGate for per-command confirmation (#400)#401
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an injectable per-command confirmation mechanism (“CommandGate”) that is consulted at the cmd.Executor.Start chokepoint, enabling a single prompt per fully-decorated command (including sudo wrapping), with support for redaction and an Ungated() escape hatch for internal probes.
Changes:
- Introduces
cmd.CommandGate(+ helpers) and wires gate checks intocmd.Executor.Start, returningcmd.ErrCommandRejectedon denial. - Adds
cmd.Ungated()and applies it to privilege-detection probes (sudo/doas/uid0/Windows admin checks) to avoid changing detection behavior under a rejecting gate. - Adds client options
rig.WithCommandGate/rig.WithConfirmFuncand tests/examples covering propagation to derived runners (sudo/FS/services) and rejection behavior.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| sudo/windows.go | Marks Windows admin probe as Ungated() so confirmation doesn’t alter privilege detection. |
| sudo/sudo.go | Marks sudo availability probe as Ungated(). |
| sudo/noop.go | Marks UID0/root probe as Ungated(). |
| sudo/doas.go | Marks doas availability probe as Ungated(). |
| example_test.go | Adds an example demonstrating WithConfirmFunc behavior and output. |
| cmd/runner.go | Adds ErrCommandRejected error sentinel. |
| cmd/executor.go | Adds gate plumbing to Executor and consults the gate in Start; refactors closer cleanup via closeAll. |
| cmd/execoptions.go | Adds skipGate option + Ungated() exec option to bypass the gate per-command. |
| cmd/confirm.go | Introduces CommandGate, CommandGateFunc, and CommandGateSetter API. |
| cmd/confirm_test.go | Unit tests for gate allow/deny, decoration visibility, and redaction. |
| clientoptions.go | Adds WithCommandGate / WithConfirmFunc options and stores the configured gate in client options. |
| client.go | Injects the configured gate into runners that support CommandGateSetter. |
| client_confirm_test.go | Integration tests verifying gating occurs once per sudo-wrapped command and propagates to derived FS operations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 05:52
6210ebc to
da79c16
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 06:00
da79c16 to
12ec7cb
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 06:20
12ec7cb to
07fc95a
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 06:29
07fc95a to
bf28063
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 07:20
bf28063 to
aa4232e
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 08:11
aa4232e to
e02480f
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 08:27
e02480f to
c44f591
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 09:00
380ab0a to
4872550
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 10:30
4872550 to
3373b6c
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 10:36
3373b6c to
dc61a79
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 10:52
dc61a79 to
34a72be
Compare
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 11:02
34a72be to
4a880c8
Compare
Restores rig v0.x's built-in per-command confirmation as an injectable gate rather than a global. A CommandGate is consulted in Executor.Start, the single chokepoint every Exec/Start/remotefs/service call funnels through, with the fully decorated (sudo-wrapped), PowerShell-decoded, redacted command — so it fires exactly once per command at the outermost runner and can show a human-readable prompt without leaking secrets. The gate is set once on the Client via WithCommandGate / WithConfirmFunc and propagated to every derived runner (sudo clone, filesystem, services) the same way the logger is injected, avoiding the leaky Runner-wrapper approach that misses the StartProcess chaining path. Internal privilege-detection probes (sudo/doas availability, UID0 and Windows admin checks) run Ungated so a rejecting gate cannot silently disable sudo instead of surfacing an error. Adds cmd.CommandGate, cmd.CommandGateFunc, cmd.CommandGateSetter, cmd.ErrCommandRejected, the cmd.Ungated() exec option, and the rig.WithCommandGate / rig.WithConfirmFunc client options. Signed-off-by: Kimmo Lehto <klehto@mirantis.com>
kke
force-pushed
the
feat/command-confirmation
branch
from
July 6, 2026 11:15
4d889dd to
5579ffb
Compare
kke
marked this pull request as ready for review
July 6, 2026 11:16
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.
Fixes #400
Restores rig v0.x's built-in per-command confirmation as an injectable gate rather than a global. A CommandGate is consulted in Executor.Start, the single chokepoint every Exec/Start/remotefs/service call funnels through, with the fully decorated (sudo-wrapped), PowerShell-decoded, redacted command — so it fires exactly once per command at the outermost runner and can show a human-readable prompt without leaking secrets.
The gate is set once on the Client via WithCommandGate / WithConfirmFunc and propagated to every derived runner (sudo clone, filesystem, services) the same way the logger is injected, avoiding the leaky Runner-wrapper approach that misses the StartProcess chaining path.
Internal privilege-detection probes (sudo/doas availability, UID0 and Windows admin checks) run Ungated so a rejecting gate cannot silently disable sudo instead of surfacing an error.
Adds cmd.CommandGate, cmd.CommandGateFunc, cmd.CommandGateSetter, cmd.ErrCommandRejected, the cmd.Ungated() exec option, and the rig.WithCommandGate / rig.WithConfirmFunc client options.