Skip to content

feat(atlas): Docker collector - containers as graph assets - #2046

Open
asdf8675309 wants to merge 1 commit into
danielmiessler:mainfrom
asdf8675309:feat/atlas-docker-collector
Open

feat(atlas): Docker collector - containers as graph assets#2046
asdf8675309 wants to merge 1 commit into
danielmiessler:mainfrom
asdf8675309:feat/atlas-docker-collector

Conversation

@asdf8675309

Copy link
Copy Markdown
Contributor

What

Atlas has no visibility into Docker. A machine running containers has real assets — databases, services, published ports — that never appear in the asset graph, so owns/blast/stale queries are blind to them.

Change

One new collector, LIFEOS/ATLAS/collectors/Docker.ts, plus its registration line in Atlas.ts and a collector-table row (with freshness stamp) in AtlasSystem.md.

  • Enumerates ALL containers (docker ps -aq, running or not), then reads canonical JSON from one batched docker inspect — no --format templates, whose field names drift across Docker versions.
  • Assets are keyed docker:container:<name> — name, not ID. A recreate (compose up, image upgrade) rotates the ID but keeps the name, and keying by ID would churn a fresh asset per recreate. Same reason Launchd.ts keys on Label.
  • Attrs capture every cheap connection signal: image, state, running, ports (published and exposed-unpublished), networks, mount destinations, restart policy, compose project, created/started timestamps.
  • One RUNS_ON edge per container to the local machine asset, the way Launchd.ts does it.

Why it's safe

  • Docker not installed, or installed with the daemon stopped, returns the DEGRADED result (complete: false, empty) — the same contract Github.ts and Launchd.ts already use. atlas sync cannot exit non-zero because a machine has no Docker, and an absent source can never sweep prior observations.
  • A container removed between ps and inspect marks the run complete: false — no sweep on a racy view; prior graph state stays intact.
  • inspect exiting 0 with unparseable output throws loudly (contract regression, not an absent source) — the same split Github.ts draws.
  • No secret values and no host paths enter the graph: mounts record destinations only, never bind-mount sources.
  • Installs without Docker are byte-identical in behavior except one PARTIAL line in sync output.

Verification

Tested on macOS, Docker Engine 29.7.2, Bun 1.3.14. The fork has no test runner, so this table is the reviewable proof.

case result
live daemon, one compose-managed container ✓ docker: 2 assets, 1 edges (complete, swept), exit 0
container asset after sync docker:container:<name> active, attrs carry image/state/ports (v4+v6 bindings)/networks/mounts/restart-policy/compose-project; active RUNS_ON edge to the machine asset
snapshot export container present in the redacted Pulse snapshot
docker CLI absent from PATH {"complete":false,"assets":[],"edges":[]} — no throw
daemon reachable, zero containers complete: true, machine asset only (early-return code path; not live-tested — the test machine has a container)
strict tsc over all of LIFEOS/ATLAS 0 errors

Scope

No change to Store.ts, the CLI surface, or any existing collector. The two edited files change by 3 code lines total (one import + one registration entry) plus one doc row. No new dependency — Bun.spawn and the docker CLI only.

Adds collectors/Docker.ts, a standalone collector for the local Docker
daemon. It enumerates ALL containers (docker ps -aq, running or not),
reads canonical JSON from one batched docker inspect, and emits one
asset per container plus a RUNS_ON edge to this machine.

- Keyed by container NAME, not ID. A recreate (compose up, image
  upgrade) rotates the ID but keeps the name, and keying by ID would
  churn a fresh asset per recreate. Same reason Launchd.ts keys on
  Label.
- Attrs capture every cheap connection signal: image, state, running,
  ports (published and exposed-unpublished), networks, mount
  destinations (never host source paths), restart policy, compose
  project, created/started timestamps.
- Degrades, never throws, when the docker CLI is absent or the daemon
  is not running. Both are normal states on most installs — the same
  DEGRADED contract Github.ts and Launchd.ts use, so an absent source
  can never sweep prior observations.
- A container removed between ps and inspect marks the run incomplete
  (complete: false) instead of sweeping on a racy view. Zero exit with
  unparseable inspect output still throws (contract regression, not an
  absent source).

Registered in Atlas.ts alongside the existing collectors. New row in
the AtlasSystem.md collector table, frontmatter stamped per
pai-freshness-v1.

Verified on a live daemon (Docker Engine 29.7.2, macOS, Bun 1.3.14):
full sync run complete and swept, one compose-managed postgres
container enumerated with image/ports/networks/mounts/restart-policy
attrs and an active RUNS_ON edge to the machine asset. With the CLI
absent from PATH the collector returns the degraded result without
throwing. Strict tsc pass over the whole ATLAS tree.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant