1- # SPDX-License-Identifier: PMPL-1.0-or-later
1+ # SPDX-License-Identifier: PMPL-1.0
2+ name : Language Policy Enforcement
3+
4+ on :
5+ push :
6+ branches : [main, master]
7+ pull_request :
8+ branches : [main, master]
9+
210# Estate guardrail: cancel superseded runs so re-pushes / rebased PR
311# updates do not pile up queued runs against the shared account-wide
412# Actions concurrency pool. Applied only to read-only check workflows
@@ -10,47 +18,172 @@ concurrency:
1018permissions :
1119 contents : read
1220
13- name : Language Policy Enforcement
14- on : [push, pull_request]
1521jobs :
16- check :
22+ check-banned-languages :
23+ name : Check for Banned Languages
1724 runs-on : ubuntu-latest
1825 steps :
19- - uses : actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
20- - name : Enforce language policies
21- run : |
22- # Block new Python files (except SaltStack)
23- NEW_PY=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.py$' | grep -v 'salt' || true)
24- if [ -n "$NEW_PY" ]; then
25- echo "❌ New Python files detected. Use Rust or AffineScript instead."
26- echo "$NEW_PY"
27- exit 1
28- fi
29-
30- # Block new Ruby files
31- NEW_RB=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.rb$' || true)
32- if [ -n "$NEW_RB" ]; then
33- echo "❌ New Ruby files detected. Use Rust, Ada/SPARK, or Crystal instead."
34- echo "$NEW_RB"
35- exit 1
36- fi
37-
38- # Block new Perl files
39- NEW_PL=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(pl|pm)$' || true)
40- if [ -n "$NEW_PL" ]; then
41- echo "❌ New Perl files detected. Use Rust instead."
42- echo "$NEW_PL"
43- exit 1
44- fi
45-
46- # Block new Java/Kotlin (except in LSP projects)
47- if [[ ! "$GITHUB_REPOSITORY" =~ "language-server" ]]; then
48- NEW_JAVA=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(java|kt)$' || true)
49- if [ -n "$NEW_JAVA" ]; then
50- echo "❌ New Java/Kotlin files detected. Use Rust instead."
51- echo "$NEW_JAVA"
26+ - name : Checkout
27+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
28+
29+ # TypeScript check delegated to rsr-antipattern.yml (which honours the
30+ # universal allowlist and the .claude/CLAUDE.md exemptions table). The
31+ # blunt `find -name "*.ts"` form previously here false-positived on
32+ # legitimate bridge files (e.g. tests/*.vitest.config.ts under the
33+ # *vscode*/tests/ allowlist).
34+
35+ - name : Check for ReScript files
36+ run : |
37+ # Estate policy: RS/TS/JS -> AffineScript -> typed-wasm.
38+ # ReScript (.res) is no longer the TS replacement.
39+ if find . -name "*.res" | grep -v node_modules | head -1 | grep -q .; then
40+ echo "::error::ReScript files found. Use AffineScript instead."
41+ find . -name "*.res" | grep -v node_modules
42+ exit 1
43+ fi
44+ echo "✓ No ReScript files found"
45+
46+ - name : Check for Go files
47+ run : |
48+ if find . -name "*.go" | head -1 | grep -q .; then
49+ echo "::error::Go files found. Use Rust instead."
50+ find . -name "*.go"
51+ exit 1
52+ fi
53+ echo "✓ No Go files found"
54+
55+ - name : Check for Python files (except Ansible)
56+ run : |
57+ # Allow Python only in ansible/ directories or for Ansible-specific files
58+ PYTHON_FILES=$(find . -name "*.py" | grep -v __pycache__ | grep -v ".venv" | grep -v "ansible" | grep -v "molecule" || true)
59+ if [ -n "$PYTHON_FILES" ]; then
60+ echo "::error::Python files found outside Ansible context. Rewrite in Rust/AffineScript."
61+ echo "$PYTHON_FILES"
62+ exit 1
63+ fi
64+ echo "✓ No unauthorized Python files found"
65+
66+ - name : Check for Makefiles
67+ run : |
68+ MAKEFILES=$(find . -name "Makefile" -o -name "Makefile.*" -o -name "*.mk" | grep -v ".github" || true)
69+ if [ -n "$MAKEFILES" ]; then
70+ echo "::error::Makefiles found. Use Mustfile/justfile instead."
71+ echo "$MAKEFILES"
72+ exit 1
73+ fi
74+ echo "✓ No Makefiles found"
75+
76+ - name : Check for package.json (npm/node)
77+ run : |
78+ if [ -f "package.json" ]; then
79+ # Allow if it only contains devDependencies for tooling
80+ if grep -q '"dependencies"' package.json; then
81+ echo "::error::package.json with runtime dependencies found. Use deno.json instead."
5282 exit 1
5383 fi
5484 fi
55-
56- echo "✅ Language policy check passed"
85+ echo "✓ No npm runtime dependencies found"
86+
87+ - name : Check for Java/Kotlin files
88+ run : |
89+ if find . -name "*.java" -o -name "*.kt" -o -name "*.kts" | head -1 | grep -q .; then
90+ echo "::error::Java/Kotlin files found. Use Rust/Tauri/Dioxus instead."
91+ find . -name "*.java" -o -name "*.kt" -o -name "*.kts"
92+ exit 1
93+ fi
94+ echo "✓ No Java/Kotlin files found"
95+
96+ - name : Check for Swift files
97+ run : |
98+ if find . -name "*.swift" | head -1 | grep -q .; then
99+ echo "::error::Swift files found. Use Tauri/Dioxus instead."
100+ find . -name "*.swift"
101+ exit 1
102+ fi
103+ echo "✓ No Swift files found"
104+
105+ - name : Check for V-lang code
106+ run : |
107+ # V-lang is banned as of 2026-04-10. Migration target: Zig.
108+ # We detect by v.mod (V-lang's module manifest) rather than *.v
109+ # extension because .v collides with Verilog hardware sources.
110+ V_MOD_FILES=$(find . -name "v.mod" -not -path "*/node_modules/*" -not -path "*/.git/*" || true)
111+ if [ -n "$V_MOD_FILES" ]; then
112+ echo "::error::V-lang code found (detected via v.mod). V-lang is banned since 2026-04-10. Migrate to Zig."
113+ echo "$V_MOD_FILES"
114+ exit 1
115+ fi
116+ # Also check for vpkg.json (alternative V package manifest)
117+ VPKG_FILES=$(find . -name "vpkg.json" -not -path "*/node_modules/*" -not -path "*/.git/*" || true)
118+ if [ -n "$VPKG_FILES" ]; then
119+ echo "::error::V-lang code found (detected via vpkg.json). V-lang is banned since 2026-04-10. Migrate to Zig."
120+ echo "$VPKG_FILES"
121+ exit 1
122+ fi
123+ echo "✓ No V-lang code found"
124+
125+ - name : Check for Flutter/Dart files
126+ run : |
127+ if find . -name "*.dart" -o -name "pubspec.yaml" | head -1 | grep -q .; then
128+ echo "::error::Flutter/Dart code found. Use Tauri/Dioxus instead (Google lock-in policy)."
129+ find . -name "*.dart" -o -name "pubspec.yaml"
130+ exit 1
131+ fi
132+ echo "✓ No Flutter/Dart code found"
133+
134+ - name : Check for ATS2 files
135+ run : |
136+ # ATS2 is rejected in favour of Idris2 (formal verification) and
137+ # Rust/SPARK (safety-critical operational code). See LANGUAGE-POLICY.adoc §Amendments v1.1.0.
138+ if find . -name "*.dats" -o -name "*.sats" -o -name "*.hats" | head -1 | grep -q .; then
139+ echo "::error::ATS2 files found. Use Idris2 (formal verification) or Rust/SPARK (safety-critical code) instead."
140+ find . -name "*.dats" -o -name "*.sats" -o -name "*.hats"
141+ exit 1
142+ fi
143+ echo "✓ No ATS2 files found"
144+
145+ check-required-files :
146+ name : Check Required Files
147+ runs-on : ubuntu-latest
148+ steps :
149+ - name : Checkout
150+ uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
151+
152+ - name : Check for .machine_readable directory
153+ run : |
154+ if [ ! -d ".machine_readable" ]; then
155+ echo "::warning::.machine_readable/ directory not found"
156+ else
157+ echo "✓ .machine_readable/ directory exists"
158+ # Per estate policy: .a2ml is canonical; .scm is reserved for Guix.
159+ for a2ml in STATE META ECOSYSTEM AGENTIC NEUROSYM PLAYBOOK; do
160+ if [ ! -f ".machine_readable/6a2/${a2ml}.a2ml" ] && [ ! -f ".machine_readable/${a2ml}.a2ml" ]; then
161+ echo "::warning::Missing .machine_readable/6a2/${a2ml}.a2ml (or top-level fallback)"
162+ else
163+ echo "✓ ${a2ml}.a2ml present"
164+ fi
165+ done
166+ fi
167+
168+ - name : Check for Mustfile/justfile
169+ run : |
170+ if [ ! -f "Mustfile" ] && [ ! -f "justfile" ]; then
171+ echo "::warning::Neither Mustfile nor justfile found"
172+ else
173+ echo "✓ Build system files present"
174+ fi
175+
176+ - name : Check SPDX headers
177+ run : |
178+ MISSING_SPDX=0
179+ for ext in rs affine js jsx mjs ts tsx py go java kt swift sh bash; do
180+ while IFS= read -r file; do
181+ if [ -n "$file" ] && ! head -5 "$file" | grep -q "SPDX-License-Identifier"; then
182+ echo "::warning::Missing SPDX header: $file"
183+ MISSING_SPDX=$((MISSING_SPDX + 1))
184+ fi
185+ done < <(find . -name "*.$ext" -type f 2>/dev/null | grep -v node_modules | grep -v .git | head -50)
186+ done
187+ if [ $MISSING_SPDX -gt 0 ]; then
188+ echo "::warning::$MISSING_SPDX files missing SPDX headers"
189+ fi
0 commit comments