Policy-driven container resource cleanup for Docker, Podman, and containerd.
Jettison discovers, evaluates, and removes container resources (containers, images, networks, volumes) that match policy criteria. All eligibility and filtering decisions are made through OPA (Open Policy Agent) policies compiled to WASM. Confirmation is required by default. All actions are auditable.
cargo install jettison-cli# Create a starter configuration
jettison init
# Preview what would be cleaned up
jettison prune --dry-run
# Run cleanup (will prompt for confirmation)
jettison prune
# Skip confirmation prompt
jettison prune --yes
# List all discovered resources
jettison list
# Validate configuration and policies
jettison validateJettison loads configuration from layered sources (later sources override earlier ones):
- Built-in defaults
.jettison.ymlin the current directory~/.config/jettison/config.yml- Environment variables with the
JETTISON_prefix
| Field | Type | Default | Description |
|---|---|---|---|
runtime.runtime_type |
string | "docker" |
Container runtime backend: docker, podman, or containerd |
runtime.endpoint |
string | (auto-detected) | Socket path for the runtime API |
safety.min_age_days |
integer | 3 |
Minimum age in days before a resource is eligible for pruning |
do_not_delete.container_ids |
list | [] |
Container IDs that must never be deleted |
do_not_delete.image_ids |
list | [] |
Image IDs that must never be deleted |
do_not_delete.network_ids |
list | [] |
Network IDs that must never be deleted |
do_not_delete.volume_ids |
list | [] |
Volume IDs that must never be deleted |
filters |
list | [] |
Named filters for matching resources (see below) |
confirmation.auto_approve |
bool | false |
Skip confirmation prompts globally |
audit.enabled |
bool | true |
Enable audit logging |
audit.format |
string | "json" |
Audit log format: json or text |
audit.output |
string | "stdout" |
Audit output target: stdout or a file path |
include_types |
list | ["container", "image", "network", "volume"] |
Resource types to include in prune operations |
Each filter is a named rule that matches resources for pruning. Within a filter, all criteria are AND-ed. Across filters, the first matching filter wins (OR logic).
| Filter Field | Type | Default | Description |
|---|---|---|---|
name |
string | (required) | Unique name for the filter |
resource_type |
string | (any) | Match only this resource type |
labels |
map | {} |
Match resources with all specified labels |
dangling |
bool | (any) | Match only dangling (true) or non-dangling (false) resources |
min_last_used_days |
integer | (any) | Match resources not used for at least this many days |
auto_approve |
bool | false |
Skip confirmation for resources matched by this filter |
runtime:
runtime_type: docker
safety:
min_age_days: 7
do_not_delete:
container_ids:
- production-db
image_ids:
- sha256:abc123
filters:
- name: dangling-images
resource_type: image
dangling: true
auto_approve: true
- name: dev-containers
resource_type: container
labels:
env: dev
min_last_used_days: 14
confirmation:
auto_approve: false
audit:
enabled: true
format: json
output: /var/log/jettison.jsonlJettison uses OPA (Open Policy Agent) policies compiled to WASM for all eligibility and filtering decisions. No business logic is hardcoded in Rust.
The eligibility policy (policies/eligibility.rego) determines whether a resource is a candidate
for pruning. A resource is eligible when:
- It is not on the do-not-delete list
- It is older than
safety.min_age_days
The filter policy (policies/filter.rego) evaluates each eligible resource against the configured
filters. A resource matches a filter when all of the filter's criteria are satisfied.
To customize eligibility or filter logic:
- Edit the
.regofiles in thepolicies/directory - Compile to WASM:
make -C policies build - Run Rego tests:
make -C policies test
Policies are compiled into the binary at build time via include_bytes!.
Jettison supports three container runtime backends:
- Docker: connects via the Docker API (default socket at
/var/run/docker.sock) - Podman: connects via the Podman Docker-compatible API (auto-detects rootful or rootless socket)
- containerd: connects via the containerd gRPC API. Note that containerd does not have native network or volume concepts, so those resource types return empty results without error.
2026-03-28T10:30:00Z INFO prune plan summary discovered=12 eligible=8 matched=3
2026-03-28T10:30:00Z INFO planned: matched all filter criteria resource_id=abc123 kind=container filter=dev-containers
Proceed with 3 deletion(s)? [y/n]: y
2026-03-28T10:30:05Z INFO removed resource resource_id=abc123 success=true
jettison prune --format json --yes[{
"resource_id": "abc123",
"action": "remove",
"success": true,
"message": "removed",
"dry_run": false
}]Jettison is organized as a Cargo workspace with five crates. jettison-engine contains all domain
logic: configuration (via schematic), container runtime adapters (Docker, Podman, containerd), the
OPA WASM policy engine, the evaluation pipeline, and audit logging. The jettison-cli crate is a
thin CLI binary handling I/O, prompts, and output formatting. jettison-oci-hook is an OCI runtime
hook binary that runs the pipeline with auto-approve on container lifecycle events. fuzz-common
and fuzz-core provide property-based testing and fuzz harness infrastructure.
MIT