Skip to navigation

CLI Commands

View as Markdown

APF ships three command-line programs. This page lists every flag each one accepts on the main branch. Where a flag has an environment variable, the flag takes precedence over the variable.

ProgramPurpose
apf-policy-serviceThe Policy Administration Point. Loads, verifies, projects, and serves signed bundles.
apf-policy-gatewayThe Policy Decision Point. Evaluates requests and hosts the OpenShell interceptor and middleware listeners.
apf-compileOffline tool for signing and verifying bundles.

Build all three with Cargo:

cargo build --release -p apf-policy-service -p apf-policy-gateway -p apf-compile

apf-policy-service

apf-policy-service <COMMAND> [OPTIONS]
CommandPurpose
serveRun the policy service.
keygenGenerate an Ed25519 key pair for document provenance tokens.

serve

apf-policy-service serve [OPTIONS]

Core Options

FlagEnvironment variableDefaultDescription
--config <PATH>APF_CONFIGNoneTOML configuration file. Refer to Configuration File.
--socket <PATH>APF_SOCKET/run/apf/policy-service.sockUnix socket for the PolicyService gRPC API. The service removes an existing file at the path, sets the parent directory to 0700, and binds the socket with mode 0600.
--allowed-uid <UID>APF_ALLOWED_UIDThe service’s own UIDThe only peer UID accepted on the socket. Other peers are disconnected and recorded as auth.uds_peer_rejected.
--audit-log-dir <DIR>APF_AUDIT_LOG_DIRNoneDirectory for apf-policy-service-audit.jsonl. Required. The service refuses to start without it or if it cannot write there.
--trust-root-dir <DIR>APF_TRUST_ROOT_DIR./trust-rootsBundle trust roots: *.pub Ed25519 keys and *.pem or *.p256 ECDSA P-256 keys. The file stem is the key ID. The service refuses to start if the directory holds no keys.
--counter-store <PATH>APF_COUNTER_STORE/var/lib/apf/counterAnti-rollback counter file. A sidecar <PATH>.digest records the accepted payload digest. A missing file means revision 0.
--surfaces <KIND,...>APF_SURFACESAll surfacesComma-separated list of surface kinds to serve. Requests for other kinds are refused. The names are not validated. Include apf.policy.v1 for the gateway and openshell.sandbox.v1 and openshell.provider-profile.v1 for the interceptor.

Policy Source Options

FlagEnvironment variableDefaultDescription
--policy-source <SOURCE>APF_POLICY_SOURCElocallocal reads --bundle-path. http fetches from --bundle-source-url. Any value other than http is treated as local without an error.
--bundle-path <PATH>APF_BUNDLE_PATHNoneSigned bundle manifest for the local source. Required when the source is local. Member paths resolve relative to its directory.
--bundle-source-url <URL>APF_BUNDLE_SOURCE_URLNoneURL of a gzipped tarball of the bundle directory. Required when the source is http. The first fetch happens at startup and fails closed.
--bundle-source-token-file <PATH>APF_BUNDLE_SOURCE_TOKEN_FILENoneFile holding the bearer token for the bundle source. Takes precedence over --bundle-source-token. An empty file is an error.
--bundle-source-token <TOKEN>APF_BUNDLE_SOURCE_TOKENNoneBearer token for the bundle source. Prefer the file form. Passing it as an argument records startup.token_in_process_args.
--bundle-source-poll-interval-secs <SECS>APF_BUNDLE_SOURCE_POLL_INTERVAL30Seconds between polls of the HTTP source. The environment variable has no _SECS suffix. Do not set 0: the polling task stops, and the service keeps running without updates.
--resolver <RESOLVER>APF_RESOLVERpassthroughDocument name resolver: passthrough or claims. Other values are rejected. Refer to Policy Name Resolution.
--claims-config <PATH>APF_CLAIMS_CONFIGNoneJSON file with a role_map from user subject to bundle variant. Required with --resolver claims.

Document Signing Options

FlagEnvironment variableDefaultDescription
--document-signing-key <PATH>APF_DOCUMENT_SIGNING_KEYNoneEd25519 seed file used to sign provenance tokens. The first non-comment line must be ed25519:<base64 seed>. Without it, the service generates an ephemeral key and records startup.ephemeral_signing_key.
--document-key-id <ID>APF_DOCUMENT_KEY_IDapf-devKey ID written to the kid header and sub claim of every provenance token. Must match the gateway’s --document-key-id.
--document-ttl-secs <SECS>APF_DOCUMENT_TTL_SECS0Lifetime of documents served over gRPC. When greater than zero, sets valid_until_ms and the token’s exp claim. 0 means no expiry.

