1+ #! /bin/bash
2+
3+ set -euo pipefail
4+
5+ # Colors for output
6+ RED=' \033[0;31m'
7+ GREEN=' \033[0;32m'
8+ YELLOW=' \033[1;33m'
9+ BLUE=' \033[0;34m'
10+ NC=' \033[0m' # No Color
11+
12+ # Logging functions
13+ log_info () {
14+ echo -e " ${BLUE} [INFO]${NC} $1 "
15+ }
16+
17+ log_success () {
18+ echo -e " ${GREEN} [SUCCESS]${NC} $1 "
19+ }
20+
21+ log_warning () {
22+ echo -e " ${YELLOW} [WARNING]${NC} $1 "
23+ }
24+
25+ log_error () {
26+ echo -e " ${RED} [ERROR]${NC} $1 "
27+ }
28+
29+ # Validate required environment variables
30+ validate_env () {
31+ local required_vars=(" GITHUB_TOKEN" " AWS_ACCESS_KEY_ID" " AWS_SECRET_ACCESS_KEY" " S3_BUCKET" " REPOSITORY" )
32+
33+ for var in " ${required_vars[@]} " ; do
34+ if [[ -z " ${! var:- } " ]]; then
35+ log_error " Required environment variable $var is not set"
36+ exit 1
37+ fi
38+ done
39+ }
40+
41+ # Download SBOM from GitHub repository
42+ download_sbom () {
43+ local repo=" $1 "
44+ local sbom_path=" $2 "
45+ local ref=" $3 "
46+ local output_file=" $4 "
47+
48+ log_info " Downloading SBOM from $repo at $ref :$sbom_path "
49+
50+ # GitHub API URL for file content
51+ local api_url=" https://api.github.com/repos/$repo /contents/$sbom_path "
52+
53+ # Add ref parameter if not default
54+ if [[ " $ref " != " main" ]]; then
55+ api_url=" $api_url ?ref=$ref "
56+ fi
57+
58+ # Download file metadata to get download URL
59+ local response
60+ response=$( curl -s -H " Authorization: token $GITHUB_TOKEN " \
61+ -H " Accept: application/vnd.github.v3+json" \
62+ " $api_url " )
63+
64+ # Check if API call was successful
65+ if ! echo " $response " | jq -e ' .download_url' > /dev/null 2>&1 ; then
66+ log_error " Failed to get SBOM file information from GitHub API"
67+ log_error " Response: $response "
68+ exit 1
69+ fi
70+
71+ # Extract download URL
72+ local download_url
73+ download_url=$( echo " $response " | jq -r ' .download_url' )
74+
75+ # Download the actual file
76+ if curl -s -H " Authorization: token $GITHUB_TOKEN " \
77+ -L " $download_url " \
78+ -o " $output_file " ; then
79+ log_success " SBOM downloaded successfully"
80+ else
81+ log_error " Failed to download SBOM file"
82+ exit 1
83+ fi
84+ }
85+
86+ # Detect SBOM format
87+ detect_sbom_format () {
88+ local sbom_file=" $1 "
89+
90+ if ! [[ -f " $sbom_file " ]]; then
91+ log_error " SBOM file not found: $sbom_file "
92+ exit 1
93+ fi
94+
95+ # Check if it's already CycloneDX format
96+ if jq -e ' .bomFormat // .metadata.component' " $sbom_file " > /dev/null 2>&1 ; then
97+ local format
98+ format=$( jq -r ' .bomFormat // "cyclonedx"' " $sbom_file " 2> /dev/null || echo " unknown" )
99+
100+ if [[ " $format " == " CycloneDX" ]] || jq -e ' .metadata.component' " $sbom_file " > /dev/null 2>&1 ; then
101+ echo " cyclonedx"
102+ return
103+ fi
104+ fi
105+
106+ # Check if it's SPDX format
107+ if jq -e ' .spdxVersion // .SPDXID' " $sbom_file " > /dev/null 2>&1 ; then
108+ echo " spdx"
109+ return
110+ fi
111+
112+ # Check if it's SWID format (basic check)
113+ if jq -e ' .SoftwareIdentity' " $sbom_file " > /dev/null 2>&1 ; then
114+ echo " swid"
115+ return
116+ fi
117+
118+ log_warning " Unable to detect SBOM format, assuming SPDX"
119+ echo " spdx"
120+ }
121+
122+ # Convert SBOM to CycloneDX format
123+ convert_to_cyclonedx () {
124+ local input_file=" $1 "
125+ local output_file=" $2 "
126+ local format=" $3 "
127+
128+ case " $format " in
129+ " cyclonedx" )
130+ log_info " SBOM is already in CycloneDX format"
131+ cp " $input_file " " $output_file "
132+ ;;
133+ " spdx" )
134+ log_info " Converting SPDX SBOM to CycloneDX format"
135+ if cyclonedx-py convert --input-file " $input_file " --output-file " $output_file " --output-format json; then
136+ log_success " SBOM converted to CycloneDX format"
137+ else
138+ log_error " Failed to convert SBOM to CycloneDX format"
139+ exit 1
140+ fi
141+ ;;
142+ * )
143+ log_warning " Unsupported format '$format ', attempting conversion anyway"
144+ if cyclonedx-py convert --input-file " $input_file " --output-file " $output_file " --output-format json; then
145+ log_success " SBOM converted to CycloneDX format"
146+ else
147+ log_error " Failed to convert SBOM to CycloneDX format"
148+ exit 1
149+ fi
150+ ;;
151+ esac
152+ }
153+
154+ # Upload to S3
155+ upload_to_s3 () {
156+ local local_file=" $1 "
157+ local s3_bucket=" $2 "
158+ local s3_key=" $3 "
159+
160+ log_info " Uploading CycloneDX SBOM to s3://$s3_bucket /$s3_key "
161+
162+ if aws s3 cp " $local_file " " s3://$s3_bucket /$s3_key " \
163+ --content-type " application/json" \
164+ --metadata " format=cyclonedx,source=github-action" ; then
165+ log_success " SBOM uploaded successfully to S3"
166+ else
167+ log_error " Failed to upload SBOM to S3"
168+ exit 1
169+ fi
170+ }
171+
172+ # Main function
173+ main () {
174+ log_info " Starting ClickBOM GitHub Action for SBOM processing"
175+
176+ # Validate environment
177+ # validate_env
178+
179+ # Set defaults for optional variables
180+ # local sbom_path="${SBOM_PATH:-sbom.json}"
181+ # local ref="${REF:-main}"
182+ # local s3_key="${S3_KEY:-sbom/cyclonedx-sbom.json}"
183+
184+ # Temporary files
185+ # local temp_dir
186+ # temp_dir=$(mktemp -d)
187+ # local original_sbom="$temp_dir/original_sbom.json"
188+ # local cyclonedx_sbom="$temp_dir/cyclonedx_sbom.json"
189+
190+ # Cleanup function
191+ # cleanup() {
192+ # log_info "Cleaning up temporary files"
193+ # rm -rf "$temp_dir"
194+ # }
195+ # trap cleanup EXIT
196+
197+ # Download SBOM
198+ # download_sbom "$REPOSITORY" "$sbom_path" "$ref" "$original_sbom"
199+
200+ # Detect format
201+ # local format
202+ # format=$(detect_sbom_format "$original_sbom")
203+ # log_info "Detected SBOM format: $format"
204+
205+ # Convert to CycloneDX
206+ # convert_to_cyclonedx "$original_sbom" "$cyclonedx_sbom" "$format"
207+
208+ # Validate the converted file
209+ # if ! jq . "$cyclonedx_sbom" > /dev/null 2>&1; then
210+ # log_error "Generated CycloneDX SBOM is not valid JSON"
211+ # exit 1
212+ # fi
213+
214+ # Upload to S3
215+ # upload_to_s3 "$cyclonedx_sbom" "$S3_BUCKET" "$s3_key"
216+
217+ # log_success "SBOM processing completed successfully!"
218+ # log_info "CycloneDX SBOM available at: s3://$S3_BUCKET/$s3_key"
219+ # }
220+
221+ # Run main function
222+ main " $@ "
0 commit comments