test(tier4): Tor-down + cosign-verify + clock/ENOSPC + per-service uid fault-injection#618
Merged
Merged
Conversation
…d fault-injection Adds the four real-hardware gaps a coverage audit found at the top tier: a --fault-injection case that stops the tor container and proves both no clearnet egress leak (#563, reuses bench-verify-egress.sh) and that `doctor` flags the outage instead of passing silently; a direct exercise of pithead's own verify_release_images() in release-smoke.sh against a real signed bundle plus a tampered-digest negative case (#376/#459); PATH-shadowed timedatectl and tmpfs-ENOSPC fault-injection cases for doctor's clock-sync and db_healthy verdicts (#383); and a per-service `docker exec <svc> id -u` matrix/--check assertion against each of the 9 services' audited uid (#255/#91). Verified by shellcheck --severity=warning, shfmt -i 4 -d, bash -n, the integration harness self-test (132/132), and manual tracing of the sourced verify_release_images()/clock_sync_status() paths against synthetic bundles — this cannot run against real hardware locally.
Drop the dead pre-existence guard around the bundle extraction (WORK is always a fresh mktemp -d, so the dir can never already exist) and replace the last-hex-char-flip case statement with a fixed all-zero 64-char digest — same effect (a well-formed but mismatched sha256), fewer lines.
VijitSingh97
force-pushed
the
claude/test-tier4-faultinjection
branch
from
July 17, 2026 23:37
bae8862 to
266cf78
Compare
VijitSingh97
added a commit
that referenced
this pull request
Jul 18, 2026
…y outage (#621) Follows up #619. That fix made BOTH egress checks fail when tor was down while mining ran — two FAIL lines for one root cause. Replace that with a single dedicated check_tor_running() that owns the "tor down while the stack runs" verdict (OK when up, FAIL when down+mining, info-skip on a clean down), called first in doctor's Network section; the two egress checks revert to a plain info-skip when tor is down. One loud line, not two. doctor still exits non-zero on the outage (the #618 fault_tor_down assertion holds). tor is unconditional (no compose profile gates it), so this never false-fires on a legitimate tor-absent deployment. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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
Adds the four real-hardware (tier-4) coverage gaps a coverage audit found — all harness code, runs at the v1.8 e2e/release gate on real hardware (gouda), not PR CI. Cannot be run locally; verified by shellcheck/shfmt/bash -n plus manual tracing (see below).
mini-stack: Tor/SOCKS-down scenario — assert no clearnet fallback and safe degradation #563 Tor-container-down / SOCKS unreachable (TOP PRIVACY PRIORITY, was uncovered at every tier) —
fault_tor_down()intests/integration/run.sh:1196(called fromrun_fault_injection()): stops thetorcontainer, asserts (a) zero clearnet egress leak viaassert_egress_posture(reusestests/integration/benchmarks/bench-verify-egress.sh's/proc/net/tcpproof — the same one the steady-state battery runs) and (b)pithead doctorexits non-zero and does not print "All checks passed." while tor is down, then restarts tor and re-asserts both the egress proof andpithead status.cosign verify path (Sign release images with cosign and verify them in
pithead upgrade#376/Post-publish release smoke test: real cosign verify + real dashboard upgrade against the published bundle (#376/#59) #459) —verify_release_images_direct()inscripts/release-smoke.sh:176: exercises pithead's ownverify_release_images()function directly (not a reimplementation) in the extracted, published bundle dir. Positive case (needs a signed release): the real function against the real pinned digests + committedcosign.pubmust pass. Negative case (security-critical, runs regardless of signing): a digest tampered in a copy of the bundle'sdocker-compose.ymlmust make the function abort fail-closed. Called frommainatscripts/release-smoke.sh:306.clock-drift/NTP + ENOSPC verdicts (doctor: check the egress firewall is actually installed, stratum :3333 is listening, and the dashboard answers #383) —
fault_clock_drift()(tests/integration/run.sh:1235) PATH-shadows thetimedatectlbinary (the same wrapper trickfault_firewall_rollbackuses forsudo) sodoctor's real NTP check classifies a real unsynced report — without touching the box's actual clock (mining is time-sensitive).fault_disk_enospc()(tests/integration/run.sh:1254) bind-mounts a 1MiB tmpfs over the dashboard data dir and fills it solid, forcing a real kernel ENOSPC (distinct from the existingfault_db_readonly's EACCES) and assertingdb_healthy:false, then unmounts and asserts recovery.Per-service runtime non-root uid (Run containers as a non-root user (drop root inside the container) #255/Security follow-ups: dashboard host-networking, Tari gRPC allow-list, assert_safe_dir #91) —
tests/integration/run.sh:615(insideassert_running_state's local-mode block, so it runs on every matrix scenario and at--check):docker exec <svc> id -ufor all 9 services against an audited expected uid — tor=100, monerod/p2pool/xmrig-proxy/dashboard/tari=1000, and caddy/docker-proxy/docker-control=0 (root, mitigated bycap_drop: ALL+ isolation, not uid — verified empirically against the actual pulled images, see below).docs/testing-strategy.md's "Known gaps" section is updated to mark all four as covered.Verification (cannot run against real hardware locally)
bash -n,shellcheck --severity=warning,shfmt -i 4 -d— clean on both changed scripts, using the exactmake lint-shfile set.tests/integration/selftest.sh— 132/132 still pass (nothing broken in the sourced pure helpers).make lint-docs-voice/ markdownlint — clean on the doc edit.caddy:2.11.4,tecnativa/docker-socket-proxy:v0.4.2, andubuntu:24.04/alpine:3.24images to empirically confirm each service's actual runtime uid before hardcoding the expected table — caddy and the two Docker socket proxies genuinely run as root by design, so the check pins that audited posture rather than asserting something false).pitheadin a scratch dir and calledverify_release_images()directly through the exactcd ... && bash -c 'source ./pithead; verify_release_images'invocation the harness uses, with a fake failingcosign, to confirm the non-zero exit propagates correctly for the negative case.pitheadand calledclock_sync_status()under the PATH-shadowedtimedatectl, and ran the full./pithead doctorinvocation under the shadow, to confirm the exact "NOT NTP-synchronized" string the assertion checks for.sedagainst a synthetic file end-to-end.What needs the real box to actually execute
doctor:check_egress_firewall_installedandcheck_tor_clearnet_egressboth SKIP (dr_info, notdr_fail/dr_warn) when the tor container isn't running, so nothing else indoctorcurrently names a tor-only outage — a healthy-otherwise box can print "All checks passed." with tor stopped. The harness is written to prove that gap, not paper over it; closing it needs a smalldoctorproduct fix (an explicit tor-down verdict), which is out of scope for this test-only PR and should be filed as a follow-up.pithead upgrade#376); on an unsigned release it warns and skips, which is documented as expected in the code.Does not merge on its own — awaiting the v1.8 cut's real-hardware run on gouda.
🤖 Generated with Claude Code