ci: mount windy-pro's read-only build inputs into dind; allow exactly that path for jobs
All checks were successful
check / gate (push) Successful in 10s
canary / probe (push) Successful in 5s

Non-secret inputs git-ignored in windy-pro (models, linux-x64 portable
bundle, enter-monitor build) that build-desktop needs. Mounted :ro into
dind; valid_volumes allows only /ci-inputs/windy-pro; refresh-ci-inputs.sh
copies them from the frozen release clone (read-only on the source).
Invariant I-5 narrowed, not dropped: exactly that one path, read-only in
dind, no other service mounts it, still no docker socket (proven to fail
on :rw). Orchestrator-approved (option a). Applied in an idle window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kit OC5
2026-09-23 14:56:48 -04:00
parent 683c01ec7d
commit c4799dcc13
4 changed files with 52 additions and 4 deletions

View File

@@ -425,9 +425,28 @@ def test_i05_jobs_get_a_network_per_job_not_a_shared_bridge():
def test_i05_jobs_cannot_bind_mount_from_the_daemon_host(): def test_i05_jobs_cannot_bind_mount_from_the_daemon_host():
cfg = (ROOT / "deploy" / "runner" / "config.yaml").read_text() """Narrowed 2026-09-23 (orchestrator-approved): a job may bind-mount EXACTLY
assert "valid_volumes: []" in cfg one daemon path, windy-pro's non-secret build inputs, and only because dind
assert 'docker_host: "-"' in cfg itself has that path READ-ONLY. Anything more (a second path, a writable
one, a glob) reopens the host to CI code. Still no docker socket for jobs."""
import re
import yaml
rd = ROOT / "deploy" / "runner"
cfg = yaml.safe_load((rd / "config.yaml").read_text())
allowed = cfg["container"]["valid_volumes"]
assert allowed in ([], ["/ci-inputs/windy-pro"]), f"I-5: jobs may mount nothing else: {allowed}"
assert cfg["container"]["docker_host"] == "-"
if allowed:
compose = yaml.safe_load((rd / "docker-compose.yml").read_text())
binds = [v for v in compose["services"]["dind"]["volumes"] if v.startswith("/")]
assert binds == ["/home/user1-gpu/ci-inputs/windy-pro:/ci-inputs/windy-pro:ro"], (
f"I-5: dind's only host bind must be the ci-inputs path, READ-ONLY: {binds}")
for name, svc in compose["services"].items():
if name != "dind":
for v in svc.get("volumes") or []:
assert not re.match(r"^/home/user1-gpu/ci-inputs", v), f"I-5: {name} mounts ci-inputs"
def test_i05_no_ci_container_can_reach_the_forge_network(): def test_i05_no_ci_container_can_reach_the_forge_network():

View File

@@ -54,6 +54,9 @@ container:
privileged: false privileged: false
options: options:
workdir_parent: /workspace workdir_parent: /workspace
valid_volumes: [] # a job cannot bind-mount anything from the daemon host # A job may bind-mount exactly ONE daemon path: the read-only windy-pro build
# inputs (mounted :ro into dind itself). Per-runner, not per-repo (act_runner
# limit): any windyadmin repo could mount it; it is non-secret and read-only.
valid_volumes: ["/ci-inputs/windy-pro"]
docker_host: "-" # do NOT expose the runner's own docker socket to jobs docker_host: "-" # do NOT expose the runner's own docker socket to jobs
force_pull: false force_pull: false

View File

@@ -49,6 +49,11 @@ services:
# A fresh volume: Sysbox shifts ownership to its own uid range. The old # A fresh volume: Sysbox shifts ownership to its own uid range. The old
# `dind-storage` is kept untouched for the privileged rollback. # `dind-storage` is kept untouched for the privileged rollback.
- dind-storage-sysbox:/var/lib/docker - dind-storage-sysbox:/var/lib/docker
# READ-ONLY, non-secret build inputs for windy-pro's desktop jobs (models,
# linux-x64 portable bundle, enter-monitor build), copied from the frozen
# release clone by deploy/runner/refresh-ci-inputs.sh. Jobs may mount ONLY
# this path (config.yaml valid_volumes). Orchestrator-approved 09-23.
- /home/user1-gpu/ci-inputs/windy-pro:/ci-inputs/windy-pro:ro
# G1.5 — bounded so a fork-bomb workflow cannot starve Grant's interactive # G1.5 — bounded so a fork-bomb workflow cannot starve Grant's interactive
# session. Veron 1 is his workstation, not a dedicated build box. # session. Veron 1 is his workstation, not a dedicated build box.
cpus: 12.0 # 12 of 24 cores cpus: 12.0 # 12 of 24 cores

View File

@@ -0,0 +1,21 @@
#!/usr/bin/env bash
# Refresh the READ-ONLY CI input cache for windy-pro desktop jobs from the FROZEN
# release clone on Veron. Reads ~/windy-pro-release only; never writes to it.
# Run when the release lane says engines / wheels / the portable bundle changed.
# Linux inputs only: 3 models + requirements-bundle.txt, bundled-portable/linux-x64,
# native/enter-monitor/build. Result is chmod a-w and mounted :ro into dind.
set -euo pipefail
SRC=/home/user1-gpu/windy-pro-release
DST=/home/user1-gpu/ci-inputs/windy-pro
models=$(ls "$SRC/extraResources/model" | grep -E '^windy-(nano|lite|core)-ct2$')
[ "$(wc -w <<<"$models")" = 3 ] || { echo "expected 3 models, got: $models"; exit 1; }
mkdir -p "$DST/extraResources/model" "$DST/bundled-portable" "$DST/native-enter-monitor-build"
chmod -R u+w "$DST"
R="ionice -c3 nice -n 19 rsync -a --delete"
for m in $models; do $R "$SRC/extraResources/model/$m/" "$DST/extraResources/model/$m/"; done
$R "$SRC/extraResources/requirements-bundle.txt" "$DST/extraResources/requirements-bundle.txt"
$R "$SRC/bundled-portable/linux-x64/" "$DST/bundled-portable/linux-x64/"
$R "$SRC/native/enter-monitor/build/" "$DST/native-enter-monitor-build/"
date -u +%FT%TZ > "$DST/.refreshed-from-windy-pro-release"
chmod -R a-w "$DST"
du -sh --apparent-size "$DST"