JFrog Evidence Management with GitHub Actions

JFrog and GitHub Integration Guide

This topic explains how to integrate GitHub Actions build attestations with JFrog's Evidence service to create a secure, verifiable audit trail for your software artifacts.

The idea is to create a secure and traceable link from your source code to the final build artifact.

  • Generate Attestation in GitHub Actions: You use the actions/attest-build-provenance action in your workflow to create a cryptographically signed attestation. This attestation follows the SLSA and in-toto frameworks, providing verifiable proof of where and how your artifact was built.

  • Push to JFrog Artifactory: Your workflow pushes the built artifact (for example, a Docker image, a binary) to JFrog Artifactory.

  • Ingest into JFrog Evidence: The integration automatically ingests the build attestation from GitHub into JFrog Evidence. It intelligently links this attestation to the specific artifact stored in Artifactory.

By integrating them, you ensure that every artifact in Artifactory has a verifiable history, which is crucial for security, compliance, and auditing. Attestations of build provenance that you generate with the GitHub Action can be automatically sent to and stored within JFrog Evidence.

Sample Workflow

  1. Code Push: A developer pushes code to your GitHub repository.

  2. Build Trigger: A GitHub Actions workflow starts.

  3. Build and Push Artifact: The workflow builds your artifact (for example, a Docker image) and pushes it to a repository in JFrog Artifactory.

  4. Generate and Store Evidence: The attest-build-provenance action generates the signed attestation. Because of the native integration (which occurs in the post jfrog/setup-jfrog-cli step), this attestation is automatically sent to your JFrog Platform and stored as evidence linked directly to the newly pushed artifact.

Ensure your workflow has the correct permissions to write attestations and use OIDC.

# This workflow demonstrates building a Docker image, pushing it to JFrog Artifactory,
# and attaching an SLSA build provenance attestation, which is stored in JFrog Evidence.

name: Build, Push, and Attest to JFrog

on:
  push:
    branches:
      - main
  workflow_dispatch:

# Use GitHub variables (vars) and secrets (secrets) for configuration
env:
  JF_REGISTRY: ${{ vars.JF_REGISTRY }}
  JF_DOCKER_REPO: ${{ vars.JF_DOCKER_REPO }}
  IMAGE_NAME: ${{ vars.IMAGE_NAME }}

jobs:
  build-and-attest:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write      # Required for OIDC token access
      attestations: write  # Required for attestation

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

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Install and Configure JFrog CLI
        id: setup-jfrog-cli
        uses: jfrog/setup-jfrog-cli@4.6.1
        env:
          JF_URL: ${{ secrets.JF_URL }}
        with:
          # Replace with the name of your configured OIDC provider in JFrog
          oidc-provider-name: 'your-github-oidc-provider-name'
      
      - name: Log in to JFrog Docker Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.JF_REGISTRY }}
          username: ${{ steps.setup-jfrog-cli.outputs.oidc-user }}
          password: ${{ steps.setup-jfrog-cli.outputs.oidc-token }}

      - name: Build and Push Docker Image
        id: build-and-push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ${{ env.JF_REGISTRY }}/${{ env.JF_DOCKER_REPO }}/${{ env.IMAGE_NAME }}:${{ github.run_number }}

      - name: Attest Docker Image and Send to JFrog Evidence
        uses: actions/attest-build-provenance@v3
        with:
          # The 'oci://' prefix is required by JFrog to correctly parse the artifact type
          subject-name: oci://${{ env.JF_REGISTRY }}/${{ env.JF_DOCKER_REPO }}/${{ env.IMAGE_NAME }}
          
          # This links the attestation directly to the image digest from the build step
          subject-digest: ${{ steps.build-and-push.outputs.digest }}

Related Information