Repository navigation
fix(container-gateway): answer 404 when an inspect fails the label check - #2078
Merged
shahar1 merged 2 commits intoNov 14, 2026
Merged
Conversation
An untyped `docker inspect <image>` asks for a container of that name first and tries the image only after a 404. The gateway answered 403, so the CLI stopped there and the tool calling it concluded the image was missing. Apache Airflow's breeze then tried to rebuild an image that was already present, and the build is refused too. An inspect of a name that is not one of the project's resources now answers 404, for a missing name and for another project's alike, with the same body. The two cases stay indistinguishable, so the gateway is still not an existence oracle. Every other failed label check stays 403. Signed-off-by: Shahar Epstein <60007259+shahar1@users.noreply.github.com> Generated-by: Claude Code (Fable 5.2)
…spect The 404 for a failed label check on an inspect also covered a backend that was unreachable or answered with an error. An outage then read as "not found", and a client could go on to create a resource that exists. The 404 now needs a 2xx or a 404 from the backend; anything else is refused with 403, as before. The docs name the routes the 404 applies to: an inspect of a container, pod, volume or network. An exec inspect keeps the 403. Signed-off-by: Shahar Epstein <60007259+shahar1@users.noreply.github.com> Generated-by: Claude Code (Fable 5.2)
Kaap10
approved these changes
Nov 14, 2026
Kaap10
left a comment
Contributor
There was a problem hiding this comment.
LGTM! Very clean and targeted fix for the untyped docker inspect probing behavior.
A few strong details in the implementation:
- Existence oracle protection preserved: Ensuring foreign and missing resources return the identical 404 response body keeps the gateway's non-detection property intact.
- Outage boundary: Keeping
403when the daemon cannot settle the check (ConnectionRefusedError/ unreachable backend) prevents outages from masquerading as "not found". - Comprehensive test coverage: Parameterized test
test_inspect_of_a_foreign_or_missing_resource_is_the_same_404and outage casetest_inspect_is_403_when_the_backend_cannot_settle_the_label_checkthoroughly pin down the contract.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. The maintainer
approving this PR has read the findings and signed off. If
something feels off, please reply on the PR and a maintainer
will follow up.More on how Apache Magpie handles maintainer review:
Contributing guide.*
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
docker inspect <image>asks for a container of that name first (GET /containers/<name>/json) and tries the image only after a404. The gateway answered403, so the CLI stopped there. A tool that checks for an image this way concluded the image was missing. Apache Airflow'sbreezethen tried to rebuild a CI image that was already present, and the gateway refuses that build as well.404, for a missing name and for another project's resource alike, with the same body. Every other failed label check stays403, an exec inspect included. The gateway still forwards nothing that it refused before.404needs a 2xx or a 404 from the daemon for the label check. When the daemon is unreachable or answers with an error, the inspect keeps the403, so an outage never reads as "not found".relay.pyexists so that a client cannot tell "no such resource" from "another project's". Both cases get one answer per route, before and after this change.docker inspectamong the workflows that cannot pass the gateway. The README and the two specs say where the404applies.Type of change
.claude/skills/<name>/) — eval fixtures updated belowtools/<system>/*.md)tools/*/withpyproject.toml)docs/,README.md,CONTRIBUTING.md)projects/_template/)prek, workflows, validators)Test plan
tools/container-gateway:uv run pytest testsgives 805 passed, 5 deselected.ruff checkandmypy srcpass.test_inspect_of_a_foreign_or_missing_resource_is_the_same_404(containers, volumes, networks) fails on all three cases without the fix. It asserts404for a foreign name and for a missing name, that the two bodies are identical once the name is substituted, and that an owned container still inspects with200.test_inspect_is_403_when_the_backend_cannot_settle_the_label_checkfails on the first commit and passes on the second.prek run workspace-pytest --from-ref upstream/main --to-ref HEADpasses.lychee,markdownlint,typos,ruff,mypy,spec-validateandskill-and-tool-validatepass on the changed files.isolated-setup-fingerprintre-stampedisolated_fingerprint.py.docker inspect ghcr.io/apache/airflow/main/ci/python3.11returns the image. With the released gateway it fails withlabel-check: … does not belong to this project.docker start <missing name>still gets the403label-check refusal.breeze shellno longer tries to build the CI image when the image exists.gpt-6.1-sol, read-only). Round 1 found the outage case, a test that passed if every inspect answered404, and doc wording that covered exec inspect. All three are fixed in the second commit. Round 2 found nothing.symlink-lint(old directories under an untracked.worktrees/) andcheck-doc-sync(an untracked eval folder). Both failures are the same without this change.RFC-AI-0004 compliance
breezeappears only as the example of a tool that hits the refusal, as in the existing troubleshooting entry.Linked issues
Refs #1810, which documented this refusal and left the
404out.Notes for reviewers (optional)
relay.pyand still not unblock breeze." The first half was wrong for a404given to both cases. The no-detection decision needs the two cases to look the same. It does not need the status to be403.404. A refused start, stop, remove or exec keeps the403, so a policy refusal of an action still reads as a refusal.breezerun through the gateway. BuildKit and the socket bind-mount are still refused, as the troubleshooting entry says. On my machinebreeze shellnow passes the image check and stops later onexternal volume "airflow-pycache-volume" not found. I infer that the volume was created outside the gateway and has no project label; I did not inspect it on the daemon.pluginsendpoint, which the gateway denies (denied-endpoint). The exit code is still non-zero. I left that alone./exists. It is the same kind of existence probe and still answers403. I have no podman here to test a change against, so it is a possible follow-up.container-gateway --project .) lacks theservesubcommand and fails withinvalid choice.Generated-by: Claude Code (Fable 5.2)
🤖 Generated with Claude Code