feat(minimos): Add support for MinimOS (#8792)

Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io>
This commit is contained in:
Daniel Wachter
2025-05-29 14:21:22 +03:00
committed by GitHub
parent 104bbc18ea
commit c2dde33c3f
25 changed files with 420 additions and 4 deletions

View File

@@ -66,6 +66,7 @@ jobs:
echo
distroless
windows
minimos
# Languages
ruby

View File

@@ -14,6 +14,7 @@ Trivy supports operating systems for
| [Alpine Linux](alpine.md) | 2.2 - 2.7, 3.0 - 3.21, edge | apk |
| [Wolfi Linux](wolfi.md) | (n/a) | apk |
| [Chainguard](chainguard.md) | (n/a) | apk |
| [MinimOS](minimos.md) | (n/a) | apk |
| [Red Hat Enterprise Linux](rhel.md) | 6, 7, 8 | dnf/yum/rpm |
| [CentOS](centos.md)[^1] | 6, 7, 8 | dnf/yum/rpm |
| [AlmaLinux](alma.md) | 8, 9 | dnf/yum/rpm |

View File

@@ -0,0 +1,30 @@
# MinimOS
Trivy supports these scanners for OS packages.
| Scanner | Supported |
| :-----------: | :-------: |
| SBOM | ✓ |
| Vulnerability | ✓ |
| License | ✓ |
The table below outlines the features offered by Trivy.
| Feature | Supported |
|:------------------------------------:|:---------:|
| Detect unfixed vulnerabilities | - |
| [Dependency graph][dependency-graph] | ✓ |
## SBOM
Same as [Alpine Linux](alpine.md#sbom).
## Vulnerability
MinimOS offers its own security advisories, and these are utilized when scanning MinimOS for vulnerabilities.
Everything else is the same as [Alpine Linux](alpine.md#vulnerability).
### Data Source
See [here](../../scanner/vulnerability.md#data-sources).
## License
Same as [Alpine Linux](alpine.md#license).
[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies

View File

@@ -168,6 +168,7 @@ trivy filesystem [flags] PATH
- bitnami
- govulndb
- echo
- minimos
- auto
(default [auto])
```

View File

@@ -189,6 +189,7 @@ trivy image [flags] IMAGE_NAME
- bitnami
- govulndb
- echo
- minimos
- auto
(default [auto])
```

View File

@@ -177,6 +177,7 @@ trivy kubernetes [flags] [CONTEXT]
- bitnami
- govulndb
- echo
- minimos
- auto
(default [auto])
```

View File

@@ -167,6 +167,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL)
- bitnami
- govulndb
- echo
- minimos
- auto
(default [auto])
```

View File

@@ -169,6 +169,7 @@ trivy rootfs [flags] ROOTDIR
- bitnami
- govulndb
- echo
- minimos
- auto
(default [auto])
```

View File

@@ -138,6 +138,7 @@ trivy sbom [flags] SBOM_PATH
- bitnami
- govulndb
- echo
- minimos
- auto
(default [auto])
```

View File

@@ -154,6 +154,7 @@ trivy vm [flags] VM_IMAGE
- bitnami
- govulndb
- echo
- minimos
- auto
(default [auto])
```

View File

@@ -25,6 +25,7 @@ See [here](../coverage/os/index.md#supported-os) for the supported OSes.
| Alpine Linux | [secdb][alpine] |
| Wolfi Linux | [secdb][wolfi] |
| Chainguard | [secdb][chainguard] |
| MinimOS | [secdb][minimos] |
| Amazon Linux | [Amazon Linux Security Center][amazon] |
| Echo | [Echo][echo] |
| Debian | [Security Bug Tracker][debian-tracker] / [OVAL][debian-oval] |
@@ -379,6 +380,7 @@ Example logic for the following vendor severity levels when scanning an Alpine i
[alpine]: https://secdb.alpinelinux.org/
[wolfi]: https://packages.wolfi.dev/os/security.json
[chainguard]: https://packages.cgr.dev/chainguard/security.json
[minimos]: https://packages.mini.dev/advisories/secdb/security.json
[amazon]: https://alas.aws.amazon.com/
[echo]: https://advisory.echohq.com/data.json
[debian-tracker]: https://security-tracker.debian.org/tracker/

2
go.mod
View File

@@ -24,7 +24,7 @@ require (
github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8
github.com/aquasecurity/tml v0.6.1
github.com/aquasecurity/trivy-checks v1.10.0
github.com/aquasecurity/trivy-db v0.0.0-20250529090941-0ee57d439c7a
github.com/aquasecurity/trivy-db v0.0.0-20250529093513-a12dfc204b6e
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48
github.com/aquasecurity/trivy-kubernetes v0.9.0
github.com/aws/aws-sdk-go-v2 v1.36.3

4
go.sum
View File

@@ -802,8 +802,8 @@ github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gw
github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY=
github.com/aquasecurity/trivy-checks v1.10.0 h1:Q0FWsYy/uwvr/icRSOzNu55yDZ1ME8hZlpglNs62ZfE=
github.com/aquasecurity/trivy-checks v1.10.0/go.mod h1:/b633SOFNp8RjkxSq+FOg4SgxjklUp+BIQEyTWCnN1k=
github.com/aquasecurity/trivy-db v0.0.0-20250529090941-0ee57d439c7a h1:VGmQ5tx5vVo4zBk8F8b/rf9s57C9bOEfWmIzF2kLFE8=
github.com/aquasecurity/trivy-db v0.0.0-20250529090941-0ee57d439c7a/go.mod h1:4zd4qZcjhNAHASz5I0O7qapv5h5gSJzSEaZXv/IPOGc=
github.com/aquasecurity/trivy-db v0.0.0-20250529093513-a12dfc204b6e h1:+B/in1DQDGwQbKhW5pWL8XxBgnZKxXhUznylJ2NCyvs=
github.com/aquasecurity/trivy-db v0.0.0-20250529093513-a12dfc204b6e/go.mod h1:4zd4qZcjhNAHASz5I0O7qapv5h5gSJzSEaZXv/IPOGc=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
github.com/aquasecurity/trivy-kubernetes v0.9.0 h1:rp8RuXwKfFWUPR/ULksA2WpD0z6rslVkzLmPGQr61Wc=

View File

@@ -81,6 +81,7 @@ nav:
- Chainguard: docs/coverage/os/chainguard.md
- Debian: docs/coverage/os/debian.md
- Echo: docs/coverage/os/echo.md
- MinimOS: docs/coverage/os/minimos.md
- Oracle Linux: docs/coverage/os/oracle.md
- Photon OS: docs/coverage/os/photon.md
- Red Hat: docs/coverage/os/rhel.md

View File

@@ -15,6 +15,7 @@ import (
"github.com/aquasecurity/trivy/pkg/detector/ospkg/chainguard"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/echo"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/minimos"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/oracle"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/photon"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/redhat"
@@ -52,6 +53,7 @@ var (
ftypes.Wolfi: wolfi.NewScanner(),
ftypes.Chainguard: chainguard.NewScanner(),
ftypes.Echo: echo.NewScanner(),
ftypes.MinimOS: minimos.NewScanner(),
}
)

View File

@@ -0,0 +1,91 @@
package minimos
import (
"context"
version "github.com/knqyf263/go-apk-version"
"golang.org/x/xerrors"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/minimos"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/scan/utils"
"github.com/aquasecurity/trivy/pkg/types"
)
// Scanner implements the MinimOS scanner
type Scanner struct {
vs minimos.VulnSrc
}
// NewScanner is the factory method for Scanner
func NewScanner() *Scanner {
return &Scanner{
vs: minimos.NewVulnSrc(),
}
}
// Detect vulnerabilities in package using MinimOS scanner
func (s *Scanner) Detect(ctx context.Context, _ string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.InfoContext(ctx, "Detecting MinimOS vulnerabilities...", log.Int("pkg_num", len(pkgs)))
var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
srcName := pkg.SrcName
if srcName == "" {
srcName = pkg.Name
}
advisories, err := s.vs.Get("", srcName)
if err != nil {
return nil, xerrors.Errorf("failed to get MinimOS advisories: %w", err)
}
installed := utils.FormatVersion(pkg)
installedVersion, err := version.NewVersion(installed)
if err != nil {
log.DebugContext(ctx, "Failed to parse the installed package version",
log.String("version", installed), log.Err(err))
continue
}
for _, adv := range advisories {
if !s.isVulnerable(ctx, installedVersion, adv) {
continue
}
vulns = append(vulns, types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
PkgID: pkg.ID,
PkgName: pkg.Name,
InstalledVersion: installed,
FixedVersion: adv.FixedVersion,
Layer: pkg.Layer,
PkgIdentifier: pkg.Identifier,
Custom: adv.Custom,
DataSource: adv.DataSource,
})
}
}
return vulns, nil
}
func (s *Scanner) isVulnerable(ctx context.Context, installedVersion version.Version, adv dbTypes.Advisory) bool {
// Compare versions for fixed vulnerabilities
fixedVersion, err := version.NewVersion(adv.FixedVersion)
if err != nil {
log.DebugContext(ctx, "Failed to parse the fixed version",
log.String("version", adv.FixedVersion), log.Err(err))
return false
}
// It means the fixed vulnerability
return installedVersion.LessThan(fixedVersion)
}
// IsSupportedVersion checks if the version is supported.
func (s *Scanner) IsSupportedVersion(_ context.Context, _ ftypes.OSType, _ string) bool {
// MinimOS doesn't have versions, so there is no case where a given input yields a
// result of an unsupported MinimOS version.
return true
}

View File

@@ -0,0 +1,210 @@
package minimos_test
import (
"sort"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/aquasecurity/trivy-db/pkg/db"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/aquasecurity/trivy/internal/dbtest"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/minimos"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/types"
)
func TestScanner_Detect(t *testing.T) {
type args struct {
repo *ftypes.Repository
pkgs []ftypes.Package
}
tests := []struct {
name string
args args
fixtures []string
want []types.DetectedVulnerability
wantErr string
}{
{
name: "happy path",
fixtures: []string{
"testdata/fixtures/minimos.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
pkgs: []ftypes.Package{
{
Name: "ansible",
Version: "2.6.4",
SrcName: "ansible",
SrcVersion: "2.6.4",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
{
Name: "invalid",
Version: "invalid", // skipped
SrcName: "invalid",
SrcVersion: "invalid",
},
},
},
want: []types.DetectedVulnerability{
{
PkgName: "ansible",
VulnerabilityID: "CVE-2019-10217",
InstalledVersion: "2.6.4",
FixedVersion: "2.8.4-r0",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
DataSource: &dbTypes.DataSource{
ID: vulnerability.MinimOS,
Name: "MinimOS Secdb",
URL: "https://packages.mini.dev/advisories/secdb/security.json",
},
},
},
},
{
name: "contain rc",
fixtures: []string{
"testdata/fixtures/minimos.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
pkgs: []ftypes.Package{
{
Name: "jq",
Version: "1.6-r0",
SrcName: "jq",
SrcVersion: "1.6-r0",
},
},
},
want: []types.DetectedVulnerability{
{
PkgName: "jq",
VulnerabilityID: "CVE-2020-1234",
InstalledVersion: "1.6-r0",
FixedVersion: "1.6-r1",
DataSource: &dbTypes.DataSource{
ID: vulnerability.MinimOS,
Name: "MinimOS Secdb",
URL: "https://packages.mini.dev/advisories/secdb/security.json",
},
},
},
},
{
name: "contain pre",
fixtures: []string{
"testdata/fixtures/minimos.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
pkgs: []ftypes.Package{
{
Name: "test",
Version: "0.1.0_alpha",
SrcName: "test-src",
SrcVersion: "0.1.0_alpha",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2030-0002",
PkgName: "test",
InstalledVersion: "0.1.0_alpha",
FixedVersion: "0.1.0_alpha2",
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
DataSource: &dbTypes.DataSource{
ID: vulnerability.MinimOS,
Name: "MinimOS Secdb",
URL: "https://packages.mini.dev/advisories/secdb/security.json",
},
},
},
},
{
name: "Get returns an error",
fixtures: []string{
"testdata/fixtures/invalid.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
pkgs: []ftypes.Package{
{
Name: "jq",
Version: "1.6-r0",
SrcName: "jq",
SrcVersion: "1.6-r0",
},
},
},
wantErr: "failed to get MinimOS advisories",
},
{
name: "No src name",
fixtures: []string{
"testdata/fixtures/minimos.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
repo: &ftypes.Repository{
Family: ftypes.MinimOS,
Release: "3.10",
},
pkgs: []ftypes.Package{
{
Name: "jq",
Version: "1.6-r0",
SrcVersion: "1.6-r0",
},
},
},
want: []types.DetectedVulnerability{
{
PkgName: "jq",
VulnerabilityID: "CVE-2020-1234",
InstalledVersion: "1.6-r0",
FixedVersion: "1.6-r1",
DataSource: &dbTypes.DataSource{
ID: vulnerability.MinimOS,
Name: "MinimOS Secdb",
URL: "https://packages.mini.dev/advisories/secdb/security.json",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_ = dbtest.InitDB(t, tt.fixtures)
defer db.Close()
s := minimos.NewScanner()
got, err := s.Detect(t.Context(), "", tt.args.repo, tt.args.pkgs)
if tt.wantErr != "" {
require.ErrorContains(t, err, tt.wantErr)
return
}
sort.Slice(got, func(i, j int) bool {
return got[i].VulnerabilityID < got[j].VulnerabilityID
})
require.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -0,0 +1,7 @@
- bucket: data-source
pairs:
- key: minimos
value:
ID: "minimos"
Name: "MinimOS Secdb"
URL: "https://packages.mini.dev/advisories/secdb/security.json"

View File

@@ -0,0 +1,9 @@
- bucket: minimos
pairs:
- bucket: jq
pairs:
- key: CVE-2020-8177
value:
FixedVersion:
- foo
- bar

View File

@@ -0,0 +1,35 @@
- bucket: minimos
pairs:
- bucket: ansible
pairs:
- key: CVE-2018-10875
value:
FixedVersion: "2.6.3-r0"
- key: CVE-2019-10217
value:
FixedVersion: "2.8.4-r0"
- key: CVE-2021-20191
value:
FixedVersion: ""
- key: CVE-2019-INVALID
value:
FixedVersion: "invalid"
- bucket: jq
pairs:
- key: CVE-2016-4074
value:
FixedVersion: "1.6_rc1-r0"
- key: CVE-2019-9999
value:
FixedVersion: "1.6_rc2"
- key: CVE-2020-1234
value:
FixedVersion: "1.6-r1"
- bucket: test-src
pairs:
- key: CVE-2030-0001
value:
FixedVersion: "0.1.0_alpha_pre2"
- key: CVE-2030-0002
value:
FixedVersion: "0.1.0_alpha2"

View File

@@ -76,6 +76,8 @@ func (a osReleaseAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInp
family = types.CBLMariner
case "echo":
family = types.Echo
case "minimos":
family = types.MinimOS
}
if family != "" && versionID != "" {

View File

@@ -159,6 +159,16 @@ func Test_osReleaseAnalyzer_Analyze(t *testing.T) {
},
},
},
{
name: "MinimOS",
inputFile: "testdata/minimos",
want: &analyzer.AnalysisResult{
OS: types.OS{
Family: types.MinimOS,
Name: "20241031",
},
},
},
{
name: "Bottlerocket",
inputFile: "testdata/bottlerocket",

View File

@@ -0,0 +1,6 @@
ID=minimos
NAME="MinimOS"
PRETTY_NAME="MinimOS"
VERSION_ID="20241031"
HOME_URL="https://minimus.io"
BUG_REPORT_URL="https://support.minimus.io"

View File

@@ -32,6 +32,7 @@ const (
Debian OSType = "debian"
Echo OSType = "echo"
Fedora OSType = "fedora"
MinimOS OSType = "minimos"
OpenSUSE OSType = "opensuse"
OpenSUSELeap OSType = "opensuse-leap"
OpenSUSETumbleweed OSType = "opensuse-tumbleweed"
@@ -116,6 +117,7 @@ var (
Debian,
Echo,
Fedora,
MinimOS,
OpenSUSE,
OpenSUSELeap,
OpenSUSETumbleweed,

View File

@@ -480,7 +480,7 @@ func purlType(t ftypes.TargetType) string {
return packageurl.TypePub
case ftypes.RustBinary, ftypes.Cargo:
return packageurl.TypeCargo
case ftypes.Alpine, ftypes.Chainguard, ftypes.Wolfi:
case ftypes.Alpine, ftypes.Chainguard, ftypes.Wolfi, ftypes.MinimOS:
return packageurl.TypeApk
case ftypes.Debian, ftypes.Ubuntu, ftypes.Echo:
return packageurl.TypeDebian