fix(demo): zet de FSC-beheeromgeving achter de inlogmuur #548
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # De scripts onder .github/scripts/ beslissen wát de rest van de CI doet: wijzigingsfilter.sh | |
| # bepaalt welke jobs draaien, uitrol-poort.sh bepaalt of een run een merge mag dragen, | |
| # merge-guard.sh bewaakt de compose-overlays en demo-grens.sh bewaakt dat het stelsel niet van | |
| # demonstratiecode afhangt, en jdk-handtekening.py bewaakt dat elke setup-java-stap de JDK op | |
| # handtekening controleert. Een fout daarin is stil — een overgeslagen job rapporteert 'skipped' | |
| # en dat telt als succes voor branch protection. Vandaar een eigen, lichte workflow: shellcheck, | |
| # actionlint en de bash-unittests, zonder de docker build van de FSC-harness. | |
| name: CI-scripts | |
| # Op een PR bewust ZONDER pad-filter. Twee redenen. Ten eerste kruiscontroleren de unittests de | |
| # workflow-namen in wijzigingsfilter.sh tegen .github/workflows/ op schijf; met een pad-filter | |
| # vuurde die controle op de verkeerde PR — niet op de PR die een workflow toevoegt, maar op de | |
| # volgende die toevallig een script aanraakt. Ten tweede hoort deze check een required context te | |
| # zijn, en een required check achter een workflow-niveau `paths`-filter wordt bij een | |
| # niet-matchende PR nooit gerapporteerd: die blijft eeuwig 'expected' en blokkeert de merge | |
| # voorgoed. De job kost enkele seconden (linting plus bash-unittests, geen build). | |
| # | |
| # Op een push naar main gelden beide redenen niet: required contexts worden alleen op PR's | |
| # beoordeeld, en de kruiscontrole heeft daar al gevuurd. De push-run blijft als vangnet voor een | |
| # commit die buiten de PR-flow om op main landt; het pad-filter beperkt hem tot de bestanden waar | |
| # dat vangnet over gaat — inclusief de paden die de kruiscontroles van schijf lezen. | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened] | |
| push: | |
| branches: [main] | |
| paths: ['.github/scripts/**', '.claude/hooks/**', '.github/workflows/**', 'docs/architecture/**', '**/pom.xml', '.clusterfuzzlite/base/Dockerfile', 'demo/*.sh', 'demo/*.py', 'demo/environment/**'] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| scripts: | |
| # Expliciete naam, want deze wordt de status-check-context zodra de check als required wordt | |
| # gezet — en de kale job-id `scripts` is daarvoor te generiek. Een standalone workflow krijgt | |
| # geen `<aanroeper-job> / <job>`-voorvoegsel dat hem onderscheidt. | |
| name: ci-scripts | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: actionlint | |
| env: | |
| # Vaste versie plus checksum in plaats van een action van derden: dezelfde | |
| # pin-discipline als de SHA-gepinde actions elders, met één partij minder in de keten. | |
| ACTIONLINT_VERSIE: 1.7.12 | |
| ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 | |
| run: | | |
| set -euo pipefail | |
| curl -fsSL --max-time 60 --retry 3 --retry-connrefused -o /tmp/actionlint.tar.gz \ | |
| "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSIE}/actionlint_${ACTIONLINT_VERSIE}_linux_amd64.tar.gz" | |
| echo "${ACTIONLINT_SHA256} /tmp/actionlint.tar.gz" | sha256sum -c - | |
| tar -xzf /tmp/actionlint.tar.gz -C /tmp actionlint | |
| # actionlint draait shellcheck over elk `run:`-blok, maar schakelt die regel stil uit | |
| # wanneer shellcheck ontbreekt: alleen een `verbose:`-regel, exitcode 0. Een | |
| # runner-image zonder shellcheck zou de stap dus halveren zonder signaal. | |
| command -v shellcheck >/dev/null \ | |
| || { echo "::error::shellcheck ontbreekt op de runner — actionlint zou zijn run-blok-analyse stil uitschakelen."; exit 1; } | |
| # Vangt onder meer een `needs.<job>.result` die verwijst naar een job die niet in | |
| # `needs:` staat, en een `cancelled()` op een plek waar die niet mag staan. | |
| /tmp/actionlint | |
| - name: Elke setup-java verifieert de handtekening van de JDK | |
| # De suite hierboven toetst de guard tegen fixtures; deze stap laat hem los op de | |
| # werkelijke workflows. Los, zodat een falende guard als eigen regel in de log staat en | |
| # niet als één van de twintig meldingen van de unittest-stap. | |
| if: ${{ !cancelled() }} | |
| run: python3 .github/scripts/jdk-handtekening.py .github/workflows | |
| - name: De COPY-lijst van het fuzz-basis-image volgt de reactor | |
| # De suite hieronder toetst deze guard tegen fixtures; deze stap laat hem los op de | |
| # werkelijke root-pom en het werkelijke Dockerfile. Los, zodat een achterlopende COPY-lijst | |
| # als eigen regel in de log staat en niet als één van de twintig meldingen van de | |
| # unittest-stap. Het Dockerfile draagt dezelfde controle, maar die gaat pas af tijdens de | |
| # bouw van het image — en die draait alleen op een push naar main, dus ná de merge. | |
| if: ${{ !cancelled() }} | |
| run: .github/scripts/fuzz-basis-modules.sh | |
| - name: shellcheck + bash-unittests | |
| # Ook draaien als actionlint viel: twee losse signalen zijn in één run meer waard dan één. | |
| if: ${{ !cancelled() }} | |
| run: | | |
| set -euo pipefail | |
| fail=0 | |
| echo "== shellcheck ==" | |
| # `find` in plaats van een glob: een script in een toekomstige submap zou anders | |
| # stilzwijgend ongecontroleerd blijven. -x volgt `source`-directives, zodat een test | |
| # zijn script meegecontroleerd krijgt. | |
| # | |
| # .claude/hooks/ hoort erbij: die scripts draaien op elke machine van het team, en een | |
| # fout erin blokkeert of verstomt een guard zonder dat iemand het merkt. | |
| scripts=$(find .github/scripts .claude/hooks -name '*.sh' | wc -l) | |
| # `xargs -r` draait shellcheck niet bij een lege lijst; zonder deze guard zou die stilte | |
| # dan als geslaagd tellen in plaats van als "niets gemeten". | |
| if [ "$scripts" -eq 0 ]; then | |
| echo "FOUT: geen enkel script onder .github/scripts/ of .claude/hooks/ — deze stap meet niets." | |
| fail=1 | |
| elif ! find .github/scripts .claude/hooks -name '*.sh' -print0 | xargs -0 -r shellcheck -x -S warning; then | |
| fail=1 | |
| fi | |
| echo "== bash-unittests ==" | |
| gedraaid=0 | |
| # Per suite het aantal asserties dat er minimaal uit moet komen. De suite rapporteert dat | |
| # zelf als afsluitende ASSERTIES=-regel; een kale `echo "OK: ..."` telt daardoor niet mee, | |
| # en het verlagen van een verwachting is een zichtbare diff in plaats van stille erosie. | |
| declare -A VERWACHTE_ASSERTIES=( | |
| [.github/scripts/test-wijzigingsfilter.sh]=107 | |
| [.github/scripts/test-uitrol-poort.sh]=86 | |
| [.github/scripts/test-demo-grens.sh]=62 | |
| [.github/scripts/test-cross-domain-preview.sh]=51 | |
| [.github/scripts/test-preview-klaarzetten.sh]=54 | |
| [.github/scripts/test-zad-deployment-bestaat.sh]=29 | |
| [.github/scripts/test-preview-comment.sh]=121 | |
| [.github/scripts/test-jdk-handtekening.sh]=22 | |
| [.github/scripts/test-fuzz-basis-modules.sh]=16 | |
| [.github/scripts/test-fuzz-basis-pin.sh]=74 | |
| [.github/scripts/test-proeftuin-image.sh]=20 | |
| [.github/scripts/test-proeftuin-pin-pr.sh]=128 | |
| [.github/scripts/test-pin-pr-teststubs.sh]=40 | |
| [.github/scripts/test-proeftuin-pin.sh]=139 | |
| ) | |
| # De andere richting: een suite die verdwijnt of buiten het `test-*.sh`-patroon wordt | |
| # hernoemd, laat alleen een verweesde sleutel achter — `find` levert hem niet meer, de | |
| # `gedraaid`-guard hieronder telt de overige suites en de stap wordt groen. Voor | |
| # demo-grens.sh is dat extra duur: die controle heeft geen andere aanroep in de keten, | |
| # dus één hernoeming haalt de architectuurgrens er geruisloos uit. | |
| for t in "${!VERWACHTE_ASSERTIES[@]}"; do | |
| if [ ! -f "$t" ]; then | |
| echo "FOUT: $t staat in VERWACHTE_ASSERTIES maar bestaat niet meer." | |
| fail=1 | |
| fi | |
| done | |
| while IFS= read -r t; do | |
| gedraaid=$((gedraaid + 1)) | |
| echo "-- $t" | |
| if ! uitvoer=$(bash "$t" 2>&1); then | |
| printf '%s\n' "$uitvoer" | |
| fail=1 | |
| continue | |
| fi | |
| printf '%s\n' "$uitvoer" | |
| gemeten=$(sed -n 's/^ASSERTIES=//p' <<<"$uitvoer" | tail -1) | |
| verwacht=${VERWACHTE_ASSERTIES[$t]:-} | |
| if [ -z "$verwacht" ]; then | |
| echo "FOUT: $t staat niet in VERWACHTE_ASSERTIES — voeg het verwachte aantal toe." | |
| fail=1 | |
| elif [ -z "$gemeten" ]; then | |
| echo "FOUT: $t rapporteert geen ASSERTIES=-regel; het aantal is niet te bewaken." | |
| fail=1 | |
| elif ! [[ "$gemeten" =~ ^[0-9]+$ ]]; then | |
| # Zonder deze tak valt de vergelijking hieronder met 'integer expression expected' | |
| # om, grijpt `set -e` niet in op een elif-conditie, en wordt de stap groen. | |
| echo "FOUT: $t rapporteert ASSERTIES=$gemeten; dat is geen aantal." | |
| fail=1 | |
| elif [ "$gemeten" -lt "$verwacht" ]; then | |
| echo "FOUT: $t leverde $gemeten asserties, verwacht minstens $verwacht." | |
| fail=1 | |
| else | |
| # Het aantal is zelf-gerapporteerd, dus een uitgeholde suite die alleen nog de | |
| # ASSERTIES-regel print zou de drempel halen zonder iets te toetsen. Tel daarom de | |
| # geslaagde asserties in de uitvoer mee: die moeten er minstens evenveel zijn. | |
| geteld=$(grep -c '^OK: ' <<<"$uitvoer" || true) | |
| if [ "$geteld" -lt "$gemeten" ]; then | |
| echo "FOUT: $t meldt ASSERTIES=$gemeten maar print $geteld geslaagde asserties; de suite toetst minder dan hij rapporteert." | |
| fail=1 | |
| fi | |
| fi | |
| done < <(find .github/scripts -name 'test-*.sh' | sort) | |
| # Zonder deze guard meldt de stap groen zodra er geen `test-*.sh` meer onder | |
| # .github/scripts/ staat — verwijderd, of buiten dat pad of die naamvorm gebracht. | |
| # | |
| if [ "$gedraaid" -eq 0 ]; then | |
| echo "FOUT: geen enkele test-*.sh gevonden — deze stap meet niets." | |
| fail=1 | |
| fi | |
| # En een benoemde set, geen aantal: een suite die mét zijn VERWACHTE_ASSERTIES-sleutel | |
| # verdwijnt laat de guards hierboven tevreden, en een vervangende stub die één `OK:` | |
| # print haalt elke telling. Deze drie dragen elk een controle die nergens anders in de | |
| # keten wordt aangeroepen — demo-grens.sh is de architectuurgrens zelf. | |
| for verplicht in .github/scripts/test-wijzigingsfilter.sh \ | |
| .github/scripts/test-uitrol-poort.sh \ | |
| .github/scripts/test-demo-grens.sh \ | |
| .github/scripts/test-jdk-handtekening.sh; do | |
| if [ ! -f "$verplicht" ]; then | |
| echo "FOUT: $verplicht ontbreekt; die controle draait nergens meer in de keten." | |
| fail=1 | |
| fi | |
| done | |
| if [ "$fail" -ne 0 ]; then | |
| echo "::error::shellcheck of een bash-unittest faalde. Zie de log hierboven." | |
| fi | |
| exit "$fail" |