-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support
environment.yaml
files (#6569)
Signed-off-by: knqyf263 <[email protected]> Co-authored-by: knqyf263 <[email protected]>
- Loading branch information
1 parent
916f6c6
commit e3bef02
Showing
21 changed files
with
673 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,6 +75,7 @@ jobs: | |
dart | ||
swift | ||
bitnami | ||
conda | ||
os | ||
lang | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Conda | ||
|
||
Trivy supports the following scanners for Conda packages. | ||
|
||
| Scanner | Supported | | ||
|:-------------:|:---------:| | ||
| SBOM | ✓ | | ||
| Vulnerability | - | | ||
| License | ✓[^1] | | ||
|
||
|
||
## SBOM | ||
Trivy detects packages that have been installed with `Conda`. | ||
|
||
|
||
### `<package>.json` | ||
Trivy parses `<conda-root>/envs/<env>/conda-meta/<package>.json` files to find the version and license for the dependencies installed in your env. | ||
|
||
### `environment.yml`[^2] | ||
Trivy supports parsing [environment.yml][environment.yml][^2] files to find dependency list. | ||
|
||
!!! note | ||
License detection is currently not supported. | ||
|
||
`environment.yml`[^2] files supports [version range][env-version-range]. We can't be sure about versions for these dependencies. | ||
Therefore, you need to use `conda env export` command to get dependency list in `Conda` default format before scanning `environment.yml`[^2] file. | ||
|
||
!!! note | ||
For dependencies in a non-Conda format, Trivy doesn't include a version of them. | ||
|
||
|
||
[^1]: License detection is only supported for `<package>.json` files | ||
[^2]: Trivy supports both `yaml` and `yml` extensions. | ||
|
||
[environment.yml]: https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#sharing-an-environment | ||
[env-version-range]: https://docs.conda.io/projects/conda-build/en/latest/resources/package-spec.html#examples-of-package-specs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
integration/testdata/conda-environment-cyclonedx.json.golden
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
{ | ||
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", | ||
"bomFormat": "CycloneDX", | ||
"specVersion": "1.5", | ||
"serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000004", | ||
"version": 1, | ||
"metadata": { | ||
"timestamp": "2021-08-25T12:20:30+00:00", | ||
"tools": { | ||
"components": [ | ||
{ | ||
"type": "application", | ||
"group": "aquasecurity", | ||
"name": "trivy", | ||
"version": "dev" | ||
} | ||
] | ||
}, | ||
"component": { | ||
"bom-ref": "3ff14136-e09f-4df9-80ea-000000000001", | ||
"type": "application", | ||
"name": "testdata/fixtures/repo/conda-environment", | ||
"properties": [ | ||
{ | ||
"name": "aquasecurity:trivy:SchemaVersion", | ||
"value": "2" | ||
} | ||
] | ||
} | ||
}, | ||
"components": [ | ||
{ | ||
"bom-ref": "3ff14136-e09f-4df9-80ea-000000000002", | ||
"type": "application", | ||
"name": "environment.yaml", | ||
"properties": [ | ||
{ | ||
"name": "aquasecurity:trivy:Class", | ||
"value": "lang-pkgs" | ||
}, | ||
{ | ||
"name": "aquasecurity:trivy:Type", | ||
"value": "conda-environment" | ||
} | ||
] | ||
}, | ||
{ | ||
"bom-ref": "pkg:conda/[email protected]", | ||
"type": "library", | ||
"name": "bzip2", | ||
"version": "1.0.8", | ||
"purl": "pkg:conda/[email protected]", | ||
"properties": [ | ||
{ | ||
"name": "aquasecurity:trivy:PkgType", | ||
"value": "conda-environment" | ||
} | ||
] | ||
} | ||
], | ||
"dependencies": [ | ||
{ | ||
"ref": "3ff14136-e09f-4df9-80ea-000000000001", | ||
"dependsOn": [ | ||
"3ff14136-e09f-4df9-80ea-000000000002" | ||
] | ||
}, | ||
{ | ||
"ref": "3ff14136-e09f-4df9-80ea-000000000002", | ||
"dependsOn": [ | ||
"pkg:conda/[email protected]" | ||
] | ||
}, | ||
{ | ||
"ref": "pkg:conda/[email protected]", | ||
"dependsOn": [] | ||
} | ||
], | ||
"vulnerabilities": [] | ||
} |
6 changes: 6 additions & 0 deletions
6
integration/testdata/fixtures/repo/conda-environment/environment.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
name: test-env | ||
channels: | ||
- defaults | ||
dependencies: | ||
- bzip2=1.0.8=h998d150_5 | ||
prefix: /opt/conda/envs/test-env |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package environment | ||
|
||
import ( | ||
"sort" | ||
"strings" | ||
"sync" | ||
|
||
"golang.org/x/xerrors" | ||
"gopkg.in/yaml.v3" | ||
|
||
"github.com/aquasecurity/go-version/pkg/version" | ||
"github.com/aquasecurity/trivy/pkg/dependency/types" | ||
"github.com/aquasecurity/trivy/pkg/log" | ||
xio "github.com/aquasecurity/trivy/pkg/x/io" | ||
) | ||
|
||
type environment struct { | ||
Dependencies []Dependency `yaml:"dependencies"` | ||
} | ||
|
||
type Dependency struct { | ||
Value string | ||
Line int | ||
} | ||
|
||
type Parser struct { | ||
logger *log.Logger | ||
once sync.Once | ||
} | ||
|
||
func NewParser() types.Parser { | ||
return &Parser{ | ||
logger: log.WithPrefix("conda"), | ||
once: sync.Once{}, | ||
} | ||
} | ||
|
||
func (p *Parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency, error) { | ||
var env environment | ||
if err := yaml.NewDecoder(r).Decode(&env); err != nil { | ||
return nil, nil, xerrors.Errorf("unable to decode conda environment.yml file: %w", err) | ||
} | ||
|
||
var libs []types.Library | ||
for _, dep := range env.Dependencies { | ||
lib := p.toLibrary(dep) | ||
// Skip empty libs | ||
if lib.Name == "" { | ||
continue | ||
} | ||
libs = append(libs, lib) | ||
} | ||
|
||
sort.Sort(types.Libraries(libs)) | ||
return libs, nil, nil | ||
} | ||
|
||
func (p *Parser) toLibrary(dep Dependency) types.Library { | ||
name, ver := p.parseDependency(dep.Value) | ||
if ver == "" { | ||
p.once.Do(func() { | ||
p.logger.Warn("Unable to detect the dependency versions from `environment.yml` as those versions are not pinned. Use `conda env export` to pin versions.") | ||
}) | ||
} | ||
return types.Library{ | ||
Name: name, | ||
Version: ver, | ||
Locations: types.Locations{ | ||
{ | ||
StartLine: dep.Line, | ||
EndLine: dep.Line, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
// parseDependency parses the dependency line and returns the name and the pinned version. | ||
// The version range is not supported. It parses only the pinned version. | ||
// e.g. | ||
// - numpy 1.8.1 | ||
// - numpy ==1.8.1 | ||
// - numpy 1.8.1 py27_0 | ||
// - numpy=1.8.1=py27_0 | ||
// | ||
// cf. https://docs.conda.io/projects/conda-build/en/latest/resources/package-spec.html#examples-of-package-specs | ||
func (*Parser) parseDependency(line string) (string, string) { | ||
line = strings.NewReplacer(">", " >", "<", " <", "=", " ").Replace(line) | ||
parts := strings.Fields(line) | ||
name := parts[0] | ||
if len(parts) == 1 { | ||
return name, "" | ||
} | ||
if _, err := version.Parse(parts[1]); err != nil { | ||
return name, "" | ||
} | ||
return name, parts[1] | ||
} | ||
|
||
func (d *Dependency) UnmarshalYAML(node *yaml.Node) error { | ||
d.Value = node.Value | ||
d.Line = node.Line | ||
return nil | ||
} |
Oops, something went wrong.