diff --git a/.gitea/workflows/gates.yml b/.gitea/workflows/gates.yml index 816563c6..5d892755 100644 --- a/.gitea/workflows/gates.yml +++ b/.gitea/workflows/gates.yml @@ -211,6 +211,9 @@ jobs: # R-986: the security-scan gate fetches the PINNED gitleaks here (sha256-checked); no Go, so govulncheck says # NOT CHECKED in CI, out loud. Warn-first either way: the scan lists, it never fails this job. FELHOM_SCAN_FETCH: "1" + # R-1327: test_image_runtime.py reads a zstd layer with the PINNED zstandard wheel (sha256-checked); with this + # set, a missing decoder FAILS the suite instead of saying NOT CHECKED. + FELHOM_WHEEL_FETCH: "1" run: python3 scripts/repo_gates.py --fast --scope="${PUSH_SCOPE:-code}" - name: Manual proof - alarm key present, optional forced failure (dispatch only, R-1129) diff --git a/.gitea/workflows/security-watch.yml b/.gitea/workflows/security-watch.yml index 3b39e106..98857fa3 100644 --- a/.gitea/workflows/security-watch.yml +++ b/.gitea/workflows/security-watch.yml @@ -51,6 +51,9 @@ jobs: RESEND_API_KEY: ${{ secrets.RESEND_API_KEY }} GH_ADVISORY_TOKEN: ${{ secrets.GH_ADVISORY_TOKEN }} MODE: ${{ github.event.inputs.mode }} + # R-1327: zstd layers (Home Assistant and others) are read with the PINNED zstandard wheel, sha256-checked + # (scripts/image_runtime.py); without it they are NOT CHECKED, out loud. + FELHOM_WHEEL_FETCH: "1" run: | set -u mkdir -p documentation/security-watch diff --git a/documentation/architecture/08-alarm-ladder.md b/documentation/architecture/08-alarm-ladder.md index 882ef73a..dd2daef9 100644 --- a/documentation/architecture/08-alarm-ladder.md +++ b/documentation/architecture/08-alarm-ladder.md @@ -691,9 +691,12 @@ needed the layers — Alpine/Debian package databases, Node's `node_version.h`, matches it against `scripts/security_watch_runtimes.json`; a hit is an ADVISORY with source „runtime", a read that fails is NOT CHECKED. Results are cached by the tag's digest in `state.json` (`runtime_cache`) and the nightly lookup is a HEAD request (Docker Hub does not count it against the anonymous pull limit — the first run's GETs hit HTTP 429). -**Decided by CC unattended 2026-10-27 — operator may reverse:** the CI runner has no zstd (Python 3.13 has none), so -images with zstd layers (Home Assistant) are read on DooPlex by a filling run (`--no-mail`, the stored Docker Hub login -through `sec run`) and committed into the cache; CI reads them from there and lists a new unread zstd image as NOT -CHECKED — instead of a new dependency in CI. The DooPlex group (`documentation/security-watch/dooplex-workloads.txt`, +**The cache fills itself in CI (2026-10-28, R-1327; replaces the 2026-10-27 night's DooPlex filling run).** Images with +zstd layers (Home Assistant) are read with the `zstandard` package, version 0.25.0, as a wheel pinned by the sha256 PyPI +publishes and checked every time it is opened; the workflows fetch it (`FELHOM_WHEEL_FETCH=1`) into the runner's cache. +Not the `zstd` program in the CI runner image: that image is built in the homelab repo, and changing it is a DooPlex +change. A missing or wrong wheel makes the zstd layers NOT CHECKED, said in the log's `RUNTIME` line — never a pass. A +new image is read on the night its tag first appears; the log's `RUNTIME read=… (… s) from-cache=…` line says how much +was read and how long it took. The DooPlex group (`documentation/security-watch/dooplex-workloads.txt`, from homelab-manifests) is read the same way and mailed in its own block; Felhom changes nothing on DooPlex. diff --git a/documentation/audits/runtime-fixes-2026-10-28/immich-repair/immich_repair.py b/documentation/audits/runtime-fixes-2026-10-28/immich-repair/immich_repair.py new file mode 100644 index 00000000..f7ae3c87 --- /dev/null +++ b/documentation/audits/runtime-fixes-2026-10-28/immich-repair/immich_repair.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +"""immich_repair.py EVDIR — re-prove Immich's after_unclean_boot scripts on v3.3.5 on scratch 9202 (the method of +felhom.eu audits/immich-repair-2026-10-14 Part C): deploy through the product (9202 pointed at the drill, Immich +v3.3.5), the admin through the setup gate, a family member, 20 + 10 photos through Immich's own API, then damage +4 thumbnail files and delete 1 original, run the template's repair and report_lost commands inside immich-server +exactly as the controller does (node -e