diff --git a/.github/workflows/next.yaml b/.github/workflows/next.yaml index 10a618a..535a446 100644 --- a/.github/workflows/next.yaml +++ b/.github/workflows/next.yaml @@ -21,6 +21,14 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' || (github.event.pull_request && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.head.ref == 'next') }} name: Docker Pre-release runs-on: ubuntu-latest + strategy: + matrix: + include: + - target: final + tag: 'next' + - target: debug-shell + tag: 'next-shell' + steps: - name: Check out the repo uses: actions/checkout@v4 @@ -31,7 +39,7 @@ jobs: with: images: ghcr.io/${{ github.repository }} tags: | - type=raw,value=next + type=raw,value=${{ matrix.tag }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -46,22 +54,26 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push Docker image + - name: Build and publish ghcr.io/${{ github.repository }}:${{ matrix.tag }} uses: docker/build-push-action@v6 id: push with: context: . file: ./Dockerfile + target: ${{ matrix.target }} push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64, linux/arm64 cache-from: type=gha cache-to: type=gha,mode=max - - name: Attestation Provenance + build-args: | + IMAGE_TAG=ghcr.io/${{ github.repository }}:${{ matrix.tag }} + + - name: Attestation Provenance for ghcr.io/${{ github.repository }}:${{ matrix.tag }} uses: actions/attest-build-provenance@v2 id: attest with: - subject-name: ghcr.io/${{ github.repository }} + subject-name: ghcr.io/${{ github.repository }}:${{ matrix.tag }} subject-digest: ${{ steps.push.outputs.digest }} push-to-registry: true diff --git a/.tool-versions b/.tool-versions index e39e04d..c06aa6a 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,4 @@ +# REMEMBER TO UPDATE mise.toml TOO pnpm 10.4.0 node 22.16 go 1.24.4 diff --git a/Dockerfile b/Dockerfile index b722f5c..4e593e9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM --platform=$BUILDPLATFORM jdxcode/mise:latest AS mise-context -COPY mise.toml . +COPY mise.toml .tool-versions ./ RUN mise install FROM --platform=$BUILDPLATFORM mise-context AS go-build @@ -13,11 +13,13 @@ COPY internal/ ./internal/ ARG TARGETOS ARG TARGETARCH +ARG IMAGE_TAG RUN mkdir -p /build/app/ && \ - GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 \ - mise run wasm ::: agent + GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 IMAGE_TAG=$IMAGE_TAG \ + mise run wasm ::: agent ::: fake-shell RUN chmod +x /build/build/hp_agent +RUN chmod +x /build/build/sh FROM --platform=$BUILDPLATFORM mise-context AS js-build WORKDIR /build @@ -32,7 +34,23 @@ COPY --from=go-build /build/app/wasm_exec.js /build/app/wasm_exec.js RUN pnpm run build RUN mkdir -p /var/lib/headplane/agent -FROM gcr.io/distroless/nodejs22-debian12:nonroot +FROM gcr.io/distroless/nodejs22-debian12:nonroot AS final +COPY --from=js-build --chown=nonroot:nonroot /build/build/ /app/build/ +COPY --from=js-build --chown=nonroot:nonroot /build/drizzle /app/drizzle/ +COPY --from=js-build --chown=nonroot:nonroot /var/lib/headplane /var/lib/headplane +COPY --from=js-build --chown=nonroot:nonroot /build/node_modules/ /app/node_modules/ +COPY --from=go-build --chown=nonroot:nonroot /build/build/hp_agent /usr/libexec/headplane/agent + +# Fake shell to inform the user that they should use the debug image +COPY --from=go-build --chown=nonroot:nonroot /build/build/sh /bin/sh +COPY --from=go-build --chown=nonroot:nonroot /build/build/sh /bin/bash + +WORKDIR /app +CMD [ "/app/build/server/index.js" ] + +FROM node:22-alpine AS debug-shell +RUN apk add --no-cache bash curl git + COPY --from=js-build --chown=nonroot:nonroot /build/build/ /app/build/ COPY --from=js-build --chown=nonroot:nonroot /build/drizzle /app/drizzle/ COPY --from=js-build --chown=nonroot:nonroot /var/lib/headplane /var/lib/headplane @@ -40,4 +58,4 @@ COPY --from=js-build --chown=nonroot:nonroot /build/node_modules/ /app/node_modu COPY --from=go-build --chown=nonroot:nonroot /build/build/hp_agent /usr/libexec/headplane/agent WORKDIR /app -CMD [ "/app/build/server/index.js" ] +CMD [ "node", "/app/build/server/index.js" ] diff --git a/cmd/fake_sh/fake_sh.go b/cmd/fake_sh/fake_sh.go new file mode 100644 index 0000000..8057a33 --- /dev/null +++ b/cmd/fake_sh/fake_sh.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "os" +) + +var imageTag string + +func main() { + if imageTag == "" { + os.Exit(1) + } + + fmt.Fprintln(os.Stderr, "Headplane containers do not contain a shell by default.") + fmt.Fprintln(os.Stderr, "If you need a non-production container with a shell and root access use:") + fmt.Fprintf(os.Stderr, "\n%s-shell\n\n", imageTag) + os.Exit(127) +} diff --git a/mise.toml b/mise.toml index e5b2ab6..559c243 100644 --- a/mise.toml +++ b/mise.toml @@ -1,3 +1,9 @@ +[tools] +# REMEMBER TO UPDATE .tool-versions TOO +go = "1.24.4" +pnpm = "10.4.0" +node = "22.16" + [tasks.copy-wasm-shim] alias = ["gojs"] description = "Copies Go's wasm_exec.js to the public directory" @@ -18,6 +24,14 @@ alias = ["agent"] description = "Builds the Go agent for HostInfo" run = "go build -o build/hp_agent ./cmd/hp_agent" +[tasks.build-fake-shell] +alias = ["fake-shell"] +description = "Builds the fake shell for Distroless docker images" +run = [ + 'test -n "$IMAGE_TAG" || (echo "IMAGE_TAG is not set" && exit 1)', + 'go build -ldflags="-s -w -X main.imageTag=$IMAGE_TAG" -o build/sh ./cmd/fake_sh' +] + [tasks.generate-caddy-certs] alias = ["mkcert"] dir = "{{cwd}}/test/caddy/certs"