49d3e113ee07fabd50711d467c3027e11ad40c8b
4 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
668592da0d |
Base: SSH ControlMaster default on a writable socket path
Validate / docs-check (push) Successful in 9s
Validate / base-change-warning (push) Successful in 11s
Validate / validate-with-pi (push) Failing after 4m6s
Validate / validate-omos (push) Failing after 4m31s
Validate / validate-omos-with-pi (push) Failing after 4m52s
Validate / validate-base (push) Failing after 13m20s
Devboxes typically mount ~/.ssh from the host read-only (security: keys
readable, but agents can't tamper with config / known_hosts /
authorized_keys / plant a malicious ProxyCommand). OpenSSH's default
ControlPath is ~/.ssh/cm/... which is unwritable on such mounts, so
any attempt to multiplex fails with:
unix_listener: cannot bind to path .../cm/...: Read-only file system
kex_exchange_identification: Connection closed by remote host
The second line is downstream — when ControlMaster fails, ssh falls
back to fresh TCP connections, and on residential CGNAT (most European
ISPs) the per-(src,dst) concurrent-flow cap (~4) silently drops further
SYNs once exceeded, manifesting as banner-exchange timeouts that look
like a remote problem.
Fix: bake /etc/ssh/ssh_config.d/00-devbox-controlmaster.conf in the
base image with Host * defaults — ControlPath rooted at /tmp/sshcm/
(per-container, always writable), ControlMaster auto, ControlPersist
10m, ServerAlive{Interval=30,CountMax=6}. Companion entrypoint-user.sh
creates /tmp/sshcm mode 700 on each container start (/tmp is
per-container so the dir can't be baked into a layer; mode 700 is
required by OpenSSH for ControlPath dirs). Debian's stock ssh_config
sources ssh_config.d/*.conf before its own Host * block, so user
~/.ssh/config overrides still win.
Two smoke assertions catch regressions: (a) the conf file exists, (b)
ssh -G reports a controlpath rooted at /tmp/sshcm/ — second one catches
the silent case where something later in the config chain shadows the
bake-in.
Discovered while running a recon shell from inside pi-devbox to a
Proxmox node — fresh ssh hit banner-exchange timeout, debug output
pointed at the read-only socket dir as the actual root cause.
Cascades to all variants and to pi-devbox automatically on next build
against base-latest. No size/threshold impact (~250-byte conf file).
|
||
|
|
73a7f96056 |
Base: add gitleaks; surface git-crypt in smoke + docs
Both tools are used as part of the secret-management setup in several of the repos this devbox operates on (gitleaks pre-commit hook + git-crypt for selectively-encrypted canonical config). Having them in the container means hooks fire correctly inside instead of warning 'gitleaks not installed' on every commit. git-crypt was already installed via apt in Dockerfile.base (line 58), just unasserted by smoke and unmentioned in user-facing docs. gitleaks is new: Go-compiled binary fetched from GitHub releases via the same /releases/latest redirect-resolution pattern as gosu, fzf, git-lfs, etc. Arch suffix is 'x64' (not 'x86_64' / 'amd64') on this project — flagged in the Dockerfile comment and in AGENTS.md's floated-binaries gotcha list. Adds ~21 MB to the base layer (gitleaks 8.30.1 binary). No variant threshold bumps needed (2500–3700 MB envelope, 21 MB is noise). CHANGES Dockerfile.base — new GITLEAKS_VERSION=latest ARG + install RUN right after the git-lfs block. Multi-arch (linux/amd64=x64, linux/arm64=arm64). Echoes resolved version + runs 'gitleaks version' to fail the build on any install error. scripts/smoke-test.sh — git-crypt and gitleaks added to the 'Resolved component versions' table (printed first thing in CI logs) and to the 'Core binaries' assertion list (run helper). Smoke now fails fast if either binary regresses. README.md — 'What's in the image' tree line names gitleaks alongside the existing git-crypt. AGENTS.md — gitleaks added to the 'GitHub-sourced binaries float by default' list with a new clause flagging project-specific arch-name deviations (gitleaks=x64, bat/eza/zoxide=x86_64/aarch64, gosu= amd64/arm64). Saves the next person from the 'why does this not download' debugging session. CHANGELOG.md — sub-entry under existing Unreleased, before the PI_VERSION/OMOS_VERSION cache-hit fix entry. DOWNSTREAM IMPACT This is a base-layer change — base-decide will compute a fresh base-<hash>, build-base will run (no cache hit), all four variants will rebuild. First real base rebuild since v1.14.50b. Pi-devbox's next FROM base-latest pull picks up gitleaks automatically with no Dockerfile change there. Verified end-to-end on host: gitleaks 8.30.1 21 MB binary extracts cleanly from the URL the Dockerfile constructs and 'gitleaks version' prints '8.30.1'. Holding off on tagging — opencode + pi upstreams unchanged at 1.15.10 and 0.75.5 respectively. Will ride along with the next upstream-bump release rather than burning a base rebuild on a no-upstream-change container-only roll. |
||
|
|
8359fef949 |
Force fresh base rebuild for v1.14.50b
Validate / validate-base (push) Failing after 17s
Validate / docs-check (push) Successful in 20s
Publish Docker Image / base-decide (push) Successful in 13s
Validate / validate-with-pi (push) Failing after 2m57s
Validate / validate-omos (push) Failing after 9m29s
Validate / validate-omos-with-pi (push) Failing after 14m25s
Publish Docker Image / build-base (push) Successful in 13m58s
Publish Docker Image / smoke-omos-with-pi (push) Failing after 27s
Publish Docker Image / build-variant-omos-with-pi (push) Has been skipped
Publish Docker Image / smoke-omos (push) Failing after 1m51s
Publish Docker Image / build-variant-omos (push) Has been skipped
Publish Docker Image / smoke-base (push) Successful in 9m1s
Publish Docker Image / smoke-with-pi (push) Successful in 11m52s
Publish Docker Image / build-variant-base (push) Successful in 17m50s
Publish Docker Image / build-variant-with-pi (push) Failing after 16m10s
Publish Docker Image / promote-base-latest (push) Has been skipped
Publish Docker Image / update-description (push) Has been skipped
Add BASE_REBUILD_DATE comment to Dockerfile.base to invalidate the content hash and trigger a full base rebuild. Picks up ~5 days of Debian trixie security updates since the previous base-bf9df274db7a was built on 2026-05-09. The comment also documents the pattern for future intentional base-rebuilds without other code changes — recommended cadence is once per release for security currency. Required because v1.14.50 hash inputs were unchanged from v1.14.44, hitting the existing base-bf9df274db7a cache and shipping stale apt packages. v1.14.50 also failed mid-flight before promote-base-latest could publish base-latest to Hub — pi-devbox and other downstream images that FROM base-latest were blocked. |
||
|
|
4c27e6fd8a |
feat: split-base build pipeline (parallel, manual-trigger only)
Validate / docs-check (push) Successful in 15s
Validate / validate-base (push) Successful in 12m13s
Validate / validate-omos (push) Failing after 15m48s
Validate / validate-with-pi (push) Successful in 13m43s
Validate / validate-omos-with-pi (push) Has been cancelled
Two-Dockerfile split-base build alongside the existing single-Dockerfile
pipeline. Goal: cut CI wall clock from ~165-180min to ~30-40min on
typical version-bump-only releases by reusing a base image across the
four variants.
Files added:
- Dockerfile.base variant-independent layers (apt, locales, AWS
CLI, Node.js, mempalace, gitea-mcp, user setup,
chromadb prewarm, ENVs, entrypoints).
- Dockerfile.variant FROMs ${BASE_IMAGE} and adds opencode / pi /
omos / Go installs gated by INSTALL_* args.
Each npm install -g uses NPM_CONFIG_PREFIX=/usr
per-RUN to keep baked binaries off the volume-
shadowed ~/.pi/npm-global path inherited from
base.
- .gitea/workflows/docker-publish-split.yml
workflow_dispatch-only pipeline:
base-decide -> build-base (conditional) ->
smoke-* (4 parallel) -> build-variant-*
(4 parallel) -> promote-base-latest ->
update-description. Hash-driven base reuse:
if base-<sha> already exists on Docker Hub,
the build is skipped entirely. Inputs:
release_tag (test tag suffix, default
v0.0.0-split-test) and promote_latest
(default false; gates latest-* aliases and
Hub description update).
Files unchanged:
- Dockerfile, docker-publish.yml, validate.yml all left in place so
the production tag-push pipeline keeps working untouched.
Migration plan (in CHANGELOG Unreleased):
1. workflow_dispatch test run with promote_latest=false; verify the
four variant images smoke-pass and have plausible sizes.
2. Compare manifest digests against the same-version output from the
production pipeline (independent test run on the same commit).
3. Once verified across 1-2 release cycles, swap docker-publish-split.yml
to on: push: tags: v* and retire docker-publish.yml.
AGENTS.md and CHANGELOG.md updated with file roles and the migration
plan. Production pipeline behavior is bit-for-bit unchanged on this
branch.
|