HTTP Surface Options

FlagEnvironment variableDefaultDescription
--http-addr <ADDR:PORT>APF_HTTP_ADDRDisabledAddress for the HTTP surface. Must be an IP address and port. A non-loopback address records startup.http_bind_non_loopback.
--http-bearer-token-file <PATH>APF_HTTP_BEARER_TOKEN_FILENoneBearer token for /v1/documents and /v1/refresh. Required whenever --http-addr is set. An empty file is an error.

Other Options

FlagDescription
--config-dumpAccepted but has no effect in this release.

keygen

Writes <key-id>.seed and <key-id>.pub and prints the public key.

apf-policy-service keygen [--key-id <ID>] [--output-dir <DIR>] [--force]
FlagDefaultDescription
--key-id <ID>apf-devKey ID and file name stem.
--output-dir <DIR>.Output directory, created if missing.
--forceOffOverwrite existing files. Without it, the command fails if either file exists.

The files are written with the process umask. Set their permissions yourself, for example chmod 0600 on the seed.

Configuration File

--config reads a TOML file whose values fill in options not set on the command line or in the environment.

KeySectionOption
bundle_pathTop level--bundle-path
trust_root_dirTop level--trust-root-dir
audit_log_dirTop level--audit-log-dir
allowed_uidTop level--allowed-uid
http_addrTop level--http-addr
surfacesTop level--surfaces
signing_key[verifier]--document-signing-key
backend[policy_source]--policy-source
bundle_source_url[policy_source]--bundle-source-url
bundle_source_token[policy_source]--bundle-source-token
bundle_source_token_file[policy_source]--bundle-source-token-file
bundle_source_poll_interval_secs[policy_source]--bundle-source-poll-interval-secs
backend[resolver]--resolver
claims_config[resolver]--claims-config

The configuration file has several limitations in this release:

  • The socket and counter_store keys apply only when the flag or environment variable holds an outdated default, /run/apf/apf-policy-service.sock or /tmp/apf-counter, and then override it. In practice they do not set the option. The document_ttl_secs, [verifier] key_id, and [provenance] keys are parsed but never applied. Set these options with flags or environment variables.
  • There is no key for --http-bearer-token-file. If you set http_addr in the file, pass the token file as a flag or environment variable.
  • Unknown keys are ignored without a warning.
  • A flag or environment variable whose value equals the built-in default can be overridden by the file.
  • The sample examples/policy-service.toml in the repository is out of date and does not work as written.

Refer to Settings Are Ignored.

apf-policy-gateway

apf-policy-gateway [OPTIONS]

The gateway has no subcommands and no configuration file. Provider registration is a separate YAML file passed with --pip-config.

Core Options

FlagEnvironment variableDefaultDescription
--socket <PATH>APF_GATEWAY_SOCKET/run/apf/policy-gateway.sockUnix socket for the EvaluationService gRPC API, mode 0600.
--allowed-uid <UID>APF_GATEWAY_ALLOWED_UIDThe gateway’s own UIDThe only peer UID accepted on the socket. Rejected peers are logged, not audited.
--policy-service-socket <PATH>APF_POLICY_SERVICE_SOCKET/run/apf/policy-service.sockThe policy service socket. The gateway exits if it cannot connect at startup.
--audit-log-dir <DIR>APF_AUDIT_LOG_DIRNoneDirectory for the gateway’s audit files. Required.
--bundle-refresh-interval-secs <SECS>None10Seconds between polls of the policy set digest. 0 disables hot swap, provider profile reconciliation, and running sandbox refresh.

Provider Options

FlagEnvironment variableDefaultDescription
--pip-config <PATH>APF_PIP_CONFIGNoneYAML registration of the policy information providers the gateway consults in the Enrichment stage. Loaded and validated before any listener binds, and the gateway refuses to start on any error. Without it there is no enrichment. Refer to Policy Information Providers.
--pip-stage-budget-ms <MS>APF_PIP_STAGE_BUDGET_MS250Hard cap in milliseconds on the whole Enrichment stage. It is the default and the upper bound of every registration’s timeout_ms, and it must stay below the timeout OpenShell applies to middleware calls.

