Skip to content

Sazwanismail patch 3#7

Merged
Sazwanend merged 4 commits into
Sazwanend:masterfrom
Sazwanismail:Sazwanismail-patch-3
Mar 16, 2026
Merged

Sazwanismail patch 3#7
Sazwanend merged 4 commits into
Sazwanend:masterfrom
Sazwanismail:Sazwanismail-patch-3

Conversation

@Sazwanismail
Copy link
Copy Markdown

Based on your interest in SLSA3 documentation and workflows, I've gathered information from several leading platforms. The documentation from these sources reveals a consistent set of architectural patterns and requirements for achieving SLSA Build Level 3.

Here is a comparison of how different platforms document and implement SLSA Level 3 workflows:

Platform/Tool Core SLSA 3 Workflow Documentation Key Implementation Details Verification Methods
GitHub Uses GitHub Artifact Attestations with a reusable workflow for provenance generation. - Signing occurs on dedicated hardware separate from the build machine .
- Leverages ephemeral, isolated GitHub-hosted runners .
- Manages Sigstore infrastructure (Fulcio, Rekor) for keyless signing .
gh artifact verify <file> --signer-workflow <owner>/<repo>/.github/workflows/sign-artifact.yml
GitLab Moving provenance generation to the GitLab Rails backend (control plane) instead of the runner. - Provenance is generated in the trusted control plane, not by a tenant of the build platform .
- Uses reusable CI components for in-pipeline signing .
- Plans to support out-of-pipeline signing with key isolation .
Planned verification via an API and glab CLI .
Google Cloud Build Generates build provenance for artifacts in Artifact Registry, meeting SLSA Level 3. - Provenance generation is enabled via the requestedVerifyOption: VERIFIED flag .
- Provides detailed buildType schema in provenance output .
- Provenance is viewable via the console or gcloud CLI .
gcloud artifacts docker images describe ... --show-provenance
VMware Tanzu Generates signed SLSA v1 attestations for images when configured with a signing key. - Build L3 requires a signing key attached to the service account, with keys readable only by system resources .
- Builds run in isolated Kubernetes pods .
- Provenance is stored as a separate image with a predictable tag (.att) .
cosign verify-attestation --key <public-key> --type=slsaprovenance1 <image-digest>
Harness Uses a dedicated SLSA Generation step in CI pipelines to generate and attest provenance. - Built-in infrastructure isolation for every build .
- Supports attestation with Cosign keys, optionally managed via HashiCorp Vault .
- Stores provenance in Harness and pushes .att files to the container registry .
Verification is done as part of the pipeline or deployment stage .
Docker Docker Hardened Images (DHIs) are cryptographically signed and comply with SLSA Build Level 3. - Each DHI includes attestations that provide verifiable build provenance .
- Integrates with Docker Scout for verification .
docker scout attest get <image> --predicate-type https://slsa.dev/provenance/v0.2 --verify

🔑 Key Architectural Patterns for SLSA Level 3

