Skip to content
Merged
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
58 changes: 58 additions & 0 deletions .github/workflows/anchore-sbom-evidence-example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: "Anchore SBOM evidence integration example"
on:
workflow_dispatch:

permissions:
id-token: write
contents: read

jobs:
package-docker-image-with-anchore-evidence:
runs-on: ubuntu-latest
env:
REGISTRY_DOMAIN: ${{ vars.JF_URL }}
REPO_NAME: 'docker-anchore-repo'
IMAGE_NAME: 'docker-anchore-sbom-image'
VERSION: ${{ github.run_number }}
BUILD_NAME: 'anchore-docker-build'
ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE: true

steps:
# Build and publish the packages to JFrog Artifactory
- name: Setup jfrog cli
uses: jfrog/setup-jfrog-cli@v4
env:
JF_URL: ${{ vars.ARTIFACTORY_URL }}
JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }}
- name: Checkout repository
uses: actions/checkout@v4
- name: Build and publish Docker Image to Artifactory
run: |
docker build . --file ./examples/anchore/Dockerfile --tag $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION
jf rt docker-push $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION $REPO_NAME

- uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY_DOMAIN }}/${{ env.REPO_NAME }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
output-file: anchore-sbom.json


# This is an optional step to generate a custom markdown report
- name: Generate optional custom markdown report
if: env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true'
run: |
python3 ./examples/anchore/markdown_generators/sbom_to_md.py anchore-sbom.json anchore-sbom.md

# Attaching the evidence to associated package
- name: Attach evidence using jfrog cli
run: |
jf evd create \
--package-name $IMAGE_NAME \
--package-version $VERSION \
--package-repo-name $REPO_NAME \
--key "${{ secrets.PRIVATE_KEY }}" \
--key-alias "${{ vars.EVIDENCE_KEY_ALIAS }}" \
--predicate ./anchore-sbom.json \
--predicate-type http://anchore.com/syft/sbom/v1 \
${{ env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true' && '--markdown "anchore-sbom.md"' || '' }}

59 changes: 59 additions & 0 deletions .github/workflows/anchore-scan-evidence-example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: "Anchore scan evidence integration example"
on:
workflow_dispatch:

permissions:
id-token: write
contents: read

jobs:
package-docker-image-with-anchore-evidence:
runs-on: ubuntu-latest
env:
REGISTRY_DOMAIN: ${{ vars.JF_URL }}
REPO_NAME: 'docker-anchore-repo'
IMAGE_NAME: 'docker-anchore-scan-image'
VERSION: ${{ github.run_number }}
BUILD_NAME: 'anchore-docker-build'
ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE: true

steps:
# Build and publish the packages to JFrog Artifactory
- name: Setup jfrog cli
uses: jfrog/setup-jfrog-cli@v4
env:
JF_URL: ${{ vars.ARTIFACTORY_URL }}
JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }}
- name: Checkout repository
uses: actions/checkout@v4
- name: Build and publish Docker Image to Artifactory
run: |
docker build . --file ./examples/anchore/Dockerfile --tag $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION
jf rt docker-push $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION $REPO_NAME

- uses: anchore/scan-action@v6
with:
image: ${{ env.REGISTRY_DOMAIN }}/${{ env.REPO_NAME }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
output-format: sarif
output-file: anchore-scan-results.sarif
fail-build: false


# This is an optional step to generate a custom markdown report
- name: Generate optional custom markdown report
if: env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true'
run: |
python3 ./examples/anchore/markdown_generators/scan_sariff_to_md.py anchore-scan-results.sarif anchore-results.md

# Attaching the evidence to associated package
- name: Attach evidence using jfrog cli
run: |
jf evd create \
--package-name $IMAGE_NAME \
--package-version $VERSION \
--package-repo-name $REPO_NAME \
--key "${{ secrets.PRIVATE_KEY }}" \
--key-alias "${{ vars.EVIDENCE_KEY_ALIAS }}" \
--predicate ./anchore-scan-results.sarif \
--predicate-type http://anchore.com/grype/vulnerabilities/v1 \
${{ env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true' && '--markdown "anchore-results.md"' || '' }}
10 changes: 10 additions & 0 deletions examples/anchore/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Use the official lightweight Python image
FROM python:3.9-slim

# Set the working directory
WORKDIR /app

# Add a simple script that prints a message
RUN echo 'print("Hello from Docker!")' > hello.py

CMD ["python", "hello.py"]
87 changes: 87 additions & 0 deletions examples/anchore/anchore-sbom-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Anchore SBOM Evidence Integration Example

This example demonstrates how to automate SBOM generation for Docker images using Anchore and attach the SBOM as signed evidence to the image in JFrog Artifactory using GitHub Actions and JFrog CLI.

## Overview

The workflow builds a Docker image, generates an SBOM (Software Bill of Materials) using Anchore, pushes the image to Artifactory, and attaches the SBOM as evidence to the image package. This enables traceability and compliance for software composition analysis in your CI/CD pipeline.

## Prerequisites

- JFrog CLI 2.65.0 or above (installed automatically in the workflow)
- Artifactory configured as a Docker registry
- The following GitHub repository variables:
- `JF_URL` (Artifactory Docker registry domain, e.g. `mycompany.jfrog.io`)
- `ARTIFACTORY_URL` (Artifactory base URL)
- `EVIDENCE_KEY_ALIAS` (Key alias for signing evidence)
- The following GitHub repository secrets:
- `ARTIFACTORY_ACCESS_TOKEN` (Artifactory access token)
- `PRIVATE_KEY` (Private key for signing evidence)

## Environment Variables Used

- `REGISTRY_DOMAIN` - Docker registry domain
- `REPO_NAME` - Repository name for the Docker image
- `IMAGE_NAME` - Name of the Docker image
- `VERSION` - Version of the Docker image
- `BUILD_NAME` - Build name for the Docker image
- `ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE` - Whether to attach custom markdown reports to evidence

## Workflow

```mermaid
graph TD
A[Workflow Dispatch Trigger] --> B[Setup JFrog CLI]
B --> C[Checkout Repository]
C --> D[Build and Publish Docker Image to Artifactory]
D --> E[Generate SBOM]
E --> F{Attach Optional Custom Markdown Report?}
F -->|Yes| G[Generate Custom Markdown Report]
F -->|No| H[Skip Markdown Report]
G --> I[Attach Evidence to Package]
H --> I[Attach Evidence to Package]
```

## Example Usage

You can trigger the workflow manually from the GitHub Actions tab. The workflow will:

- Build the Docker image
- Generate an SBOM for the image
- Push the image to Artifactory
- Attach the SBOM as evidence

## Key Commands Used

- **Build Docker Image:**
```bash
docker build . --file ./examples/anchore/Dockerfile --tag $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION
```
- **Push Docker Image:**
```bash
jf rt docker-push $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION $REPO_NAME
```
- **Generate SBOM:**
```yaml
uses: anchore/sbom-action@v0
with:
image: ${{ env.REGISTRY_DOMAIN }}/${{ env.REPO_NAME }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
output-file: anchore-sbom.json
```
- **Attach Evidence:**
```bash
jf evd create \
--package-name $IMAGE_NAME \
--package-version $VERSION \
--package-repo-name $REPO_NAME \
--key "${{ secrets.PRIVATE_KEY }}" \
--key-alias "${{ vars.EVIDENCE_KEY_ALIAS }}" \
--predicate ./anchore-sbom.json \
--predicate-type http://anchore.com/syft/sbom/v1
```

## References

- [Anchore Documentation](https://anchore.com/)
- [JFrog Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management)
- [JFrog CLI Documentation](https://jfrog.com/getcli/)
88 changes: 88 additions & 0 deletions examples/anchore/anchore-scan-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Anchore Scan Evidence Integration Example

This example demonstrates how to automate Anchore scanning for Docker images and attach the scan results as signed evidence to the image in JFrog Artifactory using GitHub Actions and JFrog CLI.

## Overview

The workflow builds a Docker image, scans it with Anchore for vulnerabilities, pushes the image to Artifactory, and attaches the Anchore scan results as evidence to the image package. This enables traceability and compliance for security scanning in your CI/CD pipeline.

## Prerequisites

- JFrog CLI 2.65.0 or above (installed automatically in the workflow)
- Artifactory configured as a Docker registry
- The following GitHub repository variables:
- `JF_URL` (Artifactory Docker registry domain, e.g. `mycompany.jfrog.io`)
- `ARTIFACTORY_URL` (Artifactory base URL)
- `EVIDENCE_KEY_ALIAS` (Key alias for signing evidence)
- The following GitHub repository secrets:
- `ARTIFACTORY_ACCESS_TOKEN` (Artifactory access token)
- `PRIVATE_KEY` (Private key for signing evidence)

## Environment Variables Used

- `REGISTRY_DOMAIN` - Docker registry domain
- `REPO_NAME` - Repository name for the Docker image
- `IMAGE_NAME` - Name of the Docker image
- `VERSION` - Version of the Docker image
- `BUILD_NAME` - Build name for the Docker image
- `ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE` - Whether to attach custom markdown reports to evidence

## Workflow

```mermaid
graph TD
A[Workflow Dispatch Trigger] --> B[Setup JFrog CLI]
B --> C[Checkout Repository]
C --> D[Build and Publish Docker Image to Artifactory]
D --> E[Run Anchore Vulnerability Scan]
E --> F{Attach Optional Custom Markdown Report?}
F -->|Yes| G[Generate Custom Markdown Report]
F -->|No| H[Skip Markdown Report]
G --> I[Attach Evidence to Package]
H --> I[Attach Evidence to Package]
```

## Example Usage

You can trigger the workflow manually from the GitHub Actions tab. The workflow will:

- Build and scan the Docker image
- Push the image to Artifactory
- Attach the Anchore scan results as evidence

## Key Commands Used

- **Build Docker Image:**
```bash
docker build . --file ./examples/anchore/Dockerfile --tag $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION
```
- **Push Docker Image:**
```bash
jf rt docker-push $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION $REPO_NAME
```
- **Run Anchore Scan:**
```yaml
uses: anchore/scan-action@v6
with:
image: ${{ env.REGISTRY_DOMAIN }}/${{ env.REPO_NAME }}/${{ env.IMAGE_NAME }}:${{ env.VERSION }}
output-format: sarif
output-file: anchore-scan-results.sarif
fail-build: false
```
- **Attach Evidence:**
```bash
jf evd create \
--package-name $IMAGE_NAME \
--package-version $VERSION \
--package-repo-name $REPO_NAME \
--key "${{ secrets.PRIVATE_KEY }}" \
--key-alias "${{ vars.EVIDENCE_KEY_ALIAS }}" \
--predicate ./anchore-scan-results.sarif \
--predicate-type http://anchore.com/grype/vulnerabilities/v1
```

## References

- [Anchore Documentation](https://anchore.com/)
- [JFrog Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management)
- [JFrog CLI Documentation](https://jfrog.com/getcli/)
52 changes: 52 additions & 0 deletions examples/anchore/markdown_generators/sbom_to_md.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import sys
import json

def json_to_md(json_path, md_path):
with open(json_path, 'r') as f:
data = json.load(f)

spdx_version = data.get('spdxVersion', 'N/A')
data_license = data.get('dataLicense', 'N/A')
document_namespace = data.get('documentNamespace', 'N/A')
creation_info = data.get('creationInfo', {})
packages = data.get('packages', [])
files = data.get('files', [])

with open(md_path, 'w') as f:
f.write(f"# SBOM Summary\n\n")
f.write(f"**SPDX Version:** {spdx_version}\n\n")
f.write(f"**Data License:** {data_license}\n\n")
f.write(f"**Document Namespace:** {document_namespace}\n\n")

f.write(f"## Creation Info\n")
f.write(f"- License List Version: {creation_info.get('licenseListVersion', 'N/A')}\n")
f.write(f"- Created: {creation_info.get('created', 'N/A')}\n")
creators = creation_info.get('creators', [])
if creators:
f.write(f"- Creators:\n")
for creator in creators:
f.write(f" - {creator}\n")
else:
f.write("- No creators found.\n")

f.write(f"\n## Packages\n")
if packages:
f.write(f"| Index | Name | Version | Supplier |\n")
f.write(f"|---|---|---|---|\n")
for idx, package in enumerate(packages, start=1):
name = package.get('name', 'N/A').replace('|', '\\|')
version = package.get('versionInfo', 'N/A').replace('|', '\\|')
supplier = package.get('supplier', 'N/A')
if isinstance(supplier, dict):
supplier = supplier.get('name', 'N/A')
supplier = supplier.replace('|', '\\|')
f.write(f"| {idx} | {name} | {version} | {supplier} |\n")
else:
f.write("No packages found.\n")

print(f"Markdown file generated at: {md_path}")

if __name__ == "__main__":
input_json = sys.argv[1]
output_md = sys.argv[2]
json_to_md(input_json, output_md)
Loading