Provenance Options

FlagEnvironment variableDefaultDescription
--jwks-url <URL>APF_JWKS_URLNoneThe policy service’s /.well-known/jwks.json. Fetched at startup, and a failed fetch stops startup. Required when the interceptor listener is enabled. Without it, provenance verification is off and the gateway logs a warning.
--jwks-refresh-interval-secs <SECS>None60Seconds between JWKS fetches. 0 disables refresh. A failed refresh keeps the current key.
--document-key-id <ID>APF_DOCUMENT_KEY_IDapf-devExpected sub claim of provenance tokens on provider profile snapshots. Set it to the policy service’s --document-key-id. Sandbox admission does not compare it, and the JWKS key is used without matching its kid.
--document-kind <KIND>Noneopenshell.sandbox.v1Surface kind the interceptor fetches for admission.
--document-name <NAME>NonedefaultDocument name the interceptor fetches for admission. Matches the SandboxPolicy member’s metadata.name.

OpenShell Options

FlagEnvironment variableDefaultDescription
--openshell-gateway-url <URL>APF_OPENSHELL_GATEWAY_URLNoneOpenShell gateway URL. Enables provider profile reconciliation and, with --jwks-url, running sandbox refresh. There are no client TLS or CA options for this connection.
--openshell-compute-driver <DRIVER>APF_OPENSHELL_COMPUTE_DRIVEREmptyThe OpenShell gateway’s compute driver, such as docker, podman, or kubernetes. The interceptor admits caller-supplied driver config (driver_config) in a sandbox request only when its single driver key equals this value. When the flag is empty and --openshell-gateway-url is set, the gateway asks OpenShell for its driver once at startup; if that fails, or neither is set, every request that carries driver config is denied.
--openshell-interceptor-addr <ADDR:PORT>APF_OPENSHELL_INTERCEPTOR_ADDRDisabledListener for the gateway interceptor. Must be an IP address and port.
--openshell-interceptor-auth-trust-file <PATH>APF_OPENSHELL_INTERCEPTOR_AUTH_TRUST_FILENoneExtension trust profile for interceptor callers.
--openshell-interceptor-tls-cert-file <PATH>APF_OPENSHELL_INTERCEPTOR_TLS_CERT_FILENonePEM certificate for the interceptor listener.
--openshell-interceptor-tls-key-file <PATH>APF_OPENSHELL_INTERCEPTOR_TLS_KEY_FILENonePEM private key for the interceptor listener.
--openshell-interceptor-allow-insecure-transportAPF_OPENSHELL_INTERCEPTOR_ALLOW_INSECURE_TRANSPORTOffServe the interceptor without TLS or caller authentication. Development only.
--openshell-middleware-addr <ADDR:PORT>APF_OPENSHELL_MIDDLEWARE_ADDRDisabledListener for the supervisor middleware.
--openshell-middleware-auth-trust-file <PATH>APF_OPENSHELL_MIDDLEWARE_AUTH_TRUST_FILENoneExtension trust profile for middleware callers.
--openshell-middleware-tls-cert-file <PATH>APF_OPENSHELL_MIDDLEWARE_TLS_CERT_FILENonePEM certificate for the middleware listener.
--openshell-middleware-tls-key-file <PATH>APF_OPENSHELL_MIDDLEWARE_TLS_KEY_FILENonePEM private key for the middleware listener.
--openshell-middleware-allow-insecure-transportAPF_OPENSHELL_MIDDLEWARE_ALLOW_INSECURE_TRANSPORTOffServe the middleware without TLS or caller authentication. Development only.

Listener Rules

The gateway checks each OpenShell listener before it does anything else:

  • An enabled listener needs either all three of its trust file, certificate, and key, or the insecure flag.
  • The insecure flag cannot be combined with a trust file, certificate, or key.
  • A trust file, certificate, key, or insecure flag without the listener’s address is an error.
  • Certificate files must be regular files of at most 1 MiB that are not group or world writable. Key files must be regular files of at most 64 KiB with no group or other permissions. Symbolic links are refused.

Refer to Configure Service Authentication for the trust profile format.

Audit Files

