Skip to content

Commit

Permalink
Merge branch '510-attach-sbomb-attestation' of https://github.com/anc…
Browse files Browse the repository at this point in the history
…hore/syft into 510-attach-sbomb-attestation

* '510-attach-sbomb-attestation' of https://github.com/anchore/syft:
  Upgrade install.sh to support installations for previous versions (#830)
  remove duplicate manifest lines (#828)
  bump stereoscope to include functional options (#823)
  update golang crypto library dependency (#815)
  deduplicate SPDX tag-value package IDs (#813)
  Add pURL generation for java packages + fix NPM pURL generation (#812)
  • Loading branch information
spiffcs committed Feb 17, 2022
2 parents c16f566 + c3f9797 commit 6c2fe7d
Show file tree
Hide file tree
Showing 25 changed files with 264 additions and 131 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/release.yaml
Expand Up @@ -142,10 +142,12 @@ jobs:
AC_PASSWORD: ${{ secrets.ENG_CI_APPLE_ID_PASS }}

- uses: anchore/sbom-action@v0
continue-on-error: true
with:
artifact-name: sbom.spdx.json

- uses: 8398a7/action-slack@v3
continue-on-error: true
with:
status: ${{ job.status }}
fields: repo,workflow,action,eventName
Expand Down
8 changes: 0 additions & 8 deletions .goreleaser.yaml
Expand Up @@ -124,17 +124,9 @@ dockers:
docker_manifests:
- name_template: anchore/syft:{{ .Tag }}
image_templates:
- anchore/syft:{{ .Tag }}-amd64
- anchore/syft:v{{ .Major }}-amd64
- anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64
- anchore/syft:{{ .Tag }}-arm64v8
- anchore/syft:v{{ .Major }}-arm64v8
- anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8
- name_template: anchore/syft:latest
image_templates:
- anchore/syft:{{ .Tag }}-amd64
- anchore/syft:v{{ .Major }}-amd64
- anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64
- anchore/syft:{{ .Tag }}-arm64v8
- anchore/syft:v{{ .Major }}-arm64v8
- anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8
2 changes: 1 addition & 1 deletion go.sum
Expand Up @@ -2931,4 +2931,4 @@ sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
32 changes: 25 additions & 7 deletions install.sh
Expand Up @@ -6,6 +6,11 @@ PROJECT_NAME="syft"
OWNER=anchore
REPO="${PROJECT_NAME}"
GITHUB_DOWNLOAD_PREFIX=https://github.com/${OWNER}/${REPO}/releases/download
INSTALL_SH_BASE_URL=https://raw.githubusercontent.com/${OWNER}/${PROJECT_NAME}
PROGRAM_ARGS=$@

# do not change the name of this parameter (this must always be backwards compatible)
DOWNLOAD_TAG_INSTALL_SCRIPT=${DOWNLOAD_TAG_INSTALL_SCRIPT:-true}

#
# usage [script-name]
Expand Down Expand Up @@ -607,7 +612,10 @@ install_asset() (
main() (
# parse arguments

# note: never change default install directory (this must always be backwards compatible)
install_dir=${install_dir:-./bin}

# note: never change the program flags or arguments (this must always be backwards compatible)
while getopts "b:dh?x" arg; do
case "$arg" in
b) install_dir="$OPTARG" ;;
Expand All @@ -629,10 +637,10 @@ main() (
tag=$1

if [ -z "${tag}" ]; then
log_info "checking github for the current release tag"
log_debug "checking github for the current release tag"
tag=""
else
log_info "checking github for release tag='${tag}'"
log_debug "checking github for release tag='${tag}'"
fi
set -u

Expand All @@ -644,20 +652,30 @@ main() (
return 1
fi

version=$(tag_to_version "${tag}")

download_dir=$(mktemp -d)
trap 'rm -rf -- "$download_dir"' EXIT

# run the application

version=$(tag_to_version "${tag}")
os=$(uname_os)
arch=$(uname_arch)
format=$(get_format_name "${os}" "${arch}" "tar.gz")
binary=$(get_binary_name "${os}" "${arch}" "${PROJECT_NAME}")
download_url="${GITHUB_DOWNLOAD_PREFIX}/${tag}"

# we always use the install.sh script that is associated with the tagged release. Why? the latest install.sh is not
# guaranteed to be able to install every version of the application. We use the DOWNLOAD_TAG_INSTALL_SCRIPT env var
# to indicate if we should continue processing with the existing script or to download the script from the given tag.
if [ "${DOWNLOAD_TAG_INSTALL_SCRIPT}" = "true" ]; then
export DOWNLOAD_TAG_INSTALL_SCRIPT=false
log_info "fetching release script for tag='${tag}'"
http_copy "${INSTALL_SH_BASE_URL}/${tag}/install.sh" "" | sh -s -- ${PROGRAM_ARGS}
exit $?
fi

log_info "using release tag='${tag}' version='${version}' os='${os}' arch='${arch}'"

download_dir=$(mktemp -d)
trap 'rm -rf -- "$download_dir"' EXIT

log_debug "downloading files into ${download_dir}"

download_and_install_asset "${download_url}" "${download_dir}" "${install_dir}" "${PROJECT_NAME}" "${os}" "${arch}" "${version}" "${format}" "${binary}"
Expand Down
Expand Up @@ -2,16 +2,16 @@ SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: /some/path
DocumentNamespace: https://anchore.com/syft/dir/some/path-22f5732a-cab0-4376-9b79-15e413049500
LicenseListVersion: 3.15
DocumentNamespace: https://anchore.com/syft/dir/some/path-4b90f56d-d596-4ad8-b6a5-17f7d801350d
LicenseListVersion: 3.16
Creator: Organization: Anchore, Inc
Creator: Tool: syft-[not provided]
Created: 2021-12-01T15:08:43Z
Created: 2022-02-10T21:09:27Z

##### Package: package-2

PackageName: package-2
SPDXID: SPDXRef-Package-deb-package-2
SPDXID: SPDXRef-Package-deb-package-2-ad3d1c4abd84bf75
PackageVersion: 2.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
Expand All @@ -24,7 +24,7 @@ ExternalRef: PACKAGE_MANAGER purl a-purl-2
##### Package: package-1

PackageName: package-1
SPDXID: SPDXRef-Package-python-package-1
SPDXID: SPDXRef-Package-python-package-1-1d97af55efe9512f
PackageVersion: 1.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
Expand Down
Expand Up @@ -2,16 +2,16 @@ SPDXVersion: SPDX-2.2
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: user-image-input
DocumentNamespace: https://anchore.com/syft/image/user-image-input-ce4d4ae5-9d79-4f84-a410-361e394c2908
LicenseListVersion: 3.15
DocumentNamespace: https://anchore.com/syft/image/user-image-input-26a2def6-53d0-4504-b99a-a046832508ac
LicenseListVersion: 3.16
Creator: Organization: Anchore, Inc
Creator: Tool: syft-[not provided]
Created: 2021-12-01T15:08:44Z
Created: 2022-02-10T21:09:27Z

##### Package: package-2

PackageName: package-2
SPDXID: SPDXRef-Package-deb-package-2
SPDXID: SPDXRef-Package-deb-package-2-73f796c846875b9e
PackageVersion: 2.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
Expand All @@ -24,7 +24,7 @@ ExternalRef: PACKAGE_MANAGER purl a-purl-2
##### Package: package-1

PackageName: package-1
SPDXID: SPDXRef-Package-python-package-1
SPDXID: SPDXRef-Package-python-package-1-d9527e708c11f8b9
PackageVersion: 1.0.1
PackageDownloadLocation: NOASSERTION
FilesAnalyzed: false
Expand Down
4 changes: 2 additions & 2 deletions internal/formats/spdx22tagvalue/to_format_model.go
Expand Up @@ -94,9 +94,9 @@ func toFormatModel(s sbom.SBOM) (*spdx.Document2_2, error) {
func toFormatPackages(catalog *pkg.Catalog) map[spdx.ElementID]*spdx.Package2_2 {
results := make(map[spdx.ElementID]*spdx.Package2_2)

for p := range catalog.Enumerate() {
for _, p := range catalog.Sorted() {
// name should be guaranteed to be unique, but semantically useful and stable
id := fmt.Sprintf("Package-%+v-%s", p.Type, p.Name)
id := fmt.Sprintf("Package-%+v-%s-%s", p.Type, p.Name, p.ID())

// If the Concluded License is not the same as the Declared License, a written explanation should be provided
// in the Comments on License field (section 3.16). With respect to NOASSERTION, a written explanation in
Expand Down
4 changes: 4 additions & 0 deletions internal/formats/syftjson/decoder_test.go
Expand Up @@ -21,6 +21,10 @@ func TestEncodeDecodeCycle(t *testing.T) {
assert.NoError(t, err)

for _, d := range deep.Equal(originalSBOM.Source, actualSBOM.Source) {
if strings.HasSuffix(d, "<nil slice> != []") {
// semantically the same
continue
}
t.Errorf("metadata difference: %+v", d)
}

Expand Down
10 changes: 9 additions & 1 deletion internal/formats/syftjson/to_format_model.go
Expand Up @@ -217,9 +217,17 @@ func toRelationshipModel(relationships []artifact.Relationship) []model.Relation
func toSourceModel(src source.Metadata) (model.Source, error) {
switch src.Scheme {
case source.ImageScheme:
metadata := src.ImageMetadata
// ensure that empty collections are not shown as null
if metadata.RepoDigests == nil {
metadata.RepoDigests = []string{}
}
if metadata.Tags == nil {
metadata.Tags = []string{}
}
return model.Source{
Type: "image",
Target: src.ImageMetadata,
Target: metadata,
}, nil
case source.DirectoryScheme:
return model.Source{
Expand Down
2 changes: 2 additions & 0 deletions internal/formats/syftjson/to_format_model_test.go
Expand Up @@ -63,6 +63,8 @@ func Test_toSourceModel(t *testing.T) {
ID: "id...",
ManifestDigest: "digest...",
MediaType: "type...",
RepoDigests: []string{},
Tags: []string{},
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions syft/pkg/cataloger/common/cpe/java.go
Expand Up @@ -40,11 +40,11 @@ var (
)

func candidateProductsForJava(p pkg.Package) []string {
return productsFromArtifactAndGroupIDs(artifactIDFromJavaPackage(p), groupIDsFromJavaPackage(p))
return productsFromArtifactAndGroupIDs(artifactIDFromJavaPackage(p), GroupIDsFromJavaPackage(p))
}

func candidateVendorsForJava(p pkg.Package) fieldCandidateSet {
gidVendors := vendorsFromGroupIDs(groupIDsFromJavaPackage(p))
gidVendors := vendorsFromGroupIDs(GroupIDsFromJavaPackage(p))
nameVendors := vendorsFromJavaManifestNames(p)
return newFieldCandidateSetFromSets(gidVendors, nameVendors)
}
Expand Down Expand Up @@ -173,7 +173,7 @@ func artifactIDFromJavaPackage(p pkg.Package) string {
return artifactID
}

func groupIDsFromJavaPackage(p pkg.Package) (groupIDs []string) {
func GroupIDsFromJavaPackage(p pkg.Package) (groupIDs []string) {
metadata, ok := p.Metadata.(pkg.JavaMetadata)
if !ok {
return nil
Expand Down
2 changes: 1 addition & 1 deletion syft/pkg/cataloger/common/cpe/java_test.go
Expand Up @@ -333,7 +333,7 @@ func Test_groupIDsFromJavaPackage(t *testing.T) {
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.ElementsMatch(t, test.expects, groupIDsFromJavaPackage(test.pkg))
assert.ElementsMatch(t, test.expects, GroupIDsFromJavaPackage(test.pkg))
})
}
}
Expand Down
17 changes: 1 addition & 16 deletions syft/pkg/cataloger/java/archive_filename.go
Expand Up @@ -55,28 +55,13 @@ type archiveFilename struct {
version string
}

// TODO: Remove this method once we're using Go 1.15+.
//
// Go 1.15 introduces a `SubexpIndex` method for the Regexp type that would let
// this code be made more elegant. Once we've reached 1.15, we should eliminate
// this function in favor of that method.
func subexpIndex(re *regexp.Regexp, name string) int {
for i, subexpName := range re.SubexpNames() {
if subexpName == name {
return i
}
}

return -1
}

func getSubexp(matches []string, subexpName string, re *regexp.Regexp, raw string) string {
if len(matches) < 1 {
log.Warnf("unexpectedly empty matches for archive '%s'", raw)
return ""
}

index := subexpIndex(re, subexpName)
index := re.SubexpIndex(subexpName)
if index < 1 {
log.Warnf("unexpected index of '%s' capture group for Java archive '%s'", subexpName, raw)
return ""
Expand Down
25 changes: 23 additions & 2 deletions syft/pkg/cataloger/java/archive_parser.go
Expand Up @@ -122,6 +122,13 @@ func (j *archiveParser) parse() ([]*pkg.Package, []artifact.Relationship, error)
pkgs = append([]*pkg.Package{parentPkg}, pkgs...)
}

// add pURLs to all packages found
// note: since package information may change after initial creation when parsing multiple locations within the
// jar, we wait until the conclusion of the parsing process before synthesizing pURLs.
for _, p := range pkgs {
addPURL(p)
}

return pkgs, relationships, nil
}

Expand Down Expand Up @@ -348,7 +355,7 @@ func newPackageFromMavenData(pomProperties pkg.PomProperties, pomProject *pkg.Po
}

if packageIdentitiesMatch(p, parentPkg) {
updatePackage(p, parentPkg)
updateParentPackage(p, parentPkg)
return nil
}

Expand Down Expand Up @@ -379,7 +386,7 @@ func packageIdentitiesMatch(p pkg.Package, parentPkg *pkg.Package) bool {
return false
}

func updatePackage(p pkg.Package, parentPkg *pkg.Package) {
func updateParentPackage(p pkg.Package, parentPkg *pkg.Package) {
// we've run across more information about our parent package, add this info to the parent package metadata
// the pom properties is typically a better source of information for name and version than the manifest
parentPkg.Name = p.Name
Expand All @@ -401,3 +408,17 @@ func updatePackage(p pkg.Package, parentPkg *pkg.Package) {
parentPkg.Metadata = parentMetadata
}
}

func addPURL(p *pkg.Package) {
purl := packageURL(*p)
if purl == "" {
return
}

metadata, ok := p.Metadata.(pkg.JavaMetadata)
if !ok {
return
}
metadata.PURL = purl
p.Metadata = metadata
}
4 changes: 4 additions & 0 deletions syft/pkg/cataloger/java/archive_parser_test.go
Expand Up @@ -134,6 +134,7 @@ func TestParseJar(t *testing.T) {
Version: "1.0-SNAPSHOT",
Extra: map[string]string{},
},
PURL: "pkg:maven/io.jenkins.plugins/example-jenkins-plugin@1.0-SNAPSHOT",
},
},
},
Expand All @@ -154,6 +155,7 @@ func TestParseJar(t *testing.T) {
"Manifest-Version": "1.0",
},
},
PURL: "pkg:maven/example-java-app-gradle/example-java-app-gradle@0.1.0",
},
},
},
Expand Down Expand Up @@ -191,6 +193,7 @@ func TestParseJar(t *testing.T) {
Version: "0.1.0",
Extra: map[string]string{},
},
PURL: "pkg:maven/org.anchore/example-java-app-maven@0.1.0",
},
},
"joda-time": {
Expand Down Expand Up @@ -219,6 +222,7 @@ func TestParseJar(t *testing.T) {
Description: "Date and time library to replace JDK date handling",
URL: "http://www.joda.org/joda-time/",
},
PURL: "pkg:maven/joda-time/joda-time@2.9.2",
},
},
},
Expand Down
25 changes: 25 additions & 0 deletions syft/pkg/cataloger/java/package_url.go
@@ -0,0 +1,25 @@
package java

import (
"github.com/anchore/packageurl-go"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/pkg/cataloger/common/cpe"
)

// PackageURL returns the PURL for the specific java package (see https://github.com/package-url/purl-spec)
func packageURL(p pkg.Package) string {
var groupID = p.Name
groupIDs := cpe.GroupIDsFromJavaPackage(p)
if len(groupIDs) > 0 {
groupID = groupIDs[0]
}

pURL := packageurl.NewPackageURL(
packageurl.TypeMaven, // TODO: should we filter down by package types here?
groupID,
p.Name,
p.Version,
nil, // TODO: there are probably several qualifiers that can be specified here
"")
return pURL.ToString()
}

0 comments on commit 6c2fe7d

Please sign in to comment.