Skip to content

fix(deploy): check_mounted_config reads what the container sees, not what docker cp re-reads - #772

Merged
Gerrrt merged 1 commit into
mainfrom
gerrrt/mounted-config-false-pass
Oct 1, 2026
Merged

Gerrrt merged 1 commit into
mainfrom
gerrrt/mounted-config-false-pass

Conversation

@Gerrrt

@Gerrrt Gerrrt commented Oct 1, 2026

Copy link
Copy Markdown
Owner

What changed

scripts/check_mounted_config.py checks that each running container has the same single-file config the repo has. make up runs it with --fix. It could never fail. This PR makes it read what the container actually sees.

  • Why it could never fail. It read the container's copy with docker cp. For a bind mount, docker cp re-resolves the mount's source path on the host, so it returns the file git just wrote. It does not return the inode the container is pinned to. Every comparison was the new file against itself.

    Measured on a scratch container after a git-style rename:

    Reader Returned
    docker exec cat old
    docker cp new
  • The new reader opens /proc/1/root/<path> from a throwaway helper that shares the container's PID namespace. That resolves the path in the container's own mount namespace. It covers distroless loki, where exec cat is impossible.

    • Helper capabilities: SYS_PTRACE for the cross-uid /proc check, and DAC_READ_SEARCH for 0640 keys. No network.
    • Helper image: the pinned Alloy image, via image-for.sh.
  • --self-test, discovered by self-tests.sh, reproduces the rename on a non-root, capability-free container. It passes with the new reader. With the old one it fails the three cases that involve a rename and passes the other two.

What it found

How it first showed up

On 2026-09-30, during the #182 rollout, the check reported blackbox.yaml as matching. The exporter was actually running without the module #182 had just added.

Verification

  • --self-test passes. A mutation run with the old docker cp reader fails it.
  • Ran against live observability and live sensitive (read-only).
  • validate.sh exit 0.

🤖 Generated with Claude Code

…what docker cp re-reads

The check read each container's copy of a single-file mount with `docker cp`.
For a bind mount, docker cp re-resolves the mount's source on the host, so it
returned the file git had just written rather than the inode the container is
pinned to, and every comparison was the new file against itself. Measured on a
scratch container after a rename: `docker exec cat` said old, `docker cp`
said new. On 2026-09-30 it passed blackbox.yaml while the exporter ran without
the module #182 had just added.

It now reads /proc/1/root/<path> from a helper sharing the container's PID
namespace (SYS_PTRACE for the uid check, DAC_READ_SEARCH for 0640 keys), the
pinned Alloy image via image-for.sh, so distroless loki is covered too.

--self-test reproduces the rename on a throwaway non-root container. It passes
with the new reader, and fails three of its five cases with the old one.

Run against production it found Alertmanager on a pre-#761 config since
2026-09-28, missing the TlsAcmeRenewalStalled-over-Late inhibit. Recreated and
verified. trinity's 12 single-file mounts all match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 00:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The implementation directly addresses the faulty read path and includes focused regression coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Fixes mounted-config verification by reading files through the container’s mount namespace instead of docker cp.

Changes:

  • Adds a capability-limited Alloy helper for accurate reads.
  • Adds a Docker-based regression self-test.
  • Documents the failure and operational findings.
File Description
scripts/​check_mounted_config.py Implements namespace-aware reads and self-testing.
docs/​changelog.md Records the incident, fix, and deployment findings.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Gerrrt
Gerrrt merged commit 653a8ab into main Oct 1, 2026
8 checks passed
@Gerrrt
Gerrrt deleted the gerrrt/mounted-config-false-pass branch October 1, 2026 00:30
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.

2 participants