Skip to content

NRCL-64 Register trusted release candidate validation (#23) #42

NRCL-64 Register trusted release candidate validation (#23)

NRCL-64 Register trusted release candidate validation (#23) #42

Workflow file for this run

name: Security Scan
on:
pull_request:
branches: [main]
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
jobs:
dependency-audit:
runs-on: ubuntu-latest
name: Dependency Audit (Advisory)
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.11"
enable-cache: true
- name: Export dependency graph for audit
run: uv export --extra dev --format requirements-txt -o requirements-dev.txt
- name: Run pip-audit
id: pip_audit
continue-on-error: true
run: uvx pip-audit -r requirements-dev.txt -f json -o pip-audit.json
- name: Summarize dependency findings
if: always()
env:
PIP_AUDIT_OUTCOME: ${{ steps.pip_audit.outcome }}
run: |
uv run python - <<'PY'
import json
import os
from pathlib import Path
summary = Path("pip-audit-summary.md")
report_path = Path("pip-audit.json")
audit_outcome = os.getenv("PIP_AUDIT_OUTCOME", "unknown")
if not report_path.exists():
summary.write_text(
"## Dependency Audit (Advisory)\n\n"
f"- pip-audit step outcome: **{audit_outcome}**\n"
"- Report missing: pip-audit did not produce `pip-audit.json`.\n"
)
print("pip-audit report missing")
else:
report = json.loads(report_path.read_text())
findings = []
for dep in report.get("dependencies", []):
for vuln in dep.get("vulns", []):
findings.append((dep["name"], dep["version"], vuln.get("id", "UNKNOWN")))
with summary.open("w", encoding="utf-8") as f:
f.write("## Dependency Audit (Advisory)\n\n")
f.write(f"- pip-audit step outcome: **{audit_outcome}**\n")
f.write(f"- Vulnerabilities found: **{len(findings)}**\n\n")
if findings:
f.write("| Package | Version | Vulnerability |\n")
f.write("|---|---|---|\n")
for pkg, ver, vuln in findings[:25]:
f.write(f"| {pkg} | {ver} | {vuln} |\n")
else:
f.write("No known vulnerabilities found.\n")
PY
cat pip-audit-summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Upload dependency report
if: always()
uses: actions/upload-artifact@v4
with:
name: pip-audit-report
path: |
pip-audit.json
pip-audit-summary.md
retention-days: 14
static-security:
runs-on: ubuntu-latest
name: Bandit Scan (Advisory)
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up uv
uses: astral-sh/setup-uv@v7
with:
python-version: "3.11"
enable-cache: true
- name: Run Bandit
id: bandit
continue-on-error: true
run: uvx --from bandit bandit -q -r neural -f json -o bandit.json
- name: Summarize Bandit findings
if: always()
env:
BANDIT_OUTCOME: ${{ steps.bandit.outcome }}
run: |
uv run python - <<'PY'
import json
import os
from pathlib import Path
report_path = Path("bandit.json")
summary = Path("bandit-summary.md")
bandit_outcome = os.getenv("BANDIT_OUTCOME", "unknown")
if not report_path.exists():
summary.write_text(
"## Static Security Scan (Bandit, Advisory)\n\n"
f"- Bandit step outcome: **{bandit_outcome}**\n"
"- Report missing: Bandit did not produce `bandit.json`.\n"
)
print("Bandit report missing")
else:
report = json.loads(report_path.read_text())
results = report.get("results", [])
with summary.open("w", encoding="utf-8") as f:
f.write("## Static Security Scan (Bandit, Advisory)\n\n")
f.write(f"- Bandit step outcome: **{bandit_outcome}**\n")
f.write(f"- Findings: **{len(results)}**\n\n")
if results:
f.write("| Severity | File | Test ID | Message |\n")
f.write("|---|---|---|---|\n")
for finding in results[:25]:
sev = finding.get("issue_severity", "UNKNOWN")
path = finding.get("filename", "unknown")
test_id = finding.get("test_id", "UNKNOWN")
text = finding.get("issue_text", "").replace("|", "\\|")
f.write(f"| {sev} | {path} | {test_id} | {text} |\n")
else:
f.write("No Bandit findings detected.\n")
PY
cat bandit-summary.md >> "$GITHUB_STEP_SUMMARY"
- name: Upload Bandit report
if: always()
uses: actions/upload-artifact@v4
with:
name: bandit-report
path: |
bandit.json
bandit-summary.md
retention-days: 14