cs-image-system-docker-runtime-plugin 0.1.6__tar.gz → 0.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/.gitignore +2 -0
  2. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/PKG-INFO +177 -45
  3. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/README.md +173 -41
  4. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/pyproject.toml +9 -4
  5. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/bootstrap.py +28 -8
  6. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/data/image-sources.yml +80 -0
  7. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/docker_names.py +5 -5
  8. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/docker_packer_source.py +2 -2
  9. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/docker_provider_specific_image.py +6 -3
  10. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/docker_runtime_builders.py +118 -24
  11. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/docker_runtime_models.py +9 -9
  12. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/local_target.py +140 -0
  13. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/main.py +1 -0
  14. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_container/main.tf +74 -0
  15. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_container/outputs.tf +23 -0
  16. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_container/provider.tf +11 -0
  17. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_container/variables.tf +82 -0
  18. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_volume/main.tf +23 -0
  19. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_volume/outputs.tf +15 -0
  20. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_volume/provider.tf +11 -0
  21. cs_image_system_docker_runtime_plugin-0.1.7/src/cs_image_system/docker_runtime/tfmodules/docker_volume/variables.tf +29 -0
  22. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/tests/test_docker_runtime.py +16 -10
  23. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/LICENSE +0 -0
  24. {cs_image_system_docker_runtime_plugin-0.1.6 → cs_image_system_docker_runtime_plugin-0.1.7}/src/cs_image_system/docker_runtime/__init__.py +0 -0
@@ -26,3 +26,5 @@ target/
26
26
  tfplan
27
27
  *.tfstate
28
28
  *.tfstate.backup
29
+ REEXAMINE*
30
+ TODO2.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: cs-image-system-docker-runtime-plugin
3
- Version: 0.1.6
3
+ Version: 0.1.7
4
4
  Summary: The docker runtime type: a durable host's container daemon as a place where images bake and instances run
5
5
  Project-URL: Repository, https://github.com/infrastructurebuilder/cs-image-system-3
6
6
  Project-URL: Documentation, https://github.com/infrastructurebuilder/cs-image-system-3/blob/develop/docs/OPERATIONS.md
@@ -9,9 +9,9 @@ Author-email: Mykel Alvis <mykelalvis@infrastructurebuilder.org>
9
9
  License-Expression: Apache-2.0
10
10
  License-File: LICENSE
11
11
  Requires-Python: >=3.13
12
- Requires-Dist: cs-image-system-base==0.1.6
13
- Requires-Dist: cs-image-system-contract==0.1.6
14
- Requires-Dist: cs-image-system-hashicorp-utils==0.1.6
12
+ Requires-Dist: cs-image-system-base==0.1.7
13
+ Requires-Dist: cs-image-system-contract<0.5,>=0.4
14
+ Requires-Dist: cs-image-system-hashicorp-utils==0.1.7
15
15
  Requires-Dist: pydantic>=2.13
16
16
  Requires-Dist: python-hcl2>=8.1
17
17
  Description-Content-Type: text/markdown
@@ -24,7 +24,13 @@ SPDX-License-Identifier: Apache-2.0
24
24
 
25
25
  # cs-image-system-docker-runtime-plugin
26
26
 
27
- The `docker` runtime type (stage 103): a durable host running a daemon that
27
+ This plugin ships the docker terraform modules as package data
28
+ (`docker_container`, `docker_volume`, under
29
+ [src/cs_image_system/docker_runtime/tfmodules/](src/cs_image_system/docker_runtime/tfmodules)),
30
+ declared through the `cs_image_system.modules` entry point;
31
+ `cs-image-system modules` lists them.
32
+
33
+ The `docker` runtime type: a durable host running a daemon that
28
34
  speaks the Docker Engine API, as a place where images bake and instances
29
35
  run. Docker Engine, Docker Desktop, OrbStack, colima and Podman's API
30
36
  service all qualify; the system reaches the daemon through the `docker` CLI
@@ -50,8 +56,8 @@ differs from them in three ways the design records as decisions:
50
56
  `<repository>:<short id>--<key>--<value>`, one per key.
51
57
  - **POSIX accounts only.** Access is through the daemon (`docker exec -u`);
