|
| 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