Compare commits

...

5 Commits

Author SHA1 Message Date
Aqua Security automated builds
86ee3c1176 release: v0.64.1 [release/v0.64] (#9122) 2025-07-03 13:18:35 +00:00
Aqua Security automated builds
4e1272283a fix(misconf): skip rewriting expr if attr is nil [backport: release/v0.64] (#9127)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
Co-authored-by: Nikita Pivkin <nikita.pivkin@smartforce.io>
2025-07-03 06:42:19 +00:00
Aqua Security automated builds
9a7d38432c fix(cli): Add more non-sensitive flags to telemetry [backport: release/v0.64] (#9124)
Co-authored-by: Owen Rumney <owen.rumney@aquasec.com>
2025-07-02 11:20:33 +00:00
Aqua Security automated builds
53adfba3c2 fix(rootio): check full version to detect root.io packages [backport: release/v0.64] (#9120)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2025-07-02 10:29:38 +00:00
Aqua Security automated builds
8cf1bf9f6f fix(alma): parse epochs from rpmqa file [backport: release/v0.64] (#9119)
Co-authored-by: Tom Fay <tom@teamfay.co.uk>
2025-07-02 09:41:53 +00:00
21 changed files with 194 additions and 71 deletions

View File

@@ -67,6 +67,7 @@ jobs:
distroless distroless
windows windows
minimos minimos
rootio
# Languages # Languages
ruby ruby

View File

@@ -1 +1 @@
{".":"0.64.0"} {".":"0.64.1"}

View File

@@ -1,5 +1,15 @@
# Changelog # Changelog
## [0.64.1](https://github.com/aquasecurity/trivy/compare/v0.64.0...v0.64.1) (2025-07-03)
### Bug Fixes
* **alma:** parse epochs from rpmqa file [backport: release/v0.64] ([#9119](https://github.com/aquasecurity/trivy/issues/9119)) ([8cf1bf9](https://github.com/aquasecurity/trivy/commit/8cf1bf9f6f86936ee7dcd29e0d1cd1ec106e28f6))
* **cli:** Add more non-sensitive flags to telemetry [backport: release/v0.64] ([#9124](https://github.com/aquasecurity/trivy/issues/9124)) ([9a7d384](https://github.com/aquasecurity/trivy/commit/9a7d38432cf00f00970259e5ac3edd060e00ccff))
* **misconf:** skip rewriting expr if attr is nil [backport: release/v0.64] ([#9127](https://github.com/aquasecurity/trivy/issues/9127)) ([4e12722](https://github.com/aquasecurity/trivy/commit/4e1272283a643bfca2d7231d286006219715fada))
* **rootio:** check full version to detect `root.io` packages [backport: release/v0.64] ([#9120](https://github.com/aquasecurity/trivy/issues/9120)) ([53adfba](https://github.com/aquasecurity/trivy/commit/53adfba3c25664b01e3a36fdec334b39b53c07f1))
## [0.64.0](https://github.com/aquasecurity/trivy/compare/v0.63.0...v0.64.0) (2025-06-30) ## [0.64.0](https://github.com/aquasecurity/trivy/compare/v0.63.0...v0.64.0) (2025-06-30)

View File

@@ -1,19 +1,40 @@
``` ```
--clear-cache
--debug --debug
--dependency-tree
--detection-priority --detection-priority
--distro
--exit-code
--exit-on-eol
--format --format
--ignore-status --ignore-status
--ignore-unfixed
--image-config-scanners
--include-deprecated-checks
--include-dev-deps --include-dev-deps
--include-non-failures
--insecure --insecure
--license-full
--list-all-pkgs --list-all-pkgs
--misconfig-scanners --misconfig-scanners
--offline-scan
--parallel
--password-stdin
--pkg-relationships --pkg-relationships
--pkg-types --pkg-types
--quiet --quiet
--redis-tls
--removed-pkgs
--report --report
--scanners --scanners
--severity --severity
--show-suppressed --show-suppressed
--skip-check-update
--skip-version-check
--skip-vex-repo-update
--slow
--tf-exclude-downloaded-modules
--timeout --timeout
--trace
--vuln-severity-source --vuln-severity-source
``` ```

View File

@@ -5,6 +5,7 @@ import (
"github.com/aquasecurity/trivy/pkg/detector/ospkg/driver" "github.com/aquasecurity/trivy/pkg/detector/ospkg/driver"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/scan/utils"
) )
var ( var (
@@ -37,7 +38,7 @@ func isRootIOEnvironment(osFamily ftypes.OSType, pkgs []ftypes.Package) bool {
// hasPackageWithPattern checks if any package version matches the specified pattern // hasPackageWithPattern checks if any package version matches the specified pattern
func hasPackageWithPattern(pkgs []ftypes.Package, pattern *regexp.Regexp) bool { func hasPackageWithPattern(pkgs []ftypes.Package, pattern *regexp.Regexp) bool {
for _, pkg := range pkgs { for _, pkg := range pkgs {
if pattern.MatchString(pkg.Version) { if pattern.MatchString(utils.FormatVersion(pkg)) {
return true return true
} }
} }

View File

@@ -21,7 +21,7 @@ func TestProvider(t *testing.T) {
name: "Debian with .root.io package", name: "Debian with .root.io package",
osFamily: ftypes.Debian, osFamily: ftypes.Debian,
pkgs: []ftypes.Package{ pkgs: []ftypes.Package{
{Name: "libc6", Version: "2.31-13+deb11u4.root.io"}, {Name: "libc6", Version: "2.31", Release: "13+deb11u4.root.io"},
{Name: "bash", Version: "5.1-2+deb11u1"}, {Name: "bash", Version: "5.1-2+deb11u1"},
}, },
want: true, want: true,

View File

@@ -5,6 +5,7 @@ import (
"context" "context"
"os" "os"
"slices" "slices"
"strconv"
"strings" "strings"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@@ -50,6 +51,7 @@ func (a rpmqaPkgAnalyzer) parseRpmqaManifest(r xio.ReadSeekerAt) ([]types.Packag
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
var name, ver, rel, sourceRpm, arch string var name, ver, rel, sourceRpm, arch string
var epoch int
// %{NAME}\t%{VERSION}-%{RELEASE}\t%{INSTALLTIME}\t%{BUILDTIME}\t%{VENDOR}\t(none)\t%{SIZE}\t%{ARCH}\t%{EPOCHNUM}\t%{SOURCERPM} // %{NAME}\t%{VERSION}-%{RELEASE}\t%{INSTALLTIME}\t%{BUILDTIME}\t%{VENDOR}\t(none)\t%{SIZE}\t%{ARCH}\t%{EPOCHNUM}\t%{SOURCERPM}
s := strings.Split(line, "\t") s := strings.Split(line, "\t")
if len(s) != 10 { if len(s) != 10 {
@@ -68,12 +70,18 @@ func (a rpmqaPkgAnalyzer) parseRpmqaManifest(r xio.ReadSeekerAt) ([]types.Packag
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to split source rpm: %w", err) return nil, xerrors.Errorf("failed to split source rpm: %w", err)
} }
epoch, err = strconv.Atoi(s[8])
if err != nil {
return nil, xerrors.Errorf("failed to parse epoch number (%s): %w", s[8], err)
}
pkgs = append(pkgs, types.Package{ pkgs = append(pkgs, types.Package{
Name: name, Name: name,
Version: ver, Version: ver,
Epoch: epoch,
Release: rel, Release: rel,
Arch: arch, Arch: arch,
SrcName: srcName, SrcName: srcName,
SrcEpoch: epoch,
SrcVersion: srcVer, SrcVersion: srcVer,
SrcRelease: srcRel, SrcRelease: srcRel,
}) })

View File

@@ -21,7 +21,8 @@ func TestParseMarinerDistrolessManifest(t *testing.T) {
name: "happy path", name: "happy path",
content: `mariner-release 2.0-12.cm2 1653816591 1653753130 Microsoft Corporation (none) 580 noarch 0 mariner-release-2.0-12.cm2.src.rpm content: `mariner-release 2.0-12.cm2 1653816591 1653753130 Microsoft Corporation (none) 580 noarch 0 mariner-release-2.0-12.cm2.src.rpm
filesystem 1.1-9.cm2 1653816591 1653628924 Microsoft Corporation (none) 7596 x86_64 0 filesystem-1.1-9.cm2.src.rpm filesystem 1.1-9.cm2 1653816591 1653628924 Microsoft Corporation (none) 7596 x86_64 0 filesystem-1.1-9.cm2.src.rpm
glibc 2.35-2.cm2 1653816591 1653628955 Microsoft Corporation (none) 10855265 x86_64 0 glibc-2.35-2.cm2.src.rpm`, glibc 2.35-2.cm2 1653816591 1653628955 Microsoft Corporation (none) 10855265 x86_64 0 glibc-2.35-2.cm2.src.rpm
ca-certificates-base 3.0.0-8.azl3 1748892790 1735838940 Microsoft Corporation (none) 130628 noarch 1 ca-certificates-3.0.0-8.azl3.src.rpm`,
wantPkgs: []types.Package{ wantPkgs: []types.Package{
{ {
Name: "mariner-release", Name: "mariner-release",
@@ -50,6 +51,17 @@ glibc 2.35-2.cm2 1653816591 1653628955 Microsoft Corporation (none) 10855265 x86
SrcVersion: "2.35", SrcVersion: "2.35",
SrcRelease: "2.cm2", SrcRelease: "2.cm2",
}, },
{
Name: "ca-certificates-base",
Version: "3.0.0",
Epoch: 1,
Release: "8.azl3",
Arch: "noarch",
SrcName: "ca-certificates",
SrcEpoch: 1,
SrcVersion: "3.0.0",
SrcRelease: "8.azl3",
},
}, },
}, },
{ {

View File

@@ -20,6 +20,7 @@ var (
ConfigName: "cache.clear", ConfigName: "cache.clear",
Usage: "clear image caches without scanning", Usage: "clear image caches without scanning",
Removed: `Use "trivy clean --scan-cache" instead`, Removed: `Use "trivy clean --scan-cache" instead`,
TelemetrySafe: true,
} }
CacheBackendFlag = Flag[string]{ CacheBackendFlag = Flag[string]{
Name: "cache-backend", Name: "cache-backend",
@@ -36,6 +37,7 @@ var (
Name: "redis-tls", Name: "redis-tls",
ConfigName: "cache.redis.tls", ConfigName: "cache.redis.tls",
Usage: "enable redis TLS with public certificates, if using redis as cache backend", Usage: "enable redis TLS with public certificates, if using redis as cache backend",
TelemetrySafe: true,
} }
RedisCACertFlag = Flag[string]{ RedisCACertFlag = Flag[string]{
Name: "redis-ca", Name: "redis-ca",

View File

@@ -24,11 +24,13 @@ var (
types.SecretScanner, types.SecretScanner,
}), }),
Usage: "comma-separated list of what security issues to detect on container image configurations", Usage: "comma-separated list of what security issues to detect on container image configurations",
TelemetrySafe: true,
} }
ScanRemovedPkgsFlag = Flag[bool]{ ScanRemovedPkgsFlag = Flag[bool]{
Name: "removed-pkgs", Name: "removed-pkgs",
ConfigName: "image.removed-pkgs", ConfigName: "image.removed-pkgs",
Usage: "detect vulnerabilities of removed packages (only for Alpine)", Usage: "detect vulnerabilities of removed packages (only for Alpine)",
TelemetrySafe: true,
} }
InputFlag = Flag[string]{ InputFlag = Flag[string]{
Name: "input", Name: "input",

View File

@@ -10,6 +10,7 @@ var (
Name: "license-full", Name: "license-full",
ConfigName: "license.full", ConfigName: "license.full",
Usage: "eagerly look for licenses in source code headers and license files", Usage: "eagerly look for licenses in source code headers and license files",
TelemetrySafe: true,
} }
IgnoredLicenses = Flag[[]string]{ IgnoredLicenses = Flag[[]string]{
Name: "ignored-licenses", Name: "ignored-licenses",

View File

@@ -36,6 +36,7 @@ var (
Name: "include-non-failures", Name: "include-non-failures",
ConfigName: "misconfiguration.include-non-failures", ConfigName: "misconfiguration.include-non-failures",
Usage: "include successes, available with '--scanners misconfig'", Usage: "include successes, available with '--scanners misconfig'",
TelemetrySafe: true,
} }
HelmValuesFileFlag = Flag[[]string]{ HelmValuesFileFlag = Flag[[]string]{
Name: "helm-values", Name: "helm-values",
@@ -82,6 +83,7 @@ var (
Name: "tf-exclude-downloaded-modules", Name: "tf-exclude-downloaded-modules",
ConfigName: "misconfiguration.terraform.exclude-downloaded-modules", ConfigName: "misconfiguration.terraform.exclude-downloaded-modules",
Usage: "exclude misconfigurations for downloaded terraform modules", Usage: "exclude misconfigurations for downloaded terraform modules",
TelemetrySafe: true,
} }
ChecksBundleRepositoryFlag = Flag[string]{ ChecksBundleRepositoryFlag = Flag[string]{
Name: "checks-bundle-repository", Name: "checks-bundle-repository",

View File

@@ -25,6 +25,7 @@ var (
Name: "password-stdin", Name: "password-stdin",
ConfigName: "registry.password-stdin", ConfigName: "registry.password-stdin",
Usage: "password from stdin. Comma-separated passwords are not supported.", Usage: "password from stdin. Comma-separated passwords are not supported.",
TelemetrySafe: true,
} }
RegistryTokenFlag = Flag[string]{ RegistryTokenFlag = Flag[string]{
Name: "registry-token", Name: "registry-token",

View File

@@ -11,6 +11,7 @@ var (
Name: "include-deprecated-checks", Name: "include-deprecated-checks",
ConfigName: "rego.include-deprecated-checks", ConfigName: "rego.include-deprecated-checks",
Usage: "include deprecated checks", Usage: "include deprecated checks",
TelemetrySafe: true,
} }
SkipCheckUpdateFlag = Flag[bool]{ SkipCheckUpdateFlag = Flag[bool]{
Name: "skip-check-update", Name: "skip-check-update",
@@ -23,11 +24,13 @@ var (
Deprecated: true, Deprecated: true,
}, },
}, },
TelemetrySafe: true,
} }
TraceFlag = Flag[bool]{ TraceFlag = Flag[bool]{
Name: "trace", Name: "trace",
ConfigName: "rego.trace", ConfigName: "rego.trace",
Usage: "enable more verbose trace output for custom queries", Usage: "enable more verbose trace output for custom queries",
TelemetrySafe: true,
} }
ConfigCheckFlag = Flag[[]string]{ ConfigCheckFlag = Flag[[]string]{
Name: "config-check", Name: "config-check",

View File

@@ -55,6 +55,7 @@ var (
Name: "dependency-tree", Name: "dependency-tree",
ConfigName: "dependency-tree", ConfigName: "dependency-tree",
Usage: "[EXPERIMENTAL] show dependency origin tree of vulnerable packages", Usage: "[EXPERIMENTAL] show dependency origin tree of vulnerable packages",
TelemetrySafe: true,
} }
ListAllPkgsFlag = Flag[bool]{ ListAllPkgsFlag = Flag[bool]{
Name: "list-all-pkgs", Name: "list-all-pkgs",
@@ -77,11 +78,13 @@ var (
Name: "exit-code", Name: "exit-code",
ConfigName: "exit-code", ConfigName: "exit-code",
Usage: "specify exit code when any security issues are found", Usage: "specify exit code when any security issues are found",
TelemetrySafe: true,
} }
ExitOnEOLFlag = Flag[int]{ ExitOnEOLFlag = Flag[int]{
Name: "exit-on-eol", Name: "exit-on-eol",
ConfigName: "exit-on-eol", ConfigName: "exit-on-eol",
Usage: "exit with the specified code when the OS reaches end of service/life", Usage: "exit with the specified code when the OS reaches end of service/life",
TelemetrySafe: true,
} }
OutputFlag = Flag[string]{ OutputFlag = Flag[string]{
Name: "output", Name: "output",

View File

@@ -30,6 +30,7 @@ var (
Name: "offline-scan", Name: "offline-scan",
ConfigName: "scan.offline", ConfigName: "scan.offline",
Usage: "do not issue API requests to identify dependencies", Usage: "do not issue API requests to identify dependencies",
TelemetrySafe: true,
} }
ScannersFlag = Flag[[]string]{ ScannersFlag = Flag[[]string]{
Name: "scanners", Name: "scanners",
@@ -79,12 +80,14 @@ var (
Default: false, Default: false,
Usage: "scan over time with lower CPU and memory utilization", Usage: "scan over time with lower CPU and memory utilization",
Deprecated: `Use "--parallel 1" instead.`, Deprecated: `Use "--parallel 1" instead.`,
TelemetrySafe: true,
} }
ParallelFlag = Flag[int]{ ParallelFlag = Flag[int]{
Name: "parallel", Name: "parallel",
ConfigName: "scan.parallel", ConfigName: "scan.parallel",
Default: 5, Default: 5,
Usage: "number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism", Usage: "number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism",
TelemetrySafe: true,
} }
SBOMSourcesFlag = Flag[[]string]{ SBOMSourcesFlag = Flag[[]string]{
Name: "sbom-sources", Name: "sbom-sources",
@@ -119,11 +122,13 @@ var (
Name: "distro", Name: "distro",
ConfigName: "scan.distro", ConfigName: "scan.distro",
Usage: "[EXPERIMENTAL] specify a distribution, <family>/<version>", Usage: "[EXPERIMENTAL] specify a distribution, <family>/<version>",
TelemetrySafe: true,
} }
SkipVersionCheckFlag = Flag[bool]{ SkipVersionCheckFlag = Flag[bool]{
Name: "skip-version-check", Name: "skip-version-check",
ConfigName: "scan.skip-version-check", ConfigName: "scan.skip-version-check",
Usage: "suppress notices about version updates and Trivy announcements", Usage: "suppress notices about version updates and Trivy announcements",
TelemetrySafe: true,
} }
DisableTelemetryFlag = Flag[bool]{ DisableTelemetryFlag = Flag[bool]{
Name: "disable-telemetry", Name: "disable-telemetry",

View File

@@ -15,6 +15,7 @@ var (
Name: "ignore-unfixed", Name: "ignore-unfixed",
ConfigName: "vulnerability.ignore-unfixed", ConfigName: "vulnerability.ignore-unfixed",
Usage: "display only fixed vulnerabilities", Usage: "display only fixed vulnerabilities",
TelemetrySafe: true,
} }
IgnoreStatusFlag = Flag[[]string]{ IgnoreStatusFlag = Flag[[]string]{
Name: "ignore-status", Name: "ignore-status",
@@ -32,6 +33,7 @@ var (
Name: "skip-vex-repo-update", Name: "skip-vex-repo-update",
ConfigName: "vulnerability.skip-vex-repo-update", ConfigName: "vulnerability.skip-vex-repo-update",
Usage: `[EXPERIMENTAL] Skip VEX Repository update`, Usage: `[EXPERIMENTAL] Skip VEX Repository update`,
TelemetrySafe: true,
} }
VulnSeveritySourceFlag = Flag[[]string]{ VulnSeveritySourceFlag = Flag[[]string]{
Name: "vuln-severity-source", Name: "vuln-severity-source",

View File

@@ -17,6 +17,11 @@ type wrappedDocument struct {
} }
func ParsePolicyFromAttr(attr *terraform.Attribute, owner *terraform.Block, modules terraform.Modules) (*iam.Document, error) { func ParsePolicyFromAttr(attr *terraform.Attribute, owner *terraform.Block, modules terraform.Modules) (*iam.Document, error) {
if attr == nil {
return &iam.Document{
Metadata: owner.GetMetadata(),
}, nil
}
attr.RewriteExpr(func(e hclsyntax.Expression) hclsyntax.Expression { attr.RewriteExpr(func(e hclsyntax.Expression) hclsyntax.Expression {
if te, ok := e.(*hclsyntax.TemplateExpr); ok { if te, ok := e.(*hclsyntax.TemplateExpr); ok {
return &terraform.PartialTemplateExpr{TemplateExpr: te} return &terraform.PartialTemplateExpr{TemplateExpr: te}

View File

@@ -1,6 +1,8 @@
package iam package iam
import ( import (
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/aquasecurity/iamgo" "github.com/aquasecurity/iamgo"
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam" "github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam"
"github.com/aquasecurity/trivy/pkg/iac/terraform" "github.com/aquasecurity/trivy/pkg/iac/terraform"
@@ -140,11 +142,20 @@ func findAttachmentPolicy(modules terraform.Modules) func(resource *terraform.Bl
} }
} }
// Searching for a referenced block only makes sense for traversal expressions,
// since only they can directly reference other blocks in the configuration.
switch attr.HCLAttribute().Expr.(type) {
case *hclsyntax.RelativeTraversalExpr, *hclsyntax.ScopeTraversalExpr:
if block, err := modules.GetReferencedBlock(attr, resource); err == nil { if block, err := modules.GetReferencedBlock(attr, resource); err == nil {
return findPolicy(modules)(block) return findPolicy(modules)(block)
} }
}
return nil return &iam.Policy{
Metadata: resource.GetMetadata(),
Document: iam.Document{
Metadata: resource.GetMetadata(),
},
}
} }
} }

View File

@@ -338,6 +338,32 @@ resource "aws_iam_role_policy_attachment" "test" {
}, },
}, },
}, },
{
name: "policy is template with unknown part",
terraform: `resource "aws_iam_role" "default" {
name = "test"
}
resource "aws_iam_role_policy_attachment" "amazon_eks_cluster_policy" {
role = aws_iam_role.default.name
policy_arn = format("arn:%s:iam::aws:policy/AmazonEKSClusterPolicy", data.aws_partition.current.partition)
}
data "aws_partition" "current" {}
`,
expected: []iam.Role{
{
Name: iacTypes.StringTest("test"),
Policies: []iam.Policy{
{
Name: iacTypes.StringTest(""),
Document: iam.Document{},
},
},
},
},
},
} }
for _, test := range tests { for _, test := range tests {

View File

@@ -834,7 +834,14 @@ func safeOp[T any](a *Attribute, fn func(cty.Value) T) T {
// RewriteExpr applies the given function `transform` to the expression of the attribute, // RewriteExpr applies the given function `transform` to the expression of the attribute,
// recursively traversing and transforming it. // recursively traversing and transforming it.
func (a *Attribute) RewriteExpr(transform func(hclsyntax.Expression) hclsyntax.Expression) { func (a *Attribute) RewriteExpr(transform func(hclsyntax.Expression) hclsyntax.Expression) {
a.hclAttribute.Expr = RewriteExpr(a.hclAttribute.Expr.(hclsyntax.Expression), transform) if a == nil || a.hclAttribute == nil {
return
}
expr, ok := a.hclAttribute.Expr.(hclsyntax.Expression)
if !ok {
return
}
a.hclAttribute.Expr = RewriteExpr(expr, transform)
} }
// nolint: gocyclo // nolint: gocyclo