From 574b98f5cb7817429fbd8ff681d9158f3fb41172 Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 16:29:23 -0400 Subject: [PATCH 1/9] ci: add actionlint pre-commit hook and fix shellcheck findings Replace ls with find in publish.yml to resolve SC2012/SC2035 shellcheck warnings, enabling a clean actionlint pass. Add actionlint as a lefthook pre-commit command scoped to staged workflow files. --- .github/workflows/publish.yml | 2 +- lefthook.yml | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index acfc0a0..38c53ac 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,7 +29,7 @@ jobs: echo "Generating rockspec..." lx generate-rockspec - ROCKSPEC=$(ls -1 *.rockspec 2>/dev/null | head -1) + ROCKSPEC=$(find . -maxdepth 1 -name '*.rockspec' -print -quit) if [[ -z "$ROCKSPEC" ]]; then echo "::error::No rockspec file generated" exit 1 diff --git a/lefthook.yml b/lefthook.yml index b6e0c0f..7a087b7 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -14,3 +14,6 @@ pre-commit: just --fmt fi stage_fixed: true + actionlint: + glob: ".github/workflows/*.yml" + run: actionlint {staged_files} From 5c0d25bd22255aa938a560cba7154c1e4b5b0665 Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 16:29:36 -0400 Subject: [PATCH 2/9] ci: add act configuration for local workflow testing Create .actrc with ubuntu-24.04 runner mapping and amd64 container architecture for macOS arm64 compatibility. Add .secrets to .gitignore to prevent accidental token commits. --- .actrc | 7 +++++++ .gitignore | 3 +++ 2 files changed, 10 insertions(+) create mode 100644 .actrc diff --git a/.actrc b/.actrc new file mode 100644 index 0000000..03b99d5 --- /dev/null +++ b/.actrc @@ -0,0 +1,7 @@ +# Map ubuntu-24.04 runner label to catthehacker medium image (24.04 variant). +# Without this, act may not resolve the runner label correctly. +-P ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04 + +# Required for macOS arm64 (M-series) — catthehacker images are amd64-only. +# Harmless no-op on native amd64 hosts. +--container-architecture linux/amd64 diff --git a/.gitignore b/.gitignore index 89d4287..78b88a2 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ luacov.report.out # Demo recording *.cast +# act (local GitHub Actions runner) +.secrets + # Build artifacts .build/ /roda From 30950dd51212fb33ac76c75a90ffd7ff5d3f443c Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 16:29:55 -0400 Subject: [PATCH 3/9] ci: add env.ACT guards to skip API-dependent workflow steps Guard steps that require GitHub API access or external secrets so they are cleanly skipped when running workflows locally via act. Affects: PR comment (tests.yml), LuaRocks upload (publish.yml), release-please action and artifact upload (release-please.yml). --- .github/workflows/publish.yml | 1 + .github/workflows/release-please.yml | 5 ++++- .github/workflows/tests.yml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 38c53ac..3fe3e24 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -46,6 +46,7 @@ jobs: rm -f "$ROCKSPEC" - name: Upload to LuaRocks + if: ${{ !env.ACT }} run: lx --verbose --lua-version 5.1 upload env: LUX_API_KEY: ${{ secrets.LUX_API_KEY }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 356f3ca..31941a5 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -18,7 +18,9 @@ jobs: release_created: ${{ steps.release.outputs.release_created }} tag_name: ${{ steps.release.outputs.tag_name }} steps: - - uses: googleapis/release-please-action@v4 + - name: Release Please + if: ${{ !env.ACT }} + uses: googleapis/release-please-action@v4 id: release with: token: ${{ secrets.PAT }} @@ -149,6 +151,7 @@ jobs: luarocks lint *.rockspec - name: Upload Release Artifacts + if: ${{ !env.ACT }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 55aec8a..b9998df 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,7 +56,7 @@ jobs: run: just lint-ci - name: Comment on PR if formatting needed - if: failure() && github.event_name == 'pull_request' + if: ${{ !env.ACT && failure() && github.event_name == 'pull_request' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | From e58dbe1f7af5f8876c617e05f3dcdcd333e2a858 Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 16:30:15 -0400 Subject: [PATCH 4/9] ci: add just recipes for local workflow testing via act Add act-test, act-lint, and act-publish recipes to the ci group. Each recipe targets a specific workflow and injects GITHUB_TOKEN from the local gh CLI session to avoid API rate limits. --- justfile | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/justfile b/justfile index 8fac6c6..aa3102e 100644 --- a/justfile +++ b/justfile @@ -246,6 +246,23 @@ publish: release @echo "Publishing to LuaRocks..." lx --lua-version {{ lua_version }} publish +# --- Local CI (act) --- + +[doc("Run test job locally via act (requires: docker, gh auth login)")] +[group('ci')] +act-test: + act push --job test -W .github/workflows/tests.yml -s GITHUB_TOKEN="$(gh auth token)" + +[doc("Run lint job locally via act")] +[group('ci')] +act-lint: + act push --job lint -W .github/workflows/tests.yml -s GITHUB_TOKEN="$(gh auth token)" + +[doc("Run publish validation locally via act (upload step skipped)")] +[group('ci')] +act-publish: + act workflow_dispatch -W .github/workflows/publish.yml -s GITHUB_TOKEN="$(gh auth token)" + # --- Maintenance --- [confirm("Remove all build artifacts and binaries?")] From 0a16f8debf3bd2e6170b6659ccf039de0a102cc1 Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 16:34:50 -0400 Subject: [PATCH 5/9] docs: add local CI verification and actionlint hook to CONTRIBUTING Document the pre-commit hook table including the new actionlint hook, and add a "Local CI Verification (macOS)" section covering act prerequisites, Docker image setup, DOCKER_HOST configuration for Rancher Desktop, and the available just recipes. --- CONTRIBUTING.md | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 18ce6ad..0bd3529 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,12 +52,55 @@ luarocks install busted --dev ### Git Hooks -We use [Lefthook](https://github.com/evilmartians/lefthook) to manage Git hooks (formatting, linting, tests). After installing lefthook (e.g., via `brew install lefthook` or `npm install -g @evilmartians/lefthook`), set up the hooks by running: +We use [Lefthook](https://github.com/evilmartians/lefthook) to manage Git hooks. After installing lefthook (e.g., via `brew install lefthook`), set up the hooks by running: ```bash lefthook install ``` +Pre-commit hooks run automatically on `git commit`: + +| Hook | Scope | What it does | +|------|-------|-------------| +| format | `*.lua` files | Auto-formats with `lx fmt` | +| lint | `*.lua` files | Lints with `lx lint` | +| justfile | justfile | Auto-formats with `just --fmt` | +| actionlint | `.github/workflows/*.yml` | Lints GitHub Actions workflows (requires [actionlint](https://github.com/rhysd/actionlint): `brew install actionlint`) | + +### Local CI Verification (macOS) + +You can run GitHub Actions workflows locally using [act](https://github.com/nektos/act) and Docker. This lets you validate CI changes without pushing. + +#### Prerequisites + +- [act](https://github.com/nektos/act): `brew install act` +- Docker runtime ([Rancher Desktop](https://rancherdesktop.io/), [OrbStack](https://orbstack.dev/), or Docker Desktop) +- [GitHub CLI](https://cli.github.com/) authenticated: `gh auth login` + +If your Docker socket is not at the default path (e.g., Rancher Desktop uses `~/.rd/run/docker.sock`), set `DOCKER_HOST`: + +```bash +export DOCKER_HOST="unix://$HOME/.rd/run/docker.sock" +``` + +#### Pull the runner image + +```bash +docker pull ghcr.io/catthehacker/ubuntu:act-24.04 +``` + +The `.actrc` file in the repo root maps `ubuntu-24.04` to this image and sets the container architecture for Apple Silicon compatibility. + +#### Available recipes + +```bash +just act-test # Run the test job (apt-get, Lux, just, unit tests) +just act-lint # Run the lint job (formatting check, linter) +just act-publish # Validate rockspec generation (upload step skipped) +``` + +Steps that require GitHub API access or external secrets (PR comments, LuaRocks upload, release-please) are automatically skipped when running under act. + ### Project Structure ``` From d0db47c365f8d51e9796e065490913d8c4815982 Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 16:39:32 -0400 Subject: [PATCH 6/9] docs: fix Rancher Desktop Docker socket path in CONTRIBUTING The correct socket path is ~/.rd/docker.sock, not ~/.rd/run/docker.sock. The run/ subdirectory was never an official Rancher Desktop path. --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0bd3529..db2a44c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,10 +77,11 @@ You can run GitHub Actions workflows locally using [act](https://github.com/nekt - Docker runtime ([Rancher Desktop](https://rancherdesktop.io/), [OrbStack](https://orbstack.dev/), or Docker Desktop) - [GitHub CLI](https://cli.github.com/) authenticated: `gh auth login` -If your Docker socket is not at the default path (e.g., Rancher Desktop uses `~/.rd/run/docker.sock`), set `DOCKER_HOST`: +If your Docker socket is not at `/var/run/docker.sock` (e.g., Rancher Desktop without Administrative Access), set `DOCKER_HOST`: ```bash -export DOCKER_HOST="unix://$HOME/.rd/run/docker.sock" +# Rancher Desktop default socket path +export DOCKER_HOST="unix://$HOME/.rd/docker.sock" ``` #### Pull the runner image From eea30f2ec961e001676f9ab5012df4e84b3c361a Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 16:48:59 -0400 Subject: [PATCH 7/9] ci: disable Docker socket mount for Rancher Desktop compatibility Add --container-daemon-socket - to .actrc to prevent act from bind-mounting the Docker socket into containers. Our workflows don't need Docker-in-Docker, and the mount fails on Rancher Desktop / Colima where the socket is not at /var/run/docker.sock. --- .actrc | 5 +++++ CONTRIBUTING.md | 2 ++ 2 files changed, 7 insertions(+) diff --git a/.actrc b/.actrc index 03b99d5..5fc6d43 100644 --- a/.actrc +++ b/.actrc @@ -5,3 +5,8 @@ # Required for macOS arm64 (M-series) — catthehacker images are amd64-only. # Harmless no-op on native amd64 hosts. --container-architecture linux/amd64 + +# Disable Docker socket bind-mount into containers. Our workflows don't need +# Docker-in-Docker. Without this, act fails on Rancher Desktop / Colima where +# the socket is not at /var/run/docker.sock. +--container-daemon-socket - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index db2a44c..98af456 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,6 +84,8 @@ If your Docker socket is not at `/var/run/docker.sock` (e.g., Rancher Desktop wi export DOCKER_HOST="unix://$HOME/.rd/docker.sock" ``` +The `.actrc` file already includes `--container-daemon-socket -` to disable Docker socket bind-mounting into containers, which avoids mount failures on Rancher Desktop and Colima. If you use actions that require Docker-in-Docker, enable Administrative Access in Rancher Desktop (Preferences > Application > General) so the socket is created at `/var/run/docker.sock`. + #### Pull the runner image ```bash From 034e3e4dc15c265d5d88096326e4adf01c96bd12 Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Thu, 9 Apr 2026 17:14:16 -0400 Subject: [PATCH 8/9] ci: skip TLS verification in act containers for corporate proxies Corporate security proxies (Netskope, Zscaler) re-sign TLS certificates with their own CA, which containers don't trust. Set NODE_TLS_REJECT_UNAUTHORIZED=0 in .actrc so Node.js actions can reach GitHub APIs from inside act containers. --- .actrc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.actrc b/.actrc index 5fc6d43..28b150f 100644 --- a/.actrc +++ b/.actrc @@ -10,3 +10,8 @@ # Docker-in-Docker. Without this, act fails on Rancher Desktop / Colima where # the socket is not at /var/run/docker.sock. --container-daemon-socket - + +# Skip TLS verification inside containers. Corporate proxies (Netskope, Zscaler) +# re-sign certificates with their own CA which the container doesn't trust. +# Safe here — this only affects local act runs in throwaway containers. +--env NODE_TLS_REJECT_UNAUTHORIZED=0 From 94756e48be3f2c14b658124cbd6008001f961b5e Mon Sep 17 00:00:00 2001 From: TJ Kolleh Date: Fri, 10 Apr 2026 17:40:05 -0400 Subject: [PATCH 9/9] ci: resolve merge conflict in release-please.yml Accept main's per-platform upload steps (linux-x86_64 with rockspec, linux-aarch64, windows, macOS) from the CI matrix expansion and add !env.ACT guards to all four upload steps. --- .github/workflows/release-please.yml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 79c51b9..3da11d9 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -187,13 +187,8 @@ jobs: run: | luarocks lint *.rockspec -<<<<<<< ci/local-testing-and-actionlint - - name: Upload Release Artifacts - if: ${{ !env.ACT }} -======= - name: Upload Release Artifacts (with rockspec) - if: matrix.name == 'linux-x86_64' ->>>>>>> main + if: ${{ !env.ACT && matrix.name == 'linux-x86_64' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -201,7 +196,7 @@ jobs: roda-${{ matrix.name }}.tar.gz roda-${{ matrix.name }}.tar.gz.sha256 *.rockspec --clobber - name: Upload Release Artifacts (Linux aarch64) - if: matrix.name == 'linux-aarch64' + if: ${{ !env.ACT && matrix.name == 'linux-aarch64' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -209,7 +204,7 @@ jobs: roda-${{ matrix.name }}.tar.gz roda-${{ matrix.name }}.tar.gz.sha256 --clobber - name: Upload Release Artifacts (Windows) - if: matrix.target == 'windows' + if: ${{ !env.ACT && matrix.target == 'windows' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -217,7 +212,7 @@ jobs: roda-${{ matrix.name }}.zip roda-${{ matrix.name }}.zip.sha256 --clobber - name: Upload Release Artifacts (macOS) - if: matrix.target == 'macos' + if: ${{ !env.ACT && matrix.target == 'macos' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: |