52
58
  whoever can reach the daemon is root on the host. An OPA group on a docker
53
- runtime is refused at validation; enrolling `sftd` in a container is a
54
- later stage.
59
+ runtime is refused at validation; enrolling `sftd` in a container is
60
+ not yet supported.
55
61
 
56
62
  ## What it registers
57
63
 
@@ -61,8 +67,8 @@ differs from them in three ways the design records as decisions:
61
67
  | `DockerContainerBuilder` ([docker_runtime_builders.py](src/cs_image_system/docker_runtime/docker_runtime_builders.py)) | `docker` | `VCT.RUNTIME_BUILDER` | Every runtime hook, answered against the daemon through the CLI. |
62
68
  | `DockerCLIVersionChecker` (same file) | `docker` | `VCT.VERSION_CHECKER` | `docker --version` for the `docker` entry of `cfg/executables.yml`. |
63
69
 
64
- Entry points: `cs_image_system.plugins.runtime` → `docker`, and (stage 103
65
- item 15) `cs_image_system.bootstrap` → `docker`, the container-host section of
70
+ Entry points: `cs_image_system.plugins.runtime` → `docker`, and
71
+ `cs_image_system.bootstrap` → `docker`, the container-host section of
66
72
  the bootstrap interview ([bootstrap.py](src/cs_image_system/docker_runtime/bootstrap.py)):
67
73
 
68
74
  | Class / function | Role |
@@ -74,8 +80,9 @@ Its render says what remains by hand (the daemon and its host, the network,
74
80
  CI's ssh key and `known_hosts` line, or, when CI cannot reach the daemon, to
75
81
  name the runtime in `GUARD_RUNTIME`) and its audit lines are all BY HAND or
76
82
  READ. The two secrets it concerns, `DOCKER_HOST_SSH_KEY` and
77
- `DOCKER_HOST_KNOWN_HOSTS`, are among the GitHub section's, set by its script
78
- from files.
83
+ `DOCKER_HOST_KNOWN_HOSTS`, are the section's own (`Section.secrets`); the
84
+ GitHub section's script sets them from files with the rest, so the core never
85
+ names them.
79
86
 
80
87
  ## Models
81
88
 
@@ -84,20 +91,34 @@ from files.
84
91
  Extends the core's `ContainerBuilderModel` (`host`, `context`, `networking`,
85
92
  `machine_types`) and the runtime model every runtime shares
