From 8349344562c41e1e960e1ab9d6de3a4eb0c7b5dc Mon Sep 17 00:00:00 2001 From: Matias Daloia Date: Thu, 18 Dec 2025 10:21:56 +0100 Subject: [PATCH] feat: add download rulesets handler [SP-3798] feat: add unit tests, update changelog [SP-3798] feat: update papi version, add path validation, add checksum verification [SP-3798] fix: lint errors [SP-3798] fix: lint errors, remove tar.gz rules form .gitignore [SP-3798] chore: add ruleset description and created-at into response headers [SP-3798] chore: add metrics [SP-3798] chore: update changelog [SP-3798] chore: final adjustments [SP-3798] chore: return less verbose errors, validate rulesets directory exists on startup [SP-3798] fix: unit tests [SP-3798] fix: unit tests --- .gitignore | 2 + CHANGELOG.md | 14 +- config/app-config-dev.json | 5 +- go.mod | 6 +- go.sum | 4 +- pkg/config/server_config.go | 31 ++ pkg/config/server_config_test.go | 82 ++- pkg/handlers/algorithm_handler_test.go | 9 + .../algorithm_in_range_handler_test.go | 9 + pkg/handlers/cryptography_support.go | 7 +- pkg/handlers/encryption_hints_handler_test.go | 9 + pkg/handlers/hints_in_range_handler_test.go | 9 + pkg/handlers/ruleset_download_handler.go | 177 +++++++ pkg/handlers/ruleset_download_handler_test.go | 393 +++++++++++++++ pkg/handlers/utils_handler.go | 31 ++ .../versions_in_range_handler_test.go | 9 + pkg/models/all_urls_test.go | 15 + pkg/models/common_test.go | 4 +- pkg/models/crypto_usage_test.go | 3 + pkg/models/library_usage_test.go | 3 + pkg/service/cryptography_service.go | 11 +- pkg/service/cryptography_service_test.go | 33 ++ pkg/testutils/test_helpers.go | 49 ++ pkg/usecase/cryptography_major_test.go | 3 + pkg/usecase/cryptography_search_test.go | 3 + .../cryptography_versions_using_test.go | 5 + pkg/usecase/library_detections_test.go | 7 + pkg/usecase/ruleset_download.go | 233 +++++++++ pkg/usecase/ruleset_download_test.go | 466 ++++++++++++++++++ test-support/rulesets/dca/latest | 1 + .../rulesets/dca/v1.0.0/dca-v1.0.0.tar.gz | Bin 0 -> 75246 bytes .../rulesets/dca/v1.0.0/manifest.json | 7 + .../rulesets/dca/v1.0.1/dca-v1.0.1.tar.gz | Bin 0 -> 75246 bytes .../rulesets/dca/v1.0.1/manifest.json | 7 + 34 files changed, 1631 insertions(+), 16 deletions(-) create mode 100644 pkg/handlers/ruleset_download_handler.go create mode 100644 pkg/handlers/ruleset_download_handler_test.go create mode 100644 pkg/testutils/test_helpers.go create mode 100644 pkg/usecase/ruleset_download.go create mode 100644 pkg/usecase/ruleset_download_test.go create mode 120000 test-support/rulesets/dca/latest create mode 100644 test-support/rulesets/dca/v1.0.0/dca-v1.0.0.tar.gz create mode 100644 test-support/rulesets/dca/v1.0.0/manifest.json create mode 100644 test-support/rulesets/dca/v1.0.1/dca-v1.0.1.tar.gz create mode 100644 test-support/rulesets/dca/v1.0.1/manifest.json diff --git a/.gitignore b/.gitignore index 1ef00f3..4a4996d 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ local-build-commands.txt *.log .DS_Store + +!**/rulesets/**/*.tar.gz diff --git a/CHANGELOG.md b/CHANGELOG.md index 8024680..6721990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ ### Added - Upcoming changes... +## [0.9.0] - 2025-12-29 +### Added +- Added gRPC DownloadRuleset and REST endpoint GET /v2/cryptography/rulesets/download + - Supports downloading cryptography detection rulesets by name and version + - Supports "latest" keyword for retrieving the most recent version + - Returns tarball with appropriate HTTP headers (Content-Disposition, SCANOSS-Ruleset-Name, SCANOSS-Ruleset-Version, X-Checksum-SHA256) + - Includes metadata validation and version resolution via symlinks + +### Fixed +- Fixed OpenTelemetry metrics initialization by properly exporting SetupMetrics function + ## [0.8.1] - 2025-10-16 ### Fixed - Fixed OpenTelemetry metrics initialization by exporting SetupMetrics function and calling it on server startup @@ -96,6 +107,7 @@ - Remove from list those versions that do not contain detections - Detailed response status message. +[0.9.0]: https://github.com/scanoss/cryptography/compare/v0.8.1...v0.9.0 [0.8.1]: https://github.com/scanoss/cryptography/compare/v0.8.0...v0.8.1 [0.8.0]: https://github.com/scanoss/cryptography/compare/v0.7.1...v0.8.0 [0.7.1]: https://github.com/scanoss/cryptography/compare/v0.7.0...v0.7.1 @@ -104,4 +116,4 @@ [0.5.0]: https://github.com/scanoss/cryptography/compare/v0.4.2...v0.5.0 [0.4.2]: https://github.com/scanoss/cryptography/releases/tag/v0.4.1....v0.4.2 [0.4.1]: https://github.com/scanoss/cryptography/releases/tag/v0.4.0...v0.4.1 -[0.4.0]: https://github.com/scanoss/cryptography/releases/tag/v0.4.0 \ No newline at end of file +[0.4.0]: https://github.com/scanoss/cryptography/releases/tag/v0.4.0 diff --git a/config/app-config-dev.json b/config/app-config-dev.json index 6acd545..c5dc856 100644 --- a/config/app-config-dev.json +++ b/config/app-config-dev.json @@ -2,11 +2,14 @@ "App": { "Name": "Cryptography Service", "Debug": true, - "Mode": "dev" + "Mode": "dev" }, "Database": { "Dsn": "./test-support/sqlite/scanoss.db?cache=shared&mode=memory", "Driver": "sqlite", "Trace": true + }, + "Rulesets": { + "StoragePath": "test-support/rulesets" } } diff --git a/go.mod b/go.mod index 884183b..c761eb7 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/lib/pq v1.10.9 github.com/scanoss/go-grpc-helper v0.9.0 github.com/scanoss/go-purl-helper v0.2.1 - github.com/scanoss/papi v0.25.1 + github.com/scanoss/papi v0.27.0 github.com/scanoss/zap-logging-helper v0.4.0 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/otel v1.38.0 @@ -37,7 +37,7 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.6.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250707201910-8d1bb00bc6a7 google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect ) @@ -70,6 +70,6 @@ require ( // Details of how to use the "replace" command for local development // https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive // ie. replace github.com/scanoss/papi => ../papi -// replace github.com/scanoss/papi => ../papi +//replace github.com/scanoss/papi => ../papi // require github.com/scanoss/papi v0.0.0-unpublished diff --git a/go.sum b/go.sum index 650a00c..74ade2d 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,8 @@ github.com/scanoss/go-purl-helper v0.2.1 h1:jp960a585ycyJSlqZky1NatMJBIQi/JGITDf github.com/scanoss/go-purl-helper v0.2.1/go.mod h1:v20/bKD8G+vGrILdiq6r0hyRD2bO8frCJlu9drEcQ38= github.com/scanoss/ipfilter/v2 v2.0.2 h1:GaB9i8kVJg9JQZm5XGStYkEpiaCVdsrj7ezI2wV/oh8= github.com/scanoss/ipfilter/v2 v2.0.2/go.mod h1:AwrpX4XGbZ7EKISMi1d6E5csBk1nWB8+ugpvXHFcTpA= -github.com/scanoss/papi v0.25.1 h1:/OUoCWkrD+PRNvssSfrVcgPFFHKl3rCp/zjz0I2qNd8= -github.com/scanoss/papi v0.25.1/go.mod h1:Z4E/4IpwYdzHHRJXTgBCGG1GjksgrFjNW5cvhbKUfeU= +github.com/scanoss/papi v0.27.0 h1:raPAm9aFmcGVHdYZh+7su20R0ow+9tpI3jMDxxQaFUM= +github.com/scanoss/papi v0.27.0/go.mod h1:Z4E/4IpwYdzHHRJXTgBCGG1GjksgrFjNW5cvhbKUfeU= github.com/scanoss/zap-logging-helper v0.4.0 h1:2qTYoaFa9+MlD2/1wmPtiDHfh+42NIEwgKVU3rPpl0Y= github.com/scanoss/zap-logging-helper v0.4.0/go.mod h1:9QuEZcq73g/0Izv1tWeOWukoIK0oTBzM4jSNQ5kRR1w= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= diff --git a/pkg/config/server_config.go b/pkg/config/server_config.go index f60692e..3772816 100644 --- a/pkg/config/server_config.go +++ b/pkg/config/server_config.go @@ -17,6 +17,9 @@ package config import ( + "fmt" + "os" + "github.com/golobby/config/v3" "github.com/golobby/config/v3/pkg/feeder" ) @@ -68,6 +71,9 @@ type ServerConfig struct { BlockByDefault bool `env:"CRYPTO_BLOCK_BY_DEFAULT"` // Block request by default if they are not in the allow list TrustProxy bool `env:"CRYPTO_TRUST_PROXY"` // Trust the interim proxy or not (causes the source IP to be validated instead of the proxy) } + Rulesets struct { + StoragePath string `env:"RULESETS_STORAGE_PATH"` // Path to directory containing cryptography detection rulesets + } } // NewServerConfig loads all config options and return a struct for use. @@ -84,6 +90,9 @@ func NewServerConfig(feeders []config.Feeder) (*ServerConfig, error) { if err != nil { return nil, err } + if err := cfg.ValidateRulesetsFolder(); err != nil { + return nil, err + } return &cfg, nil } @@ -105,4 +114,26 @@ func setServerConfigDefaults(cfg *ServerConfig) { cfg.Logging.DynamicPort = "localhost:60054" cfg.Telemetry.Enabled = false cfg.Telemetry.OltpExporter = "0.0.0.0:4317" // Default OTEL OLTP gRPC Exporter endpoint + cfg.Rulesets.StoragePath = "/var/lib/scanoss/cryptography/rulesets" +} + +// ValidateRulesetsFolder validates that the configured rulesets storage path exists and is a directory. +func (cfg *ServerConfig) ValidateRulesetsFolder() error { + if cfg.Rulesets.StoragePath == "" { + return fmt.Errorf("rulesets storage path is not configured") + } + + info, err := os.Stat(cfg.Rulesets.StoragePath) + if err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("rulesets storage path does not exist: %s", cfg.Rulesets.StoragePath) + } + return fmt.Errorf("failed to access rulesets storage path: %w", err) + } + + if !info.IsDir() { + return fmt.Errorf("rulesets storage path is not a directory: %s", cfg.Rulesets.StoragePath) + } + + return nil } diff --git a/pkg/config/server_config_test.go b/pkg/config/server_config_test.go index ea8c68f..562eecc 100644 --- a/pkg/config/server_config_test.go +++ b/pkg/config/server_config_test.go @@ -23,14 +23,19 @@ import ( "github.com/golobby/config/v3" "github.com/golobby/config/v3/pkg/feeder" + "scanoss.com/cryptography/pkg/testutils" ) func TestServerConfig(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + dbUser := "test-user" err := os.Setenv("DB_USER", dbUser) if err != nil { t.Fatalf("an error '%s' was not expected when creating new config instance", err) } + defer os.Unsetenv("DB_USER") + cfg, err := NewServerConfig(nil) if err != nil { t.Fatalf("an error '%s' was not expected when creating new config instance", err) @@ -39,17 +44,16 @@ func TestServerConfig(t *testing.T) { t.Errorf("DB user '%v' doesn't match expected: %v", cfg.Database.User, dbUser) } fmt.Printf("Server Config1: %+v\n", cfg) - err = os.Unsetenv("DB_USER") - if err != nil { - fmt.Printf("Warning: Problem runn Unsetenv: %v\n", err) - } } func TestServerConfigDotEnv(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := os.Unsetenv("DB_USER") if err != nil { fmt.Printf("Warning: Problem runn Unsetenv: %v\n", err) } + dbUser := "env-user" var feeders []config.Feeder feeders = append(feeders, feeder.DotEnv{Path: "tests/dot-env"}) @@ -64,10 +68,13 @@ func TestServerConfigDotEnv(t *testing.T) { } func TestServerConfigJson(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := os.Unsetenv("DB_USER") if err != nil { fmt.Printf("Warning: Problem runn Unsetenv: %v\n", err) } + dbUser := "json-user" var feeders []config.Feeder feeders = append(feeders, feeder.Json{Path: "tests/env.json"}) @@ -80,3 +87,70 @@ func TestServerConfigJson(t *testing.T) { } fmt.Printf("Server Config3: %+v\n", cfg) } + +func TestValidateRulesetsFolder(t *testing.T) { + // Test with non-existent path + t.Run("NonExistentPath", func(t *testing.T) { + err := os.Setenv("RULESETS_STORAGE_PATH", "/path/that/does/not/exist") + if err != nil { + t.Fatalf("failed to set RULESETS_STORAGE_PATH: %s", err) + } + defer os.Unsetenv("RULESETS_STORAGE_PATH") + + _, err = NewServerConfig(nil) + if err == nil { + t.Fatal("expected error for non-existent rulesets path, got nil") + } + if !os.IsNotExist(err) && err.Error() != "rulesets storage path does not exist: /path/that/does/not/exist" { + t.Errorf("unexpected error message: %v", err) + } + }) + + // Test with valid directory + t.Run("ValidDirectory", func(t *testing.T) { + tmpDir, err := os.MkdirTemp("", "rulesets-test-*") + if err != nil { + t.Fatalf("failed to create temp directory: %s", err) + } + defer os.RemoveAll(tmpDir) + + err = os.Setenv("RULESETS_STORAGE_PATH", tmpDir) + if err != nil { + t.Fatalf("failed to set RULESETS_STORAGE_PATH: %s", err) + } + defer os.Unsetenv("RULESETS_STORAGE_PATH") + + cfg, err := NewServerConfig(nil) + if err != nil { + t.Fatalf("unexpected error for valid rulesets path: %s", err) + } + if cfg.Rulesets.StoragePath != tmpDir { + t.Errorf("expected storage path %s, got %s", tmpDir, cfg.Rulesets.StoragePath) + } + }) + + // Test with file instead of directory + t.Run("FileInsteadOfDirectory", func(t *testing.T) { + tmpFile, err := os.CreateTemp("", "rulesets-file-*") + if err != nil { + t.Fatalf("failed to create temp file: %s", err) + } + tmpFile.Close() + defer os.Remove(tmpFile.Name()) + + err = os.Setenv("RULESETS_STORAGE_PATH", tmpFile.Name()) + if err != nil { + t.Fatalf("failed to set RULESETS_STORAGE_PATH: %s", err) + } + defer os.Unsetenv("RULESETS_STORAGE_PATH") + + _, err = NewServerConfig(nil) + if err == nil { + t.Fatal("expected error for file instead of directory, got nil") + } + expectedMsg := fmt.Sprintf("rulesets storage path is not a directory: %s", tmpFile.Name()) + if err.Error() != expectedMsg { + t.Errorf("expected error message '%s', got '%s'", expectedMsg, err.Error()) + } + }) +} diff --git a/pkg/handlers/algorithm_handler_test.go b/pkg/handlers/algorithm_handler_test.go index d848c37..00784ab 100644 --- a/pkg/handlers/algorithm_handler_test.go +++ b/pkg/handlers/algorithm_handler_test.go @@ -27,9 +27,12 @@ import ( _ "modernc.org/sqlite" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestNewCryptographyAlgorithmHandler(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("failed to initialize logger: %v", err) @@ -57,6 +60,8 @@ func TestNewCryptographyAlgorithmHandler(t *testing.T) { } func TestCryptographyAlgorithmHandler_GetAlgorithms(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -176,6 +181,8 @@ func TestCryptographyAlgorithmHandler_GetAlgorithms(t *testing.T) { } func TestCryptographyAlgorithmHandler_GetComponentsAlgorithms(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -313,6 +320,8 @@ func TestCryptographyAlgorithmHandler_GetComponentsAlgorithms(t *testing.T) { } func TestCryptographyAlgorithmHandler_GetComponentAlgorithms(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { diff --git a/pkg/handlers/algorithm_in_range_handler_test.go b/pkg/handlers/algorithm_in_range_handler_test.go index 2a60a6d..2cc95be 100644 --- a/pkg/handlers/algorithm_in_range_handler_test.go +++ b/pkg/handlers/algorithm_in_range_handler_test.go @@ -27,9 +27,12 @@ import ( _ "modernc.org/sqlite" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestNewAlgorithmInRangeHandler(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("failed to initialize logger: %v", err) @@ -57,6 +60,8 @@ func TestNewAlgorithmInRangeHandler(t *testing.T) { } func TestAlgorithmInRangeHandler_GetAlgorithmsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -176,6 +181,8 @@ func TestAlgorithmInRangeHandler_GetAlgorithmsInRange(t *testing.T) { } func TestAlgorithmInRangeHandler_GetComponentsAlgorithmsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -313,6 +320,8 @@ func TestAlgorithmInRangeHandler_GetComponentsAlgorithmsInRange(t *testing.T) { } func TestAlgorithmInRangeHandler_GetComponentAlgorithmsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { diff --git a/pkg/handlers/cryptography_support.go b/pkg/handlers/cryptography_support.go index 04f7ea2..48929c7 100644 --- a/pkg/handlers/cryptography_support.go +++ b/pkg/handlers/cryptography_support.go @@ -35,18 +35,21 @@ import ( // about handler performance and request processing times. type metricsCounters struct { cryptoAlgorithmsHistogram metric.Int64Histogram // Histogram for recording crypto algorithms request times in milliseconds + downloadRulesetHistogram metric.Int64Histogram // Histogram for recording ruleset download request times in milliseconds + downloadRulesetCounter metric.Int64Counter // Counter for tracking the number of downloaded rulesets } var oltpMetrics = metricsCounters{} -// setupMetrics configures all OpenTelemetry metric instruments for the handlers package. +// SetupMetrics configures all OpenTelemetry metric instruments for the handlers package. // // This function initializes histogram metrics for tracking request durations. // It should be called once during handler initialization to set up the metrics infrastructure. - func SetupMetrics() { meter := otel.Meter("scanoss.com/cryptography") oltpMetrics.cryptoAlgorithmsHistogram, _ = meter.Int64Histogram("crypto.algorithms.req_time", metric.WithDescription("The time taken to run a crypto algorithms request (ms)")) + oltpMetrics.downloadRulesetHistogram, _ = meter.Int64Histogram("crypto.rulesets.download_time", metric.WithDescription("The time taken to download a ruleset (ms)")) + oltpMetrics.downloadRulesetCounter, _ = meter.Int64Counter("crypto.rulesets.downloaded", metric.WithDescription("The number of downloaded rulesets")) } // ConvertPurlRequestToComponentDTO converts a legacy PurlRequest to ComponentDTO slice. diff --git a/pkg/handlers/encryption_hints_handler_test.go b/pkg/handlers/encryption_hints_handler_test.go index 3594e71..b03fee9 100644 --- a/pkg/handlers/encryption_hints_handler_test.go +++ b/pkg/handlers/encryption_hints_handler_test.go @@ -27,9 +27,12 @@ import ( _ "modernc.org/sqlite" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestNewEncryptionHintsHandler(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("failed to initialize logger: %v", err) @@ -57,6 +60,8 @@ func TestNewEncryptionHintsHandler(t *testing.T) { } func TestEncryptionHintsHandler_GetEncryptionHints(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -176,6 +181,8 @@ func TestEncryptionHintsHandler_GetEncryptionHints(t *testing.T) { } func TestEncryptionHintsHandler_GetComponentsEncryptionHints(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -324,6 +331,8 @@ func TestEncryptionHintsHandler_GetComponentsEncryptionHints(t *testing.T) { } func TestEncryptionHintsHandler_GetComponentEncryptionHints(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { diff --git a/pkg/handlers/hints_in_range_handler_test.go b/pkg/handlers/hints_in_range_handler_test.go index ef7d9e0..5567e21 100644 --- a/pkg/handlers/hints_in_range_handler_test.go +++ b/pkg/handlers/hints_in_range_handler_test.go @@ -27,9 +27,12 @@ import ( _ "modernc.org/sqlite" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestNewHintsInRangeHandler(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("failed to initialize logger: %v", err) @@ -57,6 +60,8 @@ func TestNewHintsInRangeHandler(t *testing.T) { } func TestHintsRangeHandler_GetHintsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -176,6 +181,8 @@ func TestHintsRangeHandler_GetHintsInRange(t *testing.T) { } func TestHintsRangeHandler_GetComponentsHintsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -324,6 +331,8 @@ func TestHintsRangeHandler_GetComponentsHintsInRange(t *testing.T) { } func TestHintsRangeHandler_GetComponentHintsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { diff --git a/pkg/handlers/ruleset_download_handler.go b/pkg/handlers/ruleset_download_handler.go new file mode 100644 index 0000000..12e8072 --- /dev/null +++ b/pkg/handlers/ruleset_download_handler.go @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 SCANOSS.COM + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package handlers + +import ( + "context" + "fmt" + "net/http" + "strings" + "time" + + "github.com/Masterminds/semver/v3" + "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" + pb "github.com/scanoss/papi/api/cryptographyv2" + "go.uber.org/zap" + "google.golang.org/genproto/googleapis/api/httpbody" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + + myconfig "scanoss.com/cryptography/pkg/config" + "scanoss.com/cryptography/pkg/httphelper" + "scanoss.com/cryptography/pkg/usecase" +) + +// RulesetDownloadHandler handles gRPC requests for downloading cryptography detection rulesets. +type RulesetDownloadHandler struct { + rulesetDownloadUseCase *usecase.RulesetDownloadUseCase + config *myconfig.ServerConfig +} + +// NewRulesetDownloadHandler creates a new RulesetDownloadHandler instance. +// +// This constructor initializes the handler with a ruleset download use case that provides +// access to the filesystem for serving ruleset tarballs. +// +// Parameters: +// - config: Server configuration including ruleset storage path +// +// Returns: +// - *RulesetDownloadHandler: Initialized handler ready to process requests +func NewRulesetDownloadHandler(config *myconfig.ServerConfig) *RulesetDownloadHandler { + return &RulesetDownloadHandler{ + config: config, + rulesetDownloadUseCase: usecase.NewRulesetDownload(config), + } +} + +// DownloadRuleset handles the download request for a specific ruleset version. +// +// This method processes a RulesetDownloadRequest containing the ruleset name and version +// (which can be "latest" or a specific version like "v1.2.3"). It validates the request, +// resolves the version, reads the metadata and tarball from the filesystem, and returns +// the tarball as a binary response with appropriate HTTP headers. +// +// The response includes custom headers: +// - Content-Type: application/gzip +// - Content-Disposition: attachment; filename="..." +// - SCANOSS-Ruleset-Name: Name of the ruleset +// - SCANOSS-Ruleset-Version: Resolved version number +// - SCANOSS-Ruleset-Created-At: Creation timestamp of the ruleset +// - SCANOSS-Ruleset-Description: Description of the ruleset (if present) +// - X-Checksum-SHA256: SHA256 checksum of the tarball +// +// Parameters: +// - ctx: Request context containing logger and trace information +// - request: RulesetDownloadRequest with ruleset name and version +// +// Returns: +// - *httpbody.HttpBody: Binary response containing the tarball +// - error: gRPC error with appropriate status code (NotFound, InvalidArgument, Internal) +func (r *RulesetDownloadHandler) DownloadRuleset(ctx context.Context, request *pb.RulesetDownloadRequest) (*httpbody.HttpBody, error) { + requestStartTime := time.Now() + s := ctxzap.Extract(ctx).Sugar() + s.Infof("Processing ruleset download request: %s/%s", request.RulesetName, request.Version) + + if err := r.validateRequest(request); err != nil { + s.Warnf("Invalid ruleset download request: %v", err) + httphelper.SetHTTPCodeOnTrailer(ctx, s, http.StatusBadRequest) + return nil, status.Errorf(codes.InvalidArgument, "invalid request: %v", err) + } + + ruleset, err := r.rulesetDownloadUseCase.DownloadRuleset(ctx, s, request.RulesetName, request.Version) + if err != nil { + return r.handleUseCaseError(ctx, s, err) + } + + filename := fmt.Sprintf("%s-%s.tar.gz", ruleset.Metadata.Name, ruleset.Metadata.Version) + headers := []string{ + "content-type", "application/gzip", + "content-disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename), + "scanoss-ruleset-name", ruleset.Metadata.Name, + "scanoss-ruleset-version", ruleset.Metadata.Version, + "scanoss-ruleset-created-at", ruleset.Metadata.CreatedAt, + "x-checksum-sha256", ruleset.Metadata.ChecksumSHA256, + } + + if strings.TrimSpace(ruleset.Metadata.Description) != "" { + headers = append(headers, "scanoss-ruleset-description", ruleset.Metadata.Description) + } + + md := metadata.Pairs(headers...) + + if err := grpc.SendHeader(ctx, md); err != nil { + s.Errorf("Failed to send response headers: %v", err) + httphelper.SetHTTPCodeOnTrailer(ctx, s, http.StatusInternalServerError) + return nil, status.Errorf(codes.Internal, "failed to send response headers") + } + + response := &httpbody.HttpBody{ + ContentType: "application/gzip", + Data: ruleset.TarballData, + } + + telemetryDownloadRulesetRequestTime(ctx, r.config, requestStartTime) + telemetryAddRulesetDownloaded(ctx, r.config) + + s.Infof("Successfully served ruleset: %s/%s (%d bytes)", request.RulesetName, request.Version, len(ruleset.TarballData)) + return response, nil +} + +// validateRequest validates the RulesetDownloadRequest. +func (r *RulesetDownloadHandler) validateRequest(request *pb.RulesetDownloadRequest) error { + if request == nil { + return fmt.Errorf("request cannot be empty") + } + + if strings.TrimSpace(request.RulesetName) == "" { + return fmt.Errorf("ruleset_name cannot be empty") + } + + if strings.TrimSpace(request.Version) == "" { + return fmt.Errorf("version cannot be empty, you must provide a specific version or 'latest'") + } + + version := strings.TrimSpace(request.Version) + _, err := semver.NewVersion(version) + if err != nil && version != "latest" { + return fmt.Errorf("version must be 'latest' or a valid semver string (e.g., 'v1.2.3')") + } + + return nil +} + +// handleUseCaseError converts use case errors to appropriate gRPC errors with HTTP status codes. +func (r *RulesetDownloadHandler) handleUseCaseError(ctx context.Context, s *zap.SugaredLogger, err error) (*httpbody.HttpBody, error) { + errMsg := err.Error() + + s.Errorf("Error while downloading ruleset: %v", err) + + switch { + case strings.Contains(errMsg, "not found") || strings.Contains(errMsg, "does not exist"): + httphelper.SetHTTPCodeOnTrailer(ctx, s, http.StatusNotFound) + return nil, status.Errorf(codes.NotFound, "requested ruleset or version not found") + case strings.Contains(errMsg, "integrity check failed") || strings.Contains(errMsg, "checksum"): + httphelper.SetHTTPCodeOnTrailer(ctx, s, http.StatusInternalServerError) + return nil, status.Errorf(codes.DataLoss, "ruleset integrity verification failed") + default: + httphelper.SetHTTPCodeOnTrailer(ctx, s, http.StatusInternalServerError) + return nil, status.Errorf(codes.Internal, "internal server error") + } +} diff --git a/pkg/handlers/ruleset_download_handler_test.go b/pkg/handlers/ruleset_download_handler_test.go new file mode 100644 index 0000000..28227f7 --- /dev/null +++ b/pkg/handlers/ruleset_download_handler_test.go @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 SCANOSS.COM + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package handlers + +import ( + "context" + "path/filepath" + "strings" + "testing" + + "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" + pb "github.com/scanoss/papi/api/cryptographyv2" + zlog "github.com/scanoss/zap-logging-helper/pkg/logger" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + myconfig "scanoss.com/cryptography/pkg/config" +) + +func TestNewRulesetDownloadHandler(t *testing.T) { + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = "/tmp/rulesets" + + handler := NewRulesetDownloadHandler(config) + if handler == nil { + t.Error("NewRulesetDownloadHandler() returned nil") + } + if handler.config == nil { + t.Error("NewRulesetDownloadHandler() config is nil") + } + if handler.rulesetDownloadUseCase == nil { + t.Error("NewRulesetDownloadHandler() rulesetDownloadUseCase is nil") + } +} + +func TestRulesetDownloadHandler_validateRequest(t *testing.T) { + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = "/tmp/rulesets" + + handler := NewRulesetDownloadHandler(config) + + tests := []struct { + name string + request *pb.RulesetDownloadRequest + expectError bool + errorContains string + }{ + { + name: "valid request with specific version", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: "v1.0.0", + }, + expectError: false, + }, + { + name: "valid request with latest", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: "latest", + }, + expectError: false, + }, + { + name: "nil request", + request: nil, + expectError: true, + errorContains: "cannot be empty", + }, + { + name: "empty ruleset name", + request: &pb.RulesetDownloadRequest{ + RulesetName: "", + Version: "v1.0.0", + }, + expectError: true, + errorContains: "ruleset_name cannot be empty", + }, + { + name: "empty version", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: "", + }, + expectError: true, + errorContains: "version cannot be empty", + }, + { + name: "whitespace only ruleset name", + request: &pb.RulesetDownloadRequest{ + RulesetName: " ", + Version: "v1.0.0", + }, + expectError: true, + errorContains: "ruleset_name cannot be empty", + }, + { + name: "whitespace only version", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: " ", + }, + expectError: true, + errorContains: "version cannot be empty", + }, + { + name: "invalid semver version", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: "not-a-version", + }, + expectError: true, + errorContains: "valid semver", + }, + { + name: "valid semver without v prefix", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: "1.0.0", + }, + expectError: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := handler.validateRequest(tt.request) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error containing '%s', got nil", tt.errorContains) + return + } + if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { + t.Errorf("Expected error containing '%s', got '%s'", tt.errorContains, err.Error()) + } + } else { + if err != nil { + t.Errorf("Expected no error, got: %v", err) + } + } + }) + } +} + +func TestRulesetDownloadHandler_DownloadRuleset(t *testing.T) { + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + // Get the project root directory + projectRoot, err := filepath.Abs("../../") + if err != nil { + t.Fatalf("failed to get project root: %v", err) + } + testStoragePath := filepath.Join(projectRoot, "test-support", "rulesets") + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = testStoragePath + + handler := NewRulesetDownloadHandler(config) + ctx := context.Background() + ctx = ctxzap.ToContext(ctx, zlog.L) + + tests := []struct { + name string + request *pb.RulesetDownloadRequest + expectError bool + expectedCode codes.Code + errorContains string + validateResult func(t *testing.T, contentType string, dataLen int) + }{ + { + name: "invalid request - empty ruleset name", + request: &pb.RulesetDownloadRequest{ + RulesetName: "", + Version: "v1.0.0", + }, + expectError: true, + expectedCode: codes.InvalidArgument, + errorContains: "invalid request", + }, + { + name: "invalid request - empty version", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: "", + }, + expectError: true, + expectedCode: codes.InvalidArgument, + errorContains: "invalid request", + }, + { + name: "ruleset not found", + request: &pb.RulesetDownloadRequest{ + RulesetName: "nonexistent-ruleset", + Version: "v1.0.0", + }, + expectError: true, + expectedCode: codes.NotFound, + errorContains: "not found", + }, + { + name: "version not found", + request: &pb.RulesetDownloadRequest{ + RulesetName: "dca", + Version: "v99.99.99", + }, + expectError: true, + expectedCode: codes.NotFound, + errorContains: "not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := handler.DownloadRuleset(ctx, tt.request) + + if tt.expectError { + if err == nil { + t.Error("Expected error, got nil") + return + } + + st, ok := status.FromError(err) + if !ok { + t.Errorf("Expected gRPC status error, got: %v", err) + return + } + + if st.Code() != tt.expectedCode { + t.Errorf("Expected code %v, got %v", tt.expectedCode, st.Code()) + } + + if tt.errorContains != "" && !strings.Contains(st.Message(), tt.errorContains) { + t.Errorf("Expected error containing '%s', got '%s'", tt.errorContains, st.Message()) + } + } else { + if err != nil { + t.Errorf("Expected no error, got: %v", err) + return + } + + if result == nil { + t.Error("Expected non-nil result") + return + } + + if tt.validateResult != nil { + tt.validateResult(t, result.ContentType, len(result.Data)) + } + } + }) + } +} + +func TestRulesetDownloadHandler_handleUseCaseError(t *testing.T) { + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = "/tmp/rulesets" + + handler := NewRulesetDownloadHandler(config) + ctx := context.Background() + ctx = ctxzap.ToContext(ctx, zlog.L) + s := zlog.S + + tests := []struct { + name string + inputError error + expectedCode codes.Code + errorPattern string + }{ + { + name: "not found error", + inputError: &customError{msg: "ruleset not found"}, + expectedCode: codes.NotFound, + errorPattern: "requested ruleset or version not found", + }, + { + name: "does not exist error", + inputError: &customError{msg: "file does not exist"}, + expectedCode: codes.NotFound, + errorPattern: "requested ruleset or version not found", + }, + { + name: "failed to resolve error", + inputError: &customError{msg: "failed to resolve version"}, + expectedCode: codes.Internal, + errorPattern: "internal server error", + }, + { + name: "failed to read error", + inputError: &customError{msg: "failed to read metadata"}, + expectedCode: codes.Internal, + errorPattern: "internal server error", + }, + { + name: "failed to parse error", + inputError: &customError{msg: "failed to parse manifest"}, + expectedCode: codes.Internal, + errorPattern: "internal server error", + }, + { + name: "integrity check failed error", + inputError: &customError{msg: "tarball integrity check failed"}, + expectedCode: codes.DataLoss, + errorPattern: "ruleset integrity verification failed", + }, + { + name: "checksum error", + inputError: &customError{msg: "checksum mismatch"}, + expectedCode: codes.DataLoss, + errorPattern: "ruleset integrity verification failed", + }, + { + name: "unexpected error", + inputError: &customError{msg: "some random error"}, + expectedCode: codes.Internal, + errorPattern: "internal server error", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := handler.handleUseCaseError(ctx, s, tt.inputError) + + if err == nil { + t.Error("Expected error, got nil") + return + } + + if result != nil { + t.Errorf("Expected nil result, got: %v", result) + } + + st, ok := status.FromError(err) + if !ok { + t.Errorf("Expected gRPC status error, got: %v", err) + return + } + + if st.Code() != tt.expectedCode { + t.Errorf("Expected code %v, got %v", tt.expectedCode, st.Code()) + } + + if !strings.Contains(st.Message(), tt.errorPattern) { + t.Errorf("Expected error message to contain '%s', got '%s'", tt.errorPattern, st.Message()) + } + }) + } +} + +// customError is a helper type for testing error handling +type customError struct { + msg string +} + +func (e *customError) Error() string { + return e.msg +} diff --git a/pkg/handlers/utils_handler.go b/pkg/handlers/utils_handler.go index ff6b54c..3ac8fc0 100644 --- a/pkg/handlers/utils_handler.go +++ b/pkg/handlers/utils_handler.go @@ -39,3 +39,34 @@ func telemetryRequestTime(ctx context.Context, config *myconfig.ServerConfig, re oltpMetrics.cryptoAlgorithmsHistogram.Record(ctx, elapsedTime) // Record algorithm request time } } + +// telemetryDownloadRulesetRequestTime records download ruleset request duration to OpenTelemetry. +// +// This function calculates the elapsed time since the request started and records it +// to the OpenTelemetry histogram for performance monitoring. Recording only occurs +// if telemetry is enabled in the server configuration. +// +// Parameters: +// - ctx: Context for the telemetry recording +// - config: Server configuration containing telemetry settings +// - requestStartTime: Time when the request processing began +func telemetryDownloadRulesetRequestTime(ctx context.Context, config *myconfig.ServerConfig, requestStartTime time.Time) { + if config.Telemetry.Enabled { + elapsedTime := time.Since(requestStartTime).Milliseconds() // Time taken to download ruleset request + oltpMetrics.downloadRulesetHistogram.Record(ctx, elapsedTime) // Record download ruleset request time + } +} + +// telemetryAddRulesetDownloaded adds a record for downloaded rulesets to OpenTelemetry. +// +// This function increments the counter for downloaded rulesets in the OpenTelemetry metrics. +// Recording only occurs if telemetry is enabled in the server configuration. +// +// Parameters: +// - ctx: Context for the telemetry recording +// - config: Server configuration containing telemetry settings +func telemetryAddRulesetDownloaded(ctx context.Context, config *myconfig.ServerConfig) { + if config.Telemetry.Enabled { + oltpMetrics.downloadRulesetCounter.Add(ctx, 1) + } +} diff --git a/pkg/handlers/versions_in_range_handler_test.go b/pkg/handlers/versions_in_range_handler_test.go index b2c28c1..6d0375f 100644 --- a/pkg/handlers/versions_in_range_handler_test.go +++ b/pkg/handlers/versions_in_range_handler_test.go @@ -27,9 +27,12 @@ import ( _ "modernc.org/sqlite" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestNewVersionsInRangeHandler(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("failed to initialize logger: %v", err) @@ -57,6 +60,8 @@ func TestNewVersionsInRangeHandler(t *testing.T) { } func TestVersionsInRangeHandler_GetVersionsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -176,6 +181,8 @@ func TestVersionsInRangeHandler_GetVersionsInRange(t *testing.T) { } func TestVersionsInRangeHandler_GetComponentsVersionsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -313,6 +320,8 @@ func TestVersionsInRangeHandler_GetComponentsVersionsInRange(t *testing.T) { } func TestVersionsInRangeHandler_GetComponentVersionsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { diff --git a/pkg/models/all_urls_test.go b/pkg/models/all_urls_test.go index 5061fe4..de2ff0b 100644 --- a/pkg/models/all_urls_test.go +++ b/pkg/models/all_urls_test.go @@ -25,9 +25,12 @@ import ( zlog "github.com/scanoss/zap-logging-helper/pkg/logger" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/utils" + "scanoss.com/cryptography/pkg/testutils" ) func TestAllUrlsSearchVersion(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -90,6 +93,8 @@ func TestAllUrlsSearchVersion(t *testing.T) { } } func TestAllUrlsSearchVersionRequirement(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -128,6 +133,8 @@ func TestAllUrlsSearchVersionRequirement(t *testing.T) { } func TestAllUrlsSearchVersionRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -173,6 +180,8 @@ func TestAllUrlsSearchVersionRange(t *testing.T) { } func TestAllUrlsSearchPurlList(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -203,6 +212,8 @@ func TestAllUrlsSearchPurlList(t *testing.T) { } func TestAllUrlsClosestVersionRequirement(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -232,6 +243,8 @@ func TestAllUrlsClosestVersionRequirement(t *testing.T) { } func TestAllUrlsSearchNoLicense(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -262,6 +275,8 @@ func TestAllUrlsSearchNoLicense(t *testing.T) { } func TestAllUrlsSearchBadSql(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) diff --git a/pkg/models/common_test.go b/pkg/models/common_test.go index f9e2fb3..0e58906 100644 --- a/pkg/models/common_test.go +++ b/pkg/models/common_test.go @@ -18,11 +18,11 @@ package models import ( "context" - "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" - zlog "github.com/scanoss/zap-logging-helper/pkg/logger" "testing" + "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" "github.com/jmoiron/sqlx" + zlog "github.com/scanoss/zap-logging-helper/pkg/logger" _ "modernc.org/sqlite" ) diff --git a/pkg/models/crypto_usage_test.go b/pkg/models/crypto_usage_test.go index ae327b2..0362402 100644 --- a/pkg/models/crypto_usage_test.go +++ b/pkg/models/crypto_usage_test.go @@ -24,9 +24,12 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" zlog "github.com/scanoss/zap-logging-helper/pkg/logger" myconfig "scanoss.com/cryptography/pkg/config" + "scanoss.com/cryptography/pkg/testutils" ) func TestCryptoSearchUsageByList(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) diff --git a/pkg/models/library_usage_test.go b/pkg/models/library_usage_test.go index 32e621f..cc62b46 100644 --- a/pkg/models/library_usage_test.go +++ b/pkg/models/library_usage_test.go @@ -23,9 +23,12 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap" zlog "github.com/scanoss/zap-logging-helper/pkg/logger" myconfig "scanoss.com/cryptography/pkg/config" + "scanoss.com/cryptography/pkg/testutils" ) func TestECSearchUsage(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) diff --git a/pkg/service/cryptography_service.go b/pkg/service/cryptography_service.go index 8272eb9..f9bea06 100644 --- a/pkg/service/cryptography_service.go +++ b/pkg/service/cryptography_service.go @@ -24,6 +24,7 @@ import ( "github.com/jmoiron/sqlx" common "github.com/scanoss/papi/api/commonv2" pb "github.com/scanoss/papi/api/cryptographyv2" + "google.golang.org/genproto/googleapis/api/httpbody" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/handlers" ) @@ -40,18 +41,21 @@ type cryptographyServer struct { versionsInRangeHandler *handlers.VersionsInRangeHandler hintsInRangeHandler *handlers.HintsRangeHandler encryptionHintsHandler *handlers.EncryptionHintsHandler + rulesetDownloadHandler *handlers.RulesetDownloadHandler } // NewCryptographyServer creates a new instance of Cryptography Server. func NewCryptographyServer(db *sqlx.DB, config *myconfig.ServerConfig) pb.CryptographyServer { // Setups metrics handlers.SetupMetrics() - return &cryptographyServer{db: db, config: config, + return &cryptographyServer{ + db: db, config: config, algorithmHandler: handlers.NewCryptographyAlgorithmHandler(db, config), algorithmInRangeHandler: handlers.NewAlgorithmInRangeHandler(db, config), versionsInRangeHandler: handlers.NewVersionsInRangeHandler(db, config), hintsInRangeHandler: handlers.NewHintsInRangeHandler(db, config), encryptionHintsHandler: handlers.NewEncryptionHintsHandler(db, config), + rulesetDownloadHandler: handlers.NewRulesetDownloadHandler(config), } } @@ -146,3 +150,8 @@ func (c cryptographyServer) GetComponentsEncryptionHints(ctx context.Context, re func (c cryptographyServer) GetComponentEncryptionHints(ctx context.Context, request *common.ComponentRequest) (*pb.ComponentEncryptionHintsResponse, error) { return c.encryptionHintsHandler.GetComponentEncryptionHints(ctx, request) } + +// DownloadRuleset serves cryptography detection ruleset tarballs for download. +func (c cryptographyServer) DownloadRuleset(ctx context.Context, request *pb.RulesetDownloadRequest) (*httpbody.HttpBody, error) { + return c.rulesetDownloadHandler.DownloadRuleset(ctx, request) +} diff --git a/pkg/service/cryptography_service_test.go b/pkg/service/cryptography_service_test.go index 8743688..df84651 100644 --- a/pkg/service/cryptography_service_test.go +++ b/pkg/service/cryptography_service_test.go @@ -33,9 +33,12 @@ import ( _ "modernc.org/sqlite" myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestCryptographyServer_Echo(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -95,6 +98,8 @@ func TestCryptographyServer_Echo(t *testing.T) { } func TestCryptographyServer_GetAlgorithms(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -204,6 +209,8 @@ func TestCryptographyServer_GetAlgorithms(t *testing.T) { } func TestCryptographyServer_GetAlgorithmsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() @@ -258,6 +265,8 @@ func TestCryptographyServer_GetAlgorithmsInRange(t *testing.T) { } func TestCryptographyServer_GetVersionsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -311,6 +320,8 @@ func TestCryptographyServer_GetVersionsInRange(t *testing.T) { } func TestCryptographyServer_GetHintsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() @@ -365,6 +376,8 @@ func TestCryptographyServer_GetHintsInRange(t *testing.T) { } func TestCryptographyServer_GetHints(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -414,6 +427,8 @@ func TestCryptographyServer_GetHints(t *testing.T) { } func TestCryptographyServer_GetComponentsAlgorithms(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -529,6 +544,8 @@ func TestCryptographyServer_GetComponentsAlgorithms(t *testing.T) { } func TestCryptographyServer_GetComponentAlgorithms(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -620,6 +637,8 @@ func TestCryptographyServer_GetComponentAlgorithms(t *testing.T) { } func TestCryptographyServer_GetComponentsAlgorithmsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -735,6 +754,8 @@ func TestCryptographyServer_GetComponentsAlgorithmsInRange(t *testing.T) { } func TestCryptographyServer_GetComponentAlgorithmsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -824,6 +845,8 @@ func TestCryptographyServer_GetComponentAlgorithmsInRange(t *testing.T) { } func TestCryptographyServer_GetComponentVersionsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -898,6 +921,8 @@ func TestCryptographyServer_GetComponentVersionsInRange(t *testing.T) { } func TestCryptographyServer_GetComponentsVersionsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -989,6 +1014,8 @@ func TestCryptographyServer_GetComponentsVersionsInRange(t *testing.T) { } func TestCryptographyServer_GetComponentHintsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -1100,6 +1127,8 @@ func TestCryptographyServer_GetComponentHintsInRange(t *testing.T) { } func TestCryptographyServer_GetComponentsHintsInRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -1220,6 +1249,8 @@ func TestCryptographyServer_GetComponentsHintsInRange(t *testing.T) { } func TestCryptographyServer_GetComponentsEncryptionHints(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { @@ -1331,6 +1362,8 @@ func TestCryptographyServer_GetComponentsEncryptionHints(t *testing.T) { } func TestCryptographyServer_GetComponentEncryptionHints(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + ctx := context.Background() err := zlog.NewSugaredDevLogger() if err != nil { diff --git a/pkg/testutils/test_helpers.go b/pkg/testutils/test_helpers.go new file mode 100644 index 0000000..0d22731 --- /dev/null +++ b/pkg/testutils/test_helpers.go @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 SCANOSS.COM + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package testutils + +import ( + "os" + "testing" +) + +// SetupTestRulesetsDir creates a temporary rulesets directory for testing +// and sets the RULESETS_STORAGE_PATH environment variable. +// Returns a cleanup function that should be deferred. +// +// Usage: +// func TestMyFunction(t *testing.T) { +// defer testutils.SetupTestRulesetsDir(t)() +// // ... test code +// } +func SetupTestRulesetsDir(t *testing.T) func() { + tmpDir, err := os.MkdirTemp("", "rulesets-test-*") + if err != nil { + t.Fatalf("failed to create temp rulesets directory: %v", err) + } + + err = os.Setenv("RULESETS_STORAGE_PATH", tmpDir) + if err != nil { + os.RemoveAll(tmpDir) + t.Fatalf("failed to set RULESETS_STORAGE_PATH: %v", err) + } + + return func() { + os.Unsetenv("RULESETS_STORAGE_PATH") + os.RemoveAll(tmpDir) + } +} diff --git a/pkg/usecase/cryptography_major_test.go b/pkg/usecase/cryptography_major_test.go index 292dc65..df646df 100644 --- a/pkg/usecase/cryptography_major_test.go +++ b/pkg/usecase/cryptography_major_test.go @@ -28,9 +28,12 @@ import ( myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/dtos" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestAlgorithmsInRangeUseCase(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) diff --git a/pkg/usecase/cryptography_search_test.go b/pkg/usecase/cryptography_search_test.go index 3d33676..0bd9153 100644 --- a/pkg/usecase/cryptography_search_test.go +++ b/pkg/usecase/cryptography_search_test.go @@ -28,9 +28,12 @@ import ( myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/dtos" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestCryptographyUseCase(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) diff --git a/pkg/usecase/cryptography_versions_using_test.go b/pkg/usecase/cryptography_versions_using_test.go index add8bb1..5a0853a 100644 --- a/pkg/usecase/cryptography_versions_using_test.go +++ b/pkg/usecase/cryptography_versions_using_test.go @@ -29,9 +29,12 @@ import ( myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/dtos" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestVersionsUsingCryptoUseCase(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -161,6 +164,8 @@ func TestVersionsUsingCryptoUseCase(t *testing.T) { } func TestVersionInRangeUsingCryptoUseCase(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) diff --git a/pkg/usecase/library_detections_test.go b/pkg/usecase/library_detections_test.go index e94064e..594105a 100644 --- a/pkg/usecase/library_detections_test.go +++ b/pkg/usecase/library_detections_test.go @@ -28,9 +28,12 @@ import ( myconfig "scanoss.com/cryptography/pkg/config" "scanoss.com/cryptography/pkg/dtos" "scanoss.com/cryptography/pkg/models" + "scanoss.com/cryptography/pkg/testutils" ) func TestLibrariesDetectionUseCase_InRange(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -103,6 +106,8 @@ func TestLibrariesDetectionUseCase_InRange(t *testing.T) { } func TestLibrariesDetectionUseCase_ExactVersion(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) @@ -184,6 +189,8 @@ func TestLibrariesDetectionUseCase_ExactVersion(t *testing.T) { } } func TestLibrariesDetectionUseCase_MalformedPurl(t *testing.T) { + defer testutils.SetupTestRulesetsDir(t)() + err := zlog.NewSugaredDevLogger() if err != nil { t.Fatalf("an error '%s' was not expected when opening a sugared logger", err) diff --git a/pkg/usecase/ruleset_download.go b/pkg/usecase/ruleset_download.go new file mode 100644 index 0000000..076cc6b --- /dev/null +++ b/pkg/usecase/ruleset_download.go @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 SCANOSS.COM + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package usecase + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + + "go.uber.org/zap" + myconfig "scanoss.com/cryptography/pkg/config" +) + +// RulesetMetadata represents the manifest.json structure. +type RulesetMetadata struct { + ChecksumSHA256 string `json:"checksum_sha256"` + CreatedAt string `json:"created_at"` + Description string `json:"description,omitempty"` + Name string `json:"name"` + Version string `json:"version"` +} + +// RulesetDownloadOutput contains the tarball data and metadata. +type RulesetDownloadOutput struct { + Metadata RulesetMetadata + TarballData []byte +} + +// RulesetDownloadUseCase handles the business logic for downloading rulesets. +type RulesetDownloadUseCase struct { + config *myconfig.ServerConfig +} + +// NewRulesetDownload creates a new RulesetDownloadUseCase. +func NewRulesetDownload(config *myconfig.ServerConfig) *RulesetDownloadUseCase { + return &RulesetDownloadUseCase{ + config: config, + } +} + +// verifyPathContainment ensures the resolved path is contained within the base directory. +// This prevents path traversal attacks where filepath.Join could resolve .. segments to escape. +func (r *RulesetDownloadUseCase) verifyPathContainment(resolvedPath, baseDir string) error { + absBase, err := filepath.Abs(baseDir) + if err != nil { + return fmt.Errorf("failed to resolve base directory: %w", err) + } + + absResolved, err := filepath.Abs(resolvedPath) + if err != nil { + return fmt.Errorf("failed to resolve target path: %w", err) + } + + // Ensure the resolved path starts with the base directory followed by a separator + // This prevents cases where "/base/dir" would match "/base/dir-malicious" + if !strings.HasPrefix(absResolved, absBase+string(filepath.Separator)) && absResolved != absBase { + return fmt.Errorf("path escapes base directory") + } + + return nil +} + +// resolveVersion resolves a version string (potentially "latest") to an actual version directory path +// It handles symlink resolution for "latest" version. +func (r *RulesetDownloadUseCase) resolveVersion(s *zap.SugaredLogger, rulesetName, version string) (string, error) { + basePath := filepath.Join(r.config.Rulesets.StoragePath, rulesetName) + + // Verify the resolved path is contained within the storage directory + if err := r.verifyPathContainment(basePath, r.config.Rulesets.StoragePath); err != nil { + return "", fmt.Errorf("invalid ruleset name: %w", err) + } + + if _, err := os.Stat(basePath); os.IsNotExist(err) { + s.Warnf("Ruleset directory does not exist: %s", basePath) + return "", fmt.Errorf("ruleset '%s' not found", rulesetName) + } + + versionPath := filepath.Join(basePath, version) + + // If version is "latest", it should be a symlink + if version == "latest" { + targetPath, err := os.Readlink(versionPath) + if err != nil { + s.Warnf("Failed to read 'latest' symlink for ruleset %s: %v", rulesetName, err) + return "", fmt.Errorf("failed to resolve 'latest' version for ruleset '%s'", rulesetName) + } + + // If targetPath is relative, resolve it relative to basePath + if !filepath.IsAbs(targetPath) { + versionPath = filepath.Join(basePath, targetPath) + } else { + versionPath = targetPath + } + s.Debugf("Resolved 'latest' symlink for %s to: %s", rulesetName, versionPath) + + // Verify the resolved symlink target is contained within the storage directory + if err := r.verifyPathContainment(versionPath, r.config.Rulesets.StoragePath); err != nil { + s.Warnf("Symlink target escapes storage directory: %s", versionPath) + return "", fmt.Errorf("invalid symlink target: %w", err) + } + } + + if _, err := os.Stat(versionPath); os.IsNotExist(err) { + s.Warnf("Version directory does not exist: %s", versionPath) + return "", fmt.Errorf("version '%s' not found for ruleset '%s'", version, rulesetName) + } + + return versionPath, nil +} + +// readMetadata reads and parses the manifest.json file from the version directory. +func (r *RulesetDownloadUseCase) readMetadata(s *zap.SugaredLogger, versionPath string) (RulesetMetadata, error) { + metadataPath := filepath.Join(versionPath, "manifest.json") + + s.Debugf("Reading metadata from: %s", metadataPath) + + data, err := os.ReadFile(metadataPath) + if err != nil { + s.Warnf("Failed to read metadata file %s: %v", metadataPath, err) + return RulesetMetadata{}, fmt.Errorf("failed to read metadata: %w", err) + } + + var metadata RulesetMetadata + if err := json.Unmarshal(data, &metadata); err != nil { + s.Warnf("Failed to parse metadata JSON from %s: %v", metadataPath, err) + return RulesetMetadata{}, fmt.Errorf("failed to parse metadata: %w", err) + } + + s.Debugf("Successfully parsed metadata: name=%s, version=%s, checksum=%s", + metadata.Name, metadata.Version, metadata.ChecksumSHA256) + + return metadata, nil +} + +// readTarball reads the tarball file into memory. +func (r *RulesetDownloadUseCase) readTarball(s *zap.SugaredLogger, versionPath, rulesetName, rulesetVersion string) ([]byte, error) { + fileName := fmt.Sprintf("%s-%s.tar.gz", rulesetName, rulesetVersion) + tarballPath := filepath.Join(versionPath, fileName) + + s.Debugf("Reading tarball from: %s", tarballPath) + + fileInfo, err := os.Stat(tarballPath) + if err != nil { + s.Warnf("Failed to stat tarball file %s: %v", tarballPath, err) + return nil, fmt.Errorf("tarball file not found: %w", err) + } + + s.Debugf("Tarball file size: %d bytes", fileInfo.Size()) + + data, err := os.ReadFile(tarballPath) + if err != nil { + s.Warnf("Failed to read tarball file %s: %v", tarballPath, err) + return nil, fmt.Errorf("failed to read tarball: %w", err) + } + + s.Debugf("Successfully read %d bytes from tarball", len(data)) + + return data, nil +} + +// verifyTarballChecksum validates the SHA256 checksum of the tarball data against the expected checksum. +// It returns an error if the checksum is empty, mismatched, or if there's any validation failure. +func (r *RulesetDownloadUseCase) verifyTarballChecksum(s *zap.SugaredLogger, tarballData []byte, expectedChecksum string) error { + // Check if expected checksum is empty + if strings.TrimSpace(expectedChecksum) == "" { + return fmt.Errorf("expected checksum is empty, cannot validate tarball integrity") + } + + // Compute SHA256 of the tarball data + hash := sha256.Sum256(tarballData) + actualChecksum := hex.EncodeToString(hash[:]) + + s.Debugf("Tarball checksum validation: expected=%s, actual=%s", expectedChecksum, actualChecksum) + + // Compare checksums + if actualChecksum != strings.ToLower(expectedChecksum) { + s.Warnf("Checksum mismatch! Expected: %s, Actual: %s", expectedChecksum, actualChecksum) + return fmt.Errorf("tarball integrity check failed") + } + + s.Debugf("Tarball checksum validation passed") + return nil +} + +// DownloadRuleset orchestrates the entire ruleset download process. +func (r *RulesetDownloadUseCase) DownloadRuleset(ctx context.Context, s *zap.SugaredLogger, rulesetName, version string) (RulesetDownloadOutput, error) { + if err := ctx.Err(); err != nil { + return RulesetDownloadOutput{}, fmt.Errorf("request cancelled: %w", err) + } + + resolvedVersionPath, err := r.resolveVersion(s, rulesetName, version) + if err != nil { + return RulesetDownloadOutput{}, err + } + + metadata, err := r.readMetadata(s, resolvedVersionPath) + if err != nil { + return RulesetDownloadOutput{}, err + } + + tarballData, err := r.readTarball(s, resolvedVersionPath, metadata.Name, metadata.Version) + if err != nil { + return RulesetDownloadOutput{}, err + } + + if err := r.verifyTarballChecksum(s, tarballData, metadata.ChecksumSHA256); err != nil { + return RulesetDownloadOutput{}, fmt.Errorf("tarball integrity check failed: %w", err) + } + + return RulesetDownloadOutput{ + TarballData: tarballData, + Metadata: metadata, + }, nil +} diff --git a/pkg/usecase/ruleset_download_test.go b/pkg/usecase/ruleset_download_test.go new file mode 100644 index 0000000..1d3b55f --- /dev/null +++ b/pkg/usecase/ruleset_download_test.go @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025 SCANOSS.COM + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package usecase + +import ( + "context" + "encoding/json" + "os" + "path/filepath" + "strings" + "testing" + + zlog "github.com/scanoss/zap-logging-helper/pkg/logger" + myconfig "scanoss.com/cryptography/pkg/config" +) + +func TestNewRulesetDownload(t *testing.T) { + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = "/tmp/rulesets" + + usecase := NewRulesetDownload(config) + if usecase == nil { + t.Error("NewRulesetDownload() returned nil") + } + if usecase.config == nil { + t.Error("NewRulesetDownload() config is nil") + } + if usecase.config.Rulesets.StoragePath != "/tmp/rulesets" { + t.Errorf("Expected storage path '/tmp/rulesets', got '%s'", usecase.config.Rulesets.StoragePath) + } +} + +func TestRulesetDownloadUseCase_DownloadRuleset(t *testing.T) { + // Initialize logger + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + // Get the project root directory (assuming tests run from project root or pkg/usecase) + projectRoot, err := filepath.Abs("../../") + if err != nil { + t.Fatalf("failed to get project root: %v", err) + } + testStoragePath := filepath.Join(projectRoot, "test-support", "rulesets") + + // Verify test data exists + if _, err := os.Stat(testStoragePath); os.IsNotExist(err) { + t.Skipf("Test data not found at %s, skipping tests", testStoragePath) + } + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = testStoragePath + + usecase := NewRulesetDownload(config) + ctx := context.Background() + s := zlog.S + + tests := []struct { + name string + rulesetName string + version string + expectError bool + errorContains string + validateResult func(t *testing.T, result RulesetDownloadOutput) + }{ + { + name: "download specific version - dca v1.0.1", + rulesetName: "dca", + version: "v1.0.1", + expectError: false, + validateResult: func(t *testing.T, result RulesetDownloadOutput) { + if result.Metadata.Name != "dca" { + t.Errorf("Expected name 'dca', got '%s'", result.Metadata.Name) + } + if result.Metadata.Version != "v1.0.1" { + t.Errorf("Expected version 'v1.0.1', got '%s'", result.Metadata.Version) + } + if len(result.TarballData) == 0 { + t.Error("Expected non-empty tarball data") + } + if result.Metadata.ChecksumSHA256 == "" { + t.Error("Expected non-empty checksum") + } + }, + }, + { + name: "download specific version - dca v1.0.0", + rulesetName: "dca", + version: "v1.0.0", + expectError: false, + validateResult: func(t *testing.T, result RulesetDownloadOutput) { + if result.Metadata.Name != "dca" { + t.Errorf("Expected name 'dca', got '%s'", result.Metadata.Name) + } + if result.Metadata.Version != "v1.0.0" { + t.Errorf("Expected version 'v1.0.0', got '%s'", result.Metadata.Version) + } + if len(result.TarballData) == 0 { + t.Error("Expected non-empty tarball data") + } + }, + }, + { + name: "download latest version", + rulesetName: "dca", + version: "latest", + expectError: false, + validateResult: func(t *testing.T, result RulesetDownloadOutput) { + if result.Metadata.Name != "dca" { + t.Errorf("Expected name 'dca', got '%s'", result.Metadata.Name) + } + // The latest symlink should point to v1.0.1 + if result.Metadata.Version != "v1.0.1" { + t.Errorf("Expected latest version to be 'v1.0.1', got '%s'", result.Metadata.Version) + } + if len(result.TarballData) == 0 { + t.Error("Expected non-empty tarball data") + } + }, + }, + { + name: "ruleset not found", + rulesetName: "nonexistent-ruleset", + version: "v1.0.0", + expectError: true, + errorContains: "not found", + }, + { + name: "version not found", + rulesetName: "dca", + version: "v99.99.99", + expectError: true, + errorContains: "not found", + }, + { + name: "empty ruleset name", + rulesetName: "", + version: "v1.0.0", + expectError: true, + errorContains: "not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := usecase.DownloadRuleset(ctx, s, tt.rulesetName, tt.version) + + if tt.expectError { + if err == nil { + t.Errorf("Expected error containing '%s', got nil", tt.errorContains) + return + } + if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { + t.Errorf("Expected error containing '%s', got '%s'", tt.errorContains, err.Error()) + } + } else { + if err != nil { + t.Errorf("Expected no error, got: %v", err) + return + } + if tt.validateResult != nil { + tt.validateResult(t, result) + } + } + }) + } +} + +func TestRulesetDownloadUseCase_resolveVersion(t *testing.T) { + // Initialize logger + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + projectRoot, err := filepath.Abs("../../") + if err != nil { + t.Fatalf("failed to get project root: %v", err) + } + testStoragePath := filepath.Join(projectRoot, "test-support", "rulesets") + + if _, err := os.Stat(testStoragePath); os.IsNotExist(err) { + t.Skipf("Test data not found at %s, skipping tests", testStoragePath) + } + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = testStoragePath + + usecase := NewRulesetDownload(config) + s := zlog.S + + tests := []struct { + name string + rulesetName string + version string + expectError bool + errorContains string + }{ + { + name: "resolve specific version", + rulesetName: "dca", + version: "v1.0.1", + expectError: false, + }, + { + name: "resolve latest symlink", + rulesetName: "dca", + version: "latest", + expectError: false, + }, + { + name: "ruleset does not exist", + rulesetName: "nonexistent", + version: "v1.0.0", + expectError: true, + errorContains: "not found", + }, + { + name: "version does not exist", + rulesetName: "dca", + version: "v99.99.99", + expectError: true, + errorContains: "not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := usecase.resolveVersion(s, tt.rulesetName, tt.version) + + if tt.expectError { + if err == nil { + t.Error("Expected error, got nil") + return + } + if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { + t.Errorf("Expected error containing '%s', got '%s'", tt.errorContains, err.Error()) + } + } else { + if err != nil { + t.Errorf("Expected no error, got: %v", err) + return + } + if result == "" { + t.Error("Expected non-empty result path") + } + // Verify the path exists + if _, err := os.Stat(result); err != nil { + t.Errorf("Resolved path does not exist: %s", result) + } + } + }) + } +} + +func TestRulesetDownloadUseCase_readMetadata(t *testing.T) { + // Initialize logger + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + projectRoot, err := filepath.Abs("../../") + if err != nil { + t.Fatalf("failed to get project root: %v", err) + } + testStoragePath := filepath.Join(projectRoot, "test-support", "rulesets") + + if _, err := os.Stat(testStoragePath); os.IsNotExist(err) { + t.Skipf("Test data not found at %s, skipping tests", testStoragePath) + } + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = testStoragePath + + usecase := NewRulesetDownload(config) + s := zlog.S + + tests := []struct { + name string + versionPath string + expectError bool + errorContains string + validateMeta func(t *testing.T, meta RulesetMetadata) + }{ + { + name: "read valid metadata", + versionPath: filepath.Join(testStoragePath, "dca", "v1.0.1"), + expectError: false, + validateMeta: func(t *testing.T, meta RulesetMetadata) { + if meta.Name != "dca" { + t.Errorf("Expected name 'dca', got '%s'", meta.Name) + } + if meta.Version != "v1.0.1" { + t.Errorf("Expected version 'v1.0.1', got '%s'", meta.Version) + } + if meta.ChecksumSHA256 == "" { + t.Error("Expected non-empty checksum") + } + }, + }, + { + name: "metadata file does not exist", + versionPath: filepath.Join(testStoragePath, "nonexistent"), + expectError: true, + errorContains: "failed to read metadata", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := usecase.readMetadata(s, tt.versionPath) + + if tt.expectError { + if err == nil { + t.Error("Expected error, got nil") + return + } + if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { + t.Errorf("Expected error containing '%s', got '%s'", tt.errorContains, err.Error()) + } + } else { + if err != nil { + t.Errorf("Expected no error, got: %v", err) + return + } + if tt.validateMeta != nil { + tt.validateMeta(t, result) + } + } + }) + } +} + +func TestRulesetDownloadUseCase_readTarball(t *testing.T) { + // Initialize logger + err := zlog.NewSugaredDevLogger() + if err != nil { + t.Fatalf("failed to initialize logger: %v", err) + } + defer zlog.SyncZap() + + projectRoot, err := filepath.Abs("../../") + if err != nil { + t.Fatalf("failed to get project root: %v", err) + } + testStoragePath := filepath.Join(projectRoot, "test-support", "rulesets") + + if _, err := os.Stat(testStoragePath); os.IsNotExist(err) { + t.Skipf("Test data not found at %s, skipping tests", testStoragePath) + } + + config := &myconfig.ServerConfig{} + config.Rulesets.StoragePath = testStoragePath + + usecase := NewRulesetDownload(config) + s := zlog.S + + tests := []struct { + name string + versionPath string + rulesetName string + rulesetVersion string + expectError bool + errorContains string + }{ + { + name: "read valid tarball", + versionPath: filepath.Join(testStoragePath, "dca", "v1.0.1"), + rulesetName: "dca", + rulesetVersion: "v1.0.1", + expectError: false, + }, + { + name: "tarball does not exist", + versionPath: filepath.Join(testStoragePath, "dca", "v1.0.1"), + rulesetName: "dca", + rulesetVersion: "v99.99.99", + expectError: true, + errorContains: "not found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := usecase.readTarball(s, tt.versionPath, tt.rulesetName, tt.rulesetVersion) + + if tt.expectError { + if err == nil { + t.Error("Expected error, got nil") + return + } + if tt.errorContains != "" && !strings.Contains(err.Error(), tt.errorContains) { + t.Errorf("Expected error containing '%s', got '%s'", tt.errorContains, err.Error()) + } + } else { + if err != nil { + t.Errorf("Expected no error, got: %v", err) + return + } + if len(result) == 0 { + t.Error("Expected non-empty tarball data") + } + } + }) + } +} + +func TestRulesetMetadata_JSON(t *testing.T) { + // Test JSON marshaling/unmarshaling + original := RulesetMetadata{ + Name: "test-ruleset", + Version: "v1.0.0", + Description: "Test description", + CreatedAt: "2025-01-01T00:00:00Z", + ChecksumSHA256: "abc123", + } + + // Marshal to JSON + jsonData, err := json.Marshal(original) + if err != nil { + t.Fatalf("Failed to marshal metadata: %v", err) + } + + // Unmarshal back + var decoded RulesetMetadata + err = json.Unmarshal(jsonData, &decoded) + if err != nil { + t.Fatalf("Failed to unmarshal metadata: %v", err) + } + + // Verify fields + if decoded.Name != original.Name { + t.Errorf("Name mismatch: expected '%s', got '%s'", original.Name, decoded.Name) + } + if decoded.Version != original.Version { + t.Errorf("Version mismatch: expected '%s', got '%s'", original.Version, decoded.Version) + } + if decoded.Description != original.Description { + t.Errorf("Description mismatch: expected '%s', got '%s'", original.Description, decoded.Description) + } + if decoded.CreatedAt != original.CreatedAt { + t.Errorf("CreatedAt mismatch: expected '%s', got '%s'", original.CreatedAt, decoded.CreatedAt) + } + if decoded.ChecksumSHA256 != original.ChecksumSHA256 { + t.Errorf("ChecksumSHA256 mismatch: expected '%s', got '%s'", original.ChecksumSHA256, decoded.ChecksumSHA256) + } +} diff --git a/test-support/rulesets/dca/latest b/test-support/rulesets/dca/latest new file mode 120000 index 0000000..6a2b0ac --- /dev/null +++ b/test-support/rulesets/dca/latest @@ -0,0 +1 @@ +v1.0.1 \ No newline at end of file diff --git a/test-support/rulesets/dca/v1.0.0/dca-v1.0.0.tar.gz b/test-support/rulesets/dca/v1.0.0/dca-v1.0.0.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..a0351c1fb3cb965150431797fd5117afc5eaadd4 GIT binary patch literal 75246 zcmY(qWmH^E(*=sVhXBFdg1fuBJHg$8JA(&zcXt8=4H`VSJHg%EnR9vG@2LuDEMStd>xLyY<-6wXv0VG{7xU_WfYE;+}Fgf)T$=p$i@zE zsI22`DeSJgJjI?f&yZ@=wfm)5HN>H>aQ<0SzLYcWu7m;ROBNd@PEtWk=(PgY`i*Ey z2Y=Vl-Q zFhQQ&I2Wmx#3eH_Io(3`FB3>YGU~&Oe>v0J}o;5fC%WJ*-S|u<#Y8(x_9-2=w52p$jT}uPw>9sRP|2 zy*>mypFBjf^$<-tZr=jAUeU606lAOKZwvX~5bN@c5Vc1PIC;DWfH_IuvPjIx?n394pn-|kWG(RQ1sOFgfH zJzx*u@-<}m+MMrobKVkk8@mVwhGz1Cf2;Y4Y=oO)uitcg{0{byy|}tSrFTOR6L>5J(B~osq al$4`>7e*RaKE1} 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 al$4`>7e*RaKE1} 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