Skip to content
Closed
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
53 changes: 53 additions & 0 deletions examples/gitlab-sbom-example/.gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
image: docker:stable

services:
- docker:dind

variables:
REPO_NAME: "docker-sample"
BUILD_NAME: "gitlab-evidence-docker-build"
BUILD_NUMBER: "${CI_PIPELINE_ID}"
PACKAGE_NAME: "gitlab-evidence-app"
PACKAGE_VERSION: "${CI_COMMIT_SHORT_SHA}"
PREDICATE_FILE: "./gl-sbom-report.cdx.json"
PREDICATE_TYPE: "https://cyclonedx.org/schema"
DOCKER_IMAGE_NAME_WITH_TAG: ${REGISTRY_URL}/${REPO_NAME}/${PACKAGE_NAME}:${CI_COMMIT_SHORT_SHA}
MARKDOWN_FILE: "GitLab_SBOM.md"

stages:
- build_and_push
- container_scanning
- create_md_file_and_attach_evidence

build_and_push:
stage: build_and_push
before_script:
- apk update
- apk add go curl
- curl -fL https://install-cli.jfrog.io | sh
- jf config add --url ${ARTIFACTORY_URL} --access-token ${ARTIFACTORY_ACCESS_TOKEN} --interactive=false
script:
- docker build -f ./Dockerfile -t $DOCKER_IMAGE_NAME_WITH_TAG ./
- jf rt docker-push ${DOCKER_IMAGE_NAME_WITH_TAG} $REPO_NAME --build-name=$BUILD_NAME --build-number=${BUILD_NUMBER}
- jf rt build-publish ${BUILD_NAME} ${BUILD_NUMBER}

include:
- template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
stage: container_scanning
variables:
CS_IMAGE: ${DOCKER_IMAGE_NAME_WITH_TAG}
CS_REGISTRY_USER: ${REGISTRY_USER}
CS_REGISTRY_PASSWORD: ${REGISTRY_PASSWORD}

create_md_file_and_attach_evidence:
stage: create_md_file_and_attach_evidence
before_script:
- apk update
- apk add python3 py3-pip go curl
- curl -fL https://install-cli.jfrog.io | sh
- jf config add --url ${ARTIFACTORY_URL} --access-token ${ARTIFACTORY_ACCESS_TOKEN} --interactive=false
script:
- python3 json-to-md.py
- jf evd create --package-name="${PACKAGE_NAME}" --package-version="${PACKAGE_VERSION}" --package-repo-name="${REPO_NAME}" --key="${PRIVATE_KEY}" --key-alias="${PRIVATE_KEY_ALIAS}" --predicate="${PREDICATE_FILE}" --predicate-type="${PREDICATE_TYPE}" --markdown="${MARKDOWN_FILE}"
18 changes: 18 additions & 0 deletions examples/gitlab-sbom-example/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Use Alpine Linux 3.18 as the base image
FROM alpine:3.18
#
## Set the working directory
WORKDIR /app
#
## Copy requirements.txt if needed (uncomment if using Python/Ansible)
COPY ./requirements.txt .
#
## Install Python3, pip, and Ansible
RUN apk update && \
apk add --no-cache python3 py3-pip ansible
#
## (Optional) Install Python dependencies
RUN pip3 install --no-cache-dir -r requirements.txt
#
## Default command (prints Ansible version)
CMD ["ansible", "--version"]
77 changes: 77 additions & 0 deletions examples/gitlab-sbom-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# GitLab SBOM Evidence Example

This project demonstrates how to automate Docker image builds, generate SBOM (Software Bill of Materials) reports, convert them to Markdown, and attach the signed SBOM evidence to the Docker image in JFrog Artifactory using GitLab CI/CD and JFrog CLI.

## Overview

The pipeline builds a Docker image, generates a CycloneDX SBOM, converts the SBOM JSON to Markdown, pushes the image to Artifactory, and attaches the signed SBOM as evidence to the image package. This enables traceability and compliance for your container images in CI/CD.

## Prerequisites

