Repository navigation
Linux amd64 #294
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Linux amd64 | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ['[0-9]+.[0-9]+.[0-9]+'] | |
| pull_request: | |
| workflow_dispatch: | |
| jobs: | |
| build: | |
| runs-on: ubuntu-22.04 | |
| # Frozen toolchain, not the runner image: the ubuntu-22.04 label | |
| # re-rolls weekly (gcc/glibc/binutils drift). This digest and the | |
| # archive snapshot below are both immutable, so the same commit | |
| # produces the same bytes forever. Verified by the reproducibility | |
| # check step. To move forward: look up the new digest, pick a new | |
| # snapshot timestamp, rebuild twice, compare. | |
| container: | |
| image: ubuntu:22.04@sha256:b8b6ee6aa931ecd9d0d952abc34dc0e5f7c6a30c6bb71b079fe399fde0329c02 | |
| steps: | |
| - name: Freeze apt to a pinned archive snapshot | |
| # Runs before checkout: the base image has no git yet. ca-certificates | |
| # comes from the live archive first (it only affects TLS trust, not | |
| # artifact bytes); everything that touches the binary comes from the | |
| # frozen snapshot. | |
| run: | | |
| export DEBIAN_FRONTEND=noninteractive | |
| apt-get update | |
| apt-get install -y --no-install-recommends ca-certificates | |
| sed -i 's|http://archive.ubuntu.com/ubuntu/|https://snapshot.ubuntu.com/ubuntu/20260925T000000Z/|; s|http://security.ubuntu.com/ubuntu/|https://snapshot.ubuntu.com/ubuntu/20260925T000000Z/|' /etc/apt/sources.list | |
| apt-get update | |
| # build-essential: gcc/binutils for the binary; git: checkout + | |
| # config.nims's version probe; curl/xz: nim toolchain download; | |
| # procps: test watchdog ps/pgrep; zstd: actions/cache | |
| apt-get install -y --no-install-recommends build-essential git curl ca-certificates xz-utils procps zstd | |
| - uses: actions/checkout@v4 | |
| - name: Trust the checkout | |
| # config.nims runs git (branch/sha/status) for the version define; | |
| # in a container the workspace is owned by a different uid, so | |
| # git would refuse and corrupt the version string. | |
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| - uses: jiro4989/setup-nim-action@v2 | |
| with: | |
| # Exact version, not `stable`: the same commit must compile with | |
| # the same compiler forever. Bump deliberately, together with | |
| # regenerating nimble.lock (its `nim` entry records the version). | |
| nim-version: 2.2.12 | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| parent-nim-install-directory: /opt | |
| nim-install-directory: nim-toolchain | |
| - name: Install dependencies | |
| # nimble.lock pins every dependency to an exact revision + checksum; | |
| # install honors it, so rebuilds of the same commit get identical | |
| # dependency trees (bump requires -> `nimble lock` to update). | |
| run: | | |
| nimble install -y --depsOnly | |
| - name: Compute build flags | |
| run: | | |
| if [[ "${GITHUB_REF}" == refs/tags/* ]]; then | |
| # autoupdate on releases only | |
| echo "BUILD_FLAGS=-d:autoUpdate" >> "$GITHUB_ENV" | |
| fi | |
| - name: Build | |
| run: nimble build -y -d:release ${{ env.BUILD_FLAGS }} | |
| - name: Reproducibility check (rebuild from scratch) | |
| # A clean recompile+relink of the same tree must be byte-identical. | |
| # Catches ordering nondeterminism and anything the build itself | |
| # leaks into the binary (paths, timestamps, git state). | |
| run: | | |
| h1=$(sha256sum 3code | cut -d' ' -f1) | |
| rm -f 3code | |
| rm -rf ~/.cache/nim/threecode_r | |
| nimble build -y -d:release ${{ env.BUILD_FLAGS }} | |
| h2=$(sha256sum 3code | cut -d' ' -f1) | |
| [ "$h1" = "$h2" ] || { echo "rebuild differs: $h1 vs $h2" >&2; exit 1; } | |
| echo "reproducible: $h2" | |
| - name: Package | |
| # SOURCE_DATE_EPOCH anchors all archive mtimes to the commit, so | |
| # the tarball is byte-identical across rebuilds of one commit. | |
| run: | | |
| export SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)" | |
| mkdir -p 3code-linux-amd64 | |
| cp 3code 3code-linux-amd64/ | |
| # Capture the version from the built binary so it can be checked | |
| # without running the binary on its target OS. | |
| ./3code -v > 3code-linux-amd64/VERSION | |
| # Toolchain provenance: answers "same toolchain?" when comparing | |
| # two builds later. | |
| { | |
| nim --version | head -1 | |
| cc --version | head -1 | |
| sha256sum 3code | cut -d' ' -f1 | |
| echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" | |
| } > 3code-linux-amd64/BUILD_INFO | |
| cp README.md LICENSE 3code-linux-amd64/ | |
| pack() { | |
| tar --sort=name --mtime="@${SOURCE_DATE_EPOCH}" --owner=0 --group=0 --numeric-owner \ | |
| -cf - 3code-linux-amd64 | gzip -n > 3code-linux-amd64.tar.gz | |
| } | |
| pack | |
| h1=$(sha256sum 3code-linux-amd64.tar.gz | cut -d' ' -f1) | |
| find 3code-linux-amd64 ! -type l -exec touch {} + # perturb mtimes (not symlinks: touch would create dangling targets) | |
| pack | |
| h2=$(sha256sum 3code-linux-amd64.tar.gz | cut -d' ' -f1) | |
| [ "$h1" = "$h2" ] || { echo "archive not reproducible: $h1 vs $h2" >&2; exit 1; } | |
| - name: Upload artifact (GitHub Actions) | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: 3code-linux-amd64 | |
| path: 3code-linux-amd64.tar.gz | |
| - name: Upload artifact to 3code.capocasa.dev | |
| if: github.ref == 'refs/heads/main' | |
| run: | | |
| # --retry: 5xx is transient on the upload endpoint | |
| curl -f --retry 5 --retry-delay 5 -H "Authorization: Bearer ${{ secrets.RELEASE_SECRET }}" -F "file=@3code-linux-amd64.tar.gz" \ | |
| https://3code.capocasa.dev/main/builds/upload.nim | |
| test: | |
| # Tests stay on the stock runner: they produce no artifacts, and the | |
| # sandbox/tty tests assume runner-level kernel access (landlock, | |
| # userns, PTYs) that a container's seccomp profile may not allow. | |
| needs: build | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: jiro4989/setup-nim-action@v2 | |
| with: | |
| nim-version: 2.2.12 | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| parent-nim-install-directory: $HOME | |
| nim-install-directory: nim-toolchain | |
| - name: Install dependencies | |
| # Same lock as the build jobs: what gets tested is what ships. | |
| run: | | |
| nimble install -y --depsOnly | |
| - name: Run tests | |
| # tests/tools/ci_tests.sh wraps `testament all`: categories still run in | |
| # parallel (one testament child per category), but output lands in | |
| # a log file instead of a pipe, a watchdog bounds the run and | |
| # attributes any hang to the exact test binary, and the exit code | |
| # is propagated. The old `for c in ...; testament cat` loop ran | |
| # categories sequentially and, worse, a single hung test stalled | |
| # the pipe so the step showed nothing after it. | |
| run: sh tests/tools/ci_tests.sh 1500 | |
| timeout-minutes: 30 |