Skip to content

Commit cb41f8b

Browse files
hyperpolymathclaude
andcommitted
ci: deploy missing standard workflows (10 added)
Added from rsr-template-repo: standardizing CI/CD across all repos. Part of global TODO cleanup (2026-03-16). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 44bd936 commit cb41f8b

File tree

10 files changed

+638
-0
lines changed

10 files changed

+638
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
name: Guix/Nix Package Policy
3+
on: [push, pull_request]
4+
5+
permissions: read-all
6+
7+
jobs:
8+
check:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
steps:
13+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
14+
- name: Enforce Guix primary / Nix fallback
15+
run: |
16+
# Check for package manager files
17+
HAS_GUIX=$(find . -name "*.scm" -o -name ".guix-channel" -o -name "guix.scm" 2>/dev/null | head -1)
18+
HAS_NIX=$(find . -name "*.nix" 2>/dev/null | head -1)
19+
20+
# Block new package-lock.json, yarn.lock, Gemfile.lock, etc.
21+
NEW_LOCKS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E 'package-lock\.json|yarn\.lock|Gemfile\.lock|Pipfile\.lock|poetry\.lock|cargo\.lock' || true)
22+
if [ -n "$NEW_LOCKS" ]; then
23+
echo "⚠️ Lock files detected. Prefer Guix manifests for reproducibility."
24+
fi
25+
26+
# Prefer Guix, fallback to Nix
27+
if [ -n "$HAS_GUIX" ]; then
28+
echo "✅ Guix package management detected (primary)"
29+
elif [ -n "$HAS_NIX" ]; then
30+
echo "✅ Nix package management detected (fallback)"
31+
else
32+
echo "ℹ️ Consider adding guix.scm or flake.nix for reproducible builds"
33+
fi
34+
35+
echo "✅ Package policy check passed"

