diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0bedb40..b7a7220 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -28,8 +28,10 @@ updates: - dependency-name: hashicorp/setup-terraform - dependency-name: mxschmitt/action-tmate # # Managed by cisagov/skeleton-python-library + # - dependency-name: actions/attest # - dependency-name: actions/download-artifact # - dependency-name: actions/upload-artifact + # - dependency-name: anchore/sbom-action labels: # dependabot default we need to replicate - dependencies diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5842141..b87f0a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -340,8 +340,17 @@ jobs: needs: - diagnostics permissions: - # actions/checkout needs this to fetch code + # Allows us to read artifacts + actions: read + # Necessary to create the artifact storage record + artifact-metadata: write + attestations: write + # Allows actions/checkout to fetch code; write access is not + # required for this build job. contents: read + # Allows the workflow to mint the OIDC token necessary to + # request a Sigstore signing certificate. + id-token: write runs-on: ubuntu-latest strategy: fail-fast: false @@ -408,6 +417,10 @@ jobs: with: name: dist-${{ matrix.python-version }} path: dist + - name: Create provenance attestation for distribution + uses: actions/attest@v4 + with: + subject-path: dist - name: Setup tmate debug session uses: mxschmitt/action-tmate@v3 if: env.RUN_TMATE @@ -502,3 +515,139 @@ jobs: - name: Setup tmate debug session uses: mxschmitt/action-tmate@v3 if: env.RUN_TMATE + generate-sbom: + # Generate SBOMs for the built Python wheel packages and, if there + # is a release, upload them as assets to the release. + # + # This job is located in this workflow as opposed to a separate + # release workflow because it can only run after the wheels have + # been generated in the build job. Putting it in a separate + # release workflow would require us to introduce a dependency of + # the release workflow on this one. + # + # This if statement is present to keep the push and pull_request + # events from both causing the job to be run. + if: github.event_name != 'pull_request' + name: Generate and upload SBOM + needs: + - build-wheel + - diagnostics + permissions: + # Allows us to read the SBOM artifact + actions: read + # Necessary to create the artifact storage record + artifact-metadata: write + attestations: write + # Allows us to add the SBOM to the release. Also, + # actions/checkout needs read permission to fetch code. + contents: write + # Allows the workflow to mint the OIDC token necessary to + # request a Sigstore signing certificate. + id-token: write + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" + sbom-format: + - cyclonedx-json + - spdx-json + steps: + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 + with: + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-docker#224 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + - id: setup-env + uses: cisagov/setup-env-github-action@v1 + - uses: actions/checkout@v6 + - id: setup-python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - uses: actions/cache@v5 + env: + BASE_CACHE_KEY: >- + ${{ github.job }}-${{ + runner.os }}-${{ runner.arch }}-py${{ + matrix.python-version }}- + with: + path: ${{ env.PIP_CACHE_DIR }} + key: >- + ${{ env.BASE_CACHE_KEY }}${{ + hashFiles('pyproject.toml') }} + restore-keys: | + ${{ env.BASE_CACHE_KEY }} + - name: Retrieve the built wheel + uses: actions/download-artifact@v8 + with: + name: dist-${{ matrix.python-version }} + path: dist + - id: find-wheel + name: Get the name of the retrieved wheel (there should only be one) + run: echo "wheel=$(ls dist/*whl)" >> $GITHUB_OUTPUT + - name: Update core Python packages + run: python -m pip install --upgrade pip setuptools + - name: Install pipenv + run: pip install --upgrade pipenv + - name: Install the built wheel into a Pipfile + run: pipenv install ${{ steps.find-wheel.outputs.wheel }} + - name: Lock the Pipfile + run: pipenv lock + - name: Manipulate the repo name into the preferred format + id: manipulate-repo-name + run: | + NEW_NAME=$(echo "${{ github.repository}}" \ + | tr '[:upper:]' '[:lower:]' \ + | tr '/ ' '-') + echo "repo-name=${NEW_NAME}" >> $GITHUB_OUTPUT + - name: Generate SBOM + uses: anchore/sbom-action@v0 + with: + artifact-name: >- + ${{ steps.manipulate-repo-name.outputs.repo-name }}.py${{ + matrix.python-version }}.${{ matrix.sbom-format }} + file: Pipfile.lock + format: ${{ matrix.sbom-format }} + output-file: >- + ${{ steps.manipulate-repo-name.outputs.repo-name }}.py${{ + matrix.python-version }}.${{ matrix.sbom-format }} + - name: Create provenance attestation for SBOM + uses: actions/attest@v4 + with: + subject-path: >- + ${{ steps.manipulate-repo-name.outputs.repo-name }}.py${{ + matrix.python-version }}.${{ matrix.sbom-format }} + - name: Create SBOM attestation for distribution package + uses: actions/attest@v4 + with: + sbom-path: >- + ${{ steps.manipulate-repo-name.outputs.repo-name }}.py${{ + matrix.python-version }}.${{ matrix.sbom-format }} + subject-path: dist