Put the security scanners back on the default branch

The lean cut removed scan-darkwing-portable.yml and scan-darkwing-pr.yml from
main on the reasoning that they name an internal scanner and so are
site-specific tooling rather than product. That reasoning was wrong, and it
showed up as scan-darkwing.cmd failing with

    HTTP 422: Workflow does not have 'workflow_dispatch' trigger

because the command dispatches against the DEFAULT branch and the file was no
longer there.

A CI workflow is repository infrastructure, not shipped product. It never
reaches a receiving site, so "does a site need this file" is the wrong question
to ask about it - and main is the branch a site pulls FROM, which makes it the
last place that should lose its scanning. Removing them turned security scanning
off on the default branch silently: nothing failed, no test covered it, and the
only signal was a dispatch error days later.

Both restored unchanged. scan-darkwing-portable.yml carries the
workflow_dispatch trigger the command calls; scan-darkwing-pr.yml runs on
pull_request. Neither references anything the lean cut removed.

Checked the rest of .github/ for the same mistake: the only other difference
from the site line is GE-ENFORCE-COLLECTOR-FIX.html, which is correctly absent
because the geenforce plugin is not bundled here.
This commit is contained in:
cproudlock
2026-09-19 12:13:06 -04:00
parent ecdbe53ef6
commit bf6b353b52
2 changed files with 94 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
# Darkwing vulnerability scan, manual dispatch.
#
# Copied verbatim from the ge-aero/darkwing README so it stays byte-identical
# to the sanctioned integration. Do not edit this file to add triggers or
# gating - see scan-darkwing-pr.yml for that, which is ours to change.
#
# The file must sit on the default branch before a scan can run on ANY branch.
name: Scan (darkwing, portable)
on:
workflow_dispatch:
inputs:
target_ref:
description: Ref, branch, or sha of this repo to scan
required: false
type: string
default: main
permissions:
contents: read # checkout this repo via the ambient GITHUB_TOKEN
security-events: write # SARIF upload to the Security tab
actions: read # required by upload-sarif on private/internal repos
jobs:
scan:
runs-on: darkwing-scan
steps:
# @v1 is a moving tag pointing to the latest release that is compatible
# with this workflow file.
- uses: ge-aero/darkwing@v1
with:
target_ref: ${{ inputs.target_ref || 'main' }}

62
.github/workflows/scan-darkwing-pr.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
# Darkwing scan on pull requests, so the "check against darkwing" is a check
# and not a thing somebody remembers to click.
#
# WHY THIS IS SEPARATE from scan-darkwing-portable.yml: that file is copied
# byte-for-byte from the ge-aero/darkwing README and is left alone so it keeps
# matching the sanctioned integration. Everything below is ours.
#
# THE TRAP THIS AVOIDS. The README workflow resolves its scan target as
# `inputs.target_ref || 'main'`. On a pull_request event there are no inputs,
# so that expression falls through to 'main' and the job scans the default
# branch instead of the code under review - a green Darkwing check that never
# looked at the change. Resolve the head SHA explicitly.
#
# Darkwing exits 0 whatever it finds (its own FAQ: "Does a finding fail my
# build? No."), so a passing job means the scan RAN, not that the code is
# clean. Findings land in Security -> Code scanning. Turning a finding into a
# hard failure means reading findings.sarif ourselves; the commented step at
# the bottom is the shape of that, deliberately left off until we have seen the
# false-positive rate on this repo.
name: Scan (darkwing, PR)
on:
pull_request:
permissions:
contents: read
security-events: write
actions: read
# One scan per PR. A new push supersedes the old one rather than queueing a
# second Bedrock spend against a diff nobody is reviewing any more.
concurrency:
group: darkwing-pr-${{ github.ref }}
cancel-in-progress: true
jobs:
scan:
runs-on: darkwing-scan
steps:
- uses: ge-aero/darkwing@v1
with:
# The PR's head, NOT the default branch. See the note above.
target_ref: ${{ github.event.pull_request.head.sha }}
# Gating, once the signal is trusted. Darkwing writes findings.sarif into
# its work dir and attaches it as the `findings` artifact; this reads the
# severities out and fails on error-level results only.
#
# - name: Fail on error-level findings
# run: |
# python - <<'PY'
# import json, pathlib, sys
# sarif = pathlib.Path('darkwing/findings.sarif')
# if not sarif.is_file():
# sys.exit('no findings.sarif: the scan did not produce results')
# doc = json.loads(sarif.read_text())
# bad = [r for run in doc.get('runs', [])
# for r in run.get('results', [])
# if r.get('level') == 'error']
# if bad:
# sys.exit(f'{len(bad)} error-level finding(s); see the Security tab')
# PY