FileWritten when
apf-policy-gateway-audit.jsonlAlways.
apf-policy-gateway-interceptor-audit.jsonlThe interceptor listener is enabled.
apf-policy-gateway-middleware-audit.jsonlThe middleware listener is enabled.

The gateway does not accept --trust-root-dir or --counter-store. It verifies documents through provenance tokens and the JWKS, and the policy service owns the counter store.

apf-compile

apf-compile <COMMAND> [OPTIONS]
CommandPurpose
genfixtureFill in member digests in a bundle template and sign it.
compileVerify a signed bundle and, optionally, compile it.

On failure, both commands print Error: <message> to standard error and exit with status 1.

genfixture

apf-compile genfixture --template <PATH> --key <PATH> --out <PATH> [OPTIONS]
FlagDefaultDescription
--template <PATH>RequiredBundle template with a REPLACE_WITH_DIGEST placeholder for every manifest entry.
--key <PATH>RequiredEd25519 seed file, ed25519:<base64 seed>.
--out <PATH>RequiredOutput path for the signed bundle. Overwritten if it exists.
--base-dir <DIR>The template’s directoryDirectory that member paths are resolved against.
--keyid <ID>The --key file stemKey ID written into the signature. Verifiers look for <keyid>.pub in their trust-root directory.
--generate-keyOffCreate the key file and a public key file if --key does not exist.
--pubkey-out <PATH>--key with a .pub extensionWhere to write the generated public key.

The command prints one manifest <path>: sha256=<digest> line per member and signed bundle written to <path>.

genfixture fills placeholders in the order manifest entries appear, one per entry. Use a placeholder for every entry and nowhere else in the template, including comments. Refer to Compile and Sign.

compile

apf-compile compile --bundle-path <PATH> [--trust-root-dir <DIR>] [--verify-only]
FlagDefaultDescription
--bundle-path <PATH>RequiredSigned bundle manifest.
--trust-root-dir <DIR>./trust-rootsTrust roots to verify the signature against.
--verify-onlyOffVerify only. Without it, also load and compile every member.
--key-id <ID>apf-devAccepted but not used. Any trusted key verifies the bundle.

On success it prints verified digest=<sha256> counter=<revision>, and without --verify-only, one projection kind=<kind> name=<name> bytes=<n> line per surface. It produces apf.policy.v1 and openshell.provider-profile.v1, not the OpenShell sandbox projection.

The command uses a new, empty counter store for every run, so it cannot detect a replayed bundle, and it rejects policy_revision: 0. It does not build the Cedar evaluator. Refer to Validate and Test Policies.

Logging

apf-policy-service and apf-policy-gateway log to standard output. Set RUST_LOG to change the level, for example RUST_LOG=debug or RUST_LOG=apf_policy_gateway=debug. The default is info. apf-compile prints plain output and has no log level.

Repository Tasks

The repository’s mise.toml defines development tasks. Run them with mise run <task>.

TaskRuns
lintcargo fmt --check, cargo clippy -- -D warnings, and cargo deny check.
testcargo nextest run.
dag-guardcargo xtask dag-guard, which enforces the crate dependency rules.
buf-lintbuf lint contracts/.
sign-bundleRe-signs the demo bundle with the development key.
dev, dev-logs, dev-downdev builds both images, starts the Docker Compose stack in deploy/docker/, runs the smoke suite, and leaves the stack running. dev-logs follows its logs, and dev-down stops it and keeps its volumes.
e2e:composeBrings up the Compose stack, runs the smoke suite, and tears the stack down.
e2e:compose:openshellThe same, with an OpenShell gateway that admits a sandbox through APF.
e2e:kindInstalls the Helm chart on a local kind cluster next to an OpenShell gateway, runs the smoke suite, and uninstalls.
e2e:parityChecks that the Compose stack and the Helm chart start both services with the same flags. No stack is started.
dev-nativeBuild and run both services natively.
docs, docs:servedocs runs fern check and scripts/check_docs_nav.py to validate the documentation configuration, links, and navigation. docs:serve previews the site locally. Both use the Fern CLI version pinned in fern/fern.config.json and need Node.js and uv. Refer to Contributing.

dev-native does not start on main because it sets no audit directory, which both services require, and passes flags the gateway no longer accepts. Use the commands in Installation instead.

Next Steps