From 9ae8c28ef4a35bea5aad999030c8d7c33ddee5e2 Mon Sep 17 00:00:00 2001 From: MickaelRoger Date: Thu, 23 Jul 2026 12:43:55 +0200 Subject: [PATCH] fix(runtime): refresh workspace scripts --- AGENTS.md | 2 +- internal/runtime/buildcontext/Dockerfile.workspace | 4 ++++ internal/runtime/runtime_test.go | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index e5bc202..833045e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,7 +51,7 @@ - The npm package name is `@mickaelroger78/opencode-manager`. - The npm package expects prebuilt binaries in `dist/opencode-manager-{linux,darwin}-{x64,arm64}`. - `.github/workflows/pipeline.yml` is the full CI/CD pipeline: it lints (gofmt, vet), runs unit tests, builds the four binaries, and runs a docker + podman integration matrix (`selftest` subcommand: base-image build, workspace creation, and upgrade-survives-reinstall). On push to `main` it publishes the dev channel (npm dist-tag `dev` + `docker.io/mroger78/ocm-base:dev`); on a `vX.Y.Z` tag it publishes the stable channel (npm `latest` + promotes the tested base image to `:X.Y.Z` and `:latest`). npm uses trusted publishing; the base image push needs the `DOCKERHUB_USERNAME`/`DOCKERHUB_TOKEN` secrets. -- The published base image `docker.io/mroger78/ocm-base` is the default `baseImage.name`. Its recipe lives as real files in `internal/runtime/buildcontext/` (`Dockerfile`, `Dockerfile.overlay`, `Dockerfile.workspace`, and the `opencode-manager-attach`/`opencode-manager-entrypoint` scripts). The pipeline publishes `buildcontext/Dockerfile` directly; the binary embeds the directory (`//go:embed`), materializes it to a temp dir, and builds it as a fallback, passing `BASE_IMAGE`, `EXTRA_PACKAGES`, and `EXTRA_COMMANDS` (and `UID`/`GID` for the workspace image) as `--build-arg` values (`baseBuildArgs`/`workspaceBuildArgs` in `internal/runtime/runtime.go`). So the published image and the local build never drift, and there is no Go-generated Dockerfile. `cmd/opencode-manager selftest` is an internal, undocumented integration entrypoint, not part of the public `list`/`attach` CLI. +- The published base image `docker.io/mroger78/ocm-base` is the default `baseImage.name`. Its recipe lives as real files in `internal/runtime/buildcontext/` (`Dockerfile`, `Dockerfile.overlay`, `Dockerfile.workspace`, and the `opencode-manager-attach`/`opencode-manager-entrypoint` scripts). The pipeline publishes `buildcontext/Dockerfile` directly; the binary embeds the directory (`//go:embed`), materializes it to a temp dir, and builds it as a fallback, passing `BASE_IMAGE`, `EXTRA_PACKAGES`, and `EXTRA_COMMANDS` (and `UID`/`GID` for the workspace image) as `--build-arg` values (`baseBuildArgs`/`workspaceBuildArgs` in `internal/runtime/runtime.go`). The workspace recipe also re-copies the manager scripts, so an upgraded manager replaces scripts inherited from a cached base image. `cmd/opencode-manager selftest` is an internal, undocumented integration entrypoint, not part of the public `list`/`attach` CLI. - Built-in module sources live in the repo's top-level `modules/` directory (pure data, no Go files), grouped under a **category** directory: `cloud/aws`, `cloud/outscale`, `infra/kubernetes`, `source-code/git`, `tools/ssh`. The category is the parent directory name (`module.Module.Category`, derived in `module.Load`); `module.Catalog` scans two levels (`///module.yml`) and sorts by category then name. A module is still identified by its globally unique `name`. The TUI shows a category's directory slug sentence-cased (`source-code` → "Source code") via `categoryLabel`. - The category is mirrored in the container mount path (`/opt/opencode-manager/modules//`) and recorded in each `ModuleInstance.Category` in the manifest (with a catalog fallback for pre-category manifests), so install/uninstall/reconcile can find a module's scripts. The TUI editor (`internal/tui/edit.go`) renders modules as a category browser and supports `/` filtering over name/description/category/label. - The built-in `git` module imports host global `user.name`/`user.email` and OpenPGP signing config through its host-side `resolve` hook. If `user.signingkey` exists and the secret key is exportable, the armored secret key is base64-passed only to the container install environment, imported into `~/.gnupg`, and never persisted to the manifest. diff --git a/internal/runtime/buildcontext/Dockerfile.workspace b/internal/runtime/buildcontext/Dockerfile.workspace index 99a49f1..055b6c6 100644 --- a/internal/runtime/buildcontext/Dockerfile.workspace +++ b/internal/runtime/buildcontext/Dockerfile.workspace @@ -11,4 +11,8 @@ ARG GID RUN set -eux; if getent group ${GID}; then group_name=$(getent group ${GID} | cut -d: -f1); else groupadd -g ${GID} debian && group_name=debian; fi; if getent passwd ${UID}; then user_name=$(getent passwd ${UID} | cut -d: -f1); usermod -d /home/debian -s /bin/bash ${user_name}; else useradd -m -u ${UID} -g ${GID} -s /bin/bash debian; user_name=debian; fi; mkdir -p /home/debian/workspace && chown -R ${UID}:${GID} /home/debian RUN echo 'ALL ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/opencode-manager && chmod 0440 /etc/sudoers.d/opencode-manager +# Refresh manager-owned scripts even when the resolved base image is cached. +COPY opencode-manager-attach /usr/local/bin/opencode-manager-attach +COPY opencode-manager-entrypoint /usr/local/bin/opencode-manager-entrypoint +RUN chmod 0755 /usr/local/bin/opencode-manager-attach /usr/local/bin/opencode-manager-entrypoint WORKDIR /home/debian/workspace diff --git a/internal/runtime/runtime_test.go b/internal/runtime/runtime_test.go index cdc0a98..05bc0cd 100644 --- a/internal/runtime/runtime_test.go +++ b/internal/runtime/runtime_test.go @@ -256,6 +256,19 @@ func TestBaseDockerfileModuleSupport(t *testing.T) { } } +func TestWorkspaceDockerfileRefreshesManagerScripts(t *testing.T) { + content := readBuildFile(t, workspaceDockerfile) + for _, want := range []string{ + "COPY opencode-manager-attach /usr/local/bin/opencode-manager-attach", + "COPY opencode-manager-entrypoint /usr/local/bin/opencode-manager-entrypoint", + "chmod 0755 /usr/local/bin/opencode-manager-attach /usr/local/bin/opencode-manager-entrypoint", + } { + if !strings.Contains(content, want) { + t.Fatalf("workspace Dockerfile missing %q:\n%s", want, content) + } + } +} + func TestOverlayDockerfileOnlyAddsExtras(t *testing.T) { content := readBuildFile(t, overlayDockerfile) for _, want := range []string{