From 4e97f0a81ed3bb5e513180ba592b0d48fca1139d Mon Sep 17 00:00:00 2001 From: eXPerience83 <16572400+eXPerience83@users.noreply.github.com> Date: Wed, 21 Oct 2026 08:18:14 +0200 Subject: [PATCH] docs: rebase TrueNAS install guide and release status after security and DAC fixes (#282) --- CHANGELOG.md | 8 +- PROJECT_STATUS.md | 14 ++- README.es.md | 6 +- README.md | 6 +- docs/python-dual-runtime.es.md | 15 ++- docs/python-dual-runtime.md | 15 ++- docs/releases.es.md | 2 +- docs/releases.md | 2 +- docs/roadmap.md | 7 +- docs/truenas-install.es.md | 155 ++++++++++++++++++++++++++ docs/truenas-install.md | 155 ++++++++++++++++++++++++++ docs/universal-validation-tools.es.md | 8 +- docs/universal-validation-tools.md | 8 +- 13 files changed, 360 insertions(+), 41 deletions(-) create mode 100644 docs/truenas-install.es.md create mode 100644 docs/truenas-install.md diff --git a/CHANGELOG.md b/CHANGELOG.md index bb791969..97e99490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## [Unreleased] -- PR2 candidate: add isolated locked Ruff 0.17.1, pytest 9.1.1 and pre-commit 4.7.0 CLI environments plus Aqua-locked Mike Farah yq 4.54.1, shfmt 3.14.1 and actionlint 1.7.12. Preserve Python 3.14.8 default / 3.15.0 project selection, launcher independence and immutable runtime boundaries. Final exact-head build and legal/size acceptance remain pending; see `docs/universal-validation-tools.md`. - ### Automated upstream refreshes @@ -56,6 +54,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Added +- PR2 (#281): six pre-CI validation CLIs — Ruff 0.17.1, pytest 9.1.1 and pre-commit 4.7.0 in isolated hash-locked Python CLI environments, plus Aqua-locked Mike Farah yq 4.54.1, shfmt 3.14.1 and actionlint 1.7.12. The public baseline is now 53 commands; Python 3.14/3.15 project precedence, read-only root, private agent state and fail-closed behavior are intact. Exact-head CI and main-push AMD64 build/experimental edge publication succeeded on 2026-10-18. **Live TrueNAS PR2 acceptance is pending**. The project owner approved a targeted distribution/license review and +70.41 MiB base / +68.06 MiB final uncompressed soft-budget exception under #53. This is not a stable release. +- Added bilingual TrueNAS first-install/update runbooks for exact-image-source bootstrap, preflight, host ACL audit and PR2 acceptance, reusing the existing canonical directory initializer rather than adding a second creation script. - Bundle two independently locked CPython maintenance runtimes: Python 3.14.x remains the default/administrative interpreter, while compatible projects may explicitly select the parallel Python 3.15.x interpreter. Validate both versions on AMD64 and ARM64, preserve version-specific legal evidence and maintain both update lines without relaxing mise's fail-closed policy. - Expanded the immutable common developer baseline with low-cost filesystem, process, network/DNS/TLS, archive and template diagnostics; promoted already-intentional `python3`, `sqlite3`, `xz`, `ps`, `pgrep`, `gcc` and `npx` commands; and added `tree` for bounded repository inspection while preserving project-owned tool/version precedence and deferring Corepack/Yarn/pnpm shims. - Weekly exact-digest vulnerability rescanning for published AMD64 edge images with fresh Trivy evidence, bounded 30-day reports, a deduplicated automation-owned alert for fixable `CRITICAL` findings, fail-closed report validation and split scan/issue-write permissions; image rebuilding and promotion remain separate under #93. @@ -109,6 +109,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Changed +- Reference-image rebuilds (`remote-dev-base:pr2-before` and `remote-dev:pr2-before`) and four optional before-image SPDX/Trivy reports are performed by `scripts/measure-tooling-image-delta.sh`, invoked only on explicit `workflow_dispatch` with `compare_images=true`. Normal PR/main builds run the candidate-image checks without rebuilding previous images; mandatory smoke, notices, SPDX and Trivy gates remain unchanged. - Bumped the local development baseline from `0.1.0-dev` to `0.1.1-dev`. This does not create a stable release: edge publication keeps its dated `edge-YYYY.MM.DD-` identity and stable/latest remain reserved for an explicit SemVer release. - Clarified the current browser-password policy: Codex and enabled Antigravity require only a non-empty single-line configured value unless an explicit reviewed insecure override is used; Remote Dev does not enforce minimum length, composition or cross-agent uniqueness, and the two agent configuration entries may intentionally reuse the same password pending a future browser-access/security decision. - Clarified that the current launcher is a password-free navigation surface rather than the stack's central authentication boundary. Stronger single-entry launcher/gateway authentication remains future #181 work; the existing launcher-auth override is advanced/non-default and is not required for the normal deployment. @@ -163,6 +164,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ### Security +- Security fix #286 (2026-10-21): replaced both architecture-locked Python 3.14.8/3.15.0 standalone builds with upstream `20261020` packages carrying patched `pip 26.2.2` / `certifi 2026.10.19`, and repinned `uv` to patched 0.13.4. Both base/final Trivy reports now have **zero fixable CRITICAL** on the reviewed final-head CI. Verified four upstream Python archive digests, two uv digests, runtime notices and SPDX evidence; no scanner suppression or stable release. +- TrueNAS hardening fix #285 (2026-10-21): pre-create `/usr/share/doc/remote-dev` with `root:root 0755` so license/notice files remain traversable even under `cap_drop: [ALL]`; add build-time and cap-dropped functional regression tests. Actual TrueNAS confirmation of the updated image remains pending (#121). + - Hardened launcher, Codex and experimental Antigravity outer containers with read-only root filesystems, `cap_drop: [ALL]`, exact role capability whitelists, private bounded `/tmp` and `/run` tmpfs mounts, explicit PID ceilings and live same-image isolation/toolchain assertions; `/tmp` remains `noexec`, while executable Codex update and Context7 staging remains bounded under transient `/run`. - Reduced the launcher further after retiring file-backed browser secrets: production launcher containers now start directly as UID/GID `65532` with no added capabilities, while remaining free of bind, persistent, and agent-state mounts and under `no-new-privileges`. - Added a narrow Antigravity-private `state/antigravity/config` bind at `/root/.gemini/config` so the official CLI can persist project configuration below `projects/` without making the read-only container root or all of `/root/.gemini` writable; host preflight, startup hardening and cross-service canaries enforce the separate boundary. diff --git a/PROJECT_STATUS.md b/PROJECT_STATUS.md index bb69d82e..8c41724e 100644 --- a/PROJECT_STATUS.md +++ b/PROJECT_STATUS.md @@ -14,9 +14,11 @@ - Image rebuild/update workflows for bundled components rather than broad in-container package mutation. - `dev -> edge -> stable = latest` release-channel contract; immutable digest remains the strongest reproduction/rollback identity. -## PR2 candidate (#121) +## PR2 integrated — operational acceptance pending (#121) -The candidate adds exactly Ruff, pytest, pre-commit, Mike Farah yq, shfmt and actionlint (53 public commands). Python CLI graphs use pinned mise/PyPI+uv sidecars and explicit administrative Python 3.14; no shared Python packages are added. See `docs/universal-validation-tools.md` and `.es.md` for evidence and outstanding gates. PR2 acceptance remains pending; PR3 and #180 remain separate. +Security fix #286 (emSign CA trust) and the TrueNAS notice-directory traversal fix #285 are merged into `main` (2026-10-21), with the former exact-head build and post-merge experimental edge publication verified. The notice fix creates `/usr/share/doc/remote-dev` as `root:root 0755` and tests notices under a capability-free container. **Real TrueNAS acceptance of the new image, without restoring DAC capabilities, remains to be recorded in #121.** The release channel is still experimental; there is no stable tag. + +PR #281 is squash-merged into `main` at `5a56c3006135d41c913bb09a7f3be37d35c2c4df` and passed main-push `Build AMD64` and experimental `Publish edge AMD64` (2026-10-18). Ruff, pytest, pre-commit, Mike Farah yq, shfmt and actionlint are bundled (53 public commands). Python CLIs use pinned mise/PyPI+uv graphs and administrative Python 3.14 without contaminating the shared interpreters. Owner-approved soft image-size exception and targeted distribution/licensing review are recorded under #53. **Live TrueNAS PR2 acceptance remains outstanding**; #121 is open. See `docs/universal-validation-tools.md` / `.es.md` and the first-install manuals `docs/truenas-install.md` / `.es.md`. PR3 and #180 remain separate. ## Current implementation @@ -61,7 +63,7 @@ The current TrueNAS YAML path is deterministic: - `scripts/truenas-acl-audit.py` validates the TrueNAS Generic/POSIX private-state ACL contract without modifying data; - no browser-password secret directory is created or required. -See `docs/truenas-acl-contract.md` for the ACL rationale, audit and migration guidance. +See `docs/truenas-acl-contract.md` for ACL rationale and `docs/truenas-install.md` / `.es.md` for exact-revision bootstrap and post-update acceptance instructions. ## Security boundary @@ -101,13 +103,13 @@ Exact mutable component versions remain authoritative in `versions.env` and runt The main implementation foundations are already present. Before the first stable publication the repository still needs to satisfy the support level it actually claims, including: -- merge the #92 documentation synchronization and close the stale status gap; -- reconcile #31 so completed gates are no longer listed as pending and only real release blockers remain; +- complete real TrueNAS PR2/#121 acceptance for both agent roles, persistence, the six tools, project Python selection and session continuity; +- reconcile #31 so only genuine stable-release blockers remain; - pass the stable-release checklist in `docs/releases.md` on an exact `main` revision/digest; - complete any open maintenance/security item that #31 identifies as blocking the claimed stable support level; - create the dated stable changelog section and publish an exact SemVer release only after those gates pass. -Optional/future work such as #181 stronger browser access, #170 native Community App research, #124 inbound key-only SSH, #95 Context7 for Antigravity, #71 SMB, #112 ARM64, #121 universal tooling, #148 concurrent sessions/worktrees and #151 isolated container build/test tooling does not become shipped merely because the core YAML deployment works. +Optional/future work such as #181 stronger browser access, #170 native Community App research, #124 inbound key-only SSH, #95 Context7 for Antigravity, #71 SMB, #112 ARM64, #180 persistent on-demand toolchains, #148 concurrent sessions/worktrees and #151 isolated container build/test tooling does not become shipped merely because PR2's universal baseline has been integrated. ## Upstream pin policy diff --git a/README.es.md b/README.es.md index 6d82795a..19a002da 100644 --- a/README.es.md +++ b/README.es.md @@ -1,6 +1,6 @@ # Remote Dev Containers — inicio v0.1.1-dev -El candidato PR2 añade seis CLI de validación bloqueadas; consulta [diseño, evidencias y gates pendientes](docs/universal-validation-tools.es.md). +PR2 ya está integrada en `edge`: seis herramientas de validación con versiones bloqueadas y 53 comandos públicos. Consulta el [contrato y las pruebas de PR2](docs/universal-validation-tools.es.md). La aceptación práctica en TrueNAS está pendiente. Entorno comunitario de agentes de programación accesible desde navegador para Docker, NAS y homelab. @@ -28,7 +28,7 @@ Bases actuales: - un servicio Antigravity opcional aislado con estado privado y runtime del proveedor instalado únicamente mediante acción explícita del usuario; - Ubuntu 26.04 LTS, AMD64 primero; - Codex CLI desde un artefacto oficial fijado, más una ruta opcional explícita de runtime oficial conservando el CLI incluido como fallback; -- GitHub CLI, Python 3.14, Node 24, npm, uv, mise, ttyd y tmux; +- GitHub CLI, Python 3.14 predeterminado y 3.15 seleccionable por proyecto, Node 24, npm, uv, mise, ttyd, tmux y las seis herramientas PR2 (`ruff`, `pytest`, `pre-commit`, `yq`, `shfmt`, `actionlint`); - un único contrato canónico y neutral de persistencia; - un único contrato runtime de autenticación web basado en `WEB_PASSWORD` para los endpoints de agente protegidos, con entradas separadas para Codex/Antigravity; actualmente los valores pueden reutilizarse entre agentes; - selección de proyecto debajo de cada `/workspace` privado; @@ -36,6 +36,8 @@ Bases actuales: ## Instalar en TrueNAS SCALE +**[Manual paso a paso: primer despliegue, directorios persistentes y actualización segura](docs/truenas-install.es.md).** Incluye los comandos para obtener los scripts de la misma revisión que la imagen y un checklist de aceptación de PR2. + Utiliza [`compose/truenas.yml`](compose/truenas.yml) como **YAML canónico de Custom App para TrueNAS**. No mantengas una copia independiente del stack en el README. Los detalles de la UI de TrueNAS pueden cambiar entre versiones. La referencia upstream actual es la [documentación de Custom Apps de TrueNAS](https://www.truenas.com/docs/scale/apps/installcustomappscreens/). diff --git a/README.md b/README.md index 3dafa988..f6d89130 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Remote Dev Containers — starter v0.1.1-dev -The PR2 candidate adds six locked validation CLIs; see [design, evidence and pending gates](docs/universal-validation-tools.md). +PR2 is integrated into `edge`: six pinned validation CLIs and a 53-command public baseline. See the [PR2 tooling contract and evidence](docs/universal-validation-tools.md). Live TrueNAS acceptance is still pending. Community-maintained, browser-accessible coding-agent environment for Docker, NAS and homelab systems. @@ -28,7 +28,7 @@ Current foundations: - an optional isolated Antigravity service with private state and a vendor runtime installed only by explicit user action; - Ubuntu 26.04 LTS, AMD64 first; - Codex CLI from an official pinned release asset, plus an explicit optional official runtime path with the bundled CLI retained as fallback; -- GitHub CLI, Python 3.14, Node 24, npm, uv, mise, ttyd and tmux; +- GitHub CLI, default Python 3.14 and project-selectable Python 3.15, Node 24, npm, uv, mise, ttyd, tmux and six PR2 validation CLIs (`ruff`, `pytest`, `pre-commit`, `yq`, `shfmt`, `actionlint`); - one canonical role-neutral persistent-data contract; - one configuration-backed `WEB_PASSWORD` browser-authentication runtime contract for protected agent endpoints, with separate Codex/Antigravity configuration entries; values may currently be reused across agents; - project selection below each private `/workspace` collection root; @@ -36,6 +36,8 @@ Current foundations: ## Install on TrueNAS SCALE +**[Step-by-step manual: first deployment, persistent directories, and safe updates](docs/truenas-install.md).** Includes same-source script retrieval and a PR2 acceptance checklist. + Use [`compose/truenas.yml`](compose/truenas.yml) as the **canonical TrueNAS Custom App YAML**. Do not maintain a copied stack definition in the README. TrueNAS UI details may change between releases. The current upstream reference is the [TrueNAS Custom App documentation](https://www.truenas.com/docs/scale/apps/installcustomappscreens/). diff --git a/docs/python-dual-runtime.es.md b/docs/python-dual-runtime.es.md index 352f7c46..356be949 100644 --- a/docs/python-dual-runtime.es.md +++ b/docs/python-dual-runtime.es.md @@ -1,6 +1,6 @@ # Contrato de Python 3.14 / 3.15 en paralelo -Estado: **candidato en PR #273; no está fusionado ni desplegado**. Issue responsable: [#270](https://github.com/eXPerience83/remote-dev-containers/issues/270). La ampliación de herramientas universales sigue separada en [#121 PR2](https://github.com/eXPerience83/remote-dev-containers/issues/121); el problema anterior de actualizaciones de Python #257 se corrigió en PR #271. Este documento describe el comportamiento candidato y los requisitos de aceptación, no que TrueNAS ya lo esté ejecutando. +Estado: **PR #273 fusionada en main y distribuida en edge**. Issue [#270](https://github.com/eXPerience83/remote-dev-containers/issues/270), cerrado tras la aceptación de su excepción de tamaño y la CI. La ampliación universal [PR2 #281](https://github.com/eXPerience83/remote-dev-containers/pull/281) también está integrada y publicada como edge desde el 18/10/2026, pero su aceptación operativa en TrueNAS sigue pendiente. El incidente de actualizaciones #257 se corrigió en PR #271. Esta guía describe el contrato implementado; no confunde CI con sesiones reales de agentes. ## Versiones y selección @@ -40,22 +40,21 @@ La Action `Build AMD64` ejecuta `scripts/build-local.sh` y estos controles: | --- | --- | | Ambos Python exactos y 3.14 predeterminado | `scripts/smoke-test.sh` | | Selección 3.14/3.15 por proyecto en **Codex y Antigravity** | `scripts/test-mise-project-resolution.sh` | -| Dos venv `uv` sin red: versión exacta, paquetes aislados y Python global intacto | `scripts/test-mise-project-resolution.sh` (añadida a este PR; exige CI verde del último commit) | +| Dos venv `uv` sin red: versión exacta, paquetes aislados y Python global intacto | `scripts/test-mise-project-resolution.sh` (integrada; CI de la PR superada) | | Versión ausente, proyecto no confiable, sin instalación/fallback y almacén inmutable | `scripts/test-mise-project-resolution.sh` | | Separación de estados y montajes, credenciales, launcher y rootfs | `scripts/test-cross-service-isolation.sh` | | Lock: arquitecturas, backend, artefactos, procedencia y regeneración segura | `scripts/test-validate-mise-lock.py` y `scripts/test-regenerate-mise-lock.sh` | | Retrasos de propagación y errores inesperados | `scripts/test_preflight_python_upstream.py` | | Licencias y vulnerabilidades | `scripts/validate-third-party-inventory.sh`, `remote-dev-notices --check`, SBOM SPDX, Trivy y bloqueo de críticos corregibles | -CI demuestra ejecución AMD64 y metadatos de lock completos para AMD64/ARM64; **no** implica soporte de ejecución ARM64 (issue #112) ni sesiones reales autenticadas con los agentes. Antes de implantarlo sigue siendo necesaria la validación manual de TrueNAS: interfaz de ambos agentes, historial, selección de intérpretes y seguridad de contenedores. +CI demuestra ejecución AMD64 y metadatos de lock completos para AMD64/ARM64; **no** implica soporte de ejecución ARM64 (issue #112) ni sesiones reales autenticadas con los agentes. La aceptación operativa de cada nueva imagen sigue requiriendo comprobar en TrueNAS las interfaces de los agentes, sus historiales, la selección de intérprete y los límites del contenedor; la integración PR2 se valida por separado en #121. ## Tamaño y decisión de publicación Añadir el segundo intérprete tiene coste. Con los mismos pins de componentes, el build verde de `main` `b42f9c2` ([38548947867](https://github.com/eXPerience83/remote-dev-containers/actions/runs/38548947867)) ocupa **1.547.987.128 bytes** sin comprimir. El candidato `bba44c0` ([38633948930](https://github.com/eXPerience83/remote-dev-containers/actions/runs/38633948930)) ocupa **1.655.339.677 bytes**. Incremento: **107.352.549 bytes / 102.38 MiB**. La imagen base aumenta 107.351.674 bytes. Supera el umbral **blando** de revisión de 50 MiB de #121: disponer siempre del segundo Python es una decisión explícita de funcionalidad frente a tamaño. No afirmamos conocer el incremento exacto de descarga comprimida. -## Pendiente antes de aceptar +## Decisiones y seguimiento -- CI verde del último commit con el nuevo test de venv, revisión de CodeRabbit y resolución de sus observaciones. -- Coordinar [PR #272](https://github.com/eXPerience83/remote-dev-containers/pull/272), relativo a actualizaciones upstream, y repetir la CI tras cualquier fusión/rebase. No sobrescribir pins desde PR no relacionado. -- Revisar expresamente la excepción de +102.38 MiB, registrar las evidencias en #270/PR #273 y fusionar manualmente solo si todos los controles del commit final pasan. -- Mantener PR2 del #121 (Ruff, pytest, pre-commit, yq, shfmt y actionlint) y PR3 (demanda real de herramientas) como cambios independientes. +- PR #273 está fusionada, con CI de su revisión final validada y excepción de **+102,38 MiB** sin comprimir aceptada explícitamente por el propietario el 17/10/2026. No se interpreta como incremento de descarga comprimida. +- PR2 #281, con las seis herramientas universales, se fusionó y publicó en edge el 18/10/2026. La aceptación de esa imagen en el TrueNAS real sigue pendiente en [#121](https://github.com/eXPerience83/remote-dev-containers/issues/121). +- El estudio PR3 y los toolchains bajo demanda de #180 siguen siendo trabajo independiente. No introducir parámetros de arranque ni instalaciones pasivas para suplirlos. diff --git a/docs/python-dual-runtime.md b/docs/python-dual-runtime.md index 213f8697..82881368 100644 --- a/docs/python-dual-runtime.md +++ b/docs/python-dual-runtime.md @@ -1,6 +1,6 @@ # Dual Python 3.14 / 3.15 runtime contract -Status: **candidate in PR #273, not merged or deployed**. Owning issue: [#270](https://github.com/eXPerience83/remote-dev-containers/issues/270). The shared-image universal CLI expansion remains separate under [#121 PR2](https://github.com/eXPerience83/remote-dev-containers/issues/121); Python #257 was completed by PR #271. This document describes the candidate behavior and acceptance gates, not a claim that TrueNAS already runs it. +Status: **PR #273 is merged into main and shipped in experimental edge**. Owning issue [#270](https://github.com/eXPerience83/remote-dev-containers/issues/270) is closed following exact-head CI and owner acceptance of its image-size exception. Universal CLI [PR2 #281](https://github.com/eXPerience83/remote-dev-containers/pull/281) is also merged and published in edge as of 2026-10-18, with its real TrueNAS operational acceptance still pending. Python upstream issue #257 was addressed by PR #271. This document describes implemented behavior, not proof of authenticated real-agent sessions. ## Supported versions and selection @@ -40,22 +40,21 @@ The CI `Build AMD64` workflow runs `scripts/build-local.sh` and the following gu | --- | --- | | Both exact Python executables and 3.14 default | `scripts/smoke-test.sh` | | 3.14/3.15 project selection in **both Codex and Antigravity roles** | `scripts/test-mise-project-resolution.sh` | -| Offline `uv` venvs for both interpreters, exact versions, distinct site-packages, no global version change | `scripts/test-mise-project-resolution.sh` (added in this PR; requires its exact-head CI pass) | +| Offline `uv` venvs for both interpreters, exact versions, distinct site-packages, no global version change | `scripts/test-mise-project-resolution.sh` (merged; PR CI passed) | | Missing version, untrusted config, no fallback or implicit install, immutable tool store | `scripts/test-mise-project-resolution.sh` | | State/mount/rootfs isolation, role credentials and launcher separation | `scripts/test-cross-service-isolation.sh` | | Lock platform/backend/asset/provenance drift and safe regeneration | `scripts/test-validate-mise-lock.py`, `scripts/test-regenerate-mise-lock.sh` | | Patch propagation delays and unexpected failures | `scripts/test_preflight_python_upstream.py` | | Third-party notices and vulnerabilities | `scripts/validate-third-party-inventory.sh`, `remote-dev-notices --check`, SPDX SBOM, Trivy and no-fixable-CRITICAL gate | -CI proves AMD64 execution and complete AMD64/ARM64 lock **metadata**; it does **not** claim ARM64 runtime support (tracked separately by #112) or genuine authenticated vendor-agent sessions. A final rollout still requires manual TrueNAS validation (both agent browser sessions, histories, project selections and unchanged sandbox boundaries). +CI proves AMD64 execution and complete AMD64/ARM64 lock **metadata**; it does **not** claim ARM64 runtime support (tracked separately by #112) or genuine authenticated vendor-agent sessions. Each newly published image still requires appropriate TrueNAS operational validation (agent browser sessions, histories, project selections and security boundaries); PR2 acceptance is tracked separately under #121. ## Size and release decision The candidate with both versions has a measurable cost. At identical pinned component versions, the green `main` build at `b42f9c2` (run [38548947867](https://github.com/eXPerience83/remote-dev-containers/actions/runs/38548947867)) reports a final uncompressed image size of **1,547,987,128 bytes**. Candidate build at `bba44c0` (run [38633948930](https://github.com/eXPerience83/remote-dev-containers/actions/runs/38633948930)) reports **1,655,339,677 bytes**. Increment: **107,352,549 bytes / 102.38 MiB**. Base image grows by 107,351,674 bytes. This exceeds #121's 50 MiB **soft** review threshold: shipping an always-available second interpreter is an explicit functionality/size trade-off, not a free optimization. No exact compressed-pull delta is asserted. -## Still to accept +## Decisions and remaining follow-up -- Exact-head CI of the new offline dual-venv test must pass; CodeRabbit review (and all required feedback) must be completed. -- Resolve/coordinate open upstream update PR [#272](https://github.com/eXPerience83/remote-dev-containers/pull/272) and rerun CI after any merge/rebase. Do not overwrite upstream pins in an unrelated PR. -- Explicitly review the +102.38 MiB size exception, update acceptance evidence on #270/PR #273 and manually merge only after the exact final head passes all gates. -- Keep #121 PR2 (Ruff/pytest/pre-commit/yq/shfmt/actionlint) and PR3 demand study as separate reviewed changes. +- PR #273 has merged with exact-head CI validated and an explicit owner-accepted **+102.38 MiB** uncompressed image-size exception (2026-10-17). This is not a measured compressed-pull delta. +- PR2 #281 (six immutable validation CLIs) was merged and published in edge on 2026-10-18; live TrueNAS acceptance for that integrated image remains open under [#121](https://github.com/eXPerience83/remote-dev-containers/issues/121). +- PR3 agent-demand research and #180 persistent on-demand toolchains remain separate work. Neither should introduce extra startup parameters or passive downloads. diff --git a/docs/releases.es.md b/docs/releases.es.md index 8934c731..33a9bdef 100644 --- a/docs/releases.es.md +++ b/docs/releases.es.md @@ -120,7 +120,7 @@ Dos propietarios de automatización acotados pueden modificar subsecciones machi ### Actualizaciones upstream agrupadas -`.github/workflows/check-upstream.yml` es propietario de pines de runtime/herramientas agrupados como Codex CLI, GitHub CLI, ttyd, mise, uv y las líneas seleccionadas de Python/Node/npm. +`.github/workflows/check-upstream.yml` es propietario de pines de runtime/herramientas agrupados como Codex CLI, GitHub CLI, ttyd, mise, uv, las seis CLI de validación PR2 y las líneas seleccionadas de Python/Node/npm. Cuando cambian realmente versiones de componentes, el mismo PR de revisión actualiza el área acotada `### Automated upstream refreshes` utilizando los valores antiguos/nuevos del repositorio. El ruido exclusivo de checksums no inventa una falsa actualización de aplicación. Repetir la ejecución contra la misma base es determinista y la automatización nunca hace auto-merge. diff --git a/docs/releases.md b/docs/releases.md index a03688fc..e05b03cb 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -120,7 +120,7 @@ Two bounded automation owners may update machine-owned subsections under `Unrele ### Grouped upstream refreshes -`.github/workflows/check-upstream.yml` owns bundled/runtime/tool pins such as Codex CLI, GitHub CLI, ttyd, mise, uv and selected Python/Node/npm lines. +`.github/workflows/check-upstream.yml` owns bundled/runtime/tool pins such as Codex CLI, GitHub CLI, ttyd, mise, uv, six PR2 validation CLIs and selected Python/Node/npm lines. When actual component versions change, the same review PR updates the bounded `### Automated upstream refreshes` area using repository old/new values. Checksum-only churn does not invent a fake user-facing application-version change. Re-running against the same baseline is deterministic and the automation never auto-merges the PR. diff --git a/docs/roadmap.md b/docs/roadmap.md index 141d6ec0..f021822b 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -59,9 +59,9 @@ The detailed release/support tracker is issue #31. This document summarizes deli ## Current milestone — first stable release preparation -Remote Dev still has no stable release. The current work is to make the public/support surface match the implementation and then run the exact stable-release gates. +PR2 #281 (six locked pre-CI CLIs) was integrated and published to experimental edge on 2026-10-18; live TrueNAS acceptance is pending under #121. Remote Dev still has no stable release. The current work is to make the public/support surface match the implementation and then run the exact stable-release gates. -1. **#92 — documentation synchronization.** Align README EN/ES, project status, roadmap, architecture/security/tool/release guidance and changelog with the implemented stack and final experimental Antigravity wording. +1. **Operator documentation and PR2 acceptance.** Maintain the bilingual first-install/update runbooks and validate the integrated 53-command `edge` build on TrueNAS with the two enabled agent roles. 2. **#31 — tracker reconciliation.** Remove already completed gates from the pending lists and identify only blockers that genuinely remain for the support level claimed by the first stable release. 3. **Stable candidate validation.** Run the checklist in `docs/releases.md` on one exact `main` revision and immutable published digest, including image identity, TrueNAS deployment, agent authentication, persistence, isolation, notices/SBOM and vulnerability gates. 4. **Stable publication.** Only after the gates pass, create the dated changelog release section and exact `vMAJOR.MINOR.PATCH`; publish `stable` and `latest` as the same reviewed digest. @@ -85,7 +85,8 @@ These are not shipped by the current core contract unless their own issue says o - #95 — Context7 for Antigravity. - #71 — optional SMB access to selected project paths only. - #112 — ARM64. -- #121 — broader/universal developer tooling. +- #121 — PR1 and PR2 are integrated (53 baseline commands); live TrueNAS acceptance remains before closing the tracker. PR3 is a separate agent-demand survey. +- #180 — persistent on-demand project toolchains beyond the immutable baseline. - #148 — concurrent sessions/worktrees. - #151 — isolated container build/test tooling without a host Docker socket. - #97/#90/#91/#152/#87 — frontend/mobile/browser-experience work. diff --git a/docs/truenas-install.es.md b/docs/truenas-install.es.md new file mode 100644 index 00000000..c7396a6c --- /dev/null +++ b/docs/truenas-install.es.md @@ -0,0 +1,155 @@ +# TrueNAS SCALE: instalación, persistencia y actualización + +Esta guía describe el canal **edge experimental**; todavía no existe una release estable. La única definición de despliegue es [compose/truenas.yml](../compose/truenas.yml). Para pruebas más completas, consulta el [runbook TrueNAS](truenas-antigravity-validation.md) y el [contrato ACL](truenas-acl-contract.es.md). + +## 1. Dataset inicial y seguridad + +**Instalación nueva:** crea en la interfaz TrueNAS un dataset raíz, por ejemplo **Pool1/remote-dev**, montado en **/mnt/Pool1/remote-dev**, con preset **Generic / POSIX ACL**. Solo la raíz necesita ser un dataset ZFS. Los directorios hijos de trabajo y estado serán carpetas normales que crea el inicializador; no tienen por qué aparecer en la lista de datasets. Los datasets hijos creados deliberadamente por el administrador también están permitidos y no se modifican. + +**Instalación existente:** conserva el dataset y todos sus datos. Guarda el YAML actual sin contraseñas ni secretos y el digest inmutable de la imagen anterior antes de actualizar. Si usas el preset Apps/NFSv4, no apliques cambios recursivos de ACL, permisos o propietario: revisa la [auditoría y guía de migración](truenas-acl-contract.es.md). Un preflight de rutas correcto no demuestra que las ACL NFSv4 heredadas sean privadas. + +Los endpoints Codex/Antigravity protegen su acceso mediante WEB_PASSWORD en el YAML; no existe un árbol de ficheros de contraseña. El launcher sigue sin contraseña en la LAN privada. + +## 2. Obtener scripts de la revisión exacta de la imagen + +Ejecuta el siguiente bloque en el **shell Bash del host TrueNAS**, no dentro de un agente. Fija la imagen seleccionada por digest aunque tengas un checkout coincidente. Para instalaciones sin checkout descarga también el YAML Compose de esa revisión, no solo los scripts. + +~~~bash +set -euo pipefail +IMAGE=ghcr.io/experience83/remote-dev:edge-amd64 +ROOT=/mnt/Pool1/remote-dev + +sudo docker pull "$IMAGE" +IMAGE_REPO=ghcr.io/experience83/remote-dev +PINNED_IMAGE="" +while IFS= read -r repo_digest; do + case "$repo_digest" in + "$IMAGE_REPO"@sha256:*) PINNED_IMAGE="$repo_digest"; break ;; + esac +done < <(sudo docker image inspect "$IMAGE" \ + --format '{{range .RepoDigests}}{{println .}}{{end}}') +[[ "$PINNED_IMAGE" =~ ^ghcr\.io/experience83/remote-dev@sha256:[0-9a-f]{64}$ ]] || { + echo 'Falta el digest del registro: no despliegues una etiqueta mutable' >&2 + exit 1 +} +REV="$(sudo docker image inspect "$PINNED_IMAGE" \ + --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}')" +[[ "$REV" =~ ^[0-9a-f]{40}$ ]] || { echo 'Revisión de origen inválida' >&2; exit 1; } + +SETUP="$(mktemp -d /tmp/remote-dev-setup.XXXXXXXX)" +mkdir -p "$SETUP/scripts/lib" "$SETUP/compose" +for path in \ + scripts/init-data-layout.py \ + scripts/preflight-data-layout.py \ + scripts/truenas-acl-audit.py \ + scripts/lib/data_layout.py \ + compose/truenas.yml; do + curl -fsSL --retry 2 \ + "https://raw.githubusercontent.com/eXPerience83/remote-dev-containers/$REV/$path" \ + -o "$SETUP/$path" +done +echo "Revisión de origen: $REV" +echo "Imagen inmutable: $PINNED_IMAGE" +echo "Ficheros de la misma revisión: $SETUP" +~~~ + +Los scripts **y la plantilla Compose original** se descargan por HTTPS del commit inmutable obtenido de la imagen **fijada por digest**. Mantén abierta la misma sesión Bash (`SETUP`, `REV` y `PINNED_IMAGE`) e inspecciona los scripts antes de ejecutarlos como administrador. + +## 3. Crear directamente los directorios persistentes + +Comprueba que ROOT **existe y coincide con el dataset correcto**. El inicializador no crea la raíz ni ningún dataset ZFS; rechaza symlinks y componentes no directorio, es idempotente y no borra, migra o cambia recursivamente contenido o permisos existentes. + +Para el YAML de referencia (Codex y Antigravity opcional): + +~~~bash +sudo python3 -B "$SETUP/scripts/init-data-layout.py" --root "$ROOT" --include-antigravity +sudo python3 -B "$SETUP/scripts/preflight-data-layout.py" --root "$ROOT" --include-antigravity +sudo python3 -B "$SETUP/scripts/truenas-acl-audit.py" --root "$ROOT" --include-antigravity +~~~ + +Si estás dentro de un checkout exactamente coincidente, los comandos equivalentes son: + +~~~bash +sudo python3 -B scripts/init-data-layout.py --root /mnt/Pool1/remote-dev --include-antigravity +sudo python3 -B scripts/preflight-data-layout.py --root /mnt/Pool1/remote-dev --include-antigravity +sudo python3 -B scripts/truenas-acl-audit.py --root /mnt/Pool1/remote-dev --include-antigravity +~~~ + +Quita **--include-antigravity** solamente si eliminaste de verdad ese servicio y sus bind mounts del YAML. El archivo [scripts/lib/data_layout.py](../scripts/lib/data_layout.py) define el conjunto canónico de rutas: + +~~~text +/mnt/Pool1/remote-dev/ + workspaces/codex/ + workspaces/antigravity/ + state/codex/{agent,runtime,mise,gh,git,ssh}/ + state/antigravity/{bin,runtime,vendor,config,mise,gh,git,ssh}/ +~~~ + +Los nuevos workspaces se crean con modo 0755 y las hojas privadas de estado con modo 0700; los padres estructurales reciben 0755. **Las rutas preexistentes no se reescriben** (incluidos datasets hijos). No realices chmod/chown recursivo ni montes la raíz entera en un agente. Preflight valida rutas y la auditoría ACL es de solo lectura. Ninguno de estos comandos crea contraseñas o credenciales. + +## 4. Configura el YAML y despliega + +Usa **`$SETUP/compose/truenas.yml`**, descargado del mismo `REV` que la imagen y los scripts. Genera una copia distinta fijada por digest, sin modificar la plantilla original: + +~~~bash +SOURCE_COMPOSE="$SETUP/compose/truenas.yml" +PINNED_COMPOSE="$SETUP/truenas-pinned.yml" +[[ -f "$SOURCE_COMPOSE" ]] || { echo 'Falta el YAML Compose de origen' >&2; exit 1; } +[[ "$(head -n 1 "$SOURCE_COMPOSE")" == 'x-remote-dev-image: &remote-dev-image '* ]] || { + echo 'Ancla de imagen Compose inesperada; inspecciona la plantilla' >&2 + exit 1 +} +{ + printf 'x-remote-dev-image: &remote-dev-image %s\n' "$PINNED_IMAGE" + tail -n +2 "$SOURCE_COMPOSE" +} > "$PINNED_COMPOSE" +echo "Edita y pega este YAML fijado para Custom App: $PINNED_COMPOSE" +~~~ + +Utiliza **`PINNED_COMPOSE`** en el editor Custom App, no la plantilla con el tag mutable. El bloque sustituye el **ancla compartida** `x-remote-dev-image` para que launcher, Codex y Antigravity opcional usen la misma referencia inmutable `ghcr.io/experience83/remote-dev@sha256:…`. Antes de guardar: + +- Cambia la IP bind de ejemplo 192.168.1.10 a tu IP LAN/Tailscale. +- Cambia cada bind source /mnt/Pool1/remote-dev si tu dataset está en otra ruta. +- Configura WEB_PASSWORD para Codex y Antigravity habilitado (valor no vacío, una línea). Pueden coincidir bajo el contrato actual. +- Verifica que todos los servicios habilitados usan **el mismo ancla de imagen fijada por digest**; comprueba el YAML guardado porque TrueNAS puede reescribir interpolaciones y comentarios. +- Conserva raíz de solo lectura, montajes/capacidades estrechos y puertos 7680/7681/7682 solo en red privada. No añadas el socket Docker. + +Un administrador puede leer el YAML, incluidos secretos configurados. Sanea capturas/exportaciones. + +## 5. Aceptación de PR2 después de actualizar + +Cuando la App use el nuevo edge sin haber borrado estado: + +~~~bash +set -euo pipefail +CHECK_ANTIGRAVITY=0 # Pon 1 si el servicio opcional está desplegado +containers=(codex-remote-dev) +if [[ "$CHECK_ANTIGRAVITY" == "1" ]]; then + containers+=(antigravity-remote-dev) +fi +for container in "${containers[@]}"; do + sudo docker exec "$container" remote-dev-version --check + sudo docker exec "$container" remote-dev-base-verify + [[ "$(sudo docker exec "$container" stat -c '%u:%g %a' /usr/share/doc/remote-dev)" == '0:0 755' ]] || { + echo "ERROR: $container has an unsafe or unreadable notice directory" >&2 + exit 1 + } + sudo docker exec "$container" remote-dev-notices --check + sudo docker exec "$container" /bin/bash -c \ + 'set -euo pipefail; cd / && for tool in ruff pytest pre-commit yq shfmt actionlint; do "$tool" --version; done' +done +~~~ + +En la imagen posterior a #285, el directorio de avisos debe ser `root:root 0755` y `remote-dev-notices --check` debe pasar **sin añadir `DAC_READ_SEARCH`, `DAC_OVERRIDE` ni otras capacidades**. Si falla, revisa el digest de imagen desplegado; no relajes `cap_drop: [ALL]` ni cambies ACL del host para ocultar el defecto. + +El bloque comprueba **solo Codex** por defecto. Pon `CHECK_ANTIGRAVITY=1` **cuando Antigravity esté habilitado**, para no omitir silenciosamente sus comprobaciones. Base Verify comprueba **53 comandos** desde un CWD neutral; el bucle demuestra que las seis CLI nuevas resuelven directamente. CI ya probó operaciones reales de las seis bajo ambos roles, pero no sustituye sesiones autenticadas. + +Abre el launcher en **http://IP-PRIVADA-TRUENAS:7680**, accede a Codex y Antigravity habilitado y **comprueba que las conversaciones anteriores se pueden retomar**. Comprueba que Python 3.14 sigue siendo predeterminado y que 3.15 solo se selecciona por un proyecto compatible sin cambiar los proyectos reales para probar. Revisa Doctor, montajes privados y aislamiento sin copiar secretos a los informes. + +Registra SHA, digest, resultados y errores saneados en [#121](https://github.com/eXPerience83/remote-dev-containers/issues/121). No cierres la aceptación de PR2 antes de estas pruebas reales. + +## 6. Actualización, rollback y limpieza + +Para actualizar, anota el digest anterior, comprueba los workflows edge verdes, haz pull del nuevo edge, registra su **RepoDigest** y `REV`, descarga su YAML de Compose correspondiente, vuelve a generar la copia fijada por digest como en la sección 4 y recrea los contenedores conservando sus bind mounts y ajustes específicos del host. Verifica después el SHA/digest efectivo y las sesiones. Para revertir, restaura el digest anterior **sin borrar los datos persistentes**; revertir datos requiere otro plan. + +Puedes borrar solo la carpeta temporal SETUP cuando ya no necesites los scripts. Nunca borres ROOT ni credenciales para reinstalar. El tag edge es mutable; **latest** está reservado para stable y no debe usarse aquí. diff --git a/docs/truenas-install.md b/docs/truenas-install.md new file mode 100644 index 00000000..b799afe7 --- /dev/null +++ b/docs/truenas-install.md @@ -0,0 +1,155 @@ +# TrueNAS SCALE: installation, persistence, and upgrades + +This guide describes the **experimental edge** channel; no stable release exists yet. The canonical stack definition is [compose/truenas.yml](../compose/truenas.yml). See the [advanced TrueNAS runbook](truenas-antigravity-validation.md) and [host ACL contract](truenas-acl-contract.md) for deeper validation. + +## 1. Root dataset and safety + +**New installation:** create one administrator-owned root dataset in the TrueNAS UI, e.g. **Pool1/remote-dev**, mounted at **/mnt/Pool1/remote-dev**, using the **Generic / POSIX ACL** preset. Only this root normally needs to be a ZFS dataset. The child workspace/state paths will be ordinary directories generated by bootstrap, not additional entries in the ZFS datasets view. Deliberately created child datasets are supported and never rewritten. + +**Existing installation:** preserve the root and its data. Record the old immutable image digest and save a **sanitized** current Custom App YAML before changing anything. If the root uses the Apps/NFSv4 preset, do not recursively change ACLs, modes or ownership: see the [ACL audit/migration guide](truenas-acl-contract.md). Passing a path preflight does not prove inherited NFSv4 permissions are private. + +Protected agent endpoints use WEB_PASSWORD in App configuration; no password-secret directory is created. The launcher remains password-free and must be exposed only on a trusted LAN/private mesh. + +## 2. Obtain host scripts matching the exact image revision + +Run the following in a **TrueNAS host Bash shell**, not inside an agent. Always pin the selected image by digest, even when you already have a matching checkout. The no-checkout path also downloads the revision-matched Compose YAML, not only the scripts. + +~~~bash +set -euo pipefail +IMAGE=ghcr.io/experience83/remote-dev:edge-amd64 +ROOT=/mnt/Pool1/remote-dev + +sudo docker pull "$IMAGE" +IMAGE_REPO=ghcr.io/experience83/remote-dev +PINNED_IMAGE="" +while IFS= read -r repo_digest; do + case "$repo_digest" in + "$IMAGE_REPO"@sha256:*) PINNED_IMAGE="$repo_digest"; break ;; + esac +done < <(sudo docker image inspect "$IMAGE" \ + --format '{{range .RepoDigests}}{{println .}}{{end}}') +[[ "$PINNED_IMAGE" =~ ^ghcr\.io/experience83/remote-dev@sha256:[0-9a-f]{64}$ ]] || { + echo 'Missing or invalid registry digest: do not deploy a mutable tag' >&2 + exit 1 +} +REV="$(sudo docker image inspect "$PINNED_IMAGE" \ + --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}')" +[[ "$REV" =~ ^[0-9a-f]{40}$ ]] || { echo 'Invalid source revision' >&2; exit 1; } + +SETUP="$(mktemp -d /tmp/remote-dev-setup.XXXXXXXX)" +mkdir -p "$SETUP/scripts/lib" "$SETUP/compose" +for path in \ + scripts/init-data-layout.py \ + scripts/preflight-data-layout.py \ + scripts/truenas-acl-audit.py \ + scripts/lib/data_layout.py \ + compose/truenas.yml; do + curl -fsSL --retry 2 \ + "https://raw.githubusercontent.com/eXPerience83/remote-dev-containers/$REV/$path" \ + -o "$SETUP/$path" +done +echo "Source revision: $REV" +echo "Immutable image: $PINNED_IMAGE" +echo "Revision-matched files: $SETUP" +~~~ + +Scripts **and the original Compose template** are fetched over HTTPS from the immutable source revision read from the **digest-pinned** image, not a floating branch. Keep this same Bash shell session open (it holds `SETUP`, `REV`, and `PINNED_IMAGE`). Inspect scripts before running them with administrator privileges. + +## 3. Directly create persistent directories + +Confirm ROOT **already exists and is the correct dataset**. Bootstrap does not create ROOT or ZFS datasets; it rejects symlinks and non-directory components, is idempotent, and never deletes or recursively rewrites existing permissions or contents. + +For the reference YAML with Codex and optional Antigravity: + +~~~bash +sudo python3 -B "$SETUP/scripts/init-data-layout.py" --root "$ROOT" --include-antigravity +sudo python3 -B "$SETUP/scripts/preflight-data-layout.py" --root "$ROOT" --include-antigravity +sudo python3 -B "$SETUP/scripts/truenas-acl-audit.py" --root "$ROOT" --include-antigravity +~~~ + +If you already have an exactly matching checkout, instead run: + +~~~bash +sudo python3 -B scripts/init-data-layout.py --root /mnt/Pool1/remote-dev --include-antigravity +sudo python3 -B scripts/preflight-data-layout.py --root /mnt/Pool1/remote-dev --include-antigravity +sudo python3 -B scripts/truenas-acl-audit.py --root /mnt/Pool1/remote-dev --include-antigravity +~~~ + +Omit **--include-antigravity** throughout only after removing the Antigravity service and bind mounts from your customized YAML. [scripts/lib/data_layout.py](../scripts/lib/data_layout.py) is the single authoritative source of required directories: + +~~~text +/mnt/Pool1/remote-dev/ + workspaces/codex/ + workspaces/antigravity/ + state/codex/{agent,runtime,mise,gh,git,ssh}/ + state/antigravity/{bin,runtime,vendor,config,mise,gh,git,ssh}/ +~~~ + +New workspaces use mode 0755; private state leaf directories use 0700, and structural parents use 0755. Existing paths (including any child datasets) are never rewritten. Do not recursively chmod/chown the tree or mount the parent data root in an agent. Preflight verifies paths; the read-only host ACL audit separately checks the Generic/POSIX privacy contract. None of these scripts creates passwords or credentials. + +## 4. Configure YAML and deploy + +Use **`$SETUP/compose/truenas.yml`** downloaded from the same `REV` as the image and scripts. Generate a separate digest-pinned copy, leaving the source template unchanged: + +~~~bash +SOURCE_COMPOSE="$SETUP/compose/truenas.yml" +PINNED_COMPOSE="$SETUP/truenas-pinned.yml" +[[ -f "$SOURCE_COMPOSE" ]] || { echo 'Missing source Compose file' >&2; exit 1; } +[[ "$(head -n 1 "$SOURCE_COMPOSE")" == 'x-remote-dev-image: &remote-dev-image '* ]] || { + echo 'Unexpected Compose image anchor; inspect the source template' >&2 + exit 1 +} +{ + printf 'x-remote-dev-image: &remote-dev-image %s\n' "$PINNED_IMAGE" + tail -n +2 "$SOURCE_COMPOSE" +} > "$PINNED_COMPOSE" +echo "Edit and paste this pinned Custom App YAML: $PINNED_COMPOSE" +~~~ + +Use **`PINNED_COMPOSE`** in the Custom App editor, not the mutable-tag template. This replaces the **single shared** `x-remote-dev-image` anchor so launcher, Codex, and optional Antigravity all use the same immutable `ghcr.io/experience83/remote-dev@sha256:…` reference. Before saving the Custom App: + +- Replace example bind IP 192.168.1.10 with the intended LAN/Tailscale IP. +- Change every /mnt/Pool1/remote-dev bind source if ROOT differs. +- Set non-empty, single-line WEB_PASSWORD values for Codex and enabled Antigravity. Reuse is currently permitted. +- Confirm that all enabled services use **the same digest-pinned image anchor**; inspect the saved YAML again because TrueNAS may rewrite Compose interpolation and comments. +- Preserve read-only container roots, narrow mounts/capabilities, and ports 7680/7681/7682 on trusted networks only. Do not mount a Docker socket. + +Host administrators can read the configured passwords. Sanitize YAML exports and screenshots. + +## 5. Accept PR2 on the running stack + +After updating without deleting persistent paths: + +~~~bash +set -euo pipefail +CHECK_ANTIGRAVITY=0 # Change to 1 when the optional service is deployed +containers=(codex-remote-dev) +if [[ "$CHECK_ANTIGRAVITY" == "1" ]]; then + containers+=(antigravity-remote-dev) +fi +for container in "${containers[@]}"; do + sudo docker exec "$container" remote-dev-version --check + sudo docker exec "$container" remote-dev-base-verify + [[ "$(sudo docker exec "$container" stat -c '%u:%g %a' /usr/share/doc/remote-dev)" == '0:0 755' ]] || { + echo "ERROR: $container has an unsafe or unreadable notice directory" >&2 + exit 1 + } + sudo docker exec "$container" remote-dev-notices --check + sudo docker exec "$container" /bin/bash -c \ + 'set -euo pipefail; cd / && for tool in ruff pytest pre-commit yq shfmt actionlint; do "$tool" --version; done' +done +~~~ + +In the image containing #285, the notices directory must be `root:root 0755` and `remote-dev-notices --check` must pass **without adding `DAC_READ_SEARCH`, `DAC_OVERRIDE` or other capabilities**. If it fails, recheck the deployed image digest; do not relax `cap_drop: [ALL]` or alter host ACLs to mask the problem. + +This defaults to **Codex-only**. Set `CHECK_ANTIGRAVITY=1` **when Antigravity is enabled** so its checks are not silently omitted. Base Verify checks the **53-command** canonical inventory from a neutral directory; the loop resolves the six new CLIs directly. CI already exercises the actual tools under both hardened role fixtures, but authenticated live-agent acceptance remains separate. + +Open the launcher at **http://PRIVATE-TRUENAS-IP:7680**, enter enabled agent terminals and **confirm old sessions resume**. Python 3.14 should remain the default; Python 3.15 is selected only in explicitly compatible projects. Do not mutate real project config just to prove a version. Check Doctor, private mounts and isolation without disclosing secrets. + +Record only sanitized SHA/digest and outcomes or errors in [#121](https://github.com/eXPerience83/remote-dev-containers/issues/121). Keep that issue open until genuine host acceptance. + +## 6. Upgrade, rollback and cleanup + +For upgrades, save old image digest and sanitized YAML, verify green edge workflows, pull the new edge, record the new **RepoDigest** and source `REV`, download its matched Compose template, regenerate the digest-pinned copy as in section 4 and recreate with identical bind mounts and previously documented host-specific settings. Verify effective SHA/digest and session persistence. For rollback, restore the old image digest **without deleting persistent state**; rolling back data needs a separate plan. + +Remove only the temporary SETUP helper directory when finished, never ROOT or credentials. Edge tags are mutable; **latest** is reserved for stable, not experimental edge. diff --git a/docs/universal-validation-tools.es.md b/docs/universal-validation-tools.es.md index 7c748b1a..c7420b23 100644 --- a/docs/universal-validation-tools.es.md +++ b/docs/universal-validation-tools.es.md @@ -1,6 +1,6 @@ # Herramientas de validación local PR2 (#121) -El candidato añade exactamente seis comandos a PR1 (47 → 53): Ruff **0.17.1**, pytest **9.1.1**, pre-commit **4.7.0**, yq de Mike Farah **4.54.1**, shfmt **3.14.1** y actionlint **1.7.12**. Las versiones estables y sus artefactos oficiales se consultaron de nuevo el 18/10/2026. La aceptación sigue pendiente; no implica una versión estable ni soporte ARM64. +PR2 #281 está **fusionada y publicada en edge AMD64** desde el 18/10/2026. Añade exactamente seis comandos a PR1 (47 → 53): Ruff **0.17.1**, pytest **9.1.1**, pre-commit **4.7.0**, yq de Mike Farah **4.54.1**, shfmt **3.14.1** y actionlint **1.7.12**. La validación real en TrueNAS sigue pendiente bajo #121. Publicar edge no equivale a una versión estable ni a soporte de ejecución ARM64. ## Instalación y precedencia del proyecto @@ -14,14 +14,14 @@ Arranque, health checks y Doctor no instalan ni descargan herramientas. Base Ver `scripts/regenerate-mise-lock.sh` exige el mise fijado y uv exacto (`UV_BIN`), aísla estado y valida los grafos antes de publicar el lock. Conserva directorios anteriores para no romper el lock previo ante un fallo. Los grafos acompañan a ambos nombres del lock dentro de la imagen. El actualizador upstream mantiene las seis líneas estables, el resolver verificado, grafos, inventario y licencias mediante una PR revisada sin fusión automática. -`scripts/sync-python-cli-notices.py --write` descarga ruedas oficiales verificadas con los hashes comprometidos y conserva sus licencias/notices reales, incluidas las ruedas de semillas redistribuidas en virtualenv. La comprobación sin red vincula evidencia y artefactos. El inventario incluye conservadoramente todos los paquetes del grafo, incluido colorama condicional, sin afirmar que todos se instalen en Linux. Siguen siendo obligatorios SPDX, Trivy y el bloqueo de CRITICAL corregibles. La evidencia complementa las limitaciones de detección del escáner; la revisión humana #53 sigue pendiente. +`scripts/sync-python-cli-notices.py --write` descarga ruedas oficiales verificadas con los hashes comprometidos y conserva sus licencias/notices reales, incluidas las ruedas de semillas redistribuidas en virtualenv. La comprobación sin red vincula evidencia y artefactos. El inventario incluye conservadoramente todos los paquetes del grafo, incluido colorama condicional, sin afirmar que todos se instalen en Linux. Siguen siendo obligatorios SPDX, Trivy y el bloqueo de CRITICAL corregibles. La evidencia complementa las limitaciones de detección del escáner; la aceptación específica de distribución/licencias de PR2 fue registrada por el propietario en #53 el 18/10/2026; #53 sigue abierto para auditorías periódicas y cambios futuros. ## Validación y evidencias `test-validation-tools.sh` prueba los seis comandos sin red en contenedores de solo lectura y sin capacidades, para fixtures Codex y Antigravity, desde CWD neutro y proyecto Python 3.15. Comprueba lint/formato Ruff, tests pytest reales y su intérprete aislado 3.14, hooks locales pre-commit, transformación yq, formato shfmt, workflows válidos/inválidos, site-packages globales limpios, venv explícito del proyecto y estabilidad del almacén inmutable. Las pruebas mise añaden ausencia de versión y ausencia de fallback para yq. Los fixtures prueban el entorno de procesos; no sustituyen tareas de modelos autenticados ni aceptación externa en TrueNAS. -La generación local con mise y uv fijados ha terminado para ambas arquitecturas. Pasan también las pruebas funcionales de los payloads en entornos uv privados y congelados; ambos Python globales permanecen limpios. La reproducción local con estado de instalación heredado devolvió `No lockfile URL found for python@3.14.8`; **la instalación bloqueada de Docker limpio y todas las pruebas de imagen/runtime pasaron después en CI para `6108761`**, incluidos ambos roles endurecidos y la selección de proyecto Python 3.15. El fixture local no demuestra un defecto de mise en una imagen limpia. No se desactivó ninguna garantía de bloqueo o aislamiento. +La generación bloqueada con mise y uv fijados cubre AMD64 y ARM64, aunque solo AMD64 tiene ejecución runtime soportada. **La CI definitiva de PR2** superó instalación Docker limpia, funcionamiento de las seis CLI, selección de Python 3.15, separación de roles y conservación del almacén inmutable. El incidente de estado heredado en la prueba local no se reprodujo en CI y no motivó ninguna relajación de seguridad. -La sesión carece de Docker CLI/backend. La ejecución endurecida, tamaños exactos antes/después, SPDX y Trivy deben verificarse en GitHub CI; no se atribuyen resultados locales inexistentes. Sigue pendiente revisar el umbral orientativo de 50 MiB sin comprimir. No se modifica TrueNAS, no se publica una versión estable y no se fusiona esta PR. +El HEAD exacto `d242caa7cab77b08d115c6bc6b77d7e25440622b` superó [CI de PR](https://github.com/eXPerience83/remote-dev-containers/actions/runs/39159352751), una ejecución manual sin opciones y la revisión incremental de CodeRabbit. La fusión squash en main es `5a56c3006135d41c913bb09a7f3be37d35c2c4df`; [Build AMD64](https://github.com/eXPerience83/remote-dev-containers/actions/runs/39161916570) y [Publish edge AMD64](https://github.com/eXPerience83/remote-dev-containers/actions/runs/39161916543) terminaron correctamente, con Trivy 0 CRITICAL. El aumento sin comprimir **+70,41 MiB base / +68,06 MiB final** supera el umbral blando de 50 MiB y fue aceptado explícitamente por el propietario junto con la distribución/licencias (#53). No se ha medido el tamaño de descarga comprimida. La comparación exhaustiva de imágenes solo se activa manualmente con `compare_images=true`; la CI normal mantiene sus gates. No hay release estable. **Queda por validar PR2 en el TrueNAS real**; sigue abierto #121. Los bytes de licencias se agrupan por paquete en `NOTICES.txt` con nombres exactos de rueda/miembro, para facilitar la revisión sin excluir evidencia. La inspección standalone incluye los seis artefactos Aqua nuevos AMD64/ARM64 y conserva la evidencia previa. diff --git a/docs/universal-validation-tools.md b/docs/universal-validation-tools.md index 98d5d15d..38c2baec 100644 --- a/docs/universal-validation-tools.md +++ b/docs/universal-validation-tools.md @@ -1,6 +1,6 @@ # PR2 local validation tools (#121) -This candidate adds exactly six commands to the accepted PR1 baseline (47 → 53): Ruff **0.17.1**, pytest **9.1.1**, pre-commit **4.7.0**, Mike Farah yq **4.54.1**, shfmt **3.14.1**, actionlint **1.7.12**. Official stable release metadata and assets were rechecked on 2026-10-18. This is a candidate, pending final review and acceptance; it is not a stable release or an ARM64 support claim. +PR2 #281 was **squash-merged and published in experimental edge AMD64** on 2026-10-18. It adds exactly six commands to the accepted PR1 baseline (47 → 53): Ruff **0.17.1**, pytest **9.1.1**, pre-commit **4.7.0**, Mike Farah yq **4.54.1**, shfmt **3.14.1**, actionlint **1.7.12**. Live TrueNAS acceptance remains pending under #121. Edge publication is not a stable release or an ARM64 runtime support claim. ## Installation and project precedence @@ -14,14 +14,14 @@ Startup, health checks and Doctor do not install or download tools. Base Verify Use the pinned mise from `versions.env` and the exact pinned uv (`UV_BIN`) with `scripts/regenerate-mise-lock.sh`. It isolates mise state and validates graphs before publishing the referencing lock; old graph directories remain usable if replacement fails. Native graphs must travel with both image lockfile names. The upstream workflow owns all six stable release lines, exact resolver bootstrap, sidecars, inventory and license refreshes in one review PR; it does not auto-merge. -`scripts/sync-python-cli-notices.py --write` retrieves only hash-verified official wheels from the committed graphs and preserves their actual license/notice files, including virtualenv's embedded seed wheels. Its offline check binds the preserved evidence to exact graph artifacts. All graph packages (including platform-conditional colorama) are represented conservatively in the inventory; this does not assert every conditional package is installed on Linux. Existing image SPDX SBOM and Trivy/no-fixable-critical gates remain mandatory. Repository evidence complements scanner coverage rather than claiming perfect discovery of embedded bytes. #53 human legal review remains required. +`scripts/sync-python-cli-notices.py --write` retrieves only hash-verified official wheels from the committed graphs and preserves their actual license/notice files, including virtualenv's embedded seed wheels. Its offline check binds the preserved evidence to exact graph artifacts. All graph packages (including platform-conditional colorama) are represented conservatively in the inventory; this does not assert every conditional package is installed on Linux. Existing image SPDX SBOM and Trivy/no-fixable-critical gates remain mandatory. Repository evidence complements scanner coverage rather than claiming perfect discovery of embedded bytes. The targeted owner review/acceptance of PR2 distribution and preserved license notices was logged under #53 on 2026-10-18; #53 stays open for periodic review and future changes. ## Validation and evidence `test-validation-tools.sh` exercises all six commands offline in read-only, networkless, capability-free containers for both Codex and Antigravity role fixtures, from neutral and Python-3.15 project CWDs. It checks Ruff rejection/formatting, real pytest tests and its isolated 3.14 interpreter, local pre-commit hooks, yq transformation, shfmt formatting, valid/invalid Actions workflows, both clean global Python site-packages, explicit project venv selection and immutable store stability. Existing mise tests add yq missing-version/no-fallback coverage. Role fixtures prove process environment behavior, not real authenticated model task success; live agent/TrueNAS acceptance stays external. -Local generation with the verified pinned mise and uv succeeded for both architectures. Actual payload functional tests also pass in private frozen uv environments, with both global Python site-packages clean. Local replay against inherited installation state reported `No lockfile URL found for python@3.14.8`; **clean Docker CI at `6108761` subsequently passed locked installation and all image/runtime smokes**, including both hardened role fixtures and Python 3.15 project selection. The local inherited-state fixture is not evidence of a clean-image mise defect. No locking or interpreter-isolation safeguard was disabled. +Locked mise/uv graphs cover AMD64 and ARM64, although only AMD64 runtime execution is currently supported. **Final PR2 CI** passed a clean Docker installation, real offline use of all six CLIs, project Python 3.15 selection, hardened role isolation and immutable-store checks. The inherited-state failure observed in one local replay was not reproduced by clean CI, and no security invariant was relaxed. -This session has no Docker CLI/backend. Hardened image execution, exact before/after image sizes, SPDX generation and Trivy are assessed from GitHub CI. No local image, SBOM, scan or size result is claimed. The issue's 50 MiB uncompressed soft threshold still requires review of the measured delta. No deployment, stable publication or merge is authorized by this candidate. +The exact PR head `d242caa7cab77b08d115c6bc6b77d7e25440622b` passed [PR CI](https://github.com/eXPerience83/remote-dev-containers/actions/runs/39159352751), default manual CI and final incremental CodeRabbit review. Squash merge to main is `5a56c3006135d41c913bb09a7f3be37d35c2c4df`; [Build AMD64](https://github.com/eXPerience83/remote-dev-containers/actions/runs/39161916570) and [Publish edge AMD64](https://github.com/eXPerience83/remote-dev-containers/actions/runs/39161916543) succeeded with Trivy 0 CRITICAL. The measured uncompressed increase **+70.41 MiB base / +68.06 MiB final** exceeds the 50 MiB soft review threshold and was explicitly accepted by the owner alongside the targeted distribution/license review under #53. Compressed pull-size delta was not measured. Extraordinary reference-image comparisons are manual-only through `compare_images=true`; normal CI retains all required gates. There is no stable release. **Live TrueNAS PR2 acceptance remains outstanding** under #121. License bytes are consolidated per package into labeled `NOTICES.txt` files (including exact wheel/member names), so generated evidence remains reviewable without excluding it from code review. Standalone inspection also covers all six new AMD64/ARM64 Aqua assets; existing standalone evidence is preserved.