Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions .github/workflows/deno-ci-reusable.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# SPDX-License-Identifier: PMPL-1.0-or-later
# deno-ci-reusable.yml — Reusable Deno CI bundle (RSR).
#
# Replaces the per-repo `rescript-deno-ci.yml` template that copy-drifted
# across the estate with several systemic bugs:
#
# * `deno test` ran unconditionally and failed `No test modules found`
# on repos with no Deno tests.
# * `deno lint` / `deno fmt --check` ran unconditionally and failed
# `No target files found` on repos with no JS/TS targets.
# * No top-level `permissions:` declaration, tripping the workflow
# security linter in governance-reusable.yml.
# * Still invoked `npx rescript` even though ReScript is banned in new
# code as of 2026-04-30 (see standards/.claude/CLAUDE.md).
# * The vestigial "security" job grep-audited for permission strings
# without doing anything useful with the result.
#
# Each step now early-exits cleanly when the inputs don't exist, so the
# job is a no-op on repos that don't yet ship Deno code but pass cleanly
# when they start to.
#
# Caller example (single wrapper, mirrors governance.yml's pattern):
#
# jobs:
# deno-ci:
# uses: hyperpolymath/standards/.github/workflows/deno-ci-reusable.yml@main

name: Deno CI (reusable)

on:
workflow_call:
inputs:
runs-on:
description: Runner label for the deno-ci job
type: string
required: false
default: ubuntu-latest
deno-version:
description: Deno version selector
type: string
required: false
default: v2.x

permissions:
contents: read

jobs:
deno-ci:
name: Deno CI
runs-on: ${{ inputs.runs-on }}
permissions:
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: ${{ github.repository }}
ref: ${{ github.ref }}

- uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3
with:
deno-version: ${{ inputs.deno-version }}

- name: Detect Deno targets
id: detect
run: |
# `deno.json` (or its legacy `deno.jsonc`) is the canonical
# signal that this repo opts into Deno tooling. We also count
# raw .ts/.js files as a fallback for repos still mid-migration
# to deno.json. Either way, the per-step guards below honour
# any `include` / `exclude` scoping the consumer declared in
# deno.json.
has_config=false
has_targets=false
has_tests=false
if [ -f deno.json ] || [ -f deno.jsonc ]; then has_config=true; fi
if find . -path ./node_modules -prune -o -path ./.git -prune \
-o \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.mjs" \) \
-type f -print 2>/dev/null | head -1 | grep -q .; then
has_targets=true
fi
if find . -path ./node_modules -prune -o -path ./.git -prune \
-o \( -name "*_test.ts" -o -name "*.test.ts" -o -name "*_test.js" -o -name "*.test.js" \) \
-type f -print 2>/dev/null | head -1 | grep -q .; then
has_tests=true
fi
echo "has_config=$has_config" >> "$GITHUB_OUTPUT"
echo "has_targets=$has_targets" >> "$GITHUB_OUTPUT"
echo "has_tests=$has_tests" >> "$GITHUB_OUTPUT"
echo "deno-ci: config=$has_config targets=$has_targets tests=$has_tests"

- name: Deno lint
if: steps.detect.outputs.has_targets == 'true' || steps.detect.outputs.has_config == 'true'
run: deno lint

- name: Deno fmt check
if: steps.detect.outputs.has_targets == 'true' || steps.detect.outputs.has_config == 'true'
run: deno fmt --check

- name: Deno test
if: steps.detect.outputs.has_tests == 'true'
run: deno test --allow-all --coverage=coverage

- name: Deno type check
if: steps.detect.outputs.has_targets == 'true'
# Soft-pass: `deno check` exits non-zero on unresolved imports we
# don't yet require contributors to vendor. We surface output for
# diagnostics but don't fail the gate.
run: deno check . || echo "::warning::deno check reported issues (non-blocking)."

