diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d89b5467..5a53c581 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,6 +8,11 @@ on: permissions: contents: read +# Keep every non-PR run; only superseded PR validation is cancelled. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: test: name: test + lint (full offline stack) @@ -227,6 +232,9 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml python-version: ${{ matrix.python-version }} - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: @@ -265,9 +273,15 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml python-version: "3.11" - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: + cache: npm + cache-dependency-path: | + package-lock.json node-version: "24" - name: Install dashboard and browser test dependencies run: | @@ -394,6 +408,9 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml python-version: "3.11" - name: Install pinned build and audit tooling run: >- @@ -430,6 +447,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - name: Build the candidate wheel run: | @@ -475,6 +496,7 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 with: name: candidate-journey-${{ matrix.os }}-${{ matrix.profile }} + retention-days: 14 path: | ${{ runner.temp }}/installed-candidate/journey.json ${{ runner.temp }}/installed-candidate/environment.lock diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ef36cd5b..ebd6a714 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -14,10 +14,16 @@ permissions: packages: read security-events: write +# Keep every non-PR run; only superseded PR validation is cancelled. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: analyze: name: Analyze ${{ matrix.language }} runs-on: ubuntu-latest + timeout-minutes: 30 # Pull-request analyses otherwise use diff-informed queries, whose SARIF # intentionally omits findings outside changed lines. The release gate # must inspect complete raw SARIF on both pull requests and pushes. diff --git a/.github/workflows/export-offline-evidence.yml b/.github/workflows/export-offline-evidence.yml index 206ba38f..fa9b6dca 100644 --- a/.github/workflows/export-offline-evidence.yml +++ b/.github/workflows/export-offline-evidence.yml @@ -17,9 +17,15 @@ on: - "scripts/export_offline_evidence.py" permissions: contents: read +# Keep every non-PR run; only superseded PR validation is cancelled. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: export: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: diff --git a/.github/workflows/release-pi.yml b/.github/workflows/release-pi.yml index b61424c3..94cc6b3b 100644 --- a/.github/workflows/release-pi.yml +++ b/.github/workflows/release-pi.yml @@ -13,12 +13,16 @@ jobs: build: name: Verify and pack Pi extension runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: fetch-depth: 0 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml python-version: "3.11" - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: @@ -76,6 +80,7 @@ jobs: # protected pi-v* tag and npm Trusted Publishing configured for this workflow. if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/pi-v') runs-on: ubuntu-latest + timeout-minutes: 15 permissions: contents: read id-token: write diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d4225044..ae61d273 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,6 +34,7 @@ jobs: build: name: Build distributions runs-on: ubuntu-latest + timeout-minutes: 60 if: >- github.event_name == 'push' || inputs.release_tag == '' @@ -50,6 +51,10 @@ jobs: - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - name: Install release gate and the production dependency set (without SQLCipher) @@ -167,6 +172,7 @@ jobs: reproducibility-build: name: Independent distribution builder ${{ matrix.builder }} runs-on: ubuntu-latest + timeout-minutes: 30 if: >- github.event_name == 'push' || inputs.release_tag == '' @@ -184,6 +190,10 @@ jobs: - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - name: Build in isolated pinned environment shell: bash @@ -207,6 +217,7 @@ jobs: name: Compare independent distribution builders needs: [build, reproducibility-build] runs-on: ubuntu-latest + timeout-minutes: 15 if: >- github.event_name == 'push' || inputs.release_tag == '' @@ -295,6 +306,7 @@ jobs: python-matrix: name: Python ${{ matrix.python-version }} release gate runs-on: ubuntu-latest + timeout-minutes: 60 strategy: fail-fast: false matrix: @@ -306,6 +318,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: ${{ matrix.python-version }} - name: Install version-appropriate gate shell: bash @@ -336,6 +352,7 @@ jobs: github.event_name == 'push' || inputs.release_tag == '' runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -405,6 +422,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - name: Download exact release distributions uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 @@ -473,6 +494,7 @@ jobs: encryption: name: Encryption driver release gate (Python ${{ matrix.python-version }}) runs-on: ubuntu-latest + timeout-minutes: 20 strategy: fail-fast: false matrix: @@ -484,6 +506,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: ${{ matrix.python-version }} - name: Install encryption integration gate run: | @@ -497,6 +523,7 @@ jobs: browser-accessibility: name: Browser accessibility release gate runs-on: ubuntu-latest + timeout-minutes: 30 if: >- github.event_name == 'push' || inputs.release_tag == '' @@ -504,9 +531,16 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: + cache: npm + cache-dependency-path: | + package-lock.json node-version: "24" - name: Install browser gate run: | @@ -526,6 +560,7 @@ jobs: pi-extension: name: Pi extension release gate runs-on: ubuntu-latest + timeout-minutes: 30 if: >- github.event_name == 'push' || inputs.release_tag == '' @@ -533,6 +568,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: @@ -556,6 +595,7 @@ jobs: docker-smoke: name: Production image release gate runs-on: ubuntu-latest + timeout-minutes: 30 if: >- github.event_name == 'push' || inputs.release_tag == '' @@ -723,6 +763,7 @@ jobs: github.event_name == 'push' || inputs.release_tag == '' runs-on: ubuntu-latest + timeout-minutes: 30 permissions: contents: read security-events: write @@ -757,6 +798,7 @@ jobs: needs: [build, reproducibility-check, python-matrix, artifact-core-py39, installed-artifact-platform-smoke, encryption, browser-accessibility, pi-extension, docker-smoke, code-security] if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest + timeout-minutes: 15 permissions: contents: read @@ -841,6 +883,7 @@ jobs: # semver tag, whose value was matched to pyproject.toml in the build job above. if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest + timeout-minutes: 30 permissions: id-token: write contents: read @@ -849,6 +892,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - name: Download distributions uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 @@ -906,6 +953,7 @@ jobs: environment: release-qualification if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest + timeout-minutes: 30 permissions: contents: write @@ -913,6 +961,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - name: Download distributions uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 @@ -974,6 +1026,7 @@ jobs: github.ref == 'refs/heads/main' && inputs.release_tag != '' runs-on: ubuntu-latest + timeout-minutes: 30 permissions: actions: read contents: write @@ -983,6 +1036,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: + cache: pip + cache-dependency-path: | + pyproject.toml + .github/release-constraints.txt python-version: "3.11" - name: Enforce and record the release-specific qualification waiver if: inputs.waive_v176_qualification || inputs.waive_v178_qualification || inputs.waive_v179_qualification