Files
gronod 6d47ec4e48
Build and publish / Test and build (darwin) (push) Successful in 1m25s
Build and publish / Test and build (windows) (push) Successful in 3m6s
Build and publish / Test and build (linux) (push) Successful in 3m59s
Build and publish / Build and publish Docker image (push) Successful in 2m41s
Validate Docker daemon access before CI steps
The workflow now verifies that all three DinD TLS certificates are readable
before attempting registry login or Buildx operations. The check fails early
with instructions to apply runner-compose.yaml if the runner has not mounted
/certs/client into job containers.

Buildx now creates a named Docker context from the TLS environment variables,
as Buildx cannot use TLS endpoints without an explicit context. Each CI run
uses a uniquely named builder (based
2026-09-18 23:20:51 +01:00

6.2 KiB

Gitea CI/CD

The workflow in .gitea/workflows/build.yml runs on branch pushes, v* tag pushes, pull requests, and manual dispatches. Each platform runs formatting, vet, and unit checks before building static AMD64 and ARM64 binaries. Linux also runs the mock Ombi integration suite. No live Ombi credentials are needed.

Download the ombi-mcp-darwin, ombi-mcp-linux, or ombi-mcp-windows artifacts from the workflow run. Each contains two .tar.gz archives, one per architecture, with the executable and README. Tar preserves Unix executable permissions.

Runner setup

Enable Actions in the repository settings and register these runner labels:

Label Host / requirements
macos macOS host runner, Git, Bash, tar, Node.js 20
windows Windows host runner, Git for Windows (Bash on PATH), tar, Node.js 20; public-repository access
ubuntu-latest Linux runner with Git, Bash, tar, Node.js 20, Docker Engine, curl, and Docker daemon access

The Linux jobs use the ubuntu-latest runner label. The Windows job uses Git directly because the self-hosted Windows runner cannot start the Node-based checkout action; it therefore requires access to the public repository URL. setup-go installs the version specified in go.mod. Runners need network access to GitHub actions, Go downloads/modules, Docker Hub, GitHub release downloads, and git.i3omb.com. For a Docker-in-Docker runner, the Docker job expects the sibling service at docker:2376 with TLS enabled and the client certificates mounted at /certs/client inside the job container. The workflow sets DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT_PATH explicitly because act_runner service environment variables are not inherited by job containers. If Buildx is absent, the workflow installs its pinned CLI plugin before building. Artifact uploads use upload-artifact@v3 for compatibility with Gitea's older artifact API.

The workflow requests a bind mount of /certs/client and maps docker to host-gateway. The bind source is resolved inside the DinD daemon's filesystem, where its client certificates exist. Job containers run inside that daemon; they do not share the outer Compose service network.

The runner must also permit that bind source in its active configuration:

container:
  valid_volumes:
    - /certs/client

Run 41655's job 43221 confirmed the runner discarded the requested mount: [/certs/client] is not a valid volume, will be ignored. Adding workflow options does not override this runner allowlist. This occurs before registry authentication or Buildx can run.

For the existing TrueNAS deployment, runner-compose.yaml is a complete replacement Compose definition. Apply it to the existing Compose project, preserving its volume names and data directories. It embeds the allowlist using Compose configs.content (requires Compose 2.23.1+) and sets CONFIG_FILE=/etc/act_runner/config.yaml, which the official entrypoint passes to the daemon. It reuses the existing /data/.runner registration, so no registration token is needed. The old /data/config.yaml remains on disk but is no longer used.

Before applying, verify the registered runner and DinD certificates exist:

docker exec gitea-runner test -s /data/.runner
docker exec gitea-dind test -s /certs/client/ca.pem

After saving the replacement YAML as the existing project's Compose file:

docker compose config --quiet
docker compose up -d --no-deps --force-recreate act-runner
docker exec gitea-runner cat /etc/act_runner/config.yaml

The printed config must contain /certs/client under container.valid_volumes. Then rerun CI. Its first Docker step verifies that all three TLS files are readable and that docker version can reach the daemon before attempting registry login. This repository change cannot update the running TrueNAS container itself.

References: Gitea runner volume configuration, Docker bind mount source paths, and Compose inline configs.

Container publishing

After all binary jobs succeed, Buildx builds a non-root, scratch-based image for linux/amd64 and linux/arm64. Cross-compilation runs on the builder's native architecture, so no QEMU installation is needed. The image includes public CA certificates for HTTPS connections to Ombi. Authentication and the Ombi URL are supplied at runtime.

The image job creates a named Docker context containing the DinD TLS endpoint and certificate paths; Buildx cannot create a builder from TLS environment variables alone. Each CI attempt uses its own builder and removes it on exit.

Set these repository Actions secrets before publishing:

Secret Value
REGISTRY_USERNAME Gitea username with permission to publish packages under the repository owner
REGISTRY_TOKEN That user's personal access token with write:package scope

The destination is git.i3omb.com/<repository-owner>/<repository-name> (lowercase), which is git.i3omb.com/gronod/ombi-mcp for this repository.

  • Default-branch pushes publish latest and sha-<full-commit-sha>.
  • Version-tag pushes publish the exact tag (for example v1.2.3) and the SHA tag. They do not replace latest, including prerelease tags.
  • Pull requests, other branches, and manual runs build without logging in or pushing.

Gitea's job token is not used for registry login; see the documented package authorization limitation and container registry instructions. Publishing uploads the image; it does not restart any running deployment.

Running the image

For stdio, keep stdin open and do not allocate a TTY:

docker run --rm -i --env-file .env git.i3omb.com/gronod/ombi-mcp:latest

For HTTP/SSE:

docker run --rm --env-file .env -e MCP_TRANSPORT=sse \
  -p 8080:8080 git.i3omb.com/gronod/ombi-mcp:latest

Build locally with docker build -t ombi-mcp .. CI passes the Go version from go.mod as a build argument; when upgrading Go, also update the Dockerfile's default GO_VERSION for local builds.