- JFrog CLI 2.65.0 or above (installed automatically in the pipeline)
- Artifactory configured as a Docker registry
- The following GitLab CI/CD variables:
- `REGISTRY_URL` (Artifactory Docker registry domain, e.g. `mycompany.jfrog.io`)
- `ARTIFACTORY_URL` (Artifactory base URL)
- `ARTIFACTORY_ACCESS_TOKEN` (Artifactory access token)
- `REGISTRY_USER` (Docker registry user)
- `REGISTRY_PASSWORD` (Docker registry password)
- `PRIVATE_KEY` (Private key for signing evidence)
- `PRIVATE_KEY_ALIAS` (Key alias for signing evidence)

## Environment Variables Used

- `REPO_NAME` - Docker repository name
- `BUILD_NAME` - Build name for Artifactory
- `BUILD_NUMBER` - Build number (uses GitLab pipeline ID)
- `PACKAGE_NAME` - Docker image name
- `PACKAGE_VERSION` - Docker image tag (uses Git commit short SHA)
- `PREDICATE_FILE` - Path to SBOM JSON file
- `PREDICATE_TYPE` - Predicate type URL for SBOM
- `DOCKER_IMAGE_NAME_WITH_TAG` - Full Docker image name with tag
- `MARKDOWN_FILE` - Path to the generated Markdown file from SBOM

## Pipeline Stages

1. **Build and Push Docker Image**
- Builds the Docker image using the provided Dockerfile and pushes it to Artifactory.
2. **Container Scanning**
- Scans the pushed Docker image for vulnerabilities.
3. **Generate Markdown from SBOM and Attach Evidence**
- Converts the CycloneDX SBOM JSON to Markdown.
- Attaches the SBOM (JSON and Markdown) as signed evidence to the Docker image package in Artifactory.
-
## Example Usage

Trigger the pipeline in GitLab CI/CD. The pipeline will:

- Build and push the Docker image
- Generate and convert the SBOM
- Push the image to Artifactory
- Attach the SBOM as evidence

## Key Commands Used

- **Build Docker Image:**
```bash
docker build -f ./examples/gitlab-sbom/Dockerfile -t $DOCKER_IMAGE_NAME_WITH_TAG ./examples/gitlab-sbom
```
- **Push Docker Image:**
```bash
jf rt docker-push $DOCKER_IMAGE_NAME_WITH_TAG $REPO_NAME --build-name=$BUILD_NAME --build-number=$BUILD_NUMBER
```
- **Convert SBOM JSON to Markdown:**
```bash
python3 json-to-md.py
```
- **Attach Evidence:**
```bash
jf evd create --package-name="${PACKAGE_NAME}" --package-version="${PACKAGE_VERSION}" --package-repo-name="${REPO_NAME}" --key="${PRIVATE_KEY}" --key-alias="${PRIVATE_KEY_ALIAS}" --predicate="${PREDICATE_FILE}" --predicate-type="${PREDICATE_TYPE}" --markdown="${MARKDOWN_FILE}"
```

## References

