Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ INSTANCE_DOMAIN=https://api.main.devguard.org #Choose which version of devguar

FRONTEND_URL=http://localhost:3000

OSI_LICENSES_API=https://opensource.org/api/license/

PDF_GENERATION_API=https://dwt-api.dev-l3montree.cloud/pdf
# comment to disable error tracking
ERROR_TRACKING_DSN="https://<your-error-tracking-dsn>"
Expand Down
3 changes: 3 additions & 0 deletions cmd/devguard-cli/commands/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/l3montree-dev/devguard/internal/core"
"github.com/l3montree-dev/devguard/internal/core/component"
"github.com/l3montree-dev/devguard/internal/core/vuln"
"github.com/l3montree-dev/devguard/internal/core/vulndb"
"github.com/l3montree-dev/devguard/internal/database/models"
"github.com/l3montree-dev/devguard/internal/database/repositories"
Expand Down Expand Up @@ -37,6 +38,7 @@ func newUpdateDepsDevInformation() *cobra.Command {
depsDevService := vulndb.NewDepsDevService()
componentProjectRepository := repositories.NewComponentProjectRepository(database)
componentRepository := repositories.NewComponentRepository(database)
licenseRiskService := vuln.NewLicenseRiskService(repositories.NewLicenseRiskRepository(database), repositories.NewVulnEventRepository(database))

components, err := componentRepository.All()
if err != nil {
Expand All @@ -48,6 +50,7 @@ func newUpdateDepsDevInformation() *cobra.Command {
&depsDevService,
componentProjectRepository,
componentRepository,
licenseRiskService,
)

bar := progressbar.Default(int64(len(components)))
Expand Down
24 changes: 15 additions & 9 deletions cmd/devguard/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ func BuildRouter(db core.DB) *echo.Echo {
supplyChainRepository := repositories.NewSupplyChainRepository(db)
attestationRepository := repositories.NewAttestationRepository(db)
policyRepository := repositories.NewPolicyRepository(db)
licenseOverwriteRepository := repositories.NewLicenseOverwriteRepository(db)
licenseRiskRepository := repositories.NewLicenseRiskRepository(db)

dependencyVulnService := vuln.NewService(dependencyVulnRepository, vulnEventRepository, assetRepository, cveRepository, orgRepository, projectRepository, thirdPartyIntegration, assetVersionRepository)
firstPartyVulnService := vuln.NewFirstPartyVulnService(firstPartyVulnRepository, vulnEventRepository, assetRepository)
Expand All @@ -410,7 +410,8 @@ func BuildRouter(db core.DB) *echo.Echo {
assetService := asset.NewService(assetRepository, dependencyVulnRepository, dependencyVulnService)
depsDevService := vulndb.NewDepsDevService()
componentProjectRepository := repositories.NewComponentProjectRepository(db)
componentService := component.NewComponentService(&depsDevService, componentProjectRepository, componentRepository)
licenseRiskService := vuln.NewLicenseRiskService(licenseRiskRepository, vulnEventRepository)
componentService := component.NewComponentService(&depsDevService, componentProjectRepository, componentRepository, licenseRiskService)

assetVersionService := assetversion.NewService(assetVersionRepository, componentRepository, dependencyVulnRepository, firstPartyVulnRepository, dependencyVulnService, firstPartyVulnService, assetRepository, vulnEventRepository, &componentService)
statisticsService := statistics.NewService(statisticsRepository, componentRepository, assetRiskAggregationRepository, dependencyVulnRepository, assetVersionRepository, projectRepository, repositories.NewProjectRiskHistoryRepository(db))
Expand All @@ -429,15 +430,16 @@ func BuildRouter(db core.DB) *echo.Echo {

scanController := scan.NewHTTPController(db, cveRepository, componentRepository, assetRepository, assetVersionRepository, assetVersionService, statisticsService, dependencyVulnService)

assetVersionController := assetversion.NewAssetVersionController(assetVersionRepository, assetVersionService, dependencyVulnRepository, componentRepository, dependencyVulnService, supplyChainRepository, licenseOverwriteRepository)
assetVersionController := assetversion.NewAssetVersionController(assetVersionRepository, assetVersionService, dependencyVulnRepository, componentRepository, dependencyVulnService, supplyChainRepository, licenseRiskRepository)
attestationController := attestation.NewAttestationController(attestationRepository, assetVersionRepository)
intotoController := intoto.NewHTTPController(intotoLinkRepository, supplyChainRepository, assetVersionRepository, patRepository, intotoService)
componentController := component.NewHTTPController(componentRepository, assetVersionRepository, licenseOverwriteRepository)
componentController := component.NewHTTPController(componentRepository, assetVersionRepository, licenseRiskRepository)

complianceController := compliance.NewHTTPController(assetVersionRepository, attestationRepository, policyRepository)

statisticsController := statistics.NewHTTPController(statisticsService, statisticsRepository, assetRepository, assetVersionRepository, projectService)
firstPartyVulnController := vuln.NewFirstPartyVulnController(firstPartyVulnRepository, firstPartyVulnService, projectService)
licenseOverwriteController := component.NewLicenseOverwriteController(licenseOverwriteRepository)
licenseRiskController := vuln.NewLicenseRiskController(licenseRiskRepository, licenseRiskService)

patService := pat.NewPatService(patRepository)

Expand Down Expand Up @@ -555,8 +557,6 @@ func BuildRouter(db core.DB) *echo.Echo {
organizationRouter.POST("/projects/", projectController.Create, neededScope([]string{"manage"}), accessControlMiddleware(core.ObjectOrganization, core.ActionUpdate))

organizationRouter.GET("/config-files/:config-file/", orgController.GetConfigFile)
organizationRouter.PUT("/license-overwrite/", licenseOverwriteController.Create, neededScope([]string{"manage"}))
organizationRouter.DELETE("/license-overwrite/:componentPurl", licenseOverwriteController.Delete, neededScope([]string{"manage"}))
//Api functions for interacting with a project inside an organization -> .../organizations/<organization-name>/projects/<project-name>/...
projectRouter := organizationRouter.Group("/projects/:projectSlug", projectAccessControl(projectService, "project", core.ActionRead))
projectRouter.GET("/", projectController.Read)
Expand Down Expand Up @@ -673,10 +673,8 @@ func BuildRouter(db core.DB) *echo.Echo {
dependencyVulnRouter := assetVersionRouter.Group("/dependency-vulns")
dependencyVulnRouter.GET("/", dependencyVulnController.ListPaged)
dependencyVulnRouter.GET("/:dependencyVulnID/", dependencyVulnController.Read)

dependencyVulnRouter.POST("/:dependencyVulnID/", dependencyVulnController.CreateEvent, neededScope([]string{"manage"}), projectScopedRBAC(core.ObjectAsset, core.ActionUpdate))
dependencyVulnRouter.POST("/:dependencyVulnID/mitigate/", dependencyVulnController.Mitigate, neededScope([]string{"manage"}), projectScopedRBAC(core.ObjectAsset, core.ActionUpdate))

dependencyVulnRouter.GET("/:dependencyVulnID/events/", vulnEventController.ReadAssetEventsByVulnID)

firstPartyVulnRouter := assetVersionRouter.Group("/first-party-vulns")
Expand All @@ -686,6 +684,14 @@ func BuildRouter(db core.DB) *echo.Echo {
firstPartyVulnRouter.POST("/:firstPartyVulnID/mitigate/", firstPartyVulnController.Mitigate, neededScope([]string{"manage"}), projectScopedRBAC(core.ObjectAsset, core.ActionUpdate))
firstPartyVulnRouter.GET("/:firstPartyVulnID/events/", vulnEventController.ReadAssetEventsByVulnID)

assetVersionRouter.POST("/license-risks/", licenseRiskController.Create)
licenseRiskRouter := assetVersionRouter.Group("/license-risks")
licenseRiskRouter.GET("/", licenseRiskController.ListPaged)
licenseRiskRouter.GET("/:licenseRiskID/", licenseRiskController.Read)
licenseRiskRouter.POST("/:licenseRiskID/", licenseRiskController.CreateEvent, neededScope([]string{"manage"}), projectScopedRBAC(core.ObjectAsset, core.ActionUpdate))
licenseRiskRouter.POST("/:licenseRiskID/mitigate", licenseRiskController.Mitigate, neededScope([]string{"manage"}), projectScopedRBAC(core.ObjectAsset, core.ActionUpdate))
licenseRiskRouter.POST("/:licenseRiskID/final-license-decision", licenseRiskController.MakeFinalLicenseDecision, neededScope([]string{"manage"}), projectScopedRBAC(core.ObjectAsset, core.ActionUpdate))

routes := server.Routes()
sort.Slice(routes, func(i, j int) bool {
return routes[i].Path < routes[j].Path
Expand Down
32 changes: 16 additions & 16 deletions internal/core/assetversion/asset_version_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ import (
)

type AssetVersionController struct {
assetVersionRepository core.AssetVersionRepository
assetVersionService core.AssetVersionService
dependencyVulnRepository core.DependencyVulnRepository
componentRepository core.ComponentRepository
dependencyVulnService core.DependencyVulnService
supplyChainRepository core.SupplyChainRepository
licenseOverwriteRepository core.LicenseOverwriteRepository
assetVersionRepository core.AssetVersionRepository
assetVersionService core.AssetVersionService
dependencyVulnRepository core.DependencyVulnRepository
componentRepository core.ComponentRepository
dependencyVulnService core.DependencyVulnService
supplyChainRepository core.SupplyChainRepository
licenseRiskRepository core.LicenseRiskRepository
}

func NewAssetVersionController(
Expand All @@ -42,16 +42,16 @@ func NewAssetVersionController(
componentRepository core.ComponentRepository,
dependencyVulnService core.DependencyVulnService,
supplyChainRepository core.SupplyChainRepository,
licenseOverwriteRepository core.LicenseOverwriteRepository,
licenseRiskRepository core.LicenseRiskRepository,
) *AssetVersionController {
return &AssetVersionController{
assetVersionRepository: assetVersionRepository,
assetVersionService: assetVersionService,
dependencyVulnRepository: dependencyVulnRepository,
componentRepository: componentRepository,
dependencyVulnService: dependencyVulnService,
supplyChainRepository: supplyChainRepository,
licenseOverwriteRepository: licenseOverwriteRepository,
assetVersionRepository: assetVersionRepository,
assetVersionService: assetVersionService,
dependencyVulnRepository: dependencyVulnRepository,
componentRepository: componentRepository,
dependencyVulnService: dependencyVulnService,
supplyChainRepository: supplyChainRepository,
licenseRiskRepository: licenseRiskRepository,
}
}

Expand Down Expand Up @@ -218,7 +218,7 @@ func (a *AssetVersionController) buildSBOM(ctx core.Context) (*cdx.BOM, error) {

scannerID := ctx.QueryParam("scanner")

overwrittenLicenses, err := a.licenseOverwriteRepository.GetAllOverwritesForOrganization(org.ID)
overwrittenLicenses, err := a.licenseRiskRepository.GetAllOverwrittenLicensesForAssetVersion(assetVersion.AssetID, assetVersion.Name)
if err != nil {
return nil, err
}
Expand Down
7 changes: 4 additions & 3 deletions internal/core/assetversion/asset_version_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,8 @@ func (s *service) UpdateSBOM(assetVersion models.AssetVersion, scannerID string,
}

existingComponentPurls := make(map[string]bool)
for _, c := range assetComponents {
existingComponentPurls[c.Component.Purl] = true
for _, currentComponent := range assetComponents {
existingComponentPurls[currentComponent.Component.Purl] = true
}

// we need to check if the SBOM is new or if it already exists.
Expand Down Expand Up @@ -524,7 +524,7 @@ func (s *service) UpdateSBOM(assetVersion models.AssetVersion, scannerID string,
go func() {
slog.Info("updating license information in background", "asset", assetVersion.Name, "assetID", assetVersion.AssetID)

_, err := s.componentService.GetAndSaveLicenseInformation(assetVersion.Name, assetVersion.AssetID, scannerID)
_, err := s.componentService.GetAndSaveLicenseInformation(assetVersion, scannerID)
if err != nil {
slog.Error("could not update license information", "asset", assetVersion.Name, "assetID", assetVersion.AssetID, "err", err)
} else {
Expand Down Expand Up @@ -576,6 +576,7 @@ func (s *service) BuildSBOM(assetVersion models.AssetVersion, version string, or
licenses := cdx.Licenses{}
//technically redundant call to c.Dependency.ComponentProject.License
if c.Dependency.ComponentProject != nil && c.Dependency.ComponentProject.License != "" {
// if the license is not a valid osi license we need to assign that to the name attribute in the license choice struct, because ID can only contain valid IDs
if c.Dependency.ComponentProject.License != "non-standard" {
licenses = append(licenses, cdx.LicenseChoice{
License: &cdx.License{
Expand Down
28 changes: 19 additions & 9 deletions internal/core/common_interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ type ComponentRepository interface {
common.Repository[string, models.Component, DB]

LoadComponents(tx DB, assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.ComponentDependency, error)
LoadComponentsWithProject(tx DB, overwrittenLicenses []models.LicenseOverwrite, assetVersionName string, assetID uuid.UUID, scannerID string, pageInfo PageInfo, search string, filter []FilterQuery, sort []SortQuery) (Paged[models.ComponentDependency], error)
LoadComponentsWithProject(tx DB, overwrittenLicenses []models.LicenseRisk, assetVersionName string, assetID uuid.UUID, scannerID string, pageInfo PageInfo, search string, filter []FilterQuery, sort []SortQuery) (Paged[models.ComponentDependency], error)
LoadPathToComponent(tx DB, assetVersionName string, assetID uuid.UUID, pURL string, scannerID string) ([]models.ComponentDependency, error)
SaveBatch(tx DB, components []models.Component) error
FindByPurl(tx DB, purl string) (models.Component, error)
Expand Down Expand Up @@ -164,6 +164,17 @@ type FirstPartyVulnRepository interface {
GetByAssetVersion(tx DB, assetVersionName string, assetID uuid.UUID) ([]models.FirstPartyVuln, error)
}

type LicenseRiskRepository interface {
common.Repository[string, models.LicenseRisk, DB]
GetAllLicenseRisksForAssetVersionPaged(tx DB, assetID uuid.UUID, assetVersionName string, pageInfo PageInfo, search string, filter []FilterQuery, sort []SortQuery) (Paged[models.LicenseRisk], error)
GetAllLicenseRisksForAssetVersion(assetID uuid.UUID, assetVersionName string) ([]models.LicenseRisk, error)
GetAllOverwrittenLicensesForAssetVersion(assetID uuid.UUID, assetVersionName string) ([]models.LicenseRisk, error)
MaybeGetLicenseOverwriteForComponent(assetID uuid.UUID, assetVersionName string, pURL packageurl.PackageURL) (models.LicenseRisk, error)
DeleteByComponentPurl(assetID uuid.UUID, assetVersionName string, purl packageurl.PackageURL) error
ListByScanner(assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.LicenseRisk, error)
ApplyAndSave(tx DB, licenseRisk *models.LicenseRisk, vulnEvent *models.VulnEvent) error
}

type InTotoLinkRepository interface {
common.Repository[uuid.UUID, models.InTotoLink, DB]
FindByAssetAndSupplyChainID(assetID uuid.UUID, supplyChainID string) ([]models.InTotoLink, error)
Expand Down Expand Up @@ -304,13 +315,6 @@ type VulnRepository interface {
ApplyAndSave(tx DB, dependencyVuln models.Vuln, vulnEvent *models.VulnEvent) error
}

type LicenseOverwriteRepository interface {
common.Repository[string, models.LicenseOverwrite, DB]
GetAllOverwritesForOrganization(orgID uuid.UUID) ([]models.LicenseOverwrite, error)
MaybeGetOverwriteForComponent(orgID uuid.UUID, pURL packageurl.PackageURL) (models.LicenseOverwrite, error)
DeleteByComponentPurlAndOrgID(orgID uuid.UUID, purl string) error
}

type ExternalUserRepository interface {
Save(db DB, user *models.ExternalUser) error
GetDB(tx DB) DB
Expand Down Expand Up @@ -381,11 +385,17 @@ type ComponentProjectRepository interface {
}

type ComponentService interface {
GetAndSaveLicenseInformation(assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.Component, error)
GetAndSaveLicenseInformation(assetVersion models.AssetVersion, scannerID string) ([]models.Component, error)
RefreshComponentProjectInformation(project models.ComponentProject)
GetLicense(component models.Component) (models.Component, error)
}

type LicenseRiskService interface {
FindLicenseRisksInComponents(assetVersion models.AssetVersion, components []models.Component, scannerID string) error
UpdateLicenseRiskState(tx DB, userID string, licenseRisk *models.LicenseRisk, statusType string, justification string, mechanicalJustification models.MechanicalJustificationType) (models.VulnEvent, error)
MakeFinalLicenseDecision(vulnID string, finalLicense string, userID string) error
}

type AccessControl interface {
HasAccess(subject string) (bool, error) // return error if couldnt be checked due to unauthorized access or other issues

Expand Down
18 changes: 8 additions & 10 deletions internal/core/component/component_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import (
)

type httpController struct {
componentRepository core.ComponentRepository
assetVersionRepository core.AssetVersionRepository
licenseOverwriteRepository core.LicenseOverwriteRepository
componentRepository core.ComponentRepository
assetVersionRepository core.AssetVersionRepository
licenseRiskRepository core.LicenseRiskRepository
}

func NewHTTPController(componentRepository core.ComponentRepository, assetVersionRepository core.AssetVersionRepository, licenseOverwriteRepository core.LicenseOverwriteRepository) *httpController {
func NewHTTPController(componentRepository core.ComponentRepository, assetVersionRepository core.AssetVersionRepository, licenseOverwriteRepository core.LicenseRiskRepository) *httpController {
return &httpController{
componentRepository: componentRepository,
assetVersionRepository: assetVersionRepository,
licenseOverwriteRepository: licenseOverwriteRepository,
componentRepository: componentRepository,
assetVersionRepository: assetVersionRepository,
licenseRiskRepository: licenseOverwriteRepository,
}
}

Expand Down Expand Up @@ -74,9 +74,7 @@ func (httpController httpController) ListPaged(ctx core.Context) error {
search := ctx.QueryParam("search")
sort := core.GetSortQuery(ctx)

orgID := core.GetOrg(ctx).ID

overwrittenLicense, err := httpController.licenseOverwriteRepository.GetAllOverwritesForOrganization(orgID)
overwrittenLicense, err := httpController.licenseRiskRepository.GetAllOverwrittenLicensesForAssetVersion(assetVersion.AssetID, assetVersion.Name)
if err != nil {
return err
}
Expand Down
Loading
Loading