Skip to content

Commit c1d9230

Browse files
hyperpolymathclaude
andcommitted
chore(hooks): version-controlled pre-commit; SPDX split by file-type
Replaces the un-versioned .git/hooks/pre-commit with a committed, installable hook (hooks/pre-commit + hooks/install.sh sets core.hooksPath=hooks), fixing the 'hooks not reproducible across clones' gap. Licence fix (LICENCE-POLICY Rule 1): SPDX expectation now splits by file-type — prose docs (.md/.adoc) expect CC-BY-SA-4.0, code/config expect MPL-2.0 — so the hook stops rejecting correctly CC-BY-SA-licensed docs. Owner-string check kept strict on all (deliberate LLM-edit diagnostic). No-C / SNIFs / Idris-ABI policies preserved unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent e8b8079 commit c1d9230

2 files changed

Lines changed: 86 additions & 0 deletions

File tree

hooks/install.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env bash
2+
# SPDX-License-Identifier: MPL-2.0
3+
# Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
4+
#
5+
# Install the version-controlled git hooks for this repo.
6+
# Points git at the committed hooks/ directory (reproducible across clones),
7+
# rather than copying into the un-versioned .git/hooks/.
8+
9+
set -euo pipefail
10+
cd "$(git rev-parse --show-toplevel)"
11+
12+
git config core.hooksPath hooks
13+
chmod +x hooks/pre-commit
14+
15+
echo "Installed: core.hooksPath -> hooks/ (pre-commit active)"

hooks/pre-commit

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: MPL-2.0
3+
# Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
4+
#
5+
# Pre-commit enforcer: licence/owner headers + architecture policies.
6+
# Canonical, version-controlled hook. Install with: bash hooks/install.sh
7+
# (sets core.hooksPath=hooks so this file is used directly).
8+
9+
# 1. License Check
10+
# Determine if this is a SHARED (AGPL) or OWNED (MPL) repo
11+
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
12+
DIR_NAME=$(basename "$(pwd)")
13+
14+
if [[ "$REMOTE_URL" == *"JoshuaJewell"* || "$DIR_NAME" == boj-* || "$DIR_NAME" == bofj-* ]]; then
15+
# Shared repos: components retain their original licences; verify root LICENSE is AGPL.
16+
if ! grep -q "Affero General Public License" LICENSE 2>/dev/null; then
17+
echo "ERROR: Shared repository must have AGPL-3.0-or-later LICENSE file."
18+
exit 1
19+
fi
20+
else
21+
EXPECTED_OWNER="Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>"
22+
23+
# Check staged files for SPDX header, split by file-type per LICENCE-POLICY Rule 1:
24+
# prose docs (.md/.adoc) -> CC-BY-SA-4.0 ; everything else (code/config) -> MPL-2.0.
25+
# Owner-string is required on all (deliberate LLM-edit diagnostic).
26+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(zig|ex|idr|eph|py|js|ts|rs|c|h|adoc|md)$')
27+
28+
for file in $STAGED_FILES; do
29+
case "$file" in
30+
*.md|*.adoc) FILE_LICENSE="CC-BY-SA-4.0" ;;
31+
*) FILE_LICENSE="MPL-2.0" ;;
32+
esac
33+
if ! grep -q "SPDX-License-Identifier: $FILE_LICENSE" "$file"; then
34+
echo "ERROR: File $file is missing correct SPDX-License-Identifier: $FILE_LICENSE"
35+
exit 1
36+
fi
37+
if ! grep -q "$EXPECTED_OWNER" "$file"; then
38+
echo "ERROR: File $file is missing correct Owner: $EXPECTED_OWNER"
39+
exit 1
40+
fi
41+
done
42+
fi
43+
44+
# 2. No C Policy — all APIs/FFIs must be Zig (exceptions: proven, boj-server-cartridges)
45+
if [[ "$DIR_NAME" != "proven" && "$DIR_NAME" != "boj-server-cartridges" ]]; then
46+
STAGED_C_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.c$')
47+
if [ -n "$STAGED_C_FILES" ]; then
48+
echo "ERROR: Strict No C Policy. C files are not allowed in this repository."
49+
echo "Offending files: $STAGED_C_FILES"
50+
exit 1
51+
fi
52+
fi
53+
54+
# 3. SNIFs Policy — never raw NIFs; always Safe NIFs
55+
STAGED_BEAM_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(ex|exs|erl)$')
56+
for file in $STAGED_BEAM_FILES; do
57+
if grep -qE "erlang:load_nif|:erlang\.load_nif" "$file"; then
58+
echo "ERROR: Raw NIFs are forbidden. Use SNIFs (Safe NIFs) from the snifs repository."
59+
exit 1
60+
fi
61+
done
62+
63+
# 4. Idris 2 ABI Policy — ABIs/capability matchers should be Idris 2 (Zig allowed for the FFI bridge)
64+
STAGED_ABI_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -i "abi")
65+
for file in $STAGED_ABI_FILES; do
66+
if [[ "$file" != *.idr && "$file" != *.zig && "$file" != *.adoc && "$file" != *.md ]]; then
67+
echo "WARNING: ABI definition found in non-Idris/Zig file: $file"
68+
fi
69+
done
70+
71+
exit 0

0 commit comments

Comments
 (0)