bots-garden/mini-mepublic Fork
⑂ 427799c
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

🛟 Updated.

k33g committed 2026-09-21T23:59:01+02:00 Browse files
427799c parent: fa8a56d
modified .github/workflows/release.yml +0 -108
@@ -97,111 +97,3 @@ jobs:
9797 release/${{ github.ref_name }}/SHA256SUMS
9898 release/${{ github.ref_name }}/README.md
9999 fail_on_unmatched_files: true
100-
101- # The Docker Sandbox template and its two kits, on Docker Hub, at the same
102- # version as the binaries: k33g/mm-sandbox:0.0.2 (the image, linux/amd64 +
103- # linux/arm64), k33g/mm-tui:0.0.2 and k33g/mm-acp:0.0.2 (the kits, OCI
104- # artifacts). The scripts are the ones a laptop runs — docker-sbx/build.sh
105- # with PUSH=1, then docker-sbx/push-kits.sh — so a local publish and a CI
106- # publish are the same pipeline. Runs after `release` so nothing is pushed
107- # to the Hub when the tests failed.
108- #
109- # Credentials: two repository secrets, DOCKER_HANDLE (the Docker Hub
110- # account, which is also the image owner) and DOCKER_PAT (an access token
111- # with read/write scope), exposed to the job as environment variables.
112- docker-sandbox:
113- # No expression in the name: Rickub shows it unexpanded.
114- name: publish the Docker Sandbox template and kits
115- runs-on: ubuntu-latest
116- needs: release
117- env:
118- DOCKER_HANDLE: ${{ secrets.DOCKER_HANDLE }}
119- DOCKER_PAT: ${{ secrets.DOCKER_PAT }}
120- # The sbx release whose CLI publishes the kits (docker/sbx-releases).
121- SBX_VERSION: v0.45.0
122- steps:
123- - name: Checkout
124- uses: actions/checkout@v4
125-
126- - name: Check the Docker Hub credentials
127- # Secrets pasted with a trailing newline or a stray CR are a classic;
128- # both are stripped before use. The handle must be the Docker ID, not
129- # the e-mail address: access tokens only pair with the username.
130- run: |
131- set -euo pipefail
132- handle="$(printf '%s' "${DOCKER_HANDLE}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
133- pat="$(printf '%s' "${DOCKER_PAT}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
134- if [ -z "${handle}" ] || [ -z "${pat}" ]; then
135- echo "❌ DOCKER_HANDLE and DOCKER_PAT must be set as repository secrets"
136- exit 1
137- fi
138- case "${handle}" in
139- *@*|*:*) echo "❌ DOCKER_HANDLE must be the Docker ID (username), got something with @ or : in it"; exit 1 ;;
140- esac
141- echo "handle: ${handle} (${#handle} chars), token: ${#pat} chars"
142- echo "DOCKER_HANDLE=${handle}" >> "$GITHUB_ENV"
143- echo "::add-mask::${pat}"
144- echo "DOCKER_PAT=${pat}" >> "$GITHUB_ENV"
145-
146- - name: Diagnose the path to Docker Hub
147- # An anonymous GET on the registry must answer 401 with a Bearer
148- # challenge. A 400 "malformed HTTP Authorization header" there means
149- # something between this runner and the Hub (a proxy) adds its own
150- # Authorization header — the request below carries none. The token
151- # endpoint check then says whether the credentials themselves are
152- # accepted, without going through the Docker daemon.
153- run: |
154- set -uo pipefail
155- echo "--- anonymous GET https://registry-1.docker.io/v2/ (expect 401 + www-authenticate: Bearer)"
156- curl -sS -o /dev/null -D - https://registry-1.docker.io/v2/ | grep -i -E '^HTTP/|^www-authenticate|^docker-distribution' || true
157- echo "--- token for ${DOCKER_HANDLE}/mm-sandbox with the access token (expect 200)"
158- code="$(curl -sS -o /dev/null -w '%{http_code}' -u "${DOCKER_HANDLE}:${DOCKER_PAT}" \
159- "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${DOCKER_HANDLE}/mm-sandbox:pull,push")"
160- echo "auth.docker.io answered ${code}"
161- env | grep -i -E '^(https?_proxy|no_proxy|DOCKER_)' | sed 's/=.*/=…/' || true
162-
163- - name: Set up QEMU
164- # The final image stage runs `mm --version` for linux/arm64 on an
165- # amd64 runner; the Go stage itself cross-compiles without emulation.
166- uses: docker/setup-qemu-action@v3
167-
168- - name: Set up Docker Buildx
169- uses: docker/setup-buildx-action@v3
170-
171- - name: Log in to Docker Hub
172- # Not `docker login`: its ping of the registry goes through the Docker
173- # daemon and failed on Rickub with "malformed HTTP Authorization
174- # header". Writing the credential store directly is the same result —
175- # buildx forwards it to BuildKit for the push, and `sbx kit push`
176- # reads it (credentials.NewStoreFromDocker) — without the ping.
177- run: |
178- set -euo pipefail
179- mkdir -p "${HOME}/.docker"
180- auth="$(printf '%s:%s' "${DOCKER_HANDLE}" "${DOCKER_PAT}" | base64 | tr -d '\n')"
181- if [ -f "${HOME}/.docker/config.json" ]; then
182- cp "${HOME}/.docker/config.json" "${RUNNER_TEMP}/docker-config.orig.json"
183- fi
184- printf '{"auths":{"https://index.docker.io/v1/":{"auth":"%s"}}}\n' "${auth}" > "${HOME}/.docker/config.json"
185- chmod 0600 "${HOME}/.docker/config.json"
186- echo "credential store written for ${DOCKER_HANDLE}"
187-
188- - name: Build and push the template image
189- run: PUSH=1 IMAGE_OWNER="${DOCKER_HANDLE}" bash ./docker-sbx/build.sh "${GITHUB_REF_NAME}"
190-
191- - name: Install the sbx CLI
192- # `sbx kit push` talks to the registry directly and reads the Docker
193- # credential store; no sandbox daemon is started here.
194- run: |
195- set -euo pipefail
196- mkdir -p "${RUNNER_TEMP}/sbx"
197- curl -fsSL -o "${RUNNER_TEMP}/sbx.tgz" \
198- "https://github.com/docker/sbx-releases/releases/download/${SBX_VERSION}/DockerSandboxes-linux-amd64.tar.gz"
199- tar -xzf "${RUNNER_TEMP}/sbx.tgz" -C "${RUNNER_TEMP}/sbx" --strip-components=1 docker-sbx/sbx
200- "${RUNNER_TEMP}/sbx/sbx" version
201-
202- - name: Publish the kits
203- run: IMAGE_OWNER="${DOCKER_HANDLE}" SBX="${RUNNER_TEMP}/sbx/sbx" bash ./docker-sbx/push-kits.sh "${GITHUB_REF_NAME}"
204-
205- - name: Remove the credential store
206- if: always()
207- run: rm -f "${HOME}/.docker/config.json"
@@ -97,111 +97,3 @@ jobs:
97 release/${{ github.ref_name }}/SHA256SUMS97 release/${{ github.ref_name }}/SHA256SUMS
98 release/${{ github.ref_name }}/README.md98 release/${{ github.ref_name }}/README.md
99 fail_on_unmatched_files: true99 fail_on_unmatched_files: true
100-
101- # The Docker Sandbox template and its two kits, on Docker Hub, at the same
102- # version as the binaries: k33g/mm-sandbox:0.0.2 (the image, linux/amd64 +
103- # linux/arm64), k33g/mm-tui:0.0.2 and k33g/mm-acp:0.0.2 (the kits, OCI
104- # artifacts). The scripts are the ones a laptop runs — docker-sbx/build.sh
105- # with PUSH=1, then docker-sbx/push-kits.sh — so a local publish and a CI
106- # publish are the same pipeline. Runs after `release` so nothing is pushed
107- # to the Hub when the tests failed.
108- #
109- # Credentials: two repository secrets, DOCKER_HANDLE (the Docker Hub
110- # account, which is also the image owner) and DOCKER_PAT (an access token
111- # with read/write scope), exposed to the job as environment variables.
112- docker-sandbox:
113- # No expression in the name: Rickub shows it unexpanded.
114- name: publish the Docker Sandbox template and kits
115- runs-on: ubuntu-latest
116- needs: release
117- env:
118- DOCKER_HANDLE: ${{ secrets.DOCKER_HANDLE }}
119- DOCKER_PAT: ${{ secrets.DOCKER_PAT }}
120- # The sbx release whose CLI publishes the kits (docker/sbx-releases).
121- SBX_VERSION: v0.45.0
122- steps:
123- - name: Checkout
124- uses: actions/checkout@v4
125-
126- - name: Check the Docker Hub credentials
127- # Secrets pasted with a trailing newline or a stray CR are a classic;
128- # both are stripped before use. The handle must be the Docker ID, not
129- # the e-mail address: access tokens only pair with the username.
130- run: |
131- set -euo pipefail
132- handle="$(printf '%s' "${DOCKER_HANDLE}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
133- pat="$(printf '%s' "${DOCKER_PAT}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
134- if [ -z "${handle}" ] || [ -z "${pat}" ]; then
135- echo "❌ DOCKER_HANDLE and DOCKER_PAT must be set as repository secrets"
136- exit 1
137- fi
138- case "${handle}" in
139- *@*|*:*) echo "❌ DOCKER_HANDLE must be the Docker ID (username), got something with @ or : in it"; exit 1 ;;
140- esac
141- echo "handle: ${handle} (${#handle} chars), token: ${#pat} chars"
142- echo "DOCKER_HANDLE=${handle}" >> "$GITHUB_ENV"
143- echo "::add-mask::${pat}"
144- echo "DOCKER_PAT=${pat}" >> "$GITHUB_ENV"
145-
146- - name: Diagnose the path to Docker Hub
147- # An anonymous GET on the registry must answer 401 with a Bearer
148- # challenge. A 400 "malformed HTTP Authorization header" there means
149- # something between this runner and the Hub (a proxy) adds its own
150- # Authorization header — the request below carries none. The token
151- # endpoint check then says whether the credentials themselves are
152- # accepted, without going through the Docker daemon.
153- run: |
154- set -uo pipefail
155- echo "--- anonymous GET https://registry-1.docker.io/v2/ (expect 401 + www-authenticate: Bearer)"
156- curl -sS -o /dev/null -D - https://registry-1.docker.io/v2/ | grep -i -E '^HTTP/|^www-authenticate|^docker-distribution' || true
157- echo "--- token for ${DOCKER_HANDLE}/mm-sandbox with the access token (expect 200)"
158- code="$(curl -sS -o /dev/null -w '%{http_code}' -u "${DOCKER_HANDLE}:${DOCKER_PAT}" \
159- "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${DOCKER_HANDLE}/mm-sandbox:pull,push")"
160- echo "auth.docker.io answered ${code}"
161- env | grep -i -E '^(https?_proxy|no_proxy|DOCKER_)' | sed 's/=.*/=…/' || true
162-
163- - name: Set up QEMU
164- # The final image stage runs `mm --version` for linux/arm64 on an
165- # amd64 runner; the Go stage itself cross-compiles without emulation.
166- uses: docker/setup-qemu-action@v3
167-
168- - name: Set up Docker Buildx
169- uses: docker/setup-buildx-action@v3
170-
171- - name: Log in to Docker Hub
172- # Not `docker login`: its ping of the registry goes through the Docker
173- # daemon and failed on Rickub with "malformed HTTP Authorization
174- # header". Writing the credential store directly is the same result —
175- # buildx forwards it to BuildKit for the push, and `sbx kit push`
176- # reads it (credentials.NewStoreFromDocker) — without the ping.
177- run: |
178- set -euo pipefail
179- mkdir -p "${HOME}/.docker"
180- auth="$(printf '%s:%s' "${DOCKER_HANDLE}" "${DOCKER_PAT}" | base64 | tr -d '\n')"
181- if [ -f "${HOME}/.docker/config.json" ]; then
182- cp "${HOME}/.docker/config.json" "${RUNNER_TEMP}/docker-config.orig.json"
183- fi
184- printf '{"auths":{"https://index.docker.io/v1/":{"auth":"%s"}}}\n' "${auth}" > "${HOME}/.docker/config.json"
185- chmod 0600 "${HOME}/.docker/config.json"
186- echo "credential store written for ${DOCKER_HANDLE}"
187-
188- - name: Build and push the template image
189- run: PUSH=1 IMAGE_OWNER="${DOCKER_HANDLE}" bash ./docker-sbx/build.sh "${GITHUB_REF_NAME}"
190-
191- - name: Install the sbx CLI
192- # `sbx kit push` talks to the registry directly and reads the Docker
193- # credential store; no sandbox daemon is started here.
194- run: |
195- set -euo pipefail
196- mkdir -p "${RUNNER_TEMP}/sbx"
197- curl -fsSL -o "${RUNNER_TEMP}/sbx.tgz" \
198- "https://github.com/docker/sbx-releases/releases/download/${SBX_VERSION}/DockerSandboxes-linux-amd64.tar.gz"
199- tar -xzf "${RUNNER_TEMP}/sbx.tgz" -C "${RUNNER_TEMP}/sbx" --strip-components=1 docker-sbx/sbx
200- "${RUNNER_TEMP}/sbx/sbx" version
201-
202- - name: Publish the kits
203- run: IMAGE_OWNER="${DOCKER_HANDLE}" SBX="${RUNNER_TEMP}/sbx/sbx" bash ./docker-sbx/push-kits.sh "${GITHUB_REF_NAME}"
204-
205- - name: Remove the credential store
206- if: always()
207- run: rm -f "${HOME}/.docker/config.json"
modified docker-sbx/README.md +14 -5
@@ -6,6 +6,7 @@ The full guide, with the reasoning, is in [`docs/en/how-to/run-in-a-docker-sandb
66
77 ```
88 docker-sbx/
9+├── publish.sh build + push the image, then publish the kits — the one command to release
910 ├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
1011 ├── sync-kits.sh points the kits at one image: owner + version
1112 ├── push-kits.sh publishes the kits to Docker Hub as OCI artifacts (sbx kit push)
@@ -177,15 +178,23 @@ Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the agent'
177178
178179 ## 4. Publishing a version
179180
180-The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) does this on every `v*` tag, after the binaries: it reads two repository secrets, `DOCKER_HANDLE` (the Docker Hub account, also the image owner) and `DOCKER_PAT` (an access token), logs in, then runs the same two scripts you can run from a laptop:
181+Publishing is done by hand, from a laptop with Docker Desktop (buildx and the `sbx` CLI). One command builds the image for linux/amd64 and linux/arm64, pushes it, then validates and pushes the two kits, all at mm's tag:
181182
182183 ```bash
183-docker login -u k33g # with an access token
184-PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2
185-./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
184+export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
185+export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
186+./docker-sbx/publish.sh # TAG from release.env: v0.0.3 → k33g/mm-sandbox:0.0.3, k33g/mm-tui:0.0.3, k33g/mm-acp:0.0.3
187+./docker-sbx/publish.sh v0.0.4 # another tag
186188 ```
187189
188-`push-kits.sh` needs the `sbx` CLI (the workflow downloads the Linux tarball from `docker/sbx-releases`); `sbx kit push` talks to the registry directly and authenticates from the Docker credential store, no sandbox daemon involved. Both scripts call `sync-kits.sh` first, so the published kits always name the image just pushed. `IMAGE_OWNER=<handle>` publishes under another account.
190+With the two variables set, the script logs in with them and logs out at the end; with neither, it reuses the `docker login` you already have. It is two steps you can also run alone:
191+
192+```bash
193+PUSH=1 ./docker-sbx/build.sh v0.0.3 # buildx multi-arch, pushed; proof: `imagetools inspect` lists both platforms
194+./docker-sbx/push-kits.sh v0.0.3 # sbx kit validate + sbx kit push, for each kit
195+```
196+
197+Both call `sync-kits.sh` first, so the published kits always name the image just pushed, and the kits' `spec.yaml` end up saying the new version — commit them. `sbx kit push` talks to the registry directly and authenticates from the Docker credential store; no sandbox daemon is involved. `IMAGE_OWNER=<handle>` publishes under another account. Nothing in CI publishes to the Hub: the Release workflow only builds the binaries.
189198
190199 ## The model server stays on the host
191200
@@ -6,6 +6,7 @@ The full guide, with the reasoning, is in [`docs/en/how-to/run-in-a-docker-sandb
6 6
7 ```7 ```
8 docker-sbx/8 docker-sbx/
9+├── publish.sh build + push the image, then publish the kits — the one command to release
9 ├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)10 ├── build.sh builds the template image, k33g/mm-sandbox:<version> (PUSH=1: multi-arch, pushed)
10 ├── sync-kits.sh points the kits at one image: owner + version11 ├── sync-kits.sh points the kits at one image: owner + version
11 ├── push-kits.sh publishes the kits to Docker Hub as OCI artifacts (sbx kit push)12 ├── push-kits.sh publishes the kits to Docker Hub as OCI artifacts (sbx kit push)
@@ -177,15 +178,23 @@ Why `sbx exec -i` and not `sbx run`: an ACP client speaks JSON-RPC on the agent'
177 178
178 ## 4. Publishing a version179 ## 4. Publishing a version
179 180
180-The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) does this on every `v*` tag, after the binaries: it reads two repository secrets, `DOCKER_HANDLE` (the Docker Hub account, also the image owner) and `DOCKER_PAT` (an access token), logs in, then runs the same two scripts you can run from a laptop:181+Publishing is done by hand, from a laptop with Docker Desktop (buildx and the `sbx` CLI). One command builds the image for linux/amd64 and linux/arm64, pushes it, then validates and pushes the two kits, all at mm's tag:
181 182
182 ```bash183 ```bash
183-docker login -u k33g # with an access token184+export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
184-PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2185+export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
185-./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2186+./docker-sbx/publish.sh # TAG from release.env: v0.0.3 → k33g/mm-sandbox:0.0.3, k33g/mm-tui:0.0.3, k33g/mm-acp:0.0.3
187+./docker-sbx/publish.sh v0.0.4 # another tag
186 ```188 ```
187 189
188-`push-kits.sh` needs the `sbx` CLI (the workflow downloads the Linux tarball from `docker/sbx-releases`); `sbx kit push` talks to the registry directly and authenticates from the Docker credential store, no sandbox daemon involved. Both scripts call `sync-kits.sh` first, so the published kits always name the image just pushed. `IMAGE_OWNER=<handle>` publishes under another account.190+With the two variables set, the script logs in with them and logs out at the end; with neither, it reuses the `docker login` you already have. It is two steps you can also run alone:
191+
192+```bash
193+PUSH=1 ./docker-sbx/build.sh v0.0.3 # buildx multi-arch, pushed; proof: `imagetools inspect` lists both platforms
194+./docker-sbx/push-kits.sh v0.0.3 # sbx kit validate + sbx kit push, for each kit
195+```
196+
197+Both call `sync-kits.sh` first, so the published kits always name the image just pushed, and the kits' `spec.yaml` end up saying the new version — commit them. `sbx kit push` talks to the registry directly and authenticates from the Docker credential store; no sandbox daemon is involved. `IMAGE_OWNER=<handle>` publishes under another account. Nothing in CI publishes to the Hub: the Release workflow only builds the binaries.
189 198
190 ## The model server stays on the host199 ## The model server stays on the host
191 200
modified docker-sbx/build.sh +5 -4
@@ -6,10 +6,10 @@
66 #
77 # Usage:
88 # ./docker-sbx/build.sh # TAG from release.env, image for this machine
9-# ./docker-sbx/build.sh v0.0.3 # override the tag for this run (what CI does)
9+# ./docker-sbx/build.sh v0.0.3 # override the tag for this run
1010 # PUSH=1 ./docker-sbx/build.sh # multi-arch (linux/amd64 + linux/arm64) built
1111 # # with buildx and PUSHED to the registry —
12-# # needs `docker login`; this is the CI path
12+# # needs `docker login`; publish.sh does this
1313 # IMAGE_OWNER=someone ./docker-sbx/build.sh # another image owner (default k33g)
1414 # PLATFORMS=linux/amd64 PUSH=1 … # narrower multi-arch set
1515 # SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh
@@ -19,7 +19,8 @@
1919 #
2020 # Whatever the mode, the two kits under docker-sbx/kits/ are then pointed at
2121 # the image just built (docker-sbx/sync-kits.sh), so kits and image move
22-# together. Publishing the kits themselves is docker-sbx/push-kits.sh.
22+# together. Publishing the kits themselves is docker-sbx/push-kits.sh, and
23+# docker-sbx/publish.sh chains the two.
2324 set -euo pipefail
2425
2526 cd "$(dirname "$0")/.."
@@ -52,7 +53,7 @@ if [ -n "${PUSH:-}" ]; then
5253 # Multi-arch needs buildx's container driver: the classic builder can
5354 # neither assemble a manifest list nor build for a foreign platform. The
5455 # Go stage cross-compiles on the build platform; only the final stage's
55- # `RUN mm --version` runs under emulation (QEMU, set up by the caller).
56+ # `RUN mm --version` runs under emulation (Docker Desktop ships QEMU).
5657 echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
5758 if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
5859 docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
@@ -6,10 +6,10 @@
6 #6 #
7 # Usage:7 # Usage:
8 # ./docker-sbx/build.sh # TAG from release.env, image for this machine8 # ./docker-sbx/build.sh # TAG from release.env, image for this machine
9-# ./docker-sbx/build.sh v0.0.3 # override the tag for this run (what CI does)9+# ./docker-sbx/build.sh v0.0.3 # override the tag for this run
10 # PUSH=1 ./docker-sbx/build.sh # multi-arch (linux/amd64 + linux/arm64) built10 # PUSH=1 ./docker-sbx/build.sh # multi-arch (linux/amd64 + linux/arm64) built
11 # # with buildx and PUSHED to the registry —11 # # with buildx and PUSHED to the registry —
12-# # needs `docker login`; this is the CI path12+# # needs `docker login`; publish.sh does this
13 # IMAGE_OWNER=someone ./docker-sbx/build.sh # another image owner (default k33g)13 # IMAGE_OWNER=someone ./docker-sbx/build.sh # another image owner (default k33g)
14 # PLATFORMS=linux/amd64 PUSH=1 … # narrower multi-arch set14 # PLATFORMS=linux/amd64 PUSH=1 … # narrower multi-arch set
15 # SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh15 # SHELL_TEMPLATE=docker/sandbox-templates:shell-docker ./docker-sbx/build.sh
@@ -19,7 +19,8 @@
19 #19 #
20 # Whatever the mode, the two kits under docker-sbx/kits/ are then pointed at20 # Whatever the mode, the two kits under docker-sbx/kits/ are then pointed at
21 # the image just built (docker-sbx/sync-kits.sh), so kits and image move21 # the image just built (docker-sbx/sync-kits.sh), so kits and image move
22-# together. Publishing the kits themselves is docker-sbx/push-kits.sh.22+# together. Publishing the kits themselves is docker-sbx/push-kits.sh, and
23+# docker-sbx/publish.sh chains the two.
23 set -euo pipefail24 set -euo pipefail
24 25
25 cd "$(dirname "$0")/.."26 cd "$(dirname "$0")/.."
@@ -52,7 +53,7 @@ if [ -n "${PUSH:-}" ]; then
52 # Multi-arch needs buildx's container driver: the classic builder can53 # Multi-arch needs buildx's container driver: the classic builder can
53 # neither assemble a manifest list nor build for a foreign platform. The54 # neither assemble a manifest list nor build for a foreign platform. The
54 # Go stage cross-compiles on the build platform; only the final stage's55 # Go stage cross-compiles on the build platform; only the final stage's
55- # `RUN mm --version` runs under emulation (QEMU, set up by the caller).56+ # `RUN mm --version` runs under emulation (Docker Desktop ships QEMU).
56 echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"57 echo "🐳 Building and pushing ${IMAGE} for ${PLATFORMS} (mm ${TAG}, base ${SHELL_TEMPLATE:-docker/sandbox-templates:shell})"
57 if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then58 if ! docker buildx inspect mm-sandbox-builder >/dev/null 2>&1; then
58 docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null59 docker buildx create --name mm-sandbox-builder --driver docker-container --bootstrap >/dev/null
added docker-sbx/publish.sh +82 -0
new file mode 100755
@@ -0,0 +1,82 @@
1+#!/usr/bin/env bash
2+# Build and publish everything to Docker Hub, by hand, in one go:
3+# <owner>/mm-sandbox:<version> the template image, linux/amd64 + linux/arm64
4+# <owner>/mm-tui:<version> the window-mode kit
5+# <owner>/mm-acp:<version> the editor (ACP) kit
6+#
7+# Usage:
8+# ./docker-sbx/publish.sh # TAG from release.env (v0.0.3 → 0.0.3)
9+# ./docker-sbx/publish.sh v0.0.4 # another tag
10+#
11+# Credentials, two environment variables:
12+# DOCKER_HANDLE the Docker Hub account — also the image owner (default k33g)
13+# DOCKER_PAT an access token with read/write scope
14+# With both set, the script logs in with them (and out at the end). With
15+# neither, it uses the login you already have (`docker login` done earlier).
16+#
17+# Needs: docker with buildx (Docker Desktop has it), and the sbx CLI for the
18+# kits (`SBX=/path/to/sbx` if it is not on the PATH). Pieces, runnable alone:
19+# PUSH=1 ./docker-sbx/build.sh TAG image only
20+# ./docker-sbx/push-kits.sh TAG kits only
21+set -euo pipefail
22+
23+cd "$(dirname "$0")/.."
24+
25+if [ -f release.env ]; then
26+ # shellcheck source=/dev/null
27+ source release.env
28+fi
29+TAG="${1:-${TAG:-}}"
30+if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
31+ echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/publish.sh v1.2.3)"
32+ exit 1
33+fi
34+
35+# Secrets pasted with a trailing newline or stray spaces are a classic.
36+DOCKER_HANDLE="$(printf '%s' "${DOCKER_HANDLE:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
37+DOCKER_PAT="$(printf '%s' "${DOCKER_PAT:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
38+case "${DOCKER_HANDLE}" in
39+*@* | *:*)
40+ echo "❌ DOCKER_HANDLE must be the Docker ID (username), not an e-mail: access tokens only pair with the username"
41+ exit 1
42+ ;;
43+esac
44+export IMAGE_OWNER="${IMAGE_OWNER:-${DOCKER_HANDLE:-k33g}}"
45+VERSION="${TAG#v}"
46+
47+SBX="${SBX:-sbx}"
48+if ! command -v "${SBX}" >/dev/null 2>&1; then
49+ echo "❌ sbx not found (${SBX}): install Docker Sandboxes, or SBX=/path/to/sbx"
50+ exit 1
51+fi
52+export SBX
53+
54+logged_in_here=""
55+if [ -n "${DOCKER_HANDLE}" ] && [ -n "${DOCKER_PAT}" ]; then
56+ echo "🔐 docker login as ${DOCKER_HANDLE}"
57+ printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
58+ logged_in_here=1
59+elif [ -n "${DOCKER_HANDLE}${DOCKER_PAT}" ]; then
60+ echo "❌ set both DOCKER_HANDLE and DOCKER_PAT, or neither (to reuse an existing docker login)"
61+ exit 1
62+else
63+ echo "🔐 no DOCKER_HANDLE/DOCKER_PAT: using the existing docker login, publishing under ${IMAGE_OWNER}"
64+fi
65+# Whatever happens below, a login made here does not outlive the script.
66+cleanup() {
67+ if [ -n "${logged_in_here}" ]; then
68+ docker logout >/dev/null 2>&1 || true
69+ fi
70+}
71+trap cleanup EXIT
72+
73+echo
74+echo "═══ 1/2 image ${IMAGE_OWNER}/mm-sandbox:${VERSION}"
75+PUSH=1 ./docker-sbx/build.sh "${TAG}"
76+
77+echo
78+echo "═══ 2/2 kits ${IMAGE_OWNER}/mm-tui:${VERSION} and ${IMAGE_OWNER}/mm-acp:${VERSION}"
79+./docker-sbx/push-kits.sh "${TAG}"
80+
81+echo
82+echo "✨ Published ${TAG}. The kits' spec.yaml now name version ${VERSION} — commit them."
new file mode 100755
@@ -0,0 +1,82 @@
1+#!/usr/bin/env bash
2+# Build and publish everything to Docker Hub, by hand, in one go:
3+# <owner>/mm-sandbox:<version> the template image, linux/amd64 + linux/arm64
4+# <owner>/mm-tui:<version> the window-mode kit
5+# <owner>/mm-acp:<version> the editor (ACP) kit
6+#
7+# Usage:
8+# ./docker-sbx/publish.sh # TAG from release.env (v0.0.3 → 0.0.3)
9+# ./docker-sbx/publish.sh v0.0.4 # another tag
10+#
11+# Credentials, two environment variables:
12+# DOCKER_HANDLE the Docker Hub account — also the image owner (default k33g)
13+# DOCKER_PAT an access token with read/write scope
14+# With both set, the script logs in with them (and out at the end). With
15+# neither, it uses the login you already have (`docker login` done earlier).
16+#
17+# Needs: docker with buildx (Docker Desktop has it), and the sbx CLI for the
18+# kits (`SBX=/path/to/sbx` if it is not on the PATH). Pieces, runnable alone:
19+# PUSH=1 ./docker-sbx/build.sh TAG image only
20+# ./docker-sbx/push-kits.sh TAG kits only
21+set -euo pipefail
22+
23+cd "$(dirname "$0")/.."
24+
25+if [ -f release.env ]; then
26+ # shellcheck source=/dev/null
27+ source release.env
28+fi
29+TAG="${1:-${TAG:-}}"
30+if ! [[ "${TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
31+ echo "❌ TAG must look like v1.2.3 or v1.2.3-rc.1, got '${TAG}' (check release.env or pass it: ./docker-sbx/publish.sh v1.2.3)"
32+ exit 1
33+fi
34+
35+# Secrets pasted with a trailing newline or stray spaces are a classic.
36+DOCKER_HANDLE="$(printf '%s' "${DOCKER_HANDLE:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
37+DOCKER_PAT="$(printf '%s' "${DOCKER_PAT:-}" | tr -d '\r\n' | sed 's/^ *//; s/ *$//')"
38+case "${DOCKER_HANDLE}" in
39+*@* | *:*)
40+ echo "❌ DOCKER_HANDLE must be the Docker ID (username), not an e-mail: access tokens only pair with the username"
41+ exit 1
42+ ;;
43+esac
44+export IMAGE_OWNER="${IMAGE_OWNER:-${DOCKER_HANDLE:-k33g}}"
45+VERSION="${TAG#v}"
46+
47+SBX="${SBX:-sbx}"
48+if ! command -v "${SBX}" >/dev/null 2>&1; then
49+ echo "❌ sbx not found (${SBX}): install Docker Sandboxes, or SBX=/path/to/sbx"
50+ exit 1
51+fi
52+export SBX
53+
54+logged_in_here=""
55+if [ -n "${DOCKER_HANDLE}" ] && [ -n "${DOCKER_PAT}" ]; then
56+ echo "🔐 docker login as ${DOCKER_HANDLE}"
57+ printf '%s' "${DOCKER_PAT}" | docker login --username "${DOCKER_HANDLE}" --password-stdin
58+ logged_in_here=1
59+elif [ -n "${DOCKER_HANDLE}${DOCKER_PAT}" ]; then
60+ echo "❌ set both DOCKER_HANDLE and DOCKER_PAT, or neither (to reuse an existing docker login)"
61+ exit 1
62+else
63+ echo "🔐 no DOCKER_HANDLE/DOCKER_PAT: using the existing docker login, publishing under ${IMAGE_OWNER}"
64+fi
65+# Whatever happens below, a login made here does not outlive the script.
66+cleanup() {
67+ if [ -n "${logged_in_here}" ]; then
68+ docker logout >/dev/null 2>&1 || true
69+ fi
70+}
71+trap cleanup EXIT
72+
73+echo
74+echo "═══ 1/2 image ${IMAGE_OWNER}/mm-sandbox:${VERSION}"
75+PUSH=1 ./docker-sbx/build.sh "${TAG}"
76+
77+echo
78+echo "═══ 2/2 kits ${IMAGE_OWNER}/mm-tui:${VERSION} and ${IMAGE_OWNER}/mm-acp:${VERSION}"
79+./docker-sbx/push-kits.sh "${TAG}"
80+
81+echo
82+echo "✨ Published ${TAG}. The kits' spec.yaml now name version ${VERSION} — commit them."
modified docker-sbx/push-kits.sh +2 -2
@@ -4,7 +4,7 @@
44 #
55 # Usage:
66 # ./docker-sbx/push-kits.sh # TAG from release.env
7-# ./docker-sbx/push-kits.sh v0.0.3 # override the tag (what CI does)
7+# ./docker-sbx/push-kits.sh v0.0.3 # override the tag
88 # IMAGE_OWNER=someone … # another owner (default k33g); the kits
99 # # are re-pointed at someone/mm-sandbox too
1010 # REGISTRY=localhost:5000 … # another registry (default docker.io)
@@ -14,7 +14,7 @@
1414 # `sbx kit push` talks to the registry directly — no sandbox daemon involved —
1515 # and falls back to the Docker credential store for authentication.
1616 #
17-# Push the image first (PUSH=1 ./docker-sbx/build.sh): a kit names
17+# publish.sh runs this after the image. Push the image first: a kit names
1818 # <owner>/mm-sandbox:<version>, and sbx pulls that image when the kit is used.
1919 set -euo pipefail
2020
@@ -4,7 +4,7 @@
4 #4 #
5 # Usage:5 # Usage:
6 # ./docker-sbx/push-kits.sh # TAG from release.env6 # ./docker-sbx/push-kits.sh # TAG from release.env
7-# ./docker-sbx/push-kits.sh v0.0.3 # override the tag (what CI does)7+# ./docker-sbx/push-kits.sh v0.0.3 # override the tag
8 # IMAGE_OWNER=someone … # another owner (default k33g); the kits8 # IMAGE_OWNER=someone … # another owner (default k33g); the kits
9 # # are re-pointed at someone/mm-sandbox too9 # # are re-pointed at someone/mm-sandbox too
10 # REGISTRY=localhost:5000 … # another registry (default docker.io)10 # REGISTRY=localhost:5000 … # another registry (default docker.io)
@@ -14,7 +14,7 @@
14 # `sbx kit push` talks to the registry directly — no sandbox daemon involved —14 # `sbx kit push` talks to the registry directly — no sandbox daemon involved —
15 # and falls back to the Docker credential store for authentication.15 # and falls back to the Docker credential store for authentication.
16 #16 #
17-# Push the image first (PUSH=1 ./docker-sbx/build.sh): a kit names17+# publish.sh runs this after the image. Push the image first: a kit names
18 # <owner>/mm-sandbox:<version>, and sbx pulls that image when the kit is used.18 # <owner>/mm-sandbox:<version>, and sbx pulls that image when the kit is used.
19 set -euo pipefail19 set -euo pipefail
20 20
modified docker-sbx/sync-kits.sh +1 -1
@@ -9,7 +9,7 @@
99 # sandbox.image: "<owner>/mm-sandbox:…" which owner the image lives under
1010 # Everything else — comments included — is left byte-for-byte alone, so a
1111 # kit that already matches is not changed at all. build.sh and push-kits.sh
12-# call this; CI relies on it so the published kits name the image it pushed.
12+# call this, so the published kits always name the image just pushed.
1313 set -euo pipefail
1414
1515 if [ $# -ne 2 ]; then
@@ -9,7 +9,7 @@
9 # sandbox.image: "<owner>/mm-sandbox:…" which owner the image lives under9 # sandbox.image: "<owner>/mm-sandbox:…" which owner the image lives under
10 # Everything else — comments included — is left byte-for-byte alone, so a10 # Everything else — comments included — is left byte-for-byte alone, so a
11 # kit that already matches is not changed at all. build.sh and push-kits.sh11 # kit that already matches is not changed at all. build.sh and push-kits.sh
12-# call this; CI relies on it so the published kits name the image it pushed.12+# call this, so the published kits always name the image just pushed.
13 set -euo pipefail13 set -euo pipefail
14 14
15 if [ $# -ne 2 ]; then15 if [ $# -ne 2 ]; then
modified docs/en/how-to/run-in-a-docker-sandbox.md +5 -5
@@ -113,15 +113,15 @@ Both kits allow ports 12434 and 8080 on the host in the sandbox's network policy
113113
114114 ## Publishing a version
115115
116-The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) publishes the image and the kits on every `v*` tag, after the binaries job. It needs two repository secrets, exposed to the job as environment variables: `DOCKER_HANDLE`, the Docker Hub account (also the image owner), and `DOCKER_PAT`, an access token with read/write scope. It then runs the scripts a laptop would run:
116+Publishing is a manual step, from a machine with Docker Desktop (buildx and the `sbx` CLI); the Release workflow builds only the binaries. One script builds the image for linux/amd64 and linux/arm64, pushes it, then validates and pushes the two kits, all at mm's tag:
117117
118118 ```bash
119-docker login -u k33g # paste an access token
120-PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2
121-./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
119+export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
120+export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
121+./docker-sbx/publish.sh # TAG from release.env: v0.0.3 → k33g/mm-sandbox:0.0.3, k33g/mm-tui:0.0.3, k33g/mm-acp:0.0.3
122122 ```
123123
124-`push-kits.sh` needs the `sbx` CLI on the PATH (or `SBX=/path/to/sbx`; the workflow downloads the Linux tarball of `docker/sbx-releases`). `sbx kit push` talks to the registry directly and authenticates from the Docker credential store — no sandbox daemon is involved, which is what makes it usable in CI. Both scripts call `sync-kits.sh` first, which rewrites the kits' `version`, default `tag` and image owner, so a published kit always names the image pushed with it. `IMAGE_OWNER=<handle>` publishes under another account.
124+With both variables set, the script logs in with them and logs out when it is done; with neither, it reuses your existing `docker login`. Its two halves run alone as `PUSH=1 ./docker-sbx/build.sh v0.0.3` (image) and `./docker-sbx/push-kits.sh v0.0.3` (kits, `SBX=/path/to/sbx` if the CLI is not on the PATH). Both call `sync-kits.sh` first, which rewrites the kits' `version`, default `tag` and image owner, so a published kit always names the image pushed with it — commit the two `spec.yaml` afterwards. `sbx kit push` talks to the registry directly and authenticates from the Docker credential store, no sandbox daemon involved. `IMAGE_OWNER=<handle>` publishes under another account.
125125
126126 ## Variants
127127
@@ -113,15 +113,15 @@ Both kits allow ports 12434 and 8080 on the host in the sandbox's network policy
113 113
114 ## Publishing a version114 ## Publishing a version
115 115
116-The Release workflow (`.github/workflows/release.yml`, job `docker-sandbox`) publishes the image and the kits on every `v*` tag, after the binaries job. It needs two repository secrets, exposed to the job as environment variables: `DOCKER_HANDLE`, the Docker Hub account (also the image owner), and `DOCKER_PAT`, an access token with read/write scope. It then runs the scripts a laptop would run:116+Publishing is a manual step, from a machine with Docker Desktop (buildx and the `sbx` CLI); the Release workflow builds only the binaries. One script builds the image for linux/amd64 and linux/arm64, pushes it, then validates and pushes the two kits, all at mm's tag:
117 117
118 ```bash118 ```bash
119-docker login -u k33g # paste an access token119+export DOCKER_HANDLE=k33g # the Docker Hub account, also the image owner
120-PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, pushed as k33g/mm-sandbox:0.0.2120+export DOCKER_PAT=dckr_pat_… # an access token with read/write scope
121-./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2121+./docker-sbx/publish.sh # TAG from release.env: v0.0.3 → k33g/mm-sandbox:0.0.3, k33g/mm-tui:0.0.3, k33g/mm-acp:0.0.3
122 ```122 ```
123 123
124-`push-kits.sh` needs the `sbx` CLI on the PATH (or `SBX=/path/to/sbx`; the workflow downloads the Linux tarball of `docker/sbx-releases`). `sbx kit push` talks to the registry directly and authenticates from the Docker credential store — no sandbox daemon is involved, which is what makes it usable in CI. Both scripts call `sync-kits.sh` first, which rewrites the kits' `version`, default `tag` and image owner, so a published kit always names the image pushed with it. `IMAGE_OWNER=<handle>` publishes under another account.124+With both variables set, the script logs in with them and logs out when it is done; with neither, it reuses your existing `docker login`. Its two halves run alone as `PUSH=1 ./docker-sbx/build.sh v0.0.3` (image) and `./docker-sbx/push-kits.sh v0.0.3` (kits, `SBX=/path/to/sbx` if the CLI is not on the PATH). Both call `sync-kits.sh` first, which rewrites the kits' `version`, default `tag` and image owner, so a published kit always names the image pushed with it — commit the two `spec.yaml` afterwards. `sbx kit push` talks to the registry directly and authenticates from the Docker credential store, no sandbox daemon involved. `IMAGE_OWNER=<handle>` publishes under another account.
125 125
126 ## Variants126 ## Variants
127 127
modified docs/fr/how-to/run-in-a-docker-sandbox.md +5 -5
@@ -113,15 +113,15 @@ Les deux kits autorisent les ports 12434 et 8080 de l'hôte dans la politique r
113113
114114 ## Publier une version
115115
116-Le workflow Release (`.github/workflows/release.yml`, job `docker-sandbox`) publie l'image et les kits à chaque tag `v*`, après le job des binaires. Il a besoin de deux secrets du dépôt, exposés au job comme variables d'environnement : `DOCKER_HANDLE`, le compte Docker Hub (aussi le propriétaire de l'image), et `DOCKER_PAT`, un jeton d'accès en lecture/écriture. Il lance ensuite les scripts qu'un portable lancerait :
116+La publication est une étape manuelle, depuis une machine avec Docker Desktop (buildx et la CLI `sbx`) ; le workflow Release ne construit que les binaires. Un script construit l'image pour linux/amd64 et linux/arm64, la pousse, puis valide et pousse les deux kits, le tout au tag de mm :
117117
118118 ```bash
119-docker login -u k33g # coller un jeton d'accès
120-PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, poussée comme k33g/mm-sandbox:0.0.2
121-./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2
119+export DOCKER_HANDLE=k33g # le compte Docker Hub, aussi propriétaire de l'image
120+export DOCKER_PAT=dckr_pat_… # un jeton d'accès en lecture/écriture
121+./docker-sbx/publish.sh # TAG depuis release.env : v0.0.3 → k33g/mm-sandbox:0.0.3, k33g/mm-tui:0.0.3, k33g/mm-acp:0.0.3
122122 ```
123123
124-`push-kits.sh` a besoin de la CLI `sbx` sur le PATH (ou `SBX=/chemin/vers/sbx` ; le workflow télécharge l'archive Linux de `docker/sbx-releases`). `sbx kit push` parle directement au registre et s'authentifie depuis le magasin d'identifiants Docker — aucun démon sandbox n'intervient, c'est ce qui le rend utilisable en CI. Les deux scripts appellent d'abord `sync-kits.sh`, qui réécrit `version`, le `tag` par défaut et le propriétaire de l'image des kits, de sorte qu'un kit publié nomme toujours l'image poussée avec lui. `IMAGE_OWNER=<compte>` publie sous un autre compte.
124+Avec les deux variables, le script se connecte avec elles et se déconnecte à la fin ; sans elles, il réutilise votre `docker login` existant. Ses deux moitiés se lancent seules : `PUSH=1 ./docker-sbx/build.sh v0.0.3` (l'image) et `./docker-sbx/push-kits.sh v0.0.3` (les kits, `SBX=/chemin/vers/sbx` si la CLI n'est pas sur le PATH). Les deux appellent d'abord `sync-kits.sh`, qui réécrit `version`, le `tag` par défaut et le propriétaire de l'image des kits, de sorte qu'un kit publié nomme toujours l'image poussée avec lui — commitez ensuite les deux `spec.yaml`. `sbx kit push` parle directement au registre et s'authentifie depuis le magasin d'identifiants Docker, sans démon sandbox. `IMAGE_OWNER=<compte>` publie sous un autre compte.
125125
126126 ## Variantes
127127
@@ -113,15 +113,15 @@ Les deux kits autorisent les ports 12434 et 8080 de l'hôte dans la politique r
113 113
114 ## Publier une version114 ## Publier une version
115 115
116-Le workflow Release (`.github/workflows/release.yml`, job `docker-sandbox`) publie l'image et les kits à chaque tag `v*`, après le job des binaires. Il a besoin de deux secrets du dépôt, exposés au job comme variables d'environnement : `DOCKER_HANDLE`, le compte Docker Hub (aussi le propriétaire de l'image), et `DOCKER_PAT`, un jeton d'accès en lecture/écriture. Il lance ensuite les scripts qu'un portable lancerait :116+La publication est une étape manuelle, depuis une machine avec Docker Desktop (buildx et la CLI `sbx`) ; le workflow Release ne construit que les binaires. Un script construit l'image pour linux/amd64 et linux/arm64, la pousse, puis valide et pousse les deux kits, le tout au tag de mm :
117 117
118 ```bash118 ```bash
119-docker login -u k33g # coller un jeton d'accès119+export DOCKER_HANDLE=k33g # le compte Docker Hub, aussi propriétaire de l'image
120-PUSH=1 ./docker-sbx/build.sh v0.0.2 # buildx, linux/amd64 + linux/arm64, poussée comme k33g/mm-sandbox:0.0.2120+export DOCKER_PAT=dckr_pat_… # un jeton d'accès en lecture/écriture
121-./docker-sbx/push-kits.sh v0.0.2 # sbx kit validate + sbx kit push → k33g/mm-tui:0.0.2, k33g/mm-acp:0.0.2121+./docker-sbx/publish.sh # TAG depuis release.env : v0.0.3 → k33g/mm-sandbox:0.0.3, k33g/mm-tui:0.0.3, k33g/mm-acp:0.0.3
122 ```122 ```
123 123
124-`push-kits.sh` a besoin de la CLI `sbx` sur le PATH (ou `SBX=/chemin/vers/sbx` ; le workflow télécharge l'archive Linux de `docker/sbx-releases`). `sbx kit push` parle directement au registre et s'authentifie depuis le magasin d'identifiants Docker — aucun démon sandbox n'intervient, c'est ce qui le rend utilisable en CI. Les deux scripts appellent d'abord `sync-kits.sh`, qui réécrit `version`, le `tag` par défaut et le propriétaire de l'image des kits, de sorte qu'un kit publié nomme toujours l'image poussée avec lui. `IMAGE_OWNER=<compte>` publie sous un autre compte.124+Avec les deux variables, le script se connecte avec elles et se déconnecte à la fin ; sans elles, il réutilise votre `docker login` existant. Ses deux moitiés se lancent seules : `PUSH=1 ./docker-sbx/build.sh v0.0.3` (l'image) et `./docker-sbx/push-kits.sh v0.0.3` (les kits, `SBX=/chemin/vers/sbx` si la CLI n'est pas sur le PATH). Les deux appellent d'abord `sync-kits.sh`, qui réécrit `version`, le `tag` par défaut et le propriétaire de l'image des kits, de sorte qu'un kit publié nomme toujours l'image poussée avec lui — commitez ensuite les deux `spec.yaml`. `sbx kit push` parle directement au registre et s'authentifie depuis le magasin d'identifiants Docker, sans démon sandbox. `IMAGE_OWNER=<compte>` publie sous un autre compte.
125 125
126 ## Variantes126 ## Variantes
127 127