86
93
  (`default_machine_type`, `default_image_builder`, `credentials`, `ephemeral`,
87
- `retention_keep`, ...).
88
-
89
- | Field | Default | Meaning |
90
- |---|---|---|
91
- | `host` | none | The daemon's address as a `DOCKER_HOST` URL: `unix:///var/run/docker.sock`, `ssh://user@host`, `tcp://host:2376`. May be an `ENC[age:...]` marker when the address itself is private. Declare `host` or `context`, not both. |
92
- | `context` | none | A docker context name (`docker context ls`), set as `DOCKER_CONTEXT`. |
93
- | `executable` | `docker` | The `cfg/executables.yml` entry whose `binary` every docker call on this runtime runs through; `validate` version-checks it. |
94
- | `repository` | `csis/<runtime name>` | Where this runtime's builds are tagged, made a valid repository name (lowercase). |
95
- | `tls_cert_path`, `tls_verify` | none, false | `DOCKER_CERT_PATH` and `DOCKER_TLS_VERIFY` for a `tcp://` host: TLS material by PATH, never a value. |
96
- | `networking.network` | `bridge` | The network the bake container (and, later, every instance) joins, by name; referenced, never created or changed. No subnets, no zones. |
97
- | `machine_types` | `{}` | A map from a name to `{cpus, memory}` (`--cpus 2`, `--memory 4g`). When any are declared, `default_machine_type` must name one. |
98
- | `state_configuration` | the default state manager | The state manager this runtime's roots use; a tree with no cloud declares `local`. |
99
-
100
- Nothing in the model is a credential.
94
+ `retention_keep`, ...). The field table is
95
+ [CONFIGURATION section 4.6](../../docs/CONFIGURATION.md#46-docker); what is
96
+ particular to this runtime:
97
+
98
+ - **Where the daemon is** is `host` (a `DOCKER_HOST` URL:
99
+ `unix:///var/run/docker.sock`, `ssh://user@host`, `tcp://host:2376`,
100
+ which may be an `ENC[age:...]` marker when the address itself is
101
+ private) or `context` (a docker context name, `docker context ls`, set
102
+ as `DOCKER_CONTEXT`). Declare one, not both. `tls_cert_path` and
103
+ `tls_verify` are `DOCKER_CERT_PATH` and `DOCKER_TLS_VERIFY` for a
104
+ `tcp://` host: TLS material by PATH, never a value.
105
+ - **How it is reached** is `executable`, the `cfg/executables.yml` entry
106
+ whose `binary` every docker call on this runtime runs through;
107
+ `validate` version-checks it.
108
+ - **Where builds go** is `repository` (default `csis/<runtime name>`,
109
+ made a valid repository name, lowercase): where this runtime's builds
110
+ are tagged.
111
+ - **What a container gets** is `networking.network` (default `bridge`:
112
+ the network the bake container and every instance joins, by name;
113
+ referenced, never created or changed; no subnets, no zones) and
114
+ `machine_types` (a map from a name to `{cpus, memory}`, `--cpus 2`,
115
+ `--memory 4g`; when any are declared, `default_machine_type` must name
116
+ one).
117
+ - **Where its roots keep state** is `state_configuration`; a tree with no
118
+ cloud declares `local`.
119
+
120
+ Nothing in the model is a credential: whoever reaches the daemon is root
121
+ on the host.
101
122
 
102
123
  ## The builder
103
124
 
@@ -107,12 +128,79 @@ The daemon answers the keys `name` (a repository), `version` (a tag),
107
128
  `publisher` (a registry namespace; `library` is Docker Hub's and is
108
129
  dropped), `architecture` (a platform, `x86_64` → `linux/amd64`) and
109
130
  `native.image` (a reference verbatim). The release catalog's `docker` block
110
- gives every family one (`almalinux:{version}`, `debian:{version}`, ...). The
111
- query PULLS the reference and records its digest reference
131
+ gives every family one (`almalinux:{version}`, `debian:{version}`, ...);
132
+ those blocks are this plugin's, shipped as package data in
133
+ [`data/image-sources.yml`](src/cs_image_system/docker_runtime/data/image-sources.yml)
134
+ and read by `DockerContainerBuilder.image_source_entries()`, so the
135
+ release catalog a tree sees carries a `docker` block exactly when this
136
+ plugin is installed. The query PULLS the reference and records its digest reference
112
137
  (`<repository>@sha256:...`) as the identifier, so a vendor moving a tag shows
113
138
  as a move. An entry's `image_id` pins a digest reference; a tag is refused
114
139
  there, because a tag moves.
115
140
 
141
+ ### Image query translation
142
+
143
+ What `translate_image_query()` does with each key of the system's
144
+ vocabulary (`supported_query_keys()` is the set of rows not marked
145
+ refused, the same table the cloud runtime READMEs carry). The answer is
146
+ `{"reference": "<repository>:<tag>", "platform": "<os/arch>" | None}`:
147
+ what `docker pull` takes. `validate` refuses a query that uses a refused
148
+ key before anything runs; a query that names neither `name` nor
149
+ `native.image` is refused too, because the daemon needs a reference.
150
+
151
+ | System key | Daemon's word | Note |
152
+ | --- | --- | --- |
153
+ | `name` | the repository | `almalinux`, or `<publisher>/<name>` when a publisher is named |
154
+ | `family` | refused | a registry has no image families; name the repository |
155
+ | `version` | the tag | `<repository>:<version>`; unset, the reference carries no tag and the daemon's default tag applies |
156
+ | `architecture` | `--platform` | `x86_64` and `amd64` become `linux/amd64`, `arm64` and `aarch64` become `linux/arm64`; any other word passes no platform |
157
+ | `publisher` | the registry namespace | the first value prefixes the repository; `library` (Docker Hub's own) is dropped; it is also recorded as the image's owner, `library` when none is named |
158
+ | `state` | refused | a pulled image has no state |
159
+ | `virtualization` | refused | an EC2 particular |
160
+ | `root_device` | refused | an EC2 particular |
161
+ | `tags` | refused | a pull cannot search by label |
162
+ | `newest` | refused | a tag names one image; the pull resolves it |
163
+ | `native` | `native.image` verbatim | a complete reference, used instead of `name`, `publisher` and `version`; no other `native` member is read |
164
+
165
+ ### The local test target
166
+
167
+ The core's local modification tests (`cs-image-system test-mods`; the
168
+ harness is [`mod_tests.py`](../base/src/cs_image_system/base/mod_tests.py)
169
+ in the base package) run every modification of an instance image twice on
170
+ a throwaway container and compare the filesystem diffs. The harness
171
+ itself names no runtime: it asks the registered runtime builder classes
172
+ which one offers a local test target, and this plugin is the one that
173
+ does. `DockerContainerBuilder.local_test_target()` returns the factory
174
+ `make_local_target(image, executables)` from
175
+ [`local_target.py`](src/cs_image_system/docker_runtime/local_target.py),
176
+ and everything that is docker's about the test container lives there:
177
+
178
+ - the CLI: the `binary` of the tree's `docker` entry in
179
+ `cfg/executables.yml` (its `name` when no binary is given), else
180
+ `docker` from the host's PATH;
181
+ - the daemon probe: `docker info`. When the daemon does not answer the
182
+ factory returns nothing and the harness records every modification as
183
+ `skipped` with the detail `docker: the daemon is not available`, never
184
+ as failed;
185
+ - the pull, retried (three attempts, 5 then 20 seconds apart) so that a
186
+ registry that is down is named as such; a pull that fails every attempt
187
+ or a `docker run` that refuses raises the core's `ContainerStartError`
188
+ with docker's own last line, and the harness records the modifications
189
+ as `unstarted` (the container, not the modification);
190
+ - the container itself, `DockerTarget`: `docker run -d --rm <image> sh -c
191
+ 'sleep infinity'`, then `exec`, `cp` and `diff` against it, and `rm -f`
192
+ at close. Ansible modifications reach it through ansible's `docker`
193
+ connection plugin (`ansible_connection`), and the target knows which
194
+ `docker diff` lines are noise (`/tmp`, `/var/log`, the package caches,
195
+ ansible's own directories, `/run`) and tells the harness to ignore them.
196
+
197
+ Which image the container starts from is the catalog's stand-in block,
198
+ keyed by this runtime's type: the family's own `docker` block, else the
199
+ block of the family it IS, with the OS builder's `local_test_image`
200
+ overriding both. The daemon this runs on is the host's own (the
201
+ local `docker` CLI's current context), not the daemon a `docker` runtime
202
+ entry in the tree declares: the tests are local by design.
203
+
116
204
  ### Bakes
117
205
 
118
206
  `packer_source_type()` is `docker`, HashiCorp's docker plugin. The source
@@ -154,9 +242,38 @@ per-key tags; `release_commands` moves `<repository>:<series>--<model>`.
154
242
 
155
243
  ### Instances
156
244
 
157
- The instance hooks (power state, identity, verification, sessions,
158
- relabel) are the next branch of stage 103; on this branch they answer as the
159
- core's defaults do ("cannot").
245
+ Every instance hook is answered against the daemon, by the container
246
+ that bears the instance's name (a container's name is unique on a
247
+ daemon): `docker container inspect <name>`, where a container of that
248
+ name labelled as another configuration's reads as absent.
249
+
250
+ - **Launch delivery** is by session: a container has no first boot, so
251
+ the instance root uploads the launch script at creation and the system
252
+ runs it by exec after the apply.
253
+ - **Power state** is `.State.Status` in the system's words: `running` is
254
+ running; `created` and `exited` are stopped (the container exists and
255
+ can be started); `paused` is suspended; `restarting` is starting;
256
+ `removing` is stopping; `dead` is unknown; no such container is absent.
257
+ `start_instance` and `stop_instance` are `docker start` and `docker
258
+ stop`, each confirmed by reading the state back.
259
+ - **Identity** is the container id (a re-create is a new id, so a new
260
+ generation, as the ledger expects) and the hostname the container was
261
+ given. The **boot image** is the image id the container was created
262
+ from (`.Image`), which on this runtime is the build id itself.
263
+ - **Sessions** are `docker exec -i -u root <name> bash -s` with the
264
+ script on stdin; there is no ssh proxy command, because login is by
265
+ exec.
266
+ - **Verification** runs one exec that reports the launch marker (the
267
+ script's last act, so its presence means every launch parameter
268
+ applied), each declared mount point's own line from the container's
269
+ mount table (`/proc/mounts`), and reads the image the container was
270
+ created from against the expected build; a declared mount count with
271
+ no mount points named fails, because a container's mounts are checked
272
+ by name.
273
+ - **Relabel** re-creates nothing: a container's labels are fixed when it
274
+ is created, so `retag_instance` refuses, naming the labels the
275
+ container would carry after a re-create (an upgrade, or a decommission
276
+ and redeclaration), which is the way to get them.
160
277
 
161
278
  ## Example configuration
162
279
 
@@ -194,7 +311,8 @@ image_builders:
194
311
 
195
312
  - A daemon that speaks the Docker Engine API, reachable from the machine
196
313
  that runs the system: `docker version` against the runtime's `host` or
197
- `context` must answer (preflight says so in one line per daemon).
314
+ `context` must answer (preflight says so in one line per daemon; the
315
+ probe is this plugin's own `session_status` hook).
198
316
  - The `docker` CLI, declared in `cfg/executables.yml` (`version: ">=24"`
199
317
  is the floor the system runs with); `--init` needs the daemon's
200
318
  `docker-init`, which every supported daemon ships.
@@ -202,14 +320,16 @@ image_builders:
202
320
  the image builder), and `ansible-playbook` on the machine that bakes:
203
321
  ansible's docker connection runs the local `docker` CLI against the same
204
322
  daemon.
205
- - Podman's API service works as the daemon (proved 2026-11-01 against Podman
206
- 5.8.2 rootless on AlmaLinux 10, through `docker` over ssh; the setup and what
207
- differed are in [docs/OPERATIONS.md](../../docs/OPERATIONS.md), "Podman as
208
- the daemon"). A rootless Podman user needs `/etc/subuid` and `/etc/subgid`
209
- ranges. Podman Desktop's machine on macOS works too, rootful and beside
210
- OrbStack (proved 2026-11-01 with Podman 5.8.9; `just
211
- test-podman-desktop-cycle`, which skips when no machine runs; Podman 6
212
- dropped Intel Macs, so on one the proof lasts until June 2027).
323
+ - Podman's API service works as the daemon: Podman 5.8 or later, rootless
324
+ on AlmaLinux 10 through `docker` over ssh is the proved shape, and the
325
+ setup and what differs from Docker are in
326
+ [docs/OPERATIONS.md](../../docs/OPERATIONS.md), "Podman as the daemon".
327
+ A rootless Podman user needs `/etc/subuid` and `/etc/subgid` ranges.
328
+ Podman Desktop's machine on macOS works too, rootful and beside
329
+ OrbStack (`just test-podman-desktop-cycle` runs the cycle on it and
330
+ skips when no machine runs). Podman 6 dropped Intel Macs, so an Intel
331
+ host stays on Podman 5 and the proof there has an end date, kept in
332
+ [REMINDERS.md](../../REMINDERS.md).
213
333
  - The posix identity plugin for the groups an instance image activates; an
214
334
  OPA group is refused on this runtime.
215
335
  - A tree whose only runtime is docker declares a `local` state manager; a
@@ -223,7 +343,7 @@ builder's reference in the [packer plugin](../packer-plugin/README.md) for
223
343
  `type: packer-docker`. An OS builder's `runtimes[]` entry on a docker
224
344
  runtime takes the usual keys; its `query` may use `name`, `version`,
225
345
  `publisher`, `architecture` and `native.image`, and its `image_id` is a
226
- digest reference. `output_image_name` (stage 105) is the tag prefix.
346
+ digest reference. `output_image_name` is the tag prefix.
227
347
 
228
348
  ## What it tests and verifies
229
349
 
@@ -231,13 +351,21 @@ digest reference. `output_image_name` (stage 105) is the tag prefix.
231
351
  the daemon cannot answer, a label key it cannot carry, a build name longer
232
352
  than a tag, a `default_machine_type` that names no declared machine type,
233
353
  and a runtime that declares both `host` and `context`.
234
- - `preflight` runs `docker version` against each docker runtime's daemon
235
- and prints whether it answers.
354
+ - `preflight` prints whether each docker runtime's daemon answers. The
355
+ probe is this plugin's: the builder class's `session_status` hook runs
356
+ `docker version` with the declared executable's binary against the
357
+ runtime's `host` or `context` (`probe_daemon`), and answers the core
358
+ with the engine and API versions or the first line of why not; a daemon
359
+ that answers is present and judged, one that does not is absent, with
360
+ the hint to start it or fix the address. The class also declares
361
+ `DOCKER_*` as its credential prefix (set-but-empty is refused) and
362
+ classifies `DockerUnreachable` into the one-line load failure below.
236
363
  - The unit tests ([tests/](tests/)) pin the names module (tags, repository
237
364
  names, movable tags), the query translation, the model's environment and
238
365
  the packer source and post-processor shapes without a daemon; the
239
- system's stage 103 tests drive a dry `run --all` over an overlay of the
240
- frozen fixture and check the emitted docker sources.
366
+ system's [tests/test_container_runtime.py](../../tests/test_container_runtime.py)
367
+ drives a dry `run --all` over an overlay of the frozen fixture and
368
+ checks the emitted docker sources.
241
369
  - `just test-docker-bake`, a leg of `just full-test`, bakes an AlmaLinux 10
242
370
  and a Debian 12 base image and an instance image on the local daemon,
243
371
  checks the lineage and the tags, disposes them, and skips loudly without
@@ -251,6 +379,10 @@ digest reference. `output_image_name` (stage 105) is the tag prefix.
251
379
 
252
380
  ## When it fails
253
381
 
382
+ Incidents that have happened, with their cause and fix, are recorded on
383
+ [INCIDENTS.md](../../docs/INCIDENTS.md); what follows keeps each
384
+ failure's symptom, its meaning and what to do.
385
+
254
386
  | Symptom | Cause | Remedy |
255
387
  |---|---|---|
256
388
  | `the configuration cannot load: docker runtime X: the daemon at ... cannot be reached` | The daemon is not running, or `host`/`context` names the wrong one. | Start it (OrbStack, Docker Desktop, the engine on the host) or fix the address; `preflight` shows which daemon answers. |
@@ -259,7 +391,7 @@ digest reference. `output_image_name` (stage 105) is the tag prefix.
259
391
  | `image ... is in use by container(s) ...` at disposal | A container stands on the build. | Decommission the container first; the image is never pulled from under it. |
260
392
  | An ansible step cannot reach the container | The bake ran against a daemon other than the one the local `docker` CLI uses. | The runtime's `host`/`context` is what both read; check `DOCKER_HOST` is not also set in the shell to something else. |
261
393
  | The bootstrap says `docker.runtime: ... -- no default can be derived` under `--quiet` | The tree declares no runtime of type `docker`, or the section was kept from an earlier interview of a tree that had one. | Declare the runtime, or answer `want_docker: no`. |
262
- | `parent: lineage=<id> tag=series:<name>` in the state query on a Podman daemon | A release before 2026-11-01 compared `RepoTags` as written; Podman spells them `docker.io/<repository>:<tag>`. | Take a later release; nothing on the daemon needs repairing, the movable tags were there. |
394
+ | `parent: lineage=<id> tag=series:<name>` in the state query on a Podman daemon | Podman spells `RepoTags` as `docker.io/<repository>:<tag>`, so a tag must be compared with its registry prefix stripped; a release that compares `RepoTags` as written reads every movable tag as missing ([the stage index](../../docs/CHANGES.md#s109) names the release that strips it). | Take a release that strips the prefix; nothing on the daemon needs repairing, the movable tags are there. |
263
395
  | `a docker tag is at most 128 characters` at validate | A declared `output_image_name` is too long once the timestamp is appended. | Shorten it. |
264
396
 
265
397
  ## Related