Documentation
Trust and Command Execution
Command Execution Gate
The CLI and default Go client do not run plugin commands unless all of these are true:
- The Application source names a plugin that matches a drydock plugin policy entry, or an unnamed Application plugin source matches trusted static discovery from policy.
- The matched policy entry uses
engine: execorengine: container. - The caller passes
--enable-plugins. - The command-backed policy came from trusted policy provenance.
No plugin command execution occurs unless --enable-plugins is passed. Native
rendering paths, including engine: avp-compat, engine: native-kustomize,
explicit argocd-vault-plugin sources, --enable-avp-compat, and
--enable-ksops-compat, do not execute plugin commands.
Discovered Argo CD CMP definitions that normalize to a safe kustomize build
command are interpreted by drydock’s native Kustomize renderer by default.
native-kustomize policy entries remain available as explicit overrides.
For native argocd-vault-plugin (AVP) compatibility, avp-compat performs
deterministic placeholder redaction with drydock native renderers. Explicit
Application plugin sources named argocd-vault-plugin use the same native
compatibility path by default. Discovered CMP aliases use it when their
generate command safely normalizes to argocd-vault-plugin generate .. The
--enable-avp-compat flag forces the same redaction pass for ordinary
native-rendered sources. The --enable-ksops-compat flag enables the same
opt-in, fail-closed native path for KSOPS kustomize generators.
When a discovered sidecar CMP has static discovery rules and an Application
does not name a plugin, drydock may warn that Argo CD sidecar auto-discovery
would be required. drydock evaluates only discover.fileName and
discover.find.glob against the local Application source directory. It never
executes or emulates discover.find.command.
Onboarding Commands
drydock plugin-policy init and drydock plugin-policy doctor are static
onboarding commands. They inspect Applications, CMP settings, and readable
sidecar image candidates, but they do not render Applications or execute
plugin commands. Passing --plugin-policy-ref and --enable-plugins to
doctor checks whether those gates are satisfied for future command-backed
rendering; it does not run the command-backed policy.
For normal render commands, a missing default .drydock/plugins.yaml is
ignored. For plugin-policy doctor, the same missing default policy is a
readiness FAIL with code policy.missing; an explicitly selected missing
--plugin-policy-path is a command error. Use -o json for deterministic
status and issue code fields, and --strict when readiness FAIL should
exit nonzero after the report is rendered.
Trusted Provenance
The default local policy path is .drydock/plugins.yaml. Use
--plugin-policy-path to select a different policy path relative to the
selected policy root. Missing default policy is ignored; an explicitly selected
policy path must exist. --disable-plugin-policy disables drydock policy
loading only; it does not disable built-in native Kustomize interpretation for
safe discovered CMP definitions.
Default local policy is trusted for native policy only. For single-tree
commands such as build, test, and diag, a policy loaded from the current
working tree may authorize avp-compat and native-kustomize. It is not
trusted to execute engine: exec or engine: container entries. Even with
--enable-plugins, a matching command-backed entry from the current tree fails
closed unless the caller also selects trusted policy provenance with
--plugin-policy-ref.
Diff commands load default policy from the left or baseline side, such as
--path-orig or the --ref-orig snapshot, and use that one policy for both
sides of the diff. Command-backed policy from that baseline provenance may run
only when --enable-plugins is passed. Policy command definitions,
post-renderers, container image references, and bootstrap definitions are never
sourced from the proposed side of a pull request.
--plugin-policy-ref means “load the policy from this explicit trusted Git ref
or source.” When --plugin-policy-repo is set, drydock resolves the ref in
that local Git repository; otherwise it uses the selected repository. The ref
is a trust assertion by the operator or CI job. Policy paths remain relative to
the policy root snapshot and may not escape it.
Local Validation
For a committed command-backed policy, validate with the trusted policy ref that CI will use:
drydock get apps \
--path . \
--enable-plugins \
--plugin-policy-ref main
When generated Applications point at the canonical Git remote URL, add a repository map so recursive rendering uses the local checkout:
drydock test apps \
--path . \
--enable-plugins \
--plugin-policy-ref main \
--repo-map https://github.com/example/cluster="$PWD"
To validate an uncommitted policy without making the working tree policy
trusted directly, copy the policy into a small temporary Git repository and
trust that repository’s HEAD:
mkdir -p /tmp/drydock-policy-trust/.drydock
cp .drydock/plugins.yaml /tmp/drydock-policy-trust/.drydock/plugins.yaml
git -C /tmp/drydock-policy-trust init
git -C /tmp/drydock-policy-trust add .drydock/plugins.yaml
git -C /tmp/drydock-policy-trust commit -m "Trust local drydock plugin policy"
drydock test apps \
--path . \
--enable-plugins \
--plugin-policy-ref HEAD \
--plugin-policy-repo /tmp/drydock-policy-trust \
--repo-map https://github.com/example/cluster="$PWD"
For diff validation, use the same trusted policy source and render all apps when there may be no local Git changes:
drydock diff apps \
--path-orig . \
--path . \
--enable-plugins \
--plugin-policy-ref HEAD \
--plugin-policy-repo /tmp/drydock-policy-trust \
--repo-map https://github.com/example/cluster="$PWD" \
--changed-only=false \
--exit-code=false
Common validation failures:
requires --enable-plugins: pass--enable-plugins; drydock never runs command-backed policies by default.untrusted policy source: use--plugin-policy-ref, or run a diff where the policy comes from the trusted baseline side.no trusted plugin policy match.discover: ensure the Application plugin name matches a policy key, or add trusted staticmatch.discoverorconfigManagementPlugin.discovermetadata.Application plugin parameter ... is not allowed: add a narrowparameters.allowentry with the expected type and path allowlist.container command failedduring the policy lifecycleinitphase: check copied sibling paths, package/cache requirements, and whether the policy needsnetwork: default.network: defaultwith--offline: container network access is rejected in offline mode; use local caches or run without--offline.
Command Security Model
Exec and container policy lifecycle commands are argv-only. command must be a
YAML sequence of strings; shell strings such as ytt -f . are rejected. Empty
argv tokens are rejected.
For engine: exec, the command executable may be either a basename resolved on
drydock’s controlled PATH (/usr/local/bin:/usr/bin:/bin) or an absolute path
to an executable outside protected roots. Relative executable paths such as
./render.sh are rejected. Shells and common interpreters are rejected as
argv[0], including sh, bash, zsh, dash, ksh, fish, env,
python, python3, node, ruby, perl, pwsh, and powershell.
Exec commands run from a temporary copy of the resolved Application source path. Symlinks inside that source copy are rejected. Exec binaries must not resolve inside protected roots, and command arguments must not point back into protected roots except for files inside the temporary workdir. Credential-bearing URLs in arguments are rejected.
For engine: container, drydock prepares the same temporary source or
repository-scoped workspace, makes it writable for container users, and mounts
it at /work. Container lifecycle commands run inside the configured image
with Docker run --rm --interactive, the configured network, and an env file
generated from policy-allowed values.
In offline mode, drydock adds --pull never, sets Docker client HOME and
DOCKER_CONFIG to an empty temporary directory, rejects network: default,
and rejects caller-provided remote Docker client configuration such as
non-local DOCKER_HOST, DOCKER_CONTEXT, DOCKER_CONFIG,
DOCKER_TLS_VERIFY, or DOCKER_CERT_PATH.
For engine: exec, the command environment starts with only drydock’s
controlled PATH. For engine: container, the Docker client process uses a
minimal controlled environment, while the process inside the image keeps the
image-defined environment and receives policy-allowed environment values,
Argo-style plugin parameter values, and drydock extras through --env-file.
For both command-backed engines, allowed environment names must be valid
environment identifiers, cannot be duplicated, and cannot be reserved
loader/interpreter variables such as PATH, LD_*, DYLD_*, PYTHONPATH, or
NODE_OPTIONS. Each copied value is capped at 16 KiB. Application-authored
plugin env is rejected for policy-backed plugin sources.
Application Parameters
Application plugin parameters are accepted only for engine: exec and
engine: container, and only when allowlisted by trusted policy. Native engines
reject Application plugin env and parameters.
parameters.allow[] entries:
| Field | Required | Notes |
|---|---|---|
name |
Yes | Application plugin parameter name. |
type |
Yes | string, array, or map. |
required |
No | When true, the Application must provide the parameter. |
path.base |
No | For string path parameters only. Defaults to source; may be repository. |
path.allow |
No | Slash-normalized relative glob allowlist for path values. |
String parameters may be substituted into argv tokens with {{param:name}}.
Parameter templates are not allowed in the executable position. Array and map
parameters are exposed only through Argo-style PARAM_* and
ARGOCD_APP_PARAMETERS environment values.
Path parameters may be constrained to paths under the Application source or the
repository. Repository-scoped path parameters require copy.scope: repository.
Values under the Application source are copied by default; trusted sibling
repository paths must also match copy.include.
Command-backed runs keep structured execution metadata per phase: phase name, engine, sanitized command basename, elapsed duration, and for container policy the runtime and image. Metadata does not include plugin stdout, stderr, argv beyond the command basename, environment values, or rendered manifests.