Skip to content

Commit a3e833b

Browse files
committed
go
Signed-off-by: Julio Jimenez <julio@clickhouse.com>
1 parent e0baeaa commit a3e833b

8 files changed

Lines changed: 1211 additions & 0 deletions

File tree

cmd/clickbom/main.go

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/ClickHouse/ClickBOM/internal/config"
9+
"github.com/ClickHouse/ClickBOM/internal/sbom"
10+
"github.com/ClickHouse/ClickBOM/internal/storage"
11+
"github.com/ClickHouse/ClickBOM/pkg/logger"
12+
)
13+
14+
func main() {
15+
if err := run(); err != nil {
16+
logger.Fatal("Application error: %v", err)
17+
}
18+
}
19+
20+
func run() error {
21+
logger.Info("Starting ClickBOM GitHub Action for SBOM processing")
22+
23+
// Load and validate configuration
24+
cfg, err := config.LoadConfig()
25+
if err != nil {
26+
return fmt.Errorf("configuration error: %w", err)
27+
}
28+
29+
logger.SetDebug(cfg.Debug)
30+
31+
ctx := context.Background()
32+
33+
// Create temp directory
34+
tempDir, err := os.MkdirTemp("", "clickbom-*")
35+
if err != nil {
36+
return fmt.Errorf("failed to create temp directory: %w", err)
37+
}
38+
defer os.RemoveAll(tempDir)
39+
40+
// Initialize S3 client
41+
s3Client, err := storage.NewS3Client(ctx, cfg.AWSAccessKeyID, cfg.AWSSecretAccessKey, cfg.AWSRegion)
42+
if err != nil {
43+
return fmt.Errorf("failed to create S3 client: %w", err)
44+
}
45+
46+
if cfg.Merge {
47+
return handleMergeMode(ctx, cfg, s3Client, tempDir)
48+
}
49+
50+
return handleNormalMode(ctx, cfg, s3Client, tempDir)
51+
}
52+
53+
func handleNormalMode(ctx context.Context, cfg *config.Config, s3Client *storage.S3Client, tempDir string) error {
54+
logger.Info("Running in NORMAL mode - processing SBOM from %s", cfg.SBOMSource)
55+
56+
originalSBOM := filepath.Join(tempDir, "original_sbom.json")
57+
extractedSBOM := filepath.Join(tempDir, "extracted_sbom.json")
58+
processedSBOM := filepath.Join(tempDir, "processed_sbom.json")
59+
60+
// Download SBOM based on source
61+
switch cfg.SBOMSource {
62+
case "github":
63+
logger.Info("Downloading SBOM from GitHub")
64+
ghClient := sbom.NewGitHubClient(cfg.GitHubToken)
65+
if err := ghClient.DownloadSBOM(ctx, cfg.Repository, originalSBOM); err != nil {
66+
return fmt.Errorf("failed to download GitHub SBOM: %w", err)
67+
}
68+
69+
case "mend":
70+
logger.Info("Downloading SBOM from Mend")
71+
mendClient := sbom.NewMendClient(cfg)
72+
if err := mendClient.RequestSBOMExport(ctx, originalSBOM); err != nil {
73+
return fmt.Errorf("failed to download Mend SBOM: %w", err)
74+
}
75+
76+
case "wiz":
77+
logger.Info("Downloading SBOM from Wiz")
78+
wizClient := sbom.NewWizClient(cfg)
79+
if err := wizClient.DownloadReport(ctx, originalSBOM); err != nil {
80+
return fmt.Errorf("failed to download Wiz SBOM: %w", err)
81+
}
82+
83+
default:
84+
return fmt.Errorf("unsupported SBOM source: %s", cfg.SBOMSource)
85+
}
86+
87+
// Extract from wrapper if needed
88+
if err := sbom.ExtractSBOMFromWrapper(originalSBOM, extractedSBOM); err != nil {
89+
return fmt.Errorf("failed to extract SBOM: %w", err)
90+
}
91+
92+
// Detect format
93+
detectedFormat, err := sbom.DetectSBOMFormat(extractedSBOM)
94+
if err != nil {
95+
return fmt.Errorf("failed to detect SBOM format: %w", err)
96+
}
97+
logger.Info("Detected SBOM format: %s", detectedFormat)
98+
99+
// Convert to desired format
100+
targetFormat := sbom.SBOMFormat(cfg.SBOMFormat)
101+
if err := sbom.ConvertSBOM(extractedSBOM, processedSBOM, detectedFormat, targetFormat); err != nil {
102+
return fmt.Errorf("failed to convert SBOM: %w", err)
103+
}
104+
105+
// Upload to S3
106+
if err := s3Client.Upload(ctx, processedSBOM, cfg.S3Bucket, cfg.S3Key, cfg.SBOMFormat); err != nil {
107+
return fmt.Errorf("failed to upload to S3: %w", err)
108+
}
109+
110+
logger.Success("SBOM processing completed successfully!")
111+
logger.Info("SBOM available at: s3://%s/%s", cfg.S3Bucket, cfg.S3Key)
112+
113+
// ClickHouse operations
114+
if cfg.ClickHouseURL != "" {
115+
if err := handleClickHouse(ctx, cfg, processedSBOM); err != nil {
116+
return fmt.Errorf("ClickHouse error: %w", err)
117+
}
118+
}
119+
120+
return nil
121+
}
122+
123+
func handleMergeMode(ctx context.Context, cfg *config.Config, s3Client *storage.S3Client, tempDir string) error {
124+
logger.Info("Running in MERGE mode - merging all CycloneDX SBOMs from S3")
125+
126+
// Implementation for merge mode...
127+
// This would involve downloading all SBOMs from S3, merging them, and uploading
128+
129+
return nil
130+
}
131+
132+
func handleClickHouse(ctx context.Context, cfg *config.Config, sbomFile string) error {
133+
logger.Info("Starting ClickHouse operations")
134+
135+
chClient, err := storage.NewClickHouseClient(cfg)
136+
if err != nil {
137+
return err
138+
}
139+
140+
tableName := generateTableName(cfg)
141+
142+
if err := chClient.SetupTable(ctx, tableName); err != nil {
143+
return fmt.Errorf("failed to setup table: %w", err)
144+
}
145+
146+
if err := chClient.InsertSBOMData(ctx, sbomFile, tableName, cfg.SBOMFormat); err != nil {
147+
return fmt.Errorf("failed to insert data: %w", err)
148+
}
149+
150+
logger.Success("ClickHouse operations completed successfully!")
151+
return nil
152+
}
153+
154+
func generateTableName(cfg *config.Config) string {
155+
switch cfg.SBOMSource {
156+
case "github":
157+
return strings.ReplaceAll(strings.ToLower(cfg.Repository), "/", "_")
158+
case "mend":
159+
uuid := cfg.MendProjectUUID
160+
if uuid == "" {
161+
uuid = cfg.MendProductUUID
162+
}
163+
return fmt.Sprintf("mend_%s", strings.ReplaceAll(uuid, "-", "_"))
164+
case "wiz":
165+
return fmt.Sprintf("wiz_%s", strings.ReplaceAll(cfg.WizReportID, "-", "_"))
166+
default:
167+
return "sbom_data"
168+
}
169+
}

0 commit comments

Comments
 (0)