Skip to content

Commit 0d6a814

Browse files
hyperpolymathclaude
andcommitted
zig-api: add gen-header recipe + CI drift check
The C header at generated/abi/zig_api.h is marked AUTO-GENERATED but regeneration was manual until now. Adds `just gen-header` to regenerate deterministically from the Idris2 ABI modules, and `just check-header` which CI runs to fail the build on silent drift. Eliminates the drift risk flagged in UNIFIED-ZIG-API-STACK.adoc §10. Updates that doc to mark the item resolved. Also corrects the stale src/abi/* paths in check-abi (correct path is src/ZigApi/ABI/). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent bcf9cb2 commit 0d6a814

5 files changed

Lines changed: 697 additions & 58 deletions

File tree

UNIFIED-ZIG-API-STACK.adoc

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -328,17 +328,22 @@ The trigger was the estate-wide V-lang ban on 2026-04-10 (V-lang detected via
328328

329329
== Open Questions / Deferred
330330

331-
* *proven -> zig-api active wiring.* `zig-api`'s `Foreign.idr` references
332-
`libzig_api` only. The narrative goal of calling `proven_ffi_*` symbols from
333-
within the Zig runtime (e.g. using `proven` SafeMath for buffer bounds in
334-
`gnosis.zig`) is described in `zig-api/EXPLAINME.adoc` but not yet wired.
335-
Until wired, proven and zig-api are parallel stacks that share the Idris2/Zig
336-
FFI pattern but do not chain.
337-
338-
* *C adaptor auto-regeneration pipeline.* `zig_api.h` is marked
339-
`AUTO-GENERATED` but no `just` recipe or CI step currently regenerates it
340-
from the Idris2 ABI source. Manual sync is a drift risk. A `just gen-header`
341-
recipe invoking `idris2` + an extraction pass is needed.
331+
* *proven -> zig-api active wiring.* **Actualised 2026-04-17.**
332+
`proven_path_has_traversal` is now called from
333+
`zig-api/ffi/zig/src/process.zig:safePathDefault` (line ~73) as a second gate
334+
on every gnosis path argument. It rejects paths that contain `..` components
335+
even when they pass the prefix allowlist (e.g. `/tmp/../../../etc/passwd`).
336+
`zig-api/ffi/zig/build.zig` links `libproven_ffi.a` built via
337+
`verification-ecosystem/proven/ffi/zig/build_standalone.zig`.
338+
The two stacks now chain: zig-api is a proven consumer.
339+
Next wiring candidate: `proven_header_has_crlf` in `gnosis.zig` header parsing
340+
(the `Content-Length:` and `Content-Type:` extraction in `serveRequest`).
341+
342+
* *C adaptor auto-regeneration pipeline.* **Resolved 2026-04-17.**
343+
`just gen-header` (Bash + Python3 extractor in `scripts/gen-header.sh`)
344+
regenerates `generated/abi/zig_api.h` deterministically from the Idris2 ABI
345+
source modules. `just check-header` runs in CI (`zig-api-ci.yml`) and fails
346+
the build on any drift.
342347

343348
* *Template repo for new edges.* `rsr-template-repo` does not yet include a
344349
`build.zig` skeleton that depends on `libzig_api`. A `just new-zig-edge`
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
# (MPL-2.0 is the automatic legal fallback until PMPL is formally recognised)
4+
#
5+
# zig-api-ci.yml — CI for developer-ecosystem/zig-api
6+
#
7+
# Jobs:
8+
# header-drift — runs `just check-header`; fails if zig_api.h is out of sync
9+
# with the Idris2 ABI source modules.
10+
# build — runs `just build` (zig build)
11+
# test — runs `just test` (zig build test)
12+
13+
name: zig-api CI
14+
15+
on:
16+
push:
17+
paths:
18+
- 'zig-api/**'
19+
pull_request:
20+
paths:
21+
- 'zig-api/**'
22+
23+
permissions:
24+
contents: read
25+
26+
jobs:
27+
# --------------------------------------------------------------------------
28+
# header-drift: regenerate zig_api.h from Idris2 ABI and fail on any diff.
29+
# This catches silent ABI drift between the source modules and the committed
30+
# header without requiring Idris2 to be installed (the extractor is pure
31+
# Bash + Python 3, both available on ubuntu-latest).
32+
# --------------------------------------------------------------------------
33+
header-drift:
34+
name: Check header drift
35+
runs-on: ubuntu-latest
36+
permissions:
37+
contents: read
38+
defaults:
39+
run:
40+
working-directory: zig-api
41+
42+
steps:
43+
- name: Checkout
44+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
45+
46+
- name: Regenerate header and check for drift
47+
run: just check-header
48+
49+
# --------------------------------------------------------------------------
50+
# build: compile the Zig FFI layer (shared + static libraries).
51+
# --------------------------------------------------------------------------
52+
build:
53+
name: Build (zig build)
54+
runs-on: ubuntu-latest
55+
permissions:
56+
contents: read
57+
defaults:
58+
run:
59+
working-directory: zig-api
60+
61+
steps:
62+
- name: Checkout
63+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
64+
65+
- name: Install just
66+
run: |
67+
curl -sSfL https://just.systems/install.sh | bash -s -- --to /usr/local/bin
68+
69+
- name: Install Zig
70+
run: |
71+
ZIG_VERSION=0.15.0-dev.672+b15e2d572
72+
curl -sSfL "https://ziglang.org/builds/zig-linux-x86_64-${ZIG_VERSION}.tar.xz" \
73+
| tar -xJ --strip-components=1 -C /usr/local
74+
env:
75+
ZIG_VERSION: "0.15.0-dev.672+b15e2d572"
76+
77+
- name: Build
78+
run: just build
79+
80+
# --------------------------------------------------------------------------
81+
# test: run Zig unit tests.
82+
# --------------------------------------------------------------------------
83+
test:
84+
name: Test (zig build test)
85+
runs-on: ubuntu-latest
86+
needs: build
87+
permissions:
88+
contents: read
89+
defaults:
90+
run:
91+
working-directory: zig-api
92+
93+
steps:
94+
- name: Checkout
95+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
96+
97+
- name: Install just
98+
run: |
99+
curl -sSfL https://just.systems/install.sh | bash -s -- --to /usr/local/bin
100+
101+
- name: Install Zig
102+
run: |
103+
ZIG_VERSION=0.15.0-dev.672+b15e2d572
104+
curl -sSfL "https://ziglang.org/builds/zig-linux-x86_64-${ZIG_VERSION}.tar.xz" \
105+
| tar -xJ --strip-components=1 -C /usr/local
106+
env:
107+
ZIG_VERSION: "0.15.0-dev.672+b15e2d572"
108+
109+
- name: Test
110+
run: just test

zig-api/Justfile

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,26 @@ test-all: test test-integration
3333

3434
# Check Idris2 ABI proofs (requires idris2 on PATH)
3535
check-abi:
36-
idris2 --check src/abi/Types.idr
37-
idris2 --check src/abi/Http.idr
38-
idris2 --check src/abi/Process.idr
39-
idris2 --check src/abi/Connector.idr
40-
idris2 --check src/abi/Foreign.idr
36+
idris2 --check src/ZigApi/ABI/Types.idr
37+
idris2 --check src/ZigApi/ABI/Http.idr
38+
idris2 --check src/ZigApi/ABI/Process.idr
39+
idris2 --check src/ZigApi/ABI/Connector.idr
40+
idris2 --check src/ZigApi/ABI/Foreign.idr
41+
42+
# Regenerate generated/abi/zig_api.h from the Idris2 ABI modules.
43+
# Output is deterministic (fixed section order, no timestamps).
44+
# Run this whenever any src/ZigApi/ABI/*.idr file changes.
45+
gen-header:
46+
bash scripts/gen-header.sh .
47+
48+
# Verify the committed header matches what gen-header would produce.
49+
# Fails with a diff if there is drift. Used by CI.
50+
check-header:
51+
just gen-header
52+
git diff --exit-code generated/abi/zig_api.h
4153

4254
# Build + check everything
43-
ci: check-abi test
55+
ci: check-abi gen-header test
4456

4557
# Remove build artefacts
4658
clean:

zig-api/generated/abi/zig_api.h

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -50,72 +50,72 @@ void uapi_teardown(void);
5050
* Result codes (ZigApi.ABI.Types.resultTag)
5151
* ========================================================================== */
5252

