diff --git a/.github/workflows/anchore-sbom-evidence-example.yaml b/.github/workflows/anchore-sbom-evidence-example.yaml
new file mode 100644
index 0000000..d8c9f00
--- /dev/null
+++ b/.github/workflows/anchore-sbom-evidence-example.yaml
@@ -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"' || '' }}
+
diff --git a/.github/workflows/anchore-scan-evidence-example.yaml b/.github/workflows/anchore-scan-evidence-example.yaml
new file mode 100644
index 0000000..1ca789d
--- /dev/null
+++ b/.github/workflows/anchore-scan-evidence-example.yaml
@@ -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"' || '' }}
diff --git a/examples/anchore/Dockerfile b/examples/anchore/Dockerfile
new file mode 100644
index 0000000..7522cc3
--- /dev/null
+++ b/examples/anchore/Dockerfile
@@ -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"]
\ No newline at end of file
diff --git a/examples/anchore/anchore-sbom-readme.md b/examples/anchore/anchore-sbom-readme.md
new file mode 100644
index 0000000..e11dd26
--- /dev/null
+++ b/examples/anchore/anchore-sbom-readme.md
@@ -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/)
diff --git a/examples/anchore/anchore-scan-readme.md b/examples/anchore/anchore-scan-readme.md
new file mode 100644
index 0000000..2c7beb0
--- /dev/null
+++ b/examples/anchore/anchore-scan-readme.md
@@ -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/)
diff --git a/examples/anchore/markdown_generators/sbom_to_md.py b/examples/anchore/markdown_generators/sbom_to_md.py
new file mode 100644
index 0000000..139a743
--- /dev/null
+++ b/examples/anchore/markdown_generators/sbom_to_md.py
@@ -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)
\ No newline at end of file
diff --git a/examples/anchore/markdown_generators/scan_sariff_to_md.py b/examples/anchore/markdown_generators/scan_sariff_to_md.py
new file mode 100644
index 0000000..5fc0f78
--- /dev/null
+++ b/examples/anchore/markdown_generators/scan_sariff_to_md.py
@@ -0,0 +1,40 @@
+import json
+from datetime import datetime
+
+def convert_report_to_markdown(input_file, output_file):
+ with open(input_file, 'r') as f:
+ report_data = json.load(f)
+
+ markdown_lines = ["# Report Analysis", ""]
+
+ # Add metadata
+ markdown_lines.append(f"**Generated on**: {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC')}")
+ markdown_lines.append("\n---\n")
+
+ # Process runs
+ for run in report_data.get('runs', []):
+ tool_name = run.get('tool', {}).get('driver', {}).get('name', 'Unknown Tool')
+ tool_version = run.get('tool', {}).get('driver', {}).get('semanticVersion', 'Unknown Version')
+ markdown_lines.append(f"## Tool: {tool_name} (Version: {tool_version})")
+
+ # Add results in tabular format
+ markdown_lines.append("\n| Rule ID | Message |")
+ markdown_lines.append("|---------|---------|")
+ for result in run.get('results', []):
+ rule_id = result.get('ruleId', 'Unknown Rule')
+ message = result.get('message', {}).get('text', 'No message provided').replace("\n", "
")
+ markdown_lines.append(f"| {rule_id} | {message} |")
+
+ # Write to Markdown file
+ with open(output_file, 'w') as f:
+ f.write('\n'.join(markdown_lines))
+
+if __name__ == "__main__":
+ import sys
+ if len(sys.argv) != 3:
+ print("Usage: python report_to_markdown.py ")
+ sys.exit(1)
+
+ input_json = sys.argv[1]
+ output_md = sys.argv[2]
+ convert_report_to_markdown(input_json, output_md)
\ No newline at end of file