Repository navigation
Run the 11 real-Redis store tests in CI - #49
Conversation
rust-test runs nextest through tests/allowance-redis.sh with --run-ignored all, so the store tests run against a private Redis (pinned image, --network none, Unix socket, no published port). The redis image hands /data to its own user, which under rootless Docker is another host user, so cleanup could not remove the folder from a sticky /tmp. The script now mounts a subfolder instead. tests/ci-run.test.mjs runs the real script with a docker stub.
The nightly CI server image build runs .github/ciod/prefetch.sh. It downloads the pinned redis:7.4-alpine linux/amd64 image through the registry API (Docker Hub, then public.ecr.aws, one attempt each), verifies every body against its digest and stores an OCI archive in the runner's cache. rust-test runs the same hook as the fallback, docker loads the archive and starts Redis with --pull never, so a test run never depends on reaching a registry. tests/redis-image.sh is the one pin. tests/ciod-prefetch.test.mjs runs the hook against fake local registries.
ice-zeus
left a comment
There was a problem hiding this comment.
Review of #49 at 130b5c4 (closes #26).
Blocking
None.
Checked: the hook verifies the index against the pin before it reads any digest from it, and verifies each manifest and blob before using it, so registry data can never choose a path or name an unpinned blob. The archive is built in a temp folder inside tools/ and renamed into place, with the .complete marker written last. rust_test runs as a plain part command, so set -e applies: a failed hook, docker load or Redis start stops the part before nextest runs, and tests/ci-run.test.mjs covers each of these. allowance-redis.sh keeps --network none, the Unix socket and no published port. $fixture_dir stays 0700 and only the mounted subfolder is 777. The store tests use random visitor ids, so running them in parallel against one Redis is safe. Tests cover the new behavior: 5 hook cases against fake registries and 6 ci-run cases. Size and file limits are within RULES.md. tier1 and maestro-policy are green on this head.
Notes
- NON-BLOCKING: The prefetched check (
.github/ciod/prefetch.sh:28) looks only at the marker and the archive file. That is fine because the archive appears only through a rename, but a test where.completeexists and the archive is missing would pin down that the hook downloads again. - NON-BLOCKING: When the pin changes, the old
redis-<digest>.tar(about 16 MB) stays intools/. It only matters if that cache lasts across nightly image builds.
Existing
.github/scripts/changed-scope.shdoes not counttests/as Rust input, so a pull request that changes onlytests/redis-image.shortests/allowance-redis.shskipsrust-test. The merge queue still runs it, and the PR body already says so (#27 touches that file).
Closes #26
Replaces #46, whose commits carried attribution lines that
maestro-policyrejects. Pushed history is never rewritten, so this branch starts again from main.What and why
The 11 store tests in
src/store_tests.rsneed a real Redis (REDIS_TEST_URL), and CI never ran them. Now everyrust-testpart runs them, and no test run reaches an image registry: one of three runs of the first design (pull from Docker Hub per run) failed on a 60 s Docker Hub timeout (https://github.com/shifter-io/web-proxy/actions/runs/42838989632).tests/redis-image.shis the one pin: theredis:7.4-alpineindexsha256:858f009f…3499(linux/amd64 manifestsha256:ca0acbb137c1…), the Docker Hub andpublic.ecr.awsrepository names and the local nameweb-proxy-ci/redis:7.4-alpine..github/ciod/prefetch.sh(new, the repository's ciod hook; nothing in Maestro changes): the nightly CI image build runs it without Docker. It fetches the index, the linux/amd64 manifest, its config and layers through registry API v2 with an anonymous token, Docker Hub first andpublic.ecr.awsonly if Docker Hub fails, one attempt each. Every body's sha256 is checked against its digest. It writes$CI_CACHE_DIR/web-proxy/tools/redis-<index digest>.tar(an OCI image layout) through a temp folder and a rename, plus a.completemarker. It printsredis image: prefetched <path>orredis image: installed now <path>..github/scripts/ci-run.sh:rust-testruns the hook (the fallback for server images built before this merges: one download and a::warning::),docker loads the archive and runsREDIS_IMAGE=web-proxy-ci/redis:7.4-alpine REDIS_PULL=never sh tests/allowance-redis.sh cargo nextest run … --run-ignored all. The job summary gets theredis image:line. Nothing retries: a failed download, a digest mismatch, a failed load or a Redis that does not start failsrust-test.tests/allowance-redis.shkeeps its interface. It reads the pin, takesREDIS_IMAGEandREDIS_PULL(defaults: the pinned image,--pull missing, as before) and logs itsdocker runline. One fix that rootless Docker needs: the image hands/datato itsredisuser, which under rootless Docker is another host user, so cleanup could not remove the fixture folder from a sticky/tmp(the part failed with 42 tests green, https://github.com/shifter-io/web-proxy/actions/runs/42837209874). The script now mounts a subfolder.#[ignore]is only for tests that needREDIS_TEST_URL.Tests
tests/ciod-prefetch.test.mjs(new) runs the hook against fake local registries (token, index, manifest, config, layer) throughREGISTRY_URL,MIRROR_URLandAUTH_URL:installed nowand writes a verified archive; the second printsprefetchedand makes no request;tests/ci-run.test.mjsruns the realallowance-redis.shwith adockerstub and a stub hook. It checksdocker load,--pull never --network nonewith no-p, the local image,REDIS_TEST_URLfor nextest, the container removed after a failing test, the summary line, the warning oninstalled now, and that a failed download, load or Redis start failsrust-testbefore any test runs.CI_CACHE_DIRandHOMEin a temp folder):installed now, thenprefetched, both exit 0, a 16 MB archive.docker loadgaveLoaded image: web-proxy-ci/redis:7.4-alpine, andallowance-redis.shstarted Redis from it with--pull never --network none.Coverage
ci-run.test.mjs, 5 inciod-prefetch.test.mjs)Proofs that the store tests cannot be skipped silently
Throwaway branches, each one change on this PR's head
130b5c4;maestro-prune-branchesremoves them after the issue closes.task/26-proof-redis-start,redis-server --no-such-option): https://github.com/shifter-io/web-proxy/actions/runs/42842718650.tier1red, onlyrust-testfailed ("Redis fixture did not become ready").task/26-proof-assert): https://github.com/shifter-io/web-proxy/actions/runs/42842725819.tier1red, onlyrust-testfailed: 42 run, 41 passed, 1 failed, 0 skipped.tests/redis-image.sh(task/26-proof-digest, last hex digit changed): https://github.com/shifter-io/web-proxy/actions/runs/42842732984.tier1red,rust-testfailed. A digest that names nothing gets 404 from both registries, so the hook ends with "redis image: download failed from https://registry-1.docker.io and https://public.ecr.aws". The "digest mismatch" path (a registry sending other bytes) is covered byciod-prefetch.test.mjs.node-testis red too, sinceci-run.test.mjschecks the pinned archive name.rust-testlog showsredis fixture: docker run --pull never --network none web-proxy-ci/redis:7.4-alpineafterLoaded image: web-proxy-ci/redis:7.4-alpine(ci-timingartifact,parts/rust-test.log).Stability and times (ci-8cpu, head 130b5c4)
Five dispatch runs, all green with the same counts (Rust 42 passed / 0 skipped, Node 246 passed), plus the pull-request run:
Today's server images predate the hook, so these runs took the fallback (
redis image: installed now, one download, with the warning).rust-testis now the longest part, about 7 s longer than clippy, and the parts step stays well under 90 s. After merge, the firsttier1run on a server image built after the merge should showredis image: prefetched.Notes
.github/scripts/changed-scope.shdoes not counttests/as Rust input, so a pull request that changes onlytests/redis-image.shskipsrust-test. The merge queue runs every part, so a bad pin still cannot merge. That file is outside this issue, and Merge-queue drill: two PRs that pass alone and break together #27 touches it.Size: about 125 production lines (the hook 90, ci-run.sh 32, ci.yml 4).