Across all these platforms, a few critical patterns emerge that are essential for meeting the SLSA Level 3 requirements:

  • Isolated and Ephemeral Build Environments: Every build must run in a clean, temporary environment that is destroyed after the build completes. This prevents cross-build contamination and ensures that no persistent state can influence the build process .
  • Provenance Generation in a Trusted Control Plane: The provenance (the record of how an artifact was built) must be generated by the build platform's control plane, not by the build process itself. This makes the provenance "non-forgeable" because the tenant running the build cannot alter the record .
  • Strict Separation of Signing Keys: User-defined build steps must not have access to the keys used to sign the provenance. Signing is performed by a separate, trusted component (like a reusable workflow or the platform's backend) to prevent key compromise .

💡 How to Use This Information

This documentation from various platforms shows that achieving SLSA Level 3 is about more than just a single tool or configuration. It requires a fundamental shift in how your build pipeline is architected. To apply this to your own workflows:

  1. Audit Your Current Build Platform: Determine where your builds run. Are they on ephemeral, isolated infrastructure? Is the build process fully automated and scripted? This is the foundation .
  2. Plan for Provenance: Decide how you will generate and sign your provenance. This could involve using platform-native features (like GitHub Artifact Attestations or Google Cloud Build's verified builds ) or integrating tools like Sigstore Cosign .
  3. Implement Verification: Simply generating provenance isn't enough. You must also verify it as part of your deployment process to ensure the artifacts you're deploying haven't been tampered with since the build .

Would you like a deeper dive into the workflow specifics for one of these platforms, or help mapping these patterns to your existing CI/CD setup?Certainly! Based on your request for a deeper dive into workflow specifics, and given that we've been discussing your GitHub Actions YAML files, let's focus on GitHub's approach to SLSA Level 3. I'll break down exactly how to structure your workflows to meet the standard, referencing the documentation from GitHub and Google that outlines the architecture .

The core idea is to create a trusted builder by separating the build process from the provenance generation, using GitHub's reusable workflows and OIDC tokens for non-forgeable signing .

Here is a step-by-step guide to adapting your cmake-single-platform.yml for full SLSA Level 3 compliance.

Step 1: Isolate the Build in a Reusable Workflow

SLSA Level 3 requires that the build process be isolated and ephemeral. GitHub-hosted runners achieve this naturally, as each job runs in a fresh virtual machine . However, you also need to isolate the provenance generation from the build steps themselves to prevent tampering .

  • Action: Move your core build logic (checkout, configure, compile, test) into a reusable workflow (e.g., cmake-build-reusable.yml). This workflow will be responsible for producing the build artifacts and their hashes.
  • Why: Reusable workflows act as a trusted builder. The calling workflow can only pass parameters to it, preventing maintainers from altering the build process in a way that could interfere with provenance .

Step 2: Generate Non-Forgeable Provenance

This is the most critical step. The provenance (the metadata about the build) must be generated and signed by the platform's control plane, not by the build process itself .

  • Action: In your main workflow, after the build job completes, call the official SLSA generator. GitHub provides a specific action for this.
  • Configuration: Your main workflow file (the "caller") needs specific permissions to request an identity token and write attestations :
    permissions:
      id-token: write   # Required for OIDC token to sign provenance
      attestations: write # Required to create the attestation
      contents: read    # To read the repository contents
  • The Mechanism: When the workflow runs, it receives a unique OIDC token from GitHub. This token contains verifiable information about the workflow run (repo, commit SHA, workflow path). The SLSA generator uses this token to request a short-lived signing certificate from Sigstore's Fulcio CA, signs the provenance, and logs it in the public Rekor transparency log .

Step 3: Structure Your Workflow with Jobs

Your updated main workflow (the one that triggers on a release) should have a clear separation of jobs:

  1. Build Job: Calls your reusable build workflow. Its primary output should be a list of the generated artifacts and their cryptographic hashes (subjects).
  2. Provenance Job: Needs the build job. It uses the slsa-framework/slsa-github-generator action, passing in the hashes from the build job. This job runs in a completely separate, fresh environment, ensuring the signing keys are never accessible to the build steps .
  3. Verification/Deployment Job (Optional but Recommended): Needs the provenance job. This job downloads the artifact and its provenance and verifies them together before any deployment step.

Step 4: Verify the Provenance

Generating provenance is only half the battle; you must also verify it to ensure the artifact you have is the one that was built .

  • Action: Use the gh CLI tool to verify the attestation against your repository.
  • Command Example: After downloading an artifact, you can verify it. If your build used a reusable workflow from another repo, you must specify the signer repository .
    gh attestation verify artifact.bin \
      --owner YOUR_ORG_OR_USER \
      --signer-repo YOUR_ORG/YOUR_REPO_FOR_REUSABLE_WORKFLOW
    This command checks the signature against the public key in the transparency log and validates that the build occurred in the expected workflow from the expected repository .

Summary of Key Changes for Your YAML

To transform your existing cmake-single-platform.yml into a fully compliant SLSA Level 3 workflow, you would need to:

  1. Create a reusable workflow (.github/workflows/cmake-build.yml) containing your CMake configure, build, test, and artifact hashing steps.
  2. Modify your main release workflow to have two jobs:
    • build-cmake: uses: ./.github/workflows/cmake-build.yml (calls your reusable workflow).
    • provenance: uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 (or latest) with needs: [build-cmake].
  3. Set the correct permissions on your main workflow: attestations: write, id-token: write, contents: read.
  4. Add a verification step before any deployment to run gh attestation verify.

This architecture, where a trusted builder runs in an isolated environment and provenance is generated and signed by a separate, secure component, is the pattern used not only by GitHub but also by other platforms like GitLab (moving signing to their glgo control plane) and Google Cloud Build (generating provenance in the backend) . It ensures that no matter how the build is compromised, the provenance record remains a trustworthy, non-forgeable link back to the source code.

Sazwanismail and others added 4 commits March 17, 2026 01:18
# Updated CMake Single Platform GitHub Actions Workflow

This repository provides an up-to-date GitHub Actions workflow for building CMake projects on a single platform (Linux, macOS, or Windows). It includes:

- CMake configuration and build
- Caching for dependencies (vcpkg, ccache)
- Multiple build types (Debug, Release)
- Running tests with CTest
- Uploading build artifacts
- Code formatting and linting (optional)

## 📄 Workflow File: `.github/workflows/cmake-single-platform.yml`

```yaml
name: CMake Single Platform Build

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:  # Allow manual trigger

env:
  BUILD_TYPE: Release
  # Customize CMake build type if needed

jobs:
  build:
    # Choose the runner: ubuntu-latest, windows-latest, or macos-latest
    runs-on: ubuntu-latest

    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    # ===== SETUP DEPENDENCIES =====
    - name: Install Linux dependencies (if any)
      if: runner.os == 'Linux'
      run: |
        sudo apt-get update
        sudo apt-get install -y ninja-build ccache
        # Add other packages as needed

    - name: Install macOS dependencies
      if: runner.os == 'macOS'
      run: |
        brew install ninja ccache
        # Add other packages

    - name: Install Windows dependencies (using Chocolatey)
      if: runner.os == 'Windows'
      run: |
        choco install ninja ccache
        # Or use vcpkg (see below)

    # ===== CACHE MANAGEMENT =====
    - name: Cache ccache
      uses: actions/cache@v4
      with:
        path: ~/.ccache
        key: ${{ runner.os }}-ccache-${{ github.sha }}
        restore-keys: ${{ runner.os }}-ccache-

    - name: Cache vcpkg (if used)
      if: false  # Enable if you use vcpkg
      uses: actions/cache@v4
      with:
        path: |
          ~/.cache/vcpkg
          build/vcpkg_installed
        key: ${{ runner.os }}-vcpkg-${{ hashFiles('**/vcpkg.json') }}
        restore-keys: ${{ runner.os }}-vcpkg-

    # ===== CONFIGURE & BUILD =====
    - name: Configure CMake
      run: |
        cmake -B build -S . \
          -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
          -G Ninja \
          -DCMAKE_C_COMPILER_LAUNCHER=ccache \
          -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
      env:
        CC: clang   # Override compiler if needed (gcc, clang, cl)
        CXX: clang++

    - name: Build
      run: cmake --build build --config ${{ env.BUILD_TYPE }} --parallel

    # ===== TEST =====
    - name: Test
      working-directory: build
      run: ctest -C ${{ env.BUILD_TYPE }} --output-on-failure --parallel

    # ===== CODE QUALITY (optional) =====
    - name: Run clang-format lint
      if: false  # Enable if you want formatting checks
      uses: jidicula/clang-format-action@v4.11.0
      with:
        clang-format-version: '16'
        check-path: 'src'

    # ===== ARTIFACTS =====
    - name: Upload build artifacts
      uses: actions/upload-artifact@v4
      with:
        name: ${{ runner.os }}-${{ env.BUILD_TYPE }}-binaries
        path: |
          build/bin
          build/lib
          build/*.exe
          build/*.dll
          build/*.so
          build/*.dylib
        if-no-files-found: ignore
```

## 🔧 Customization Tips

1. **Runner OS**: Change `runs-on` to `windows-latest` or `macos-latest` as needed.
2. **Dependencies**: Adjust package installation steps for your specific libraries.
3. **vcpkg**: If your project uses vcpkg, enable the vcpkg cache step and install vcpkg in a setup step.
4. **Compiler**: Override `CC` and `CXX` environment variables to use different compilers (e.g., `gcc`, `clang`, `msvc`).
5. **Build Types**: You can matrix over `BUILD_TYPE` to build both Debug and Release, or add a strategy matrix.
6. **Artifacts**: Customize the artifact paths to match your output locations.

## 📦 Example with vcpkg and Matrix

If you need multiple build types or configurations, extend with a matrix:

```yaml
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        build_type: [Debug, Release]
    env:
      BUILD_TYPE: ${{ matrix.build_type }}
    steps:
      # ... steps (use matrix.os and matrix.build_type)
```

## ✅ Best Practices Included

- **Caching** with ccache and vcpkg speeds up rebuilds.
- **Ninja** generator for faster builds.
- **Parallel** builds and tests.
- **Artifact** upload for easy access to binaries.
- **Manual trigger** (`workflow_dispatch`) for ad-hoc runs.

## 🔗 References

- [GitHub Actions Documentation](https://docs.github.com/actions)
- [CMake Documentation](https://cmake.org/cmake/help/latest/)
- [vcpkg with GitHub Actions](https://vcpkg.io/en/getting-started.html)

---

**Maintainer:** Your Team  
**License:** MIT
# Updated Advanced CMake Single/Multi-Platform Workflow

This workflow provides a robust CI pipeline for CMake projects, supporting multiple operating systems and build configurations. It includes caching, testing, code coverage, static analysis, and artifact upload.

## 📄 `.github/workflows/cmake-advanced.yml`

```yaml
name: CMake Advanced CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]
  workflow_dispatch:        # Allow manual trigger

env:
  # Global build type; can be overridden per matrix
  BUILD_TYPE: Release

jobs:
  build:
    name: ${{ matrix.os }} / ${{ matrix.build_type }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false      # Continue other jobs if one fails
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        build_type: [Debug, Release]
        # Optionally exclude some combinations
        # exclude:
        #   - os: windows-latest
        #     build_type: Debug

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

    # ===== DEPENDENCY INSTALLATION =====
    - name: Install Linux dependencies
      if: runner.os == 'Linux'
      run: |
        sudo apt-get update
        sudo apt-get install -y \
          ninja-build \
          ccache \
          lcov \
          clang-tidy \
          curl \
          zip
        # Add project-specific packages here

    - name: Install macOS dependencies
      if: runner.os == 'macOS'
      run: |
        brew install \
          ninja \
          ccache \
          llvm      # provides clang-tidy, lcov
        # Ensure llvm binaries are in PATH
        echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH

    - name: Install Windows dependencies
      if: runner.os == 'Windows'
      run: |
        choco install ninja ccache
        # vcpkg is usually installed on GitHub runners; if needed, bootstrap:
        # git clone https://github.com/Microsoft/vcpkg.git
        # .\vcpkg\bootstrap-vcpkg.bat
        # echo "${{ github.workspace }}/vcpkg" >> $GITHUB_PATH

    # ===== CACHE SETUP =====
    - name: Cache ccache
      uses: actions/cache@v4
      with:
        path: ~/.ccache
        key: ${{ runner.os }}-ccache-${{ matrix.build_type }}-${{ github.sha }}
        restore-keys: |
          ${{ runner.os }}-ccache-${{ matrix.build_type }}-
          ${{ runner.os }}-ccache-

    - name: Cache vcpkg (if used)
      if: false   # Enable if you use vcpkg.json manifest mode
      uses: actions/cache@v4
      with:
        path: |
          ~/.cache/vcpkg
          ${{ github.workspace }}/build/vcpkg_installed
        key: ${{ runner.os }}-vcpkg-${{ hashFiles('**/vcpkg.json') }}
        restore-keys: ${{ runner.os }}-vcpkg-

    # ===== CONFIGURE CMAKE =====
    - name: Configure CMake
      shell: bash
      run: |
        cmake -B build -S . \
          -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
          -G Ninja \
          -DCMAKE_C_COMPILER_LAUNCHER=ccache \
          -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
          -DCMAKE_EXPORT_COMPILE_COMMANDS=ON   # for clang-tidy

    # ===== BUILD =====
    - name: Build
      run: cmake --build build --config ${{ matrix.build_type }} --parallel

    # ===== RUN TESTS =====
    - name: Test
      working-directory: build
      run: ctest -C ${{ matrix.build_type }} --output-on-failure --parallel

    # ===== STATIC ANALYSIS (clang-tidy) =====
    - name: Run clang-tidy
      if: runner.os == 'Linux' && matrix.build_type == 'Debug'   # Run once to avoid duplication
      working-directory: build
      run: |
        # Adjust source directory and checks as needed
        run-clang-tidy -p . -extra-arg=-Wno-unknown-warning-option -quiet

    # ===== CODE COVERAGE (Linux only) =====
    - name: Generate coverage report
      if: runner.os == 'Linux' && matrix.build_type == 'Debug' && github.event_name == 'push'
      run: |
        # Ensure you have built with coverage flags: -fprofile-arcs -ftest-coverage
        lcov --directory . --capture --output-file coverage.info
        lcov --remove coverage.info '/usr/*' --output-file coverage.info
        lcov --list coverage.info
      working-directory: build

    - name: Upload coverage to Codecov
      if: runner.os == 'Linux' && matrix.build_type == 'Debug' && github.event_name == 'push'
      uses: codecov/codecov-action@v4
      with:
        files: build/coverage.info
        flags: unittests
        name: codecov-umbrella
        fail_ci_if_error: false
        token: ${{ secrets.CODECOV_TOKEN }}

    # ===== UPLOAD ARTIFACTS =====
    - name: Prepare artifacts
      shell: bash
      run: |
        mkdir -p artifacts
        # Copy binaries, libraries, etc.
        if [ -d build/bin ]; then cp -r build/bin artifacts/; fi
        if [ -d build/lib ]; then cp -r build/lib artifacts/; fi
        # Include compile_commands.json for debugging
        cp build/compile_commands.json artifacts/ || true

    - name: Upload build artifacts
      uses: actions/upload-artifact@v4
      with:
        name: ${{ runner.os }}-${{ matrix.build_type }}-artifacts
        path: artifacts/
```

## 🚀 Key Features

- **Matrix Build**: Builds on Ubuntu, Windows, and macOS with both Debug and Release configurations.
- **Caching**: Uses `ccache` to speed up rebuilds; vcpkg cache ready.
- **Dependencies**: Installs `ninja`, `ccache`, and platform-specific tools.
- **Static Analysis**: Runs `clang-tidy` (on Linux/Debug once).
- **Code Coverage**: Generates and uploads coverage reports to Codecov (Linux/Debug only).
- **Artifacts**: Uploads binaries, libraries, and `compile_commands.json`.

## 🔧 Customization

- **Add more packages**: Modify the dependency installation steps.
- **Adjust coverage**: Ensure your CMake project enables coverage flags when `CMAKE_BUILD_TYPE` is Debug.
- **vcpkg**: Uncomment the cache step and add a vcpkg installation step if needed.
- **Compiler**: Override `CC`/`CXX` in the configure step to use specific compilers.
- **Artifacts**: Modify the `Prepare artifacts` step to capture your desired output.

## ✅ Best Practices

- **fail-fast: false** allows all matrix jobs to run even if one fails.
- **Conditional steps** avoid redundant work (e.g., coverage only once).
- **Caching keys** use both OS and build type to avoid mixing caches.
- **Parallel** builds and tests reduce CI time.

## 📚 References

- [GitHub Actions Documentation](https://docs.github.com/actions)
- [CMake Documentation](https://cmake.org/documentation)
- [Codecov Action](https://github.com/codecov/codecov-action)
- [clang-tidy Integration](https://clang.llvm.org/extra/clang-tidy/)

---

**Maintainer:** Your Team  
**License:** MIT
# Building a SLSA3‑Compliant Development Workflow: A Practical Guide

You’ve asked to “Create development” – and that’s exactly what we’ll do. Below is a **step‑by‑step blueprint** for setting up a development environment and process that meets SLSA Level 3 requirements while remaining practical for everyday coding. This guide builds on everything we’ve discussed and gives you a concrete path forward.

## 🎯 Goal
Establish a development pipeline where every artifact (commits, builds, releases) carries verifiable proof of its origin and integrity, satisfying SLSA Build Level 3 and setting the foundation for higher levels.

---

## 📦 Phase 1: Repository Foundation

### 1.1 Enable Signed Commits
- **What**: Require that every commit is signed with a GPG, SSH, or S/MIME key.
- **How**:
  - Generate a signing key (GPG: `gpg --full-generate-key`).
  - Add the public key to your GitHub/GitLab account.
  - Configure Git locally:  
    ```bash
    git config --global user.signingkey <key-id>
    git config --global commit.gpgsign true
    ```
- **Why**: Establishes a chain of custody from developer to code, which is part of the source integrity expected by SLSA.

### 1.2 Branch Protection Rules
- **Require signed commits** on all protected branches (main, release/*).
- **Require pull request reviews** before merging.
- **Optionally require** that all status checks pass (including any SLSA verification steps you add later).

### 1.3 Dependency Locking
- Use lock files (`go.sum`, `package-lock.json`, `Cargo.lock`, etc.) to pin dependency versions.
- Commit these lock files to the repository.

---

## 🛠️ Phase 2: Local Developer Environment

### 2.1 Containerized Development Environment
- Provide a `Dockerfile` or Dev Container configuration that mirrors your CI build environment.
- Example `.devcontainer/devcontainer.json`:
  ```json
  {
    "name": "MyApp Dev",
    "build": { "dockerfile": "Dockerfile" },
    "features": {
      "ghcr.io/devcontainers/features/common-utils:2": {}
    }
  }
  ```
- This ensures builds are reproducible and eliminates “works on my machine” discrepancies.

### 2.2 Pre‑commit Hooks for Security
- Use [pre-commit](https://pre-commit.com/) to run:
  - **Dependency hash verification** (e.g., check `go.sum` against a known good state).
  - **Linting and static analysis**.
  - **Secret scanning** (e.g., `detect-secrets` or `truffleHog`).
- Example `.pre-commit-config.yaml`:
  ```yaml
  repos:
    - repo: local
      hooks:
        - id: verify-deps
          name: Verify dependencies
          entry: scripts/verify-deps.sh
          language: script
          files: '.*\.(mod|sum|lock)$'
    - repo: https://github.com/pre-commit/pre-commit-hooks
      rev: v4.4.0
      hooks:
        - id: detect-aws-credentials
        - id: detect-private-key
  ```

### 2.3 Local Build with Provenance (Optional but Recommended)
- For testing, you can generate lightweight attestations using [in-toto](https://in-toto.io/).
- Example wrapper script `local-build.sh`:
  ```bash
  #!/bin/bash
  in-toto-run --step-name local-build --products myapp --key mykey -- ./build.sh
  ```
- This creates a link file that you can keep locally for debugging.

---

## 🔁 Phase 3: Continuous Integration (CI) Pipeline

### 3.1 Reusable Build Workflow
Create a reusable workflow (`.github/workflows/build.yml`) that encapsulates your build steps and outputs artifact hashes.

```yaml
name: Reusable Build

on:
  workflow_call:
    outputs:
      base64-subjects:
        description: "Base64-encoded subjects (artifacts with digests)"
        value: ${{ jobs.build.outputs.base64-subjects }}

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      base64-subjects: ${{ steps.hashes.outputs.base64_subjects }}
    steps:
      - uses: actions/checkout@v4
      - run: make build
      - run: mkdir -p artifacts && cp bin/* artifacts/
      - id: hashes
        run: |
          cd artifacts
          subjects="[]"
          for file in *; do
            hash=$(sha256sum "$file" | cut -d' ' -f1)
            subjects=$(jq -c --arg name "$file" --arg hash "sha256:$hash" \
                      '. += [{"name": $name, "digest": $hash}]' <<< "$subjects")
          done
          echo "base64_subjects=$(echo -n "$subjects" | base64 -w0)" >> $GITHUB_OUTPUT
      - uses: actions/upload-artifact@v4
        with:
          name: build-artifacts-${{ github.run_id }}
          path: artifacts/
```

### 3.2 Main CI Workflow (PRs and Merges)
Create a main workflow (`.github/workflows/ci.yml`) that calls the reusable build and then verifies dependencies.

```yaml
name: CI

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write   # Needed if you verify provenance of dependencies

jobs:
  build:
    uses: ./.github/workflows/build.yml

  verify-deps:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Download dependency provenance
        run: |
          # Example: verify a third-party binary used in build
          curl -LO https://example.com/dependency.bin
          curl -LO https://example.com/dependency.intoto.jsonl
          slsa-verifier verify-artifact \
            --provenance-path dependency.intoto.jsonl \
            --source-uri github.com/trusted-owner/dependency \
            --builder-id trusted-builder-id \
            dependency.bin
```

### 3.3 Release Workflow with SLSA3 Provenance
Create a separate workflow (`.github/workflows/release.yml`) triggered on tags or release publication.

```yaml
name: Release

on:
  release:
    types: [published]

permissions:
  id-token: write
  attestations: write
  contents: write
  actions: read

jobs:
  build:
    uses: ./.github/workflows/build.yml

  provenance:
    needs: build
    uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
    with:
      base64-subjects: ${{ needs.build.outputs.base64-subjects }}
      upload-artifacts-name: build-artifacts-${{ github.run_id }}
      upload-assets: true

  verify-and-publish:
    needs: provenance
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: build-artifacts-${{ github.run_id }}
          path: artifacts/

      - name: Verify provenance
        run: |
          gh attestation verify artifacts/myapp \
            --owner ${{ github.repository_owner }} \
            --signer-repo slsa-framework/slsa-github-generator

      - name: Upload to release
        run: |
          gh release upload ${{ github.event.release.tag_name }} artifacts/* provenance.json
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

---

## 🔐 Phase 4: Verification Gate Before Deployment

### 4.1 Deployment Job
In the release workflow (or a separate deployment workflow), add a final verification step:

```yaml
deploy:
  needs: verify-and-publish
  runs-on: ubuntu-latest
  environment: production
  steps:
    - name: Verify attestation again (defense in depth)
      run: |
        gh attestation verify artifacts/myapp \
          --owner ${{ github.repository_owner }}
    - name: Deploy
      run: ./deploy.sh artifacts/
```

### 4.2 Enforce Verification in Production Environment
- Configure GitHub Environments with **required reviewers**.
- Optionally, use a deployment protection rule that calls an external verification service (e.g., via a custom GitHub Action).

---

## 📘 Phase 5: Developer Onboarding & Documentation

Create a `CONTRIBUTING.md` or `DEVELOPMENT.md` that covers:
- How to set up the local environment (Docker, pre‑commit, signing keys).
- How to run a local build that mimics CI.
- How to interpret verification failures.
- Where to find provenance files and how to manually verify them.

Example section:

```markdown
## Verifying Artifacts Locally

After a CI build, you can download the provenance file from the workflow run and verify it:

```bash
gh attestation verify myapp --owner myorg
```

Or using the `slsa-verifier` tool:

```bash
slsa-verifier verify-artifact \
  --provenance-path provenance.json \
  --source-uri github.com/myorg/myapp \
  myapp
```
```

---

## 🧪 Phase 6: Testing the Pipeline

1. **Test a pull request**: Push a change, ensure the CI workflow runs, and that dependency verification passes.
2. **Create a pre‑release**: Tag a commit, push the tag, and trigger the release workflow. Download the artifacts and verify them manually.
3. **Simulate a tampering attempt**: Modify an artifact locally and try to verify it – the verification should fail.
4. **Rotate keys**: If using GPG for commit signing, practice rotating a developer key and updating the repository settings.

---

## 📈 Ongoing Maintenance

- Keep the SLSA generator version up to date (check for releases at [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator/releases)).
- Periodically review dependency verification rules.
- Update developer documentation as tooling evolves.

---

## 🎉 You’re Now SLSA3‑Ready

By following this guide, your development workflow will:
- Produce **non‑forgeable provenance** for every release.
- Ensure **source integrity** through signed commits.
- Provide **reproducible builds** via containerized environments.
- Build a **culture of security** where every developer understands and participates in supply chain protection.

This is a living process – adapt it to your team’s size, tech stack, and release cadence. And remember, the SLSA community is constantly improving tooling and practices; stay engaged to keep your pipeline cutting‑edge.

Would you like help with any specific part, such as setting up the containerized environment or writing the reusable workflow? I’m here to assist!
@Sazwanend Sazwanend added this to the Google milestone Mar 16, 2026
@Sazwanend Sazwanend self-assigned this Mar 16, 2026
@Sazwanend Sazwanend merged commit cf6c5a5 into Sazwanend:master Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants