Skip to content

Commit 3542a60

Browse files
committed
feat(lua-binding): stand up detachable CI + tests — binding-tier-1
1 parent 2bb8ba8 commit 3542a60

6 files changed

Lines changed: 520 additions & 0 deletions

File tree

.github/workflows/lua-ci.yml

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# Lua CI — proven binding-tier-1.
5+
#
6+
# This workflow follows the DETACHABLE-HARNESS contract for proven binding CI.
7+
# It references ONLY: bindings/lua/, ffi/zig/, and bindings/c/include/proven.h.
8+
9+
name: Lua CI
10+
11+
permissions:
12+
contents: read
13+
14+
on:
15+
push:
16+
branches: [main]
17+
paths:
18+
- 'bindings/lua/**'
19+
- 'ffi/zig/**'
20+
- 'bindings/c/include/proven.h'
21+
- '.github/workflows/lua-ci.yml'
22+
pull_request:
23+
branches: [main]
24+
paths:
25+
- 'bindings/lua/**'
26+
- 'ffi/zig/**'
27+
- 'bindings/c/include/proven.h'
28+
- '.github/workflows/lua-ci.yml'
29+
workflow_dispatch:
30+
31+
concurrency:
32+
group: lua-ci-${{ github.ref }}
33+
cancel-in-progress: true
34+
35+
env:
36+
LUA_VERSION: '5.1' # Standard for LuaJIT compatibility
37+
ZIG_VERSION: '0.15.2'
38+
39+
jobs:
40+
detachability-guard:
41+
runs-on: ubuntu-22.04
42+
timeout-minutes: 2
43+
steps:
44+
- name: Checkout (workflow file only)
45+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
46+
with:
47+
sparse-checkout: |
48+
.github/workflows/lua-ci.yml
49+
sparse-checkout-cone-mode: false
50+
51+
- name: Detachability grep guard
52+
run: |
53+
set -euo pipefail
54+
forbidden=0
55+
while IFS= read -r raw; do
56+
p="${raw%[.,;:)]}"
57+
case "$p" in
58+
bindings/lua/*|ffi/zig/*|bindings/c/include|bindings/c/include/proven.h|.github/workflows/lua-ci.yml)
59+
;;
60+
bindings/*/*)
61+
echo "::error file=.github/workflows/lua-ci.yml::detachability violation: $p"
62+
forbidden=1
63+
;;
64+
tests/*)
65+
echo "::error file=.github/workflows/lua-ci.yml::detachability violation (root-level tests/): $p"
66+
forbidden=1
67+
;;
68+
esac
69+
done < <(grep -oE '(bindings/[a-zA-Z0-9_-]+/[A-Za-z0-9_./-]*|tests/[A-Za-z0-9_./-]+)' \
70+
.github/workflows/lua-ci.yml | sort -u)
71+
[ "$forbidden" -eq 0 ]
72+
echo "detachability-guard: OK"
73+
74+
lua-build:
75+
runs-on: ubuntu-22.04
76+
needs: detachability-guard
77+
timeout-minutes: 20
78+
79+
steps:
80+
- name: Checkout proven
81+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
82+
with:
83+
path: proven
84+
85+
- name: Setup Zig ${{ env.ZIG_VERSION }}
86+
uses: mlugg/setup-zig@e7d1537c378b83b8049f65dda471d87a2f7b2df2 # v1
87+
with:
88+
version: ${{ env.ZIG_VERSION }}
89+
90+
- name: Build libproven.so (WIRED-subset fixture)
91+
working-directory: proven/ffi/zig
92+
run: |
93+
set -euo pipefail
94+
mkdir -p zig-out/lib
95+
zig build-lib -dynamic -O ReleaseSafe \
96+
-fPIC \
97+
--name proven \
98+
-femit-bin=zig-out/lib/libproven.so \
99+
src/main.zig -lc
100+
nm -D --defined-only zig-out/lib/libproven.so \
101+
| awk '$2 ~ /^[TWV]$/ { print $3 }' \
102+
| grep -E '^(proven_path_has_traversal|proven_header_has_crlf|proven_free_string|proven_version_major|proven_version_minor|proven_version_patch)$' \
103+
| sort -u | tee /tmp/wired-exports.txt
104+
105+
- name: Setup Lua ${{ env.LUA_VERSION }}
106+
uses: leafo/gh-actions-lua@35906ca5d804245663738096f90640d89052d9a3 # v10
107+
with:
108+
luaVersion: ${{ env.LUA_VERSION }}
109+
110+
- name: Setup Luarocks
111+
uses: leafo/gh-actions-luarocks@86047715ec236b539c3683f707f16f1207e7b69c # v4
112+
113+
- name: Install dependencies
114+
run: luarocks install luafilesystem
115+
116+
- name: Upload libproven.so artefact
117+
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4
118+
with:
119+
name: libproven-x86_64-linux-gnu
120+
path: proven/ffi/zig/zig-out/lib/libproven.so
121+
if-no-files-found: error
122+
retention-days: 1
123+
124+
lua-symbol-audit:
125+
runs-on: ubuntu-22.04
126+
needs: lua-build
127+
timeout-minutes: 5
128+
steps:
129+
- name: Checkout (binding only)
130+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
131+
with:
132+
sparse-checkout: |
133+
bindings/lua
134+
sparse-checkout-cone-mode: false
135+
136+
- name: Download libproven.so
137+
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
138+
with:
139+
name: libproven-x86_64-linux-gnu
140+
path: lib/
141+
142+
- name: Run lua-symbol-audit
143+
working-directory: bindings/lua
144+
env:
145+
PROVEN_LIB_PATH: ${{ github.workspace }}/lib
146+
run: ./scripts/symbol-audit.sh
147+
148+
lua-smoke:
149+
runs-on: ubuntu-22.04
150+
needs: lua-build
151+
timeout-minutes: 10
152+
steps:
153+
- name: Checkout (binding + C header only)
154+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
155+
with:
156+
sparse-checkout: |
157+
bindings/lua
158+
bindings/c/include
159+
.github/workflows/lua-ci.yml
160+
sparse-checkout-cone-mode: false
161+
162+
- name: Setup Lua ${{ env.LUA_VERSION }}
163+
uses: leafo/gh-actions-lua@35906ca5d804245663738096f90640d89052d9a3 # v10
164+
with:
165+
luaVersion: ${{ env.LUA_VERSION }}
166+
167+
- name: Setup Luarocks
168+
uses: leafo/gh-actions-luarocks@86047715ec236b539c3683f707f16f1207e7b69c # v4
169+
170+
- name: Download libproven.so
171+
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
172+
with:
173+
name: libproven-x86_64-linux-gnu
174+
path: lib/
175+
176+
- name: Build + Run hello_smoke
177+
working-directory: bindings/lua
178+
env:
179+
PROVEN_LIB_PATH: ${{ github.workspace }}/lib
180+
PROVEN_INCLUDE_PATH: ${{ github.workspace }}/bindings/c/include
181+
LD_LIBRARY_PATH: ${{ github.workspace }}/lib
182+
run: |
183+
export LUA_PATH="./?.lua;./?/init.lua;$LUA_PATH"
184+
lua smoke/hello_smoke.lua
185+
186+
lua-tests:
187+
runs-on: ubuntu-22.04
188+
needs: lua-build
189+
timeout-minutes: 15
190+
steps:
191+
- name: Checkout (binding + C header only)
192+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
193+
with:
194+
sparse-checkout: |
195+
bindings/lua
196+
bindings/c/include
197+
.github/workflows/lua-ci.yml
198+
sparse-checkout-cone-mode: false
199+
200+
- name: Setup Lua ${{ env.LUA_VERSION }}
201+
uses: leafo/gh-actions-lua@35906ca5d804245663738096f90640d89052d9a3 # v10
202+
with:
203+
luaVersion: ${{ env.LUA_VERSION }}
204+
205+
- name: Setup Luarocks
206+
uses: leafo/gh-actions-luarocks@86047715ec236b539c3683f707f16f1207e7b69c # v4
207+
208+
- name: Install busted
209+
run: luarocks install busted
210+
211+
- name: Download libproven.so
212+
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4
213+
with:
214+
name: libproven-x86_64-linux-gnu
215+
path: lib/
216+
217+
- name: Run all Lua tests (busted)
218+
working-directory: bindings/lua
219+
env:
220+
PROVEN_LIB_PATH: ${{ github.workspace }}/lib
221+
PROVEN_INCLUDE_PATH: ${{ github.workspace }}/bindings/c/include
222+
LD_LIBRARY_PATH: ${{ github.workspace }}/lib
223+
run: |
224+
export LUA_PATH="./?.lua;./?/init.lua;$LUA_PATH"
225+
busted
226+
227+
lua-detachable-build:
228+
runs-on: ubuntu-22.04
229+
needs: lua-build
230+
timeout-minutes: 15
231+
steps:
232+
- name: Sparse checkout (detachable set only)
233+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
234+
with:
235+
sparse-checkout: |
236+
bindings/lua
237+
bindings/c/include/proven.h
238+
.github/workflows/lua-ci.yml
239+
sparse-checkout-cone-mode: false
240+
path: proven-lua
241+
242+
- name: Verify detached layout (no other proven trees present)
243+
working-directory: proven-lua
244+
run: |
245+
set -euo pipefail
246+
if [ -d "src" ] || [ -d "ffi" ] || [ -d "tests" ] || [ -d "audits" ]; then
247+
echo "::error::detachability violation: non-binding trees present in detached checkout"
248+
ls -la
249+
exit 1
250+
fi
251+
test -d bindings/lua

Justfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,23 @@ chapel-test: build-ffi
180180
chapel-clean:
181181
just -d bindings/chapel --justfile bindings/chapel/Justfile clean
182182

183+
# --- Lua Binding (Tier 1 Detachable Harness) ---
184+
# These recipes are THIN FORWARDERS into bindings/lua/.
185+
lua-check: build-ffi
186+
PROVEN_LIB_PATH="$(pwd)/ffi/zig/zig-out/lib" \
187+
just -d bindings/lua --justfile bindings/lua/Justfile check
188+
189+
lua-build: build-ffi
190+
PROVEN_LIB_PATH="$(pwd)/ffi/zig/zig-out/lib" \
191+
just -d bindings/lua --justfile bindings/lua/Justfile build
192+
193+
lua-test: build-ffi
194+
PROVEN_LIB_PATH="$(pwd)/ffi/zig/zig-out/lib" \
195+
just -d bindings/lua --justfile bindings/lua/Justfile test
196+
197+
lua-clean:
198+
just -d bindings/lua --justfile bindings/lua/Justfile clean
199+
183200
# ---------------------------------------------------------------------------
184201
# Cleaning
185202
# ---------------------------------------------------------------------------

bindings/lua/Justfile

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# SPDX-License-Identifier: MPL-2.0
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
#
4+
# proven-lua binding — detachable build harness.
5+
#
6+
# This Justfile contains every recipe needed to build, audit, and test the
7+
# Lua binding. It is self-contained: it MUST NOT reference recipes
8+
# from the proven repo's root Justfile, nor reach outside the binding's
9+
# directory tree. The libproven.so artefact is supplied via the
10+
# PROVEN_LIB_PATH environment variable so that this harness works in three
11+
# layouts:
12+
#
13+
# 1. in-tree (PROVEN_LIB_PATH=../../ffi/zig/zig-out/lib)
14+
# 2. installed (PROVEN_LIB_PATH=/usr/local/lib)
15+
# 3. standalone proven-lua checkout (PROVEN_LIB_PATH=<external path>)
16+
#
17+
# rockspec is the package-metadata source of truth (luaVersion range,
18+
# license, dependencies). The actual compile uses `lua` directly because
19+
# Mason does not currently support C-library linking declaratively; see
20+
# the ADR at docs/adr/0001-binding-ci-template.md for the rationale.
21+
22+
# Source of truth for the C ABI header. This is supplied via env so the
23+
# harness can be extracted to a standalone repo carrying its own copy of
24+
# proven.h (e.g. vendored under include/).
25+
PROVEN_INCLUDE_PATH := env_var_or_default("PROVEN_INCLUDE_PATH", justfile_directory() + "/../c/include")
26+
27+
default:
28+
@just --list
29+
30+
# Fast pre-build gate: confirm libproven.so exports every WIRED symbol in
31+
# symbol-manifest.txt. Runs in < 5s; no compilation.
32+
check:
33+
#!/usr/bin/env bash
34+
set -euo pipefail
35+
if [ -z "${PROVEN_LIB_PATH:-}" ]; then
36+
echo "ERROR: set PROVEN_LIB_PATH to the directory containing libproven.so" >&2
37+
exit 2
38+
fi
39+
./scripts/symbol-audit.sh
40+
41+
# Typecheck the Lua modules without producing an executable. Mason is
42+
# used here as a lightweight metadata + luaVersion check; the actual
43+
# binding build is performed by the build / test recipes via lua.
44+
mason-check:
45+
@echo "[lua] mason check (luaVersion gate, no link)..."
46+
mason build --no-rebuild || mason build
47+
48+
# Build the smoke target against PROVEN_LIB_PATH/libproven.so.
49+
build: check
50+
#!/usr/bin/env bash
51+
set -euo pipefail
52+
lua -o smoke/hello_smoke \
53+
smoke/hello_smoke.lua \
54+
-M src/ \
55+
-I "{{PROVEN_INCLUDE_PATH}}" \
56+
-L "$PROVEN_LIB_PATH" -lproven \
57+
--ldflags "-Wl,-rpath,$PROVEN_LIB_PATH"
58+
echo "[lua] hello_smoke built: smoke/hello_smoke"
59+
60+
# Build + run smoke + every WIRED per-module test in tests/.
61+
# Fails on the first red test.
62+
test: check
63+
#!/usr/bin/env bash
64+
set -euo pipefail
65+
INC="{{PROVEN_INCLUDE_PATH}}"
66+
LIB="$PROVEN_LIB_PATH"
67+
echo "[lua] Building hello_smoke..."
68+
lua -o smoke/hello_smoke smoke/hello_smoke.lua \
69+
-M src/ -I "$INC" -L "$LIB" -lproven \
70+
--ldflags "-Wl,-rpath,$LIB"
71+
echo "[lua] === hello_smoke ==="
72+
./smoke/hello_smoke
73+
for t in tests/Test*.lua; do
74+
name="$(basename "${t%.lua}")"
75+
echo "[lua] === $name ==="
76+
lua -o "tests/$name" "$t" \
77+
-M src/ -I "$INC" -L "$LIB" -lproven \
78+
--ldflags "-Wl,-rpath,$LIB"
79+
"./tests/$name"
80+
done
81+
echo "[lua] All Lua tests passed."
82+
83+
# Clean compiled binaries; leaves sources untouched.
84+
clean:
85+
#!/usr/bin/env bash
86+
set -euo pipefail
87+
rm -f smoke/hello_smoke
88+
find tests -maxdepth 1 -type f -perm -u+x ! -name '*.lua' -delete 2>/dev/null || true
89+
find . -name '*.tmp' -delete 2>/dev/null || true
90+
echo "[lua] Clean complete."

0 commit comments

Comments
 (0)