|
1 | | -# Reusable: lint + security-static + codeql-gate |
| 1 | +# Reusable: lint only (cppcheck + clang-format). |
| 2 | +# Security-static and CodeQL gate are separate — see _security.yml. |
2 | 3 | name: Lint & Security |
3 | 4 |
|
4 | 5 | on: |
|
43 | 44 |
|
44 | 45 | - name: Lint (cppcheck + clang-format, no clang-tidy — enforced locally) |
45 | 46 | run: scripts/lint.sh --ci CLANG_FORMAT=clang-format-20 |
46 | | - |
47 | | - security-static: |
48 | | - runs-on: ubuntu-latest |
49 | | - timeout-minutes: 5 |
50 | | - steps: |
51 | | - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 |
52 | | - - name: "Layer 1: Static allow-list audit" |
53 | | - run: scripts/security-audit.sh |
54 | | - - name: "Layer 6: UI security audit" |
55 | | - run: scripts/security-ui.sh |
56 | | - - name: "Layer 8: Vendored dependency integrity" |
57 | | - run: scripts/security-vendored.sh |
58 | | - |
59 | | - codeql-gate: |
60 | | - runs-on: ubuntu-latest |
61 | | - timeout-minutes: 50 |
62 | | - steps: |
63 | | - - name: Wait for CodeQL on current commit (max 45 min) |
64 | | - env: |
65 | | - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
66 | | - run: | |
67 | | - CURRENT_SHA="${{ github.sha }}" |
68 | | - echo "Waiting for CodeQL to complete on $CURRENT_SHA..." |
69 | | - for attempt in $(seq 1 90); do |
70 | | - LATEST=$(gh api repos/${{ github.repository }}/actions/workflows/codeql.yml/runs?per_page=5 \ |
71 | | - --jq '.workflow_runs[] | select(.head_sha == "'"$CURRENT_SHA"'") | "\(.conclusion) \(.status)"' 2>/dev/null | head -1 || echo "") |
72 | | - if [ -z "$LATEST" ]; then |
73 | | - echo " $attempt/90: no run yet..."; sleep 30; continue |
74 | | - fi |
75 | | - CONCLUSION=$(echo "$LATEST" | cut -d' ' -f1) |
76 | | - STATUS=$(echo "$LATEST" | cut -d' ' -f2) |
77 | | - if [ "$STATUS" = "completed" ] && [ "$CONCLUSION" = "success" ]; then |
78 | | - echo "=== CodeQL passed ==="; exit 0 |
79 | | - elif [ "$STATUS" = "completed" ]; then |
80 | | - echo "BLOCKED: CodeQL $CONCLUSION"; exit 1 |
81 | | - fi |
82 | | - echo " $attempt/90: $STATUS..."; sleep 30 |
83 | | - done |
84 | | - echo "BLOCKED: CodeQL timeout"; exit 1 |
85 | | -
|
86 | | - - name: Check for open code scanning alerts |
87 | | - env: |
88 | | - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
89 | | - run: | |
90 | | - echo "Waiting 60s for alert API to settle..." |
91 | | - sleep 60 |
92 | | - ALERTS=$(gh api 'repos/${{ github.repository }}/code-scanning/alerts?state=open' --jq 'length' 2>/dev/null || echo "0") |
93 | | - sleep 15 |
94 | | - ALERTS2=$(gh api 'repos/${{ github.repository }}/code-scanning/alerts?state=open' --jq 'length' 2>/dev/null || echo "0") |
95 | | - [ "$ALERTS" -lt "$ALERTS2" ] && ALERTS=$ALERTS2 |
96 | | - if [ "$ALERTS" -gt 0 ]; then |
97 | | - echo "BLOCKED: $ALERTS open alert(s)" |
98 | | - gh api 'repos/${{ github.repository }}/code-scanning/alerts?state=open' \ |
99 | | - --jq '.[] | " #\(.number) [\(.rule.security_severity_level // .rule.severity)] \(.rule.id) — \(.most_recent_instance.location.path):\(.most_recent_instance.location.start_line)"' 2>/dev/null || true |
100 | | - exit 1 |
101 | | - fi |
102 | | - echo "=== CodeQL gate passed (0 alerts) ===" |
0 commit comments