Skip to content

runtime command run

runtime command run <binary> [args...]

The Command Engine wraps approved CLI binaries. It is a thin deterministic wrapper: it never interprets a binary's output, it only executes the requested subcommand and returns whatever the binary printed.

runtime command run git status
runtime command run terraform plan
runtime command run kubectl get pods
runtime command run gh repo list --limit 5

Two ways the Command Engine is reached

  1. A provider chose it. runtime github pr list dispatches to the GitHub provider, which decided that operation is best served by gh. The provider supplies the binary and arguments.
  2. Directly, via command run — the raw escape hatch for binaries no provider covers.

Both paths are gated by the same policy. When a provider picks the CLI transport, allowed_binaries and command_policy are evaluated on top of the provider's own rule. A provider can only reach binaries the installation already permits, and cannot launder a denied binary through an operation.

Prefer a provider operation

command run is an escape hatch, not the default style. When a provider already exposes what you need, use it:

runtime github repo list             # preferred
runtime command run gh repo list     # works, but bypasses the curated surface

A provider operation is a stable contract — the transport can change beneath it without breaking you. A command run invocation is pinned to one tool's exact CLI forever.

Allowed binaries

Only binaries in allowed_binaries may execute at all. The seeded policy ships 21:

Category Binaries
VCS / GitHub git, gh
IaC terraform, pulumi, packer
GCP gcloud, gsutil, bq
AWS / Azure aws, az
Kubernetes kubectl, oc, helm, kustomize, flux, istioctl, argocd
Containers docker, podman
Secrets vault, sops

Check what your install actually allows — new entries in a release do not reach an existing policy-config.yaml:

runtime config validate

That report also tells you which allowed binaries are actually installed on the machine.

See Command Engine Binaries for per-binary detail, and Policy to change the list.

Governance layers

1. Binary allow-list

A binary not in allowed_binaries can never run. Full stop.

2. Hard-denied binaries

command_policy:
  denied_binaries:
    - rm
    - sudo
    - chmod
    - curl
    - wget
    - ssh

Refused outright, independent of allowed_binaries — adding one to the allow-list does not un-deny it.

3. Subcommand rules

command_policy:
  rules:
    terraform:
      denied: ["destroy"]
    git:
      denied: ["push --force", "reset --hard"]
List Matching
denied A contiguous run of argument tokens anywhere in the command
allowed Prefix match; when present, only matching prefixes may run

Denials always win.

Because denied matches anywhere rather than as a prefix, leading flags cannot bypass a rule:

runtime command run terraform destroy -auto-approve   # denied
runtime command run git -C /tmp/wd push --force       # denied

Evaluation order

Policy is evaluated before the Command Engine runs, against the raw arguments — before Runtime Context injection happens.

allow-list → denied_binaries → subcommand rules → auth → context injection → execute

This ordering is deliberate: an injected flag can only ever narrow a command, never smuggle a denied operation past the policy check.

Authentication

Auth is resolved from config.yaml's command_providers map:

command_providers:
  gh: github
  gcloud: gcp
  gsutil: gcp
  bq: gcp
  kubectl: kubernetes
  oc: openshift
  helm: kubernetes
  flux: kubernetes
  istioctl: kubernetes

A binary with no entry skips the Auth Engine entirely. There is no silent fallback to a default provider — omission means "manages its own credentials" (terraform's provider blocks, Docker's registry logins) or "no Auth Engine provider exists for that platform yet" (aws, az, vault).

gh needs no gh auth login — the runtime forwards the validated token as GH_TOKEN and GITHUB_TOKEN.

Runtime Context injection

Injection is narrow, on purpose — only two cases:

Binary Injected From
gcloud --project=<project> cloud.project
kubectl, oc -n <namespace> kubernetes.namespace

Nothing is injected when the field is empty or the flag is already present in your arguments. Every other allowed binary receives its arguments unchanged, however many are added to allowed_binaries over time.

Keeping the injection surface small keeps it auditable: a new binary does not silently gain context injection.

helm, flux and istioctl accept -n but don't receive it

They map to the kubernetes auth provider but have no injection case. Pass -n <namespace> yourself where those tools need it.

Auditing

Every invocation — allowed, denied, or failed — is recorded. Nothing executes without a trace.

runtime command run git push --force
runtime audit tail -n 1 --output json

The transport field is empty for command run records, which is how you tell a direct escape-hatch invocation apart from a provider operation that happened to choose the CLI.

Deliberately excluded

ansible and ansible-playbook are not on the allow-list and should not be added by the same pattern as everything else.

Their ad-hoc and playbook modules (ansible all -m shell -a '<opaque payload>') are arbitrary remote command execution — the same risk category as ssh, which is refused outright. The dangerous part is an opaque payload argument, not a recognizable subcommand, so a denied: rule cannot meaningfully cap it the way terraform destroy can be capped.

Revisit deliberately if a real need arises.

In capabilities

A binary: step is the same escape hatch inside a capability:

workflow:
  - binary: gh
    args: [release, upload, "v1.0.0", "./dist/runtime"]

The binary must be in allowed_binaries or validation fails. Note that runtime itself is not an allowed binary — a capability cannot invoke another capability. See Composing capabilities.