drydock
Inspect your Argo CD fleet without getting wet

drydock is a fast, single static Go binary and embeddable library for
runtime-offline Argo CD desired-state analysis. It discovers, renders, tests,
diffs, and diagnoses GitOps Applications without requiring a live Argo CD
instance or Kubernetes cluster.
It is built for operators who want quick, deterministic feedback before a
change reaches the cluster. Pull request diffing is a key workflow, but
the same native engine also supports render validation, image inventory,
repository diagnostics, cache inspection, and Go API embedding.
Default commands use native Go renderers and do not shell out to kubectl,
argocd, Helm CLI, Kustomize CLI, or repo-server wrappers. Runtime-offline
does not mean network-disconnected: declared Git, HTTP Helm, OCI Helm, and
remote Kustomize sources may still be fetched into explicit drydock caches
unless --offline is set.
Full documentation: sholdee.github.io/drydock.
Install
Install the latest Linux/macOS release with Homebrew:
brew install sholdee/tap/drydock
Homebrew installs shell completions automatically.
For GitOps repository and CI pinning, use mise with the GitHub backend:
[tools]
"github:sholdee/drydock[exe=drydock]" = "vX.Y.Z"
Install Script
curl -fsSL https://raw.githubusercontent.com/sholdee/drydock/main/scripts/install-drydock.sh -o install-drydock.sh
bash install-drydock.sh --yes
The script verifies release checksums, verifies Sigstore bundles when
available, installs the drydock binary, and attempts shell completion
installation. Pin a release with --version vX.Y.Z.
Pipe form:
curl -fsSL https://raw.githubusercontent.com/sholdee/drydock/main/scripts/install-drydock.sh | bash -s -- --yes
Pinned pipe form:
curl -fsSL https://raw.githubusercontent.com/sholdee/drydock/main/scripts/install-drydock.sh | bash -s -- --version vX.Y.Z --yes
Use --no-completions when completions should be installed manually.
GitHub Actions
Workflows that install a released binary can use the setup action:
- uses: sholdee/drydock/setup-action@main
with:
version: vX.Y.Z
For pull request validation, the PR action wraps render tests, manifest diffs,
image diff reports, source caches, artifacts, and sticky PR comments:
name: drydock
on:
pull_request:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
drydock:
runs-on: ubuntu-latest
steps:
- uses: sholdee/drydock/pr-action@main
with:
version: vX.Y.Z
The setup action accepts latest, vX.Y.Z, or bare X.Y.Z and verifies the
selected archive with the release checksum manifest by default.
See the GitHub Actions reference
for full action inputs, GitHub App token support, cache behavior, comments,
artifacts, and outputs.
Download A Binary
Download Linux and macOS amd64 or arm64 archives from the
latest release. Verify
the archive with checksums.txt before installing the drydock binary.
Docker / GHCR
Release containers are published to GHCR for Linux amd64 and arm64:
docker run --rm -v "$PWD:/workspace:ro" ghcr.io/sholdee/drydock:latest test apps --path /workspace
For repeatable automation, pin ghcr.io/sholdee/drydock:vX.Y.Z.
Go Install
Build from source with Go:
go install github.com/sholdee/drydock/cmd/drydock@latest
Manual binary installs can generate shell completions with:
drydock completion zsh
drydock completion bash
drydock completion fish
Quick Start
Run drydock from the root of an Argo CD GitOps repository.
List discovered Applications:
drydock get apps --path .
Test every discovered Application without printing rendered manifests:
drydock test apps --path .
Example text output:
PASS renovate
PASS cert-manager
FAIL argocd/broken Application argocd/broken source[0] path="..." ...
Compare a pull request checkout against a baseline tree:
git worktree add ../baseline main
drydock diff apps --path . --path-orig ../baseline
Diff commands use changed-only selection by default. Use
--changed-only=false when you want to render and compare every discovered
Application. Use repeatable --changed-only-include and
--changed-only-ignore globs when CI should ignore known non-GitOps paths
before changed-only ownership is evaluated.
You can also compare against committed Git refs without creating a baseline
worktree:
drydock diff apps --path . --ref-orig main
drydock diff apps --repo . --ref feature --ref-orig main
Inspect image changes in a machine-readable form:
drydock diff images --path . --path-orig ../baseline -o json
For CI jobs that have already populated drydock's source caches, require a
cache-only run:
drydock test apps --path . --offline
drydock diff apps --path . --path-orig ../baseline --offline
Common Workflows
| Goal |
Command |
| List Applications |
drydock get apps --path . |
| List rendered image references |
drydock get images --path . -o name |
| Render all Applications |
drydock build apps --path . |
| Render one Application |
drydock build app renovate --path . |
| Test renderability |
drydock test apps --path . |
| Diff rendered manifests |
drydock diff apps --path . --path-orig ../baseline |
| Diff one Application |
drydock diff app renovate --path . --path-orig ../baseline |
| Diff rendered image references |
drydock diff images --path . --path-orig ../baseline -o json |
| Inspect repository diagnostics |
drydock diag --path . |
| Inspect redacted settings |
drydock diag --path . --settings -o json |
| Inspect cache roots |
drydock cache path |
| List cache entries |
drydock cache list -o json |
drydock <command> --help lists command-specific flags. See
the CLI usage guide for the
full command reference.
What It Supports
drydock covers the common Argo CD GitOps repository shapes operators need to
inspect locally and in CI:
- Application discovery: committed Applications, supported ApplicationSets,
rendered app-of-apps/bootstrap children, explicit Kustomize discovery
entrypoints, AppProjects, and settings objects.
- Rendering: directory, Kustomize, Helm, Jsonnet, single-source and
multi-source Applications, Kustomize Helm charts, remote Helm charts, and
remote Kustomize sources.
- Source acquisition: declared Git, HTTP Helm, OCI Helm, and remote
Kustomize inputs through explicit drydock caches, plus
--repo-map for
adjacent local checkouts.
- Diffs and images: desired-vs-desired manifest and image diffs,
changed-only selection, default noisy-field filtering, and structured or
markdown output.
- Plugins: native safe Kustomize compatibility,
avp-compat placeholder
redaction, native policy overrides, and explicit trusted exec policy with
--enable-plugins.
- Diagnostics: render status, custom health Lua validation, redacted
settings/repository/AppProject checks, source acquisition diagnostics, and
cache lifecycle commands.
See the compatibility overview
for the support matrix and links to detailed reference docs.
Offline Runtime Model
drydock performs desired-vs-desired analysis. It renders Kubernetes manifests
from repository inputs, explicit mappings, and drydock caches. Diff commands
compare a current snapshot to a baseline snapshot.
Default commands do not ask a live Kubernetes cluster or Argo CD server what is
currently running. They also do not reproduce runtime behavior such as API
defaulting, admission mutation, server-side diff, live health aggregation,
managed-fields ownership, or full RBAC authorization.
This boundary is intentional: normal workflows stay fast, deterministic, and
safe for local use and CI. Source acquisition may still fetch declared Git,
Helm, OCI, or remote Kustomize inputs unless --offline is set.
See Runtime Offline
and Argo CD Render Parity
for the design model and validation strategy.
How It Works
flowchart TD
current[Current tree]
baseline[Baseline tree]
current --> discover
baseline --> discover
discover[Discover static and rendered Argo CD fleet objects]
discover --> plan[Plan sources, resolve repo maps, use caches]
plan --> render[Render desired manifests with Go libraries]
render --> normalize[Apply Argo-aware filters and diff normalization]
normalize --> outputs[Test statuses, manifest diffs, image diffs, diagnostics]
The render path imports Argo CD API types and selected reusable helpers, but
drydock owns offline orchestration. See the
design notes for the
architecture and behavior model.
Go API
Embedding callers can use github.com/sholdee/drydock/pkg/drydock to list,
render, and diff Applications without shelling out:
result, err := drydock.Render(ctx, drydock.Config{Path: "."})
drydock.NewClient accepts public Git, chart, and remote-resource acquirer
interfaces, plus a public config management plugin renderer hook. Embedders can
use those interfaces for tests, offline fixtures, and custom source handling.
When one selected Application fails, the result still includes successful
manifests, diagnostics, and per-Application statuses from the partial build.
drydock is inspired by Flate, a
Flux resource inflator, and the home-operations community.
Join the home-operations Discord at https://discord.gg/home-operations.
Documentation
- Documentation site: curated operator
docs and full reference pages.
- Getting started:
first local discovery, render test, and comparison commands.
- GitHub Actions:
setup action, PR action, comments, artifacts, and caches.
- Local diffs:
terminal manifest and image diff workflows.
- Compatibility: supported
Argo CD behavior and intentional runtime boundaries.
- Runtime Offline:
what drydock does without live Argo CD or Kubernetes.
- Argo CD Render Parity:
how covered render semantics are validated against real Argo CD.
- Plugin policy: trusted
policy engines, schema, CMP compatibility, and exec security.
- Source acquisition:
Git, Helm, remote Kustomize, cache, and auth behavior.
- Reference: full command and
behavior reference.
License
Apache-2.0. See LICENSE.