cli-guard examples/passthrough

NAME

passthrough-demo - wrap an existing binary as an audited subcommand

SYNOPSIS

passthrough-demo

DESCRIPTION

passthrough-demo exercises cli-guard's thin pass-through. The pattern wraps any external CLI (aws, gh, kubectl, docker, tailscale, plus every package manager) as a single coily verb with two properties:

1. Audit. Every invocation produces a JSONL row in
   ~/.coily/audit/*.jsonl with timestamp, full argv, cwd, exit
   code. Reconstructable from the row alone.
2. Argv validation. policy.ValidateArg rejects shell metacharacters
   before execve. Blocks the dumbest injection paths (`coily kubectl
   get pod 'foo; curl bad'`).

What the wrapper does NOT buy:

- Not a sandbox. A malicious binary or post-install hook
  installed on the host runs with the user's privileges. The
  wrapper is audit + gate, not isolation. Sandboxing belongs in
  agentcontainers, not here.
- Not deep verb modeling. The pass-through has no idea what
  `kubectl apply` does differently from `kubectl get`. Per-leaf
  readonly-vs-mutator gating is delegated to the lockdown deny
  list, which fires before coily ever runs.

Why per-CLI subcommand trees were ripped (issue #27): generator- driven trees that wrapped aws/gh/kubectl earned their cost only via the readonly-vs-mutator gate already handled by the lockdown deny list. The remaining benefits (help mirroring, tab completion below coily ops aws) were convenience without security value, and the cost was ~80k lines of generated Go plus a weekly refresh cadence per upstream. SkipFlagParsing + verb.Wrap is the same security boundary in 60 lines.

Operating model for an agent calling pass-through verbs:

- The wrapper does not pre-validate the wrapped tool's flag
  syntax. `coily ops aws --unknown-flag` reaches aws as
  `aws --unknown-flag`, and aws decides what to do with it.
- On policy rejection (exit 2), the argv never reached the
  binary. Do not retry; the input contained a forbidden byte.
- On upstream failure (exit 3), the binary ran. Stderr from the
  binary is the authoritative reason; coily's wrapping error is
  just the envelope.

Usage:

passthrough-demo [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]

COMMANDS

echo

audited passthrough wrapper around /bin/echo