- [Gitlab Container Scanning](https://docs.gitlab.com/user/application_security/container_scanning/)
- [CycloneDX SBOM Specification](https://cyclonedx.org/)
- [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/gitlab-sbom-example/json-to-md.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import json

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

name = data.get('metadata', {}).get('component', {}).get('name', 'N/A')
timestamp = data.get('metadata', {}).get('timestamp', 'N/A')
tools = data.get('metadata', {}).get('tools', {}).get('components', [])
components = data.get('components', [])
dependencies = data.get('dependencies', [])

with open(md_path, 'w') as f:
f.write(f"# SBOM Summary\n\n")
f.write(f"**Component Name:** {name}\n\n")
f.write(f"**Timestamp:** {timestamp}\n\n")
f.write(f"## Tools Used\n")
if tools:
for tool in tools:
tool_name = tool.get('name', 'Unknown Tool')
tool_version = tool.get('version', 'Unknown Version')
f.write(f"- {tool_name} (version: {tool_version})\n")
else:
f.write("No tool information found.\n")
f.write(f"\n## Components\n")
if components:
f.write("| bom-ref | name | version |\n")
f.write("|---|---|---|\n")
for comp in components:
bom_ref = comp.get('bom-ref', 'N/A').replace('|', '\\|')
comp_name = comp.get('name', 'N/A').replace('|', '\\|')
comp_version = comp.get('version', 'N/A').replace('|', '\\|')
f.write(f"| {bom_ref} | {comp_name} | {comp_version} |\n")
else:
f.write("No components found.\n")

f.write(f"\n## Dependencies\n")
if dependencies:
f.write("| Reference | DependsOn |\n")
f.write("|---|---|\n")
for dep in dependencies:
ref = dep.get('ref', 'N/A').replace('|', '\\|')
dependson = dep.get('dependsOn', [])
dependson_str = ', '.join(d.replace('|', '\\|') for d in dependson) if dependson else ''
f.write(f"| {ref} | {dependson_str} |\n")
else:
f.write("No dependencies found.\n")
print(f"Markdown file generated at: {md_path}")


if __name__ == "__main__":
json_to_md('./gl-sbom-report.cdx.json', 'GitLab_SBOM.md')
1 change: 1 addition & 0 deletions examples/gitlab-sbom-example/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ansible==2.9.9
53 changes: 53 additions & 0 deletions examples/gitlab-sbom/.gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
image: docker:stable

services:
- docker:dind

variables:
REPO_NAME: "docker-sample"
BUILD_NAME: "gitlab-evidence-docker-build"
BUILD_NUMBER: "${CI_PIPELINE_ID}"
PACKAGE_NAME: "gitlab-evidence-app"
PACKAGE_VERSION: "${CI_COMMIT_SHORT_SHA}"
PREDICATE_FILE: "./gl-sbom-report.cdx.json"
PREDICATE_TYPE: "https://cyclonedx.org/schema"
DOCKER_IMAGE_NAME_WITH_TAG: ${REGISTRY_URL}/${REPO_NAME}/${PACKAGE_NAME}:${CI_COMMIT_SHORT_SHA}
MARKDOWN_FILE: "GitLab_SBOM.md"

stages:
- build_and_push
- container_scanning
- create_md_file_and_attach_evidence

build_and_push:
stage: build_and_push
before_script:
- apk update
- apk add go curl
- curl -fL https://install-cli.jfrog.io | sh
- jf config add --url ${ARTIFACTORY_URL} --access-token ${ARTIFACTORY_ACCESS_TOKEN} --interactive=false
script:
- docker build -f ./Dockerfile -t $DOCKER_IMAGE_NAME_WITH_TAG ./
- jf rt docker-push ${DOCKER_IMAGE_NAME_WITH_TAG} $REPO_NAME --build-name=$BUILD_NAME --build-number=${BUILD_NUMBER}
- jf rt build-publish ${BUILD_NAME} ${BUILD_NUMBER}

include:
- template: Jobs/Container-Scanning.gitlab-ci.yml

container_scanning:
stage: container_scanning
variables:
CS_IMAGE: ${DOCKER_IMAGE_NAME_WITH_TAG}
CS_REGISTRY_USER: ${REGISTRY_USER}
CS_REGISTRY_PASSWORD: ${REGISTRY_PASSWORD}

create_md_file_and_attach_evidence:
stage: create_md_file_and_attach_evidence
before_script:
- apk update
- apk add python3 py3-pip go curl
- curl -fL https://install-cli.jfrog.io | sh
- jf config add --url ${ARTIFACTORY_URL} --access-token ${ARTIFACTORY_ACCESS_TOKEN} --interactive=false
script:
- python3 json-to-md.py
- jf evd create --package-name="${PACKAGE_NAME}" --package-version="${PACKAGE_VERSION}" --package-repo-name="${REPO_NAME}" --key="${PRIVATE_KEY}" --key-alias="${PRIVATE_KEY_ALIAS}" --predicate="${PREDICATE_FILE}" --predicate-type="${PREDICATE_TYPE}" --markdown="${MARKDOWN_FILE}"
18 changes: 18 additions & 0 deletions examples/gitlab-sbom/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Use Alpine Linux 3.18 as the base image
FROM alpine:3.18
#
## Set the working directory
WORKDIR /app
#
## Copy requirements.txt if needed (uncomment if using Python/Ansible)
COPY ./requirements.txt .
#
## Install Python3, pip, and Ansible
RUN apk update && \
apk add --no-cache python3 py3-pip ansible
#
## (Optional) Install Python dependencies
RUN pip3 install --no-cache-dir -r requirements.txt
#
## Default command (prints Ansible version)
CMD ["ansible", "--version"]
77 changes: 77 additions & 0 deletions examples/gitlab-sbom/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# GitLab SBOM Evidence Example

This project demonstrates how to automate Docker image builds, generate SBOM (Software Bill of Materials) reports, convert them to Markdown, and attach the signed SBOM evidence to the Docker image in JFrog Artifactory using GitLab CI/CD and JFrog CLI.

## Overview

The pipeline builds a Docker image, generates a CycloneDX SBOM, converts the SBOM JSON to Markdown, pushes the image to Artifactory, and attaches the signed SBOM as evidence to the image package. This enables traceability and compliance for your container images in CI/CD.

## Prerequisites

- JFrog CLI 2.65.0 or above (installed automatically in the pipeline)
- Artifactory configured as a Docker registry
- The following GitLab CI/CD variables:
- `REGISTRY_URL` (Artifactory Docker registry domain, e.g. `mycompany.jfrog.io`)
- `ARTIFACTORY_URL` (Artifactory base URL)
- `ARTIFACTORY_ACCESS_TOKEN` (Artifactory access token)
- `REGISTRY_USER` (Docker registry user)
- `REGISTRY_PASSWORD` (Docker registry password)
- `PRIVATE_KEY` (Private key for signing evidence)
- `PRIVATE_KEY_ALIAS` (Key alias for signing evidence)

## Environment Variables Used

- `REPO_NAME` - Docker repository name
- `BUILD_NAME` - Build name for Artifactory
- `BUILD_NUMBER` - Build number (uses GitLab pipeline ID)
- `PACKAGE_NAME` - Docker image name
- `PACKAGE_VERSION` - Docker image tag (uses Git commit short SHA)
- `PREDICATE_FILE` - Path to SBOM JSON file
- `PREDICATE_TYPE` - Predicate type URL for SBOM
- `DOCKER_IMAGE_NAME_WITH_TAG` - Full Docker image name with tag
- `MARKDOWN_FILE` - Path to the generated Markdown file from SBOM

## Pipeline Stages

1. **Build and Push Docker Image**
- Builds the Docker image using the provided Dockerfile and pushes it to Artifactory.
2. **Container Scanning**
- Scans the pushed Docker image for vulnerabilities.
3. **Generate Markdown from SBOM and Attach Evidence**
- Converts the CycloneDX SBOM JSON to Markdown.
- Attaches the SBOM (JSON and Markdown) as signed evidence to the Docker image package in Artifactory.
-
## Example Usage

Trigger the pipeline in GitLab CI/CD. The pipeline will:

- Build and push the Docker image
- Generate and convert the SBOM
- Push the image to Artifactory
- Attach the SBOM as evidence

## Key Commands Used

- **Build Docker Image:**
```bash
docker build -f ./examples/gitlab-sbom/Dockerfile -t $DOCKER_IMAGE_NAME_WITH_TAG ./examples/gitlab-sbom
```
- **Push Docker Image:**
```bash
jf rt docker-push $DOCKER_IMAGE_NAME_WITH_TAG $REPO_NAME --build-name=$BUILD_NAME --build-number=$BUILD_NUMBER
```
- **Convert SBOM JSON to Markdown:**
```bash
python3 json-to-md.py
```
- **Attach Evidence:**
```bash
jf evd create --package-name="${PACKAGE_NAME}" --package-version="${PACKAGE_VERSION}" --package-repo-name="${REPO_NAME}" --key="${PRIVATE_KEY}" --key-alias="${PRIVATE_KEY_ALIAS}" --predicate="${PREDICATE_FILE}" --predicate-type="${PREDICATE_TYPE}" --markdown="${MARKDOWN_FILE}"
```

## References

- [Gitlab Container Scanning](https://docs.gitlab.com/user/application_security/container_scanning/)
- [CycloneDX SBOM Specification](https://cyclonedx.org/)
- [JFrog Evidence Management](https://jfrog.com/help/r/jfrog-artifactory-documentation/evidence-management)
- [JFrog CLI Documentation](https://jfrog.com/getcli/)
Loading