diff --git a/.github/workflows/codeql-evidence-example.yml b/.github/workflows/codeql-evidence-example.yml
index 2dfbf57..147514a 100644
--- a/.github/workflows/codeql-evidence-example.yml
+++ b/.github/workflows/codeql-evidence-example.yml
@@ -83,7 +83,6 @@ jobs:
# Attaching the evidence to associated package
- name: Attach Evidence using JFrog CLI
run: |
- jf config show
if [ ${{ matrix.language_details.name }} == 'go' ]; then
PACKAGE_VERSION="v0.0.${{ github.run_number }}"
jf evd create \
diff --git a/.github/workflows/scorecard-evidence-example.yml b/.github/workflows/scorecard-evidence-example.yml
new file mode 100644
index 0000000..43afc8e
--- /dev/null
+++ b/.github/workflows/scorecard-evidence-example.yml
@@ -0,0 +1,64 @@
+name: "Scorecard Evidence Integration example"
+on:
+ workflow_dispatch:
+
+permissions: read-all
+
+jobs:
+ ossf-scorecard-analysis:
+ runs-on: ubuntu-latest
+ env:
+ REGISTRY_DOMAIN: ${{ vars.JF_URL }}
+ REPO_NAME: 'docker-scorecard-repo'
+ IMAGE_NAME: 'docker-scorecard-image'
+ VERSION: ${{ github.run_number }}
+ BUILD_NAME: 'scorecard-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 }}
+ - uses: actions/checkout@v4
+ with:
+ sparse-checkout: |
+ examples/scorecard/**
+ sparse-checkout-cone-mode: false
+ - name: Build and publish Docker Image to Artifactory
+ run: |
+ docker build . --file ./examples/scorecard/Dockerfile --tag $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION
+ echo "Pushing Docker Image to Artifactory"
+ jf rt docker-push $REGISTRY_DOMAIN/$REPO_NAME/$IMAGE_NAME:$VERSION $REPO_NAME --build-name=$BUILD_NAME --build-number=${{ github.run_number }}
+ echo "Pushing Docker Image to Artifactory completed"
+ echo "publishing build info"
+ jf rt build-publish $BUILD_NAME ${{ github.run_number }}
+
+ # Fetch Scorecard Analysis
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@v2.4.2
+ with:
+ results_file: scorecard-results.sarif
+ results_format: sarif
+ publish_results: 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: |
+ python ./examples/scorecard/scorecard_json_to_markdown_helper.py scorecard-results.sarif scorecard-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 ./scorecard-results.sarif \
+ --predicate-type http://openssf.org/scorecard/security-scan/v1 \
+ ${{ env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true' && '--markdown "scorecard-results.md"' || '' }}
diff --git a/.github/workflows/semgrep-evidence-example.yml b/.github/workflows/semgrep-evidence-example.yml
new file mode 100644
index 0000000..4ac7e5d
--- /dev/null
+++ b/.github/workflows/semgrep-evidence-example.yml
@@ -0,0 +1,70 @@
+name: "Semgrep Evidence Integration example"
+on:
+ workflow_dispatch:
+
+jobs:
+ semgrep_scan:
+ name: semgrep/ci
+ runs-on: ubuntu-latest
+ container:
+ image: semgrep/semgrep
+ env:
+ ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE: true
+ permissions:
+ security-events: write
+ actions: read
+ contents: read
+
+ steps:
+ # Install Node.js and npm
+ - name: Install Node.js and npm
+ run: |
+ apk add --no-cache nodejs npm
+
+ # 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
+ with:
+ sparse-checkout: |
+ examples/semgrep/**
+ sparse-checkout-cone-mode: false
+ - name: Build and Publish js package
+
+ run: |
+ cd examples/semgrep/js
+ jf npm-config --repo-resolve=javascript-remote --repo-deploy=javascript-local \
+ --server-id-deploy=setup-jfrog-cli-server \
+ --server-id-resolve=setup-jfrog-cli-server
+ jf npm publish --build-name=js-semgrep-sample-build --build-number=${{ github.run_number }}
+ cd -
+ continue-on-error: true
+
+ # Run Semgrep analysis
+ - name: Perform Semgrep Analysis
+ run: |
+ semgrep scan -q --sarif --config auto ./examples/semgrep/js > semgrep-results.sarif
+
+ # This is an optional step to generate a custom markdown report
+ - name: Generate optional custom markdown
+ if: env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true'
+ run: |
+ python examples/semgrep/sarif_to_markdown.py semgrep-results.sarif semgrep-results.md
+
+ # Attaching the evidence to associated package
+ - name: Attach Evidence using JFrog CLI
+ run: |
+ jf evd create \
+ --package-name js-semgrep-sample-build \
+ --package-version "0.0.1" \
+ --package-repo-name javascript-local \
+ --key "${{ secrets.PRIVATE_KEY }}" \
+ --key-alias "${{ vars.EVIDENCE_KEY_ALIAS }}" \
+ --predicate "semgrep-results.sarif" \
+ --predicate-type "http://semgrep.com/security-scan/v1" \
+ ${{ env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true' && '--markdown "semgrep-results.md"' || '' }}
+
diff --git a/examples/scorecard/Dockerfile b/examples/scorecard/Dockerfile
new file mode 100644
index 0000000..ae6f34b
--- /dev/null
+++ b/examples/scorecard/Dockerfile
@@ -0,0 +1,9 @@
+FROM python:3.7-slim-buster
+
+WORKDIR /app
+
+COPY ./examples/scorecard/requirements.txt .
+
+RUN pip install --no-cache-dir -r requirements.txt
+
+CMD ["ansible", "--version"]
\ No newline at end of file
diff --git a/examples/scorecard/README.md b/examples/scorecard/README.md
new file mode 100644
index 0000000..8718977
--- /dev/null
+++ b/examples/scorecard/README.md
@@ -0,0 +1,86 @@
+# Scorecard Security Scan Evidence Example
+
+This example demonstrates how to automate Scorecard security 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 Scorecard for security and quality metrics, pushes the image to Artifactory, and
+attaches the Scorecard 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:
+ - `REGISTRY_DOMAIN` (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
+
+## 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 Scorecard Analysis]
+ 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 Scorecard scan results as evidence
+
+## Key Commands Used
+
+- **Build Docker Image:**
+ ```bash
+ docker build . --file ./examples/scorecard/Dockerfile --tag $REGISTRY_URL/$REPO_NAME/$IMAGE_NAME:$VERSION
+ ```
+- **Run Scorecard Analysis:**
+ ```yaml
+ uses: ossf/scorecard-action@v2.4.2
+ with:
+ results_file: scorecard-results.sarif
+ results_format: sarif
+ publish_results: false
+ ```
+- **Push Docker Image:**
+ ```bash
+ jf rt docker-push $REGISTRY_URL/$REPO_NAME/$IMAGE_NAME:$VERSION $REPO_NAME --build-name=$BUILD_NAME --build-number=${{ github.run_number }}
+ ```
+- **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 ./scorecard-results.sarif \
+ --predicate-type http://openssf.org/scorecard/security-scan/v1 \
+ ${{ env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true' && '--markdown "scorecard-results.md"' || '' }}
+ ```
+
+## References
+
+- [Scorecard Documentation](https://github.com/ossf/scorecard)
+- [JFrog Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management)
+- [JFrog CLI Documentation](https://jfrog.com/getcli/)
diff --git a/examples/scorecard/requirements.txt b/examples/scorecard/requirements.txt
new file mode 100644
index 0000000..b9f0773
--- /dev/null
+++ b/examples/scorecard/requirements.txt
@@ -0,0 +1 @@
+ansible==2.9.9
\ No newline at end of file
diff --git a/examples/scorecard/scorecard_json_to_markdown_helper.py b/examples/scorecard/scorecard_json_to_markdown_helper.py
new file mode 100644
index 0000000..29e5fb8
--- /dev/null
+++ b/examples/scorecard/scorecard_json_to_markdown_helper.py
@@ -0,0 +1,47 @@
+import json
+from datetime import datetime
+
+def convert_report_to_markdown(input_file, output_file):
+ """
+ Converts the Scorecard report.json file to a Markdown file with tabular formatting for lists.
+
+ Args:
+ input_file (str): Path to the input JSON file.
+ output_file (str): Path to the output Markdown file.
+ """
+ with open(input_file, 'r') as f:
+ report_data = json.load(f)
+
+ markdown_lines = ["# Scorecard Analysis Report", ""]
+
+ # 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
diff --git a/examples/semgrep/README.md b/examples/semgrep/README.md
new file mode 100644
index 0000000..babca04
--- /dev/null
+++ b/examples/semgrep/README.md
@@ -0,0 +1,78 @@
+# Semgrep Security Scan Evidence Example
+
+This example demonstrates how to automate Semgrep security scanning for JavaScript code and attach the scan results as signed evidence to the package in JFrog Artifactory using GitHub Actions and JFrog CLI.
+
+## Overview
+
+The workflow scans JavaScript code with Semgrep for security issues, publishes the package to Artifactory, and attaches the Semgrep scan results as evidence to the 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 repository
+- The following GitHub repository variables:
+ - `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
+
+- `ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE` - Whether to attach a custom markdown report to the evidence
+
+## Workflow
+
+```mermaid
+graph TD
+ A[Workflow Dispatch Trigger] --> B[Setup JFrog CLI]
+ B --> C[Checkout Repository]
+ C --> D[Publish JavaScript Package to Artifactory]
+ D --> E[Run Semgrep Security 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 Using JFrog CLI]
+ H --> I[Attach Evidence Using JFrog CLI]
+```
+
+## Example Usage
+
+You can trigger the workflow manually from the GitHub Actions tab. The workflow will:
+
+- Scan the JavaScript code
+- Publish the package to Artifactory
+- Attach the Semgrep scan results as evidence
+
+## Key Commands Used
+
+- **Publish JavaScript Package:**
+ ```bash
+ jf npm-config --repo-resolve=javascript-remote --repo-deploy=javascript-local \
+ --server-id-deploy=setup-jfrog-cli-server \
+ --server-id-resolve=setup-jfrog-cli-server
+ jf npm publish --build-name=js-semgrep-sample-build --build-number=${{ github.run_number }}
+ jf rt bp js-semgrep-sample-build ${{ github.run_number }}
+ ```
+- **Run Semgrep Scan:**
+ ```bash
+ semgrep scan -q --sarif --config auto ./examples/semgrep/js > semgrep-results.sarif
+ ```
+- **Attach Evidence:**
+ ```bash
+ jf evd create \
+ --package-name js-semgrep-sample-build \
+ --package-version "0.0.1" \
+ --package-repo-name javascript-local \
+ --key "${{ secrets.PRIVATE_KEY }}" \
+ --key-alias "${{ vars.EVIDENCE_KEY_ALIAS }}" \
+ --predicate "results-javascript/javascript.sarif" \
+ --predicate-type "http://semgrep.com/security-scan/v1" \
+ ${{ env.ATTACH_OPTIONAL_CUSTOM_MARKDOWN_TO_EVIDENCE == 'true' && '--markdown "results-javascript/javascript-report.md"' || '' }}
+ ```
+
+## References
+
+- [Semgrep Documentation](https://semgrep.dev/docs/)
+- [JFrog Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management)
+- [JFrog CLI Documentation](https://jfrog.com/getcli/)
\ No newline at end of file
diff --git a/examples/semgrep/js/index.js b/examples/semgrep/js/index.js
new file mode 100644
index 0000000..aca1f31
--- /dev/null
+++ b/examples/semgrep/js/index.js
@@ -0,0 +1,3 @@
+export function evaluate(a, b, operation) {
+ return eval(`(${a}) ${operation} (${b})`);
+}
\ No newline at end of file
diff --git a/examples/semgrep/js/package.json b/examples/semgrep/js/package.json
new file mode 100644
index 0000000..a78f482
--- /dev/null
+++ b/examples/semgrep/js/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "js-semgrep-sample-build",
+ "version": "0.0.1",
+ "description": "Dummy package for testing semgrep",
+ "main": "index.js",
+ "scripts": {
+ },
+ "keywords": [],
+ "author": "JFrog",
+ "license": "ISC"
+}
diff --git a/examples/semgrep/sarif_to_markdown.py b/examples/semgrep/sarif_to_markdown.py
new file mode 100644
index 0000000..60bb1d0
--- /dev/null
+++ b/examples/semgrep/sarif_to_markdown.py
@@ -0,0 +1,47 @@
+import json
+from datetime import datetime
+
+def convert_sarif_to_markdown(input_file, output_file):
+ """
+ Converts a SARIF file to a Markdown file with tabular formatting for results.
+
+ Args:
+ input_file (str): Path to the input SARIF file.
+ output_file (str): Path to the output Markdown file.
+ """
+ with open(input_file, 'r') as f:
+ sarif_data = json.load(f)
+
+ markdown_lines = ["# SARIF Analysis Report", ""]
+
+ # 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 sarif_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 sarif_to_markdown.py ")
+ sys.exit(1)
+
+ input_sarif = sys.argv[1]
+ output_md = sys.argv[2]
+ convert_sarif_to_markdown(input_sarif, output_md)