53-
#define UAPI_OK 0
54-
#define UAPI_ERR 1
55-
#define UAPI_INVALID_PARAM 2
56-
#define UAPI_OUT_OF_MEMORY 3
57-
#define UAPI_NULL_POINTER 4
58-
#define UAPI_PATH_DENIED 5
59-
#define UAPI_PROCESS_FAILED 6
60-
#define UAPI_TIMEOUT 7
61-
#define UAPI_NOT_FOUND 8
62-
#define UAPI_ALREADY_EXISTS 9
63-
#define UAPI_SLOT_EXHAUSTED 10
53+
#define UAPI_OK 0
54+
#define UAPI_ERR 1
55+
#define UAPI_INVALID_PARAM 2
56+
#define UAPI_OUT_OF_MEMORY 3
57+
#define UAPI_NULL_POINTER 4
58+
#define UAPI_PATH_DENIED 5
59+
#define UAPI_PROCESS_FAILED 6
60+
#define UAPI_TIMEOUT 7
61+
#define UAPI_NOT_FOUND 8
62+
#define UAPI_ALREADY_EXISTS 9
63+
#define UAPI_SLOT_EXHAUSTED 10
6464

6565
/* ============================================================================
6666
* ServerState tags (ZigApi.ABI.Http.serverStateTag)
6767
* ========================================================================== */
6868

