Skip to content

feat(cli): route privileged provisioning through graphical sudo (askpass)#56

Merged
ElbertePlinio merged 2 commits into
mainfrom
feat/27-graphical-sudo
Jul 23, 2026
Merged

feat(cli): route privileged provisioning through graphical sudo (askpass)#56
ElbertePlinio merged 2 commits into
mainfrom
feat/27-graphical-sudo

Conversation

@ElbertePlinio

Copy link
Copy Markdown
Member

Summary

Implements #27 per the locked v1 shared askpass contract (pinned on the issue), mirroring the pickforge#215/#258 sibling semantics:

  • pure four-state capability detector (provision/askpass.ts): graphical session + user SUDO_ASKPASS if executable else the fixed probe list; Linux-only, fail-closed
  • ProvisioningStep.privileged now materializes as arg-array sudo -A with SUDO_ASKPASS as the only injected env key (hostile config values structurally cannot become sudo options — argv-position verified in review); old sudo -n path removed
  • pre-flight failure (no helper/headless) → actionable error naming the manual fallback, before any mutation; runtime denial/cancellation → distinct cancelled state via sudo's own diagnostics, no retry, redacted
  • fixes a pre-existing bug where a static "sudo not found" reason masked the real preflight failure; JSON reports now expose the structured status for machine consumers
  • mcp-server no-sudo invariant untouched and still enforced

Refs #27 — issue stays open for the formally-signed-off hardware smoke (real sudo -A -v success + cancellation on Elberte-PC, RC phase; sign-off recorded on the issue). No feature flag: self-contained.

Validation

  • typecheck, build, focused suites green (askpass 14, executor 25, cli 39 incl. 10 Linux-gated tests that run on ubuntu CI with no real-sudo dependency, security 32)
  • full suite: 976 passed / 44 failed — failing set verified identical to the pre-existing Darwin-only platform cluster, zero overlap with touched files

Local review: serious security class — Opus 4.8 (security/trust: clean), Sonnet 5 (correctness: clean + the smoke-deferral P2 resolved by explicit sign-off), Sonnet 5 (conformance: clean, clause-by-clause table on the issue's contract); 2 accepted P3s fixed in b6e3a87. KISS keep ×3.

…ass)

Implements the "Shared graphical sudo (askpass) security contract — locked
v1" (#27, shared with pickforge/pickforge#215/#258): a
pure four-state capability detector (available/no-helper/headless/
unsupported-platform) gated to Linux, wired into the provisioning executor
so privileged steps run `sudo -A` with an explicit SUDO_ASKPASS — the only
env var this feature injects — instead of the prior ad hoc `sudo -n`.

Missing capability fails preflight, before any mutation, with an actionable
error naming the manual `sudo ...` fallback; sudo-level denial/cancellation
at runtime (detected from sudo's own `sudo:`-prefixed diagnostics, never
prompt text) surfaces as a distinct `cancelled` status with no retry.
Reconciled with the existing no-sudo policy: MCP tools still never import
provisioning code or touch sudo (unchanged, still enforced by
test/security/security-no-sudo.test.ts); the CLI's privileged-step path
remains the sole, explicit, consent-gated sudo entry point.

Also fixes a section-level privilegeUnavailable.reason override (written
only for the pre-existing "sudo missing" case) from masking the new,
correct askpass-unavailable message with a stale "sudo not found" one.
…refix

Add status (mirrors ExecuteProvisioningResult.status) to SetupLabUserReport,
InitReport, and the doctor --fix report, so --json consumers can tell a
sudo-cancelled run apart from declined/failed without string-matching.

Fix prepareSections dropping a section's "lab-user: "/"avd: " skip-reason
context for an askpass-unavailable failure (it only ever applied to the
older sudo-missing case). Sections can now supply an optional
privilegeUnavailable.context prefix that askpass-unavailable reasons honor
too, restoring parity with sibling skip reasons in doctor --fix.
@ElbertePlinio
ElbertePlinio merged commit bc1aefb into main Jul 23, 2026
1 check passed
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