.github/workflows/instant-sync.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Instant Forge Sync - Triggers propagation to all forges on push/release
3+
name: Instant Sync
4+
5+
on:
6+
push:
7+
branches: [main, master]
8+
release:
9+
types: [published]
10+
11+
permissions:
12+
contents: read
13+
14+
jobs:
15+
dispatch:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Trigger Propagation
19+
uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v3
20+
with:
21+
token: ${{ secrets.FARM_DISPATCH_TOKEN }}
22+
repository: hyperpolymath/.git-private-farm
23+
event-type: propagate
24+
client-payload: |-
25+
{
26+
"repo": "${{ github.event.repository.name }}",
27+
"ref": "${{ github.ref }}",
28+
"sha": "${{ github.sha }}",
29+
"forges": ""
30+
}
31+
32+
- name: Confirm
33+
run: echo "::notice::Propagation triggered for ${{ github.event.repository.name }}"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
name: NPM/Bun Blocker
3+
on: [push, pull_request]
4+
5+
permissions: read-all
6+
7+
jobs:
8+
check:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
steps:
13+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
14+
- name: Block npm/bun
15+
run: |
16+
if [ -f "package-lock.json" ] || [ -f "bun.lockb" ] || [ -f ".npmrc" ]; then
17+
echo "❌ npm/bun artifacts detected. Use Deno instead."
18+
exit 1
19+
fi
20+
echo "✅ No npm/bun violations"
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# RSR Anti-Pattern CI Check
3+
# SPDX-License-Identifier: PMPL-1.0-or-later
4+
#
5+
# Enforces: No TypeScript, No Go, No Python (except SaltStack), No npm
6+
# Allows: ReScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme
7+
8+
name: RSR Anti-Pattern Check
9+
10+
on:
11+
push:
12+
branches: [main, master, develop]
13+
pull_request:
14+
branches: [main, master, develop]
15+
16+
17+
permissions: read-all
18+
19+
jobs:
20+
antipattern-check:
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: read
24+
steps:
25+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26+
27+
- name: Check for TypeScript
28+
run: |
29+
# Exclude bindings/deno/ - those are Deno FFI files using Deno.dlopen, not plain TypeScript
30+
# Exclude .d.ts files - those are TypeScript type declarations for ReScript FFI
31+
TS_FILES=$(find . \( -name "*.ts" -o -name "*.tsx" \) | grep -v node_modules | grep -v 'bindings/deno' | grep -v '\.d\.ts$' || true)
32+
if [ -n "$TS_FILES" ]; then
33+
echo "❌ TypeScript files detected - use ReScript instead"
34+
echo "$TS_FILES"
35+
exit 1
36+
fi
37+
echo "✅ No TypeScript files (Deno FFI bindings excluded)"
38+
39+
- name: Check for Go
40+
run: |
41+
if find . -name "*.go" | grep -q .; then
42+
echo "❌ Go files detected - use Rust/WASM instead"
43+
find . -name "*.go"
44+
exit 1
45+
fi
46+
echo "✅ No Go files"
47+
48+
- name: Check for Python (non-SaltStack)
49+
run: |
50+
PY_FILES=$(find . -name "*.py" | grep -v salt | grep -v _states | grep -v _modules | grep -v pillar | grep -v venv | grep -v __pycache__ || true)
51+
if [ -n "$PY_FILES" ]; then
52+
echo "❌ Python files detected - only allowed for SaltStack"
53+
echo "$PY_FILES"
54+
exit 1
55+
fi
56+
echo "✅ No non-SaltStack Python files"
57+
58+
- name: Check for npm lockfiles
59+
run: |
60+
if [ -f "package-lock.json" ] || [ -f "yarn.lock" ]; then
61+
echo "❌ npm/yarn lockfile detected - use Deno instead"
62+
exit 1
63+
fi
64+
echo "✅ No npm lockfiles"
65+
66+
- name: Check for tsconfig
67+
run: |
68+
if [ -f "tsconfig.json" ]; then
69+
echo "❌ tsconfig.json detected - use ReScript instead"
70+
exit 1
71+
fi
72+
echo "✅ No tsconfig.json"
73+
74+
- name: Verify Deno presence (if package.json exists)
75+
run: |
76+
if [ -f "package.json" ]; then
77+
if [ ! -f "deno.json" ] && [ ! -f "deno.jsonc" ]; then
78+
echo "⚠️ Warning: package.json without deno.json - migration recommended"
79+
fi
80+
fi
81+
echo "✅ Deno configuration check complete"
82+
83+
- name: Summary
84+
run: |
85+
echo "╔════════════════════════════════════════════════════════════╗"
86+
echo "║ RSR Anti-Pattern Check Passed ✅ ║"
87+
echo "║ ║"
88+
echo "║ Allowed: ReScript, Deno, WASM, Rust, OCaml, Haskell, ║"
89+
echo "║ Guile/Scheme, SaltStack (Python) ║"
90+
echo "║ ║"
91+
echo "║ Blocked: TypeScript, Go, npm, Python (non-Salt) ║"
92+
echo "╚════════════════════════════════════════════════════════════╝"
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Prevention workflow - runs OpenSSF Scorecard and fails on low scores
3+
name: OpenSSF Scorecard Enforcer
4+
5+
on:
6+
push:
7+
branches: [main]
8+
schedule:
9+
- cron: '0 6 * * 1' # Weekly on Monday
10+
workflow_dispatch:
11+
12+
permissions: read-all
13+
14+
jobs:
15+
scorecard:
16+
runs-on: ubuntu-latest
17+
permissions:
18+
security-events: write
19+
id-token: write # For OIDC
20+
steps:
21+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
22+
with:
23+
persist-credentials: false
24+
25+
- name: Run Scorecard
26+
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
27+
with:
28+
results_file: results.sarif
29+
results_format: sarif
30+
publish_results: true
31+
32+
- name: Upload SARIF
33+
uses: github/codeql-action/upload-sarif@9e907b5e64f6b83e7804b09294d44122997950d6 # v3
34+
with:
35+
sarif_file: results.sarif
36+
37+
- name: Check minimum score
38+
run: |
39+
# Parse score from results
40+
SCORE=$(jq -r '.runs[0].tool.driver.properties.score // 0' results.sarif 2>/dev/null || echo "0")
41+
42+
echo "OpenSSF Scorecard Score: $SCORE"
43+
44+
# Minimum acceptable score (0-10 scale)
45+
MIN_SCORE=5
46+
47+
if [ "$(echo "$SCORE < $MIN_SCORE" | bc -l)" = "1" ]; then
48+
echo "::error::Scorecard score $SCORE is below minimum $MIN_SCORE"
49+
exit 1
50+
fi
51+
52+
# Check specific high-priority items
53+
check-critical:
54+
runs-on: ubuntu-latest
55+
steps:
56+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
57+
58+
- name: Check SECURITY.md exists
59+
run: |
60+
if [ ! -f "SECURITY.md" ]; then
61+
echo "::error::SECURITY.md is required"
62+
exit 1
63+
fi
64+
65+
- name: Check for pinned dependencies
66+
run: |
67+
# Check workflows for unpinned actions
68+
unpinned=$(grep -r "uses:.*@v[0-9]" .github/workflows/*.yml 2>/dev/null | grep -v "#" | head -5 || true)
69+
if [ -n "$unpinned" ]; then
70+
echo "::warning::Found unpinned actions:"
71+
echo "$unpinned"
72+
fi
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
# Prevention workflow - scans for hardcoded secrets before they reach main
3+
name: Secret Scanner
4+
5+
on:
6+
pull_request:
7+
push:
8+
branches: [main]
9+
10+
permissions: read-all
11+
12+
jobs:
13+
trufflehog:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
17+
with:
18+
fetch-depth: 0 # Full history for scanning
19+
20+
- name: TruffleHog Secret Scan
21+
uses: trufflesecurity/trufflehog@6961f2bace57ab32b23b3ba40f8f420f6bc7e004 # v3
22+
with:
23+
extra_args: --only-verified --fail
24+
25+
gitleaks:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Gitleaks Secret Scan
33+
uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2
34+
env:
35+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
37+
# Rust-specific: Check for hardcoded crypto values
38+
rust-secrets:
39+
runs-on: ubuntu-latest
40+
if: hashFiles('**/Cargo.toml') != ''
41+
steps:
42+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
43+
44+
- name: Check for hardcoded secrets in Rust
45+
run: |
46+
# Patterns that suggest hardcoded secrets
47+
PATTERNS=(
48+
'const.*SECRET.*=.*"'
49+
'const.*KEY.*=.*"[a-zA-Z0-9]{16,}"'
50+
'const.*TOKEN.*=.*"'
51+
'let.*api_key.*=.*"'
52+
'HMAC.*"[a-fA-F0-9]{32,}"'
53+
'password.*=.*"[^"]+"'
54+
)
55+
56+
found=0
57+
for pattern in "${PATTERNS[@]}"; do
58+
if grep -rn --include="*.rs" -E "$pattern" src/; then
59+
echo "WARNING: Potential hardcoded secret found matching: $pattern"
60+
found=1
61+
fi
62+
done
63+
64+
if [ $found -eq 1 ]; then
65+
echo "::error::Potential hardcoded secrets detected. Use environment variables instead."
66+
exit 1
67+
fi
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
name: Security Policy
3+
on: [push, pull_request]
4+
5+
permissions: read-all
6+
7+
jobs:
8+
check:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
steps:
13+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
14+
- name: Security checks
15+
run: |
16+
FAILED=false
17+
18+
# Block MD5/SHA1 for security (allow for checksums/caching)
19+
WEAK_CRYPTO=$(grep -rE 'md5\(|sha1\(' --include="*.py" --include="*.rb" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" . 2>/dev/null | grep -v 'checksum\|cache\|test\|spec' | head -5 || true)
20+
if [ -n "$WEAK_CRYPTO" ]; then
21+
echo "⚠️ Weak crypto (MD5/SHA1) detected. Use SHA256+ for security:"
22+
echo "$WEAK_CRYPTO"
23+
fi
24+
25+
# Block HTTP URLs (except localhost)
26+
HTTP_URLS=$(grep -rE 'http://[^l][^o][^c]' --include="*.py" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" --include="*.yaml" --include="*.yml" . 2>/dev/null | grep -v 'localhost\|127.0.0.1\|example\|test\|spec' | head -5 || true)
27+
if [ -n "$HTTP_URLS" ]; then
28+
echo "⚠️ HTTP URLs found. Use HTTPS:"
29+
echo "$HTTP_URLS"
30+
fi
31+
32+
# Block hardcoded secrets patterns
33+
SECRETS=$(grep -rEi '(api_key|apikey|secret_key|password)\s*[=:]\s*["\x27][A-Za-z0-9+/=]{20,}' --include="*.py" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" --include="*.env" . 2>/dev/null | grep -v 'example\|sample\|test\|mock\|placeholder' | head -3 || true)
34+
if [ -n "$SECRETS" ]; then
35+
echo "❌ Potential hardcoded secrets detected!"
36+
FAILED=true
37+
fi
38+
39+
if [ "$FAILED" = true ]; then
40+
exit 1
41+
fi
42+
43+
echo "✅ Security policy check passed"

.github/workflows/ts-blocker.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# SPDX-License-Identifier: PMPL-1.0-or-later
2+
name: TypeScript/JavaScript Blocker
3+
on: [push, pull_request]
4+
5+
permissions: read-all
6+
7+
jobs:
8+
check:
9+
runs-on: ubuntu-latest
10+
permissions:
11+
contents: read
12+
steps:
13+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
14+
- name: Block new TypeScript/JavaScript
15+
run: |
16+
NEW_TS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(ts|tsx)$' | grep -v '\.gen\.' || true)
17+
NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.res\.js$' | grep -v '\.gen\.' | grep -v 'node_modules' || true)
18+
19+
if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ]; then
20+
echo "❌ New TS/JS files detected. Use ReScript instead."
21+
[ -n "$NEW_TS" ] && echo "$NEW_TS"
22+
[ -n "$NEW_JS" ] && echo "$NEW_JS"
23+
exit 1
24+
fi
25+
echo "✅ ReScript policy enforced"

0 commit comments

Comments
 (0)