Compare commits

...

3 Commits

Author SHA1 Message Date
74c28c1d71 Merge pull request '#17: Hash-pin every external reference in deploy.yml (closes #7)'
Some checks failed
check / check (push) Successful in 3s
Build and Deploy to Cloudflare Pages / build (push) Failing after 22s
Build and Deploy to Cloudflare Pages / deploy (push) Has been skipped
2026-08-09 04:28:21 +02:00
b157bfd52c Install runner prerequisites in the pinned build container (closes #7)
All checks were successful
check / check (push) Successful in 10s
Replacing klakegg/hugo:ext-alpine with the Dockerfile's pinned alpine
digest satisfied the pinning requirement but dropped the runtime the
Actions runner itself depends on, which would have broken the deploy:

- act_runner executes JavaScript actions with `node` inside the job
  container and does not inject one. Stock alpine has no node, so
  actions/checkout - the job's first step - would fail with
  "node: not found", and script/bootstrap (which installs node) is step
  2 and never runs. The build job fails, deploy is skipped for
  `needs: build`, and the site stops publishing.
- Steps default to `bash`, which stock alpine does not ship either.

Fixes, both scoped to keeping the mandated image replacement runnable:

- A pre-checkout inline `run:` step (`apk add --no-cache nodejs git tar`)
  installs what the runner needs before the first `uses:` step. An
  inline run needs only a shell, so it works on the bare image. git is
  there for checkout's `submodules: recursive`; without it checkout
  degrades to a tarball download that cannot do submodules.
- `defaults.run.shell: sh` on the build job, so the shell is stated
  rather than left to a bash-to-sh fallback.

No pinned value is touched. The apk packages resolve at run time and are
not hash-pinned; that gap is repo-wide (script/bootstrap has it too) and
is tracked in #19.

Also moves each version/date comment to sit directly above the pinned
line rather than above the step's `- name:`, matching check.yml, and
dates the actions/checkout pin 2026-02-28 as check.yml already does for
the same SHA.

Verified by running the build job's step sequence inside the pinned
alpine digest: bare, `node` and `bash` are absent and the pinned
checkout bundle dies with "node: not found"; after the new apk step,
node 22.23.2, git 2.47.3 and GNU tar 1.35 are present, that same
checkout bundle runs under node and gets as far as "GITHUB_WORKSPACE not
defined", and script/bootstrap, script/test and the tar step all
complete. make check and script/cibuild (with the build cache pruned, so
nothing was CACHED) are green.
2026-08-09 02:15:44 +00:00
3f91a7c273 Hash-pin every external reference in deploy.yml (closes #7)
All checks were successful
check / check (push) Successful in 7s
deploy.yml was the last file in the repo carrying mutable external
references. Every image is now pinned by digest and every action by a
full 40-hex commit SHA, each with a version/date comment on the line
above. All values were resolved from upstream and verified to resolve.

- build container: klakegg/hugo:ext-alpine (abandoned since 2021,
  mutable tag) replaced by the exact alpine 3.21 digest the Dockerfile
  already pins, with script/bootstrap to install hugo and script/test
  to build. One pinned base and one dependency list now serve both the
  check build and the deploy build.
- deploy container: node:20 -> node@sha256:8f693eaa... (node 20.20.2,
  bookworm).
- actions/checkout: v4 -> 11bd7190... (v4.2.2), the same SHA check.yml
  pins, so the two workflows agree.
- actions/upload-artifact: v3 -> ea165f8d... (v4.6.2); v3 is deprecated.
- actions/download-artifact: v3 -> d3f86a10... (v4.3.0); v3 is
  deprecated.
- npm install -g wrangler -> wrangler@4.120.0, so the deploy no longer
  executes whatever the wrangler tag happens to point at.

Also drops the dead feat/initial-site push trigger (that branch is fully
merged into main) and reindents the file to 4-space YAML to match
check.yml and .editorconfig.

The two jobs are deliberately left separate so a deploy regression can
be attributed unambiguously.

Verified: make check and script/cibuild both green; the workflow parses
as YAML with the expected job/step structure. The Cloudflare Pages
deploy path itself cannot be exercised from a branch (it runs only on
push to main and needs CLOUDFLARE_API_TOKEN), so the deploy run on main
must be watched after merge.
2026-08-09 01:49:21 +00:00
2 changed files with 84 additions and 44 deletions

View File

@@ -3,28 +3,56 @@ name: Build and Deploy to Cloudflare Pages
on: on:
push: push:
branches: branches:
- feat/initial-site
- main - main
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: klakegg/hugo:ext-alpine # Same digest the Dockerfile pins: one pinned base image and the
# same dependency list (script/bootstrap) for both the check build
# and the deploy build. The one extra thing this job needs on top
# of the Dockerfile is the Actions runner's own prerequisites --
# see the first step.
# alpine 3.21, 2026-02-28
image: alpine@sha256:c3f8e73fdb79deaebaa2037150150191b9dcbfba68b4a46d70103204c53f4709
defaults:
run:
# The default step shell is bash; this image has only busybox
# sh, so say so explicitly rather than rely on a fallback.
shell: sh
steps: steps:
# This image is bare busybox+musl. act_runner executes JavaScript
# actions (checkout, upload-artifact) with `node` *inside* the job
# container and does not inject one, so node has to exist before
# the first `uses:` step -- script/bootstrap runs too late. git is
# needed for checkout's `submodules: recursive` (without it
# checkout degrades to a tarball download that cannot do
# submodules). An inline `run:` needs only a shell, so this step
# works on the bare image. These apk packages resolve at run time
# and are not hash-pinned; that gap is repo-wide (script/bootstrap
# has it too) and is tracked in #19.
- name: Install runner prerequisites
run: apk add --no-cache nodejs git tar
- name: Checkout - name: Checkout
uses: actions/checkout@v4 # actions/checkout v4.2.2, 2026-02-28
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with: with:
submodules: recursive submodules: recursive
- name: Install build dependencies
run: script/bootstrap
- name: Build site - name: Build site
run: hugo --minify run: script/test
- name: Archive site - name: Archive site
run: tar -czf site.tar.gz public run: tar -czf site.tar.gz public
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v3 # actions/upload-artifact v4.6.2, 2026-08-09
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with: with:
name: site name: site
path: site.tar.gz path: site.tar.gz
@@ -33,10 +61,12 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: build needs: build
container: container:
image: node:20 # node 20.20.2-bookworm, 2026-08-09
image: node@sha256:8f693eaa7e0a8e71560c9a82b55fd54c2ae920a2ba5d2cde28bac7d1c01c9ba5
steps: steps:
- name: Download artifact - name: Download artifact
uses: actions/download-artifact@v3 # actions/download-artifact v4.3.0, 2026-08-09
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with: with:
name: site name: site
@@ -44,7 +74,8 @@ jobs:
run: tar -xzf site.tar.gz run: tar -xzf site.tar.gz
- name: Install Wrangler - name: Install Wrangler
run: npm install -g wrangler # wrangler 4.120.0, 2026-08-09
run: npm install -g wrangler@4.120.0
- name: Deploy to Cloudflare Pages - name: Deploy to Cloudflare Pages
run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }} run: wrangler pages deploy public --project-name=lora-vegas --branch=${{ github.ref_name }}

