Skip to content

Policy framework: allow / require-approval / deny per (session, host, command) #9

@cuihtlauac

Description

@cuihtlauac

Problem

Every privileged command goes through the same TUI Y/N prompt, regardless of how trivial or how routine. There is no way to say "this agent may run apt-get update without prompting on this host" or "this agent must never run dd." The result is approval fatigue (humans Y-mash through long sequences) which is the exact failure mode sudo-proxy is meant to prevent.

The README has flagged this as needing a policy framework, and the warning is well-placed: sudoers-style regex allowlists have a 30-year history of being misconfigured (* doesn't mean what users think, argument-order tricks bypass intent). The naive fix is worse than the status quo.

Proposal

Per-host TOML policy at ~/.config/sudo-proxy/policy.toml, evaluated server-side — never trust the client to self-classify. Three tiers per matched command:

  • allow — skip TUI, run immediately. Off by default. Audit-logged (Append-only audit log of approved requests and outcomes #6) at a higher visibility so retroactive review is possible.
  • require-approval — current behaviour, the unmatched default.
  • deny — refuse outright with Status::Denied, do not prompt.

Match structure (no regex):

  • Key: (session, host) from the request, falling back to (session, *) then (*, host) then (*, *).
  • Command match: resolved absolute path of argv[0] (already computed for the TUI), exact string. No PATH-based matching — too easy to spoof.
  • Argument match: exact-string list, or named placeholder ({pkg} matches one token, no whitespace, no shell metachars). No globs, no regex.
  • Pipelines (req.pipeline, src/protocol.rs:16): a pipeline matches only if every stage matches; a pipeline with any unmatched stage falls through to require-approval.

First match wins. deny rules are evaluated before allow rules within the same scope.

Things to consider:

  • Build Append-only audit log of approved requests and outcomes #6 (audit log) first. Designing an allowlist without weeks of real-workload data is speculation. The audit log lets operators see which commands they actually approve repeatedly, then write rules accordingly.
  • TUI must show prominently, the first time a session triggers an allow rule, that auto-approval was applied. "Allowed by policy: rule apt-update-allow" line. Otherwise operators don't notice when policy is wider than they remember.
  • Reload behaviour: SIGHUP-reload, or stat-on-each-request? Stat-on-each-request is simpler and the rule file is small.
  • Validation: reject policy files that don't parse, with a clear error, rather than silently falling back to deny-all.
  • This depends on Per-session policy isolation (allowlists, rate limits, audit grouping) #8 (session validation) — session becomes a principal at the policy layer and must be trustworthy.
  • Out of scope for this issue: time-based rules, per-rule rate limits, GUI editor.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions