From d290730e49d5a7dda3c4a4bb912e19e9a5092148 Mon Sep 17 00:00:00 2001 From: BryanFRD Date: Sun, 25 Oct 2026 09:38:13 +0100 Subject: [PATCH] fix(ci): move the remaining caller inputs out of run blocks --- .../actions/sast-external-issues/action.yml | 7 +++- .github/actions/setup-sccache/action.yml | 14 ++++--- .github/workflows/reusable-ci-astro.yml | 28 +++++++++---- .github/workflows/reusable-ci-go.yml | 29 ++++++++++---- .github/workflows/reusable-ci-node.yml | 40 ++++++++++++++----- .github/workflows/reusable-ci-rust.yml | 12 ++++-- .github/workflows/reusable-docker-build.yml | 12 ++++-- .github/workflows/reusable-release-rust.yml | 14 ++++--- .github/workflows/reusable-security-scan.yml | 13 ++++-- 9 files changed, 121 insertions(+), 48 deletions(-) diff --git a/.github/actions/sast-external-issues/action.yml b/.github/actions/sast-external-issues/action.yml index 92fe580..0d17757 100644 --- a/.github/actions/sast-external-issues/action.yml +++ b/.github/actions/sast-external-issues/action.yml @@ -43,12 +43,15 @@ runs: steps: - name: Install OpenGrep + gitleaks shell: bash + env: + OPENGREP_VERSION: ${{ inputs.opengrep-version }} + GITLEAKS_VERSION: ${{ inputs.gitleaks-version }} run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/sast-bin" - curl -fsSL "https://github.com/opengrep/opengrep/releases/download/v${{ inputs.opengrep-version }}/opengrep_manylinux_x86" \ + curl -fsSL "https://github.com/opengrep/opengrep/releases/download/v${OPENGREP_VERSION}/opengrep_manylinux_x86" \ -o "$RUNNER_TEMP/sast-bin/opengrep" - curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/v${{ inputs.gitleaks-version }}/gitleaks_${{ inputs.gitleaks-version }}_linux_x64.tar.gz" \ + curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \ | tar -xz -C "$RUNNER_TEMP/sast-bin" gitleaks chmod +x "$RUNNER_TEMP/sast-bin/opengrep" "$RUNNER_TEMP/sast-bin/gitleaks" echo "$RUNNER_TEMP/sast-bin" >> "$GITHUB_PATH" diff --git a/.github/actions/setup-sccache/action.yml b/.github/actions/setup-sccache/action.yml index df3f9a8..a12e0ba 100644 --- a/.github/actions/setup-sccache/action.yml +++ b/.github/actions/setup-sccache/action.yml @@ -61,6 +61,10 @@ runs: env: SCCACHE_S3_KEY: ${{ inputs.s3-key }} SCCACHE_S3_SECRET: ${{ inputs.s3-secret }} + INPUT_BUCKET: ${{ inputs.bucket }} + INPUT_ENDPOINT: ${{ inputs.endpoint }} + INPUT_REGION: ${{ inputs.region }} + INPUT_KEY_PREFIX: ${{ inputs.key-prefix }} run: | set -euo pipefail # NOTE: RUSTC_WRAPPER is deliberately NOT set here. It is set only by the @@ -72,16 +76,16 @@ runs: # exclusive — incremental artifacts are never cached, so leaving it on # just wastes the wrapper. Off is also the CI-release default. echo "CARGO_INCREMENTAL=0" - echo "SCCACHE_BUCKET=${{ inputs.bucket }}" - echo "SCCACHE_ENDPOINT=${{ inputs.endpoint }}" - echo "SCCACHE_REGION=${{ inputs.region }}" + echo "SCCACHE_BUCKET=${INPUT_BUCKET}" + echo "SCCACHE_ENDPOINT=${INPUT_ENDPOINT}" + echo "SCCACHE_REGION=${INPUT_REGION}" # garage on :3900 is plain HTTP inside the cluster. echo "SCCACHE_S3_USE_SSL=false" # Keep the server alive for the whole job so --show-stats reflects the # full run (default idle shutdown would reset the counters mid-job). echo "SCCACHE_IDLE_TIMEOUT=0" - if [ -n "${{ inputs.key-prefix }}" ]; then - echo "SCCACHE_S3_KEY_PREFIX=${{ inputs.key-prefix }}" + if [ -n "$INPUT_KEY_PREFIX" ]; then + echo "SCCACHE_S3_KEY_PREFIX=${INPUT_KEY_PREFIX}" fi # sccache reads S3 creds from the standard AWS env vars. echo "AWS_ACCESS_KEY_ID=${SCCACHE_S3_KEY}" diff --git a/.github/workflows/reusable-ci-astro.yml b/.github/workflows/reusable-ci-astro.yml index f57e195..44694fe 100644 --- a/.github/workflows/reusable-ci-astro.yml +++ b/.github/workflows/reusable-ci-astro.yml @@ -135,16 +135,23 @@ jobs: - name: Install dependencies env: NODE_AUTH_TOKEN: ${{ secrets.FERRLABS_PACKAGES_READ || secrets.FERRFLOW_PACKAGES_READ || secrets.GITHUB_TOKEN }} - run: pnpm install ${{ inputs.install-args }} + INSTALL_ARGS: ${{ inputs.install-args }} + run: pnpm install $INSTALL_ARGS - name: Astro check if: inputs.enable-astro-check - run: pnpm exec astro check ${{ inputs.astro-check-args }} + env: + ASTRO_CHECK_ARGS: ${{ inputs.astro-check-args }} + run: pnpm exec astro check $ASTRO_CHECK_ARGS - name: Lint if: inputs.enable-lint - run: pnpm run ${{ inputs.lint-script }} + env: + LINT_SCRIPT: ${{ inputs.lint-script }} + run: pnpm run "$LINT_SCRIPT" - name: Build if: inputs.enable-build - run: pnpm run ${{ inputs.build-script }} + env: + BUILD_SCRIPT: ${{ inputs.build-script }} + run: pnpm run "$BUILD_SCRIPT" - name: Upload dist (for downstream Lighthouse) if: inputs.enable-build && inputs.enable-lighthouse && (github.event_name == 'pull_request' || !inputs.lighthouse-only-pr) uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 @@ -175,9 +182,12 @@ jobs: - name: Install dependencies env: NODE_AUTH_TOKEN: ${{ secrets.FERRLABS_PACKAGES_READ || secrets.FERRFLOW_PACKAGES_READ || secrets.GITHUB_TOKEN }} - run: pnpm install ${{ inputs.install-args }} + INSTALL_ARGS: ${{ inputs.install-args }} + run: pnpm install $INSTALL_ARGS - name: Check i18n parity - run: pnpm run ${{ inputs.i18n-script }} + env: + I18N_SCRIPT: ${{ inputs.i18n-script }} + run: pnpm run "$I18N_SCRIPT" continue-on-error: true lighthouse: @@ -197,9 +207,11 @@ jobs: - name: Run Lighthouse env: LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} + LIGHTHOUSE_VERSION: ${{ inputs.lighthouse-version }} + DIST_PATH: ${{ inputs.dist-path }} run: | - npm install -g @lhci/cli@${{ inputs.lighthouse-version }} - lhci autorun --collect.staticDistDir=${{ inputs.dist-path }} || true + npm install -g "@lhci/cli@${LIGHTHOUSE_VERSION}" + lhci autorun --collect.staticDistDir="$DIST_PATH" || true sonarqube: name: SonarQube diff --git a/.github/workflows/reusable-ci-go.yml b/.github/workflows/reusable-ci-go.yml index 7f318a5..9d52a68 100644 --- a/.github/workflows/reusable-ci-go.yml +++ b/.github/workflows/reusable-ci-go.yml @@ -107,8 +107,10 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - id: check + env: + GO_VERSION_FILE: ${{ inputs.go-version-file }} run: | - if [ -f "${{ inputs.go-version-file }}" ]; then + if [ -f "$GO_VERSION_FILE" ]; then echo "has_go=true" >> "$GITHUB_OUTPUT" else echo "has_go=false" >> "$GITHUB_OUTPUT" @@ -145,7 +147,9 @@ jobs: fi - name: go vet if: inputs.enable-vet - run: go vet ${{ inputs.test-paths }} + env: + TEST_PATHS: ${{ inputs.test-paths }} + run: go vet $TEST_PATHS - if: inputs.enable-lint uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9 with: @@ -173,11 +177,15 @@ jobs: go-version-file: ${{ inputs.go-version == '' && format('{0}/{1}', inputs.working-directory, inputs.go-version-file) || '' }} cache: true - name: Test + env: + ENABLE_RACE: ${{ inputs.enable-race }} + ENABLE_COVERAGE: ${{ inputs.enable-coverage }} + TEST_PATHS: ${{ inputs.test-paths }} run: | ARGS="" - if [ "${{ inputs.enable-race }}" = "true" ]; then ARGS="$ARGS -race"; fi - if [ "${{ inputs.enable-coverage }}" = "true" ]; then ARGS="$ARGS -coverprofile=coverage.out"; fi - go test $ARGS ${{ inputs.test-paths }} + if [ "$ENABLE_RACE" = "true" ]; then ARGS="$ARGS -race"; fi + if [ "$ENABLE_COVERAGE" = "true" ]; then ARGS="$ARGS -coverprofile=coverage.out"; fi + go test $ARGS $TEST_PATHS - if: inputs.enable-coverage uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 with: @@ -230,13 +238,16 @@ jobs: go-version-file: ${{ inputs.go-version == '' && format('{0}/{1}', inputs.working-directory, inputs.go-version-file) || '' }} cache: true - name: govulncheck + env: + TEST_PATHS: ${{ inputs.test-paths }} + FAIL_ON_VULNCHECK: ${{ inputs.fail-on-vulncheck }} run: | go install golang.org/x/vuln/cmd/govulncheck@latest set +e - govulncheck ${{ inputs.test-paths }} + govulncheck $TEST_PATHS EXIT=$? set -e - if [ "${{ inputs.fail-on-vulncheck }}" = "true" ]; then + if [ "$FAIL_ON_VULNCHECK" = "true" ]; then exit $EXIT fi if [ "$EXIT" != "0" ]; then @@ -266,7 +277,9 @@ jobs: go-version-file: ${{ inputs.go-version == '' && format('{0}/{1}', inputs.working-directory, inputs.go-version-file) || '' }} cache: true - name: Build - run: go build -o bin/ ${{ inputs.build-paths }} + env: + BUILD_PATHS: ${{ inputs.build-paths }} + run: go build -o bin/ $BUILD_PATHS sonarqube: name: SonarQube diff --git a/.github/workflows/reusable-ci-node.yml b/.github/workflows/reusable-ci-node.yml index 8b02546..1c0e655 100644 --- a/.github/workflows/reusable-ci-node.yml +++ b/.github/workflows/reusable-ci-node.yml @@ -175,16 +175,27 @@ jobs: - name: Install dependencies env: NODE_AUTH_TOKEN: ${{ secrets.FERRLABS_PACKAGES_READ || secrets.FERRFLOW_PACKAGES_READ || secrets.GITHUB_TOKEN }} - run: ${{ inputs.package-manager }} install ${{ inputs.install-args }} + PKG_MANAGER: ${{ inputs.package-manager }} + INSTALL_ARGS: ${{ inputs.install-args }} + run: $PKG_MANAGER install $INSTALL_ARGS - name: Typecheck if: inputs.enable-typecheck - run: ${{ inputs.script-runner }} ${{ inputs.typecheck-script }} + env: + SCRIPT_RUNNER: ${{ inputs.script-runner }} + TYPECHECK_SCRIPT: ${{ inputs.typecheck-script }} + run: $SCRIPT_RUNNER $TYPECHECK_SCRIPT - name: Lint if: inputs.enable-lint - run: ${{ inputs.script-runner }} ${{ inputs.lint-script }} + env: + SCRIPT_RUNNER: ${{ inputs.script-runner }} + LINT_SCRIPT: ${{ inputs.lint-script }} + run: $SCRIPT_RUNNER $LINT_SCRIPT - name: Test if: inputs.enable-test - run: ${{ inputs.script-runner }} ${{ inputs.test-script }} + env: + SCRIPT_RUNNER: ${{ inputs.script-runner }} + TEST_SCRIPT: ${{ inputs.test-script }} + run: $SCRIPT_RUNNER $TEST_SCRIPT - name: Upload coverage if: inputs.enable-test && inputs.coverage-upload uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 @@ -209,6 +220,7 @@ jobs: env: BASE: ${{ inputs.working-directory }} LCOV: ${{ inputs.sonar-lcov-path }} + COVERAGE_NAME: ${{ inputs.coverage-upload-as }} run: | mkdir -p "${{ runner.temp }}/sonarcov" # vitest emits SF: paths relative to the package dir; prefix the component @@ -222,7 +234,7 @@ jobs: print "SF:" p; next } { print } - ' "$LCOV" > "${{ runner.temp }}/sonarcov/${{ inputs.coverage-upload-as }}.lcov" + ' "$LCOV" > "${{ runner.temp }}/sonarcov/${COVERAGE_NAME}.lcov" - name: Upload rebased lcov if: inputs.coverage-upload-as != '' && inputs.enable-test # Side output: losing the upload must not fail the gate that produced it. @@ -235,7 +247,10 @@ jobs: retention-days: 1 - name: Build if: inputs.enable-build - run: ${{ inputs.script-runner }} ${{ inputs.build-script }} + env: + SCRIPT_RUNNER: ${{ inputs.script-runner }} + BUILD_SCRIPT: ${{ inputs.build-script }} + run: $SCRIPT_RUNNER $BUILD_SCRIPT quality: name: Quality (knip, madge, audit) @@ -260,14 +275,21 @@ jobs: - name: Install dependencies env: NODE_AUTH_TOKEN: ${{ secrets.FERRLABS_PACKAGES_READ || secrets.FERRFLOW_PACKAGES_READ || secrets.GITHUB_TOKEN }} - run: ${{ inputs.package-manager }} install ${{ inputs.install-args }} + PKG_MANAGER: ${{ inputs.package-manager }} + INSTALL_ARGS: ${{ inputs.install-args }} + run: $PKG_MANAGER install $INSTALL_ARGS - name: knip if: inputs.enable-knip - run: ${{ inputs.package-manager }} dlx knip --reporter compact + env: + PKG_MANAGER: ${{ inputs.package-manager }} + run: $PKG_MANAGER dlx knip --reporter compact continue-on-error: true - name: madge (circular imports) if: inputs.enable-madge - run: ${{ inputs.package-manager }} dlx madge --circular --extensions ts,tsx,js,jsx ${{ inputs.madge-paths }} + env: + PKG_MANAGER: ${{ inputs.package-manager }} + MADGE_PATHS: ${{ inputs.madge-paths }} + run: $PKG_MANAGER dlx madge --circular --extensions ts,tsx,js,jsx $MADGE_PATHS continue-on-error: true - name: audit if: inputs.enable-audit diff --git a/.github/workflows/reusable-ci-rust.yml b/.github/workflows/reusable-ci-rust.yml index a874f13..04c1607 100644 --- a/.github/workflows/reusable-ci-rust.yml +++ b/.github/workflows/reusable-ci-rust.yml @@ -502,10 +502,13 @@ jobs: restore-keys: advisory-db- - name: cargo audit (RustSec advisories) if: inputs.enable-audit + env: + AUDIT_IGNORE: ${{ inputs.audit-ignore }} + FAIL_ON_AUDIT: ${{ inputs.fail-on-audit }} run: | IGNORES="" - if [ -n "${{ inputs.audit-ignore }}" ]; then - for id in $(echo "${{ inputs.audit-ignore }}" | tr ',' ' '); do + if [ -n "$AUDIT_IGNORE" ]; then + for id in $(echo "$AUDIT_IGNORE" | tr ',' ' '); do IGNORES="$IGNORES --ignore $id" done fi @@ -513,7 +516,7 @@ jobs: cargo audit --deny warnings $IGNORES EXIT=$? set -e - if [ "${{ inputs.fail-on-audit }}" = "true" ]; then + if [ "$FAIL_ON_AUDIT" = "true" ]; then exit $EXIT fi if [ "$EXIT" != "0" ]; then @@ -671,6 +674,7 @@ jobs: if: inputs.coverage-upload-as != '' && inputs.coverage-tool == 'llvm-cov' env: BASE: ${{ inputs.working-directory }} + COVERAGE_NAME: ${{ inputs.coverage-upload-as }} run: | mkdir -p "${{ runner.temp }}/sonarcov" # llvm-cov emits absolute SF: paths; strip $GITHUB_WORKSPACE to make them @@ -684,7 +688,7 @@ jobs: print "SF:" p; next } { print } - ' lcov.info > "${{ runner.temp }}/sonarcov/${{ inputs.coverage-upload-as }}.lcov" + ' lcov.info > "${{ runner.temp }}/sonarcov/${COVERAGE_NAME}.lcov" - name: Upload rebased lcov if: inputs.coverage-upload-as != '' && inputs.coverage-tool == 'llvm-cov' # Side output: losing the upload must not fail the gate that produced it. diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml index 670b019..8718093 100644 --- a/.github/workflows/reusable-docker-build.yml +++ b/.github/workflows/reusable-docker-build.yml @@ -161,6 +161,9 @@ jobs: with: ref: ${{ inputs.ref }} - name: Lint Dockerfile (hadolint) + env: + CONTEXT: ${{ inputs.context }} + DOCKERFILE: ${{ inputs.dockerfile }} run: | curl -fsSL https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 \ -o "${RUNNER_TEMP}/hadolint" @@ -170,7 +173,7 @@ jobs: # pins break the build. Every other warning still fails the gate. "${RUNNER_TEMP}/hadolint" --failure-threshold warning \ --ignore DL3008 --ignore DL3018 \ - "${{ inputs.context }}/${{ inputs.dockerfile }}" + "${CONTEXT}/${DOCKERFILE}" build: name: Build & push @@ -191,7 +194,8 @@ jobs: if: startsWith(inputs.image-name, 'ghcr.io/') env: GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: buildah login -u "${{ github.actor }}" --password-stdin ghcr.io <<< "$GHCR_TOKEN" + GHCR_USER: ${{ github.actor }} + run: buildah login -u "$GHCR_USER" --password-stdin ghcr.io <<< "$GHCR_TOKEN" # The Actions cache endpoint and token exist only inside a step's # environment. Exporting them here is what lets the build reach the cache; # they are handed to buildah as build secrets, never as build-args, so @@ -536,9 +540,11 @@ jobs: - name: Sign image (keyless) env: COSIGN_EXPERIMENTAL: '1' + IMAGE_NAME: ${{ inputs.image-name }} + DIGEST: ${{ needs.build.outputs.digest }} run: | cosign sign --yes \ - "${{ inputs.image-name }}@${{ needs.build.outputs.digest }}" + "${IMAGE_NAME}@${DIGEST}" - name: Attest build provenance # Best-effort: GitHub artifact attestations are an org-plan feature # ("Feature not available for the … organization" otherwise). The diff --git a/.github/workflows/reusable-release-rust.yml b/.github/workflows/reusable-release-rust.yml index a5b144e..eb6eec5 100644 --- a/.github/workflows/reusable-release-rust.yml +++ b/.github/workflows/reusable-release-rust.yml @@ -98,15 +98,19 @@ jobs: run: cargo build --release --target ${{ matrix.target }} - name: Package (Unix) if: matrix.os != 'windows-latest' + env: + BIN_NAME: ${{ inputs.bin-name }} run: | - tar -czf ${{ inputs.bin-name }}-${{ matrix.arch_label }}.tar.gz \ - -C target/${{ matrix.target }}/release ${{ inputs.bin-name }}${{ matrix.ext }} + tar -czf "${BIN_NAME}-${{ matrix.arch_label }}.tar.gz" \ + -C "target/${{ matrix.target }}/release" "${BIN_NAME}${{ matrix.ext }}" - name: Package (Windows) if: matrix.os == 'windows-latest' + env: + BIN_NAME: ${{ inputs.bin-name }} run: | Compress-Archive ` - -Path target/${{ matrix.target }}/release/${{ inputs.bin-name }}${{ matrix.ext }} ` - -DestinationPath ${{ inputs.bin-name }}-${{ matrix.arch_label }}.zip + -Path "target/${{ matrix.target }}/release/${env:BIN_NAME}${{ matrix.ext }}" ` + -DestinationPath "${env:BIN_NAME}-${{ matrix.arch_label }}.zip" - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: ${{ inputs.bin-name }}-${{ matrix.arch_label }} @@ -129,8 +133,8 @@ jobs: - name: Upload to release env: GH_TOKEN: ${{ secrets.FERRFLOW_TOKEN || secrets.GITHUB_TOKEN }} + TAG: ${{ github.ref_name }} run: | - TAG="${{ github.ref_name }}" for file in artifacts/*; do gh release upload "$TAG" "$file" --clobber done diff --git a/.github/workflows/reusable-security-scan.yml b/.github/workflows/reusable-security-scan.yml index 7356b8e..7f5690a 100644 --- a/.github/workflows/reusable-security-scan.yml +++ b/.github/workflows/reusable-security-scan.yml @@ -184,14 +184,17 @@ jobs: echo '{"runs":[{"tool":{"driver":{"name":"osv-scanner","informationUri":"https://osv.dev"}},"results":[]}],"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0"}' > osv-results.sarif - name: Run osv-scanner if: steps.detect.outputs.has_go == 'false' + env: + OSV_SCAN_ARGS: ${{ inputs.osv-scan-args }} + FAIL_ON_CVE: ${{ inputs.fail-on-cve }} run: | set +e osv-scanner scan source \ --output=osv-results.sarif --format=sarif \ - ${{ inputs.osv-scan-args }} + $OSV_SCAN_ARGS EXIT=$? set -e - if [ "${{ inputs.fail-on-cve }}" = "true" ]; then + if [ "$FAIL_ON_CVE" = "true" ]; then exit $EXIT fi - name: Upload SARIF @@ -257,6 +260,7 @@ jobs: - name: Run OpenGrep env: FERRLABS_RULES: ${{ steps.ferrlabs-rules.outputs.path }} + RULES_PATH: ${{ steps.rules.outputs.path }} run: | set +e EXTRA=() @@ -266,7 +270,7 @@ jobs: opengrep scan \ --sarif-output=opengrep.sarif \ --error \ - -f "${{ steps.rules.outputs.path }}" \ + -f "$RULES_PATH" \ "${EXTRA[@]}" \ . EXIT=$? @@ -397,9 +401,10 @@ jobs: if: steps.guard.outputs.run == 'true' env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + SNYK_TEST_ARGS: ${{ inputs.snyk-test-args }} run: | set +e - OUT=$(snyk test ${{ inputs.snyk-test-args }} --sarif-file-output=snyk.sarif 2>&1) + OUT=$(snyk test $SNYK_TEST_ARGS --sarif-file-output=snyk.sarif 2>&1) EXIT=$? set -e echo "$OUT"