69-
#define UAPI_SERVER_IDLE 0
70-
#define UAPI_SERVER_LISTENING 1
71-
#define UAPI_SERVER_DRAINING 2
72-
#define UAPI_SERVER_STOPPED 3
69+
#define UAPI_SERVER_IDLE 0
70+
#define UAPI_SERVER_LISTENING 1
71+
#define UAPI_SERVER_DRAINING 2
72+
#define UAPI_SERVER_STOPPED 3
7373

7474
/* ============================================================================
7575
* HealthStatus tags (ZigApi.ABI.Http.healthStatusTag)
7676
* ========================================================================== */
7777

78-
#define UAPI_HEALTH_SERVING 0
79-
#define UAPI_HEALTH_NOT_SERVING 1
78+
#define UAPI_HEALTH_SERVING 0
79+
#define UAPI_HEALTH_NOT_SERVING 1
8080

8181
/* ============================================================================
8282
* ConnectorState tags (ZigApi.ABI.Connector.connectorStateTag)
8383
* ========================================================================== */
8484

85-
#define UAPI_CONNECTOR_DISCONNECTED 0
86-
#define UAPI_CONNECTOR_CONNECTING 1
87-
#define UAPI_CONNECTOR_CONNECTED 2
88-
#define UAPI_CONNECTOR_DEGRADED 3
89-
#define UAPI_CONNECTOR_FAILED 4
90-
#define UAPI_CONNECTOR_DRAINING 5
85+
#define UAPI_CONNECTOR_DISCONNECTED 0
86+
#define UAPI_CONNECTOR_CONNECTING 1
87+
#define UAPI_CONNECTOR_CONNECTED 2
88+
#define UAPI_CONNECTOR_DEGRADED 3
89+
#define UAPI_CONNECTOR_FAILED 4
90+
#define UAPI_CONNECTOR_DRAINING 5
9191

9292
/* ============================================================================
9393
* ServiceId tags (ZigApi.ABI.Connector.serviceIdTag)
9494
* ========================================================================== */
9595

96-
#define UAPI_SERVICE_AMBIENT_OPS 0
97-
#define UAPI_SERVICE_BOJ 1
98-
#define UAPI_SERVICE_BURBLE 2
99-
#define UAPI_SERVICE_ECHIDNA 3
100-
#define UAPI_SERVICE_GOSSAMER 4
101-
#define UAPI_SERVICE_GROOVE_BRIDGE 5
102-
#define UAPI_SERVICE_HYPATIA 6
103-
#define UAPI_SERVICE_IDAPTIK 7
104-
#define UAPI_SERVICE_REPOSYSTEM 8
105-
#define UAPI_SERVICE_STAPELN 9
106-
#define UAPI_SERVICE_VERISIMDB 10
96+
#define UAPI_SERVICE_AMBIENT_OPS 0
97+
#define UAPI_SERVICE_BOJ 1
98+
#define UAPI_SERVICE_BURBLE 2
99+
#define UAPI_SERVICE_ECHIDNA 3
100+
#define UAPI_SERVICE_GOSSAMER 4
101+
#define UAPI_SERVICE_GROOVE_BRIDGE 5
102+
#define UAPI_SERVICE_HYPATIA 6
103+
#define UAPI_SERVICE_IDAPTIK 7
104+
#define UAPI_SERVICE_REPOSYSTEM 8
105+
#define UAPI_SERVICE_STAPELN 9
106+
#define UAPI_SERVICE_VERISIMDB 10
107107

108108
/* ============================================================================
109109
* HTTP Method tags (ZigApi.ABI.Http.methodTag)
110110
* ========================================================================== */
111111

112-
#define UAPI_METHOD_GET 0
113-
#define UAPI_METHOD_POST 1
114-
#define UAPI_METHOD_PUT 2
115-
#define UAPI_METHOD_DELETE 3
116-
#define UAPI_METHOD_HEAD 4
117-
#define UAPI_METHOD_OPTIONS 5
118-
#define UAPI_METHOD_PATCH 6
112+
#define UAPI_METHOD_GET 0
113+
#define UAPI_METHOD_POST 1
114+
#define UAPI_METHOD_PUT 2
115+
#define UAPI_METHOD_DELETE 3
116+
#define UAPI_METHOD_HEAD 4
117+
#define UAPI_METHOD_OPTIONS 5
118+
#define UAPI_METHOD_PATCH 6
119119

120120
/* ============================================================================
121121
* Gnosis API server (ffi/zig/src/gnosis.zig)

0 commit comments

Comments
 (0)