Skip to content

build(deps): Bump the gh-actions group with 2 updates #271

build(deps): Bump the gh-actions group with 2 updates

build(deps): Bump the gh-actions group with 2 updates #271

Workflow file for this run

name: CI
on:
# Manual on-demand runs (e.g. to re-trigger the browser-SDK SonarQube scan
# against a chosen ref without pushing a commit): gh workflow run ci.yml --ref main
workflow_dispatch:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up JDK 21
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
with:
java-version: '21'
distribution: 'temurin'
# Verify gradle-wrapper.jar matches a known-good Gradle release checksum before it
# is executed — guards against a tampered wrapper jar (a classic build-time backdoor).
- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
- name: Set up Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
# The persistence integration suites self-skip when PKAUTH_SKIP_TESTCONTAINERS=1. The CI
# gate must exercise them against real Postgres/DynamoDB Local, so fail loudly if that
# escape hatch leaks into the gating pipeline (otherwise the build can go green with zero
# persistence and concurrency coverage).
- name: Guard against skipped integration tests
run: |
if [ "${PKAUTH_SKIP_TESTCONTAINERS:-}" = "1" ]; then
echo "PKAUTH_SKIP_TESTCONTAINERS=1 must not be set in the CI gate — it would silently skip all persistence integration tests." >&2
exit 1
fi
- name: Build and test
run: ./gradlew clean build test --stacktrace
- name: Upload JaCoCo reports
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: jacoco-reports
path: '**/build/reports/jacoco/**'
if-no-files-found: ignore
# Run mutation tests and submit results to the Stryker Dashboard (stryker-mutator.io),
# which tracks mutation score over time with a badge. Requires STRYKER_DASHBOARD_TOKEN
# set as a repo secret.
browser-mutation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '20'
- name: Install dependencies
run: npm ci --ignore-scripts
working-directory: clients/passkeys-browser
- name: Run tests with coverage
run: npx vitest run --coverage
working-directory: clients/passkeys-browser
- name: SonarQube scan
# JavaScript/browser-SDK static analysis only. SonarQube was dropped for the JVM modules
# (ADR 0018, native JaCoCo gates) but retained here for the TypeScript SDK.
# Needs SONAR_TOKEN, which GitHub withholds from fork PRs AND from Dependabot-triggered
# runs — skip in both cases so the scan doesn't hard-fail without a token. Manual
# (workflow_dispatch) and push runs always have the secret available.
if: github.actor != 'dependabot[bot]' && (github.event_name == 'workflow_dispatch' || github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository)
uses: sonarsource/sonarqube-scan-action@22918119ff8e1ca75a623e15c8296b6ea4fbe28f # v8.2.1
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
projectBaseDir: clients/passkeys-browser
- name: Run Stryker mutation tests
# Skip on Dependabot PRs: the dashboard reporter needs STRYKER_DASHBOARD_API_KEY, which is
# withheld from Dependabot-triggered runs, and mutation testing a dependency bump adds no
# signal. The vitest suite above still runs and gates the PR.
if: github.actor != 'dependabot[bot]'
run: npm exec --no-install -- stryker run
working-directory: clients/passkeys-browser
env:
STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_TOKEN }}
- name: Annotate surviving mutants
if: always()
working-directory: clients/passkeys-browser
run: |
node -e "
const fs = require('fs');
if (!fs.existsSync('reports/mutation/mutation.json')) process.exit(0);
const report = JSON.parse(fs.readFileSync('reports/mutation/mutation.json', 'utf8'));
for (const [file, data] of Object.entries(report.files || {})) {
for (const mutant of data.mutants || []) {
if (mutant.status !== 'Survived' && mutant.status !== 'NoCoverage') continue;
const {start, end} = mutant.location;
const title = mutant.status === 'NoCoverage' ? 'No Coverage' : 'Surviving Mutant';
const msg = (mutant.mutatorName + ': ' + (mutant.replacement || '(removed)'))
.replace(/%/g, '%25').replace(/\r/g, '%0D').replace(/\n/g, '%0A');
const path = 'clients/passkeys-browser/' + file;
process.stdout.write('::warning file=' + path + ',line=' + start.line + ',col=' + start.column + ',endLine=' + end.line + ',endColumn=' + end.column + ',title=' + title + '::' + msg + '\n');
}
}
"
- name: Upload mutation report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: mutation-report
path: clients/passkeys-browser/reports/mutation/
if-no-files-found: ignore
# Playwright end-to-end suites for the three example demos. Each demo carries a sibling `e2e/`
# Playwright project that drives the full passkey ceremony through Chrome's CDP virtual WebAuthn
# authenticator. These are wired into Gradle `check` as an OPT-IN task (skipped by default so the
# `build` job above stays fast and Chrome-free) — here we flip the switch with PK_RUN_E2E=1 and
# let the `e2eTest` task provision Chrome (PW_INSTALL_DEPS=1 → playwright install --with-deps) and
# boot the demo via its Gradle `run` task. One job per adapter (all three bind :8080).
e2e:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
demo: [ spring-boot-demo, dropwizard-demo, micronaut-demo ]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up JDK 21
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5
with:
java-version: '21'
distribution: 'temurin'
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '20'
# The e2eTest task executes the wrapper jar (directly and again nested, when Playwright boots
# the demo via the Gradle `run` task) — validate it for the same reason the build job does.
- name: Validate Gradle wrapper
uses: gradle/actions/wrapper-validation@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
- name: Set up Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6
- name: Run ${{ matrix.demo }} e2e
run: ./gradlew :examples:${{ matrix.demo }}:e2eTest --stacktrace
env:
PK_RUN_E2E: '1' # flip the opt-in e2eTest task on
PW_INSTALL_DEPS: '1' # playwright install --with-deps chrome (needs the runner's apt deps)
- name: Upload Playwright traces
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: playwright-traces-${{ matrix.demo }}
path: examples/${{ matrix.demo }}/e2e/test-results/
if-no-files-found: ignore
# Block PRs that introduce dependencies with known vulnerabilities or incompatible
# licenses, before they merge. Uses the GitHub dependency graph; PR-only.
dependency-review:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Dependency review
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: high