Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions .github/ACTIONS-SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,13 @@ Workflow-level permissions default to read-only (`contents: read`). Write permis

`.github/dependabot.yml` is configured for the `github-actions` ecosystem with weekly update cadence. Dependabot automatically creates PRs to update SHA pins when new action versions are released.

## Exceptions

* `slsa-framework/slsa-github-generator@v2.1.0` uses tag-based pinning because GitHub requires tag references for reusable workflow calls (`jobs.<id>.uses`). SHA pinning is not supported for this use case.

## Compliance Verification

Verify all actions comply with this policy:

```bash
# Verify no tag-only pins (except slsa-framework and local workflow refs)
grep -rn "uses:" .github/workflows/ | grep -v "uses:.*\./" | grep -v "@[a-f0-9]\{40\}" | grep -v "slsa-framework"
# Verify no tag-only pins (except local workflow refs)
grep -rn "uses:" .github/workflows/ | grep -v "uses:.*\./" | grep -v "@[a-f0-9]\{40\}"

# Verify all SHA pins have version comments
grep -rn "uses:.*@[a-f0-9]\{40\}" .github/workflows/ | grep -v "#"
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ jobs:
pages: write
contents: read
id-token: write
attestations: write
# Only deploy if there are documentation changes
if: success()
uses: ./.github/workflows/pages-deploy.yml
Expand Down
73 changes: 40 additions & 33 deletions .github/workflows/pages-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ permissions:
contents: read
pages: write
id-token: write
attestations: write

# Allow only one concurrent deployment
concurrency:
Expand All @@ -130,8 +131,6 @@ jobs:
build:
name: Build Documentation
runs-on: ubuntu-latest
outputs:
hashes: ${{ steps.hash.outputs.hashes }}
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand Down Expand Up @@ -737,28 +736,10 @@ jobs:
run: |
echo "[TARGET] Build validation completed successfully"

- name: Generate artifact hashes for SLSA attestation
id: hash
- name: Create build artifact archive
run: |
echo "🔒 Generating artifact hashes for SLSA attestation..."

# Create a tarball of the built site for consistent hashing
tar -czf site-artifact.tar.gz -C ./_site .

# Generate SHA256 hash
HASH=$(sha256sum site-artifact.tar.gz | cut -d' ' -f1)

# Generate base64 encoded subjects in the format required by SLSA
# Format: "name":"sha256:hash"
SUBJECTS_JSON='{"site-artifact.tar.gz":"sha256:'$HASH'"}'
SUBJECTS_B64=$(echo -n "$SUBJECTS_JSON" | base64 -w0)

echo "hashes=$SUBJECTS_B64" >> "$GITHUB_OUTPUT"

echo "✅ Generated artifact hash: $HASH"
echo "📄 Subject: site-artifact.tar.gz"
echo "🔐 SLSA subjects: $SUBJECTS_JSON"

- name: Upload build artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
Expand All @@ -772,25 +753,51 @@ jobs:
# Adjust this path to match your documentation output directory
path: './_site'

# SLSA attestation for documentation artifacts
slsa-attestation:
name: SLSA Attestation
needs: build
permissions:
id-token: write
contents: read
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with:
base64-subjects: "${{ needs.build.outputs.hashes }}"
upload-assets: true
attest-documentation:
needs: [build]
if: inputs.deploy_environment == 'production'
runs-on: ubuntu-latest
steps:
- name: Download build artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: documentation-build-${{ github.run_number }}
path: ./attestation-staging

- name: Attest build provenance
uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0
with:
subject-path: ./attestation-staging/**

- name: Sparse checkout for SBOM config
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
sparse-checkout: |
.syft.yaml
sparse-checkout-cone-mode: false

- name: Generate SBOM
uses: anchore/sbom-action@e11c554f704a0b820cbf8c51673f6945e0731532 # v0.20.0
with:
artifact-name: documentation-sbom-${{ github.run_number }}
output-file: documentation-sbom.spdx.json
format: spdx-json
config: .syft.yaml

- name: Attest SBOM
uses: actions/attest@afd638254319277bb3d7f0a234478733e2e46a73 # v2.3.0
with:
subject-path: documentation-sbom.spdx.json
predicate-type: https://spdx.dev/Document/v2.3
predicate-path: documentation-sbom.spdx.json

deploy:
name: Deploy to GitHub Pages
environment:
name: ${{ inputs.deploy_environment }}
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: [build, slsa-attestation]
needs: [build, attest-documentation]
outputs:
page_url: ${{ steps.deployment.outputs.page_url }}
steps:
Expand Down
17 changes: 17 additions & 0 deletions .syft.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Syft SBOM scanner configuration for anchore/sbom-action
# Generates SPDX 2.3 JSON format SBOMs for documentation artifact attestation
output:
- "spdx-json"

default-catalogers:
- "javascript"
- "python"
- "go"
- "rust-cargo"

file:
metadata:
digests:
- "sha256"
content:
skip-files-above-size: 1048576
5 changes: 4 additions & 1 deletion scripts/security/Update-ActionSHAPinning.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,15 @@ $ActionSHAMap = @{
"actions/setup-python@v4" = "actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236" # v4.8.0
"actions/setup-dotnet@v4" = "actions/setup-dotnet@6bd8b7f7774af54e05809fcc5431931b3eb1ddee" # v4.0.1
"actions/setup-dotnet@v3" = "actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3" # v3.2.0
"actions/attest@v2" = "actions/attest@afd638254319277bb3d7f0a234478733e2e46a73" # v2.3.0
"actions/attest-build-provenance@v2" = "actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd" # v2.3.0
"actions/cache@v4" = "actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9" # v4.0.2
"actions/cache@v3" = "actions/cache@88522ab9f39a2ea568f7027eddc7d8d8bc9d59c8" # v3.3.1
"actions/upload-artifact@v4" = "actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808" # v4.3.6
"actions/upload-artifact@v3" = "actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3" # v3.1.3
"actions/download-artifact@v4" = "actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16" # v4.1.8
"actions/download-artifact@v4" = "actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093" # v4.3.0
"actions/download-artifact@v3" = "actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a" # v3.0.2
"anchore/sbom-action@v0" = "anchore/sbom-action@e11c554f704a0b820cbf8c51673f6945e0731532" # v0.20.0
"github/super-linter@v6" = "github/super-linter@4ac6c1e9bce95c4e5e456c8c2c6b468998248097" # v6.8.0
"github/super-linter@v5" = "github/super-linter@45fc0d88288beee4701c62761281edfee85655d7" # v5.7.2
"step-security/harden-runner@v2" = "step-security/harden-runner@5c7944e73c4c2a096b17a9cb74d65b6c2bbafbde" # v2.9.1
Expand Down
Loading