quorate/services/mirrored-image/controller/inventory.go

96 lines
3.1 KiB
Go
Raw Normal View History

package main
import (
"fmt"
apk "github.com/knqyf263/go-apk-version"
)
type scanInventory struct {
Hash string `json:"manifest_hash"`
Packages map[string]*scanPackage `json:"packages"`
Distributions map[string]*scanDistribution `json:"distributions"`
Environments map[string][]*scanEnvironment `json:"environments"`
}
type scanPackage struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Kind string `json:"kind"`
Source *scanPackage `json:"source"`
}
type scanDistribution struct {
ID string `json:"id"`
DID string `json:"did"`
Name string `json:"name"`
Version string `json:"version"`
PrettyName string `json:"pretty_name"`
}
type scanEnvironment struct {
PackageDB string `json:"package_db"`
IntroducedIn string `json:"introduced_in"`
DistributionID string `json:"distribution_id"`
RepositoryIDs []string `json:"repository_ids"`
}
type featureKey struct {
Name string
Version string
Layer string
}
func checkInventory(data *securityData, digest string, layers map[string]bool) error {
if data == nil || data.Inventory == nil || data.Layer == nil || data.Layer.Features == nil {
return fmt.Errorf("scan inventory is unavailable")
}
inv := data.Inventory
if inv.Hash != digest || data.Layer.Name != digest {
return fmt.Errorf("scan identity does not match candidate")
}
if len(inv.Packages) == 0 || len(inv.Distributions) == 0 || len(inv.Environments) != len(inv.Packages) {
return fmt.Errorf("scan inventory is incomplete")
}
for id, distro := range inv.Distributions {
if distro == nil || distro.ID != id || distro.DID != "alpine" || distro.Version != "3.23" || distro.Name != "Alpine Linux" || distro.PrettyName != "Alpine Linux v3.23" {
return fmt.Errorf("distribution coverage is not qualified")
}
}
expected := map[featureKey]int{}
for id, pkg := range inv.Packages {
if pkg == nil || pkg.ID != id || pkg.Name == "" || pkg.Version == "" || pkg.Kind != "binary" {
return fmt.Errorf("package identity is incomplete")
}
if _, err := apk.NewVersion(pkg.Version); err != nil {
return fmt.Errorf("package version is not matchable")
}
if pkg.Source == nil || pkg.Source.Name == "" || pkg.Source.Kind != "source" {
return fmt.Errorf("source package identity is missing")
}
envs := inv.Environments[id]
if len(envs) == 0 {
return fmt.Errorf("package environment is missing")
}
for _, env := range envs {
if env == nil || env.PackageDB != "lib/apk/db/installed" || !layers[env.IntroducedIn] || inv.Distributions[env.DistributionID] == nil || len(env.RepositoryIDs) != 0 {
return fmt.Errorf("package environment is not qualified")
}
}
expected[featureKey{pkg.Name, pkg.Version, envs[0].IntroducedIn}]++
}
for _, feature := range *data.Layer.Features {
key := featureKey{feature.Name, feature.Version, feature.AddedBy}
if expected[key] == 0 {
return fmt.Errorf("scan feature does not match inventory")
}
expected[key]--
}
for _, count := range expected {
if count != 0 {
return fmt.Errorf("scan features omit indexed packages")
}
}
return nil
}