- name: Summary
run: |
if [ "${{ steps.detect.outputs.has_config }}" = "false" ] \
&& [ "${{ steps.detect.outputs.has_targets }}" = "false" ]; then
echo "deno-ci: no Deno targets detected — skipped all checks."
else
echo "deno-ci: passed (lint / fmt / type / test where applicable)."
fi
38 changes: 34 additions & 4 deletions .github/workflows/governance-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ jobs:
# 3. Inline `# hypatia:ignore ...` pragma in the file's first
# 8 lines — the same escape the Hypatia scanner itself
# honours.
- name: Check for ReScript / Go / Python (banned language files)
- name: Check banned-language files (ReScript / Go / Python / Java / Kotlin / Swift / Dart / V-lang / ATS2 / Makefile)
run: |
rule_module="cicd_rules"
rule_type="banned_language_file"
Expand Down Expand Up @@ -300,15 +300,36 @@ jobs:
echo "✅ No non-exempt ${label}"
}

RES_FILES=$(find . -name "*.res" | grep -v node_modules || true)
GO_FILES=$(find . -name "*.go" || true)
PY_FILES=$(find . -name "*.py" | grep -v salt | grep -v _states \
RES_FILES=$(find . -name "*.res" -not -path "./node_modules/*" -not -path "./.git/*" || true)
GO_FILES=$(find . -name "*.go" -not -path "./.git/*" || true)
PY_FILES=$(find . -name "*.py" -not -path "./.git/*" \
| grep -v salt | grep -v _states \
| grep -v _modules | grep -v pillar | grep -v venv \
| grep -v __pycache__ || true)
MAKE_FILES=$(find . \( -name "Makefile" -o -name "Makefile.*" -o -name "*.mk" \) \
-not -path "./.git/*" -not -path "./.github/*" || true)
JAVA_FILES=$(find . \( -name "*.java" -o -name "*.kt" -o -name "*.kts" \) \
-not -path "./.git/*" || true)
SWIFT_FILES=$(find . -name "*.swift" -not -path "./.git/*" || true)
DART_FILES=$(find . \( -name "*.dart" -o -name "pubspec.yaml" \) \
-not -path "./.git/*" || true)
# V-lang detected by manifest (v.mod / vpkg.json); the .v extension
# collides with Verilog so we never key on it.
VMOD_FILES=$(find . \( -name "v.mod" -o -name "vpkg.json" \) \
-not -path "./node_modules/*" -not -path "./.git/*" || true)
# ATS2 source extensions: rejected in favour of Idris2 / Rust/SPARK.
ATS2_FILES=$(find . \( -name "*.dats" -o -name "*.sats" -o -name "*.hats" \) \
-not -path "./.git/*" || true)

enforce "ReScript files" "use AffineScript instead" "$RES_FILES"
enforce "Go files" "use Rust/WASM instead" "$GO_FILES"
enforce "Python files" "only allowed for SaltStack" "$PY_FILES"
enforce "Makefiles" "use Mustfile/justfile instead" "$MAKE_FILES"
enforce "Java/Kotlin files" "use Rust/Tauri/Dioxus instead" "$JAVA_FILES"
enforce "Swift files" "use Tauri/Dioxus instead" "$SWIFT_FILES"
enforce "Flutter/Dart files" "use Tauri/Dioxus instead (Google lock-in)" "$DART_FILES"
enforce "V-lang manifests (v.mod / vpkg.json)" "V-lang is banned since 2026-04-10 — migrate to Zig" "$VMOD_FILES"
enforce "ATS2 files (.dats / .sats / .hats)" "use Idris2 or Rust/SPARK instead" "$ATS2_FILES"

- name: Check for npm/bun artifacts
# standards#67 — npm-avoidant: package-lock.json must never be tracked
Expand Down Expand Up @@ -340,6 +361,15 @@ jobs:
printf '%s\n' "$NPMRC_FILES"
FAILED=1
fi
# Root package.json with runtime "dependencies" — moved here from
# the now-deleted language-policy.yml. devDependencies-only is
# tolerated for transitional tooling (e.g., a legacy bundler
# invoked from Justfile), but a `"dependencies"` field
# indicates Node.js runtime use, which Deno replaces.
if [ -f package.json ] && grep -q '"dependencies"[[:space:]]*:[[:space:]]*{[^}]' package.json; then
echo "❌ package.json with runtime \"dependencies\" detected. Use deno.json imports instead."
FAILED=1
fi
if [ -n "$FAILED" ]; then
echo "See hyperpolymath/standards docs/JS-RUNTIME-POLICY.adoc for remediation."
exit 1
Expand Down
189 changes: 0 additions & 189 deletions .github/workflows/language-policy.yml

This file was deleted.

Loading