diff --git a/.github/workflows/semantic-pr.yaml b/.github/workflows/semantic-pr.yaml index 6afd5f995b..ba66d38b03 100644 --- a/.github/workflows/semantic-pr.yaml +++ b/.github/workflows/semantic-pr.yaml @@ -50,6 +50,7 @@ jobs: plugin # OS + activestate alpine wolfi chainguard diff --git a/docs/guide/coverage/others/activestate.md b/docs/guide/coverage/others/activestate.md new file mode 100644 index 0000000000..a887a85d28 --- /dev/null +++ b/docs/guide/coverage/others/activestate.md @@ -0,0 +1,41 @@ +# ActiveState Images + +While it is not an OS with a package manager, this page describes the details of ActiveState container images. +ActiveState images don't contain OS packages. + +Trivy supports the following scanners for ActiveState images. + +| Scanner | Supported | +|:-------------:|:---------:| +| SBOM | ✓ | +| Vulnerability | ✓ | +| License | ✓ | + +## SBOM +Trivy collects packages from two sources: + +- Pre-built SBOM file at `/opt/activestate/.spdx.json` (if present) +- Language-specific packages (e.g., npm, pip, go.mod) + +!!! note + This may result in [duplicates](#duplicates) if both sources contain the same packages. + +## Vulnerability +Trivy detects vulnerabilities in language-specific packages found in the image. + +ActiveState images don't contain OS packages, so vulnerability detection for OS packages is not performed. + +## License +Trivy detects licenses from language-specific packages found in the image. + +## Duplicates +Scan results may contain duplicates when the same packages are detected both from the SBOM file +and by Trivy's analyzers. This is expected behavior. + +To avoid duplicates, you can either: + +- [Skip the SBOM file][skipping] from scanning +- [Filter the results][filtering] to remove duplicates + +[skipping]: ../../configuration/skipping.md +[filtering]: ../../configuration/filtering.md diff --git a/docs/guide/coverage/others/index.md b/docs/guide/coverage/others/index.md index e5eee65bbe..99a295f056 100644 --- a/docs/guide/coverage/others/index.md +++ b/docs/guide/coverage/others/index.md @@ -12,6 +12,7 @@ Trivy supports them for | Element | File | Image[^1] | Rootfs[^2] | Filesystem[^3] | Repository[^4] | |--------------------------------|-----------------------------------------------------|:---------:|:----------:|:--------------:|:--------------:| +| [ActiveState images](activestate.md) | `/opt/activestate/.spdx.json` | ✅ | ✅ | - | - | | [Bitnami packages](bitnami.md) | `/opt/bitnami//.spdx-.spdx` | ✅ | ✅ | - | - | | [Conda](conda.md) | `/envs//conda-meta/.json` | ✅ | ✅ | - | - | | | `environment.yml` | - | - | ✅ | ✅ | diff --git a/mkdocs.yml b/mkdocs.yml index 328fd2c45b..608e94d97c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -117,6 +117,7 @@ nav: - Terraform: guide/coverage/iac/terraform.md - Others: - Overview: guide/coverage/others/index.md + - ActiveState Images: guide/coverage/others/activestate.md - Bitnami Images: guide/coverage/others/bitnami.md - Conda: guide/coverage/others/conda.md - Root.io Images: guide/coverage/others/rootio.md diff --git a/pkg/fanal/analyzer/os/release/release.go b/pkg/fanal/analyzer/os/release/release.go index 2f237f3303..30c572c88f 100644 --- a/pkg/fanal/analyzer/os/release/release.go +++ b/pkg/fanal/analyzer/os/release/release.go @@ -69,6 +69,8 @@ func (a osReleaseAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInp //nolint:gocyclo func idToOSFamily(id string) types.OSType { switch id { + case "activestate": + return types.ActiveState case "rhel": return types.RedHat case "centos": diff --git a/pkg/fanal/analyzer/os/release/release_test.go b/pkg/fanal/analyzer/os/release/release_test.go index c893d07e0f..9b31cb91b3 100644 --- a/pkg/fanal/analyzer/os/release/release_test.go +++ b/pkg/fanal/analyzer/os/release/release_test.go @@ -19,6 +19,16 @@ func Test_osReleaseAnalyzer_Analyze(t *testing.T) { want *analyzer.AnalysisResult wantErr string }{ + { + name: "ActiveState", + inputFile: "testdata/activestate", + want: &analyzer.AnalysisResult{ + OS: types.OS{ + Family: types.ActiveState, + Name: "1.0", + }, + }, + }, { name: "Fedora", inputFile: "testdata/fedora", diff --git a/pkg/fanal/analyzer/os/release/testdata/activestate b/pkg/fanal/analyzer/os/release/testdata/activestate new file mode 100644 index 0000000000..7921b4aaa8 --- /dev/null +++ b/pkg/fanal/analyzer/os/release/testdata/activestate @@ -0,0 +1,8 @@ +ID=activestate +ID_LIKE="buildroot busybox" +VERSION_ID="1.0" +IMAGE_ID="activestate-k3s" +IMAGE_VERSION="1.34.1" +RELEASE_TYPE=experiment +EXPERIMENT="Trivy integration" +ACTIVESTATE_SBOM_PATH=/opt/activestate/k3s.spdx.json diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index 8fa3b720d2..ac7df78dec 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -21,6 +21,7 @@ const ( // Operating systems const ( + ActiveState OSType = "activestate" Alma OSType = "alma" Alpine OSType = "alpine" Amazon OSType = "amazon" @@ -48,6 +49,17 @@ const ( Wolfi OSType = "wolfi" ) +// HasOSPackages returns true if the OS type has OS-level packages managed by a package manager. +// Some OS types like ActiveState only contain language-specific packages. +func (o OSType) HasOSPackages() bool { + switch o { + case ActiveState: + return false + default: + return true + } +} + // PurlNamespace returns the normalized namespace for Package URL (PURL) representation. // For SUSE-based distributions (SLES, SLE Micro), it returns "suse". // For openSUSE variants (Tumbleweed, Leap), it returns "opensuse". @@ -125,6 +137,7 @@ const ( var ( OSTypes = []OSType{ + ActiveState, Alma, Alpine, Amazon, diff --git a/pkg/scan/local/service.go b/pkg/scan/local/service.go index 4042c75a01..ffe017f5eb 100644 --- a/pkg/scan/local/service.go +++ b/pkg/scan/local/service.go @@ -75,6 +75,9 @@ func (s Service) Scan(ctx context.Context, targetName, artifactKey string, blobK Name: detail.Repository.Release, } } + case !detail.OS.Family.HasOSPackages(): + // Some OS types like ActiveState don't have OS packages, only language-specific packages. + // No warning needed. case errors.Is(err, analyzer.ErrNoPkgsDetected): log.Warn("No OS package is detected. Make sure you haven't deleted any files that contain information about the installed packages.") log.Warn(`e.g. files under "/lib/apk/db/", "/var/lib/dpkg/" and "/var/lib/rpm"`) diff --git a/pkg/scan/ospkg/scan.go b/pkg/scan/ospkg/scan.go index d89c58b20e..dc87503ee9 100644 --- a/pkg/scan/ospkg/scan.go +++ b/pkg/scan/ospkg/scan.go @@ -30,6 +30,12 @@ func (s *scanner) Scan(ctx context.Context, target types.ScanTarget, opts types. log.Info("Detected OS", log.String("family", string(target.OS.Family)), log.String("version", target.OS.Name)) + // Skip OS package scanning if the target is expected not to have OS packages + if !target.OS.Family.HasOSPackages() { + log.Debug("Skipping OS package scanning", log.String("family", string(target.OS.Family))) + return types.Result{}, false, nil + } + if target.OS.Extended { // TODO: move the logic to each detector target.OS.Name += "-ESM"