Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: docker/setup-buildx-action@v3
# Multi-arch builds for releases happen in release.yaml via GoReleaser
# (uses native runners + Go cross-compile, not QEMU). This job is a fast
# PR smoke test — single-platform, host-arch.
# Multi-arch builds for releases happen in release.yaml via
# docker/build-push-action (uses Go cross-compile under
# BUILDPLATFORM, not QEMU). This job is a fast PR smoke test:
# single-platform, host-arch.
- uses: docker/login-action@v4
if: github.event_name == 'push'
with:
Expand Down
62 changes: 45 additions & 17 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,50 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Sign container image tags with cosign (keyless OIDC)
env:
COSIGN_EXPERIMENTAL: "true"
- name: Compute image tags
id: image_tags
run: |
IMAGE="ghcr.io/stubbi/hermes-operator"
TAG="${{ github.ref_name }}"
MAJOR_MINOR=$(echo "$TAG" | sed 's/^v//' | cut -d. -f1,2)
for t in "${TAG}" "${MAJOR_MINOR}" "latest"; do
DIGEST=$(docker buildx imagetools inspect "${IMAGE}:${t}" --format '{{.Manifest.Digest}}' 2>/dev/null || true)
if [ -n "$DIGEST" ]; then
cosign sign --yes "${IMAGE}@${DIGEST}"
fi
done
IMAGE="ghcr.io/stubbi/hermes-operator"
{
echo "image=${IMAGE}"
echo "major_minor=${MAJOR_MINOR}"
} >> "$GITHUB_OUTPUT"
{
echo "tags<<EOF"
echo "${IMAGE}:${TAG}"
echo "${IMAGE}:${MAJOR_MINOR}"
echo "${IMAGE}:latest"
echo "EOF"
} >> "$GITHUB_OUTPUT"

- name: Build and push container image (multi-arch)
id: docker_build
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.image_tags.outputs.tags }}
provenance: true
sbom: false
cache-from: type=gha
cache-to: type=gha,mode=max
labels: |
org.opencontainers.image.title=hermes-operator
org.opencontainers.image.version=${{ github.ref_name }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.source=https://github.com/stubbi/hermes-operator
org.opencontainers.image.licenses=Apache-2.0

- name: Sign container image with cosign (keyless OIDC)
env:
COSIGN_EXPERIMENTAL: "true"
IMAGE: ${{ steps.image_tags.outputs.image }}
DIGEST: ${{ steps.docker_build.outputs.digest }}
run: cosign sign --yes "${IMAGE}@${DIGEST}"

- name: Generate SBOM for container image
uses: anchore/sbom-action@v0
Expand All @@ -83,13 +114,10 @@ jobs:
- name: Attest SBOM with cosign
env:
COSIGN_EXPERIMENTAL: "true"
run: |
IMAGE="ghcr.io/stubbi/hermes-operator"
TAG="${{ github.ref_name }}"
DIGEST=$(docker buildx imagetools inspect "${IMAGE}:${TAG}" --format '{{.Manifest.Digest}}' 2>/dev/null || true)
if [ -n "$DIGEST" ]; then
cosign attest --yes --predicate "sbom-${TAG}.spdx.json" --type spdxjson "${IMAGE}@${DIGEST}"
fi
IMAGE: ${{ steps.image_tags.outputs.image }}
DIGEST: ${{ steps.docker_build.outputs.digest }}
TAG: ${{ github.ref_name }}
run: cosign attest --yes --predicate "sbom-${TAG}.spdx.json" --type spdxjson "${IMAGE}@${DIGEST}"

- name: Upload SBOM to GitHub release
uses: softprops/action-gh-release@v2
Expand Down
33 changes: 4 additions & 29 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,10 @@ builds:
- -X main.commit={{.Commit}}
- -X main.date={{.Date}}

dockers_v2:
- id: hermes-operator
dockerfile: Dockerfile
ids:
- manager
images:
- "ghcr.io/stubbi/hermes-operator"
tags:
- "{{ .Tag }}"
- "{{ .Major }}.{{ .Minor }}"
- "latest"
platforms:
- linux/amd64
- linux/arm64
labels:
"org.opencontainers.image.title": "{{ .ProjectName }}"
"org.opencontainers.image.version": "{{ .Version }}"
"org.opencontainers.image.revision": "{{ .FullCommit }}"
"org.opencontainers.image.created": "{{ .Date }}"
"org.opencontainers.image.source": "{{ .GitURL }}"
"org.opencontainers.image.licenses": "Apache-2.0"
build_args:
PREBUILT_BINARY: "manager"
extra_files:
- cmd/
- api/
- internal/
- go.mod
- go.sum
# Container images are built separately by docker/build-push-action in the
# release workflow. GoReleaser's dockers_v2 had trouble staging the prebuilt
# binary into the build context, and buildx with native Go cross-compile
# (BUILDPLATFORM) is faster than QEMU anyway.

archives:
- id: binaries
Expand Down
28 changes: 7 additions & 21 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,36 +1,22 @@
ARG PREBUILT_BINARY=""

# Build the manager binary
FROM golang:1.26 AS builder
ARG PREBUILT_BINARY
# Build the manager binary. Use BUILDPLATFORM so Go cross-compiles natively
# rather than running the whole compile under QEMU emulation, which is
# pathologically slow for Go.
FROM --platform=$BUILDPLATFORM golang:1.26 AS builder
ARG TARGETOS
ARG TARGETARCH

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN if [ -z "$PREBUILT_BINARY" ]; then go mod download; fi
RUN go mod download

# Copy the go source
COPY cmd/ cmd/
COPY api/ api/
COPY internal/ internal/

# GoReleaser will COPY a prebuilt binary in; otherwise build from source.
COPY ${PREBUILT_BINARY:-cmd/main.go} ./prebuilt-or-main
RUN set -eu; \
if [ -n "${PREBUILT_BINARY:-}" ]; then \
cp ./prebuilt-or-main /workspace/manager && chmod +x /workspace/manager; \
else \
rm ./prebuilt-or-main && \
CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o /workspace/manager cmd/main.go; \
fi
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} \
go build -a -ldflags="-s -w" -o /workspace/manager cmd/main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --from=builder /workspace/manager .
Expand Down
Loading