mirror of
https://github.com/safedep/vet.git
synced 2025-12-10 13:43:01 -06:00
fix: Package manifest namespace and path handling
This commit is contained in:
parent
69e32d99cc
commit
18af8d54e1
@ -2,11 +2,13 @@ package cloud
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/jedib0t/go-pretty/v6/table"
|
"github.com/jedib0t/go-pretty/v6/table"
|
||||||
"github.com/safedep/vet/internal/auth"
|
"github.com/safedep/vet/internal/auth"
|
||||||
|
"github.com/safedep/vet/internal/ui"
|
||||||
"github.com/safedep/vet/pkg/cloud/query"
|
"github.com/safedep/vet/pkg/cloud/query"
|
||||||
"github.com/safedep/vet/pkg/common/logger"
|
"github.com/safedep/vet/pkg/common/logger"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@ -82,6 +84,8 @@ func renderQueryResponseAsTable(response *query.QueryResponse) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.PrintSuccess(fmt.Sprintf("Query returned %d results", response.Count()))
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
headers := []string{}
|
headers := []string{}
|
||||||
response.GetRow(0).ForEachField(func(key string, _ interface{}) {
|
response.GetRow(0).ForEachField(func(key string, _ interface{}) {
|
||||||
|
|||||||
4
go.mod
4
go.mod
@ -3,8 +3,8 @@ module github.com/safedep/vet
|
|||||||
go 1.22.1
|
go 1.22.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241009065537-4ffd9786549f.1
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241011110723-95b33664baad.1
|
||||||
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241009065537-4ffd9786549f.1
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241011110723-95b33664baad.1
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.7
|
github.com/AlecAivazis/survey/v2 v2.3.7
|
||||||
github.com/CycloneDX/cyclonedx-go v0.9.0
|
github.com/CycloneDX/cyclonedx-go v0.9.0
|
||||||
github.com/anchore/syft v1.11.1
|
github.com/anchore/syft v1.11.1
|
||||||
|
|||||||
8
go.sum
8
go.sum
@ -1,9 +1,17 @@
|
|||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.35.1-20240508200655-46a4cf4ba109.1 h1:PvjTFY+MqrYYulH74R8ddQodrEP1sThjkba8kcqO2dM=
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.35.1-20240508200655-46a4cf4ba109.1 h1:PvjTFY+MqrYYulH74R8ddQodrEP1sThjkba8kcqO2dM=
|
||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.35.1-20240508200655-46a4cf4ba109.1/go.mod h1:Duw/9JoXkXIydyASnLYIiufkzySThoqavOsF+IihqvM=
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.35.1-20240508200655-46a4cf4ba109.1/go.mod h1:Duw/9JoXkXIydyASnLYIiufkzySThoqavOsF+IihqvM=
|
||||||
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241008111718-480f2b42b425.1 h1:ofDpCRg/yPfD0UMny+yaq4G5sHLNFhBH2DtIN9orEzQ=
|
||||||
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241008111718-480f2b42b425.1/go.mod h1:DGREO91B1aVG1+zfN4gT/ZQZ0Ykcv+TZGf18SeGDcMc=
|
||||||
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241009065537-4ffd9786549f.1 h1:7+y3t/2/6sEf63xCX9ErNdsuFzB0Q18PIT14aAxz5wo=
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241009065537-4ffd9786549f.1 h1:7+y3t/2/6sEf63xCX9ErNdsuFzB0Q18PIT14aAxz5wo=
|
||||||
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241009065537-4ffd9786549f.1/go.mod h1:Io32CuF5oJZDSkWJVgKvfOBTqSHnC7mqh9dpqq/PSNA=
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241009065537-4ffd9786549f.1/go.mod h1:Io32CuF5oJZDSkWJVgKvfOBTqSHnC7mqh9dpqq/PSNA=
|
||||||
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241011110723-95b33664baad.1 h1:bUOILp76S06U58bp3EWI6qsoeEEBGGQJeMFdQ5Otc34=
|
||||||
|
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20241011110723-95b33664baad.1/go.mod h1:LSghi5M4Z+uYLyo85Bs6lVpzit6ZoSph8YOyvpHL3mY=
|
||||||
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241008111718-480f2b42b425.1 h1:IziBLru8MusSLO2lNDzSxbVxKu0dGI8zE8vG+tCMYjI=
|
||||||
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241008111718-480f2b42b425.1/go.mod h1:WCxZaBpYxgWnSpauuzVhzbJawAp6uPXJPN5tbDpceQ0=
|
||||||
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241009065537-4ffd9786549f.1 h1:F4fk9nhlB2ZU8odF5S/w/nS8r0htIbu6eKDKDBP+kzQ=
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241009065537-4ffd9786549f.1 h1:F4fk9nhlB2ZU8odF5S/w/nS8r0htIbu6eKDKDBP+kzQ=
|
||||||
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241009065537-4ffd9786549f.1/go.mod h1:WCxZaBpYxgWnSpauuzVhzbJawAp6uPXJPN5tbDpceQ0=
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241009065537-4ffd9786549f.1/go.mod h1:WCxZaBpYxgWnSpauuzVhzbJawAp6uPXJPN5tbDpceQ0=
|
||||||
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241011110723-95b33664baad.1 h1:HMED4kNSQJgrmFZXorIP1mpVbnKxzvhMgc3BOawTtGw=
|
||||||
|
buf.build/gen/go/safedep/api/protocolbuffers/go v1.35.1-20241011110723-95b33664baad.1/go.mod h1:WCxZaBpYxgWnSpauuzVhzbJawAp6uPXJPN5tbDpceQ0=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
|||||||
@ -33,12 +33,13 @@ func cloudClientConnection(name, loc, tok string) (*grpc.ClientConn, error) {
|
|||||||
port = "443"
|
port = "443"
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debugf("ControlTower host: %s, port: %s", host, port)
|
logger.Debugf("Establishing grpc connection for: %s host: %s, port: %s",
|
||||||
|
name, host, port)
|
||||||
|
|
||||||
headers := http.Header{}
|
headers := http.Header{}
|
||||||
headers.Set("x-tenant-id", TenantDomain())
|
headers.Set("x-tenant-id", TenantDomain())
|
||||||
|
|
||||||
vetTenantMockUser := os.Getenv(controlTowerTenantEnvKey)
|
vetTenantMockUser := os.Getenv("VET_CONTROL_TOWER_MOCK_USER")
|
||||||
if vetTenantMockUser != "" {
|
if vetTenantMockUser != "" {
|
||||||
headers.Set("x-mock-user", vetTenantMockUser)
|
headers.Set("x-mock-user", vetTenantMockUser)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package models
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -29,17 +30,59 @@ const (
|
|||||||
EcosystemSpdxSBOM = "SpdxSbom"
|
EcosystemSpdxSBOM = "SpdxSbom"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ManifestSourceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ManifestSourceLocal = ManifestSourceType("local")
|
||||||
|
ManifestSourceGitRepository = ManifestSourceType("git_repository")
|
||||||
|
)
|
||||||
|
|
||||||
|
// We now have different sources from where a package
|
||||||
|
// manifest can be identified. For example, local, github,
|
||||||
|
// and may be in future within containers or archives like
|
||||||
|
// JAR. So we need to store additional internal metadata
|
||||||
|
type PackageManifestSource struct {
|
||||||
|
// The source type of this package namespace
|
||||||
|
Type ManifestSourceType
|
||||||
|
|
||||||
|
// The namespace of the package manifest. Examples:
|
||||||
|
// - Directory when source is local
|
||||||
|
// - GitHub repo URL when source is GitHub
|
||||||
|
Namespace string
|
||||||
|
|
||||||
|
// The namespace relative path of the package manifest
|
||||||
|
Path string
|
||||||
|
|
||||||
|
// Explicit override the display path
|
||||||
|
DisplayPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps PackageManifestSource) GetDisplayPath() string {
|
||||||
|
switch ps.Type {
|
||||||
|
case ManifestSourceLocal:
|
||||||
|
return filepath.Join(ps.Namespace, ps.Path)
|
||||||
|
default:
|
||||||
|
return ps.DisplayPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps PackageManifestSource) GetNamespace() string {
|
||||||
|
return ps.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ps PackageManifestSource) GetPath() string {
|
||||||
|
return ps.Path
|
||||||
|
}
|
||||||
|
|
||||||
// Represents a package manifest that contains a list
|
// Represents a package manifest that contains a list
|
||||||
// of packages. Example: pom.xml, requirements.txt
|
// of packages. Example: pom.xml, requirements.txt
|
||||||
type PackageManifest struct {
|
type PackageManifest struct {
|
||||||
|
// The source of the package manifest
|
||||||
|
Source PackageManifestSource `json:"source"`
|
||||||
|
|
||||||
// Filesystem path of this manifest
|
// Filesystem path of this manifest
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
|
|
||||||
// When we scan non-path entities like Github org / repo
|
|
||||||
// then only path doesn't make sense, which is more local
|
|
||||||
// temporary file path
|
|
||||||
DisplayPath string `json:"display_path"`
|
|
||||||
|
|
||||||
// Ecosystem to interpret this manifest
|
// Ecosystem to interpret this manifest
|
||||||
Ecosystem string `json:"ecosystem"`
|
Ecosystem string `json:"ecosystem"`
|
||||||
|
|
||||||
@ -53,8 +96,30 @@ type PackageManifest struct {
|
|||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use NewPackageManifest* initializers
|
||||||
func NewPackageManifest(path, ecosystem string) *PackageManifest {
|
func NewPackageManifest(path, ecosystem string) *PackageManifest {
|
||||||
|
return NewPackageManifestFromLocal(path, ecosystem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPackageManifestFromLocal(path, ecosystem string) *PackageManifest {
|
||||||
|
return newPackageManifest(PackageManifestSource{
|
||||||
|
Type: ManifestSourceLocal,
|
||||||
|
Namespace: filepath.Dir(path),
|
||||||
|
Path: filepath.Base(path),
|
||||||
|
}, path, ecosystem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPackageManifestFromGitHub(repo, repoRelativePath, realPath, ecosystem string) *PackageManifest {
|
||||||
|
return newPackageManifest(PackageManifestSource{
|
||||||
|
Type: ManifestSourceGitRepository,
|
||||||
|
Namespace: repo,
|
||||||
|
Path: repoRelativePath,
|
||||||
|
}, realPath, ecosystem)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPackageManifest(source PackageManifestSource, path, ecosystem string) *PackageManifest {
|
||||||
return &PackageManifest{
|
return &PackageManifest{
|
||||||
|
Source: source,
|
||||||
Path: path,
|
Path: path,
|
||||||
Ecosystem: ecosystem,
|
Ecosystem: ecosystem,
|
||||||
Packages: make([]*Package, 0),
|
Packages: make([]*Package, 0),
|
||||||
@ -62,6 +127,16 @@ func NewPackageManifest(path, ecosystem string) *PackageManifest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parsers usually create a package manifest from file, readers
|
||||||
|
// have the context to set the source correct. Example: GitHub reader
|
||||||
|
func (p *PackageManifest) UpdateSourceAsGitRepository(repo, repoRelativePath string) {
|
||||||
|
p.Source = PackageManifestSource{
|
||||||
|
Type: ManifestSourceGitRepository,
|
||||||
|
Namespace: repo,
|
||||||
|
Path: repoRelativePath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (pm *PackageManifest) AddPackage(pkg *Package) {
|
func (pm *PackageManifest) AddPackage(pkg *Package) {
|
||||||
pm.m.Lock()
|
pm.m.Lock()
|
||||||
defer pm.m.Unlock()
|
defer pm.m.Unlock()
|
||||||
@ -74,22 +149,22 @@ func (pm *PackageManifest) AddPackage(pkg *Package) {
|
|||||||
pm.DependencyGraph.AddNode(pkg)
|
pm.DependencyGraph.AddNode(pkg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pm *PackageManifest) GetSource() PackageManifestSource {
|
||||||
|
return pm.Source
|
||||||
|
}
|
||||||
|
|
||||||
func (pm *PackageManifest) GetPath() string {
|
func (pm *PackageManifest) GetPath() string {
|
||||||
return pm.Path
|
return pm.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pm *PackageManifest) SetDisplayPath(path string) {
|
func (pm *PackageManifest) SetDisplayPath(path string) {
|
||||||
pm.DisplayPath = path
|
pm.Source.DisplayPath = path
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDisplayPath returns the [DisplayPath] if available or fallsback
|
// GetDisplayPath returns the [DisplayPath] if available or fallsback
|
||||||
// to [Path]
|
// to [Path]
|
||||||
func (pm *PackageManifest) GetDisplayPath() string {
|
func (pm *PackageManifest) GetDisplayPath() string {
|
||||||
if len(pm.DisplayPath) > 0 {
|
return pm.Source.GetDisplayPath()
|
||||||
return pm.DisplayPath
|
|
||||||
}
|
|
||||||
|
|
||||||
return pm.GetPath()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPackages returns the list of packages in this manifest
|
// GetPackages returns the list of packages in this manifest
|
||||||
|
|||||||
@ -129,7 +129,9 @@ func (p *githubReader) processTopLevelLockfiles(ctx context.Context, client *git
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pm.SetDisplayPath(gitUrl.GetHttpCloneURL())
|
pm.UpdateSourceAsGitRepository(gitUrl.GetHttpCloneURL(), entry.GetPath())
|
||||||
|
pm.SetDisplayPath(entry.GetURL())
|
||||||
|
|
||||||
err = handler(pm, NewManifestModelReader(pm))
|
err = handler(pm, NewManifestModelReader(pm))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -179,6 +181,7 @@ func (p *githubReader) processRemoteDependencyGraph(ctx context.Context, client
|
|||||||
|
|
||||||
// Override the display path because local path of the downloaded
|
// Override the display path because local path of the downloaded
|
||||||
// SBOM does not actually have a meaning
|
// SBOM does not actually have a meaning
|
||||||
|
manifest.UpdateSourceAsGitRepository(gitUrl.GetHttpCloneURL(), "<github-dependency-graph>")
|
||||||
manifest.SetDisplayPath(gitUrl.GetHttpCloneURL())
|
manifest.SetDisplayPath(gitUrl.GetHttpCloneURL())
|
||||||
|
|
||||||
return handler(manifest, NewManifestModelReader(manifest))
|
return handler(manifest, NewManifestModelReader(manifest))
|
||||||
|
|||||||
1
pkg/reporter/ci/git.go
Normal file
1
pkg/reporter/ci/git.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package ci
|
||||||
@ -151,6 +151,8 @@ func NewSyncReporter(config SyncReporterConfig) (Reporter, error) {
|
|||||||
trigger := controltowerv1.ToolTrigger_TOOL_TRIGGER_MANUAL
|
trigger := controltowerv1.ToolTrigger_TOOL_TRIGGER_MANUAL
|
||||||
source := packagev1.ProjectSourceType_PROJECT_SOURCE_TYPE_UNSPECIFIED
|
source := packagev1.ProjectSourceType_PROJECT_SOURCE_TYPE_UNSPECIFIED
|
||||||
|
|
||||||
|
// A multi-project sync is required for cases like GitHub org where
|
||||||
|
// we are scanning multiple repositories
|
||||||
if !config.EnableMultiProjectSync {
|
if !config.EnableMultiProjectSync {
|
||||||
logger.Debugf("Report Sync: Creating tool session for project: %s, version: %s",
|
logger.Debugf("Report Sync: Creating tool session for project: %s, version: %s",
|
||||||
config.ProjectName, config.ProjectVersion)
|
config.ProjectName, config.ProjectVersion)
|
||||||
@ -197,7 +199,7 @@ func (s *syncReporter) Name() string {
|
|||||||
func (s *syncReporter) AddManifest(manifest *models.PackageManifest) {
|
func (s *syncReporter) AddManifest(manifest *models.PackageManifest) {
|
||||||
manifestSessionKey := manifest.Path
|
manifestSessionKey := manifest.Path
|
||||||
if s.config.EnableMultiProjectSync && !s.sessions.hasKeyedSession(manifestSessionKey) {
|
if s.config.EnableMultiProjectSync && !s.sessions.hasKeyedSession(manifestSessionKey) {
|
||||||
projectName := manifest.GetDisplayPath()
|
projectName := manifest.GetSource().GetNamespace()
|
||||||
projectVersion := "main"
|
projectVersion := "main"
|
||||||
|
|
||||||
source := packagev1.ProjectSourceType_PROJECT_SOURCE_TYPE_UNSPECIFIED
|
source := packagev1.ProjectSourceType_PROJECT_SOURCE_TYPE_UNSPECIFIED
|
||||||
@ -341,6 +343,7 @@ func (s *syncReporter) syncEvent(event *analyzer.AnalyzerEvent) error {
|
|||||||
logger.Warnf("unsupported check type: %s", filter.GetCheckType())
|
logger.Warnf("unsupported check type: %s", filter.GetCheckType())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace := pkg.Manifest.GetSource().GetNamespace()
|
||||||
req := controltowerv1.PublishPolicyViolationRequest{
|
req := controltowerv1.PublishPolicyViolationRequest{
|
||||||
ToolSession: &controltowerv1.ToolSession{
|
ToolSession: &controltowerv1.ToolSession{
|
||||||
ToolSessionId: session.sessionId,
|
ToolSessionId: session.sessionId,
|
||||||
@ -348,8 +351,8 @@ func (s *syncReporter) syncEvent(event *analyzer.AnalyzerEvent) error {
|
|||||||
|
|
||||||
Manifest: &packagev1.PackageManifest{
|
Manifest: &packagev1.PackageManifest{
|
||||||
Ecosystem: pkg.Manifest.GetControlTowerSpecEcosystem(),
|
Ecosystem: pkg.Manifest.GetControlTowerSpecEcosystem(),
|
||||||
Namespace: &pkg.Manifest.Path,
|
Namespace: &namespace,
|
||||||
Name: pkg.Manifest.GetDisplayPath(),
|
Name: pkg.Manifest.GetSource().GetPath(),
|
||||||
},
|
},
|
||||||
|
|
||||||
PackageVersion: &packagev1.PackageVersion{
|
PackageVersion: &packagev1.PackageVersion{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user