Spaces:
Sleeping
Deployment trust & reproducibility (D7, 2026-07)
Deep revision D7 from
2026-07-full-repo-review.md. Addresses
finding #5 ("the trust model no longer matches deployment") and the
deployment gaps in dimension 12: desktop-era filesystem RPCs shipping
unauthenticated on the public Space, and a continuous, ungated,
force-pushed deploy with no rollback primitive.
The security-critical half — the lockdown profile — shipped in full. The reproducibility tail (a pinned Python closure) is a documented follow-up because it must be resolved on the deployment's interpreter.
The lockdown profile
The filesystem RPCs assume the caller is the local operator:
| Endpoint | Desktop intent | Risk on the public Space |
|---|---|---|
POST /api/config-file-path |
point the app at a custom config JSON | read any JSON on the container |
POST /api/save-session |
save a study to a chosen folder | write anywhere on the container |
GET /api/list-sessions |
browse saved studies | enumerate any directory |
POST /api/load-session |
reload a saved study | read any session.json |
GET /api/pick-path |
native OS file/dir picker | n/a headless (already a no-op) |
On the Space (anonymous visitors, Game Mode) none of these are needed —
studies come from the bundled presets. So when COSTUDY4GRID_LOCKDOWN
is truthy (1/true/yes/on), each is disabled:
403 {"detail": "This operation is disabled on the hosted deployment.",
"code": "LOCKED_DOWN"}
- The flag is read once at import into
main._LOCKDOWN; the guard_reject_when_locked_down()is the first statement of each locked handler.LOCKED_DOWNis a stable code in the D2 error envelope (services/api_errors.py, mapped from status 403) and the frontendApiErrorCodeunion. - The read-only app config (
GET /api/user-config,GET /api/config-file-path) stays available so the SPA still boots and reads its bundledconfig.json. - The
DockerfilesetsCOSTUDY4GRID_LOCKDOWN=1. Local dev and the test suite leave it unset, so behaviour is unchanged off the Space —TestLockdownProfileintest_api_endpoints.pyexercises both states (403 +LOCKED_DOWNwhen on; normal 200 when off; read-only config reachable either way).
Disabling (rather than confining to a fixed directory) is the conservative choice for a single-player ephemeral container; confinement is a possible future refinement if the Space ever needs session persistence.
Test-gated deploy + rollback
.github/workflows/deploy-huggingface.yml previously fired on every push
to main and force-pushed a history-free snapshot to the Space — no test
gate, and (because the Space push is force-pushed + squashed) no rollback
trail. D7 tightens both:
- Test gate: the deploy now triggers on
workflow_runof the Tests workflow completing successfully onmain. A red build no longer ships.workflow_dispatchstill runs unconditionally (the rollback path). - Rollback pointer: every successful deploy tags the exact commit it
shipped on origin as
space-deploy-<UTC-timestamp>-<shortsha>. Since the Space's own history is squashed away, this origin tag is the only durable record of what shipped. Roll back by re-dispatching the workflow from a priorspace-deploy-*tag (workflow_dispatchis not gated). Full steps indeploy/huggingface/SETUP.md→ "Rolling back a bad deploy".
Reproducible Python closure (tracked follow-up)
The image resolves the dependency tree at build time (version floors in
pyproject.toml plus the expert_op4grid_recommender floor), so a
zero-change rebuild can still pick up newer transitive releases — the
Dockerfile's "mirrors CI" claim isn't literally true. The fix is a
committed lockfile consumed by both the Dockerfile and the Tests
workflow:
# on Python 3.10 (the image base — NOT a dev 3.11, or it pins wrong wheels):
pip install pip-tools
pip-compile --output-file requirements.lock pyproject.toml
This is left as a follow-up rather than generated in-repo precisely
because it must be resolved on the deployment's 3.10 interpreter; a
lockfile pinned on the wrong Python is worse than none. See
SETUP.md → "Reproducible Python
closure".
Remaining (tracked)
- Generate + wire the
requirements.lock(above). - Confinement (vs. outright disabling) of the session RPCs if the Space ever needs persistence.
HEALTHCHECKin the Dockerfile and dropping the image's dead weight (dimension-12 items, independent of the trust model).