Files
image-build/README.md
T

134 lines
6.0 KiB
Markdown
Raw Normal View History

2026-05-06 08:07:13 -05:00
# action/image-build
Composite Gitea Action that builds a container image with buildx and optionally
runs a smoke test. **Does not push** — pair with `action/image-push` to publish.
Splitting build from push lets a PR workflow run `image-build` without push or
deploy side effects while `main` runs the full build → push → deploy chain. A
PR build that pulls a private base image still needs a registry token limited to
the `read:package` capability; public-base builds need no token. The action logs
in as `ci-bot`, so the token must be issued to that account.
2026-05-06 08:07:13 -05:00
## Private Go module builds
`tools/private-modules/` owns the stdlib-only offline generator and verifier for
native Go file-proxy bundles. Consumers export exact committed source bytes so
their first check needs no Git, network, module dependency, or credential.
Changes belong here; consumers must not edit their generated copies.
From this checkout, export a reviewed full commit ID into a service checkout:
```sh
python3 tools/export-private-modules.py /path/to/service --revision FULL_COMMIT_ID
python3 tools/export-private-modules.py /path/to/service --revision FULL_COMMIT_ID --check
```
The export includes source revision/path/digest metadata and a SHA256 lock.
Service Make and Docker builds run `sha256sum -c tools/private-modules.sha256`
before `GO111MODULE=off GOTOOLCHAIN=local GOFLAGS= go run tools/private-modules.go`.
Reviewers can reproduce `--check` from that pinned source commit. The local hash
check detects accidental drift; Git review establishes the trusted source pin.
Populate selected private versions through the configured authenticated Go
client once, then run the generated command with `-write` to copy unchanged
`.info`, `.mod`, and `.zip` cache artifacts into `third_party/go-proxy`. The
generator itself enforces offline resolution and a local toolchain. It preserves
the complete original archives, including any licenses and notices. Normal Go
downloads still validate their content against the consumer's `go.sum`.
The generated proxy directory has an exact build-only nested `go.mod` marker.
Native Go module packaging excludes that directory from provider releases, so
downstream consumers never recursively bundle another provider's build inputs.
The checker requires the marker, and a native local-Git archive test proves the
exclusion without permitting Git network protocols.
Consumer resolution uses `GONOPROXY=none`, `GONOSUMDB=code.fritzlab.net`,
`GOFLAGS=-mod=readonly`, `GOTOOLCHAIN=local`, and
`GOPROXY=file:///absolute/service/third_party/go-proxy,https://proxy.golang.org`.
Run the checker before and after downloads; its exact go.mod/go.sum fingerprint
rejects stale dependency closures. Public modules stay on the public proxy.
Registry publication remains a separate authenticated operation.
2026-05-06 08:07:13 -05:00
## Usage
```yaml
- uses: actions/checkout@v4
- uses: https://code.fritzlab.net/action/image-build@v1
with:
image: code.fritzlab.net/fritzlab/chrony
smoke-test: docker run --rm --entrypoint /usr/sbin/chronyd $IMAGE -v
```
The image is built and tagged as `<image>:<github.run_number>` in the runner's
local Docker daemon. Subsequent steps (e.g. `action/image-push`) can reference
the same tag.
### Private bases in PRs
Pass `token` only when the PR head is trusted, and limit `ci-bot` package access
to the private base images that the build requires. Never expose an
organization-wide package reader to a contributor-controlled Dockerfile: it can
pull and disclose any package that the account can read.
```yaml
with:
token: ${{ secrets.PACKAGE_READ_TOKEN }} # caller-chosen secret name
```
The token must be issued to `ci-bot` with `read:package` capability. Tokens from
other accounts fail because the action's registry username is fixed. Omit the
input for public bases.
2026-05-06 08:07:13 -05:00
## Inputs
| Name | Required | Default | Description |
|---|---|---|---|
| `image` | yes | — | Full image name without tag (e.g. `code.fritzlab.net/fritzlab/chrony`). |
| `context` | no | `.` | Docker build context. |
2026-05-27 13:07:11 -05:00
| `dockerfile` | no | `Dockerfile` (in context) | Path to the Dockerfile, relative to the context (or absolute under `$GITHUB_WORKSPACE`). Use for monorepos where the build context is the repo root but the Dockerfile lives in a subdir, e.g. `dockerfile: api/Dockerfile`. |
| `build-args` | no | — | Multiline `KEY=VALUE` build args. Visible in `docker history` — never put secrets here. |
| `secrets` | no | — | Multiline `id=VALUE` BuildKit secrets (`--secret`). For tokens the build needs (e.g. a ci-bot token to `go mod download` a private module) that must not leak into layers. Reference with `RUN --mount=type=secret,id=<id>`. |
2026-05-06 08:07:13 -05:00
| `smoke-test` | no | — | Shell command run after build. `$IMAGE` is set to `<image>:<run_number>`. Non-zero exit fails the action. |
| `token` | no | — | `ci-bot` access token with `read:package` capability. Required to pull a private base image; omit for public bases. |
2026-05-06 08:07:13 -05:00
## Outputs
| Name | Description |
|---|---|
| `tag` | Numeric tag assigned (= `github.run_number`). |
## Private module contract validation
The private-module contract workflow runs its Go race tests in the digest-pinned
standard Go compiler image in `tests/private-modules.Dockerfile`. The Fritzlab
runner doesn't provide GCC. Only `tools/private-modules` enters that build context;
the test runs with networking and module downloads disabled. The public compiler
image must already be cached or obtainable through the existing image pull path.
This check doesn't publish an image or change runner configuration.
```sh
python3 -m unittest discover -s tests
docker build --network none --file tests/private-modules.Dockerfile tools/private-modules
```
2026-05-06 08:07:13 -05:00
## Smoke test patterns
Override entrypoint for a binary that expects no args:
```yaml
smoke-test: docker run --rm --entrypoint /usr/sbin/chronyd $IMAGE -v
```
Run a help command that returns non-zero:
```yaml
smoke-test: docker run --rm $IMAGE --help || true
```
Multiple checks chained:
```yaml
smoke-test: |
docker run --rm $IMAGE --version
docker run --rm --entrypoint /bin/sh $IMAGE -c 'test -x /usr/local/bin/myapp'
```