From 0b84f3900d86571402ab3d7a31e67a9bf91dd33d Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 22:29:20 +0000 Subject: [PATCH] ci: publish the Zig FFI library image to GHCR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a publish-image workflow + Containerfile so checky-monkey publishes its own GHCR image, re-linking the ghcr.io/hyperpolymath/checky-monkey package back to this repo (it was previously mis-attributed to odds-and-sods-package-manager, which built a Rust/axum service that does not exist here). checky-monkey is currently a Zig C-ABI library (libchecky_monkey.{so,a}) with Idris2 ABI bindings — not a running service — so the image is a distribution artifact carrying the compiled library for downstream FFI consumers. Also fixes a pre-existing compile error so the library builds: - ffi/zig/src/main.zig: `Handle` was declared as `opaque { ...fields... }`, which Zig rejects (opaque types cannot carry fields). Declared it as a struct; it is still exposed to C only as an opaque `*Handle` pointer. - The Containerfile builds the lib directly with `zig build-lib ... -lc` (libc is needed for std.heap.c_allocator), bypassing the in-tree build.zig, which is a not-yet-instantiated scaffold template ({{project}} placeholders + a missing include/ header). Verified locally with Zig 0.13.0: both the shared and static libraries build. Actions are SHA-pinned, permissions least-privilege, provenance attested. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_012kWck3NjBo5orHKAXMHm5W --- .github/workflows/publish-image.yml | 63 +++++++++++++++++++++++++++++ Containerfile | 37 +++++++++++++++++ ffi/zig/src/main.zig | 10 +++-- 3 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/publish-image.yml create mode 100644 Containerfile diff --git a/.github/workflows/publish-image.yml b/.github/workflows/publish-image.yml new file mode 100644 index 0000000..3ce23fe --- /dev/null +++ b/.github/workflows/publish-image.yml @@ -0,0 +1,63 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# Publish the checky-monkey FFI library image to GHCR so the +# ghcr.io/hyperpolymath/checky-monkey package links back to this repo via the +# org.opencontainers.image.source label injected by metadata-action. +name: Publish Image +on: + push: + branches: [main] + paths: + - 'ffi/zig/**' + - 'Containerfile' + - '.github/workflows/publish-image.yml' + workflow_dispatch: {} +permissions: + contents: read +jobs: + build-push: + name: Build and push image + runs-on: ubuntu-latest + timeout-minutes: 20 + permissions: + contents: read + packages: write + id-token: write + attestations: write + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + - name: Log in to GHCR + uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Extract metadata + id: meta + uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0 + with: + images: ghcr.io/hyperpolymath/checky-monkey + tags: | + type=raw,value=latest,enable={{is_default_branch}} + type=sha + - name: Build and push + id: push + uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v6 + with: + context: . + file: ./Containerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + - name: Attest container provenance + uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2 + with: + subject-name: ghcr.io/hyperpolymath/checky-monkey + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/Containerfile b/Containerfile new file mode 100644 index 0000000..aa1c474 --- /dev/null +++ b/Containerfile @@ -0,0 +1,37 @@ +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# Checky-Monkey — distribution image for the Zig FFI library. +# +# checky-monkey is currently an Idris2 ABI + Zig C-ABI library +# (libchecky_monkey.{so,a}), not a running service. This image is a +# distribution artifact carrying the compiled library (and its source) for +# downstream FFI consumers to `COPY --from`. The in-tree build.zig is a +# not-yet-instantiated scaffold template (its `{{project}}` placeholders and a +# missing include/ header break `zig build`), so the library is built directly +# with `zig build-lib`, which only needs the self-contained src/main.zig. +FROM cgr.dev/chainguard/wolfi-base:latest AS builder +RUN apk add --no-cache zig +WORKDIR /build +COPY ffi/zig/src/ ./src/ +# Build the shared (.so) and static (.a) libraries directly from the +# self-contained source (src/main.zig imports only std + builtin). -lc links +# libc, which std.heap.c_allocator requires. +RUN zig build-lib src/main.zig -dynamic -O ReleaseSafe --name checky_monkey -lc \ + && zig build-lib src/main.zig -O ReleaseSafe --name checky_monkey -lc \ + && ls -l libchecky_monkey.so libchecky_monkey.a + +FROM cgr.dev/chainguard/wolfi-base:latest +RUN apk add --no-cache libgcc \ + && addgroup -g 1000 checky \ + && adduser -D -u 1000 -G checky checky +WORKDIR /app +COPY --from=builder --chown=checky:checky /build/libchecky_monkey.so /build/libchecky_monkey.a ./lib/ +COPY --chown=checky:checky ffi/zig/src/ ./src/ +USER checky +# A library image — no server, so no EXPOSE / no service HEALTHCHECK. +LABEL org.opencontainers.image.title="Checky-Monkey" \ + org.opencontainers.image.description="Idris2 ABI + Zig FFI library for userscript verification (libchecky_monkey.{so,a})" \ + org.opencontainers.image.source="https://github.com/hyperpolymath/checky-monkey" \ + org.opencontainers.image.licenses="MPL-2.0" \ + org.opencontainers.image.authors="Jonathan D.A. Jewell " diff --git a/ffi/zig/src/main.zig b/ffi/zig/src/main.zig index d19f02e..5047a65 100644 --- a/ffi/zig/src/main.zig +++ b/ffi/zig/src/main.zig @@ -37,12 +37,14 @@ pub const Result = enum(c_int) { null_pointer = 4, }; -/// Library handle (opaque to prevent direct access) -pub const Handle = opaque { - // Internal state hidden from C +/// Library handle. Exposed to C as an opaque `*Handle` pointer — callers never +/// dereference it, so the field layout stays private in practice. (Declared as +/// a struct rather than `opaque {}` because Zig opaque types cannot carry +/// fields; the previous `opaque { ... fields ... }` form did not compile.) +pub const Handle = struct { + // Internal state, hidden from C behind the opaque pointer. allocator: std.mem.Allocator, initialized: bool, - // Add your fields here }; //==============================================================================