17
TODO.md
View File

@@ -14,7 +14,8 @@ pre-1.0
No git tags. The site is live and now has the scripts-to-rule-them-all scaffold No git tags. The site is live and now has the scripts-to-rule-them-all scaffold
(`Makefile`, `script/`, `Dockerfile`, `check.yml`); still missing `LICENSE` and (`Makefile`, `script/`, `Dockerfile`, `check.yml`); still missing `LICENSE` and
policy files. policy files. Every external reference in the repo is now pinned by
cryptographic hash (or, for the wrangler CLI install, an exact version).
# Next Step # Next Step
@@ -24,6 +25,17 @@ Update `README.md` accordingly.
# Completed Steps # Completed Steps
- 2026-08-09: hash-pinned every external reference in
`.gitea/workflows/deploy.yml` (closes #7): both job container images are
pinned by digest, all three `uses:` are pinned by 40-hex commit SHA
(`upload`/`download-artifact` moved v3 to v4), and the wrangler install is
pinned to an exact version. The abandoned `klakegg/hugo:ext-alpine` image is
gone: the build job now runs on the same pinned `alpine` digest the
`Dockerfile` uses, with a pre-checkout `apk add nodejs git tar` step (the
Actions runner needs `node` inside the job container to execute JavaScript
actions), an explicit `shell: sh` default, then `script/bootstrap` and
`script/test`. Also dropped the dead `feat/initial-site` push trigger and
reindented the file to 4-space YAML to match `check.yml`
- 2026-07-25: added the scripts-to-rule-them-all scaffold (closes #4): `script/` - 2026-07-25: added the scripts-to-rule-them-all scaffold (closes #4): `script/`
entrypoints, `Makefile` shims, a Hugo `Dockerfile` (sha256-pinned alpine) plus entrypoints, `Makefile` shims, a Hugo `Dockerfile` (sha256-pinned alpine) plus
`.dockerignore` that runs `make check`, `.gitea/workflows/check.yml` running `.dockerignore` that runs `make check`, `.gitea/workflows/check.yml` running
@@ -40,9 +52,6 @@ Update `README.md` accordingly.
# Future Steps # Future Steps
- Pin the images and actions in `deploy.yml` by sha256
(`klakegg/hugo:ext-alpine`, `node:20`, `actions/checkout`,
`upload`/`download-artifact` are all unpinned)
- Rework README.md into the standard sections: Description, Getting Started, - Rework README.md into the standard sections: Description, Getting Started,
Rationale, Design, TODO, License, Author (currently About, Contributing, Rationale, Design, TODO, License, Author (currently About, Contributing,
Technical Details, License) Technical Details, License)