From 99663addeea78fefce791d1b917c6659d3631c23 Mon Sep 17 00:00:00 2001 From: Joshua Gilman Date: Sun, 23 Aug 2026 13:27:25 -0700 Subject: [PATCH] chore(repo): complete source-only cutover Remove obsolete executable, image, and publishing machinery. Wire the actual MCP smoke and race suites into Moon and CI, converge CodeMode documentation, and add the Apache-2.0 license. --- .agents/skills/apko/SKILL.md | 187 ---------------- .../skills/apko/references/apko-commands.md | 156 -------------- .agents/skills/melange/SKILL.md | 134 ------------ .../melange/references/melange-commands.md | 151 ------------- .agents/skills/mise/SKILL.md | 93 ++++---- .../skills/mise/references/mise-commands.md | 16 +- .github/repository-settings.toml | 10 +- .github/scripts/test_configure_github_repo.py | 8 +- .github/workflows/ci.yml | 5 +- .github/workflows/release.yml | 77 ------- .github/workflows/security-scan.yml | 83 ------- .gitignore | 16 +- .goreleaser.yaml | 138 ------------ .moon/toolchains.yml | 4 +- .moon/workspace.yml | 5 +- .release-please-manifest.json | 2 +- CHANGELOG.md | 38 ---- CONTRIBUTING.md | 68 +++--- DELETE_ME.md | 150 ------------- LICENSE | 202 ++++++++++++++++++ README.md | 202 ++++++++++-------- SECURITY.md | 33 +-- apko.yaml | 37 ---- docs/docs/index.md | 63 ++++-- docs/mkdocs.yml | 2 +- docs/moon.yml | 2 +- docs/pyproject.toml | 4 +- docs/uv.lock | 22 +- melange.yaml | 26 --- mise.lock | 150 ++----------- mise.toml | 66 ++---- moon.yml | 38 +++- release-please-config.json | 2 +- 33 files changed, 561 insertions(+), 1629 deletions(-) delete mode 100644 .agents/skills/apko/SKILL.md delete mode 100644 .agents/skills/apko/references/apko-commands.md delete mode 100644 .agents/skills/melange/SKILL.md delete mode 100644 .agents/skills/melange/references/melange-commands.md delete mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/security-scan.yml delete mode 100644 .goreleaser.yaml delete mode 100644 DELETE_ME.md create mode 100644 LICENSE delete mode 100644 apko.yaml delete mode 100644 melange.yaml diff --git a/.agents/skills/apko/SKILL.md b/.agents/skills/apko/SKILL.md deleted file mode 100644 index 5812093..0000000 --- a/.agents/skills/apko/SKILL.md +++ /dev/null @@ -1,187 +0,0 @@ ---- -name: apko -description: > - Assemble the runtime OCI image for template-go with apko (`apko.yaml`) — the - Dockerfile-free, multi-arch, nonroot image built from the melange-produced apk plus a - minimal Wolfi base. Use when changing image contents, the `image-local` mise task, the - `apko build`/`apko publish` steps in `.github/workflows/release.yml` or - `security-scan.yml`, runtime packages, the nonroot user, OCI annotations, or the - per-build SBOM. Pairs with the `melange` skill (the apk) and the `mise` skill (the CLI). ---- - -# apko - -apko owns exactly one step in this repo: turn the melange-built apk plus a small set of -Wolfi base packages into the runtime image. It is the modern, distroless-equivalent -replacement for `gcr.io/distroless/static-debian12:nonroot` — no Dockerfile, no `RUN`, no -shell. The entire image is declared in `apko.yaml`; everything else (signing, attestation, -the apk itself) belongs to adjacent tools. - -## Verified against - -- apko `v1.2.19` (pinned in `mise.toml` as `aqua:chainguard-dev/apko`, locked in `mise.lock`). -- Grounded in the local `apko --help` for this version and the repo files - (`apko.yaml`, `mise.toml`, `.github/workflows/release.yml`, - `.github/workflows/security-scan.yml`), not from memory. -- Run apko through mise so the pinned binary is used: `mise exec -- apko --help`. - -## Use this skill when - -- Adding or removing a runtime dependency (a Wolfi package in `contents.packages`). -- Editing the nonroot account, entrypoint, archs, or OCI annotations in `apko.yaml`. -- Touching `apko build`/`apko publish` in the release or security-scan workflows, or the - `image-local` mise task. -- Debugging the published image (wrong arch set, missing apk, untrusted `@local` package, - SBOM directory errors). - -## apko's lane (do not cross it) - -1. The image is defined **only** in `apko.yaml`. There is no Dockerfile and there must not - be one. Never add `RUN`, `apt`, `apk add`, shell steps, or a base-image `FROM`. -2. Add a runtime dependency by adding a **Wolfi package** to `contents.packages` — nothing - else. Keep the set minimal; every package is CVE surface in a distroless image. -3. apko consumes the apk; it never builds it. Source → apk is the `melange` skill's job. If - the app changed, rebuild the apk first, then apko. -4. apko does not sign or attest. `cosign sign` and the `attest.yml` provenance are separate - release steps. Do not fold them into apko invocations. -5. Keep it nonroot. The image runs as uid/gid 65532 with no shell; do not add a shell, - package manager, or root entrypoint for convenience. -6. Do not reintroduce `apko.lock.json` / `apko lock`. The Wolfi base floats by design (see - below). Pinning is recorded in the per-build SBOM + provenance, not a committed lockfile. - -## How the image is wired (`apko.yaml` anatomy) - -Read `apko.yaml` before changing anything. The load-bearing parts: - -- `contents.repositories`: the Wolfi os repo **and** `@local ./packages`. The `@local` - repository is melange's output directory — that is how the just-built apk is found. -- `contents.keyring`: the Wolfi signing key URL. The **ephemeral melange public key(s)** are - not listed here; they are appended at build/publish time with `--keyring-append` and are - never committed. Without the matching pub key in the keyring, apko refuses the `@local` - apk as unsigned. -- `contents.packages`: `wolfi-baselayout`, `ca-certificates-bundle`, `tzdata`, and - `template-go@local`. The `@local` suffix pins the package to the `@local` repository, - i.e. the apk melange just built (not anything from the Wolfi index). -- `accounts`: defines group+user `nonroot` (gid/uid **65532**) and `run-as: 65532`. Wolfi has - no `nonroot` package, so the user is created here. This mirrors `distroless:nonroot`. -- `entrypoint.command: /usr/bin/template-go` — where the `go/build` melange pipeline - installs the binary. -- `archs: [amd64, arm64]` — the index architectures. -- `annotations`: OCI labels. `org.opencontainers.image.version` carries the - `# x-release-please-version` marker; release-please bumps it. Do not hand-edit it. - -## Local build (the `image-local` mise task) - -`mise run image-local` builds a single host-arch image and loads it into Docker as -`template-go:dev` for local running/inspection. The apko step is: - -```bash -apko build apko.yaml template-go:dev image.tar \ - --arch "$arch" \ - --keyring-append ./melange.rsa.pub -docker load < image.tar -docker tag "template-go:dev-$arch" template-go:dev -``` - -Non-obvious points: - -- **The retag is required, not cosmetic.** A single-arch `apko build` loads into Docker under - an arch-suffixed tag (`template-go:dev-amd64` / `-arm64`, using the Go arch name from - `go env GOARCH`). The task retags to the plain `template-go:dev` so it is easy to - `docker run`. `security-scan.yml` does the same (`...:security-scan-amd64` → `...:security-scan`). -- `apko build` writes a tarball for `docker load`. The positional output can also be an - `oci-layout-dir/`, but the repo uses a `.tar`. -- `--keyring-append ./melange.rsa.pub` makes apko trust the locally-signed `@local` apk. The - local task mints one ephemeral key (`melange.rsa`); only its single pub key is appended. -- `--arch "$arch"` uses the explicit Go arch name. `host` is also accepted by apko, but the - task passes the resolved value. -- melange must have run first (`packages/` must contain the apk). The task does this in order; - if you run apko by hand, build the apk first — see the `melange` skill. - -## CI publish (`release.yml` → multi-arch index) - -The `container-image-release` job assembles and pushes the multi-arch image: - -```bash -mkdir -p sbom # apko does NOT create --sbom-path; it must pre-exist -apko publish apko.yaml "$IMAGE_TAG" \ - --arch amd64,arm64 \ - --keyring-append ./melange-amd64.rsa.pub \ - --keyring-append ./melange-arm64.rsa.pub \ - --sbom-path ./sbom \ - | tee apko-out.txt -``` - -Non-obvious points: - -- **`--sbom-path` must pre-exist.** apko moves SBOMs into the directory but does not create - it; a missing `sbom/` is a real release failure (baked-in `mkdir -p sbom` guards it). -- **Two keyring keys.** Each arch's apk was signed on its own native runner with its own - ephemeral key, so both `melange-amd64.rsa.pub` and `melange-arm64.rsa.pub` must be appended; - apko verifies each per-arch apk against the matching key. -- **`docker login` is a precondition.** `apko publish` authenticates via the Docker keychain. - release.yml runs `docker/login-action` against `ghcr.io` first; without it, the push fails. -- **The digest is parsed from stdout.** apko prints the published refs/digest; release.yml - greps `sha256:[0-9a-f]{64}` and takes the last match. `--image-refs ` can write the - refs to a file instead, but the repo parses stdout. -- The image is pushed even while the GitHub release is still a draft — GHCR has no draft - state. That is expected. -- apko emits its own SBOM (`--sbom-path ./sbom`, spdx by default). The **attested** image SBOM - is generated separately by `syft -o spdx-json` and attached with `actions/attest-sbom`. - Two different SBOMs; do not conflate them. - -After publish, release.yml (adjacent steps, not apko's job): verifies the manifest is exactly -`linux/amd64,linux/arm64` via `docker buildx imagetools inspect`, smoke-tests `--version` and -`--message`, then `cosign sign --yes` (keyless), syft SBOM attestation, and finally the -isolated `attest.yml` SLSA-L3 provenance. - -## Multi-arch model - -apko does not emulate. It assembles a 2-arch index from per-arch apks that **melange already -built natively** (amd64 on `ubuntu-24.04`, arm64 on `ubuntu-24.04-arm`, no QEMU). The -`archs:` in `apko.yaml` and `--arch amd64,arm64` must line up with the apks present under -`packages/` (Wolfi arch dirs `x86_64`/`aarch64`). If an arch's apk is missing, publish fails. - -## Read-only inspection - -Use these to reason about the image without building it: - -```bash -apko show-config apko.yaml # the fully-derived config apko will act on -apko show-packages apko.yaml # exact packages + versions that would install -``` - -`show-packages` resolves the live Wolfi index, so it shows what the floating base would pull -right now — the right tool to preview a CVE bump or confirm a new package resolves. Both -accept `--keyring-append`/`--repository-append` if you need them to see the `@local` apk. - -## Why `apko lock` is deliberately unused - -`apko lock` exists (it writes a `.lock.json` of pinned package versions) but the repo does not -use it, on purpose: - -- The app package is a per-build `@local` apk; a committed lock would pin a stale/foreign - checksum for it. -- The Wolfi base (`ca-certificates-bundle`, `tzdata`, …) is meant to float to latest for a - fresh CA bundle/timezones and low CVE surface. Pinning fights that model. -- Reproducibility comes from recording the exact resolved versions in the per-build SBOM + - provenance attestation, not from a lockfile. Do not add `apko.lock.json`. - -## Gotchas - -- Single-arch `apko build` Docker-loads under an **arch-suffixed tag**; retag before using it. - (The suffix is the value passed to `--arch`; the repo passes the Go arch name, e.g. - `-amd64`, not the Wolfi `-x86_64`.) -- `--sbom-path` directory must already exist. -- `--keyring-append` is mandatory for the `@local` apk and must cover **every** arch being - published. -- `apko publish` needs a prior `docker login`; `apko build` (tarball) does not. -- `org.opencontainers.image.version` in `apko.yaml` is release-please-owned — never hand-edit. -- Adding a runtime dep means a Wolfi package in `contents.packages`, then rebuild the apk and - the image. There is no Dockerfile to edit. -- apko is pinned by mise; invoke it via `mise exec -- apko …` (or a mise task / shimmed PATH), - not a system install. Bumping apko is a `mise.toml` + `mise lock` change — see the `mise` - skill. - -See [references/apko-commands.md](references/apko-commands.md) for the version-stamped command -and flag reference. diff --git a/.agents/skills/apko/references/apko-commands.md b/.agents/skills/apko/references/apko-commands.md deleted file mode 100644 index b2e590e..0000000 --- a/.agents/skills/apko/references/apko-commands.md +++ /dev/null @@ -1,156 +0,0 @@ -# apko Command Map - -Curated operator reference for `apko v1.2.19` (pinned in `mise.toml` as -`aqua:chainguard-dev/apko`, locked in `mise.lock`). Prefer local `--help` -(`mise exec -- apko --help`) and the official docs if anything here drifts. Only the -flags this repo uses, plus the few an operator reaches for, are listed — every flag below is -real and correctly spelled/typed for this version. - -## Global flags - -Apply to every `apko` subcommand: - -- `--log-level `: `debug|info|warn|error|fatal|panic` (default `INFO`). -- `-C, --workdir `: working directory (default is the current dir). apko searches for - config, base image, and `@local` paths relative to this. -- `-h, --help`. - -## `apko build` - -Purpose: build an image from `apko.yaml` into a `docker load`-able tarball (or an -`oci-layout-dir/`). Used by the `image-local` mise task and `security-scan.yml`. - -Usage: - -```bash -apko build [flags] -``` - -Flags that matter here: - -- `--arch `: architectures to build (e.g. `amd64`, `x86_64`, or `amd64,arm64`). - Accepts `host` for the host arch. Default is all archs in the config. The repo passes a - single resolved arch for local/scan builds. -- `-k, --keyring-append `: extra public keys to trust. **Required** here to trust the - ephemeral melange-signed `@local` apk (`--keyring-append ./melange.rsa.pub`). Repeatable. -- `--sbom`: generate SBOMs (default `true`; disable with `--sbom=false`). -- `--sbom-path `: write SBOMs to this dir (default: the image dir). Must already exist. -- `--sbom-formats `: SBOM formats (default `[spdx]`). -- `--annotations `: OCI annotations as `key:value` (colon-separated). The repo - declares annotations in `apko.yaml` instead. -- `-r, --repository-append `: extra package repositories. -- `-b, --build-repository-append `: extra repositories used only at build time. -- `-p, --package-append `: extra packages beyond `contents.packages`. -- `--build-date `: timestamp (RFC3339) for files inside the image. Repo relies on the - default; set only when you need a specific reproducible timestamp. -- `--offline`: do not fetch packages (cache must be pre-populated). -- `--cache-dir `: apk/index cache directory. -- `--lockfile `: constrain package versions to a `.lock.json`. Not used here (see the - SKILL on why `apko lock` is avoided). -- `--include-paths `: extra paths to resolve input files from. -- `--ignore-signatures`: skip repository signature verification. Do not use; it defeats the - `@local`/Wolfi signing checks. - -Notes: - -- A single-arch build loads into Docker under an **arch-suffixed tag** (`-`, Go arch - name). Retag to the plain `` before running it. -- `build` has **no** `--local` or `--image-refs` flag — those are `publish`-only. - -## `apko publish` - -Purpose: build **and push** the (multi-arch) image to a registry, printing the published -refs/digest to stdout. Used by `release.yml` (`container-image-release`). - -Usage: - -```bash -apko publish [flags] -``` - -Flags that matter here: - -- `--arch `: architectures for the index. Repo uses `--arch amd64,arm64`; must match - the per-arch apks present under `packages/`. -- `-k, --keyring-append `: trust keys. Repo appends **both** ephemeral melange pub - keys (`./melange-amd64.rsa.pub`, `./melange-arm64.rsa.pub`) — one per arch. Repeatable. -- `--sbom-path `: write SBOMs here. **apko does not create this dir** — `mkdir -p` - it first (real release bug otherwise). -- `--sbom` (default `true`; `--sbom=false` to disable), `--sbom-formats ` (default `[spdx]`). -- `--image-refs `: write the published refs to a file. Repo parses stdout instead. -- `--local`: publish only to the local Docker daemon (no registry push). Not used here. -- `--annotations `: OCI annotations `key:value`. Repo uses `apko.yaml`. -- `-r, --repository-append` / `-b, --build-repository-append` / `-p, --package-append`: as in - `build`. -- `--build-date`, `--offline`, `--cache-dir`, `--lockfile`, `--ignore-signatures`: as in - `build`. - -Notes: - -- Authenticates via the **Docker keychain** — run `docker login ` first. -- Accepts multiple `` positionals; the repo passes one version tag. -- Pushes even while the GitHub release is a draft (GHCR has no draft state). - -## `apko show-config` - -Purpose: print the fully-derived config apko will act on (YAML). Read-only. - -Usage: - -```bash -apko show-config [flags] -``` - -Flags: `-k, --keyring-append`, `-r, --repository-append`, `-b, --build-repository-append`, -`--offline`, `--cache-dir`. No `--arch`. - -## `apko show-packages` - -Purpose: resolve and print the exact packages + versions that would install, without building. -Best preview of what the floating Wolfi base pulls right now (CVE bumps, new packages). - -Usage: - -```bash -apko show-packages [flags] -``` - -Flags that matter here: - -- `--arch `: which arch's resolution to show (accepts `host`). -- `--format `: predefined name (e.g. `name-version`, `name=version`, `packagelock`, - `packagelock-source`) or a Go template over `.Name`, `.Version`, `.Source` (default - `{{ .Name }} {{ .Version }}`). `packagelock`/`packagelock-source` emit a YAML-list-ready form. -- `-k, --keyring-append`, `-r, --repository-append`, `-b, --build-repository-append`, - `--offline`, `--cache-dir`. Append the melange pub key if you need it to resolve `@local`. - -## `apko lock` - -Exists but intentionally **not used** in this repo (see the SKILL). Writes a `.lock.json` that -pins package versions. - -Usage: - -```bash -apko lock [flags] -``` - -Flags: `--arch`, `--output ` (lockfile path), `-k, --keyring-append`, -`-r, --repository-append`, `-b, --build-repository-append`, `--cache-dir`, -`--include-paths`, `--ignore-signatures`. Do not add `apko.lock.json` to this repo. - -## `apko version` - -Purpose: print the apko version. - -Usage: - -```bash -apko version [--json] -``` - -## Other subcommands (not used here) - -`build-minirootfs`, `clean`, `dot`, `install-keys`, `login`, `completion`, `help`. `apko login` -can authenticate to a registry, but the repo relies on `docker login` + the Docker keychain. -`apko dot` (dependency digraph) and `apko clean` (cache) are occasional debugging aids. diff --git a/.agents/skills/melange/SKILL.md b/.agents/skills/melange/SKILL.md deleted file mode 100644 index 4434bb8..0000000 --- a/.agents/skills/melange/SKILL.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -name: melange -description: > - Build the project's signed Wolfi apk with melange. Use when editing melange.yaml or its - go/build pipeline, changing how version/commit/date are stamped into the binary, adding a - build-time package, signing the apk, or debugging `mise run image-local` or the release - `melange-build` job. This is the source-to-signed-apk step that apko later turns into the image. ---- - -# Melange - -melange has exactly one job in this repo: compile the Go binary into a signed -[Wolfi](https://github.com/wolfi-dev) apk described by `melange.yaml`. That apk is the only -artifact apko assembles into the runtime image. There is no Dockerfile. Ground every command -in `--help` and the repo files below, not memory. - -## Verified against - -- melange `v0.54.0` (GitCommit `7fb1d6a`), pinned in `mise.toml` as - `aqua:chainguard-dev/melange = "0.54.0"` and locked per-platform in `mise.lock`. Run it via - mise (`mise exec -- melange ...`) or an activated shell; do not install it any other way. -- Grounded in local `melange --help` / `melange build --help` and the repo files: `melange.yaml`, - `mise.toml` (`[tasks.image-local]`), `.github/workflows/release.yml`, `release-dry-run.yml`, - and `security-scan.yml`. -- Sibling skills: `mise` provisions melange and puts it on PATH; `apko` consumes the apk this - step produces. See those skills for their lanes. - -## Use this skill when - -- Editing `melange.yaml` or the `go/build` pipeline. -- Changing how `version` / `commit` / `date` reach the binary. -- Adding a build-time package or toolchain to the apk. -- Signing an apk or reasoning about the melange-to-apko key handoff. -- Debugging a failed `mise run image-local` or the release/dry-run melange build job. - -## melange's lane (non-negotiable) - -1. melange does ONE thing: source to signed Wolfi apk. It does not build the image (that is - apko) and it does not push anything anywhere. -2. The apk is the single artifact. apko reads it from `./packages` via `@local`; nothing else - consumes, tags, or distributes it. -3. Never hand-edit `package.version` in `melange.yaml`. It carries `# x-release-please-version` - and release-please owns it. Do not run `melange bump` in this repo. -4. Inject `version` / `commit` / `date` ONLY through `--vars-file`. Never edit the `ldflags` - line per build and never add date math inside the sandbox. The defaults under `vars:` - (`0.0.0` / `none` / `unknown`) exist only so a bare build does not fail. -5. Never commit signing keys. `melange*.rsa`, `melange*.rsa.pub`, `melange-vars.yaml`, - `.melange-vars.local.yaml`, and `/packages/` are gitignored. Keys are ephemeral, minted per - build; the private key never leaves the machine that built the apk. -6. No Dockerfile, no `RUN`, no `apt`. Build-time tools come from - `environment.contents.packages` (the `go-1.26` Wolfi package). Runtime dependencies belong - in `apko.yaml`, not here. -7. Always pass `--runner docker`. Do not rely on the platform default runner. - -## melange.yaml anatomy - -- `package`: `name: template-go`, `version: "0.1.1"` (release-please marker), `epoch: 0`. -- `environment.contents`: the Wolfi `os` repository + its signing keyring, plus - `packages: [go-1.26]` (the build toolchain). `environment.environment.CGO_ENABLED: "0"`. -- `vars`: build-time defaults overridden by `--vars-file`. -- `pipeline: - uses: go/build` with `packages: ./cmd/template-go`, - `output: template-go`, `go-package: go-1.26`, `modroot: .`, `strip: "-s -w"`, the - `ldflags` that stamp `main.version/commit/date` from `${{vars.*}}`, and - `extra-args: "-mod=readonly -buildvcs=false"`. The `go/build` builtin auto-adds `-trimpath` - and installs to `/usr/bin/` — apko's entrypoint `/usr/bin/template-go` depends on - that path. The module source mounts in from `--source-dir`. - -## Build the apk locally - -`mise run image-local` is the supported local path; it runs melange then apko. The melange -portion is: - -```bash -melange keygen melange.rsa -printf 'version: "dev"\ncommit: "%s"\ndate: "%s"\n' \ - "$(git rev-parse --short HEAD)" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > .melange-vars.local.yaml -melange build melange.yaml \ - --arch "$(go env GOARCH)" \ - --runner docker \ - --signing-key melange.rsa \ - --source-dir . \ - --vars-file .melange-vars.local.yaml -``` - -This drops a signed apk under `./packages//` (default `--out-dir` is `./packages/`). -`` is the Wolfi arch name, not the Go arch: `amd64` to `x86_64`, `arm64` to `aarch64`. -apko then reads the whole `./packages` directory as the `@local` repository. - -## How the release / CI build differs - -`release.yml` (`melange-build`) and `release-dry-run.yml` run the same `melange build` -invocation under a matrix, one arch per NATIVE runner — `amd64` on `ubuntu-24.04`, `arm64` on -`ubuntu-24.04-arm`. No QEMU. Differences from local: - -- Each runner mints its own ephemeral key with a distinct name: `melange keygen melange-.rsa`. -- The vars file (`melange-vars.yaml`) carries the real release `version`, the full - `git rev-parse HEAD`, and the committer date `git show -s --format=%cI HEAD`. -- Each runner uploads `packages//**` plus its `melange-.rsa.pub`. The private key - never leaves the runner; apko later trusts the apk via the uploaded public keys. - -`security-scan.yml` builds only `amd64` for the weekly Trivy scan — the same -`melange build`, but it mints a single `melange.rsa` key (not the per-arch -`melange-.rsa` naming above). - -## Signing and the apko handoff - -`--signing-key` signs the apk during the build. apko must trust that signature to install the -`@local` apk, so the matching public key is appended to apko's keyring with -`--keyring-append`. Locally that is `--keyring-append ./melange.rsa.pub`; in the release job apko -appends both arches' keys (`./melange-amd64.rsa.pub`, `./melange-arm64.rsa.pub`). Omit the public -key and apko rejects the apk as untrusted. See the `apko` skill. - -## Gotchas - -- `--runner docker` is required wherever melange runs: it needs a Linux build sandbox, and on - macOS/Docker Desktop the Docker runner provides it. Docker must be running. Valid runners are - `bubblewrap`, `docker`, `qemu`; this repo always uses `docker`. -- Wolfi arch name is not the Go arch in output paths: `amd64`→`x86_64`, `arm64`→`aarch64`. Match - these when globbing `packages//**`. -- melange produces an SBOM for the apk (`--namespace` sets its package-URL namespace). The - image-level SBOM and SLSA provenance are produced later by syft + `attest.yml`, NOT by melange. - Do not add `--generate-provenance` to chase that; the repo does not use it. -- Build metadata flows version/commit/date through `--vars-file` into `ldflags` only. Neither - local nor CI uses melange's `--build-date` flag (that controls in-image file timestamps for - reproducibility, a different concern from the ldflag date). -- Do not override `output:` in the pipeline without updating `apko.yaml`'s `entrypoint.command` - and `contents.packages` — the binary path `/usr/bin/template-go` is contractual. -- To add a build-time tool or a different Go toolchain, edit `environment.contents.packages` - (Wolfi package names) in `melange.yaml`. Do not install inside the sandbox. - -## Command reference - -See [references/melange-commands.md](references/melange-commands.md) for the version-stamped -command and flag reference. diff --git a/.agents/skills/melange/references/melange-commands.md b/.agents/skills/melange/references/melange-commands.md deleted file mode 100644 index 5496380..0000000 --- a/.agents/skills/melange/references/melange-commands.md +++ /dev/null @@ -1,151 +0,0 @@ -# Melange Command Map - -Curated operator reference for `melange v0.54.0`. Prefer local `melange --help` / -`melange --help` output and the official docs (https://github.com/chainguard-dev/melange) -if anything here drifts. Every flag below is copied from the pinned version's `--help`; flags -not used by this repo are marked so. - -## Global flags - -Apply across all `melange` commands: - -- `--log-level string`: log level — `debug`, `info`, `warn`, `error` (default `INFO`). -- `-h`, `--help`: help for the command. - -## `melange build` - -Purpose: build a package (the signed apk) from a YAML configuration file. This is the repo's -core operation. - -Usage: - -```bash -melange build [config.yaml] [flags] -``` - -Flags that matter here: - -- `--arch strings`: architectures to build for (e.g. `x86_64,arm64`). The repo passes a single - Go-style arch per invocation (`amd64` or `arm64`); default is all arches in the config. -- `--runner string`: runner used to execute build steps — `bubblewrap`, `docker`, or `qemu`. - The repo always passes `docker` (required on macOS; needs Docker running). -- `--signing-key string`: key used to sign the produced apk. -- `--source-dir string`: directory of included sources mounted into the build (the repo passes - `.` so the module source compiles in). -- `--vars-file string`: file of preloaded build vars; overrides `vars:` in the config. The repo - injects `version` / `commit` / `date` this way. -- `-k`, `--keyring-append strings`: extra keys to include in the build environment keyring (for - pulling from signed repositories; the apko keyring handoff is a separate concern). -- `--out-dir string`: directory packages are written to (default `./packages/`). The apk lands - in `//`, where the Wolfi arch is `x86_64`/`aarch64`, not `amd64`/`arm64`. -- `-r`, `--repository-append strings`: extra repositories for the build environment. -- `--package-append strings`: extra packages to install into the build environment. -- `--namespace string`: namespace for package URLs in the generated apk SBOM (default `unknown`). -- `--generate-index`: whether to generate `APKINDEX.tar.gz` (default `true`). -- `--cache-dir string`: cached inputs directory (default `./melange-cache/`). -- `--debug`: enable debug logging of build pipelines. -- `--debug-runner`: keep the builder container after success/failure for inspection. -- `-i`, `--interactive`: attach a tty to the builder pod on failure. - -Not used by this repo (do not add without reason): - -- `--generate-provenance`: emits SLSA provenance as a separate `.attest.tar.gz` next to the apk. - This repo produces image-level provenance via `attest.yml` instead, so this stays off. -- `--build-date string`: timestamp for files inside the image (reproducibility). Distinct from - the ldflag `date`, which comes from `--vars-file`. The repo leaves this at default. - -Notes: - -- Canonical repo invocation: `melange build melange.yaml --arch --runner docker - --signing-key .rsa --source-dir . --vars-file .yaml`. -- The output public key (the `.rsa.pub` matching `--signing-key`) is handed to `apko build` / - `apko publish` via `--keyring-append` so apko trusts the `@local` apk. - -## `melange keygen` - -Purpose: generate an RSA keypair for package signing. - -Usage: - -```bash -melange keygen [key.rsa] [flags] -``` - -Flags: - -- `--key-size int`: size of the RSA key in bits (default `4096`). - -Notes: - -- Writes `.rsa` (private) and `.rsa.pub` (public). In this repo keys are ephemeral - and gitignored; CI uses per-arch names (`melange-amd64.rsa`, `melange-arm64.rsa`). - -## `melange sign` - -Purpose: sign an existing `.apk` on disk in place with the provided key. - -Usage: - -```bash -melange sign [--signing-key=key.rsa] package.apk -melange sign [--signing-key=key.rsa] *.apk -``` - -Flags: - -- `-k`, `--signing-key string`: signing key (default `local-melange.rsa`). - -Notes: - -- The repo signs during `build` via `--signing-key`, so this standalone command is rarely - needed. Use it only to re-sign a prebuilt apk. - -## `melange sign-index` - -Purpose: sign an APK repository index (`APKINDEX.tar.gz`). - -Usage: - -```bash -melange sign-index [--signing-key=key.rsa] -melange sign-index [--signing-key=key.rsa] --force -``` - -Flags: - -- `-f`, `--force`: overwrite the existing index with a newly signed one. -- `--signing-key string`: signing key (default `melange.rsa`). - -Note: the default key name here (`melange.rsa`) differs from `sign`'s default -(`local-melange.rsa`). Not part of the repo's build flow. - -## `melange package-version` - -Purpose: print the target package id for a config, i.e. -`{{ .Package.Name }}-{{ .Package.Version }}-r{{ .Package.Epoch }}`. - -Usage: - -```bash -melange package-version [config.yaml] -``` - -Notes: - -- Read-only; useful for scripting the expected apk filename. It is sugar over `melange query`. - -## `melange bump` - -Purpose: update a melange YAML to a new package version. - -Notes: - -- Do NOT use in this repo. `package.version` carries `# x-release-please-version` and is owned - by release-please. Flags are not captured here; run `melange bump --help` if ever needed - outside this repo. - -## Other subcommands (present, unused here) - -`compile`, `index`, `initramfs`, `license-check`, `lint` (experimental), `query`, `scan`, -`source`, `test`, `update-cache`, `version`, `completion`. None are part of the repo's build -path; consult `melange --help` before relying on any of them. diff --git a/.agents/skills/mise/SKILL.md b/.agents/skills/mise/SKILL.md index 3475926..532c5f8 100644 --- a/.agents/skills/mise/SKILL.md +++ b/.agents/skills/mise/SKILL.md @@ -2,39 +2,36 @@ name: mise description: > Operate mise as the single source of truth for tool versions and integrity in - template-go. Use when touching mise.toml or mise.lock, bumping or adding a pinned - tool (go, python, uv, golangci-lint, moon, melange, apko, cosign), resolving - "command not found"/PATH problems, fixing locked/trust failures, or wiring mise - into moon, the CI workflow, or the local container task. + CodeMode. Use when touching mise.toml or mise.lock, bumping or adding a pinned + tool (go, python, golangci-lint, mockery, uv, moon, gh), resolving "command not + found"/PATH problems, fixing locked/trust failures, or wiring mise into moon and + the CI workflow. --- # mise mise owns the lifecycle of every pinned tool and the project's tool-related env in -this repo. It replaced Proto (`.prototools`, `.moon/proto/*`). Treat `mise.toml` + -`mise.lock` as the only place a toolchain version is declared; everything else -(moon, CI, the container build) consumes what mise puts on PATH. +this repo. Treat `mise.toml` + `mise.lock` as the only place a toolchain version is +declared; everything else (moon, CI) consumes what mise puts on PATH. ## Verified against -- `mise 2026.6.14` (`macos-arm64`), grounded in the captured `--help` for - `install/use/ls/lock/exec/run/trust/outdated/upgrade/settings/current/activate/env/which` - and `mise doctor --help`, plus this repo's `mise.toml`, `mise.lock`, `moon.yml`, - `.moon/toolchains.yml`, `.github/workflows/ci.yml`, and `README.md`. -- Advice is grounded in the local CLI and these files, not memory. Re-verify on a - mise minor/major bump. +- `mise 2026.7.17` (`macos-arm64`) for the lock/trust workflow below, and this + repo's `mise.toml`, `mise.lock`, `moon.yml`, `.moon/toolchains.yml`, and + `.github/workflows/ci.yml`. +- The command map in `references/mise-commands.md` is a `--help` capture from + `mise 2026.6.14`, the version CI installs. Re-verify on a mise minor/major bump. ## Use this skill when - Bumping or adding a tool, or reviewing a diff that touches `mise.toml`/`mise.lock`. - A tool is missing from PATH, or `mise install` fails closed under `locked`. - mise prompts for trust (commonly inside a `.wt/` worktree that nests under the repo). -- Explaining how moon, `ci.yml`, or `mise run image-local` get their binaries. +- Explaining how moon or `ci.yml` get their binaries. ## mise's lane (non-negotiables) -mise manages **tool + env lifecycle only**, plus the one local container task below. -State these as rules: +mise manages **tool + env lifecycle only**. State these as rules: 1. mise is **not the task runner and not the CI gate** — that is moon. Do not move build/lint/test into mise tasks. @@ -46,18 +43,18 @@ State these as rules: backend resolves without a recorded checksum — never let a tool land that way. 4. **Bump = edit `mise.toml`, then `mise lock`, then commit both together.** Never hand-edit `mise.lock` (`# @generated`) and never commit one without the other. -5. The only mise *task* in this repo is `image-local` (a local container convenience). - Do not add general-purpose tasks here. +5. This repo defines **no mise tasks**. Do not add them; tasks belong in `moon.yml`. ## How mise is wired here `mise.toml`: -- `[tools]`: `go = "1.26.4"`, `python = "3.14.3"` (core backends), and six CLIs - pinned via explicit `aqua:` refs (`golangci/golangci-lint`, `astral-sh/uv`, - `moonrepo/moon`, `chainguard-dev/melange`, `chainguard-dev/apko`, `sigstore/cosign`). +- `[tools]`: `go = "1.26.6"`, `python = "3.14.3"` (core backends), and five CLIs + pinned via explicit `aqua:` refs — `golangci/golangci-lint` (format + lint), + `vektra/mockery` (generated mocks, per AGENTS.md T2/T3), `astral-sh/uv` (the + MkDocs toolchain), `moonrepo/moon` (task runner), and `cli/cli` (`gh`). - `[env] GOTOOLCHAIN = "local"`: never auto-download a Go toolchain other than the - pinned one; matches `go.mod`'s `go 1.26.4`. mise `[env]` is **not** carried by the + pinned one; matches `go.mod`'s `go 1.26.6`. mise `[env]` is **not** carried by the CI action's shims, so `ci.yml` also sets `GOTOOLCHAIN: local` at job level — keep both in sync. - `[settings] lockfile = true` (read/write `mise.lock`) and `locked = true` (the @@ -67,18 +64,16 @@ moon consumes mise, it does not duplicate it: `.moon/toolchains.yml` declares no language toolchain and `moon.yml` sets `toolchains.default: system`, so every moon task command is a bare binary (`go`, `golangci-lint`) resolved from PATH. `moon.yml` also lists `mise.toml` + `mise.lock` as inputs (via the `goSources`/`lintConfig` -groups) of build/format/lint/test, so a tool bump re-triggers those tasks and -invalidates the result cache of the cacheable one (build; format/lint/test already -run with `cache: false`). See the `worktrunk` skill for worktree mechanics and the -`melange`/`apko` skills for the container build those pinned tools feed. +groups), so a tool bump re-triggers those tasks and invalidates the result cache of +the cacheable one (`build`; `format`, `lint`, `test`, `mcp-smoke`, `race`, and +`check` all run with `cache: false`). See the `worktrunk` skill for worktree +mechanics. CI (`.github/workflows/ci.yml`) installs via `jdx/mise-action@… with: version: 2026.6.14, cache: true`. The action installs every tool from `mise.toml` honoring `mise.lock` (locked → fail closed), including `moon`, and prepends the shim dir to PATH so moon's `system` tasks find the -binaries. CI uses mise-action, **not** `moonrepo/setup-toolchain`. (The -publishing pipeline — `release.yml`'s mise-action steps — sets `cache: false` so a -poisoned Actions cache can't influence the toolchain that builds/signs artifacts.) +binaries. CI uses mise-action, **not** `moonrepo/setup-toolchain`. ## The lockfile, precisely @@ -90,15 +85,14 @@ of the four platforms: `linux-x64`, `linux-arm64`, `macos-x64`, `macos-arm64`. `url` per platform** and fails closed otherwise (per `mise install --help`: it prevents API calls to GitHub/aqua at install time). - Every entry in this repo also carries `checksum = "sha256:…"`, which is enforced. - (Tools that publish no upstream checksum — e.g. sqlc — would carry a `url` but no - `checksum`; none of this repo's pinned tools are in that situation, so a missing - checksum here would be unexpected, not normal.) -- A subset additionally records a `provenance` field, reflecting the verification - the aqua registry applies for that tool: `provenance = "github-attestations"` on - `uv`, `golangci-lint`, and `python`; `provenance = "cosign"` on `cosign`. The - remaining tools (`go`, `melange`, `apko`, `moon`) carry no `provenance` field. Do - **not** claim every tool is attestation-verified; the always-on guarantees are the - pinned `url` and the `checksum`. + (Tools that publish no upstream checksum would carry a `url` but no `checksum`; + none of this repo's pinned tools are in that situation, so a missing checksum here + would be unexpected, not normal.) +- A subset additionally records `provenance = "github-attestations"`, reflecting the + verification the aqua registry applies for that tool: `uv`, `gh`, `golangci-lint`, + and `python`. The remaining tools (`go`, `moon`, `mockery`) carry no `provenance` + field. Do **not** claim every tool is attestation-verified; the always-on + guarantees are the pinned `url` and the `checksum`. ## Bumping a tool (the canonical operation) @@ -127,6 +121,12 @@ mise lock --platform linux-x64,linux-arm64,macos-x64,macos-arm64 `mise.toml`/`mise.lock` are already inputs of the main task groups. 4. `mise install` locally to materialize it, then commit both files. +## Removing a tool + +1. Delete its `[tools]` entry from `mise.toml`. +2. Re-run `mise lock --platform linux-x64,linux-arm64,macos-x64,macos-arm64`; the + regenerated lockfile drops the removed tool's blocks. Never delete them by hand. + ## Worktree trust gotcha `.wt/` worktrees nest **under** the repo, so mise's upward config search loads both @@ -138,7 +138,7 @@ mise trust --all # trust this dir and its parents mise trust --show # inspect trust status without changing it ``` -The main checkout `/Users/josh/code/meigma/template-go` is already trusted. +The main checkout `/Users/josh/code/meigma/codemode` is already trusted. ## Inspection / read-only ops @@ -154,19 +154,14 @@ mise exec -- golangci-lint version # run a pinned tool ad hoc, no shell activa ## Gotchas - `mise install` installs but does **not** activate — tools are not on PATH until - `mise activate` runs in the shell, or you go through `mise exec` / `mise run` / - shims. CI relies on mise-action prepending the shim dir; locally use - `eval "$(mise activate zsh)"` once, or prefix one-off commands with `mise exec --`. + `mise activate` runs in the shell, or you go through `mise exec` / shims. CI relies + on mise-action prepending the shim dir; locally use `eval "$(mise activate zsh)"` + once, or prefix one-off commands with `mise exec --`. - `mise.local.toml` / `.mise.local.toml` are gitignored per-developer overrides. Never commit them and never put project pins there — project pins belong in the committed `mise.toml`. -- `mise.toml` and `mise.lock` are committed and authoritative; the gitignored - `melange*.rsa*`, `melange-vars.yaml`, `.melange-vars.local.yaml`, and the - `packages/`/`image.tar` artifacts come from `mise run image-local` and must stay - uncommitted (see the `melange`/`apko` skills). -- `[tasks.image-local]` passes `--runner docker` to melange (melange needs a Linux - build sandbox) and loads/retags the host-arch image into Docker as - `template-go:dev`. Docker must be running on macOS. +- `mockery` is pinned here but driven by `.mockery.yml`; regenerate mocks with + `mise exec -- mockery` rather than a locally installed copy. ## Command reference diff --git a/.agents/skills/mise/references/mise-commands.md b/.agents/skills/mise/references/mise-commands.md index 8c19d89..24f6c46 100644 --- a/.agents/skills/mise/references/mise-commands.md +++ b/.agents/skills/mise/references/mise-commands.md @@ -36,7 +36,7 @@ Usage: ```bash mise install # install everything in mise.toml (honors mise.lock) -mise install go@1.26.4 # install a specific version +mise install go@1.26.6 # install a specific version ``` Flags that matter here: @@ -129,7 +129,7 @@ Usage: ```bash mise exec -- golangci-lint version -mise exec go@1.26.4 -- go version # override one tool ad hoc +mise exec go@1.26.6 -- go version # override one tool ad hoc ``` Flags that matter here: @@ -142,14 +142,10 @@ Flags that matter here: ### `mise run` (alias `r`) -Purpose: run mise tasks. In this repo only `image-local` exists (a local container -convenience); day-to-day build/test/lint go through moon, not mise. - -Usage: - -```bash -mise run image-local -``` +Purpose: run mise tasks. **This repo defines no mise tasks** — build, lint, test, +`mcp-smoke`, `race`, and `check` all go through moon (`moon run root:check`, +`moon ci --summary minimal`). Listed only so the command is not mistaken for the +project's entrypoint. Flags that matter here: diff --git a/.github/repository-settings.toml b/.github/repository-settings.toml index f356773..f0ae95a 100644 --- a/.github/repository-settings.toml +++ b/.github/repository-settings.toml @@ -1,19 +1,19 @@ # GitHub repository settings managed by .github/scripts/configure_github_repo.py. # # Run: -# uv run .github/scripts/configure_github_repo.py plan --repo OWNER/REPO -# uv run .github/scripts/configure_github_repo.py apply --repo OWNER/REPO +# uv run .github/scripts/configure_github_repo.py plan --repo meigma/codemode +# uv run .github/scripts/configure_github_repo.py apply --repo meigma/codemode # # Notes: # - Supported settings are applied directly through the GitHub REST API. # - Unsupported settings stay in this file so the script can report manual follow-ups. # - The branch ruleset follows the repository default branch via ~DEFAULT_BRANCH. -# - Status checks default to the standard template CI check. Adjust them when -# the repository adds more required workflows. +# - The only required status check is `ci`, the single Moon CI job. Add contexts +# here when the repository adds more required workflows. [repository] default_branch = "master" -is_template = true +is_template = false immutable_releases = true has_wiki = false diff --git a/.github/scripts/test_configure_github_repo.py b/.github/scripts/test_configure_github_repo.py index bd13a6c..746858d 100644 --- a/.github/scripts/test_configure_github_repo.py +++ b/.github/scripts/test_configure_github_repo.py @@ -103,7 +103,7 @@ def test_plan_creates_workflow_pages_site(self) -> None: plan = configure.build_plan( api, "meigma", - "template-go", + "codemode", base_config({"build_type": "workflow", "https_enforced": True}), mode="plan", hostname="github.com", @@ -120,7 +120,7 @@ def test_plan_updates_existing_pages_site(self) -> None: plan = configure.build_plan( api, "meigma", - "template-go", + "codemode", base_config({"build_type": "workflow", "https_enforced": True}), mode="plan", hostname="github.com", @@ -133,7 +133,7 @@ def test_plan_updates_existing_pages_site(self) -> None: def test_apply_create_pages_runs_follow_up_update(self) -> None: api = FakeGitHubApi() plan = configure.PlanResult( - repo="meigma/template-go", + repo="meigma/codemode", hostname="github.com", mode="apply", changes=[ @@ -153,7 +153,7 @@ def test_apply_create_pages_runs_follow_up_update(self) -> None: warnings=[], ) - applied = configure.apply_plan(api, "meigma", "template-go", plan) + applied = configure.apply_plan(api, "meigma", "codemode", plan) self.assertEqual(applied, ["Create GitHub Pages site"]) self.assertEqual(api.created_pages, [{"build_type": "workflow"}]) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 157b00b..adb6b01 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,5 +78,8 @@ jobs: restore-keys: | ${{ runner.os }}-uv-docs- - - name: Run Moon CI + # Single CI gate. `root:check` fans out to format, lint, build, the MCP + # transport smoke test (root:mcp-smoke), the race-detector suite + # (root:race), and the docs build. + - name: Run Moon CI (root:check — includes MCP smoke and race) run: moon ci --summary minimal diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 47f31b0..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,77 +0,0 @@ -name: Release - -on: - push: - tags: - - 'v*' - -permissions: {} - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: false - -jobs: - release-assets: - name: Build release assets - if: github.event.deleted == false - permissions: - attestations: read - contents: read - id-token: write - uses: meigma/release/.github/workflows/go-pre-publish.yml@0dee66ff6c4cc7e28d7bb65e97a37d701e0eff4a - with: - sign-and-notarize-macos: false - sign-native-packages: false - - oci-image: - name: Build OCI image - needs: release-assets - permissions: - actions: read - attestations: read - contents: read - uses: meigma/release/.github/workflows/go-oci-build.yml@0dee66ff6c4cc7e28d7bb65e97a37d701e0eff4a - with: - artifact-id: ${{ needs.release-assets.outputs.oci-input-artifact-id }} - artifact-digest: ${{ needs.release-assets.outputs.oci-input-artifact-digest }} - - oci-publish: - name: Publish OCI image - needs: oci-image - permissions: - actions: read - artifact-metadata: write - attestations: write - contents: read - id-token: write - packages: write - uses: meigma/release/.github/workflows/publish-oci-image.yml@0dee66ff6c4cc7e28d7bb65e97a37d701e0eff4a - with: - artifact-id: ${{ needs.oci-image.outputs.artifact-id }} - artifact-digest: ${{ needs.oci-image.outputs.artifact-digest }} - image-digest: ${{ needs.oci-image.outputs.image-digest }} - publish-image: true - - github-release: - name: Publish GitHub Release - needs: - - release-assets - - oci-publish - permissions: - actions: read - artifact-metadata: write - attestations: write - contents: read - id-token: write - uses: meigma/release/.github/workflows/publish-github-release.yml@0dee66ff6c4cc7e28d7bb65e97a37d701e0eff4a - with: - artifact-id: ${{ needs.release-assets.outputs.artifact-id }} - artifact-digest: ${{ needs.release-assets.outputs.artifact-digest }} - checksum-signing-workflow-ref: meigma/release/.github/workflows/go-pre-publish.yml@0dee66ff6c4cc7e28d7bb65e97a37d701e0eff4a - require-oci-image: true - oci-image-reference: ${{ needs.oci-publish.outputs.image-reference }} - release-app-client-id: ${{ vars.MEIGMA_RELEASE_APP_CLIENT_ID }} - publish-release: true - secrets: - release-app-private-key: ${{ secrets.MEIGMA_RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml deleted file mode 100644 index c9b75fd..0000000 --- a/.github/workflows/security-scan.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Security Scan - -on: - schedule: - - cron: "37 9 * * 1" - workflow_dispatch: - -permissions: {} - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - container-vulnerability-scan: - name: Container Vulnerability Scan - runs-on: ubuntu-24.04 - permissions: - contents: read - security-events: write - steps: - - name: Check out repository - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - with: - persist-credentials: false - - - name: Resolve scan metadata - id: scan - run: | - { - echo "version=security-scan-${GITHUB_RUN_ID}.${GITHUB_RUN_ATTEMPT}" - echo "commit=${GITHUB_SHA}" - echo "date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" - } >> "$GITHUB_OUTPUT" - - - name: Setup mise - uses: jdx/mise-action@3c2e0cf82a5b2e5249f0d3635a4d83d0ae861518 # v4.2.5 - with: - version: 2026.8.8 - cache: true - - - name: Build local scan image (Go + melange + apko) - env: - VERSION: ${{ steps.scan.outputs.version }} - COMMIT: ${{ steps.scan.outputs.commit }} - DATE: ${{ steps.scan.outputs.date }} - run: | - set -euo pipefail - mkdir -p scan-input - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath \ - -ldflags="-s -w -buildid= -X main.version=$VERSION -X main.commit=$COMMIT -X main.date=$DATE" \ - -o scan-input/application ./cmd/template-go - printf '{"version":"0.0.0"}\n' > melange-vars.json - melange keygen melange.rsa - melange build melange.yaml --arch x86_64 --runner docker \ - --signing-key melange.rsa --source-dir scan-input --out-dir packages \ - --vars-file melange-vars.json - apko build apko.yaml template-go:security-scan scan.tar \ - --arch amd64 --repository-append ./packages --keyring-append ./melange.rsa.pub - docker load < scan.tar - docker tag template-go:security-scan-amd64 template-go:security-scan - - - name: Scan local image - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 - with: - scan-type: image - image-ref: template-go:security-scan - scanners: vuln - vuln-type: os,library - severity: HIGH,CRITICAL - ignore-unfixed: true - format: sarif - output: trivy-results.sarif - exit-code: "1" - hide-progress: true - limit-severities-for-sarif: true - - - name: Upload scan results - if: ${{ always() && hashFiles('trivy-results.sarif') != '' }} - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 - with: - sarif_file: trivy-results.sarif - category: container-vulnerability-scan diff --git a/.gitignore b/.gitignore index 2d426bb..d9d7e99 100644 --- a/.gitignore +++ b/.gitignore @@ -17,20 +17,6 @@ mise.local.toml .mise.local.toml -# Local container build artifacts (melange apks + ephemeral signing keys + apko -# image tarballs/SBOMs from `mise run image-local`). melange.yaml/apko.yaml ARE committed. -/packages/ -/sbom/ -melange*.rsa -melange*.rsa.pub -melange-vars.yaml -.melange-vars.local.yaml -.melange-vars.local.json -.image-local/ -image.tar -*.oci -*.spdx.json - # Go bin/ cover.out @@ -86,7 +72,7 @@ pnpm-debug.log* .svelte-kit/ coverage/ -# Template repo outputs +# Docs site outputs docs/build/ docs/.venv/ diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index e88bec4..0000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,138 +0,0 @@ -# yaml-language-server: $schema=https://goreleaser.com/static/schema.json -version: 2 - -project_name: template-go - -gomod: - proxy: true - env: - - GOTOOLCHAIN=local - - GOPROXY=https://proxy.golang.org,direct - - GOSUMDB=sum.golang.org - -builds: - - id: template-go - main: ./cmd/template-go - binary: template-go - env: - - CGO_ENABLED=0 - goos: - - darwin - - linux - - windows - goarch: - - amd64 - - arm64 - flags: - - -trimpath - ldflags: - - -s -w -buildid= - - -X main.version={{ .Version }} - - -X main.commit={{ .FullCommit }} - - -X main.date={{ .CommitDate }} - mod_timestamp: "{{ .CommitTimestamp }}" - -notarize: - macos: - - enabled: '{{ eq .Env.MACOS_NOTARIZE_ENABLED "true" }}' - ids: - - template-go - sign: - certificate: "{{ .Env.MACOS_SIGN_P12 }}" - password: "{{ .Env.MACOS_SIGN_PASSWORD }}" - notarize: - issuer_id: "{{ .Env.MACOS_NOTARY_ISSUER_ID }}" - key_id: "{{ .Env.MACOS_NOTARY_KEY_ID }}" - key: "{{ .Env.MACOS_NOTARY_KEY }}" - wait: true - timeout: 20m - -archives: - - id: template-go - ids: - - template-go - formats: - - tar.gz - format_overrides: - - goos: windows - formats: - - zip - name_template: >- - {{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }} - -nfpms: - - id: release - ids: - - template-go - vendor: Meigma - homepage: https://github.com/meigma/template-go - maintainer: Meigma - description: Meigma Go repository template application. - license: Apache-2.0 OR MIT - formats: - - deb - - rpm - - apk - bindir: /usr/bin - rpm: - signature: - key_file: "{{ .Env.RELEASE_RPM_SIGNING_KEY_FILE }}" - apk: - signature: - key_file: "{{ .Env.RELEASE_APK_SIGNING_KEY_FILE }}" - key_name: template-go-001 - -homebrew_casks: - - name: template-go - ids: - - template-go - binaries: - - template-go - repository: - owner: meigma - name: homebrew-tap - homepage: https://github.com/meigma/template-go - description: Meigma Go repository template application - license: Apache-2.0 OR MIT - url: - template: "https://github.com/meigma/template-go/releases/download/{{ .Tag }}/{{ .ArtifactName }}" - skip_upload: true - -scoops: - - name: template-go - ids: - - template-go - repository: - owner: meigma - name: scoop-bucket - homepage: https://github.com/meigma/template-go - description: Meigma Go repository template application - license: Apache-2.0 OR MIT - url_template: "https://github.com/meigma/template-go/releases/download/{{ .Tag }}/{{ .ArtifactName }}" - skip_upload: true - -checksum: - name_template: checksums.txt - -sboms: - - id: archives - artifacts: archive - - id: packages - artifacts: package - -signs: - - id: checksums - cmd: cosign - artifacts: checksum - signature: "${artifact}.sigstore.json" - args: - - sign-blob - - "--bundle=${signature}" - - "${artifact}" - - --yes - -changelog: - disable: true - -release: - disable: true diff --git a/.moon/toolchains.yml b/.moon/toolchains.yml index fdaa414..ad228ea 100644 --- a/.moon/toolchains.yml +++ b/.moon/toolchains.yml @@ -1,4 +1,4 @@ -# Toolchains for the current template. +# Toolchains for CodeMode. # # Tool versions (Go, Python, uv, and the CLIs) are managed by mise (mise.toml + # mise.lock); moon runs every task against `system` binaries that mise puts on @@ -9,7 +9,7 @@ # version: 'REPLACE_ME_RUST_VERSION' # components: ['clippy', 'rustfmt'] -# JavaScript ecosystems can be added later if a generated project needs them. +# JavaScript ecosystems can be added later if this repository ever needs them. # javascript: # packageManager: 'pnpm' # inferTasksFromScripts: true diff --git a/.moon/workspace.yml b/.moon/workspace.yml index 7e19aea..8d4a58c 100644 --- a/.moon/workspace.yml +++ b/.moon/workspace.yml @@ -1,6 +1,6 @@ -# Shared Moon workspace configuration for the repository template. +# Shared Moon workspace configuration for CodeMode. # Keep the current projects explicit, then uncomment the discovery patterns -# below as the template grows into apps, packages, services, or tools. +# below if the repository grows beyond the root library and the docs site. projects: globs: [] @@ -15,7 +15,6 @@ projects: # - 'services/*' # - 'tools/*' # - 'crates/*' - # - 'cmd/*' # - 'sdk/*' # # Uncomment if glob-discovered IDs are likely to collide. diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c05df9b..e18ee07 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.3" + ".": "0.0.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 3644ed1..825c32f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,39 +1 @@ # Changelog - -## [0.1.3](https://github.com/meigma/template-go/compare/v0.1.2...v0.1.3) (2026-08-23) - - -### Features - -* **release:** add container publishing flow ([#1](https://github.com/meigma/template-go/issues/1)) ([cb5c8f4](https://github.com/meigma/template-go/commit/cb5c8f4a38b5332f77a4adb7e7e0f8dc32114cd3)) -* **session:** improve concurrent journal coordination ([#40](https://github.com/meigma/template-go/issues/40)) ([bb1d9ba](https://github.com/meigma/template-go/commit/bb1d9ba71c935d700ee82b6b051e87c65eb7d9b7)) -* standardize Go repository template ([7f61141](https://github.com/meigma/template-go/commit/7f6114150b9864d090bdee3027f0387a32d8ad75)) - - -### Bug Fixes - -* **release:** align release-please tag creation ([#4](https://github.com/meigma/template-go/issues/4)) ([da5d101](https://github.com/meigma/template-go/commit/da5d10171f6fc7e401c73213f711a6ec6e0f619c)) -* **release:** allow draft release resolution ([#5](https://github.com/meigma/template-go/issues/5)) ([75aee65](https://github.com/meigma/template-go/commit/75aee659cc31bbb7517b1b9bda5a94fab6bb50d7)) -* **release:** enable reusable publishers ([#45](https://github.com/meigma/template-go/issues/45)) ([de97be8](https://github.com/meigma/template-go/commit/de97be81975f4c5dbc725d55aaf683b7a337c1f6)) -* **release:** harden container publishing ([#8](https://github.com/meigma/template-go/issues/8)) ([dceb740](https://github.com/meigma/template-go/commit/dceb740741eeb3a6cf86d503ba29acaf38457ef9)) -* **release:** resolve drafts with explicit repository ([#6](https://github.com/meigma/template-go/issues/6)) ([c6e8f2d](https://github.com/meigma/template-go/commit/c6e8f2dc2b38be293efc70b827887d94e785f339)) - -## [0.1.2](https://github.com/meigma/template-go/compare/v0.1.1...v0.1.2) (2026-08-23) - - -### Features - -* **session:** improve concurrent journal coordination ([#40](https://github.com/meigma/template-go/issues/40)) ([bb1d9ba](https://github.com/meigma/template-go/commit/bb1d9ba71c935d700ee82b6b051e87c65eb7d9b7)) - - -### Bug Fixes - -* **release:** harden container publishing ([#8](https://github.com/meigma/template-go/issues/8)) ([dceb740](https://github.com/meigma/template-go/commit/dceb740741eeb3a6cf86d503ba29acaf38457ef9)) - -## [0.1.1](https://github.com/meigma/template-go/compare/template-go-v0.1.0...template-go-v0.1.1) (2026-05-12) - - -### Features - -* **release:** add container publishing flow ([#1](https://github.com/meigma/template-go/issues/1)) ([cb5c8f4](https://github.com/meigma/template-go/commit/cb5c8f4a38b5332f77a4adb7e7e0f8dc32114cd3)) -* standardize Go repository template ([7f61141](https://github.com/meigma/template-go/commit/7f6114150b9864d090bdee3027f0387a32d8ad75)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9f7076c..9806543 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,50 +1,52 @@ # Contributing -Thank you for your interest in contributing. -This repository is a Go project template, so changes should keep the generated-project path simple and predictable. -For private vulnerability reporting, use [SECURITY.md](SECURITY.md) instead of public channels. +Contributions should preserve CodeMode's public package boundaries, typed capability binding, per-call authorization, bounded Starlark execution, and exact three-tool MCP surface. -## Reporting Bugs +Report suspected vulnerabilities through the private process in [SECURITY.md](SECURITY.md), not through public GitHub channels. -Report non-security bugs through GitHub issues. -Include the following details when possible: +## Report a bug -- version, commit, or environment details -- steps to reproduce -- expected behavior -- actual behavior -- logs, screenshots, or a minimal reproduction +Open a GitHub issue for non-security bugs. Include: -If you are reporting a security issue, stop and follow [SECURITY.md](SECURITY.md) instead. +- the CodeMode commit or version you used +- your Go version and relevant environment details +- a minimal capability registration or Starlark program that reproduces the problem +- the steps you followed +- the expected and actual behavior +- relevant error classifications or logs with credentials and sensitive arguments removed -## Pull Requests +## Prepare a change -Contributors should: +1. Install the pinned tools: -1. Keep changes focused and scoped to a single problem. -2. Add or update tests when behavior changes. -3. Update documentation when user-facing behavior changes. -4. Use Conventional Commit subjects, such as `feat: add config loader` or `fix: handle empty input`. -5. Make sure `moon run root:check` passes before requesting review. + ```sh + mise install + ``` -## Local Setup +2. Keep the change focused. Add or update behavior tests when a public contract changes. Update the user documentation when behavior visible through the root, `authz`, or `mcpserver` packages changes. +3. Before requesting review, run: -```sh -mise install # provision the pinned toolchain (Go, Moon, the dev CLIs) -moon run root:check -``` + ```sh + moon run root:check + ``` + + `root:check` includes formatting, linting, compilation, the official MCP secure-loop test, the race detector, and the documentation build. -Useful project commands: +For focused investigation, the security-boundary checks are available separately: ```sh -moon run root:format -moon run root:lint -moon run root:build -moon run root:test -go run ./cmd/template-go --version +moon run root:mcp-smoke +moon run root:race ``` -## Release Changes +`root:mcp-smoke` runs `TestActualMCPSecureLoop` through the official in-memory MCP transport. `root:race` runs all Go packages with the race detector and disables cached test results. + +## Submit a pull request + +- Explain the user-visible or security-relevant behavior that changed. +- Keep capability metadata, authorization behavior, MCP output, tests, and documentation consistent. +- Do not expose credentials, policy diagnostics, handler failures, Starlark source, or arguments in client-facing errors. +- Ensure `moon run root:check` passes before requesting review. +- Use a Conventional Commit subject, for example `feat(mcpserver): add trusted invocation resolver` or `fix(authz): stop dispatch after denial`. -Release Please reads Conventional Commit subjects to build changelogs and release PRs. -Keep release-impacting commits clear; routine docs, CI, and maintenance commits should use the appropriate non-release type. +Release Please uses Conventional Commit subjects to prepare source version changes, tags, changelog entries, and draft GitHub releases. Use the commit type that matches the change; routine documentation, CI, and maintenance changes should use the corresponding non-feature type. diff --git a/DELETE_ME.md b/DELETE_ME.md deleted file mode 100644 index b686363..0000000 --- a/DELETE_ME.md +++ /dev/null @@ -1,150 +0,0 @@ -# Welcome to the Meigma Go Template - -This repository was generated from `template-go`, the standard starter for Meigma Go projects. -It is meant to give new repositories a working baseline on day one: a small Go CLI by default, Moon task orchestration, pinned CI, dependency automation, repository security defaults, and an enabled release pipeline that has already been exercised by the template application. - -Delete this file after you finish the first-repository setup checklist below. -It is only here to orient the initial project owner. - -## What This Template Provides - -- A minimal Go module at `github.com/meigma/template-go`. -- A Cobra/Viper CLI skeleton under `cmd/template-go` and `internal/cli`. -- Moon tasks for `format`, `lint`, `build`, `test`, and `check`. -- `golangci-lint` wired through mise and Moon. -- CI that delegates to `moon ci --summary minimal` with pinned actions, dependency caches, and minimal token permissions. -- A scheduled container vulnerability scan that uploads SARIF results to GitHub code scanning. -- Dependabot coverage for GitHub Actions, Go modules, and the docs uv project. -- MkDocs Material docs scaffolding under `docs/`, with GitHub Pages as the default publishing target. -- Repository settings for signed commits, squash-only merges, immutable releases, private vulnerability reporting, and protected tags. -- Release Please plus a full-SHA-pinned `meigma/release` caller for verified GitHub Release assets and a multi-architecture GHCR image. - -## How It Works - -Moon is the main entrypoint for local development and CI: - -```sh -moon run root:check -``` - -That aggregate check runs the Go formatter/linter/build/tests plus the docs build. -The GitHub Actions CI workflow runs the same path through: - -```sh -moon ci --summary minimal -``` - -The workflow caches Go modules, Go build artifacts, golangci-lint state, and uv's download cache through GitHub Actions. If that is not enough for a larger generated repository, add Moon remote caching later with Depot or another Bazel Remote Execution-compatible backend and repository credentials. - -The `GitHub Pages` workflow builds the MkDocs site on pull requests and deploys the default-branch `docs/build` output to Pages. The repository settings manifest defaults Pages to workflow-based publishing with HTTPS enforcement. - -The release machinery is enabled so the template proves the supported -`meigma/release` contract before generated projects inherit it: one static Go -application, downloadable release assets, and a Linux `amd64`/`arm64` OCI image. - -## First Setup Checklist - -1. Rename the Go module: - - ```sh - go mod edit -module github.com/meigma/YOUR_REPO - ``` - -2. Choose the project shape. - - The reusable release unit supports one Go application with downloadable - binaries and an OCI image. For other shapes: - - - Binary plus OCI image: keep the default release caller. - - Binary only: remove the `oci-image` and `oci-publish` jobs, set - `require-oci-image: false`, and remove `melange.yaml`, `apko.yaml`, the - `image-local` task, and the container security scan. - - Container only: the maintained release unit is not a container-only - contract. Keep its canonical binary path or replace the release workflow - with a container-specific design. - - Library only: remove the CLI and artifact workflow. Keep Release Please - only if the library needs changelogs, tags, and draft GitHub Releases. - -3. For a binary-producing project, rename the binary directory: - - ```sh - mv cmd/template-go cmd/YOUR_BINARY - ``` - - For a library-only project, delete `cmd/template-go`, remove or rewrite `internal/cli`, and remove Cobra/Viper dependencies that are no longer used. - -4. Replace template placeholders: - - ```sh - rg "template-go|TEMPLATE_GO|github.com/meigma/template-go" - ``` - - Update Go imports, Moon metadata, README and docs text, CLI environment - prefixes, `.goreleaser.yaml`, `melange.yaml`, `apko.yaml`, and the release - workflow metadata. Update `docs/mkdocs.yml` with the generated repository's - GitHub Pages URL, usually `https://OWNER.github.io/REPO/`. - -5. Refresh module metadata: - - ```sh - go mod tidy - ``` - -6. Configure and rehearse releases. - - - Review a published [`meigma/release`](https://github.com/meigma/release) - version and resolve it to a full commit SHA. - - Update every `uses: meigma/release/...` reference and - `checksum-signing-workflow-ref` in `.github/workflows/release.yml` to that - same SHA. Mixed revisions are unsupported. - - Update `.goreleaser.yaml`: project name, build ID, command path, binary - name, package metadata, archive names, and generated Homebrew/Scoop - metadata. - - Update `melange.yaml`: package metadata and the destination binary path. - Melange must install the staged `application` file rather than compile a - second binary. - - Update `apko.yaml`: package name, entrypoint, runtime packages, and OCI - annotations. - - Update `.github/workflows/security-scan.yml`: local image name and SARIF - category. - - Configure `MEIGMA_RELEASE_APP_CLIENT_ID` and - `MEIGMA_RELEASE_APP_PRIVATE_KEY`, install the App on the repository, and - grant it protected-tag bypass if `v*` tags are protected. - - Leave `publish-image` and `publish-release` set to `false` for the first - stable candidate. Merge the Release Please PR, inspect the populated draft - and workflow artifacts, and verify their checksums, attestations, and OCI - digest. - - After the rehearsal succeeds, enable both publication inputs in a reviewed - change and publish the next stable release. - - The template does not call the optional Homebrew, Scoop, or central native - package-repository publishers. To add them: - - - Follow - [Add Homebrew and Scoop](https://github.com/meigma/release/blob/v0.1.17/docs/how-to/add-homebrew-and-scoop.md) - before adding the `publish-homebrew.yml` or `publish-scoop.yml` caller jobs. - - Follow - [Operate a native package repository](https://github.com/meigma/release/blob/v0.1.17/docs/how-to/operate-a-native-package-repository.md) - before enabling native package signing or adding - `request-package-repository.yml`. - - Do not enable an optional publisher until its destination repository, App - installation, credentials, and required checks exist. - -7. Run the full local check: - - ```sh - moon run root:check - ``` - -8. Update project-facing docs: - - - Rewrite `README.md` for the actual project. - - Review `CONTRIBUTING.md` and `SECURITY.md`. - - Add a real license before publishing the repository. - -9. Delete this file: - - ```sh - rm DELETE_ME.md - ``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6bca3b3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Joshua Gilman + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 10459af..3599ca3 100644 --- a/README.md +++ b/README.md @@ -1,128 +1,146 @@ -# template-go +# CodeMode -`template-go` is the reusable Go repository starter for Meigma projects. -It includes a small Go CLI skeleton, Moon tasks, pinned CI, Dependabot, baseline repository security settings, and Release Please plus the reusable `meigma/release` release unit. +CodeMode is a source-only Go library for exposing typed Go capabilities to Model Context Protocol (MCP) clients through bounded Starlark programs. A host registers capabilities, applies a static deployment filter, and authorizes each validated native call. -## Local Bootstrap +CodeMode does not start a transport, authenticate callers, open listeners, or manage shutdown. The host application owns those responsibilities. The module has no executable entry point and no generic downstream MCP proxy. -Prerequisites: +## MCP tools -- [mise](https://mise.jdx.dev) — provisions every pinned tool from `mise.toml` + - `mise.lock`: Go, Moon, Python + uv, `golangci-lint`, GoReleaser, GitHub CLI, - Syft, Cosign, Melange, and apko. Run `mise install` once; there is nothing - else to install by hand. +The `mcpserver` package constructs an official Go SDK server with exactly three tools: -Tool versions live in `mise.toml`; `mise.lock` records a per-platform download URL -and checksum for each (and, for the aqua-backed CLIs, cosign/SLSA/GitHub-attestation -verification). `mise install` runs with `locked = true`, so it **fails closed** if a -tool lacks a pre-resolved, checksummed entry for the current platform. Moon runs every -task against these tools as `system` binaries on PATH and manages no toolchain itself. -To bump a tool, edit its version in `mise.toml`, run -`mise lock --platform linux-x64,linux-arm64,macos-x64,macos-arm64`, and commit -`mise.toml` + `mise.lock`. +| Tool | Input | Successful structured output | +| --- | --- | --- | +| `search_api` | `{"query": string}` | A bounded array of enabled capability names, generated signatures, and summaries | +| `describe_api` | `{"name": string}` for one exact capability name | The capability name, signature, summary, description, and supported input and output fields | +| `execute` | `{"source": string}` containing one bounded Starlark program | `{"result":
}` | -After creating a new repository from this template, replace the placeholder names before doing feature work: +Every tool resolves an authenticated `authz.Subject` from host-owned Go context before discovery or execution. Tool arguments and MCP `_meta` are untrusted and cannot supply identity, credentials, limits, modules, or capability visibility. -```sh -go mod edit -module github.com/meigma/YOUR_REPO -mv cmd/template-go cmd/YOUR_BINARY -``` +Each `execute` call uses a fresh interpreter. The program must define a zero-argument `main()` function. CodeMode returns only the converted value from `main`; it does not separately expose printed text, globals, or intermediate values. -Then update `template-go` references in the Moon tasks, GoReleaser, Melange and apko configurations, README, and package docs. +## Prerequisites -## Common Tasks +- Go 1.26.6, as declared by `go.mod` +- [mise](https://mise.jdx.dev) for repository development; `mise install` installs the pinned Go, Python, `golangci-lint`, uv, Moon, GitHub CLI, and mockery versions -Moon is the standard task front door: +CodeMode has no released version yet. To evaluate the current `master` branch from another Go module, run: ```sh -moon run root:format -moon run root:lint -moon run root:build -moon run root:test -moon run root:check +go get github.com/meigma/codemode@master ``` -CI runs the same aggregate check: - -```sh -moon ci --summary minimal +## Integrate CodeMode + +The following outline assembles a root CodeMode server and the MCP adapter. Replace the example policy and context plumbing with host-specific authentication and authorization. + +```go +package integration + +import ( + "context" + + "github.com/modelcontextprotocol/go-sdk/mcp" + + "github.com/meigma/codemode" + "github.com/meigma/codemode/authz" + "github.com/meigma/codemode/mcpserver" +) + +type lookupInput struct { + Key string `json:"key"` +} + +type lookupOutput struct { + Key string `json:"key"` +} + +type policy struct{} + +func (policy) Authorize(_ context.Context, input authz.AuthorizationInput) error { + if input.CapabilityID != "records.entry.lookup" { + return authz.ErrDenied + } + return nil +} + +type subjectKey struct{} + +type subjectResolver struct{} + +func (subjectResolver) Resolve(ctx context.Context) (authz.Subject, error) { + subject, ok := ctx.Value(subjectKey{}).(authz.Subject) + if !ok || subject.ID == "" { + return authz.Subject{}, codemode.ErrUnauthenticated + } + return subject, nil +} + +// withSubject is called by trusted host middleware after authentication. +func withSubject(ctx context.Context, subject authz.Subject) context.Context { + return context.WithValue(ctx, subjectKey{}, subject) +} + +func newMCPServer() (*mcp.Server, error) { + builder := codemode.New(codemode.Options{ + Authorizer: policy{}, + Limits: codemode.DefaultLimits(), + }) + + err := codemode.Register(builder, codemode.Capability[lookupInput, lookupOutput]{ + ID: "records.entry.lookup", + Name: "records.lookup", + Summary: "Look up one record by key.", + Description: "Returns the record identified by key.", + Handler: func(_ context.Context, _ authz.Subject, input lookupInput) (lookupOutput, error) { + return lookupOutput{Key: input.Key}, nil + }, + }) + if err != nil { + return nil, err + } + + root, err := builder.Build() + if err != nil { + return nil, err + } + return mcpserver.New(root, subjectResolver{}) +} ``` -The starter CLI is intentionally small: +Connect the returned `*mcp.Server` to a transport only after the host has authenticated the request and placed the non-secret subject in trusted context. The host must also manage listener lifecycle, request cancellation, and shutdown. -```sh -go run ./cmd/template-go --version -go run ./cmd/template-go --message "hello from cobra" -go test ./... -``` +## Security boundary -The CLI entrypoint uses Cobra and Viper in the same shape as other Meigma CLIs: `cmd/template-go` stays thin, `internal/cli` owns command construction, and Viper-backed flags can also be supplied through `TEMPLATE_GO_*` environment variables. +Capability input is converted to the registered Go type before authorization. The authorizer receives the trusted subject, stable capability ID, exposed capability name, and a fresh JSON-shaped copy of the validated arguments. A recognized denial prevents the handler from running. Capabilities disabled at build time are absent from search, description, and execution. -## Container Image +The Starlark runtime bounds source bytes, interpreter steps, elapsed time, native calls, value depth, result bytes, search query bytes, and search results. Module loading is disabled. These in-process controls reduce the reachable surface; they are not a hard isolation boundary between mutually untrusted tenants. Authorizers and handlers run as Go code in the host process and must honor context cancellation. See [SECURITY.md](SECURITY.md) for vulnerability reporting and containment limits. -The image is built without a Dockerfile. GoReleaser produces the canonical Linux -binaries. [Melange](https://github.com/chainguard-dev/melange) packages those -exact bytes into signed [Wolfi](https://github.com/wolfi-dev) APKs, and -[apko](https://github.com/chainguard-dev/apko) assembles a minimal, -multi-architecture, nonroot image. The runtime uses UID/GID 65532 and includes -CA certificates and timezone data. +## Repository checks -Build and run a host-architecture image locally with Docker: +Moon is the task entry point after `mise install`: ```sh -mise run image-local -docker run --rm template-go:dev --version -docker run --rm template-go:dev --message "hello from container" +moon run root:mcp-smoke +moon run root:race +moon run root:check ``` -The Wolfi base resolves current packages during each build. The generated SBOM -and provenance record the resolved contents. GoReleaser stamps `version`, -`commit`, and `date` into the release binary; `mise run image-local` uses -development values. +`root:mcp-smoke` runs the official MCP secure-loop test. `root:race` runs all Go packages with the race detector. `root:check` depends on format, lint, build, MCP smoke, race, and `docs:build`. -## CI and Security +CI runs Moon's affected-task graph, including `root:check` and the standalone `root:test` task: -The default CI workflow keeps permissions minimal, pins external actions, disables checkout credential persistence, and delegates checks to Moon. -It uses GitHub-hosted dependency caches for Go, golangci-lint, and uv download artifacts while leaving Moon remote caching as an optional follow-up for repositories that need a shared task-output cache. -The docs workflow builds the MkDocs site on pull requests and deploys `docs/build` to GitHub Pages from the default branch. -The scheduled security scan workflow builds the local container image weekly, scans it for high/critical fixed vulnerabilities, and uploads SARIF results to GitHub code scanning. -Dependabot covers GitHub Actions, the root Go module, and the docs uv project. - -Repository settings live in `.github/repository-settings.toml`. -They default to immutable releases, private vulnerability reporting, signed commits, squash-only merges, GitHub Pages workflow publishing, and protected tags. - -## Release Layer - -Release automation is enabled for the template application so the template -proves the binary and OCI paths before generated projects inherit them. - -The release path is: - -- Release Please maintains the release PR and creates a stable `vMAJOR.MINOR.PATCH` - tag plus a draft GitHub Release after merge. -- `.github/workflows/release.yml` calls one immutable - [`meigma/release`](https://github.com/meigma/release) release unit pinned by - full commit SHA. -- The release unit builds and verifies archives, native packages, checksums, - SBOMs, and the checksum Sigstore bundle. -- The same canonical Linux binaries become a signed, attested - `ghcr.io/meigma/template-go` image for `amd64` and `arm64`. -- The release unit uploads the verified assets and publishes the GitHub Release - only after the OCI path succeeds. - -Generated repositories must update names and metadata, pin one reviewed -`meigma/release` revision across every workflow and signer reference, and -rehearse with both publication inputs disabled before their first public -release. See [`DELETE_ME.md`](DELETE_ME.md) for the setup checklist. +```sh +moon ci --summary minimal +``` ## Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines, local setup expectations, and pull request workflow. +See [CONTRIBUTING.md](CONTRIBUTING.md) for local checks and pull request expectations. ## Security -See [SECURITY.md](SECURITY.md) for supported versions and the private vulnerability reporting path. +Report vulnerabilities through the private process in [SECURITY.md](SECURITY.md), not through a public issue. ## License -Add the repository license before publishing a project generated from this template. +CodeMode is licensed under the [Apache License 2.0](LICENSE). diff --git a/SECURITY.md b/SECURITY.md index 11f4f74..9f726ce 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,26 +1,27 @@ # Security Policy -This template expects generated projects to use GitHub private vulnerability reporting. -Replace this file with the actual support policy before publishing a generated repository. +## Supported versions -## Supported Versions +CodeMode has no released version yet. Security fixes target the `master` branch until the first release establishes a versioned support policy. -Do not claim support windows or release lines until the generated project actually maintains them. -For a brand-new project, a short policy such as "only the latest release is supported" is usually enough. +## Report a vulnerability -## Reporting a Vulnerability +Use [GitHub private vulnerability reporting](https://github.com/meigma/codemode/security/advisories/new) to report a suspected vulnerability. Do not open a public issue, pull request, or discussion, and do not disclose the report in another public channel. -Report vulnerabilities privately through GitHub's private vulnerability reporting flow when it is enabled for the generated repository. +Include the following details when available: -Do not use public GitHub issues, pull requests, discussions, chat channels, or other public forums for vulnerability reports. +- the affected commit +- the affected public package or MCP tool +- the security impact and the conditions required to trigger it +- reproduction steps or a minimal proof of concept +- whether the issue crosses the host context, authorization, capability, Starlark, or MCP output boundary +- relevant logs or traces with credentials and other secrets removed +- a suggested mitigation or fix, if known -When reporting a vulnerability, include as much of the following as possible: +## In-process containment -- affected version, commit, or deployment identifier -- a description of the issue and the security impact -- steps to reproduce or a minimal proof of concept -- any relevant logs, screenshots, or traces -- any suggested mitigations or fixes, if available +CodeMode executes each submitted program in a fresh in-process Starlark interpreter. Module loading is disabled, native capabilities are limited to the immutable set registered and enabled by the host, and native calls are rejected during top-level program loading. A program must define a zero-argument `main()` function, and only its converted return value is exposed. -If the project has a documented disclosure timeline, add it here. -If not, keep the policy short and avoid inventing guarantees. +Configured limits bound source bytes, interpreter steps, elapsed time, attempted native calls, converted-value depth, result bytes, search query bytes, and search results. Each validated native call passes through the host-supplied `authz.Authorizer` before its handler runs. The MCP adapter resolves the subject from trusted Go context and ignores identity or credential claims in tool arguments and request `_meta`. + +These controls restrict Starlark evaluation inside the host process. They do not form a hard tenant boundary. The authorizer and capability handlers are ordinary Go code with the host process's privileges. CodeMode can cancel Starlark evaluation when a request or elapsed deadline ends, but it cannot forcibly interrupt a blocking Go authorizer or handler. Host implementations must honor context cancellation and add process or workload isolation when their threat model requires it. diff --git a/apko.yaml b/apko.yaml deleted file mode 100644 index 688e952..0000000 --- a/apko.yaml +++ /dev/null @@ -1,37 +0,0 @@ -contents: - repositories: - - https://packages.wolfi.dev/os - keyring: - - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub - packages: - - wolfi-baselayout - - ca-certificates-bundle - - tzdata - - template-go - -entrypoint: - command: /usr/bin/template-go - -accounts: - groups: - - groupname: nonroot - gid: 65532 - users: - - username: nonroot - uid: 65532 - gid: 65532 - run-as: 65532 - -environment: - PATH: /usr/bin - SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt - -archs: - - amd64 - - arm64 - -annotations: - org.opencontainers.image.title: template-go - org.opencontainers.image.description: Meigma Go repository template application - org.opencontainers.image.source: https://github.com/meigma/template-go - org.opencontainers.image.licenses: Apache-2.0 OR MIT diff --git a/docs/docs/index.md b/docs/docs/index.md index e7fe8dd..9e4d3f4 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -1,32 +1,63 @@ --- title: CodeMode slug: / -description: Build MCP servers that expose bounded Go capabilities through Starlark. +description: Reference for bounded Starlark access to registered Go capabilities over MCP. --- # CodeMode -CodeMode is a Go library for building code-native Model Context Protocol (MCP) servers. An application registers typed Go capabilities, selects the capabilities enabled for one deployment, and exposes them through a restricted Starlark runtime. +CodeMode is a Go library that exposes registered, typed Go capabilities to Model Context Protocol (MCP) clients through Starlark programs. The current implementation consists of an immutable capability server, an authorization interface, and an adapter for the official MCP Go SDK. -## MCP boundary +## Public packages -The `mcpserver` package exposes exactly three tools: +- `github.com/meigma/codemode` registers typed capabilities, filters disabled capabilities, searches and describes the enabled catalog, and executes bounded Starlark programs. +- `github.com/meigma/codemode/authz` defines the trusted subject, canonical authorization input, authorizer interface, and recognized denial. +- `github.com/meigma/codemode/mcpserver` binds a CodeMode service and trusted invocation resolver to an official MCP SDK server. -| Tool | Input | Output | +## MCP surface + +`mcpserver.New` exposes exactly three tools: + +| Tool | Required input | Successful structured output | | --- | --- | --- | -| `search_api` | A bounded query string | Enabled capability names, signatures, and summaries | -| `describe_api` | One exact capability name | Its signature, description, and supported input and output fields | -| `execute` | One bounded Starlark program | `{"result":
}` | +| `search_api` | `{"query": string}` | An array of `{name, signature, summary}` records for matching enabled capabilities | +| `describe_api` | `{"name": string}` with one exact capability name | `{name, signature, summary, description, input, output}` | +| `execute` | `{"source": string}` with one Starlark program | `{"result":
}` | + +Search is case-normalized over capability names and summaries, returns name-sorted results, and returns an empty array for a blank query. Description uses exact names. A disabled capability is absent from search, description, the Starlark namespace, and execution. + +Each program must define a zero-argument `main()` function. CodeMode rejects native capability calls made while top-level source is loading. It discards printed text and returns only the converted value from `main` under the `result` key. + +## Trust model + +The host authenticates the request and stores a non-secret `authz.Subject` in typed, host-owned Go context. An `mcpserver.InvocationResolver` reads that context for every tool call. Resolver failure or an empty subject stops the request before discovery or execution. Tool arguments and MCP `_meta` are untrusted and cannot replace the resolved subject or provide credentials, budgets, modules, or capability filters. + +For a native capability call, CodeMode first binds the Starlark arguments to the registered Go input type. It then calls the host's `authz.Authorizer` with: + +- the resolved subject +- the stable capability ID +- the model-facing capability name +- a fresh JSON-shaped copy of the validated arguments + +A recognized denial prevents handler dispatch. Client-facing MCP failures use coarse error classifications rather than forwarding source, arguments, credentials, policy diagnostics, stack traces, or handler error text. + +The host owns transport startup, authentication, listeners, request context, and shutdown. CodeMode has no executable entry point and no generic downstream MCP forwarding path. -Each tool call resolves an authenticated subject from trusted Go context before it reaches the CodeMode service. Tool arguments and MCP `_meta` cannot provide or replace identity, credentials, execution budgets, modules, or capability allow-lists. +## Runtime limits -`execute` creates a fresh interpreter for each call. The program must define a zero-argument `main()` function. Only the value returned by `main()` crosses the MCP boundary; printed text and intermediate values do not. +`codemode.DefaultLimits()` currently sets: -## Integration outline +| Limit | Default | +| --- | ---: | +| Starlark source | 64 KiB | +| Interpreter steps | 1,000,000 | +| Elapsed execution time | 5 seconds | +| Attempted native calls | 100 | +| Converted-value depth | 32 | +| Encoded final result | 1 MiB | +| Search query | 256 bytes | +| Search results | 20 | -1. Build an immutable `codemode.Server` from typed capabilities and deployment options. -2. Implement `authz.Authorizer` for each native capability call. -3. Implement `mcpserver.InvocationResolver` to read the authenticated subject from host-owned typed context. -4. Call `mcpserver.New` and connect the returned official MCP SDK server to the transport owned by the host application. +Every configured limit must be positive; zero does not mean unlimited. Each execution gets a fresh interpreter and its own budgets. Module loading is disabled, and only the frozen namespace built from enabled capabilities is predeclared. -Disabled capabilities are absent from search, description, and execution. Authorization denial stops the native handler from running. Public tool errors use coarse classifications and do not include source text, arguments, credentials, policy details, stack traces, or handler results. +These are in-process restrictions, not a hard isolation boundary between mutually untrusted tenants. Authorizers and handlers run as Go code with the host process's privileges. They must honor context cancellation and return promptly because CodeMode cannot forcibly interrupt blocking Go code. diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 4589f12..1513b5e 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -1,5 +1,5 @@ site_name: CodeMode -site_description: Code-native MCP servers with bounded Go capabilities +site_description: Reference for bounded Starlark access to registered Go capabilities over MCP site_url: https://meigma.github.io/codemode/ repo_name: meigma/codemode repo_url: https://github.com/meigma/codemode diff --git a/docs/moon.yml b/docs/moon.yml index 068200b..1d7e9fb 100644 --- a/docs/moon.yml +++ b/docs/moon.yml @@ -8,7 +8,7 @@ tags: project: title: 'CodeMode docs' - description: 'MkDocs documentation for the CodeMode Go library.' + description: 'Reference documentation for the CodeMode Go library.' owner: 'meigma' maintainers: - 'meigma' diff --git a/docs/pyproject.toml b/docs/pyproject.toml index 1993e99..7600f55 100644 --- a/docs/pyproject.toml +++ b/docs/pyproject.toml @@ -1,7 +1,7 @@ [project] -name = "template-go-docs" +name = "codemode-docs" version = "0.0.0" -description = "MkDocs documentation site for the Meigma Go repository template." +description = "Reference documentation for the CodeMode Go library." requires-python = ">=3.14" dependencies = [ "mkdocs-material>=9.7.0", diff --git a/docs/uv.lock b/docs/uv.lock index 8baaf2b..50d7775 100644 --- a/docs/uv.lock +++ b/docs/uv.lock @@ -86,6 +86,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, ] +[[package]] +name = "codemode-docs" +version = "0.0.0" +source = { virtual = "." } +dependencies = [ + { name = "mkdocs-material" }, +] + +[package.metadata] +requires-dist = [{ name = "mkdocs-material", specifier = ">=9.7.0" }] + [[package]] name = "colorama" version = "0.4.6" @@ -377,17 +388,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] -[[package]] -name = "template-go-docs" -version = "0.0.0" -source = { virtual = "." } -dependencies = [ - { name = "mkdocs-material" }, -] - -[package.metadata] -requires-dist = [{ name = "mkdocs-material", specifier = ">=9.7.0" }] - [[package]] name = "urllib3" version = "2.7.0" diff --git a/melange.yaml b/melange.yaml deleted file mode 100644 index 34fce4e..0000000 --- a/melange.yaml +++ /dev/null @@ -1,26 +0,0 @@ -package: - name: template-go - version: ${{vars.version}} - epoch: 0 - description: Meigma Go repository template application. - target-architecture: - - x86_64 - - aarch64 - copyright: - - license: Apache-2.0 OR MIT - -vars: - version: 0.0.0 - -environment: - contents: - repositories: - - https://packages.wolfi.dev/os - keyring: - - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub - packages: - - busybox - -pipeline: - - runs: | - install -Dm755 -o 0 -g 0 application "${{targets.destdir}}/usr/bin/template-go" diff --git a/mise.lock b/mise.lock index 09f2974..21696af 100644 --- a/mise.lock +++ b/mise.lock @@ -1,29 +1,5 @@ # @generated - this file is auto-generated by `mise lock` https://mise.en.dev/dev-tools/mise-lock.html -[[tools."aqua:anchore/syft"]] -version = "1.51.0" -backend = "aqua:anchore/syft" - -[tools."aqua:anchore/syft"."platforms.linux-arm64"] -checksum = "sha256:6c0466811541ea03add5213a60a1562f0851e4c0b0ecfdee1a694a9455285900" -url = "https://github.com/anchore/syft/releases/download/v1.51.0/syft_1.51.0_linux_arm64.tar.gz" -url_api = "https://api.github.com/repos/anchore/syft/releases/assets/508878652" - -[tools."aqua:anchore/syft"."platforms.linux-x64"] -checksum = "sha256:2a2e837a2c8d59ec9af5472ee22d3b04ee463c4e44476ecf993fd1e5ab6ebc7f" -url = "https://github.com/anchore/syft/releases/download/v1.51.0/syft_1.51.0_linux_amd64.tar.gz" -url_api = "https://api.github.com/repos/anchore/syft/releases/assets/508878656" - -[tools."aqua:anchore/syft"."platforms.macos-arm64"] -checksum = "sha256:4f37f4c7fefce0a68e4cf71ba3f5f9829a99e65d89b29f7ee41b8c2c10ea8c59" -url = "https://github.com/anchore/syft/releases/download/v1.51.0/syft_1.51.0_darwin_arm64.tar.gz" -url_api = "https://api.github.com/repos/anchore/syft/releases/assets/508878653" - -[tools."aqua:anchore/syft"."platforms.macos-x64"] -checksum = "sha256:cddf9a044145caf0a1a3194d00d1dd51a1666f4814f2919cdb4768a0c062ad95" -url = "https://github.com/anchore/syft/releases/download/v1.51.0/syft_1.51.0_darwin_amd64.tar.gz" -url_api = "https://api.github.com/repos/anchore/syft/releases/assets/508878649" - [[tools."aqua:astral-sh/uv"]] version = "0.11.0" backend = "aqua:astral-sh/uv" @@ -52,54 +28,6 @@ url = "https://github.com/astral-sh/uv/releases/download/0.11.0/uv-x86_64-apple- url_api = "https://api.github.com/repos/astral-sh/uv/releases/assets/380020610" provenance = "github-attestations" -[[tools."aqua:chainguard-dev/apko"]] -version = "1.2.37" -backend = "aqua:chainguard-dev/apko" - -[tools."aqua:chainguard-dev/apko"."platforms.linux-arm64"] -checksum = "sha256:43e94fcda75df76e0b9fe78a98b2277ce4cc7eabe246e02df7c6f52c75b50f5d" -url = "https://github.com/chainguard-dev/apko/releases/download/v1.2.37/apko_1.2.37_linux_arm64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/apko/releases/assets/517375968" - -[tools."aqua:chainguard-dev/apko"."platforms.linux-x64"] -checksum = "sha256:9fa4ed893d0d87483a5f709fd5e2f1a1e6f93e40b35195949df2d9cf4f7093cc" -url = "https://github.com/chainguard-dev/apko/releases/download/v1.2.37/apko_1.2.37_linux_amd64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/apko/releases/assets/517375966" - -[tools."aqua:chainguard-dev/apko"."platforms.macos-arm64"] -checksum = "sha256:097ebf8e1f19278bca2e5fd788b7df002b40f25b2cbcda90165e5b78982b8c5b" -url = "https://github.com/chainguard-dev/apko/releases/download/v1.2.37/apko_1.2.37_darwin_arm64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/apko/releases/assets/517375993" - -[tools."aqua:chainguard-dev/apko"."platforms.macos-x64"] -checksum = "sha256:7edc3c7c5839b7c8352c78e11f510537ff261f0bdcaf7b70c8fe985a1e3d5119" -url = "https://github.com/chainguard-dev/apko/releases/download/v1.2.37/apko_1.2.37_darwin_amd64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/apko/releases/assets/517375996" - -[[tools."aqua:chainguard-dev/melange"]] -version = "0.59.1" -backend = "aqua:chainguard-dev/melange" - -[tools."aqua:chainguard-dev/melange"."platforms.linux-arm64"] -checksum = "sha256:aa5d221f92a248ba9aa490d1441c733417ad4c02f32fa9a13b8800acb42946f9" -url = "https://github.com/chainguard-dev/melange/releases/download/v0.59.1/melange_0.59.1_linux_arm64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/melange/releases/assets/514836314" - -[tools."aqua:chainguard-dev/melange"."platforms.linux-x64"] -checksum = "sha256:90f76f3e5fcb90ddc4c932ad352982bda98d58001d2bcccb982dd7fb2e608a1f" -url = "https://github.com/chainguard-dev/melange/releases/download/v0.59.1/melange_0.59.1_linux_amd64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/melange/releases/assets/514836359" - -[tools."aqua:chainguard-dev/melange"."platforms.macos-arm64"] -checksum = "sha256:6485fcff49ca60fc3f75a773eb1f7f81562cf394b86cc9fe8371f7d55e8f9b98" -url = "https://github.com/chainguard-dev/melange/releases/download/v0.59.1/melange_0.59.1_darwin_arm64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/melange/releases/assets/514836312" - -[tools."aqua:chainguard-dev/melange"."platforms.macos-x64"] -checksum = "sha256:0a1080caa973c9a10b9e331542e927531710810647c4f3b9ec9e53bf22f2e960" -url = "https://github.com/chainguard-dev/melange/releases/download/v0.59.1/melange_0.59.1_darwin_amd64.tar.gz" -url_api = "https://api.github.com/repos/chainguard-dev/melange/releases/assets/514836357" - [[tools."aqua:cli/cli"]] version = "2.97.0" backend = "aqua:cli/cli" @@ -156,34 +84,6 @@ url = "https://github.com/golangci/golangci-lint/releases/download/v2.12.2/golan url_api = "https://api.github.com/repos/golangci/golangci-lint/releases/assets/413470980" provenance = "github-attestations" -[[tools."aqua:goreleaser/goreleaser"]] -version = "2.17.1" -backend = "aqua:goreleaser/goreleaser" - -[tools."aqua:goreleaser/goreleaser"."platforms.linux-arm64"] -checksum = "sha256:702f03769ac8bcb0e47839c82243cc614ae995633599a98c63062e13ea85f829" -url = "https://github.com/goreleaser/goreleaser/releases/download/v2.17.1/goreleaser_Linux_arm64.tar.gz" -url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/490565875" -provenance = "github-attestations" - -[tools."aqua:goreleaser/goreleaser"."platforms.linux-x64"] -checksum = "sha256:a99bbc7ae0d8d897b07c4c497a9b62f222558804715ef219d1af05a7e417bc80" -url = "https://github.com/goreleaser/goreleaser/releases/download/v2.17.1/goreleaser_Linux_x86_64.tar.gz" -url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/490565870" -provenance = "github-attestations" - -[tools."aqua:goreleaser/goreleaser"."platforms.macos-arm64"] -checksum = "sha256:f49d4fe67d283b5b5130c380c983087dca0a4d4ec15b6637b18fe1ab096780d8" -url = "https://github.com/goreleaser/goreleaser/releases/download/v2.17.1/goreleaser_Darwin_all.tar.gz" -url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/490565848" -provenance = "github-attestations" - -[tools."aqua:goreleaser/goreleaser"."platforms.macos-x64"] -checksum = "sha256:f49d4fe67d283b5b5130c380c983087dca0a4d4ec15b6637b18fe1ab096780d8" -url = "https://github.com/goreleaser/goreleaser/releases/download/v2.17.1/goreleaser_Darwin_all.tar.gz" -url_api = "https://api.github.com/repos/goreleaser/goreleaser/releases/assets/490565848" -provenance = "github-attestations" - [[tools."aqua:moonrepo/moon"]] version = "2.3.5" backend = "aqua:moonrepo/moon" @@ -207,33 +107,29 @@ url_api = "https://api.github.com/repos/moonrepo/moon/releases/assets/458831440" checksum = "sha256:ffc0bf6e808f2c08f97593adec269c41fc6396e1399f546f13bb2f878efb6ce7" url = "https://github.com/moonrepo/moon/releases/download/v2.3.5/moon_cli-x86_64-apple-darwin.tar.xz" -[[tools."aqua:sigstore/cosign"]] -version = "3.1.3" -backend = "aqua:sigstore/cosign" - -[tools."aqua:sigstore/cosign"."platforms.linux-arm64"] -checksum = "sha256:c5d324e091826b0d7a78eb16fef316450b4eb9aaec045611c08ba06f5e73220a" -url = "https://github.com/sigstore/cosign/releases/download/v3.1.3/cosign-linux-arm64" -url_api = "https://api.github.com/repos/sigstore/cosign/releases/assets/503286299" -provenance = "cosign" - -[tools."aqua:sigstore/cosign"."platforms.linux-x64"] -checksum = "sha256:4629c757b7618056f8ddd7e2625ae9fdd94c0372a65049520bc7d9df9efc7f71" -url = "https://github.com/sigstore/cosign/releases/download/v3.1.3/cosign-linux-amd64" -url_api = "https://api.github.com/repos/sigstore/cosign/releases/assets/503286005" -provenance = "cosign" - -[tools."aqua:sigstore/cosign"."platforms.macos-arm64"] -checksum = "sha256:5cf948c2f4dfe59687bdd0b8523709067383e03982cc543475c8a7dc70e92a76" -url = "https://github.com/sigstore/cosign/releases/download/v3.1.3/cosign-darwin-arm64" -url_api = "https://api.github.com/repos/sigstore/cosign/releases/assets/503286205" -provenance = "cosign" - -[tools."aqua:sigstore/cosign"."platforms.macos-x64"] -checksum = "sha256:2347488e5d5b25336644024dfeca5601b190e91197a71a917bda44744aff106c" -url = "https://github.com/sigstore/cosign/releases/download/v3.1.3/cosign-darwin-amd64" -url_api = "https://api.github.com/repos/sigstore/cosign/releases/assets/503286177" -provenance = "cosign" +[[tools."aqua:vektra/mockery"]] +version = "3.7.1" +backend = "aqua:vektra/mockery" + +[tools."aqua:vektra/mockery"."platforms.linux-arm64"] +checksum = "sha256:27bcb1d78a4e78488aaa9f90864f6281456f12a92548d5deb0e0af719478f418" +url = "https://github.com/vektra/mockery/releases/download/v3.7.1/mockery_3.7.1_Linux_arm64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/445750704" + +[tools."aqua:vektra/mockery"."platforms.linux-x64"] +checksum = "sha256:79e6a7374d444f7e47aab79a30993ec403d0a573212c2c707c4bffede5f1780f" +url = "https://github.com/vektra/mockery/releases/download/v3.7.1/mockery_3.7.1_Linux_x86_64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/445750702" + +[tools."aqua:vektra/mockery"."platforms.macos-arm64"] +checksum = "sha256:ec94a61c80e55bcfa868c59b51a662dcb47e451ef041f3f274630b58a2647fb1" +url = "https://github.com/vektra/mockery/releases/download/v3.7.1/mockery_3.7.1_Darwin_arm64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/445750703" + +[tools."aqua:vektra/mockery"."platforms.macos-x64"] +checksum = "sha256:ccd4aed104cf886e4049b4ba5fafdf340a839c48b9d1b093927513051cc4df57" +url = "https://github.com/vektra/mockery/releases/download/v3.7.1/mockery_3.7.1_Darwin_x86_64.tar.gz" +url_api = "https://api.github.com/repos/vektra/mockery/releases/assets/445750705" [[tools.go]] version = "1.26.6" diff --git a/mise.toml b/mise.toml index a8307fb..e68ae6e 100644 --- a/mise.toml +++ b/mise.toml @@ -1,10 +1,9 @@ -# mise: tool + environment management for template-go. +# mise: tool + environment management for CodeMode. # -# mise REPLACES Proto (the former .prototools + .moon/proto/*). The committed -# mise.lock records per-platform download URLs + checksums; for aqua-backed tools -# it additionally carries cosign / SLSA / GitHub-attestation verification. -# `settings.locked` makes `mise install` FAIL CLOSED when a tool lacks a -# pre-resolved URL for the current platform. +# The committed mise.lock records per-platform download URLs + checksums, plus a +# `provenance` marker for the tools whose upstream releases carry verifiable +# GitHub attestations. `settings.locked` makes `mise install` FAIL CLOSED when a +# tool lacks a pre-resolved URL for the current platform. # # moon stays the task runner / CI gate; it is configured (.moon/toolchains.yml + # moon.yml `toolchains.default: system`) to run these tools as `system` binaries @@ -19,23 +18,19 @@ go = "1.26.6" python = "3.14.3" -# Go dev-tool CLI. The explicit `aqua:` ref forces the VERIFYING backend (checksum + -# cosign/SLSA/GitHub-attestation recorded in mise.lock); it must never fall back to -# a version-only backend (asdf/npm/cargo/pipx), which records no checksum. +# Go dev-tool CLIs. The explicit `aqua:` ref forces the VERIFYING backend (checksum +# and, where upstream provides it, attestation provenance recorded in mise.lock); it +# must never fall back to a version-only backend (asdf/npm/cargo/pipx), which +# records no checksum. "aqua:golangci/golangci-lint" = "2.12.2" +"aqua:vektra/mockery" = "3.7.1" # Docs (MkDocs) toolchain — moved off moon's former unstable_python/unstable_uv. "aqua:astral-sh/uv" = "0.11.0" -# Build / CI / release / supply-chain CLIs. The reusable release unit resolves -# these exact tools through mise and refuses unlocked replacements. -"aqua:moonrepo/moon" = "2.3.5" -"aqua:goreleaser/goreleaser" = "2.17.1" -"aqua:cli/cli" = "2.97.0" -"aqua:anchore/syft" = "1.51.0" -"aqua:sigstore/cosign" = "3.1.3" -"aqua:chainguard-dev/melange" = "0.59.1" -"aqua:chainguard-dev/apko" = "1.2.37" +# Task runner and GitHub CLI. +"aqua:moonrepo/moon" = "2.3.5" +"aqua:cli/cli" = "2.97.0" [env] # Pin the Go toolchain: never auto-download a toolchain other than the one above. @@ -44,39 +39,6 @@ GOTOOLCHAIN = "local" [settings] # Read/write mise.lock, and fail closed if a tool lacks a pre-resolved URL for the -# current platform — replaces Proto's `checksum-url` and extends integrity -# enforcement to every tool. +# current platform — integrity enforcement for every tool. lockfile = true locked = true - -# Local equivalent of the reusable OCI build's package-and-compose path. -# Go builds the canonical Linux binary; melange packages those exact bytes. -[tasks.image-local] -description = "Build the apko image for the host arch and load it into Docker as template-go:dev" -run = ''' -set -euo pipefail -go_arch="$(go env GOARCH)" -case "$go_arch" in - amd64) apk_arch="x86_64" ;; - arm64) apk_arch="aarch64" ;; - *) echo "unsupported host architecture: $go_arch" >&2; exit 1 ;; -esac - -rm -rf .image-local packages image.tar -mkdir -p .image-local -commit="$(git rev-parse --short HEAD 2>/dev/null || echo none)" -build_date="$(date -u +%Y-%m-%dT%H:%M:%SZ)" -CGO_ENABLED=0 GOOS=linux GOARCH="$go_arch" go build -trimpath \ - -ldflags="-s -w -buildid= -X main.version=dev -X main.commit=$commit -X main.date=$build_date" \ - -o .image-local/application ./cmd/template-go - -melange keygen melange.rsa -printf '{"version":"0.0.0"}\n' > .melange-vars.local.json -melange build melange.yaml --arch "$apk_arch" --signing-key melange.rsa --runner docker \ - --source-dir .image-local --out-dir packages --vars-file .melange-vars.local.json -apko build apko.yaml template-go:dev image.tar --arch "$go_arch" \ - --repository-append ./packages --keyring-append ./melange.rsa.pub -docker load < image.tar -docker tag "template-go:dev-$go_arch" template-go:dev -echo "loaded template-go:dev (host arch $go_arch)" -''' diff --git a/moon.yml b/moon.yml index 351b8c9..86feed5 100644 --- a/moon.yml +++ b/moon.yml @@ -1,10 +1,10 @@ language: 'go' -layer: 'application' +layer: 'library' stack: 'backend' project: - title: 'template-go' - description: 'Meigma Go repository template.' + title: 'codemode' + description: 'Go library for running MCP tool calls through bounded Starlark programs.' owner: 'meigma' maintainers: - 'meigma' @@ -31,11 +31,6 @@ fileGroups: - '.golangci.yml' - 'mise.toml' - 'mise.lock' - releaseConfig: - - '.goreleaser.yaml' - - 'release-please-config.json' - - '.release-please-manifest.json' - - '.github/workflows.disabled/**/*.yml' workspace: inheritedTasks: @@ -70,17 +65,40 @@ tasks: options: cache: false + # End-to-end guard for the real MCP transport loop: an actual MCP server, the + # real client session, and the bounded Starlark runtime wired together. + # + # `script` (not `command`) because moon's argument normalizer rewrites a + # trailing single-dash `-flag=value` into two arguments; `script` runs the line + # through the shell verbatim. + mcp-smoke: + script: "go test ./mcpserver -run '^TestActualMCPSecureLoop$' -count=1" + inputs: + - '@group(goSources)' + options: + cache: false + + # Concurrency guard: the library is used from concurrent MCP sessions, so the + # whole suite runs under the race detector. `script` for the same reason as + # `mcp-smoke`. + race: + script: 'go test -race ./... -count=1' + inputs: + - '@group(goSources)' + options: + cache: false + check: deps: - 'root:format' - 'root:lint' - 'root:build' - - 'root:test' + - 'root:mcp-smoke' + - 'root:race' - 'docs:build' inputs: - '@group(goSources)' - '@group(lintConfig)' - - '@group(releaseConfig)' options: cache: false runInCI: true diff --git a/release-please-config.json b/release-please-config.json index 94aaa1f..d97cb5a 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -9,7 +9,7 @@ "bump-patch-for-minor-pre-major": true, "packages": { ".": { - "package-name": "template-go", + "package-name": "codemode", "changelog-path": "CHANGELOG.md" } },