From 5376364549273497b09c622f77962c8aa7732822 Mon Sep 17 00:00:00 2001 From: Or Toren Date: Mon, 30 Mar 2026 11:57:23 +0300 Subject: [PATCH 1/2] save results in gitlab format --- scanrepository/scanrepository.go | 11 +- utils/consts.go | 9 +- utils/getconfiguration.go | 16 +- utils/gitlabreport/gitlabreport.go | 334 +++++++++++++++++++++++++++++ utils/utils.go | 57 ++++- 5 files changed, 415 insertions(+), 12 deletions(-) create mode 100644 utils/gitlabreport/gitlabreport.go diff --git a/scanrepository/scanrepository.go b/scanrepository/scanrepository.go index 379c45d29..88bc5e68a 100644 --- a/scanrepository/scanrepository.go +++ b/scanrepository/scanrepository.go @@ -4,12 +4,13 @@ import ( "context" "errors" "fmt" - "github.com/jfrog/frogbot/v2/packageupdaters" "os" "path/filepath" "regexp" "strings" + "github.com/jfrog/frogbot/v2/packageupdaters" + "github.com/go-git/go-git/v5" biutils "github.com/jfrog/build-info-go/utils" @@ -154,6 +155,14 @@ func (sr *ScanRepositoryCmd) scanAndFixBranch(repository *utils.Repository) (tot totalFindings = getTotalFindingsFromScanResults(scanResults) sr.uploadResultsToGithubDashboardsIfNeeded(repository, scanResults) + if repository.Params.Git.GitProvider == vcsutils.GitLab && repository.Params.Git.GitlabScanResultsOutputDir != "" { + log.Debug(fmt.Sprintf("Trying to save scan results to directory: %s", repository.Params.Git.GitlabScanResultsOutputDir)) + if err = utils.WriteScanResultsToDir(repository.Params.Git.GitlabScanResultsOutputDir, scanResults, sr.scanDetails.StartTime); err != nil { + log.Warn(fmt.Sprintf("Failed to write scan results to directory: %s", err.Error())) + } + return + } + if !repository.Params.FrogbotConfig.CreateAutoFixPr { log.Info(fmt.Sprintf("This command is running in detection mode only. To enable automatic fixing of issues, set the '%s' flag under the repository's coniguration settings in Jfrog platform", createAutoFixPrConfigNameInProfile)) return totalFindings, nil diff --git a/utils/consts.go b/utils/consts.go index f124f9e1a..d56674008 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -42,10 +42,11 @@ const ( GitDependencyGraphSubmissionEnv = "JF_UPLOAD_SBOM_TO_VCS" //#nosec G101 -- False positive - no hardcoded credentials. - GitTokenEnv = "JF_GIT_TOKEN" - GitBaseBranchEnv = "JF_GIT_BASE_BRANCH" - GitPullRequestIDEnv = "JF_GIT_PULL_REQUEST_ID" - GitApiEndpointEnv = "JF_GIT_API_ENDPOINT" + GitTokenEnv = "JF_GIT_TOKEN" + GitBaseBranchEnv = "JF_GIT_BASE_BRANCH" + GitPullRequestIDEnv = "JF_GIT_PULL_REQUEST_ID" + GitApiEndpointEnv = "JF_GIT_API_ENDPOINT" + GitlabScanResultsOutputDirEnv = "JF_SCAN_RESULTS_OUTPUT_DIR" // Placeholders for templates PackagePlaceHolder = "{IMPACTED_PACKAGE}" diff --git a/utils/getconfiguration.go b/utils/getconfiguration.go index b4941e6c9..6e39774c2 100644 --- a/utils/getconfiguration.go +++ b/utils/getconfiguration.go @@ -68,12 +68,13 @@ func (jp *JFrogPlatform) setJfProjectKeyIfExists() (err error) { type Git struct { GitProvider vcsutils.VcsProvider vcsclient.VcsInfo - RepoOwner string - RepoName string - Branches []string - PullRequestDetails vcsclient.PullRequestInfo - RepositoryCloneUrl string - UploadSbomToVcs *bool + RepoOwner string + RepoName string + Branches []string + PullRequestDetails vcsclient.PullRequestInfo + RepositoryCloneUrl string + UploadSbomToVcs *bool + GitlabScanResultsOutputDir string } func (g *Git) GetRepositoryHttpsCloneUrl(gitClient vcsclient.VcsClient) (string, error) { @@ -95,6 +96,7 @@ func (g *Git) setDefaultsIfNeeded(gitParamsFromEnv *Git, commandName string) (er g.VcsInfo = gitParamsFromEnv.VcsInfo g.PullRequestDetails = gitParamsFromEnv.PullRequestDetails g.RepoName = gitParamsFromEnv.RepoName + g.GitlabScanResultsOutputDir = gitParamsFromEnv.GitlabScanResultsOutputDir if commandName == ScanPullRequest { if gitParamsFromEnv.PullRequestDetails.ID == 0 { @@ -425,6 +427,8 @@ func extractGitParamsFromEnvs() (*Git, error) { gitEnvParams.PullRequestDetails = vcsclient.PullRequestInfo{ID: int64(convertedPrId)} } + gitEnvParams.GitlabScanResultsOutputDir = getTrimmedEnv(GitlabScanResultsOutputDirEnv) + return gitEnvParams, nil } diff --git a/utils/gitlabreport/gitlabreport.go b/utils/gitlabreport/gitlabreport.go new file mode 100644 index 000000000..0667e0201 --- /dev/null +++ b/utils/gitlabreport/gitlabreport.go @@ -0,0 +1,334 @@ +package gitlabreport + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/jfrog/jfrog-cli-security/utils/formats" + "github.com/jfrog/jfrog-cli-security/utils/results" + "github.com/jfrog/jfrog-cli-security/utils/results/conversion" + "github.com/jfrog/jfrog-cli-security/utils/techutils" + "github.com/jfrog/jfrog-client-go/utils/log" +) + +const ( + gitLabReportSchemaVersion = "15.2.4" + gitLabReportSchemaURL = "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/dependency-scanning-report-format.json" + frogbotAnalyzerID = "frogbot-dependency-scanning" + frogbotAnalyzerName = "JFrog Frogbot" + frogbotVendorName = "JFrog" +) + +type DependencyScanningReport struct { + Scan ScanReport `json:"scan"` + Schema string `json:"schema,omitempty"` + Version string `json:"version"` + Vulnerabilities []VulnerabilityReport `json:"vulnerabilities"` +} + +type ScanReport struct { + Analyzer AnalyzerScanner `json:"analyzer"` + Scanner AnalyzerScanner `json:"scanner"` + StartTime string `json:"start_time"` // ISO8601 UTC yyyy-mm-ddThh:mm:ss + EndTime string `json:"end_time"` + Status string `json:"status"` // "success" or "failure" + Type string `json:"type"` // "dependency_scanning" +} + +type AnalyzerScanner struct { + ID string `json:"id"` + Name string `json:"name"` + Version string `json:"version"` + Vendor Vendor `json:"vendor"` + URL string `json:"url,omitempty"` +} + +type Vendor struct { + Name string `json:"name"` +} + +type VulnerabilityReport struct { + ID string `json:"id"` + Name string `json:"name,omitempty"` + Description string `json:"description,omitempty"` + Severity string `json:"severity,omitempty"` // Info, Unknown, Low, Medium, High, Critical + Solution string `json:"solution,omitempty"` + Identifiers []Identifier `json:"identifiers"` + Location Location `json:"location"` + Links []Link `json:"links,omitempty"` +} + +type Identifier struct { + Type string `json:"type"` + Name string `json:"name"` + Value string `json:"value"` + URL string `json:"url,omitempty"` +} + +type Location struct { + File string `json:"file"` + Dependency Dependency `json:"dependency"` +} + +type Dependency struct { + Package Package `json:"package"` + Version string `json:"version"` + Direct *bool `json:"direct,omitempty"` +} + +type Package struct { + Name string `json:"name"` +} + +type Link struct { + Name string `json:"name,omitempty"` + URL string `json:"url"` +} + +func ConvertToGitLabDependencyScanningReport(scanResults *results.SecurityCommandResults, startTime, endTime time.Time, frogbotVersion string) (*DependencyScanningReport, error) { + if scanResults == nil { + return &DependencyScanningReport{ + Scan: ScanReport{ + Analyzer: makeAnalyzerScanner(frogbotVersion), + Scanner: makeAnalyzerScanner(frogbotVersion), + StartTime: formatGitLabTime(startTime), + EndTime: formatGitLabTime(endTime), + Status: "success", + Type: "dependency_scanning", + }, + Version: gitLabReportSchemaVersion, + Schema: gitLabReportSchemaURL, + Vulnerabilities: []VulnerabilityReport{}, + }, nil + } + + convertor := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ + IncludeVulnerabilities: scanResults.IncludesVulnerabilities(), + HasViolationContext: scanResults.HasViolationContext(), + }) + simpleJSON, err := convertor.ConvertToSimpleJson(scanResults) + if err != nil { + return nil, fmt.Errorf("convert to simple json: %w", err) + } + + var vulns []formats.VulnerabilityOrViolationRow + vulns = append(vulns, simpleJSON.Vulnerabilities...) + vulns = append(vulns, simpleJSON.SecurityViolations...) + + reports := make([]VulnerabilityReport, 0, len(vulns)) + seen := make(map[string]struct{}) + + for i := range vulns { + v := &vulns[i] + key := v.ImpactedDependencyName + "|" + v.ImpactedDependencyVersion + "|" + v.IssueId + if _, ok := seen[key]; ok { + continue + } + seen[key] = struct{}{} + + report := vulnerabilityToReport(v) + reports = append(reports, report) + } + + status := "success" + if err = scanResults.GetErrors(); err != nil { + status = "failure" + } + + return &DependencyScanningReport{ + Scan: ScanReport{ + Analyzer: makeAnalyzerScanner(frogbotVersion), + Scanner: makeAnalyzerScanner(frogbotVersion), + StartTime: formatGitLabTime(startTime), + EndTime: formatGitLabTime(endTime), + Status: status, + Type: "dependency_scanning", + }, + Schema: gitLabReportSchemaURL, + Version: gitLabReportSchemaVersion, + Vulnerabilities: reports, + }, nil +} + +func makeAnalyzerScanner(version string) AnalyzerScanner { + if version == "" { + version = "0.0.0" + } + return AnalyzerScanner{ + ID: frogbotAnalyzerID, + Name: frogbotAnalyzerName, + Version: version, + Vendor: Vendor{Name: frogbotVendorName}, + URL: "https://github.com/jfrog/frogbot", + } +} + +func formatGitLabTime(t time.Time) string { + return t.UTC().Format("2006-01-02T15:04:05") +} + +func vulnerabilityToReport(v *formats.VulnerabilityOrViolationRow) VulnerabilityReport { + id := deterministicVulnID(v.ImpactedDependencyName, v.ImpactedDependencyVersion, v.IssueId, v.Cves) + identifiers := buildIdentifiers(v) + location := Location{ + File: manifestFileForTechnology(v.Technology), + Dependency: Dependency{ + Package: Package{Name: v.ImpactedDependencyName}, + Version: v.ImpactedDependencyVersion, + }, + } + severity := normalizeSeverity(getSeverity(v)) + name := v.IssueId + if len(v.Cves) > 0 { + name = v.Cves[0].Id + } + desc := getSummary(v) + solution := "" + if len(v.FixedVersions) > 0 { + solution = fmt.Sprintf("Upgrade %s to version %s or later.", v.ImpactedDependencyName, v.FixedVersions[0]) + } + var links []Link + for _, cve := range v.Cves { + if cve.Id != "" { + links = append(links, Link{Name: cve.Id, URL: "https://nvd.nist.gov/vuln/detail/" + cve.Id}) + } + } + return VulnerabilityReport{ + ID: id, + Name: name, + Description: desc, + Severity: severity, + Solution: solution, + Identifiers: identifiers, + Location: location, + Links: links, + } +} + +func deterministicVulnID(pkg, version, issueId string, cves []formats.CveRow) string { + h := sha256.New() + h.Write([]byte(pkg)) + h.Write([]byte("|")) + h.Write([]byte(version)) + h.Write([]byte("|")) + h.Write([]byte(issueId)) + for _, c := range cves { + h.Write([]byte(c.Id)) + } + sum := h.Sum(nil) + hexStr := hex.EncodeToString(sum) + // Format as UUID-like 8-4-4-4-12 for compatibility + if len(hexStr) < 32 { + hexStr = hexStr + strings.Repeat("0", 32-len(hexStr)) + } + return hexStr[0:8] + "-" + hexStr[8:12] + "-" + hexStr[12:16] + "-" + hexStr[16:20] + "-" + hexStr[20:32] +} + +func buildIdentifiers(v *formats.VulnerabilityOrViolationRow) []Identifier { + var ids []Identifier + for _, cve := range v.Cves { + if cve.Id != "" { + ids = append(ids, Identifier{ + Type: "cve", + Name: "CVE", + Value: cve.Id, + URL: "https://nvd.nist.gov/vuln/detail/" + cve.Id, + }) + } + } + if v.IssueId != "" && !strings.HasPrefix(strings.ToUpper(v.IssueId), "CVE-") { + ids = append(ids, Identifier{ + Type: "xray", + Name: "Xray", + Value: v.IssueId, + }) + } + if len(ids) == 0 { + ids = append(ids, Identifier{ + Type: "other", + Name: "JFrog Xray", + Value: v.ImpactedDependencyName + "@" + v.ImpactedDependencyVersion, + }) + } + return ids +} + +func getSeverity(v *formats.VulnerabilityOrViolationRow) string { + if v.Severity != "" { + return v.Severity + } + if v.ImpactedDependencyDetails.SeverityDetails.Severity != "" { + return v.ImpactedDependencyDetails.SeverityDetails.Severity + } + return "" +} + +func getSummary(v *formats.VulnerabilityOrViolationRow) string { + if v.Summary != "" { + return v.Summary + } + if v.JfrogResearchInformation != nil && v.JfrogResearchInformation.Summary != "" { + return v.JfrogResearchInformation.Summary + } + return "" +} + +func normalizeSeverity(severity string) string { + switch strings.ToLower(severity) { + case "critical": + return "Critical" + case "high": + return "High" + case "medium", "moderate": + return "Medium" + case "low": + return "Low" + case "info", "informational": + return "Info" + default: + return "Unknown" + } +} + +func manifestFileForTechnology(tech techutils.Technology) string { + switch tech { + case techutils.Npm, techutils.Yarn: + return "package-lock.json" + case techutils.Go: + return "go.sum" + case techutils.Pip, techutils.Pipenv: + return "requirements.txt" + case techutils.Maven: + return "pom.xml" + case techutils.Nuget: + return "packages.config" + default: + return "manifest" + } +} + +// WriteDependencyScanningReport writes the GitLab dependency-scanning report to outputDir/gl-dependency-scanning-report.json. +func WriteDependencyScanningReport(outputDir string, report *DependencyScanningReport) error { + if outputDir == "" { + return fmt.Errorf("output directory is required") + } + if err := os.MkdirAll(outputDir, 0755); err != nil { + return fmt.Errorf("create output dir: %w", err) + } + path := filepath.Join(outputDir, "gl-dependency-scanning-report.json") + data, err := json.MarshalIndent(report, "", " ") + if err != nil { + return fmt.Errorf("marshal report: %w", err) + } + if err := os.WriteFile(path, data, 0644); err != nil { + return fmt.Errorf("write report: %w", err) + } + log.Info(fmt.Sprintf("GitLab dependency-scanning report written to %s", path)) + return nil +} diff --git a/utils/utils.go b/utils/utils.go index 1876d2c6b..f573a3804 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -8,11 +8,14 @@ import ( "fmt" "net/http" "os" + "path/filepath" "regexp" "sort" "strings" "sync" + "time" + "github.com/CycloneDX/cyclonedx-go" "github.com/jfrog/froggit-go/vcsclient" "github.com/jfrog/gofrog/version" "github.com/jfrog/jfrog-cli-core/v2/common/commands" @@ -29,6 +32,7 @@ import ( "github.com/jfrog/jfrog-client-go/utils/io/fileutils" "github.com/jfrog/jfrog-client-go/utils/log" + "github.com/jfrog/frogbot/v2/utils/gitlabreport" "github.com/jfrog/frogbot/v2/utils/issues" ) @@ -49,7 +53,8 @@ const ( skipIndirectVulnerabilitiesMsg = "\n%s is an indirect dependency that will not be updated to version %s.\nFixing indirect dependencies can potentially cause conflicts with other dependencies that depend on the previous version.\nFrogbot skips this to avoid potential incompatibilities and breaking changes." skipBuildToolDependencyMsg = "Skipping vulnerable package %s since it is not defined in your package descriptor file. " + "Update %s version to %s to fix this vulnerability." - JfrogHomeDirEnv = "JFROG_CLI_HOME_DIR" + JfrogHomeDirEnv = "JFROG_CLI_HOME_DIR" + cyclonedxOutputFilename = "cyclonedx.json" ) var ( @@ -459,3 +464,53 @@ func CreateErrorIfFailUponScannerErrorEnabled(fail bool, messageForLog string, e } return err } + +func WriteScanResultsToDir(outputDir string, scanResults *results.SecurityCommandResults, startTime time.Time) error { + if outputDir == "" { + return fmt.Errorf("output directory is required") + } + if err := os.MkdirAll(outputDir, 0755); err != nil { + return fmt.Errorf("create output dir: %w", err) + } + endTime := time.Now().UTC() + + if err := writeCycloneDxToDir(outputDir, scanResults); err != nil { + return fmt.Errorf("write CycloneDX: %w", err) + } + report, err := gitlabreport.ConvertToGitLabDependencyScanningReport(scanResults, startTime, endTime, FrogbotVersion) + if err != nil { + return fmt.Errorf("convert to GitLab report: %w", err) + } + if err = gitlabreport.WriteDependencyScanningReport(outputDir, report); err != nil { + return fmt.Errorf("write GitLab report: %w", err) + } + log.Info(fmt.Sprintf("Scan results written to %s (CycloneDX and GitLab dependency-scanning format)", outputDir)) + return nil +} + +func writeCycloneDxToDir(outputDir string, scanResults *results.SecurityCommandResults) error { + if scanResults == nil { + return fmt.Errorf("scan results are required") + } + fullBom, err := conversion.NewCommandResultsConvertor(conversion.ResultConvertParams{ + HasViolationContext: scanResults.HasViolationContext(), + IncludeVulnerabilities: scanResults.IncludesVulnerabilities(), + IncludeSbom: true, + }).ConvertToCycloneDx(scanResults) + if err != nil { + return fmt.Errorf("convert to CycloneDX: %w", err) + } + bom := fullBom.BOM + path := filepath.Join(outputDir, cyclonedxOutputFilename) + f, err := os.Create(path) + if err != nil { + return fmt.Errorf("create file: %w", err) + } + defer func() { _ = f.Close() }() + encoder := cyclonedx.NewBOMEncoder(f, cyclonedx.BOMFileFormatJSON) + if err = encoder.Encode(&bom); err != nil { + return fmt.Errorf("encode CycloneDX: %w", err) + } + log.Info(fmt.Sprintf("CycloneDX SBOM written to %s", path)) + return nil +} From afc390786cd33fb4215c212c0d1bd29e4bb2e346 Mon Sep 17 00:00:00 2001 From: JFrog-Frogbot Date: Mon, 30 Mar 2026 08:59:54 +0000 Subject: [PATCH 2/2] Upgrade google.golang.org/grpc to 1.79.3 --- go.mod | 20 ++++++++++---------- go.sum | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 728fae4e4..d5c2c2de8 100644 --- a/go.mod +++ b/go.mod @@ -111,18 +111,18 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.45.0 // indirect + golang.org/x/crypto v0.46.0 // indirect golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/oauth2 v0.33.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/term v0.37.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/oauth2 v0.34.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.12.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/grpc v1.72.1 // indirect - google.golang.org/protobuf v1.36.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect + google.golang.org/grpc v1.79.3 // indirect + google.golang.org/protobuf v1.36.10 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 01c9dfc9a..109114593 100644 --- a/go.sum +++ b/go.sum @@ -83,6 +83,7 @@ github.com/go-git/go-git/v5 v5.16.5 h1:mdkuqblwr57kVfXri5TTH+nMFLNUxIj9Z7F5ykFbw github.com/go-git/go-git/v5 v5.16.5/go.mod h1:QOMLpNf1qxuSY4StA/ArOdfFR2TrKEjJiye2kel2m+M= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= @@ -320,16 +321,22 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -340,6 +347,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39 h1:DHNhtq3sNNzrvduZZIiFyXWOL9IWaDPHqTnLJp+rCBY= golang.org/x/exp v0.0.0-20251125195548-87e1e737ad39/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -362,10 +371,14 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -374,6 +387,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -407,6 +422,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -415,6 +432,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -424,6 +443,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -440,10 +461,16 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=