186 lines
4.9 KiB
Bash
186 lines
4.9 KiB
Bash
#!/bin/bash
|
|
# Copyright (c) StellaOps. All rights reserved.
|
|
# Licensed under the BUSL-1.1 license.
|
|
#
|
|
# generate-slsa-provenance.sh
|
|
# Generates SLSA v1.0 provenance statements for release artifacts
|
|
#
|
|
# Usage: ./generate-slsa-provenance.sh --version <version> --commit <sha> --output <dir>
|
|
|
|
set -euo pipefail
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Default values
|
|
VERSION=""
|
|
COMMIT=""
|
|
OUTPUT_DIR="provenance"
|
|
ARTIFACTS_DIR="artifacts"
|
|
BUILDER_ID="${BUILDER_ID:-https://ci.stella-ops.org/builder/v1}"
|
|
BUILD_TYPE="${BUILD_TYPE:-https://stella-ops.io/ReleaseBuilder/v1}"
|
|
REPOSITORY_URI="${REPOSITORY_URI:-git+https://git.stella-ops.org/stella-ops.org/git.stella-ops.org}"
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--version)
|
|
VERSION="$2"
|
|
shift 2
|
|
;;
|
|
--commit)
|
|
COMMIT="$2"
|
|
shift 2
|
|
;;
|
|
--output)
|
|
OUTPUT_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--artifacts)
|
|
ARTIFACTS_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--builder-id)
|
|
BUILDER_ID="$2"
|
|
shift 2
|
|
;;
|
|
--build-type)
|
|
BUILD_TYPE="$2"
|
|
shift 2
|
|
;;
|
|
--help)
|
|
echo "Usage: $0 --version <version> --commit <sha> --output <dir>"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --version Release version (required)"
|
|
echo " --commit Git commit SHA (required)"
|
|
echo " --output Output directory for provenance files (default: provenance)"
|
|
echo " --artifacts Directory containing release artifacts (default: artifacts)"
|
|
echo " --builder-id Builder ID URI (default: https://ci.stella-ops.org/builder/v1)"
|
|
echo " --build-type Build type URI (default: https://stella-ops.io/ReleaseBuilder/v1)"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo -e "${RED}Unknown option: $1${NC}"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Validate required arguments
|
|
if [[ -z "$VERSION" ]]; then
|
|
echo -e "${RED}Error: --version is required${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "$COMMIT" ]]; then
|
|
echo -e "${RED}Error: --commit is required${NC}"
|
|
exit 1
|
|
fi
|
|
|
|
# Create output directory
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
# Get timestamps
|
|
STARTED_ON="${BUILD_STARTED_ON:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}"
|
|
FINISHED_ON="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
|
|
# Get invocation ID from CI environment
|
|
INVOCATION_ID="${CI_JOB_ID:-${GITHUB_RUN_ID:-$(uuidgen || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "local-build")}}"
|
|
|
|
echo -e "${GREEN}Generating SLSA v1.0 provenance for version ${VERSION}${NC}"
|
|
echo " Commit: ${COMMIT}"
|
|
echo " Builder: ${BUILDER_ID}"
|
|
echo " Output: ${OUTPUT_DIR}"
|
|
|
|
# Function to generate provenance for a single artifact
|
|
generate_provenance() {
|
|
local artifact_path="$1"
|
|
local artifact_name
|
|
artifact_name=$(basename "$artifact_path")
|
|
|
|
# Compute SHA-256 digest
|
|
local sha256
|
|
sha256=$(sha256sum "$artifact_path" | cut -d' ' -f1)
|
|
|
|
# Determine component name from artifact
|
|
local component_name
|
|
component_name=$(echo "$artifact_name" | sed -E 's/stella-([^-]+).*/\1/')
|
|
|
|
local output_file="${OUTPUT_DIR}/${component_name}.slsa.intoto.jsonl"
|
|
|
|
echo " Generating provenance for: ${artifact_name}"
|
|
|
|
# Generate SLSA v1.0 provenance statement
|
|
cat > "$output_file" << EOF
|
|
{
|
|
"_type": "https://in-toto.io/Statement/v1",
|
|
"subject": [
|
|
{
|
|
"name": "${artifact_name}",
|
|
"digest": {
|
|
"sha256": "${sha256}"
|
|
}
|
|
}
|
|
],
|
|
"predicateType": "https://slsa.dev/provenance/v1",
|
|
"predicate": {
|
|
"buildDefinition": {
|
|
"buildType": "${BUILD_TYPE}",
|
|
"externalParameters": {
|
|
"version": "${VERSION}",
|
|
"repository": "${REPOSITORY_URI}",
|
|
"ref": "refs/tags/v${VERSION}"
|
|
},
|
|
"internalParameters": {},
|
|
"resolvedDependencies": [
|
|
{
|
|
"uri": "${REPOSITORY_URI}@refs/tags/v${VERSION}",
|
|
"digest": {
|
|
"gitCommit": "${COMMIT}"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"runDetails": {
|
|
"builder": {
|
|
"id": "${BUILDER_ID}",
|
|
"version": {
|
|
"stellaOps": "${VERSION}"
|
|
}
|
|
},
|
|
"metadata": {
|
|
"invocationId": "${INVOCATION_ID}",
|
|
"startedOn": "${STARTED_ON}",
|
|
"finishedOn": "${FINISHED_ON}"
|
|
},
|
|
"byproducts": []
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
|
|
echo -e " ${GREEN}Created: ${output_file}${NC}"
|
|
}
|
|
|
|
# Find and process artifacts
|
|
artifact_count=0
|
|
for artifact in "${ARTIFACTS_DIR}"/stella-*.tar.gz "${ARTIFACTS_DIR}"/stella-*.zip; do
|
|
if [[ -f "$artifact" ]]; then
|
|
generate_provenance "$artifact"
|
|
((artifact_count++))
|
|
fi
|
|
done
|
|
|
|
if [[ $artifact_count -eq 0 ]]; then
|
|
echo -e "${YELLOW}Warning: No artifacts found in ${ARTIFACTS_DIR}${NC}"
|
|
exit 0
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${GREEN}Generated ${artifact_count} provenance statement(s)${NC}"
|
|
echo "Files written to: ${OUTPUT_DIR}/"
|