Compare commits

...
Author SHA1 Message Date
Alex Goodman da0b17b719 Add cataloging of macho multi-architecture binaries (#657)
* add cataloging within universal binaries

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update json test fixtures

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add comments + correct 32 bit multi arch magic check

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-12-08 16:25:24 -05:00
Alex Goodman c7752f0f6c fix panic from reading nonexistent reader (#658)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-12-08 20:28:47 +00:00
Bala Raman 7a359dc16b Adding AlmaLinux OS Support (#652)
* Adding AlmaLinux Support

Signed-off-by: Bala Raman <srbala@gmail.com>

* Adding AlmaLinux Support

Signed-off-by: Bala Raman <srbala@gmail.com>
2021-12-07 15:59:31 -05:00
Dan Luhring 7957294b26 Add section for community meetings (#655)
Signed-off-by: Dan Luhring <dan+github@luhrings.com>
2021-12-06 12:18:34 -05:00
Jonas Galvão Xavier 5374a1dc6f add cyclone-json output format (#635)
* add cyclone json format

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* adapt format to sbom.SBOM structure

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* cycloneDX json output with official lib

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* add cycloneDX 1.3 schema output in xml

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* fix lints errors

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* tidying go mod

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* remove cycloneDX 1.2 format

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* update cycloneDX xml schema

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* fix cyclone according to schema

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* use RFC 2141 URN form of uuid for serial number

add schema validation for cycloneDX 1.3 JSON output

add yajsv cli for JSON schema validation during tests

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* tidying go mod up

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* go get json schema validator

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* install yajsv without mess with go mod

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* reuse code between cycloneDX json & xml encoders

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* add output options for cyclone XML

add bom.json to .gitignore

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* add cyclone json format

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* adapt format to sbom.SBOM structure

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* cycloneDX json output with official lib

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* add cycloneDX 1.3 schema output in xml

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* fix lints errors

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* tidying go mod

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* remove cycloneDX 1.2 format

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* update cycloneDX xml schema

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* fix cyclone according to schema

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* use RFC 2141 URN form of uuid for serial number

add schema validation for cycloneDX 1.3 JSON output

add yajsv cli for JSON schema validation during tests

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* tidying go mod up

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* go get json schema validator

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* install yajsv without mess with go mod

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* reuse code between cycloneDX json & xml encoders

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* add output options for cyclone XML

add bom.json to .gitignore

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* fix cyclone12xml removal

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* feedback changes

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* go mod tidy

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>
2021-12-03 17:06:23 -08:00
Alex Goodman 22c4b275e7 bump containerd and image-spec (#654)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-12-03 16:12:43 +00:00
Alex Goodman ffccfc8f3f update stereoscope to bump docker dependency (#648)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-12-02 11:18:00 -05:00
Alex Goodman 5aec918683 reduce relationship noise (#653)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-12-02 09:51:18 -05:00
Alex Goodman da62387545 Fix SPDX namespace value (#649)
* fix spdx namespace and add scheme range assertions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* validate SPDX document name from source metadata

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* comment why namespace tests only check prefix

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-12-02 14:10:40 +00:00
Alex Goodman 21d1738b27 fix directory content fetching (#651)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-12-02 09:02:54 -05:00
Dan Luhring ed84e43d67 Remove webinar announcement (#650)
Signed-off-by: Dan Luhring <dan+github@luhrings.com>
2021-12-01 19:07:10 +00:00
Alex Goodman fe616acd98 directory resolver should account for the proc cwd relative to the root path (#644)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-30 15:34:37 -05:00
Blaize KayeandAlex Goodman 6af132e088 Adds composer installed.json parser (#643)
* Adds installed.json functionality and tests

Signed-off-by: Blaize Kaye <blaize.kaye@amazee.com>

* Adds php-installed-cataloger

Signed-off-by: Blaize Kaye <blaize.kaye@amazee.com>

* Changes fallback logic

Signed-off-by: Blaize Kaye <blaize.kaye@amazee.com>

* Adds image tests for installed.json composer packages

Signed-off-by: Blaize Kaye <blaize.kaye@amazee.com>

* tweak PHP cataloger names

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* unexport PHP types and fix CLI tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename PHP cataloger file

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-30 11:36:08 -05:00
Alex Goodman 00206233e6 use smaller jotframe event buffer (#647)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-30 11:23:16 -05:00
Alex Goodman bd9007fc0e Migrate SPDX-JSON relationships to SBOM model (#634)
* remove power-user document shape

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add power-user specific fields to syft-json format

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* port remaining spdx-json relationships to sbom model

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add coordinate set

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add SBOM file path helper

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use internal mimetype helper in go binary cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add new package-of relationship

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update json schema to v2

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* replace power-user presenter with syft-json format

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix tests and linting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove "package-of" relationship (in favor of "contains")

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add tests for spdx22json format encoding enhancements

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update TODO and log entries

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* introduce sbom.Descriptor

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-23 14:54:17 -05:00
Alex Goodman e3b34813d7 ignore partybus unsubscribe errors (#641)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-22 16:07:55 -05:00
Dan Luhring f0b2d81599 Announce meetup on 2021-12-01 (#640)
Signed-off-by: Dan Luhring <dan+github@luhrings.com>
2021-11-22 10:13:18 -05:00
Christopher Angelo Phillips 0849539729 Update concurrency primitives for relationships in command layer (#639)
* update concurrency primitives for relationships in command layer

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-11-20 03:44:17 -05:00
Christopher Angelo Phillips 4f0099583a promote catalog task pattern to all commands (#636)
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-11-19 13:26:23 -05:00
Alex Goodman d76c868481 Catalog archive contents for single-file input (#637)
* add first-level archive processing when input is a file

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add license exception for github.com/xi2/xz

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* always return cleanup function

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* change source.NewFromFile log entry to warn

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* ensure file source always has cleanup function

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* ensure we are always preferring the unarchive cleanup function for source

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-19 14:16:25 +00:00
Alex GoodmanandDan Luhring e38cde35ed Introduce minimal source coordinates (#623)
* split source.Location and create source.Coordinates for minimal path addressing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* move coordinates into separate file

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* Update syft/source/coordinates.go

Co-authored-by: Dan Luhring <luhring@users.noreply.github.com>
2021-11-18 18:13:22 +00:00
Alex Goodman 9090c3a772 bump stereoscope, docker, and GGCR (#633)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-16 19:43:46 +00:00
Alex Goodman ef627d82ef Introduce relationships as first-class objects (#607)
* migrate pkg.ID and pkg.Relationship to artifact package

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* return relationships from tasks

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix more tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add artifact.Identifiable by Identity() method

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix linting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove catalog ID assignment

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* adjust spdx helpers to use copy of packages

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* stabilize package ID relative to encode-decode format cycles

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename Identity() to ID()

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use zero value for nils in ID generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* enable source.Location to be identifiable

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* hoist up package relationship discovery to analysis stage

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update ownership-by-file-overlap relationship description

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add test reminders to put new relationships under test

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* adjust PHP composer.lock parser function to return relationships

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-16 14:14:13 -05:00
Christopher Angelo Phillips 45ea4177e8 update SPDX license list => 3.15 (#630)
* update SPDX license list 

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-11-15 14:41:46 -05:00
Alex Goodman e28b7b53b0 bump chronicle to v0.3.0 (#627)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-13 18:56:25 -08:00
Christopher Angelo Phillips fc39710d06 287 - Add retry for image fetch using user's input (#626)
* add fallback to user input if source hint fails

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* refactor for smaller functions

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-11-12 17:57:04 -05:00
Swathi Gangisetty e732f419f8 Add new distro and mapping to support Rocky Linux distro identification (#624)
Signed-off-by: Swathi Gangisetty <swathi@anchore.com>
2021-11-12 13:10:21 -08:00
NikitaandAlex Goodman 25835ef589 PHP parser composer.lock (#609)
* PHP parse composer.lock

Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com>

* rename PHP package type

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add PHP composer package support to source info SPDX helper

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update directory cataloger integration tests (make exception for images)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-10 14:08:41 -05:00
Christopher Angelo Phillips 319c6ee2eb document current draft for iana submission (#618)
* document current draft for IANA submission

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-11-10 11:28:47 -05:00
Alex Goodman 9c27fa7b0b use sbom.SBOM in ImportConfig (#621)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-08 18:39:06 -05:00
Christopher Angelo PhillipsandAlex Goodman 9bbc9ff633 Add layer information for go-module-binary-cataloger (#620)
* update functions to pass Location

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* update unit tests to pass new locations

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* fix image source.FileResolvers to include layer info

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add non-empty location in golang binary cataloger testing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-08 16:05:53 -05:00
Alex GoodmanandChristopher Angelo Phillips bb0f35bac4 Introduce a single SBOM document (#606)
* [wip] single sbom doc

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix more tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix linting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update cli tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove scope in import path

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* swap SPDX tag-value formatter to single sbom document

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bust CLI cache

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update fixture to byte diff

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* byte for byte

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* bust the cache

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* who needs cache

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* add jar for testing

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* no more bit flips

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* update apk with the delta for image and directory cases

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* restore cache workflow

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

Co-authored-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-11-05 10:05:49 -04:00
Jonas Galvão Xavier 6d0ee326d8 ignore irregular files while indexing directory (#616)
* stop hidding  command from help doc

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* do not index irregular files

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* fix fixture dir and err name

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* improve the description of irregular files

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>

* explicitly check indexed file name

Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>
2021-11-04 11:24:05 -07:00
Alex Goodman 23a67dd729 document file scheme (#613)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-02 19:47:25 -04:00
Christopher Angelo Phillips 3e20edee55 update readme with private registry section (#610) 2021-11-02 15:00:56 -04:00
Alex Goodman 8ec3f1d102 Use anchore fork of go-presenter (#611)
* use anchore fork of go-presenter

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* drop coverage threshold

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-02 18:09:26 +00:00
Alex Goodman ecab44bba1 Add SPDX tag-value format object (#605)
* add new spdx tag-value format

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove public presenter package

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-02 13:45:34 -04:00
Alex GoodmanandChristopher Angelo Phillips 484284706c Use named pipe bit when checking for piped input (#603)
* use named pipe bit when checking for piped input

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-11-02 16:41:02 +00:00
Alex Goodman 3ac95ac4f6 Allow for cataloging a single file (#608)
* allow for cataloging a single file

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use all catalogers for file schemes

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-11-02 12:09:06 -04:00
Christopher Angelo Phillips a2882ee810 Update package identifier to be constant across multiple syft run (#595)
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-29 16:00:36 +00:00
Alex Goodman 358b3a2cf8 port text presenter to a format object (#604)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-29 11:31:15 -04:00
Alex Goodman 9aca23f766 Add SPDX JSON format object (#584)
* remove existing spdxjson presenter + helpers

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add new spdx22json format

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add common sdpxhelpers (migrated)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use new common spdx helpers

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* wire up new spdx22json format object

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove lossless syft-specific property bags

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove spdxjson decoder and validator

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add nil checks in spdx test helpers

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove empty default case

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use explicit golden snapshot

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-29 14:55:20 +00:00
Alex Goodman 4a2d1d7225 Port cyclonedx presenter to format object (#589)
* add new cyclonedx format object

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove cyclonedx presenter

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove cyclonedx presenter call

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove dependence on golden images for format tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* wire up new formt + rename all-presenters ref

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add CLI test to ensure that all formats can be expressed as report output

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add cyclonedx version and encoding format to package name

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* optionally preserve format snapshot images

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix linting + text unit tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-29 10:17:03 -04:00
Christopher Angelo Phillips 3286a4d4cc update docker manifest tagging (#600)
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-28 15:41:39 -04:00
Christopher Angelo Phillips 0ff7013382 update manifest to use Tag over Version
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-28 15:05:34 -04:00
Christopher Angelo Phillips 71708e5bf8 update goreleaser with correct tag information (#598)
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-28 13:37:22 -04:00
Jonas Galvão Xavier dd024298eb stop hidding command from help doc (#596)
Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>
2021-10-27 13:49:04 -07:00
Christopher Angelo Phillips 1c63943055 Add arm64 image support and Darwin M1 support to .goreleaser.yaml (#591)
* update support arm64

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* small update syntax

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* restore release command

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* add docker manifests

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-26 09:42:35 -04:00
Alex Goodman ff5fa2dc1d pull in space suffix fix (#587)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-25 10:14:17 -04:00
Alex Goodman fb588ff500 replace table presenter with format object (#586)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-24 08:09:27 -04:00
Alex Goodman d5b425e1b5 force exiting the etui upon worker error (#583)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-22 13:44:50 -04:00
Dan Luhring 7b319e32bb Remove webinar announcement (#582)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-10-22 07:48:36 -04:00
Alex Goodman 89242e6ed3 bump chronicle to v0.2.0-beta (#581)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-21 18:34:17 +00:00
Alex Goodman 4bf08e6b6d swap out the changelog generator for chronicle tool (#580)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-21 13:37:13 -04:00
Alex Goodman 87ce9fff06 swap go binary parsing warning logging entry (#579)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-21 17:03:07 +00:00
Christopher Angelo Phillips 10fa8dc7c9 Add windows support (#548)
* update  build tags, ui support, and stereoscope, and release for windows support

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-21 12:49:36 -04:00
Alex Goodman 560b05c2c9 Introduce new format pattern + port json processing (#550)
* add new format pattern

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add syftjson format

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add internal formats helper

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add SBOM encode/decode to lib API

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove json presenter + update presenter tests to use common utils

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove presenter format enum type + add formats shim in presenter helper

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add MustCPE helper for tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update usage of format enum

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add test fixtures for encode/decode tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix integration test

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* migrate format detection to use reader

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* address review comments

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-20 21:36:34 +00:00
Alex Goodman 5e315c0f17 Disable ETUI for piped input (#571)
* fixed piped input

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* allow pipedinput helper to raise an error

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* factor out verbosity check to function

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-20 12:40:52 -04:00
Alex Goodman 6f3fa494d7 Show help text when no args are given (#573)
* show help text when no args are given

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* repurpose the input args validation function

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* ensure app does not check for update in cli tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-20 09:51:05 -04:00
Alex GoodmanandChristopher Angelo Phillips a82463574b Rollback goreleaser version (#570)
* rollback goreleaser version

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update go sum

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

Co-authored-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-19 12:01:51 -04:00
Alex Goodman cbdb72ea22 remove unnecessary codeql checkout from second parent commit (#567)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-18 13:31:19 -04:00
Christopher Angelo Phillips 7a005fec06 update to point at new script for new release (#551)
* update to point at local script release

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-15 13:26:34 -04:00
Dan Luhring c0f55866ec Announce upcoming webinar (#553)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-10-15 12:13:28 -04:00
Christopher Angelo Phillips 9ea6330ebc update split in py package_cataloger to cap at 2 (#549)
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-14 12:32:06 -04:00
Christopher Angelo Phillips 7d13fbf0d4 540 add additional go package metadata (#546)
* update with distinct golang metadata types

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-13 11:00:28 -04:00
Dan Luhring 10368f6fe8 Add Syft logo (#545)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-10-11 21:06:27 +00:00
Josh Bressers f2840029d1 Allow Syft to build with podman (#537)
* Don't check the Built-By flag

Signed-off-by: Josh Bressers <josh@bress.net>

* Remove alpine pinning to resolve conflict with main

Signed-off-by: Josh Bressers <josh@bress.net>
2021-10-11 12:39:34 -04:00
Christopher Angelo Phillips b25f5b664b (464) - remove mod and cargo from image cataloger (#539)
* remove mod and cargo from image cataloger

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* update test error messages for clear failures

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-07 15:18:20 -04:00
Christopher Angelo PhillipsandAlex Goodman 3462e18af3 478 identify go binaries and extract mod information (#534)
* add query by MIME type to source.FileResolver

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* import stereoscope lib changes to find mime type

- add bin cataloger
- add bin parser
- add mime type go utils
- import new resolver

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* add go std library code to unpack bin

- keep them in their own (original) files
- add note for "this code was copied from"
- comment the lines the required changing

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-07 12:16:38 -04:00
Alex Goodman 05ac3f1eff split application configuration parsing to multiple methods (#532)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-06 09:48:53 -04:00
Alex Goodman a000a2926b update linter + fix whitespace (#536)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-06 13:46:55 +00:00
Alex Goodman 9189ed68df Add query by MIME type to source.FileResolver (#529)
* add query by MIME type to source.FileResolver

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* pull in stereoscope MIME type feature

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-05 20:50:53 -04:00
Alex Goodman ba1cd8d753 specify optional file.Digests instances to abbreviate json output (#531)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-05 15:35:28 -04:00
Alex Goodman dd2c178085 add --file option to readme (#533)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-05 15:34:32 -04:00
Alex Goodman 1b23a94015 Add option to output SBOM report to a file (#530)
* add output to file option

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* log errors on close of the report destination

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove file option from persistent args

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update file option comments and logging

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* allow for multiple UI fallback options

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update UI select signatures + tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-10-05 14:47:24 -04:00
Christopher Angelo Phillips f47a6a88b1 (#495) Update documentNamespace uniqueness for spdx-json output (#528)
* add unique namespace identifier

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-05 13:10:49 -04:00
Dan Luhring 4b7217f052 Improve documentation (#525)
* Make installation methods more obvious

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Create linkable section headers

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add badge for joining Slack

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Document requirement for signed commits

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-10-04 09:29:27 -04:00
Christopher Angelo Phillips 5e4b668e5a 497 stable sorted CPE array (JSON and SPDX) (#522)
* add small sorting change to our specificity

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-10-01 15:31:17 -04:00
Dan Luhring 6480f06173 Update description for Slack link (#523)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-09-30 21:43:43 +00:00
Christopher Angelo Phillips 75aed5f3ec (#460) Extend license mapping for common SPDX license names (#509)
Fixes #460 
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-09-30 16:54:36 -04:00
Jamie Magee 270fbb7665 Add mariner to distro types (#520)
Signed-off-by: Jamie Magee <jamie.magee@gmail.com>
2021-09-30 13:20:15 -04:00
Alex GoodmanandChristopher Angelo Phillips 0395c47445 Add vendor + product known good CPE field values (#517)
* add better infrastructure around CPE candidate additions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add test cases for CPE candidate additions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* small ergonomic updates

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* clean java OSGI directives from group ID

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* unquote CPE candidate field values (double quotes only)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add remaining CPE vendor & product additions (+ tests)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-09-27 18:31:59 -04:00
Keith Zantow e5caba043d Add SBOM to releases (#500)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2021-09-24 20:21:23 -04:00
Dan Luhring d1ac476986 Add announcement for KubeCon meetup (#515)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-09-24 11:42:06 -04:00
Dan Luhring dd23d49986 Prevent invalid CPE field values (#514)
* Fix CPE set comparison mismatch

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add failing test to assert CPE generation excludes URLs

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add removeByCondition method to fieldCandidateSet

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Prevent invalid CPE values for products and vendors

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Introduce removeWhere and rename filter to condition

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Refactor fieldCandidateSet and condition logic

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Move CPE parsing filter to end of CPE generation

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-09-24 09:23:58 -04:00
Alex Goodman 6d4d083acc Filter out CPE product candidates that are asterisks (#513)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-09-22 20:55:03 -04:00
Dan Luhring 316d4341c8 Use Anchore fork of packageurl lib without replace directive (#512)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-09-22 15:04:09 -04:00
Christopher Angelo Phillips 3e8afc5274 update log file permissions to 0644 (#511)
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-09-21 10:34:10 -04:00
Christopher Angelo Phillips 93d00dc340 Populate Files and Relationship fields for spdx-json output (#507)
* update spdx22 Document model to include relationships field

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* update document and relationship to match current JSON spec
https://github.com/spdx/spdx-spec/blob/development/v2.2.1/schemas/spdx-schema.json
https://github.com/spdx/spdx-spec/pull/528
https://github.com/spdx/spdx-spec/pull/528#issuecomment-904180177

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* update File struct based on SPDX schema

Required fields:
[ "SPDXID", "fileName", "copyrightText", "licenseConcluded" ]
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-09-17 09:06:12 -04:00
Alex Goodman 9fe1da8ee6 update go-rpmdb and restruct gomod references (#506)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-09-14 14:51:19 -04:00
Christopher Angelo Phillips 95df7dd035 Add command examples to release documentation (#503)
* update release document with commands run
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* small edits
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-09-14 09:08:37 -04:00
Alex Goodman ddfc8e20c0 Revert "disable docker releases (workaround) (#493)" (#501)
This reverts commit 06dcd3261d.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-09-13 13:06:23 -04:00
Christopher Angelo Phillips 3f305aa6cd (#342) - remove strong distro check (#496)
* add Type conversion to remove strong distro type limit
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* update signatures to be correct variable from os-release
Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
2021-09-09 13:05:22 -04:00
houdini91 2f99a35f51 Power user command support for directory scans (#467)
* Power-user directory source support
Signed-off-by: Mikey Strauss <mikey@scribe-security.com>

Signed-off-by: houdini91 <mdstrauss91@gmail.com>

* Remove newline

Signed-off-by: houdini91 <mdstrauss91@gmail.com>

* Shared filetree (#1)

* Shared directory resolver filetree

Signed-off-by: houdini91 <mdstrauss91@gmail.com>

* PR - change error ErrObserve to ErrPath

Signed-off-by: houdini91 <mdstrauss91@gmail.com>

* PR - share directory resolver
* Use pointer to source struct

Signed-off-by: houdini91 <mdstrauss91@gmail.com>

* Fix Lint

Signed-off-by: houdini91 <mdstrauss91@gmail.com>
2021-09-08 09:18:53 -04:00
Alex Goodman 06dcd3261d disable docker releases (workaround) (#493)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-09-03 21:29:34 +00:00
Alex Goodman abbba3fc19 Modify CPE vendor candidate generation approach (#484)
* consider additional vendor candidates for ruby, python, rpm, npm, and java

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add java pom.xml processing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* allow for downstream transform control in cpe generation processing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* migrate CPE generation logic to dedicated package

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* split java manifest groupID extraction into two tiers

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* extract groupID from pom parent project during CPE generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update java groupID processing tests to cover multi-tier approach

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix constructor names for cpe.fieldCandidate

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename helper function to startsWithTopLevelDomain

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add nil changes for java manifest sections

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update comment to reflect parsing maven files

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* split out java description parsing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* split out pom parent processing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* simplify vendorsFromGroupIDs and associated tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* simplify test type for vendorsFromGroupIDs

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* copy candidate varidations to new instances

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename CPE generation string util functions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add an explanation around fieldCandidate

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* simplify type for the cpe.fieldCandidateSet

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* make CPE filter function names more readable

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update groupIDsFromJavaManifest to use a guard clause

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* extract groupID extraction from artifactID fields into a separate function

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bump goreleaser version to combat failure

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-09-03 14:21:25 -04:00
Samuel Dacanay 0799fd9d46 Add support for older CentOS versions (6 & 5) by checking additional release files for information
Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>
2021-09-03 16:06:10 +01:00
Alex Goodman 5de1a0a236 Revert "Add announcement for upcoming OSS meetup (#490)" (#491)
This reverts commit 035ef03b0c.

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-09-02 10:59:51 -04:00
Dan Luhring 035ef03b0c Add announcement for upcoming OSS meetup (#490)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-08-25 14:35:32 -04:00
Toure Dunnon 9acabb8307 Merge pull request #489 from anchore/SLES_support_berkeleyDB
Updated the distro package to include SLES
2021-08-23 16:14:52 -04:00
Toure Dunnon 0f0fe59bf2 Updated the distro package to include SLES type to expand support, this change will not include the new sqlite3 rpmDB format
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2021-08-23 15:05:39 -04:00
Keith Zantow ff828fbac2 Skip package-lock.json and yarn.lock in node_modules #431 (#485)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2021-08-20 13:50:28 -04:00
cba5b5723b Added parser for Pipfile.lock to cataloger (#473)
* Added parser for Pipfile.lock to cataloger

Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com>

* make lint-fix

Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com>

* Update syft/pkg/cataloger/python/parse_pipfile_lock.go

Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com>

* fix _version

Signed-off-by: Nikita <33390074+Zilborg@users.noreply.github.com>

* swap method for trimming "==" prefix from pipfile pkg versions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2021-08-19 10:32:10 -04:00
Alex Goodman b0e9b92a25 Merge pull request #483 from anchore/fix-gomod-gosum-validation
Fix go module tidy checks for release pipeline
2021-08-18 11:00:49 -04:00
Alex Goodman d25d3b1fb3 fix go module tidy checks for release pipeline
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-08-18 10:13:56 -04:00
Keith Zantow 93b4bf9379 Add option to enable http registry connections (#482)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2021-08-17 12:52:51 -04:00
Keith Zantow 58f2be95fd chore: update packageurl-go and add encoding tests for #351 (#481)
Signed-off-by: Keith Zantow <kzantow@gmail.com>
2021-08-13 15:39:52 -04:00
Alex Goodman 6f038e9208 Merge pull request #447 from bureado/main
Minimal changes to use ID_LIKE
2021-08-12 14:20:13 -04:00
Alex Goodman 32a54b94be add unit tests for distro identification based on "like" field
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-08-12 14:09:22 -04:00
Alex Goodman 98d4749f86 Enhance CPE generation (#472)
* adjust CPE specificity sorting to include field length and bias certain fields

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove * vendor values from CPE generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* re-enable generating CPEs for jenkins and jira plugins

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* improve CPE generation logic based on java artifactID and groupID

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add ruby-lang as target software candidate for gems in CPE generation logic

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename filterCpes to filterCPEs

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* refactor CPE filters and groupID processing (for linting)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use ruby-lang as vendor candidate not target software

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* address PR comments for CPE generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-08-09 19:52:19 +00:00
Alex Goodman 3a5168917e Update SPDX license list from 3.13 to 3.14 (#474)
* update SPDX license list from 3.13 to 3.14

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove license list version from spdx snapshot unit tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-08-09 19:47:33 +00:00
Alex Goodman 58b21c03c3 Merge pull request #461 from anchore/update-slack
Update slack channels
2021-07-12 08:28:01 -04:00
Alex Goodman 2093d2a1dc update slack channels
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-07-12 08:04:04 -04:00
Alex Goodman dd56450f92 Revert "Add callout for OSS meetup (#446)" (#459)
This reverts commit 66e71c39e2.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2021-07-02 14:29:27 +00:00
Alex Goodman 6f2b52971d directory resolver indexer should report one progressable (#457)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-07-02 10:18:41 -04:00
Alex Goodman fee74d57b8 Update documentation to show SPDX support (#452)
* add docs for spdx support

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* copy updates for format options

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-07-01 14:52:57 +00:00
Alex Goodman fee35dd175 redirect cursor hide/show to stderr (#456)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-30 13:10:00 -04:00
Alex Goodman ecf4e5546a add help message when no arguments are provided (#455)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-30 12:53:12 -04:00
Alex Goodman 2de56c0749 force UI teardown when event is sourced from a signal interrupt (#453)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-29 18:16:32 -04:00
Alex Goodman fb0857ff93 Add support for indexing root filesystem (#442)
* change directory resolver to ignore system runtime paths + drive by index

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add event/etui support for filesystem indexing (for dir resolver)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add warnings for path indexing problems

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add directory resolver index tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* improve testing around directory resolver

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* renamed p var to path when not conflicting with import

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* pull docker image in CLI dir scan timeout test

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* ensure file not exist errors do not stop directory resolver indexing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-29 22:06:47 +00:00
Alex Goodman 962e82297c Split UI from event handling (#448)
* split UI from event handling

Signed-off-by: Alex Goodman <wagoodman@gmail.com>

* add event loop tests

Signed-off-by: Alex Goodman <wagoodman@gmail.com>

* use stereoscope cleanup function during signal handling

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* correct error wrapping in packages cmd

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* migrate ui event handlers to ui package

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* clarify command worker input var + remove dead comments

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-29 18:28:09 +00:00
Jose Miguel Parrella c833472b6e If distro name is unknown, try with the ID_LIKE
Signed-off-by: Jose Miguel Parrella <j@bureado.com>
2021-06-25 22:18:40 -07:00
Jose Miguel Parrella c825ae2404 Completing the test for distro version
Signed-off-by: Jose Miguel Parrella <j@bureado.com>
2021-06-25 22:18:40 -07:00
Alex Goodman 706322f826 Add SPDX support (#445)
* add initial spdx support

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* expose FileOwner and use in SPDX presenter

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add initial json support for SPDX

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add remaining package fields

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add spdx license list generation + tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* keep fileOwner unexported from pkg

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* restore cli test util

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add external refs to spdx tag-value format

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add golang support to CPE generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use tag-value format as default "spdx" format flavor

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add tests around spdx presenters + refactor presenter tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add bouncer exception for spdx tools-golang repo

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove spdx model questions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-25 16:30:41 -04:00
Dan Luhring 66e71c39e2 Add callout for OSS meetup (#446)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-06-24 11:44:20 -04:00
Alex Goodman 6dd698d89e Merge pull request #438 from anchore/enable-pull-request-events
Respond to pull_request events for internal PRs
2021-06-19 14:32:13 -04:00
Dan Luhring 50928ebd05 Add comments with examples for yarn.lock regexps (#439)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-06-17 09:24:05 -04:00
Alex Goodman 6e70d8af98 respond to pull_request events for internal PRs
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-16 12:48:50 -04:00
Dan Luhring 67b7d63875 Fix yarn.lock parsing (#437) 2021-06-15 09:57:54 -04:00
Samuel Dacanay 5a2e2eb679 Export the presenter interface so it may be used by external projects
Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>
2021-06-09 10:21:55 -07:00
Alex Goodman 801e662633 Merge pull request #428 from anchore/self-extracting-jar
Add support for processing files with prepended bytes before the zip archive
2021-06-04 12:50:22 -04:00
Alex Goodman 6a398f9771 update zip util tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-04 12:11:49 -04:00
Alex Goodman bf1bf057ab add and update zip util tests with ZipReadCloser coverage
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-04 12:11:49 -04:00
Alex Goodman 36b44b1d8e add zip-byte-offset support to zip utils
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-04 12:11:49 -04:00
Alex Goodman 8f85c8affc update springboot fixture to create jar with a prepended shell script
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-04 12:11:49 -04:00
Alex Goodman 776164a078 Merge pull request #427 from anchore/epoch-fix
Allow for RPM package epoch to be optionally provided in the version field
2021-06-04 09:52:54 -04:00
Alex Goodman 5ea1d78464 rename helper fn to toELVersion
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-04 09:38:15 -04:00
Alex Goodman afbd8f8ea0 remove variadic functionality from intRef() test helper
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-02 17:13:31 -04:00
Alex Goodman 2f81a2548c allow for RPM package epoch to be optionally provided in the version string
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-06-02 15:28:12 -04:00
Dan Luhring 2754c889eb Replace links to Slack channels with public signup link (#424)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-05-26 09:18:25 -04:00
Dan Luhring 8be0d988e7 Fix go mod tidy release problem (#422)
* Add go mod tidy check

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Run go mod tidy

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-05-25 17:13:58 -04:00
Dan Luhring 80e23bdb50 Add config option for import timeout (#421)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-05-25 15:01:02 -04:00
Dan Luhring 17bbf840cf Allow registry auth config without authority value (#420)
* Allow registry auth config without authority value

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Update CLI tests for new stereoscope log output

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-05-24 16:05:56 -04:00
Alex Goodman 2ca2f03501 Merge pull request #418 from anchore/add-all-pkg-metadata-types
Add all package metadata types slice for use in downstream testing
2021-05-24 11:15:56 -04:00
Alex Goodman 1201ad6df0 add all package metadata types slice for use in downstream testing
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-05-24 10:20:14 -04:00
Alex Goodman baa859d2ed Merge pull request #414 from anchore/fix-leaky-fds
Close all ReadClosers explicitly retrieved from resolvers
2021-05-12 17:28:52 -04:00
Alex Goodman a6c798f438 close all ReadClosers explicitly retrieved from resolvers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-05-12 17:21:30 -04:00
Alfredo Deza 360eb74cc7 Merge pull request #410 from anchore/readme-grype
update readme to point to grype
2021-05-06 15:09:09 -04:00
Alfredo Deza 92c20c885e update readme to point to grype
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2021-05-06 14:03:38 -04:00
Alfredo Deza 284b0c20b0 Merge pull request #389 from anchore/issue-381
Support msrc types
2021-04-29 14:59:04 -04:00
Alfredo Deza 4cce32f5c9 tests: remove KbPkg from defined pkgs since it isn't parsed
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2021-04-23 10:17:16 -04:00
Alfredo Deza 26007db650 manually add msrc as an observed distro
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2021-04-23 10:17:16 -04:00
Alfredo Deza 5af2687022 support msrc types
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2021-04-23 10:17:16 -04:00
Alex Goodman 032cecbe7f Merge pull request #406 from anchore/align-check-names-to-quality-gate
Align check names to release quality gate
2021-04-22 16:38:09 -04:00
Alex Goodman 5e1e2628cf align check names to release quality gate
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-22 16:20:21 -04:00
Alex Goodman 1632fdd85e Merge pull request #405 from anchore/add-jenkins-filter
Add for known bad CPE field combinations for jenkins package
2021-04-22 15:56:18 -04:00
Alex Goodman 18af21d2a5 add jenkins filter for known bad CPE field combinations
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-22 15:51:59 -04:00
Alex Goodman 1b62b10b2b Merge pull request #403 from anchore/pom-persist-not-for-shaded-jars
Update parent pom persistence with regard to shaded jars
2021-04-22 15:51:38 -04:00
Alex Goodman 170681943c remove type assertion check in packageIdentitiesMatch fn
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-22 14:00:31 -04:00
Alex Goodman 46043510ae update parent pom persistence with regard to shaded jars
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-22 14:00:31 -04:00
Alex Goodman c34060d188 Merge pull request #404 from anchore/add-more-jenkins-plugin-group-ids
Add additional cases for categorizing jenkins package type by group id
2021-04-22 13:33:17 -04:00
Alex Goodman 24a2f9344b add additional string.contains case for jenkins package by group id
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-22 13:20:12 -04:00
Alex Goodman d9de63c837 Enhance CPE generation for java GroupId and filtering (#402)
* enhance cpe generation for group id and filtering

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename group id const + add doc comment for HasAnyOfPrefixes

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-22 12:22:56 +00:00
Alex Goodman 0c29090b42 Add hyphen replacement logic for CPE generation (#397)
* add hyphen replacement logic for CPE generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* migrate "python-" vendor prefix to product candidate processing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bump linter timeout for CI

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update cpe candidate product tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-21 12:59:48 +00:00
Alex Goodman 6d2f139397 Merge pull request #401 from anchore/boostrap-gomod-tidy
Ensure consistent go.sum state during release
2021-04-21 08:54:55 -04:00
Alex Goodman 9c7906364d add go mod tidy to bootstrap make target
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-21 08:45:51 -04:00
Dan Luhring 7ae4504182 Merge pull request #399 from anchore/java-cpe-group-id-handling
Don't use pom groupId for Jenkins and Jira plugins
2021-04-21 08:06:33 -04:00
Dan Luhring 060e60b6dd Add more tests to CPE generation
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-04-20 20:42:40 -04:00
Dan Luhring 33e6be0b74 Identify Jenkins plugin upstream of CPE generation
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-04-20 19:36:34 -04:00
Dan Luhring fa7fd718cb Refactor Java archive parsing logic
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-04-20 19:34:59 -04:00
Dan Luhring 65e4e17590 Pin gradle builder container image
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-04-20 19:34:59 -04:00
Dan Luhring 091fd1f0b0 Improve CPE generation for Jenkins/Jira plugins
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-04-20 19:34:53 -04:00
Alex Goodman b301b56db1 add nomatch_inclusion engine mechanism in cpe generation logic (#394)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-20 19:57:04 +00:00
Alex Goodman 676bdf9816 refactor pom properties to modify parent pkg less often (#392)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-20 16:19:28 +00:00
Alex Goodman c06ee1ecc2 Merge pull request #388 from anchore/add-apk-extra-fields
Use the standard file.Digest for apk checksums
2021-04-19 16:46:41 -04:00
Alex Goodman 136e439dc2 use the standard file.Digest for apk checksums
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-19 16:42:17 -04:00
Alex Goodman ecb16b6a34 Merge pull request #387 from anchore/add-rpmdb-extra-fields
Expand RPM DB fields
2021-04-19 16:41:05 -04:00
Alex Goodman 6edbae08e5 update json schema with extra rpm fields
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-16 10:25:47 -04:00
Alex Goodman 0c7706f254 add extra RPM file record fields (user, group, flags)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-16 10:25:46 -04:00
Alex Goodman 11866ab69e Merge pull request #391 from anchore/cache-acceptance-mac-image
Change mac acceptance test image.tar path
2021-04-16 10:16:49 -04:00
Alex Goodman 0c100c4037 change mac acceptance test image.tar path
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-16 09:57:13 -04:00
Alex Goodman cca9d33b36 Merge pull request #390 from anchore/bump-go-mod-go-version
Bump go.mod minimum required go version to 1.16
2021-04-16 09:03:05 -04:00
Alex Goodman 8b315367e8 fix validations badge
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-16 08:59:07 -04:00
Alex Goodman b771d7bfd3 bump go.mod minimum required go version
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-16 08:53:03 -04:00
Alex Goodman 0c9eca4a30 Merge pull request #386 from anchore/add-safe-join
Safely join paths derived from archive headers
2021-04-15 08:59:39 -04:00
Alex Goodman 484730435b safely join paths derived from archive headers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-15 08:55:29 -04:00
Alex Goodman d5dfaaba53 Merge pull request #384 from anchore/add-registry-follow-up
Modify registry credential verification
2021-04-14 16:03:32 -04:00
Alex Goodman 9fb79bfa2e dont append registry auth if potentially empty
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-14 10:28:21 -04:00
Alex Goodman 2a5207ec88 Merge pull request #382 from anchore/add-manifest-to-registry-source
Add manifest + repo digests on registry source
2021-04-14 08:03:04 -04:00
Alex Goodman 2ff3f58730 pull in stereoscope manifest + repo digests on registry source
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-13 18:29:12 -04:00
Dan Luhring 8c178c497e Merge pull request #379 from anchore/fix-column-mismatch
Expose column index for UI handler consumers
2021-04-13 10:08:27 -04:00
Dan Luhring 4abffc8fbc Expose column index for UI handler consumers
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-04-13 09:32:38 -04:00
Alex Goodman c363b2b532 Add ability to pull images directly from a registry (#378)
* add registry image source

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use explicit source for fetching image + add scheme and registry tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* adjust test variable name and add credential helper function

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-13 13:30:57 +00:00
Alex Goodman c02ab88d5f Merge pull request #370 from anchore/add-file-contents-cataloger
Add file contents cataloger
2021-04-12 17:41:54 -04:00
Alex Goodman cd542bab5b ensure file content cataloger is using the proper scope
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:37:38 -04:00
Alex Goodman b5d4b2f7b2 simplify test assertions + rename file contents cataloger size limiter var
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:34:56 -04:00
Alex Goodman 51b13f8221 rename Contents to FileContents in app config and documentation
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:34:54 -04:00
Alex Goodman 44915b435f add documentation for the file contents cataloger config options
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:33:49 -04:00
Alex Goodman d451a5ad30 update the json schema and tests with file contents section
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:33:20 -04:00
Alex Goodman c1551a03c5 add file contents cataloger
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:30:57 -04:00
Alex Goodman 9ad786d608 Merge pull request #374 from anchore/add-binary-classifier
Add file classification cataloger
2021-04-12 17:25:16 -04:00
Alex Goodman 28c407572c simplify test assertions for classification cataloger
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:11:43 -04:00
Alex Goodman f9d49885ae simplify MatchNamedCaptureGroups implementation
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:11:43 -04:00
Alex Goodman f438ee974c add documentation for the file classifier cataloger config options
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:11:43 -04:00
Alex Goodman 309cbf5264 add missing file classification test fixtures + gitignore adjustment
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:11:43 -04:00
Alex Goodman 46fffe5c6f update json schema + presenter snapshots with file classification section
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:11:40 -04:00
Alex Goodman 080057b217 add file classifications to power-user json presenter
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:08:50 -04:00
Alex Goodman 870a676a5d wire up file classifier to power-user cmd
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:08:50 -04:00
Alex Goodman 46bfb68113 add file classifier + tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:08:50 -04:00
Alex Goodman 5743e32e02 add tests around MatchNamedCaptureGroups + rename
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-12 17:08:50 -04:00
Alex Goodman 66ebe49a04 Merge pull request #375 from anchore/package-verification-fields-dpkg
Update package verification fields for DPKG
2021-04-12 16:35:45 -04:00
Alex Goodman 0511972dfa clarify default collection value + fix appending conffiles location
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-09 11:41:44 -04:00
Alex Goodman c56690fc52 fix DpkgMetadata.Files test to ensure it is never nil
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-09 08:46:59 -04:00
Alex Goodman ba3407a767 add dpkg conffile update to json schema + json test snapshots
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-09 08:37:28 -04:00
Alex Goodman 269832ce8d add conffile listing to dpkg metadata + normalize digests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-08 14:21:23 -04:00
Alex Goodman 7a10cbae0c Merge pull request #368 from anchore/fix-registry-auth-encode-issue
Ensure credentials are not HTML encoded
2021-04-05 14:25:57 -04:00
Alex Goodman 7ec0e3785f bump stereoscope ; pull in fix to ensure credentials are not HTML encoded
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-05 14:20:49 -04:00
Alex Goodman 9ec09add67 Add secrets search capability (#367)
* add initial secrets cataloger

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update ETUI elements with new catalogers (file metadata, digests, and secrets)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update secrets cataloger to read full contents into memory for searching

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* quick prototype of parallelization secret regex search

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* quick prototype with single aggregated regex

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* quick prototype for secret search line-by-line

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* quick prototype hybrid secrets search

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add secrets cataloger with line strategy

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* adjust verbiage towards SearchResults instead of Secrets + add tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update json schema with secrets cataloger results

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* address PR comments

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update readme with secrets config options

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* ensure file catalogers call AllLocations once

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-04-01 21:34:15 +00:00
Alex Goodman 557ad8be49 Merge pull request #366 from zhill/issue-331
Use sorted artifacts for consistent SBoM output in table, cyclonedx, and json presenters
2021-04-01 11:04:34 -04:00
Zach Hill c332ba0867 Use cataloger Sorted() output instead of Enumerate() for stable result sorting in presenters. Fixes #331
Also adds artifact location to sort key for Sorted() to ensure
consistent sorts when artifacts of same name, version, and type are
found in different locations in the image. Location should be sufficient
since we assume only one package of a given name and version can exist
in one location, even if that location is an package-db like rpmdb.

Signed-off-by: Zach Hill <zach@anchore.com>
2021-04-01 01:40:41 -07:00
Alex Goodman 485caa1ea3 Merge pull request #357 from anchore/enhance-file-metadata
Add link destination to file metadata
2021-03-30 09:36:10 -04:00
Alex Goodman cd925e5664 account for repoDigests data in power-user json testing
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-30 08:46:42 -04:00
Alex Goodman db35186c7d allow file metadata digests to be optional + add link destination
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-29 12:07:42 -04:00
Alex Goodman 8551168702 capitalize file type strings
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-29 12:07:41 -04:00
Alex Goodman 772613647c Merge pull request #364 from anchore/allow-for-failures-of-benchmark-sticky-note
Ignore failures on benchmark sticky comment
2021-03-29 12:03:10 -04:00
Alex Goodman 8658abc8c4 ignore failures on benchmark sticky comment
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-29 11:59:49 -04:00
Robert Prince ab83b7f840 Merge pull request #350 from octarinesec/repo-digests
Add repo digests if available from Stereoscope to the image metadata
2021-03-29 08:47:50 -07:00
Alex Goodman 0f26681ac5 Merge pull request #356 from anchore/dedup-pkg-index
Ensure pkg.Catalog path index deduplicates real vs virtual paths
2021-03-28 14:06:25 -04:00
Alex Goodman 9abdb174d5 ensure pkg.Catalog path index deduplicates real vs virtual paths
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-26 13:27:24 -04:00
Alex Goodman 44cf7ccb44 Merge pull request #355 from anchore/move-docker-login-after-keychain-step
Move docker login to after keychain creation
2021-03-26 11:05:47 -04:00
Alex Goodman 2a9b1b2680 move docker login after keychain creation
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-26 10:41:44 -04:00
Alex Goodman cedf8cd6d7 Merge pull request #352 from anchore/enable-release-environment
Enable manual release approval
2021-03-25 12:13:41 -04:00
Alex Goodman cfec812804 enable release environment (manual approval for releases)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-25 12:01:20 -04:00
Alex Goodman 7b25237cea Merge pull request #354 from anchore/fix-benchmark-sticky-comment
Fix sticky benchmark comment on PRs
2021-03-25 12:00:32 -04:00
Alex Goodman ac4b653721 fix sticky benchmark comment on PRs
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-25 11:53:05 -04:00
Alex Goodman 8464d9766a Merge pull request #353 from anchore/fix-docker-login
Manually login to docker via cli during release
2021-03-25 11:49:10 -04:00
Haim Helman 13a066ea18 Add repo digests if available from Stereoscope to the image metadata
Signed-off-by: Haim Helman <hhelman@vmware.com>
2021-03-25 05:57:23 -07:00
Alex Goodman 51bf9f9e05 manually login to docker via cli during release
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 17:57:41 -04:00
Alex Goodman e256e86888 Merge pull request #339 from anchore/add-file-metadata-indexer-invert-control
Add file metadata cataloger
2021-03-23 17:02:10 -04:00
Alex Goodman 1b7c755536 add file-type mix as golden image
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 16:50:57 -04:00
Alex Goodman 8854d83934 cache mac acceptance image
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 15:03:25 -04:00
Alex Goodman 3ef30f99be pull in stereoscope cache fix + add test cache makefile target helpers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 14:31:59 -04:00
Alex Goodman 12f419111e remove docker layer cache from validation pipeline
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 13:04:13 -04:00
Alex Goodman 68c4bf8bbe update documentation to reflect root vs packages subcommand
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 13:00:25 -04:00
Alex Goodman 929b78efbf remove prealloc nolint rule in catalogers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 12:56:00 -04:00
Alex Goodman d420368ba9 add tests around new file metadata cataloger
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 11:00:59 -04:00
Alex Goodman 40199096e9 stabilize json file metadata presenter order
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 11:00:36 -04:00
Alex Goodman 0e9c1c1d86 arrange power-user tasks ahead of parsing the source image
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 10:29:38 -04:00
Alex Goodman 77e4c89a5a bump coverage threshold + use ubuntu for snapshot builds
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 10:28:57 -04:00
Alex Goodman e3b1522394 upgrade goreleaser + constrain pipeline tool cache
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-23 06:58:30 -04:00
Alex Goodman 46636ccb3c simplify command alias logic + remove deprecation warning for root command
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 15:25:04 -04:00
Alex Goodman 36e4af1953 adjust jsom schema version + adopt java pom properies test fixtures
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 11:27:01 -04:00
Alex Goodman abca2c5f0b remove token usage from benchmark sticky comment action
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:58:09 -04:00
Alex Goodman f180d1c537 improve config parsing + fix command deprecation warning
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:58:09 -04:00
Alex Goodman b1b57f6ba6 remove benchmark test event filter in validations pipeline
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:58:08 -04:00
Alex Goodman 4bde850f04 add file-metadata config options to docs
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:58:08 -04:00
Alex Goodman 1d87f07da1 update pipeline with new levels of testing
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:58:07 -04:00
Alex Goodman cf516add95 add cli testing
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:56:18 -04:00
Alex Goodman 68d698e9f2 remove inline-compare testing
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:56:18 -04:00
Alex Goodman efcd8a8b9a update integration and acceptance tests for new resolvers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:56:18 -04:00
Alex Goodman ae32942a18 update import to require patching image metadata source field
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:56:18 -04:00
Alex Goodman 18dd2950ac update event handlers relative to new command structure
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:56:18 -04:00
Alex Goodman 6a960ec1f3 update json schema with optional poweruser data shape
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:56:16 -04:00
Alex Goodman 97f0f83544 add poweruser command and alias root to packages subcommand
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:53:53 -04:00
Alex Goodman a6cba5d9db remove multi* content fetching from resolvers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:53:51 -04:00
Alex Goodman f22d7d23c1 add poweruser concerns to the application config
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:52:37 -04:00
Alex Goodman ff4ed40d50 migrate syft/presenter to internal/presenter
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:52:33 -04:00
Alex Goodman 4666ca8469 migrate syft/cataloger to syft/pkg/cataloger
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 10:46:51 -04:00
Alex Goodman cb5e7d0e08 Merge pull request #345 from westonsteimel/rust-cargo-cataloger
add cataloger for rust crates from Cargo.lock files
2021-03-22 09:51:57 -04:00
Alex Goodman 48a1d4711a update presenter tests with json schema 1.0.3 examples + rename rust metadata type
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-22 09:44:55 -04:00
Weston Steimel 35cc00b74a capture extra metadata about rust crates from the Cargo.lock file
Signed-off-by: Weston Steimel <weston.steimel@gmail.com>
2021-03-22 09:13:17 -04:00
Alex Goodman 26a4dd36a8 Merge pull request #348 from anchore/fix-java-pom-properties-parse-delimiter
Allow for multiple pom.properties delimiters
2021-03-20 12:23:57 -04:00
Alex Goodman e9e9fe6d9c prefer warnings over errors when parsing java manifests and pom properties
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-20 08:08:46 -04:00
Alex Goodman 2f8a568d4f check for multiple delimiters when parsing pom properties
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-20 08:00:08 -04:00
Alex Goodman c828e47765 Merge pull request #346 from anchore/fix-snapshot-build
Run snapshot build on ubuntu
2021-03-19 09:40:37 -04:00
Alex Goodman 83778677c1 run snapshot build on ubuntu
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-19 08:42:27 -04:00
Alex Goodman a5ae8e9668 Merge pull request #344 from anchore/add-docker-image
Add Docker image to release process
2021-03-18 16:45:22 -04:00
Alex Goodman 9f57e17887 add labels to the docker image + pin the docker pipeline install version
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-18 16:28:03 -04:00
Weston Steimel ba81bfe529 add cataloger for rust crates from Cargo.lock files
Signed-off-by: Weston Steimel <weston.steimel@gmail.com>
2021-03-18 03:12:51 +00:00
Alex Goodman a83d79f330 Merge pull request #341 from octarinesec/add_photon_to_list_of_distros
Added Photon OS to the list of distros
2021-03-16 07:29:18 -04:00
Haim Helman 87e1a0f501 Added Photon OS to the list of distros
Signed-off-by: Haim Helman <hhelman@vmware.com>
2021-03-11 19:06:17 -08:00
Alex Goodman e9105c180a add dockerfile + docker build step
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-11 16:45:20 -05:00
Alex Goodman c7b26c55ac add docker to mac instance
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-11 14:01:00 -05:00
Alex Goodman 0c2a51554a Merge pull request #343 from anchore/revert-310-add-docker-image-and-refactor-release-pipeline
Revert "Add docker image and refactor release pipeline"
2021-03-11 12:47:49 -05:00
Alex Goodman 5e62bca72f Revert "Add docker image and refactor release pipeline (#310)"
This reverts commit 6195002ae5.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2021-03-11 12:42:18 -05:00
Dan LuhringandAlex Goodman 6195002ae5 Add docker image and refactor release pipeline (#310)
* Create independent build targets for Mac and Linux

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Create targets for macOS signing and notarization

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Create target for Linux packaging

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Update release workflow and leverage new make targets

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add release assets to release draft

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add homebrew formula release follow-up and improve Makefile

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add follow-up workflow for updating version check file

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Get rid of fetch depth 0 for checkout action

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add follow-up workflow for Docker images

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Restore wait-for-checks job

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Replace make functions with shell functions

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Account for envsubst command in bootstrap-ci-linux

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* move homebrew generation into script

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add release approval step; remove goreleaser; add docker image smoke testing in acceptance step

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* replace homebrew formula template file with heredoc template

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update release documentation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2021-03-10 13:25:31 -05:00
Alex Goodman 8c4370b7cc Merge pull request #332 from westonsteimel/detect-distroless-packages
allow ability to catalog packages from /var/lib/dpkg/status.d/
2021-03-09 10:37:22 -05:00
Weston Steimel 6c80f9910f add to dpkg integration test cases to detect packages from /var/lib/dpkg/status.d/
Signed-off-by: Weston Steimel <weston.steimel@gmail.com>
2021-02-27 01:58:59 +00:00
Weston Steimel b963be219b allow ability to catalog packages from /var/lib/dpkg/status.d/
Some debian-based variants (such as Google's Distroless images)
don't write a single file to `/var/lib/dpkg/status`, but rather write
a file per package to `/var/lib/dpkg/status.d/`

related to #44

Signed-off-by: Weston Steimel <weston.steimel@gmail.com>
2021-02-27 01:20:44 +00:00
Alex Goodman 40e9c4b146 Merge pull request #334 from anchore/ignore-ownership
Ignore ownership for shared copyright resources
2021-02-26 15:59:49 -05:00
Alex Goodman 1aa8a10f6b ignore ownership for shared copyright resources
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-02-26 12:30:24 -05:00
Alex Goodman 6d5ff0fd8e Mark package relations by file ownership (#329)
* add marking package relations by file ownership

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* correct json schema version; ensure fileOwners dont return dups; pin test pkg versions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* extract package relationships into separate section

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* pull in client-go features for import of PackageRelationships

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* move unit test for ownership by files relationship further down

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rename relationship to "ownership-by-file-overlap"

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-02-25 13:47:13 -05:00
Alfredo Deza c5e3b631ac Merge pull request #328 from anchore/issue-327
Be lenient on invalid fields in PKG-INFO
2021-02-17 08:14:18 -05:00
Alfredo Deza 05b9d35ee6 python: log a warning when invalid fields in PKG-INFO are found
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2021-02-16 15:27:08 -05:00
Alfredo Deza 555376e250 python: test leniency with invalid fields in PKG-INFO
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2021-02-16 14:20:07 -05:00
Dan Luhring fee878028a Merge pull request #324 from anchore/etui-handle-signals
Add handling of interrupting signals to the UI
2021-02-12 09:21:16 -05:00
Dan Luhring 5370daf027 Add handling of interrupting signals to ETUI
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-02-11 22:29:43 -05:00
Alfredo Deza 8d838b18a8 Merge pull request #320 from anchore/pin-cache-action
Pin actions/cache to v2.1.3
2021-02-05 11:26:40 -05:00
Dan Luhring bf2d5ed87e Pin actions/cache to v2.1.3
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-02-05 11:15:53 -05:00
Alfredo Deza a350e5889b Merge pull request #319 from anchore/bust-ci-cache
make: add a bootstrap cache buster
2021-02-05 10:47:54 -05:00
Alfredo Deza e4393e7a3d make: add a bootstrap cache buster
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2021-02-05 10:17:09 -05:00
Dan Luhring 26d1975870 Merge pull request #318 from anchore/allow-path-prefixes
Allow path prefixes
2021-02-02 10:30:34 -05:00
Dan Luhring babb09b3a4 Refactor and improve base URL prep for client
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-02-02 09:54:00 -05:00
Dan Luhring b207bc8ee2 Ensure upload base path ends in /v1
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-02-01 16:59:23 -05:00
Dan Luhring 5b5fa7ec90 Add tests for Anchore client URL intake
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-02-01 13:57:40 -05:00
Dan Luhring 6d730d24dd Lean on built-in URL parsing to enable path prefix
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-02-01 13:48:25 -05:00
Dan Luhring b22fd987db Merge pull request #316 from anchore/fix-zero-layers-panic
Bring in fix from stereoscope for zero-layers panic
2021-02-01 12:03:28 -05:00
Dan Luhring 3b4d4b186f Bring in fix to zero layers panic from stereoscope
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-02-01 11:54:30 -05:00
Dan Luhring 407769e88c Merge pull request #314 from anchore/issue-291-java-parent-ref
Ensure java parent pkg ref isn't nil when looking for parent matches
2021-01-27 11:51:40 -05:00
Dan Luhring 1416e3cb7a Invert if statement to reduce nesting in archive parser
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-27 10:34:52 -05:00
Dan Luhring 0ccfee03f1 Fix dependency resolution issue in test image
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-27 10:30:49 -05:00
Alex Goodman bb1facbf81 ensure java parent pkg ref isnt nil when looking for parent matches
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-27 10:12:41 -05:00
Dan Luhring ae7cd6bbb7 Add test for Java cataloging with no main package
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-27 10:12:41 -05:00
Dan Luhring 7bcdafe745 Merge pull request #312 from anchore/omit-empty-packages
Omit empty packages
2021-01-22 16:10:06 -05:00
Dan Luhring 4576c081b9 Improve output for test case
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-22 15:20:42 -05:00
Dan Luhring d5779a9822 Clarify debug message for package.json omissions
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-22 15:20:24 -05:00
Dan Luhring 9ec3ad58c8 Update regression test expected value and pin deps
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-22 14:03:50 -05:00
Dan Luhring 176dfdd9c1 Don't create packages unless package.json has name and version
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-22 13:56:54 -05:00
Alex Goodman 0f6288881b Merge pull request #308 from anchore/prefer-real-paths-on-glob-results
Prefer real paths over those with links for glob results
2021-01-05 21:32:24 -05:00
Alex Goodman 6a49717314 add VirtualPath to source.Location
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-05 21:16:42 -05:00
Alex Goodman 06641cfda2 prefer real paths for glob results
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-05 18:48:28 -05:00
Alex Goodman a5537943fa keep original dpkg md5sum location
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-05 14:30:05 -05:00
Alex Goodman 0030880e74 Merge pull request #307 from anchore/dup-readers-on-bulk-fetch
Duplicate reference readers for duplicate location resolutions
2021-01-05 14:12:42 -05:00
Alex Goodman fc8b431ea6 duplicate reference readers for duplicate location resolutions
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-05 13:54:39 -05:00
Alex Goodman bb70b0b43e Merge pull request #305 from anchore/add-has-path-to-resolver
Add HasPath() to Resolver interface for existence check
2021-01-04 19:45:03 -05:00
Alex Goodman ee0a02621a Merge pull request #306 from anchore/update-gemspec-glob
Update gemspec glob to include named nested specification directories
2021-01-04 19:42:26 -05:00
Alex Goodman 33c27c4f3d add HasPath() to Resolver interface
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-04 19:39:49 -05:00
Alex Goodman 133d180eec update gemspec glob to include named spec dirs
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-04 19:33:52 -05:00
Alex Goodman 37b96a241b ensure acceptance tests use existing snapshot dir
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-04 16:50:35 -05:00
Alex Goodman 7f4e8ab97d Fix symlink resolutions for constituent paths (#304)
* bump stereoscope to pull in content API refactors

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* incorporate symlink fixes

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* with filetree.File() adjustments

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* regress all-layers scope to not include dead-links + default tests to squashed scope

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* restore all layers resolver glob behavior (custom + lazy link resolution)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* incorporate filetree link resolution options and restore no-follow dead link option for resolvers

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* removed path from lower-level FileTree.File() calls

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bump stereoscope to pull in latest link resolution fixes

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bump doublestar to v2 for directory resolver

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-04 16:41:45 -05:00
Dan Luhring 76446abd7d Merge pull request #299 from anchore/with-content-api-refactor
Bump stereoscope to pull in content API refactors
2021-01-04 14:41:00 -05:00
Dan Luhring c2799b35d8 Fix mock resolver interface implementation
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2021-01-04 14:18:51 -05:00
Alex Goodman d475e6280a bump stereoscope to pull in content API refactors
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2021-01-04 14:07:14 -05:00
Dan Luhring e299a5355f Merge pull request #303 from anchore/fix-site-packages-dir
Handle site packages based on which egg file is parsed
2020-12-23 13:23:01 -05:00
Dan Luhring 359212e8ee Disable lint rule prealloc
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-23 11:35:49 -05:00
Dan Luhring 52e719dcb8 Create MockResolver and use to improve python cataloger tests
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-23 11:24:49 -05:00
Dan Luhring 13c289eb7e Add tests for determining site packages root
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-23 08:22:31 -05:00
Dan Luhring c1fa701602 Apply lint fix
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-22 17:46:33 -05:00
Dan Luhring 183b8f79d0 Handle site packages based on which egg file is parsed
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-22 17:41:27 -05:00
Alex Goodman 558781eed6 Merge pull request #302 from anchore/add-manual-cache-buster
add manual cache buster to the pipeline
2020-12-22 16:32:59 -05:00
Alex Goodman 60f525af18 add manual cache buster to the pipeline
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-22 16:22:42 -05:00
Alfredo Deza 8dbb095fc6 Merge pull request #301 from anchore/issue-300
catalogers: Python runtime is not a Python package itself, ignore it
2020-12-22 15:18:56 -05:00
Alfredo Deza d0d7e849c9 catalogers: Python runtime is not a Python package itself, ignore it
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-12-22 10:59:43 -05:00
Alex Goodman 6aaf9ee712 Incorporate import changes + add image overwrite option (#294)
* incorporate import changes + add image overwrite option

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update import tests to account for arbitrary json shape

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-18 16:59:30 -05:00
Alex Goodman 75d89293ce fix acceptance tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-18 14:32:29 -05:00
7962002f81 Split dpk source into name and version (#297)
* Split dpk source into name and version

Signed-off-by: Zach Hill <zach@anchore.com>

* update dpkg status source name parsing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Dan Luhring <luhring@users.noreply.github.com>
Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-18 14:08:19 -05:00
Alex GoodmanandDan Luhring ea162f87f4 update dpkg license to include single-word entries (#298)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Dan Luhring <luhring@users.noreply.github.com>
2020-12-18 12:54:09 -05:00
Zach HillandDan Luhring 9adb57bcb5 Adds globs for .egg-info file for python detection as well as tests (#296)
* Adds globs for .egg-info file for python detection as well as tests

Signed-off-by: Zach Hill <zach@anchore.com>

* Fix lint error

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

Co-authored-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-18 12:36:25 -05:00
Alex Goodman 0891faa756 Merge pull request #293 from anchore/revert-288-syft_docker_image
Revert "Add the ability to run syft from a scratch image."
2020-12-16 16:55:26 -05:00
Alex Goodman a56292e2e0 Revert "Add the ability to run syft from a scratch image."
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2020-12-16 16:54:34 -05:00
Toure Dunnon 688aa2e832 Merge pull request #288 from anchore/syft_docker_image
Add the ability to run syft from a scratch image.
2020-12-16 10:39:30 -05:00
Toure Dunnon 2c90ec84b9 Merge branch 'main' into syft_docker_image 2020-12-15 19:52:55 -05:00
Alex Goodman d1d7471f2f Merge pull request #290 from anchore/improve-python-cataloger
Improve performance of the python cataloger
2020-12-15 12:41:58 -05:00
Toure Dunnon a19496b846 added: Docker login github action to publish new images
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-12-15 11:07:14 -05:00
Alex Goodman d94d7a7d80 add tests for content requester object
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-15 10:59:15 -05:00
Alex Goodman 45fed7c69b break out packageEntry into a separate file
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-15 10:59:14 -05:00
Alex Goodman e4a3e433b6 add content requested and refactor python cataloger to use it
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-15 10:59:14 -05:00
Alex Goodman 82c8a8e17b add mem profile option and refactor python cataloger for batch requests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-15 10:59:14 -05:00
Alex Goodman be5917a058 add profiler dev option
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-15 10:59:13 -05:00
Toure Dunnon 9365625fc3 added: corrected request from review.
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-12-15 09:27:09 -05:00
Toure Dunnon c626cb1c60 added: update to README.md to indicate on how to use the new feature.
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-12-14 08:10:46 -05:00
Toure Dunnon 07f2c2f702 Add the ability to run syft from a scratch image.
This change will allow endusers or CI to run syft from a
minimum image which will simplify CI deployment.

Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-12-14 08:10:46 -05:00
Dan Luhring 737a81c38c Sort generated CPEs by specificity (#289)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-11 12:08:39 -05:00
Alex Goodman 52bac6e2fd Add enterprise upload capability (#285)
* add support to upload results to enterprise

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add package sbom upload

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add dockerfile support

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add manifest, index, and dockerfile import functions

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* schema version to json output + enhance json schema generation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* modify package SBOM shape to be entire syft document + add etui updates

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add import image config and manifest support

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add config options for import to enterprise

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* incorporate final stereoscope and client-go deps

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-09 22:20:53 -05:00
Toure Dunnon 2d0c127419 Merge pull request #282 from anchore/issue_270
Corrected syft cyclonedx generated bom to adhere to the specifications found in CycloneDX 1.2
2020-12-04 13:48:55 -05:00
Toure Dunnon 1a124bd77b added: regenerated new test fixtures to reflect change in specification.
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-12-04 11:48:20 -05:00
Toure Dunnon a5fd83b21d added: correct the bom descriptor to meet the cyclonedx 1.2
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-12-04 11:48:20 -05:00
Alex Goodman f87c59b4eb Merge pull request #286 from anchore/rm-tree-catalog-sync-check
Bump stereoscope to remove tree-catalog syft check
2020-12-03 16:32:24 -05:00
Alex Goodman 3ce7eabc98 bump stereoscope to remove tree-catalog syft check
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-03 16:20:17 -05:00
Alex Goodman 6f9ded60ed Merge pull request #279 from anchore/enhance-java-cpe-by-group-id
Include CPEs with elements from POM GroupId fields
2020-12-02 07:50:31 -05:00
Dan Luhring 65cbacd135 Clarify python wheel parsing process (#281)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-12-01 16:30:30 -05:00
Alex Goodman 2989d3d975 include CPEs with elementds from POM GroupId fields
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-12-01 08:00:49 -05:00
Dan Luhring ae71b8832d Update stereoscope version to fix opaque directory merge issue (#278)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-30 11:37:44 -05:00
Alex Goodman c42b036f46 Merge pull request #276 from anchore/generate-json-schema
Generate json schema from struct definitions
2020-11-23 11:22:33 -05:00
Alex Goodman 8a17bfb69f generate json schema from struct definitions
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-20 15:47:10 -05:00
Alex Goodman 0ed30138c4 Merge pull request #271 from anchore/cpe-generation
Move package PURL and CPEs to Package definition
2020-11-19 12:38:20 -05:00
Alex Goodman 3aaa0e5566 move package purl and cpes (identities) to pkg.Package
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-19 11:25:51 -05:00
Alex Goodman 71939557e6 Merge pull request #266 from anchore/document-import
Add JSON document import
2020-11-17 13:21:57 -05:00
Alex Goodman 030427bb33 rename json artifact to package + update resolver integrity checks
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:13 -05:00
Alex Goodman 569a598df7 minimize pointer usage & order return types consistently
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:13 -05:00
Dan Luhring 0ad8c53ec2 Fix cyclonedx test fixture usage of dynamic digest value
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-17 12:37:13 -05:00
Alex Goodman c892c3609e improve doc comments
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:13 -05:00
Alex Goodman 62b03f3a91 dont export structs used for unmarshaling
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:12 -05:00
Alex Goodman 4b45c42f5a make cyclonedx presenter generally reusable (for grype)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:12 -05:00
Alex Goodman f46de19c6b migrate scope option to image metadata (from source)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:12 -05:00
Alex Goodman 91baabe5a1 add image metadata as catalogFromJSON return
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:12 -05:00
Alex Goodman 6f7a4fd3e4 move source metadata upstream and fix tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:12 -05:00
Alex Goodman aa0d444fd4 fix tests to use location instead of file.Reference
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:12 -05:00
Alex Goodman b694dacb21 add source.Location + reorient Resolvers to use it
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:11 -05:00
Alex Goodman 9668341a14 rename scope to source
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:37:11 -05:00
Alex Goodman 495fb0a45f add sbom document import lib helper function
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-17 12:36:51 -05:00
Dan Luhring a640a2c4cd Merge pull request #267 from anchore/improve-java-version-recognition
Improve Java version recognition
2020-11-17 10:59:54 -05:00
Dan Luhring 3e8bca6911 Rework Java archive name and version detection and clean up tests
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-17 08:35:10 -05:00
Dan Luhring 5afdd574a8 Update existing archive test cases to correct names and versions
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-17 08:35:10 -05:00
Dan Luhring 0ebe791acd Add archive filename test case for failing example from #255
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-17 08:35:10 -05:00
Dan Luhring a5b72405dd Merge pull request #265 from anchore/package-json-license-objects
Improve package.json license parsing
2020-11-14 13:06:24 -05:00
Dan Luhring 4861f69d7c Fix spelling in logger setup
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 11:35:55 -05:00
Dan Luhring 6bde075cd3 Remove unused argument value
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 11:20:06 -05:00
Dan Luhring f7be73dbcc Fix package.json parsing for no licenses
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 11:12:13 -05:00
Dan Luhring fc99538d78 Fix package.json parsing for multiple licenses objects
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 11:12:13 -05:00
Dan Luhring 4d4e242251 Fix package.json parsing for license object
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 11:12:12 -05:00
Dan Luhring 416afa015e Add test for package.json with no licenses
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 11:11:46 -05:00
Dan Luhring bd4c784a64 Add test for package.json multiple license objects
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 11:01:59 -05:00
Dan Luhring 624a090631 Add test for package.json license object
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-14 09:50:17 -05:00
Alex Goodman dad1d9691c Merge pull request #263 from anchore/add-source-to-rpmdb-cataloger
Add source to packages found by RPMdb cataloger
2020-11-12 09:36:20 -05:00
Alex Goodman 7964c27bd8 add source to packages found by rpmdb cataloger
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-12 09:27:08 -05:00
Alex Goodman 9581a0309b Merge pull request #262 from anchore/fix-release
Fix release process
2020-11-11 15:15:12 -05:00
Alex Goodman 7e270bf76c restore the checksum file during release
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-11 15:11:51 -05:00
Alex Goodman fde37b4b56 provide goreleaser asset version via env var
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-11 14:36:24 -05:00
Dan Luhring 8627ea88ce Fix usage of goreleaser's artifact pipeline
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-11 14:29:55 -05:00
Alex Goodman 2c82c7c0f0 Merge pull request #257 from anchore/enhance-deb-support
Enhance dpkg support
2020-11-11 13:12:29 -05:00
Dan Luhring 4c38ea595d Merge pull request #261 from anchore/fix-brew
Add signed and notarized ZIP release asset
2020-11-11 13:09:45 -05:00
Dan Luhring 6fe5ad0739 Avoid Finder window flash during install
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-11 12:38:11 -05:00
Dan Luhring 7bced775c4 Add zip to gon outputs
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-11 12:30:29 -05:00
Alex Goodman db98fba3b4 Merge pull request #260 from anchore/add-warning-levels
Add warning log level
2020-11-11 11:13:51 -05:00
Alfredo Deza 29d464c38a Merge pull request #258 from anchore/distro-like
Report the ID_LIKE value in the JSON presenter
2020-11-11 11:11:13 -05:00
Alex Goodman 2a329002b8 enhance dpkg support by parsing md5sum and copyright file sources
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-11 11:06:34 -05:00
Alex Goodman a6365886ad add warning log level
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-10 15:09:41 -05:00
Alfredo Deza 6ae3b47959 tests: update all tests to pass the IDLike value
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-11-10 12:40:50 -05:00
Alfredo Deza 10b55311df presenter: provide ID_LIKE information in json
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-11-10 12:40:17 -05:00
Alfredo Deza 64d5554144 include ID_LIKE in distro detection
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-11-10 12:37:35 -05:00
Alfredo Deza b3098f3423 Merge pull request #250 from anchore/issue-169
Add distro information to JSON presenter
2020-11-09 14:18:48 -05:00
Alfredo Deza c2cf4eb7b0 update tests for the new distro information
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-11-09 12:16:00 -05:00
Alfredo Deza 1e79986188 json: update the document to include distro information
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-11-09 12:16:00 -05:00
Dan Luhring 3699a917fd Merge pull request #254 from anchore/updates-to-mac-releases
Updates for macOS release process
2020-11-06 13:49:54 -05:00
Dan Luhring 501870f89f Update README for secure macOS releases
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-06 13:40:31 -05:00
Dan Luhring c878cc361c Update install.sh to handle new macOS releases
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-06 13:39:26 -05:00
Dan Luhring 8fb5b17dbd Use .Version in place of .Tag for release asset name
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-06 13:36:02 -05:00
Alex Goodman b6eb589b78 Merge pull request #251 from anchore/add-rpm-file-info
Add RPM file info sourced from the RPM DB
2020-11-06 11:06:34 -05:00
Alex Goodman 6aba2f48d4 split out rpmdb file processing to helper + lint fixes
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-06 10:44:27 -05:00
Alex Goodman 0205e72be9 ensure resolvers ignore directories for "FilesBy*" methods
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-06 07:21:38 -05:00
Alex Goodman 8095cd9980 add rpmdb file info to cataloger
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-06 07:21:23 -05:00
Dan Luhring ecfc471ce5 Resolve security warning for macOS users (#249)
* Add support for macOS signing and notarization

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Use Docker to run the changelog generator locally

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-11-04 15:47:55 -05:00
Alex Goodman a52750bdd3 enhance alpine file discovery (#248)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-11-04 09:56:52 -05:00
Alex Goodman 773581704c bump threshold for inline compare for jenkins image
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-30 15:14:32 -04:00
Alex Goodman 6e98752c6b Merge pull request #247 from anchore/syft-java-cataloger-integration
General Java cataloger enhancements
2020-10-30 13:55:16 -04:00
Alex Goodman e2593cd6b7 remove extra fields from the compare script metadata namedtuple
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-30 10:59:53 -04:00
Alex Goodman 232cd13035 update tests for enhanced java pkg pairings
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-30 10:44:45 -04:00
Alex Goodman 2532928afa bump java compare testing thresholds
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-30 10:06:47 -04:00
Alex Goodman 03dbfb8dfb improve java name and version extraction as well as parent pkg pairing
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-30 08:12:25 -04:00
Alex Goodman a5cba13ddf enable more flexible java manifest structure (closer to the spec)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-29 16:26:04 -04:00
Alex Goodman a4f22e65fc expand compare testing images
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-29 13:52:51 -04:00
Alex Goodman ab45be98b8 append java nested package names to the virtual path
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-29 13:52:34 -04:00
Alex Goodman fc991bc62e partial java comparison with extra metadata
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-29 12:40:49 -04:00
Alex Goodman 1230650771 allow for java manifest data to be optional
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-29 11:28:27 -04:00
Alex Goodman 452426d1d6 Merge pull request #245 from anchore/update-java-cataloger-for-engine
Java cataloger miscellaneous fixes
2020-10-28 17:36:44 -04:00
Alex Goodman 2675891110 remove parent java package from json && add java manifest section parsing
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-28 17:19:06 -04:00
Dan Luhring bffc4713a7 Update zip archive handling to match globs as expected (#244)
* Refactor zip file tests

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Add glob support for leading slashes

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Update zip testing to account for glob matching

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Ignore .DS_STORE

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Improve normalization of zip entry names

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Rename zip test helpers file

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-10-28 16:50:40 -04:00
Alex Goodman 62f6146c37 do not include optional fields
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-28 15:58:54 -04:00
Alex Goodman 8bcba7d830 update json schema and test for java virtualPath
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-28 15:25:30 -04:00
Alex Goodman 76c8f24090 add java virtual path
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-28 13:53:44 -04:00
Alex Goodman cc466e47da bump python version for acceptance tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-27 14:53:52 -04:00
Alex Goodman f9407d0ce4 Add java/npm to inline comparison (#235)
* Adds java and npm package comparison
* Adds probable matching of extra packages syft found and missing packages that syft did not find (but inline did). This way there is a section of output that fuzzy-matches the package names to get a better sense of "real" problems (actual missing packages) vs slightly mismatched metadata during troubleshooting.
* Adds a set or probable missing packages to the report based on the probable matches (again, to aid in troubleshooting)
* Fixes image reference clean function to support references with registries
* Only shows metadata differences when the package was found by both inline and syft
* Splits the inline-compare code into more manageable pieces

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-27 13:43:36 -04:00
Dan Luhring f19cb03aa0 Update doublestar to include fix for open dirs issue (#240)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-10-26 11:19:25 -04:00
Toure Dunnon 076454d7a8 Merge pull request #233 from anchore/javascript_parser_fix_author
Javascript parser fix author
2020-10-26 09:30:11 -04:00
Toure Dunnon 7c42a7441c Merge branch 'javascript_parser_fix_author' of https://github.com/anchore/syft into javascript_parser_fix_author 2020-10-23 16:49:51 -04:00
Toure Dunnon cbb7e00a52 Cleaned up go.mod import.
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-10-23 16:44:07 -04:00
Alex Goodman 6eb36bc3c8 allow for optional fields in npm metadata
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-23 15:00:55 -04:00
Toure Dunnon 94ffc2caa8 Merge branch 'main' into javascript_parser_fix_author
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-10-23 12:05:30 -04:00
Alex Goodman 15e2e32103 Merge pull request #237 from anchore/update-future-plans
Remove CycloneDX from future plans
2020-10-23 11:06:51 -04:00
Alex Goodman 1cdf2b9151 remove cyclonedx from future plans (already implemented)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-23 11:05:28 -04:00
Alex Goodman fd65f363ce Merge pull request #236 from anchore/fix-acceptance-test-pipeline
Bootstrap cached dependencies and CI dependencies separately for acceptance tests
2020-10-23 10:55:24 -04:00
Alex Goodman 103f0617f5 bootstrap cached deps and ci deps separately for acceptance tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-23 10:42:57 -04:00
Alex Goodman de2e6a13b8 Merge pull request #234 from anchore/split-python-cataloger-with-cataloger-addition
Split python cataloger by image/directory scanning + add more metadata
2020-10-23 10:37:01 -04:00
Alex Goodman 7d55bca0a0 allow for python metadata fields to be optional
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-23 10:29:52 -04:00
Toure 48c7dee9da included additional support for older npm spec.
Signed-off-by: Toure <tdunnon@gmail.com>
2020-10-23 08:50:38 -04:00
Toure 94e448a818 Merge commit '15379d1' into javascript_parser_fix_author
Signed-off-by: Toure <tdunnon@gmail.com>
2020-10-22 14:08:33 -04:00
Toure Dunnon 15379d1075 Fix for errors+failures parsing package.json
closes: #230

Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-10-22 13:58:18 -04:00
Alex Goodman 2e5ff4a995 add top_level.txt processing to python package cataloger
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-22 12:39:03 -04:00
Alex Goodman 1414d1fbc3 add test coverage for python pacakge cataloger and update catalog interface
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-22 09:51:29 -04:00
Alex Goodman 7fc926d40d add python author and emil fields + add metadata type
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-22 09:51:29 -04:00
Toure Dunnon 5b08616e47 Fix for errors+failures parsing package.json
closes: #230

Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-10-21 14:11:35 -04:00
Alex Goodman 0ce8701e73 split python package catalogers by image vs directory
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-21 11:48:26 -04:00
Alex Goodman beb6afff36 Merge pull request #232 from anchore/cataloger-interface-upgrade
Upgrade cataloger interface to use full resolver
2020-10-21 11:47:52 -04:00
Alex Goodman d4ca0ab167 expand the resolver to include content requests for a single reference
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-21 11:40:14 -04:00
Alex Goodman 6cd9c2b771 upgrade cataloger interface to use full resolver (remove SelectFiles function)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-21 10:49:33 -04:00
Alex Goodman 931c796158 add dynamic package.json parsing of author field
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-20 15:23:04 -04:00
Alex Goodman bb14f3b45b reduce number of open files while processing nested java archives (#227)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-16 17:22:14 -04:00
Toure Dunnon c0b9d7854b Merge pull request #224 from anchore/add_package_json
Add support for package.json #200
2020-10-16 11:43:27 -04:00
Toure Dunnon 27c62e34f2 Add support for package.json #200
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-10-16 11:28:54 -04:00
Alex Goodman 4c751cb1d4 Merge pull request #222 from VinodAnandan/main
Enable CodeQL Security Scan
2020-10-15 23:11:01 -04:00
Vinod Anandan 0f92f16eb6 Enable CodeQL Security Scan
https://github.blog/2020-09-30-code-scanning-is-now-available/

remove java from codeql scan

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
Signed-off-by: Vinod Anandan <vinod.anandan@jpmorgan.com>
2020-10-16 03:02:09 +01:00
Alex Goodman 1bf1e643eb restore original release token
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-15 14:41:28 -04:00
Alex Goodman 3ba67a6bcc update json schema to account for optional gemspec fields (#225)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-15 13:56:59 -04:00
Alex Goodman 4a8ee15e87 fix syft version verbiage
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-15 11:50:23 -04:00
Alex Goodman dcb5d6d08e remove greeter action since it is broken for forked PRs (#223)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-15 10:20:09 -04:00
Alex Goodman b3387807c1 allow for gemspec metadata fields to be optional (#218)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-15 09:57:58 -04:00
Alex Goodman 24c4c025e1 Merge pull request #217 from jhujasonw/main
Fixes #212 by increasing buffer size for scanner
2020-10-14 07:29:00 -04:00
Alex Goodman 5d0909f31e add regression test to cover issue #212
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-14 07:22:19 -04:00
Jason Williams 1f64b3cd49 Fixes #212 by increasing buffer size for scanner
Signed-off-by: Jason Williams <jasonw@jhu.edu>
2020-10-13 11:00:55 -04:00
Toure Dunnon 8d25d44ea9 Add homepage field as output to the gemspec metadata (#215)
https://github.com/anchore/syft/issues/214

Signed-off-by: Toure <tdunnon@gmail.com>
2020-10-12 18:59:56 -04:00
Alex Goodman 1fc46291a6 update install script arguments for proper argument processing (#211)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-09 11:04:53 -04:00
Alex Goodman 2b932f8d65 run tests on fork PRs (#210)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-09 07:45:05 -04:00
Alex Goodman 0d3e153959 replace circle ci badge with GHA (#209)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 15:45:26 -04:00
587589bfe3 Add first issue/PR welcome message action (#185)
* Add first issue/PR welcome message action

Signed-off-by: Robert Prince <robert.prince@anchore.com>

* update first-pr-issue message with a simple greeting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Alex Goodman <alex.goodman@anchore.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2020-10-08 15:42:46 -04:00
Alfredo Deza 4ff330e396 Merge pull request #208 from anchore/non-prerelase
docs: update the readme to remove pre-release note
2020-10-08 15:34:06 -04:00
Alfredo Deza 949bf7bc91 docs: update the readme to remove pre-release note
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-10-08 15:30:50 -04:00
Alex Goodman 956af57d3b update release token name
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 14:37:06 -04:00
Alex Goodman 262a0888a8 fix release pipeline to wait for GHA check names
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 13:57:43 -04:00
Alex Goodman 335a6b022f add acceptance test to cover gem cataloger + fix gem cataloger parent dir (#207)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 13:13:31 -04:00
Alex Goodman da0eb6f20f fix acceptance tests & add notification upon failures (#204)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 11:07:00 -04:00
Toure Dunnon 1be5f5756a Merge pull request #203 from anchore/syft_bundler_wip
Add gemspec support
2020-10-08 11:03:30 -04:00
Alex Goodman 9edbc65bce move unicode regex to static space
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 10:55:57 -04:00
Alex Goodman 398d8903e7 finalize gemspec parser + update json schema to match
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 10:52:14 -04:00
Alex Goodman 46c74865e5 add render unicode in gemspec parser
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 10:52:14 -04:00
Alex Goodman 1f0f6fa3e5 more gemspec tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 10:52:03 -04:00
Alex Goodman abdd00cd24 rename gem parsers and catalogers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 10:23:24 -04:00
Alex Goodman 10b44f5311 split catalogers into two sets, one for images another for directory scans
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 10:23:24 -04:00
Alex Goodman 1c320a8382 defer to GenericCataloger instances for pkg catalogers
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-08 10:23:24 -04:00
Toure 7a8a5419b8 adding ruby gemspec support.
Signed-off-by: Toure Dunnon <toure.dunnon@anchore.com>
2020-10-08 10:19:33 -04:00
Alex Goodman 16b23e7994 add gha pipeline to replace circlei pipeline (#202)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-07 12:20:51 -04:00
Alex Goodman e6b71486b0 modify version command to match grype (#196)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-10-06 13:13:52 -04:00
Dan Luhring 5adfce19e0 Set prerelease to auto (#189)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-09-29 16:33:40 -04:00
Dan Luhring b6dfdf16b6 Remove and update TODOs (#194)
* Remove and update TODOs

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Update TODO with link

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-09-29 11:53:19 -04:00
Alex Goodman b5ce187ba7 replace modfile with stdlib (#187)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-28 17:25:04 -04:00
Alex Goodman 26855a2a9e ignore apk xattr file checksum + remove log.Errorf error wraps (#192)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-28 17:22:17 -04:00
Alex Goodman 4b78d9a1c0 support home dir expansion (#188)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-28 15:02:21 -04:00
Alex Goodman 2844b9878f add release notification
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 23:21:16 -04:00
Alex Goodman 8b81c87d18 remove unreleased tags and exclude size labels
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 22:59:19 -04:00
Alex Goodman 9bd9dad76c remove unrelease changelog option
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 18:11:02 -04:00
Alex Goodman 6d9f9a9b3b pin the two tags used for release autochangelog
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 17:57:51 -04:00
Alex Goodman 50cb5612d0 fix github releaser changelog intake
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 17:20:27 -04:00
Alex Goodman 080f010746 remove tty requirement from release process
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 17:07:59 -04:00
Alex Goodman f4502fc824 Add notifications around the release process (#184)
* add pipeline notification upon release

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add pending notification to release pipeline

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 16:58:56 -04:00
Alex Goodman 03378e976c always return a cleanup function from scope (#183)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 16:20:06 -04:00
Alex Goodman 576fbc898b rm stereoscope from testutils (#181)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 14:53:05 -04:00
Alex Goodman 49800b6747 Normalize the json image/dir source (#180)
* normalize the json image/dir source

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update json image presenter golden file

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 14:07:38 -04:00
Alex Goodman c46d004a3b remove duplicate rows from the summary table (#179)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 10:32:37 -04:00
Alex Goodman 3d91a66536 Add OCI support + use URI schemes for user image input (#178)
* add oci support + update image schemes

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update docs to reflect OCI image sources + URI scheme change

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update to oci-dir

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bump upstream stereoscope pin

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-25 10:24:24 -04:00
Alex Goodman 45b5cab49a unpin skopeo during mac acceptance tests (#176)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-09-18 13:54:40 -04:00
Sam Dacanay 1866949eff Merge pull request #175 from anchore/fix-json-keys
Change kebab case to camelCase in json keys throughout app
2020-09-18 09:19:37 -07:00
Samuel Dacanay 0567206b38 Change kebab case to camelCase in json keys throughout app
Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>
2020-09-18 08:55:17 -07:00
Alex GoodmanandAlfredo Deza f3076c3905 Add docs around the main execution path (#172)
* add docs around the main execution path of syft

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* Update syft/lib.go

Co-authored-by: Alfredo Deza <adeza@anchore.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* Update syft/lib.go

Co-authored-by: Alfredo Deza <adeza@anchore.com>
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* wrap line

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

Co-authored-by: Alfredo Deza <adeza@anchore.com>
2020-09-17 06:02:51 -04:00
Samuel Dacanay b467964044 port over shell completion w/ cobra from grype, find/replace, etc.
Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>
2020-09-15 09:07:17 -07:00
Praveen Mylavarapu e26627d8b6 remove accessing tag when not available (#174)
Signed-off-by: praveenmylavarapu <saipraveenmylavarapu@gmail.com>
2020-09-15 07:55:08 -04:00
Sam Dacanay 80ee18d20b Merge pull request #171 from anchore/version-output-json
Add support for JSON version output
2020-09-14 13:51:59 -07:00
Samuel Dacanay ef64a6f206 Add support for JSON version output
Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>

Make json version output always verbose, cleanup struct tag

Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>

Use camel case for json

Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>
2020-09-14 13:48:27 -07:00
Sam Dacanay 22dfcb2d0b Merge pull request #170 from anchore/add-distro-mappings-arch-and-opensuseleap
Add support for Arch (which doesnt return a version) and Open Suse Leap
2020-09-14 09:02:28 -07:00
Samuel Dacanay 329b080a37 Add support for Arch (which doesnt return a version) and Open Suse Leap
Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>

remove bad-version test fixture (no longer relevant since it is now an expected case) and add cases for arch and opensuse-leap

Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>

Reduce nesting, simplify empty version logic

Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>
2020-09-13 13:50:56 -07:00
Sam Dacanay 11334b632e Expand matching of requirements.txt file to include any prefixes or suffixes (#168)
* Expand matching of requirements.txt file to include any prefixes or suffixes

Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>

* Add some test cases to integration test (ensure syft can pick up multiple requirements files)

Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>

* Run lint-fix

Signed-off-by: Samuel Dacanay <sam.dacanay@anchore.com>
2020-09-08 10:23:37 -07:00
Alex Goodman df7c83c9b0 use xml encoder (#165)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-31 08:06:56 -04:00
Alex Goodman 8a4886ec0e Add package URL support to the CycloneDX presenter (#164)
* add package URL support to the CycloneDX presenter

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* wrap license tags with licenses

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-30 21:40:19 -04:00
Alex Goodman eda0f8c774 add bom descriptor schema + test against xml schemas in pipeline (#163)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-27 19:12:45 -04:00
Alex Goodman d85d0ac418 add changelog generation (#162)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-27 08:10:56 -04:00
Alex Goodman 63661da377 Fix acceptance tests (#158)
* ensure acceptance tests fail when results are piped

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix spelling in inline-compare python script

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-24 21:28:07 -04:00
Alex Goodman f892289e7c Add CycloneDX presenter (#157)
* add CycloneDX presenter + BOM Descriptor extension

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add docstrings to cyclonedx presenter

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-24 20:43:29 -04:00
Alex Goodman 6b65cb6d7d add release process docs (#153)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-24 14:38:31 -04:00
Alfredo Deza ae1d99b5a1 Merge pull request #150 from anchore/issue-59
Add a `setup.py` cataloger
2020-08-17 17:23:13 -04:00
Alfredo Deza 861806f1dd test: add setup.py integration cases
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-08-17 16:00:49 -04:00
Alfredo Deza 9c4024d6fa cataloger: add setup.py support for Python
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-08-17 16:00:49 -04:00
Alfredo Deza 27c207bbca pkg: add a new type to identify setup.py packages
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-08-17 10:12:27 -04:00
Alex Goodman afce14388b replace in-repo asset 2020-08-14 13:58:45 -04:00
Alex Goodman 95517d131a Improve overall documentation (#148)
* improve overall documentation

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix tests to use scope.Resolver over scope

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-13 16:34:32 -04:00
Dan Luhring 47a0454084 Update dependencies (#147)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-08-13 12:12:05 -04:00
Alex Goodman f17feeb6ed Add demo gif + slack channel links (#145)
* add demo gif

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add slack channels to issue template selection

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* github is picky about the issue template file extension

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-12 14:57:22 -04:00
Alex Goodman 51b9c73c31 Add documentation around catalogers, UI elements, and the event bus (#143)
* add basic documentation for catalogers (with refactoring for simplification)

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add docs for catalog parsers, UI, and event bus

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update bus phrasing

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-12 11:04:39 -04:00
Alex Goodman 5042d371cf migrate to anchore/go-rpmdb (#144)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-11 15:32:51 -04:00
Alex Goodman 90bd68e44c Disable prerelease version update check (#140)
* disable prerelease version update check

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* use prerelease flag as source of truth for user notifications

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-11 09:54:04 -04:00
Alfredo Deza 691e26d3a3 Merge pull request #142 from anchore/args-fix
cmd: allow no args passed, don't error
2020-08-11 08:29:28 -04:00
Alfredo Deza 3bcae045cd cmd: allow no args passed, don't error
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-08-11 08:01:19 -04:00
Ross Turk d7695aeae1 Add beta warning and todos (#136)
* Add future ideas + beta warning to README

Signed-off-by: Ross Turk <ross@rossturk.com>

* Update link

Signed-off-by: Ross Turk <ross@rossturk.com>
2020-08-11 07:07:55 -04:00
Dan Luhring 73ec35f513 Update installation method (#139)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-08-10 19:29:19 -04:00
Alex Goodman 676544b6ab use token on release
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-10 18:28:43 -04:00
Alex Goodman 647c806ee4 Add install script + brew tap (#138)
* add install script

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add brew tap

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* rm install warning

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* force non-prereleases

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-10 17:15:00 -04:00
Dan Luhring 89dc415e49 Add badges (#137)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-08-10 16:46:12 -04:00
Alex Goodman ac9141e2ad add issue template (#135)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-10 14:47:32 -04:00
Alfredo Deza 21aa32c599 Merge pull request #134 from anchore/issue-69
docs: add contributing guidelines
2020-08-10 14:46:54 -04:00
Alfredo Deza 2adbe75002 docs: add contributing guidelines
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-08-10 14:15:07 -04:00
Alex Goodman 2d452bf59e Add inline-comparison as acceptance test (#130)
* add inline-compare as acceptance test

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add additional RPM metadata

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* add comments and doc strings to the compare-* make targets

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-10 10:33:44 -04:00
Dan Luhring 4c7784da62 Add shell completion script (#131)
Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-08-10 09:31:02 -04:00
Ross Turk 86d3336280 Add macos quarantine to readme (#129)
* Add note about macOS quarantine

Signed-off-by: Ross Turk <ross@rossturk.com>

* Fix project name

Signed-off-by: Ross Turk <ross@rossturk.com>
2020-08-07 16:47:36 -04:00
Alex Goodman a3a3e3848f replace master with main (#128)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-07 13:27:11 -04:00
Alex Goodman fa5d2b5d98 fix readme installation notice
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-07 11:42:58 -04:00
Alex Goodman 817ce61036 Add detailed location info to json artifact (#127)
* add detailed location info to json artifact

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* decompose json presenter

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
2020-08-07 10:05:16 -04:00
Alex Goodman dc8dfc8457 fix panic on top-level log (#125) 2020-08-06 08:29:52 -04:00
Alex Goodman f855a38a01 pull all commits on checkout for release to build changelog (#126) 2020-08-06 08:28:01 -04:00
Alex Goodman bfc5dd87af replace fetching->loading and reading->parsing in UI (#124) 2020-08-06 08:19:03 -04:00
Dan Luhring 70e673204c Add poetry cataloger (#121)
* Minor cleanup

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Update pkg Type definition to string

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Implement poetry.lock parsing

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Address CI issues

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>

* Integrate Alex's changes

Signed-off-by: Dan Luhring <dan.luhring@anchore.com>
2020-08-04 18:22:43 -04:00
Alex Goodman e2a874a277 finalize json output & add schema (#118) 2020-08-04 16:05:53 -04:00
Alex GoodmanandAlfredo Deza 2560266e38 Initial README (#120)
* initial readme + logging and output fixes to support descriptions

* minor tweaks to README descriptions

* simplify phrasing

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* add comment for example gif

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* spelling fix

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* update phrasing

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* simplify TODO note

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* grammar fix

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* phrase fix

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* rm readme bash block indicators

* clarify config examples are default values

* rm value

Co-authored-by: Alfredo Deza <adeza@anchore.com>

Co-authored-by: Alfredo Deza <adeza@anchore.com>
2020-08-04 15:22:34 -04:00
Alex Goodman 8fe59c6f1a bump stereoscope for docker pull + add UI elements for pull status (#117) 2020-08-03 16:03:47 -04:00
Alex Goodman 78515da285 replace zap logger with logrus (#116) 2020-08-01 11:56:38 -04:00
Alex Goodman 076d5c2f1a fix ui handlers to write before first event 2020-07-31 17:53:22 -04:00
Alex Goodman 5320280216 show message when no packages are discovered (#115) 2020-07-31 08:30:35 -04:00
Alfredo Deza c67e17a2cf Merge pull request #114 from anchore/issue-111
Add another option to fall back on name detection
2020-07-31 07:50:49 -04:00
Alfredo Deza 04a1c91881 java: fallback to manifest.ImplTitle when there is no name
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-31 07:35:43 -04:00
Alfredo Deza bb81c0b9fe tests: java cataloger tests for selecting name
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-31 07:35:43 -04:00
Alex Goodman e3976596f3 pull in fix for bounds check progress formatting values in etui 2020-07-31 06:56:20 -04:00
Alex Goodman 271ba35c85 Export UI handlers for reuse in other tools (#113)
* export UI handlers for reuse in other tools

* bump jotframe to fix cursor issues at frame close
2020-07-30 15:16:58 -04:00
Alex Goodman 857f41b04b Merge pull request #112 from anchore/ignore-prerelease-versions
Ignore prerelease versions when uploading version file on release
2020-07-30 12:37:25 -04:00
Alex Goodman ad1a72c6ff ignore prerelease verions when uploading version file on release 2020-07-29 14:54:47 -04:00
Alfredo Deza bc693829a6 Merge pull request #110 from anchore/issue-8
adds the yarn.lock cataloger
2020-07-29 11:20:06 -04:00
Alfredo Deza caecce9b41 tests: update integration tests to include yarn packages
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-28 15:35:45 -04:00
Alfredo Deza 713f660528 cataloger: update controller to use javascript (vs. npm)
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-28 15:20:11 -04:00
Alfredo Deza d79cecea3e tests: verify new yarn.lock parser
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-28 15:20:11 -04:00
Alfredo Deza 57904743aa pkg: define the Yarn package type
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-28 15:18:47 -04:00
Alfredo Deza 67fb1326e0 cataloger: implement the yarn.lock parser
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-28 15:18:47 -04:00
Alfredo Deza 146b4bd01f cataloger: rename npm to javascript to accommodate yarn parser
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-28 15:18:47 -04:00
Alex Goodman 06f8355fce finalize update check URL 2020-07-27 15:13:41 -04:00
Alex Goodman 19eadde9ca use aws creds for version file upload 2020-07-27 09:55:11 -04:00
Alex Goodman d21de64cb3 use mount path for version upload 2020-07-27 09:35:55 -04:00
Alex Goodman 50b50a50b2 Merge pull request #108 from anchore/upload-version
Upload version check file on release
2020-07-27 09:33:52 -04:00
Alex Goodman 6536f0bb36 upload version check file on release 2020-07-27 09:30:05 -04:00
Alex Goodman 2e15d854eb bump circle resources 2020-07-25 19:08:19 -04:00
Alex Goodman 78c3652759 bump bouncer version 2020-07-25 16:55:41 -04:00
Alex Goodman 2502814143 rollup static analysis to make target 2020-07-25 16:40:37 -04:00
Alex Goodman 991bf203da bust old imgbom cache 2020-07-25 10:36:17 -04:00
Alex Goodman 05c78de9d3 generate java fixtures ahead of tests 2020-07-25 10:06:52 -04:00
Alex Goodman c9dea59232 verify signing fingerprint 2020-07-25 09:59:48 -04:00
Alex Goodman 08ea496544 Merge pull request #94 from anchore/table-output
Add default table presenter
2020-07-25 08:49:14 -04:00
Alex Goodman 1ba0678cf6 provide signed checksums 2020-07-25 08:42:50 -04:00
Alex Goodman c814379c80 add auto prerelease option 2020-07-25 07:33:24 -04:00
Alex Goodman f3428e49b8 add release quality gate 2020-07-25 07:23:15 -04:00
Alex Goodman 585569e929 fix gha go cache key; rm brew until oss release 2020-07-25 07:18:21 -04:00
Alex Goodman 32bd57886e add publish release 2020-07-25 07:09:20 -04:00
Alex Goodman 44f26c7f90 update release quality gate version 2020-07-25 07:03:57 -04:00
Alfredo DezaandAlex Goodman f8a5c56191 Fix acceptance tests (#106)
* test: allow no metadata in packages

Signed-off-by: Alfredo Deza <adeza@anchore.com>

* test: update centos json fixture

Signed-off-by: Alfredo Deza <adeza@anchore.com>

Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2020-07-25 06:39:44 -04:00
Alex Goodman 2e458cd73d make acceptance test results dir on run 2020-07-24 18:04:52 -04:00
Alex Goodman 6b0ab2de4a Merge pull request #107 from anchore/fix-acceptance-compare
Fix acceptance test compare script & persist results
2020-07-24 17:53:02 -04:00
Alex Goodman 14ec30aee1 fix acceptance test compare script & persist 2020-07-24 17:41:22 -04:00
Alfredo Deza 578952986f Merge pull request #103 from anchore/issue-81
scope: do not create scope if path is invalid
2020-07-24 15:33:30 -04:00
Alfredo Deza e1ce040ead scope: do not create scope if path is invalid
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-24 15:25:14 -04:00
Alex Goodman 9ec5da24dd fix py globs to include partial matches (#101) 2020-07-24 08:22:56 -04:00
Alex Goodman 32071b0bf1 add default table presenter 2020-07-23 21:48:12 -04:00
Alex Goodman 0a0bc68e95 show verbose test output to prevent circleci kills 2020-07-23 21:47:11 -04:00
Alex Goodman a4016d35ce rename to syft 2020-07-23 20:54:04 -04:00
Alex Goodman 2132700198 add apk/alpine support (#98) 2020-07-23 20:35:57 -04:00
Alex Goodman 63ba7ae47d add remaining debian & el distro support (#99) 2020-07-23 20:35:40 -04:00
Alex Goodman 5ccd6d5f6a check for unsupported "go get" chars (#100) 2020-07-23 13:08:31 -04:00
Alex GoodmanandAlfredo Deza ba4f63099d Add release process (#89)
* add check for app update; fix ETUI error handling

* validate user args

* add goreleaser support

* replace cgo dependencies (go-rpm) with go equivalents

* add acceptance tests against build snapshot

* add brew tap + acceptance test pipeline

* add mac acceptance tests

* fix compare makefile

* fix mac acceptance tests

* add release pipeline with wait checks

* add token to release step

* rm dir presenters int test

* enforce dpkg to be non interactive

Co-authored-by: Alfredo Deza <adeza@anchore.com>

* pin brew formulae

* pin skopeo to formulae url

* only run acceptance tests

Co-authored-by: Alfredo Deza <adeza@anchore.com>
2020-07-23 10:52:44 -04:00
Alfredo Deza 3cb7c43dbc Merge pull request #96 from anchore/issue-7
Add support for analyzing package-lock.json files
2020-07-23 09:54:39 -04:00
Alfredo Deza f1c14d97f6 integration: validate package-lock.json parsing
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-23 09:51:05 -04:00
Alfredo Deza 9f314eb493 cataloger: support npm packages from package-lock.json files
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-23 09:51:05 -04:00
Alfredo Deza fb4b83cf3e cataloger: define Javascript (npm) package type
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-23 09:51:01 -04:00
Alex Goodman 44c69f1f91 add go.mod cataloger (#97) 2020-07-23 08:17:30 -04:00
Alfredo Deza 265516682f Merge pull request #92 from anchore/issue-58
catalog Python packages from a requirements.txt file
2020-07-21 16:00:20 -04:00
Alfredo Deza 74d87254ed integration: validate requirements.txt is picked up and parsed
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 15:49:19 -04:00
Alfredo Deza 50eae46d37 type: add PythonPkg types for requirements-based packages
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 15:49:19 -04:00
Alfredo Deza f8a2b7a626 tests: verify requirements.txt captures versions
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 15:49:19 -04:00
Alfredo Deza 83056a4b6f cataloger: add a requirements.txt parser
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 15:38:30 -04:00
Alfredo Deza 8747b68b86 cataloger: add a glob path for parsing requirements.txt
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 14:37:06 -04:00
Alex Goodman 7ebb9f4e0b Add check for app update (#88)
* add check for app update; fix ETUI error handling

* validate user args
2020-07-21 12:02:03 -04:00
Alfredo Deza 380cd39514 Merge pull request #91 from anchore/issue-75
Recurse when creating a directory catalog
2020-07-21 11:26:03 -04:00
Alfredo Deza cea38fcba3 cataloger: use ** for glob patterns
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 11:19:42 -04:00
Alfredo Deza 03bbcfa08d cataloger: add ability to recurse with doublestar
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 11:10:02 -04:00
Alfredo Deza 942cd6eb18 dependencies: add doublestar for recursive globbing support
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 11:10:02 -04:00
Alfredo Deza f02b8cc7bc tests: use the catalog directly instead of via the presenters
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-21 11:10:02 -04:00
Alfredo Deza fe15c0a08b tests: remove dir_presenters, no longer needed
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-20 15:55:52 -04:00
Alex Goodman 4fa391b4cb remove metadata from text presenter (#90) 2020-07-20 15:28:26 -04:00
Alex Goodman 9e285fd0e2 use common entry point for integration tests; refactor cmd pkg (#86) 2020-07-17 15:16:33 -04:00
Alfredo Deza b5a353349f Merge pull request #87 from anchore/unkown-distro
Add a helper function/constructor for an UnkownDistro
2020-07-17 13:54:14 -04:00
Alfredo Deza b734623ef0 make: bump test coverage
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-17 13:32:53 -04:00
Alfredo Deza 0534a68ec6 tests for new Identify distro func
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-17 13:32:53 -04:00
Alfredo Deza e2b71184aa when no distros are matched, return an UnkownDistro
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-17 13:32:53 -04:00
Alfredo Deza f51cae2043 distro: add new constructor for getting UnkownDistros
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-17 13:32:53 -04:00
Alfredo Deza f03f7b32e9 Merge pull request #85 from anchore/issue-84
Remove carriage returns from distro files
2020-07-17 08:31:22 -04:00
Alfredo Deza fb6bc116e0 tests: verify carriage returns are parsed in distro files
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-16 17:20:30 -04:00
Alfredo Deza 5edcae13b3 distro: remove unwanted chars from os distro files
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-16 17:19:57 -04:00
Alfredo Deza aa0693bdc0 Merge pull request #83 from anchore/issue-82
Do not join paths when returning multiple file contents by ref
2020-07-16 14:36:30 -04:00
Alfredo Deza a05d58686e resolvers: do not join paths, it is assumed they are already joined
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-16 13:14:03 -04:00
Alfredo Deza d82a0872c9 tests: verify MultipleFileContentsByRef gets contents from the right path
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-16 13:14:03 -04:00
Alfredo Deza 07b2a1da87 Merge pull request #76 from anchore/issue-73
Better abstraction for img/dir decision fork
2020-07-15 10:49:15 -04:00
Alfredo Deza b457d4ebd2 tests: drop coverage requirement to 69% for now
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 10:15:58 -04:00
Alfredo Deza d982ad6345 lib: implement a NewScope to produce scopes from inputs
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 10:15:58 -04:00
Alfredo Deza b2c8685437 integration: use new constructor params for scope from images
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 10:15:58 -04:00
Alfredo Deza f418c99a3b remove old text support files
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 10:15:58 -04:00
Alfredo Deza 45b5fa82c8 presenters: abstract into text only
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 10:15:58 -04:00
Alfredo Deza e7518ad998 tests: move img-based tests and fixtures
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 09:59:40 -04:00
Alfredo Deza a6e1866cdb cmd: do not default for images, handle it specifically
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 09:59:40 -04:00
Alfredo Deza 2f626bf9fd directory resolver should join path and target directory for retrieving contents
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 09:59:40 -04:00
Alfredo Deza 429c28720c integration: update tests to use scope instead of img directly
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:28 -04:00
Alfredo Deza 69b01caba7 update scope tests to use new generic scope
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:28 -04:00
Alfredo Deza c56b82e529 resolvers: add a directory resolver
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:28 -04:00
Alfredo Deza 5cee2668e3 resolvers: satisfy interface with multiple file contents by ref
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:28 -04:00
Alfredo Deza 6e9171e8a6 presenter: use new scoped source
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:27 -04:00
Alfredo Deza 4b69758f2c scope: create a new generic Resolver interface
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:27 -04:00
Alfredo Deza b35a412467 scope: use a generic scope struct instead of specific to images
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:27 -04:00
Alfredo Deza 145bb95a2d lib: use scope instead of requiring images
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:27 -04:00
Alfredo Deza d22c1d0838 distro: identify uses the scope resolvers now, not images
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:27 -04:00
Alfredo Deza 923d220a90 controller: use new scope.Resolver interface
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:27 -04:00
Alfredo Deza 6cbf6d3409 cmd: do not pass img around, use scope
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-15 07:53:27 -04:00
Alex Goodman 66a16a67fd Add support for detecting nested java archives (#77)
* with sb build app

* test nested jar support

* pin jdk version during parse test (but dont compare version)
2020-07-15 07:42:35 -04:00
Alex Goodman e8d11eec69 add license validation (#80) 2020-07-13 13:07:20 -04:00
Alex GoodmanandAlfredo Deza 61f51d80bb Add comparative analysis with anchore-engine (#78)
* add comparative analysis

* remove extra comma from compare script tuple

Co-authored-by: Alfredo Deza <adeza@anchore.com>

Co-authored-by: Alfredo Deza <adeza@anchore.com>
2020-07-13 12:12:00 -04:00
Alex Goodman 3f090f9647 fix java cache key for CI; fix circle docker api version (#79) 2020-07-13 12:11:11 -04:00
Alex Goodman 502e2afd06 fix linting issue 2020-07-10 07:45:13 -04:00
Alex Goodman 15ff94b56b tweak java manifest version processing 2020-07-10 07:41:13 -04:00
Alex Goodman ef8c215772 Merge pull request #74 from anchore/add-java-cataloger
Adds java cataloger
2020-07-09 17:05:29 -04:00
Alex Goodman 4c7d9ccef7 simplify unzip; update java error statements 2020-07-09 11:53:52 -04:00
Alex GoodmanandAlfredo Deza 0f8dcf3f17 Update imgbom/cataloger/java/pom_properties.go
Co-authored-by: Alfredo Deza <adeza@anchore.com>
2020-07-09 11:38:02 -04:00
Alex GoodmanandAlfredo Deza c9bfc0aecd Update imgbom/cataloger/java/pom_properties.go
Co-authored-by: Alfredo Deza <adeza@anchore.com>
2020-07-09 11:37:45 -04:00
Alex GoodmanandAlfredo Deza 40f8e3a7de Update imgbom/cataloger/java/java_manifest.go
Co-authored-by: Alfredo Deza <adeza@anchore.com>
2020-07-09 11:31:23 -04:00
Alex Goodman 1f89d26902 reduce java packages to java-archive and jenkins-plugin 2020-07-09 10:46:28 -04:00
Alex Goodman e55db9247e add java cataloger 2020-07-08 16:16:01 -04:00
Alfredo Deza 1d711ee06f Merge pull request #71 from anchore/protocol-cleanup
cmd: replace Printf with a logging statement
2020-07-07 10:42:26 -04:00
Alfredo Deza 74f339e043 cmd: replace Printf with a logging statement
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-07 10:40:55 -04:00
Alex Goodman e040fc8930 Merge pull request #72 from anchore/add-rpm-cataloger
Add RPM DB support
2020-07-07 09:06:54 -04:00
Alex Goodman 1896831c39 add rpmdb support; enhance integration tests 2020-07-06 12:55:11 -04:00
Alex Goodman 7cd16d05b8 Merge pull request #70 from anchore/add-coverage
Add test coverage (+ makefile improvements)
2020-07-06 12:45:52 -04:00
Alex Goodman d59a19697d add coverage + makefile improvements 2020-07-06 07:25:18 -04:00
Alex Goodman 027f71de45 fix env config reads for nested config values 2020-07-03 12:00:46 -04:00
Alfredo Deza fe338760b0 Merge pull request #68 from anchore/issue-31-1
Add support for file-based contents
2020-07-02 17:29:45 -04:00
Alfredo Deza 9baae90c0b integration: add tests for dir-based presenters
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 16:09:55 -04:00
Alfredo Deza 3548c7b132 tests for scope.go
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 16:09:55 -04:00
Alfredo Deza 3eedb86a1f tests for protocol.go
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 16:09:55 -04:00
Alfredo Deza c35108b00d tests: reorganize text img files to match new layout
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 16:09:55 -04:00
Alfredo Deza f49ca8107a tests: add verification for dirs and imgs
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 16:09:55 -04:00
Alfredo Deza 293b7b6ff9 tests: update integration tests to use new cataloger
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 16:09:55 -04:00
Alfredo Deza 96d86fa214 tests: move existing json tests to json/imgs
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 16:09:55 -04:00
Alfredo Deza 7544330bc2 json img presenter needs to degrade nicely when file metadata is not present
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza feef7e28dc cmd: add note about panic when img is nil
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza ec52e91301 scope: create interface for content and file resolvers
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza b2d7bd3b1a scope: add directory-based scoping
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza e38e3e9ff4 create text-based presenters for dirs and imgs
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza 268cfef0ee re-organize json-based presenters for dirs and imgs
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza 312c8acfbe presenter can pick text-dir, text-img, json-text, or json-img for reporting
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza 69a0376f99 distro: add note to replace with MultipleFileContents in the future
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza 507a6b69cb catalog controller uses scope to determine file resolvers
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza faf21a67a6 lib: return a protocol-based scope (dir or img)
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 15:12:48 -04:00
Alfredo Deza 678a2c1dcb create a protocol-parsing package to distinguish dir,docker, etc...
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-02 13:04:19 -04:00
Alfredo Deza 4d31655908 allow root command to catalog a directory
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-01 07:35:01 -04:00
Alex Goodman 466169e8d7 Merge pull request #65 from anchore/add-an-event-bus
Add and use event bus for UI progress
2020-06-25 11:04:45 -04:00
Alex Goodman 926b5f2a50 add and use event bus for UI progress 2020-06-25 10:39:11 -04:00
Alex Goodman 2e9e969c5f Merge pull request #66 from anchore/add-license
Add apache v2 license
2020-06-24 14:51:51 -04:00
Alex Goodman 1569a85820 add apache v2 license 2020-06-24 14:37:00 -04:00
Alfredo Deza d2e6229b2e Merge pull request #64 from anchore/issue-36
Create a text presenter, default to it
2020-06-22 14:05:06 -04:00
Alfredo Deza 0a1f99503f cli: default to the new text presenter
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-22 11:09:00 -04:00
Alfredo Deza 2e6aef17e1 implement a text presenter
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-22 11:09:00 -04:00
Alfredo Deza 72f9091493 presenter: allow a text presenter option
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-19 15:46:31 -04:00
Alfredo Deza acbeea9800 option: add a Text-based presenter
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-19 15:45:58 -04:00
Alex Goodman 2cb7dad967 Merge pull request #63 from anchore/add-symlink-suport
Add symlink support
2020-06-16 13:10:24 -04:00
Alex Goodman cd94179985 add symlink content fetching support 2020-06-16 11:37:37 -04:00
Alex Goodman 778754dd59 Merge pull request #62 from anchore/add-simple-pipeline
Add basic pipeline
2020-06-15 13:53:49 -04:00
Alex Goodman 6b5a22da46 add basic pipeline 2020-06-15 13:51:07 -04:00
Alex Goodman 0d66cb8a1c Merge pull request #60 from anchore/rename-analyzers
Rename analyzers to catalogers
2020-06-15 13:18:07 -04:00
Alex Goodman 294e267e47 rename analyzers to catalogers; fix generic cataloger path dispatcher 2020-06-15 10:52:55 -04:00
Alfredo Deza 812934c964 Merge pull request #57 from anchore/issue-33
Initial take on distro detection
2020-06-12 15:58:36 -04:00
Alfredo Deza e460c031b6 distro: add tests and fixtures for identification
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-12 15:57:51 -04:00
Alfredo Deza 889fa52b7d lib: update signature to *Distro
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-12 10:49:14 -04:00
Alfredo Deza 75375d0b58 cmd: IdentifyDistro returns a distro object which can be nil
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-12 10:49:14 -04:00
Alfredo Deza dba5f0b197 initial take on distro identification
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-12 10:49:14 -04:00
Alfredo Deza 56c2318ea1 add support for distro detection
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-12 10:49:14 -04:00
Alfredo Deza f1851556a8 distro: add a Name stringer
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-06-12 10:49:14 -04:00
Alex Goodman 64a9125895 Merge pull request #53 from anchore/add-python-wheel-egg-analyzers
Add python wheel and egg analyzer support
2020-06-05 09:59:27 -04:00
Alex Goodman a0ccfe220b add python wheel and egg analyzer support 2020-06-05 08:47:17 -04:00
Alex Goodman 83e96e8880 generalize common analyzer elements 2020-06-04 17:49:52 -04:00
Alex Goodman e88669c536 Merge pull request #52 from anchore/add-gem-analyzer
Add gem analyzer
2020-06-04 14:43:52 -04:00
Alex Goodman f33720eaa1 add gem analyzer 2020-06-04 14:42:59 -04:00
Alex Goodman 033c91a233 Merge pull request #35 from anchore/use-filetree-reader
Utilize filetree reader
2020-06-04 14:36:40 -04:00
Alex Goodman b6122a413b add distro version tests 2020-06-02 20:48:15 -04:00
Alex Goodman cc724bff26 use filetree reader instead of filetree 2020-06-02 08:52:26 -04:00
Alex Goodman f0b8aaacda Merge pull request #34 from anchore/focus-dkpg-metadata
Add dpkg source field to metadata
2020-06-01 17:42:18 -04:00
Alex Goodman 17787f856f rm unused dkpg metadata, add dpkg source field, add analyzer source name 2020-06-01 15:25:47 -04:00
Alex Goodman 83e486d6ca Merge pull request #29 from anchore/add-os-types
Start of distro identification support
2020-06-01 10:47:31 -04:00
Alex Goodman 45fbd05cf9 add first distro support 2020-06-01 10:46:06 -04:00
Alex Goodman 1f272c2bda Merge pull request #27 from anchore/add-package-id
Add package id
2020-06-01 08:55:22 -04:00
Alex Goodman a0e48468c2 with package id 2020-05-29 16:06:31 -04:00
825 changed files with 87990 additions and 1806 deletions
+22
View File
@@ -0,0 +1,22 @@
permit:
- BSD.*
- MIT.*
- Apache.*
- MPL.*
- ISC
ignore-packages:
# packageurl-go is released under the MIT license located in the root of the repo at /mit.LICENSE
- github.com/anchore/packageurl-go
# from: https://github.com/spdx/tools-golang/blob/main/LICENSE.code
# The tools-golang source code is provided and may be used, at your option,
# under either:
# * Apache License, version 2.0 (Apache-2.0), OR
# * GNU General Public License, version 2.0 or later (GPL-2.0-or-later).
# (we choose Apache-2.0)
- github.com/spdx/tools-golang
# from: https://github.com/xi2/xz/blob/master/LICENSE
# All these files have been put into the public domain.
# You can do whatever you want with these files.
- github.com/xi2/xz
+20
View File
@@ -0,0 +1,20 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**What happened**:
**What you expected to happen**:
**How to reproduce it (as minimally and precisely as possible)**:
**Anything else we need to know?**:
**Environment**:
- Output of `syft version`:
- OS (e.g: `cat /etc/os-release` or similar):
+6
View File
@@ -0,0 +1,6 @@
contact_links:
- name: Join the Slack community 💬
# link to our community Slack registration page
url: https://anchore.com/slack
about: 'Come chat with us! Ask for help, join our software development efforts, or just give us feedback!'
+15
View File
@@ -0,0 +1,15 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
**What would you like to be added**:
**Why is this needed**:
**Additional context**:
<!-- Add any other context or screenshots about the feature request here. -->
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -eu
ORIGINAL_STATE_DIR=$(mktemp -d "TEMP-original-state-XXXXXXXXX")
TIDY_STATE_DIR=$(mktemp -d "TEMP-tidy-state-XXXXXXXXX")
trap "cp -v ${ORIGINAL_STATE_DIR}/* ./ && rm -fR ${ORIGINAL_STATE_DIR} ${TIDY_STATE_DIR}" EXIT
echo "Capturing original state of files..."
cp -v go.mod go.sum "${ORIGINAL_STATE_DIR}"
echo "Capturing state of go.mod and go.sum after running go mod tidy..."
go mod tidy
cp -v go.mod go.sum "${TIDY_STATE_DIR}"
echo ""
set +e
# Detect difference between the git HEAD state and the go mod tidy state
DIFF_MOD=$(diff -u "${ORIGINAL_STATE_DIR}/go.mod" "${TIDY_STATE_DIR}/go.mod")
DIFF_SUM=$(diff -u "${ORIGINAL_STATE_DIR}/go.sum" "${TIDY_STATE_DIR}/go.sum")
if [[ -n "${DIFF_MOD}" || -n "${DIFF_SUM}" ]]; then
echo "go.mod diff:"
echo "${DIFF_MOD}"
echo "go.sum diff:"
echo "${DIFF_SUM}"
echo ""
printf "FAILED! go.mod and/or go.sum are NOT tidy; please run 'go mod tidy'.\n\n"
exit 1
fi
+398
View File
@@ -0,0 +1,398 @@
#!/bin/sh
set -e
# Code generated by godownloader on 2019-12-25T12:47:14Z. DO NOT EDIT.
#
usage() {
this=$1
cat <<EOF
$this: download go binaries for goreleaser/goreleaser
Usage: $this [-b] bindir [-d] [tag]
-b sets bindir or installation directory, Defaults to ./bin
-d turns on debug logging
[tag] is a tag from
https://github.com/goreleaser/goreleaser/releases
If tag is missing, then the latest will be used.
Generated by godownloader
https://github.com/goreleaser/godownloader
EOF
exit 2
}
parse_args() {
#BINDIR is ./bin unless set be ENV
# over-ridden by flag below
BINDIR=${BINDIR:-./bin}
while getopts "b:dh?x" arg; do
case "$arg" in
b) BINDIR="$OPTARG" ;;
d) log_set_priority 10 ;;
h | \?) usage "$0" ;;
x) set -x ;;
esac
done
shift $((OPTIND - 1))
TAG=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
tmpdir=$(mktemp -d)
log_debug "downloading files into ${tmpdir}"
http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
srcdir="${tmpdir}"
(cd "${tmpdir}" && untar "${TARBALL}")
test ! -d "${BINDIR}" && install -d "${BINDIR}"
for binexe in $BINARIES; do
if [ "$OS" = "windows" ]; then
binexe="${binexe}.exe"
fi
install "${srcdir}/${binexe}" "${BINDIR}/"
log_info "installed ${BINDIR}/${binexe}"
done
rm -rf "${tmpdir}"
}
get_binaries() {
case "$PLATFORM" in
darwin/386) BINARIES="goreleaser" ;;
darwin/amd64) BINARIES="goreleaser" ;;
darwin/arm64) BINARIES="goreleaser" ;;
darwin/armv6) BINARIES="goreleaser" ;;
linux/386) BINARIES="goreleaser" ;;
linux/amd64) BINARIES="goreleaser" ;;
linux/arm64) BINARIES="goreleaser" ;;
linux/armv6) BINARIES="goreleaser" ;;
windows/386) BINARIES="goreleaser" ;;
windows/amd64) BINARIES="goreleaser" ;;
windows/arm64) BINARIES="goreleaser" ;;
windows/armv6) BINARIES="goreleaser" ;;
*)
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
exit 1
;;
esac
}
tag_to_version() {
if [ -z "${TAG}" ]; then
log_info "checking GitHub for latest tag"
else
log_info "checking GitHub for tag '${TAG}'"
fi
REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
if test -z "$REALTAG"; then
log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
exit 1
fi
# if version starts with 'v', remove it
TAG="$REALTAG"
VERSION=${TAG#v}
}
adjust_format() {
# change format (tar.gz or zip) based on OS
case ${OS} in
windows) FORMAT=zip ;;
esac
true
}
adjust_os() {
# adjust archive name based on OS
case ${OS} in
386) OS=i386 ;;
amd64) OS=x86_64 ;;
darwin) OS=Darwin ;;
linux) OS=Linux ;;
windows) OS=Windows ;;
esac
true
}
adjust_arch() {
# adjust archive name based on ARCH
case ${ARCH} in
386) ARCH=i386 ;;
amd64) ARCH=x86_64 ;;
darwin) ARCH=Darwin ;;
linux) ARCH=Linux ;;
windows) ARCH=Windows ;;
esac
true
}
cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
command -v "$1" >/dev/null
}
echoerr() {
echo "$@" 1>&2
}
log_prefix() {
echo "$0"
}
_logp=6
log_set_priority() {
_logp="$1"
}
log_priority() {
if test -z "$1"; then
echo "$_logp"
return
fi
[ "$1" -le "$_logp" ]
}
log_tag() {
case $1 in
0) echo "emerg" ;;
1) echo "alert" ;;
2) echo "crit" ;;
3) echo "err" ;;
4) echo "warning" ;;
5) echo "notice" ;;
6) echo "info" ;;
7) echo "debug" ;;
*) echo "$1" ;;
esac
}
log_debug() {
log_priority 7 || return 0
echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
}
log_info() {
log_priority 6 || return 0
echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
}
log_err() {
log_priority 3 || return 0
echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
}
log_crit() {
log_priority 2 || return 0
echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
}
uname_os() {
os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$os" in
cygwin_nt*) os="windows" ;;
mingw*) os="windows" ;;
msys_nt*) os="windows" ;;
esac
echo "$os"
}
uname_arch() {
arch=$(uname -m)
case $arch in
x86_64) arch="amd64" ;;
x86) arch="386" ;;
i686) arch="386" ;;
i386) arch="386" ;;
aarch64) arch="arm64" ;;
armv5*) arch="armv5" ;;
armv6*) arch="armv6" ;;
armv7*) arch="armv7" ;;
esac
echo ${arch}
}
uname_os_check() {
os=$(uname_os)
case "$os" in
darwin) return 0 ;;
dragonfly) return 0 ;;
freebsd) return 0 ;;
linux) return 0 ;;
android) return 0 ;;
nacl) return 0 ;;
netbsd) return 0 ;;
openbsd) return 0 ;;
plan9) return 0 ;;
solaris) return 0 ;;
windows) return 0 ;;
esac
log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
return 1
}
uname_arch_check() {
arch=$(uname_arch)
case "$arch" in
386) return 0 ;;
amd64) return 0 ;;
arm64) return 0 ;;
armv5) return 0 ;;
armv6) return 0 ;;
armv7) return 0 ;;
ppc64) return 0 ;;
ppc64le) return 0 ;;
mips) return 0 ;;
mipsle) return 0 ;;
mips64) return 0 ;;
mips64le) return 0 ;;
s390x) return 0 ;;
amd64p32) return 0 ;;
esac
log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
return 1
}
untar() {
tarball=$1
case "${tarball}" in
*.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;;
*.tar) tar --no-same-owner -xf "${tarball}" ;;
*.zip) unzip "${tarball}" ;;
*)
log_err "untar unknown archive format for ${tarball}"
return 1
;;
esac
}
http_download_curl() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
else
code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
fi
if [ "$code" != "200" ]; then
log_debug "http_download_curl received HTTP status $code"
return 1
fi
return 0
}
http_download_wget() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
wget -q -O "$local_file" "$source_url"
else
wget -q --header "$header" -O "$local_file" "$source_url"
fi
}
http_download() {
log_debug "http_download $2"
if is_command curl; then
http_download_curl "$@"
return
elif is_command wget; then
http_download_wget "$@"
return
fi
log_crit "http_download unable to find wget or curl"
return 1
}
http_copy() {
tmp=$(mktemp)
http_download "${tmp}" "$1" "$2" || return 1
body=$(cat "$tmp")
rm -f "${tmp}"
echo "$body"
}
github_release() {
owner_repo=$1
version=$2
test -z "$version" && version="latest"
giturl="https://github.com/${owner_repo}/releases/${version}"
json=$(http_copy "$giturl" "Accept:application/json")
test -z "$json" && return 1
version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
test -z "$version" && return 1
echo "$version"
}
hash_sha256() {
TARGET=${1:-/dev/stdin}
if is_command gsha256sum; then
hash=$(gsha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command sha256sum; then
hash=$(sha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command shasum; then
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command openssl; then
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f a
else
log_crit "hash_sha256 unable to find command to compute sha-256 hash"
return 1
fi
}
hash_sha256_verify() {
TARGET=$1
checksums=$2
if [ -z "$checksums" ]; then
log_err "hash_sha256_verify checksum file not specified in arg2"
return 1
fi
BASENAME=${TARGET##*/}
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
if [ -z "$want" ]; then
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
return 1
fi
got=$(hash_sha256 "$TARGET")
if [ "$want" != "$got" ]; then
log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
return 1
fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF
PROJECT_NAME="goreleaser"
OWNER=goreleaser
REPO="goreleaser"
BINARY=goreleaser
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"
# use in logging routines
log_prefix() {
echo "$PREFIX"
}
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
uname_os_check "$OS"
uname_arch_check "$ARCH"
parse_args "$@"
get_binaries
tag_to_version
adjust_format
adjust_os
adjust_arch
log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
NAME=${PROJECT_NAME}_${OS}_${ARCH}
TARBALL=${NAME}.${FORMAT}
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
CHECKSUM=checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
execute
log_err "this script is deprecated, please do not use it anymore. check https://github.com/goreleaser/godownloader/issues/207"
+31
View File
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -eu
CI_HOME="/Users/runner"
if [[ "${HOME}" != "${CI_HOME}" ]]; then
printf "WARNING! It looks like this isn't the CI environment. This script modifies the macOS Keychain setup in ways you probably wouldn't want for your own machine. It also requires an Apple Developer ID Certificate that you shouldn't have outside of the CI environment.\n\nExiting early to make sure nothing bad happens.\n"
exit 1
fi
# Install gon (see https://github.com/mitchellh/gon for details).
brew tap mitchellh/gon
brew install mitchellh/gon/gon
# Write signing certificate to disk from environment variable.
CERT_FILE="$HOME/developer_id_certificate.p12"
echo -n "$APPLE_DEVELOPER_ID_CERT" | base64 --decode > "$CERT_FILE"
# In order to have all keychain interactions avoid an interactive user prompt, we need to control the password for the keychain in question, which means we need to create a new keychain into which we'll import the signing certificate and from which we'll later access this certificate during code signing.
EPHEMERAL_KEYCHAIN="ci-ephemeral-keychain"
EPHEMERAL_KEYCHAIN_PASSWORD="$(openssl rand -base64 100)"
security create-keychain -p "${EPHEMERAL_KEYCHAIN_PASSWORD}" "${EPHEMERAL_KEYCHAIN}"
# Import signing certificate into the keychain. (This is a pre-requisite for gon, which is invoked via goreleaser.)
EPHEMERAL_KEYCHAIN_FULL_PATH="$HOME/Library/Keychains/${EPHEMERAL_KEYCHAIN}-db"
security import "${CERT_FILE}" -k "${EPHEMERAL_KEYCHAIN_FULL_PATH}" -P "${APPLE_DEVELOPER_ID_CERT_PASS}" -T "$(command -v codesign)"
# Setting the partition list for this certificate's private key to include "apple-tool:" and "apple:" allows the codesign command to access this keychain item without an interactive user prompt. (codesign is invoked by gon.)
security set-key-partition-list -S "apple-tool:,apple:" -s -k "${EPHEMERAL_KEYCHAIN_PASSWORD}" "${EPHEMERAL_KEYCHAIN_FULL_PATH}"
# Make this new keychain the user's default keychain, so that codesign will be able to find this certificate when we specify it during signing.
security default-keychain -d "user" -s "${EPHEMERAL_KEYCHAIN_FULL_PATH}"
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -eu
IS_SNAPSHOT="$1" # e.g. "true", "false"
if [[ "${IS_SNAPSHOT}" == "true" ]]; then
# This is a snapshot build —— skipping signing and notarization...
exit 0
fi
GON_CONFIG="$2" # e.g. "gon.hcl"
NEW_NAME_WITHOUT_EXTENSION="$3" # e.g. "./dist/syft-0.1.0"
ORIGINAL_NAME_WITHOUT_EXTENSION="./dist/output" # This should match dmg and zip output_path in the gon config file, without the extension.
gon "${GON_CONFIG}"
# Rename outputs with specified desired name
mv -v "${ORIGINAL_NAME_WITHOUT_EXTENSION}.dmg" "${NEW_NAME_WITHOUT_EXTENSION}.dmg"
mv -v "${ORIGINAL_NAME_WITHOUT_EXTENSION}.zip" "${NEW_NAME_WITHOUT_EXTENSION}.zip"
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -ue
BIN="syft"
DISTDIR=$1
VERSION=$2
# the source of truth as to whether we want to notify users of an update is if the release just created is NOT
# flagged as a pre-release on github
if [[ "$(curl -SsL https://api.github.com/repos/anchore/${BIN}/releases/tags/${VERSION} | jq .prerelease)" == "true" ]] ; then
echo "skipping publishing a version file (this is a pre-release: ${VERSION})"
exit 0
fi
echo "creating and publishing version file"
# create a version file for version-update checks
VERSION_FILE="${DISTDIR}/VERSION"
echo "${VERSION}" | tee "${VERSION_FILE}"
# upload the version file that supports the application version update check
export AWS_DEFAULT_REGION=us-west-2
aws s3 cp "${VERSION_FILE}" s3://toolbox-data.anchore.io/${BIN}/releases/latest/VERSION
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -ue
DISTDIR=$1
export FINGERPRINT=$(gpg --verify ${DISTDIR}/*checksums.txt.sig ${DISTDIR}/*checksums.txt 2>&1 | grep 'using RSA key' | awk '{ print $NF }')
if [[ "${FINGERPRINT}" == "${SIGNING_FINGERPRINT}" ]]; then
echo 'verified signature'
else
echo "signed with unknown fingerprint: ${FINGERPRINT}"
echo " expected fingerprint: ${SIGNING_FINGERPRINT}"
exit 1
fi
+62
View File
@@ -0,0 +1,62 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
name: "CodeQL Security Scan"
on:
push:
branches: [main]
pull_request:
# The branches below must be a subset of the branches above
branches: [main]
schedule:
- cron: '0 0 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Override automatic language detection by changing the below list
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
language: ['go', 'python']
# Learn more...
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
+173
View File
@@ -0,0 +1,173 @@
name: "Release"
on:
push:
# take no actions on push to any branch...
branches-ignore:
- "**"
# ... only act on release tags
tags:
- "v*"
env:
GO_VERSION: "1.16.x"
jobs:
quality-gate:
environment: release
runs-on: ubuntu-latest # This OS choice is arbitrary. None of the steps in this job are specific to either Linux or macOS.
steps:
- uses: actions/checkout@v2
# we don't want to release commits that have been pushed and tagged, but not necessarily merged onto main
- name: Ensure tagged commit is on main
run: |
echo "Tag: ${GITHUB_REF##*/}"
git fetch origin main
git merge-base --is-ancestor ${GITHUB_REF##*/} origin/main && echo "${GITHUB_REF##*/} is a commit on main!"
- name: Check static analysis results
uses: fountainhead/action-wait-for-check@v1.0.0
id: static-analysis
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Static analysis"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check unit test results
uses: fountainhead/action-wait-for-check@v1.0.0
id: unit
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Unit tests"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check integration test results
uses: fountainhead/action-wait-for-check@v1.0.0
id: integration
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Integration tests"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check acceptance test results (linux)
uses: fountainhead/action-wait-for-check@v1.0.0
id: acceptance-linux
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Acceptance tests (Linux)"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check acceptance test results (mac)
uses: fountainhead/action-wait-for-check@v1.0.0
id: acceptance-mac
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "Acceptance tests (Mac)"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Check cli test results (linux)
uses: fountainhead/action-wait-for-check@v1.0.0
id: cli-linux
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This check name is defined as the github action job name (in .github/workflows/testing.yaml)
checkName: "CLI tests (Linux)"
ref: ${{ github.event.pull_request.head.sha || github.sha }}
- name: Quality gate
if: steps.static-analysis.outputs.conclusion != 'success' || steps.unit.outputs.conclusion != 'success' || steps.integration.outputs.conclusion != 'success' || steps.cli-linux.outputs.conclusion != 'success' || steps.acceptance-linux.outputs.conclusion != 'success' || steps.acceptance-mac.outputs.conclusion != 'success'
run: |
echo "Static Analysis Status: ${{ steps.static-analysis.conclusion }}"
echo "Unit Test Status: ${{ steps.unit.outputs.conclusion }}"
echo "Integration Test Status: ${{ steps.integration.outputs.conclusion }}"
echo "Acceptance Test (Linux) Status: ${{ steps.acceptance-linux.outputs.conclusion }}"
echo "Acceptance Test (Mac) Status: ${{ steps.acceptance-mac.outputs.conclusion }}"
echo "CLI Test (Linux) Status: ${{ steps.cli-linux.outputs.conclusion }}"
false
release:
needs: [quality-gate]
runs-on: macos-latest # Due to our code signing process, it's vital that we run our release steps on macOS.
steps:
- uses: docker-practice/actions-setup-docker@v1
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Import GPG key
id: import_gpg
uses: crazy-max/ghaction-import-gpg@v2
env:
GPG_PRIVATE_KEY: ${{ secrets.SIGNING_GPG_PRIVATE_KEY }}
PASSPHRASE: ${{ secrets.SIGNING_GPG_PASSPHRASE }}
- name: GPG signing info
run: |
echo "fingerprint: ${{ steps.import_gpg.outputs.fingerprint }}"
echo "keyid: ${{ steps.import_gpg.outputs.keyid }}"
echo "name: ${{ steps.import_gpg.outputs.name }}"
echo "email: ${{ steps.import_gpg.outputs.email }}"
- name: Build & publish release artifacts
run: make release
env:
DOCKER_USERNAME: ${{ secrets.TOOLBOX_DOCKER_USER }}
DOCKER_PASSWORD: ${{ secrets.TOOLBOX_DOCKER_PASS }}
GITHUB_TOKEN: ${{ secrets.ANCHORE_GIT_READ_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.SIGNING_GPG_PRIVATE_KEY }}
PASSPHRASE: ${{ secrets.SIGNING_GPG_PASSPHRASE }}
SIGNING_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
AWS_ACCESS_KEY_ID: ${{ secrets.TOOLBOX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TOOLBOX_AWS_SECRET_ACCESS_KEY }}
APPLE_DEVELOPER_ID_CERT: ${{ secrets.APPLE_DEVELOPER_ID_CERT }} # Used during macOS code signing.
APPLE_DEVELOPER_ID_CERT_PASS: ${{ secrets.APPLE_DEVELOPER_ID_CERT_PASS }} # Used during macOS code signing.
AC_USERNAME: ${{ secrets.ENG_CI_APPLE_ID }} # Used during macOS notarization.
AC_PASSWORD: ${{ secrets.ENG_CI_APPLE_ID_PASS }} # Used during macOS notarization.
- uses: anchore/sbom-action@v0
with:
artifact-name: sbom.spdx.json
- uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,workflow,action,eventName
text: "A new Syft release is ready to be manually published: https://github.com/anchore/syft/releases"
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_TOOLBOX_WEBHOOK_URL }}
if: ${{ success() }}
- uses: actions/upload-artifact@v2
with:
name: artifacts
path: dist/**/*
+345
View File
@@ -0,0 +1,345 @@
name: "Validations"
on:
workflow_dispatch:
push:
pull_request:
env:
GO_VERSION: "1.16.x"
jobs:
Static-Analysis:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Static analysis"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Run static analysis
run: make static-analysis
Unit-Test:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Unit tests"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Build cache key for java test-fixture blobs (for unit tests)
run: make java-packages-fingerprint
- name: Restore Java test-fixture cache
id: unit-java-cache
uses: actions/cache@v2.1.3
with:
path: syft/pkg/cataloger/java/test-fixtures/java-builds/packages
key: ${{ runner.os }}-unit-java-cache-${{ hashFiles( 'syft/pkg/cataloger/java/test-fixtures/java-builds/packages.fingerprint' ) }}
- name: Run unit tests
run: make unit
- uses: actions/upload-artifact@v2
with:
name: unit-test-results
path: test/results/**/*
Integration-Test:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Integration tests"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Validate syft output against the CycloneDX schema
run: make validate-cyclonedx-schema
- name: Build key for tar cache
run: make integration-fingerprint
- name: Restore integration test cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/test/integration/test-fixtures/cache
key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('test/integration/test-fixtures/cache.fingerprint') }}
- name: Run integration tests
run: make integration
Benchmark-Test:
name: "Benchmark tests"
runs-on: ubuntu-20.04
# note: we want benchmarks to run on pull_request events in order to publish results to a sticky comment, and
# we also want to run on push such that merges to main are recorded to the cache. For this reason we don't filter
# the job by event.
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Bootstrap CI environment dependencies
run: make ci-bootstrap
- name: Restore base benchmark result
uses: actions/cache@v2
with:
path: test/results/benchmark-main.txt
# use base sha for PR or new commit hash for main push in benchmark result key
key: ${{ runner.os }}-bench-${{ (github.event.pull_request.base.sha != github.event.after) && github.event.pull_request.base.sha || github.event.after }}
- name: Run benchmark tests
id: benchmark
run: |
REF_NAME=${GITHUB_REF##*/} make benchmark
OUTPUT=$(make show-benchstat)
OUTPUT="${OUTPUT//'%'/'%25'}" # URL encode all '%' characters
OUTPUT="${OUTPUT//$'\n'/'%0A'}" # URL encode all '\n' characters
OUTPUT="${OUTPUT//$'\r'/'%0D'}" # URL encode all '\r' characters
echo "::set-output name=result::$OUTPUT"
- uses: actions/upload-artifact@v2
with:
name: benchmark-test-results
path: test/results/**/*
- name: Update PR benchmark results comment
uses: marocchino/sticky-pull-request-comment@v2
continue-on-error: true
with:
header: benchmark
message: |
### Benchmark Test Results
<details>
<summary>Benchmark results from the latest changes vs base branch</summary>
```
${{ steps.benchmark.outputs.result }}
```
</details>
Build-Snapshot-Artifacts:
name: "Build snapshot artifacts"
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Restore tool cache
id: tool-cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/.tmp
key: ${{ runner.os }}-tool-${{ hashFiles('Makefile') }}
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap all project dependencies
if: steps.tool-cache.outputs.cache-hit != 'true' || steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap
- name: Build snapshot artifacts
run: make snapshot
- uses: actions/upload-artifact@v2
with:
name: artifacts
path: snapshot/**/*
Acceptance-Linux:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Acceptance tests (Linux)"
needs: [Build-Snapshot-Artifacts]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
with:
name: artifacts
path: snapshot
- name: Run Acceptance Tests (Linux)
run: make acceptance-linux
Acceptance-Mac:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "Acceptance tests (Mac)"
needs: [Build-Snapshot-Artifacts]
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/download-artifact@v2
with:
name: artifacts
path: snapshot
- name: Restore docker image cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: image.tar
key: ${{ runner.os }}-${{ hashFiles('test/acceptance/mac.sh') }}
- name: Run Acceptance Tests (Mac)
run: make acceptance-mac
Cli-Linux:
# Note: changing this job name requires making the same update in the .github/workflows/release.yaml pipeline
name: "CLI tests (Linux)"
needs: [Build-Snapshot-Artifacts]
runs-on: ubuntu-20.04
steps:
- uses: actions/setup-go@v2
with:
go-version: ${{ env.GO_VERSION }}
- uses: actions/checkout@v2
- name: Restore go cache
id: go-cache
uses: actions/cache@v2.1.3
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ env.GO_VERSION }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ env.GO_VERSION }}-
- name: (cache-miss) Bootstrap go dependencies
if: steps.go-cache.outputs.cache-hit != 'true'
run: make bootstrap-go
- name: Build key for tar cache
run: make cli-fingerprint
- name: Restore CLI test cache
uses: actions/cache@v2.1.3
with:
path: ${{ github.workspace }}/test/cli/test-fixtures/cache
key: ${{ runner.os }}-cli-test-cache-${{ hashFiles('test/cli/test-fixtures/cache.fingerprint') }}
- uses: actions/download-artifact@v2
with:
name: artifacts
path: snapshot
- name: Run CLI Tests (Linux)
run: make cli
+20 -1
View File
@@ -1,4 +1,18 @@
CHANGELOG.md
/test/results
/dist
/snapshot
.server/
.vscode/
.history/
*.fingerprint
*.tar
*.jar
*.war
*.ear
*.jpi
*.hpi
*.zip
.idea/
*.log
.images
@@ -16,4 +30,9 @@ coverage.txt
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.out
# macOS Finder metadata
.DS_STORE
*.profile
+13 -6
View File
@@ -1,4 +1,9 @@
linter-settings:
# TODO: enable this when we have coverage on docstring comments
#issues:
# # The list of ids of default excludes to include or disable.
# include:
# - EXC0002 # disable excluding of issues about comments from golint
linters:
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
disable-all: true
@@ -10,6 +15,7 @@ linters:
- dogsled
- dupl
- errcheck
- exportloopref
- funlen
- gocognit
- goconst
@@ -17,19 +23,16 @@ linters:
- gocyclo
- gofmt
- goimports
- golint
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- maligned
- misspell
- nakedret
- nolintlint
- prealloc
- revive
- rowserrcheck
- scopelint
- staticcheck
- structcheck
- stylecheck
@@ -46,9 +49,13 @@ linters:
# - godot
# - godox
# - goerr113
# - golint # deprecated
# - gomnd # this is too aggressive
# - interfacer # this is a good idea, but is no longer supported and is prone to false positives
# - lll # without a way to specify per-line exception cases, this is not usable
# - maligned # this is an excellent linter, but tricky to optimize and we are not sensitive to memory layout optimizations
# - nestif
# - prealloc # following this rule isn't consistently a good idea, as it sometimes forces unnecessary allocations that result in less idiomatic code
# - scopelint # deprecated
# - testpackage
# - wsl
# - wsl # this doens't have an auto-fixer yet and is pretty noisy (https://github.com/bombsimon/wsl/issues/90)
+160
View File
@@ -0,0 +1,160 @@
release:
# If set to auto, will mark the release as not ready for production in case there is an indicator for this in the
# tag e.g. v1.0.0-rc1 .If set to true, will mark the release as not ready for production.
prerelease: auto
# If set to true, will not auto-publish the release. This is done to allow us to review the changelog before publishing.
draft: true
builds:
- binary: syft
id: syft
env:
- CGO_ENABLED=0
goos:
- linux
goarch:
- amd64
- arm64
# Set the modified timestamp on the output binary to the git timestamp (to ensure a reproducible build)
mod_timestamp: '{{ .CommitTimestamp }}'
ldflags: |
-w
-s
-extldflags '-static'
-X github.com/anchore/syft/internal/version.version={{.Version}}
-X github.com/anchore/syft/internal/version.gitCommit={{.Commit}}
-X github.com/anchore/syft/internal/version.buildDate={{.Date}}
-X github.com/anchore/syft/internal/version.gitTreeState={{.Env.BUILD_GIT_TREE_STATE}}
- binary: syft
id: syft-win
env:
- CGO_ENABLED=0
goos:
- windows
goarch:
- amd64
# Set the modified timestamp on the output binary to the git timestamp (to ensure a reproducible build)
mod_timestamp: '{{ .CommitTimestamp }}'
ldflags: |
-w
-s
-extldflags '-static'
-X github.com/anchore/syft/internal/version.version={{.Version}}
-X github.com/anchore/syft/internal/version.gitCommit={{.Commit}}
-X github.com/anchore/syft/internal/version.buildDate={{.Date}}
-X github.com/anchore/syft/internal/version.gitTreeState={{.Env.BUILD_GIT_TREE_STATE}}
# For more info on this macOS build, see: https://github.com/mitchellh/gon#usage-with-goreleaser
- binary: syft
id: syft-macos
env:
- CGO_ENABLED=0
goos:
- darwin
goarch:
- amd64
- arm64
# Set the modified timestamp on the output binary to the git timestamp (to ensure a reproducible build)
mod_timestamp: '{{ .CommitTimestamp }}'
ldflags: |
-w
-s
-extldflags '-static'
-X github.com/anchore/syft/internal/version.version={{.Version}}
-X github.com/anchore/syft/internal/version.gitCommit={{.Commit}}
-X github.com/anchore/syft/internal/version.buildDate={{.Date}}
-X github.com/anchore/syft/internal/version.gitTreeState={{.Env.BUILD_GIT_TREE_STATE}}
archives:
- format: tar.gz
builds:
- syft # i.e. Linux only
- format: zip # This is a hack for syft-macos! We don't actually intend to use _this_ ZIP file, we just need goreleaser to consider the ZIP file produced by gon (which will have the same file name) to be an artifact so we can use it downstream in publishing (e.g. to a homebrew tap)
id: syft-zip
builds:
- syft-macos
- syft-win
signs:
- artifacts: checksum
cmd: sh
args:
- '-c'
# we should not include the zip artifact, as the artifact is mutated throughout the next macOS notarization step
# note: sed -i is not portable
- 'sed "/.*\.zip/d" ${artifact} > tmpfile && mv tmpfile ${artifact} && gpg --output ${signature} --detach-sign ${artifact}'
- id: syft-macos-signing
ids:
- syft-macos
cmd: ./.github/scripts/mac-sign-and-notarize.sh
signature: "syft_${VERSION}_darwin_amd64.dmg" # This is somewhat unintuitive. This gets the DMG file recognized as an artifact. In fact, both a DMG and a ZIP file are being produced by this signing step.
args:
- "{{ .IsSnapshot }}"
- "gon.hcl"
- "./dist/syft_{{ .Version }}_darwin_amd64"
artifacts: all
nfpms:
- license: "Apache 2.0"
maintainer: "Anchore, Inc"
homepage: &website "https://github.com/anchore/syft"
description: &description "A tool that generates a Software Bill Of Materials (SBOM) from container images and filesystems"
formats:
- rpm
- deb
brews:
- tap:
owner: anchore
name: homebrew-syft
homepage: *website
description: *description
dockers:
- image_templates:
- "anchore/syft:latest"
- "anchore/syft:{{ .Tag }}-amd64"
- "anchore/syft:v{{ .Major }}-amd64"
- "anchore/syft:v{{ .Major }}.{{ .Minor }}-amd64"
dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--platform=linux/amd64"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
- image_templates:
- "anchore/syft:{{ .Tag }}-arm64v8"
- "anchore/syft:v{{ .Major }}-arm64v8"
- "anchore/syft:v{{ .Major }}.{{ .Minor }}-arm64v8"
goarch: arm64
dockerfile: Dockerfile
use: buildx
build_flag_templates:
- "--platform=linux/arm64/v8"
- "--build-arg=BUILD_DATE={{.Date}}"
- "--build-arg=BUILD_VERSION={{.Version}}"
- "--build-arg=VCS_REF={{.FullCommit}}"
- "--build-arg=VCS_URL={{.GitURL}}"
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
+108
View File
@@ -0,0 +1,108 @@
# Contributing to Syft
If you are looking to contribute to this project and want to open a GitHub pull request ("PR"), there are a few guidelines of what we are looking for in patches. Make sure you go through this document and ensure that your code proposal is aligned.
## Sign off your work
The `sign-off` is an added line at the end of the explanation for the commit, certifying that you wrote it or otherwise have the right to submit it as an open-source patch. By submitting a contribution, you agree to be bound by the terms of the DCO Version 1.1 and Apache License Version 2.0.
Signing off a commit certifies the below Developer's Certificate of Origin (DCO):
```text
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
All contributions to this project are licensed under the [Apache License Version 2.0, January 2004](http://www.apache.org/licenses/).
When committing your change, you can add the required line manually so that it looks like this:
```text
Signed-off-by: John Doe <john.doe@example.com>
```
Alternatively, configure your Git client with your name and email to use the `-s` flag when creating a commit:
```text
$ git config --global user.name "John Doe"
$ git config --global user.email "john.doe@example.com"
```
Creating a signed-off commit is then possible with `-s` or `--signoff`:
```text
$ git commit -s -m "this is a commit message"
```
To double-check that the commit was signed-off, look at the log output:
```text
$ git log -1
commit 37ceh170e4hb283bb73d958f2036ee5k07e7fde7 (HEAD -> issue-35, origin/main, main)
Author: John Doe <john.doe@example.com>
Date: Mon Aug 1 11:27:13 2020 -0400
this is a commit message
Signed-off-by: John Doe <john.doe@example.com>
```
[//]: # (TODO: Commit guidelines, granular commits)
[//]: # (TODO: Commit guidelines, descriptive messages)
[//]: # (TODO: Commit guidelines, commit title, extra body description)
[//]: # (TODO: PR title and description)
## Sign your commits
To ensure the authenticity and integrity of code contributions, **we require that all commits are signed**. Signing commits proves that your commits were truly created by you, as the holder of a private key.
Configuring git to sign your commits is a straightforward process. To get set up, see [GitHub's documentation on signing commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits).
## Test your changes
This project has a `Makefile` which includes many helpers running both unit and integration tests. Although PRs will have automatic checks for these, it is useful to run them locally, ensuring they pass before submitting changes. Ensure you've bootstrapped once before running tests:
```text
$ make bootstrap
```
You only need to bootstrap once. After the bootstrap process, you can run the tests as many times as needed:
```text
$ make unit
$ make integration
```
## Document your changes
When proposed changes are modifying user-facing functionality or output, it is expected the PR will include updates to the documentation as well.
+28
View File
@@ -0,0 +1,28 @@
FROM alpine:latest AS build
RUN apk --no-cache add ca-certificates
FROM scratch
# needed for version check HTTPS request
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
# create the /tmp dir, which is needed for image content cache
WORKDIR /tmp
COPY syft /
ARG BUILD_DATE
ARG BUILD_VERSION
ARG VCS_REF
ARG VCS_URL
LABEL org.label-schema.schema-version="1.0"
LABEL org.label-schema.build-date=$BUILD_DATE
LABEL org.label-schema.name="syft"
LABEL org.label-schema.description="CLI tool and library for generating a Software Bill of Materials from container images and filesystems"
LABEL org.label-schema.vcs-url=$VCS_URL
LABEL org.label-schema.vcs-ref=$VCS_REF
LABEL org.label-schema.vendor="Anchore, Inc."
LABEL org.label-schema.version=$BUILD_VERSION
ENTRYPOINT ["/syft"]
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+318 -39
View File
@@ -1,58 +1,337 @@
BIN = syft
TEMPDIR = ./.tmp
LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --config .golangci.yaml
BOLD := $(shell tput bold)
PURPLE := $(shell tput setaf 5)
GREEN := $(shell tput setaf 2)
RESET := $(shell tput sgr0)
RESULTSDIR = test/results
COVER_REPORT = $(RESULTSDIR)/unit-coverage-details.txt
COVER_TOTAL = $(RESULTSDIR)/unit-coverage-summary.txt
LINTCMD = $(TEMPDIR)/golangci-lint run --tests=false --timeout=2m --config .golangci.yaml
ACC_TEST_IMAGE = centos:8.2.2004
ACC_DIR = ./test/acceptance
BOLD := $(shell tput -T linux bold)
PURPLE := $(shell tput -T linux setaf 5)
GREEN := $(shell tput -T linux setaf 2)
CYAN := $(shell tput -T linux setaf 6)
RED := $(shell tput -T linux setaf 1)
RESET := $(shell tput -T linux sgr0)
TITLE := $(BOLD)$(PURPLE)
SUCCESS := $(BOLD)$(GREEN)
# the quality gate lower threshold for unit test total % coverage (by function statements)
COVERAGE_THRESHOLD := 62
# CI cache busting values; change these if you want CI to not use previous stored cache
INTEGRATION_CACHE_BUSTER="88738d2f"
CLI_CACHE_BUSTER="9a2c03cf"
BOOTSTRAP_CACHE="c7afb99ad"
ifndef TEMPDIR
$(error TEMPDIR is not set)
## Build variables
DISTDIR=./dist
SNAPSHOTDIR=./snapshot
GITTREESTATE=$(if $(shell git status --porcelain),dirty,clean)
OS := $(shell uname)
ifeq ($(OS),Darwin)
SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)-macos_darwin_amd64/$(BIN))
else
SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN))
endif
.PHONY: all boostrap lint lint-fix unit coverage integration build-release
ifeq "$(strip $(VERSION))" ""
override VERSION = $(shell git describe --always --tags --dirty)
endif
all: lint unit integration
## Variable assertions
ifndef TEMPDIR
$(error TEMPDIR is not set)
endif
ifndef RESULTSDIR
$(error RESULTSDIR is not set)
endif
ifndef ACC_DIR
$(error ACC_DIR is not set)
endif
ifndef DISTDIR
$(error DISTDIR is not set)
endif
ifndef SNAPSHOTDIR
$(error SNAPSHOTDIR is not set)
endif
ifndef REF_NAME
REF_NAME = $(VERSION)
endif
define title
@printf '$(TITLE)$(1)$(RESET)\n'
endef
## Tasks
.PHONY: all
all: clean static-analysis test ## Run all linux-based checks (linting, license check, unit, integration, and linux acceptance tests)
@printf '$(SUCCESS)All checks pass!$(RESET)\n'
bootstrap:
@printf '$(TITLE)Downloading dependencies$(RESET)\n'
# install project dependencies
go get ./...
mkdir -p $(TEMPDIR)
# install golangci-lint
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b .tmp/ v1.26.0
# install go-acc
GOPATH=$(shell realpath ${TEMPDIR}) GO111MODULE=off go get github.com/ory/go-acc
# cleanup
rm -rf $(TEMPDIR)/src
.PHONY: test
test: unit validate-cyclonedx-schema integration benchmark acceptance-linux cli ## Run all tests (currently unit, integration, linux acceptance, and cli tests)
lint:
@printf '$(TITLE)Running linters$(RESET)\n'
test -z "$(shell gofmt -l -s .)"
.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(BOLD)$(CYAN)%-25s$(RESET)%s\n", $$1, $$2}'
.PHONY: ci-bootstrap
ci-bootstrap:
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y bc jq libxml2-utils && go install github.com/neilpa/yajsv@latest
.PHONY:
ci-bootstrap-mac:
github_changelog_generator --version || sudo gem install github_changelog_generator
$(RESULTSDIR):
mkdir -p $(RESULTSDIR)
$(TEMPDIR):
mkdir -p $(TEMPDIR)
.PHONY: bootstrap-tools
bootstrap-tools: $(TEMPDIR)
GO111MODULE=off GOBIN=$(shell realpath $(TEMPDIR)) go get -u golang.org/x/perf/cmd/benchstat
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(TEMPDIR)/ v1.42.1
curl -sSfL https://raw.githubusercontent.com/wagoodman/go-bouncer/master/bouncer.sh | sh -s -- -b $(TEMPDIR)/ v0.2.0
curl -sSfL https://raw.githubusercontent.com/anchore/chronicle/main/install.sh | sh -s -- -b $(TEMPDIR)/ v0.3.0
.github/scripts/goreleaser-install.sh -b $(TEMPDIR)/ v0.177.0
.PHONY: bootstrap-go
bootstrap-go:
go mod download
.PHONY: bootstrap
bootstrap: $(RESULTSDIR) bootstrap-go bootstrap-tools ## Download and install all go dependencies (+ prep tooling in the ./tmp dir)
$(call title,Bootstrapping dependencies)
.PHONY: static-analysis
static-analysis: lint check-go-mod-tidy check-licenses
.PHONY: lint
lint: ## Run gofmt + golangci lint checks
$(call title,Running linters)
# ensure there are no go fmt differences
@printf "files with gofmt issues: [$(shell gofmt -l -s .)]\n"
@test -z "$(shell gofmt -l -s .)"
# run all golangci-lint rules
$(LINTCMD)
lint-fix:
@printf '$(TITLE)Running lint fixers$(RESET)\n'
# go tooling does not play well with certain filename characters, ensure the common cases don't result in future "go get" failures
$(eval MALFORMED_FILENAMES := $(shell find . | grep -e ':'))
@bash -c "[[ '$(MALFORMED_FILENAMES)' == '' ]] || (printf '\nfound unsupported filename characters:\n$(MALFORMED_FILENAMES)\n\n' && false)"
.PHONY: lint-fix
lint-fix: ## Auto-format all source code + run golangci lint fixers
$(call title,Running lint fixers)
gofmt -w -s .
$(LINTCMD) --fix
go mod tidy
unit:
@printf '$(TITLE)Running unit tests$(RESET)\n'
go test --race ./...
.PHONY: check-licenses
check-licenses: ## Ensure transitive dependencies are compliant with the current license policy
$(TEMPDIR)/bouncer check
coverage:
@printf '$(TITLE)Running unit tests + coverage$(RESET)\n'
$(TEMPDIR)/bin/go-acc -o $(TEMPDIR)/coverage.txt ./...
check-go-mod-tidy:
@ .github/scripts/go-mod-tidy-check.sh && echo "go.mod and go.sum are tidy!"
# TODO: add benchmarks
.PHONY: validate-cyclonedx-schema
validate-cyclonedx-schema:
cd schema/cyclonedx && make
integration:
@printf '$(TITLE)Running integration tests...$(RESET)\n'
go test -tags=integration ./integration
.PHONY: unit
unit: $(RESULTSDIR) fixtures ## Run unit tests (with coverage)
$(call title,Running unit tests)
go test -coverprofile $(COVER_REPORT) $(shell go list ./... | grep -v anchore/syft/test)
@go tool cover -func $(COVER_REPORT) | grep total | awk '{print substr($$3, 1, length($$3)-1)}' > $(COVER_TOTAL)
@echo "Coverage: $$(cat $(COVER_TOTAL))"
@if [ $$(echo "$$(cat $(COVER_TOTAL)) >= $(COVERAGE_THRESHOLD)" | bc -l) -ne 1 ]; then echo "$(RED)$(BOLD)Failed coverage quality gate (> $(COVERAGE_THRESHOLD)%)$(RESET)" && false; fi
build-release:
go build -s -w -X main.version="$(git describe --tags --dirty --always)" \
-X main.commit="$(git describe --dirty --always)" \
-X main.buildTime="$(date --rfc-3339=seconds --utc)"
.PHONY: benchmark
benchmark: $(RESULTSDIR) ## Run benchmark tests and compare against the baseline (if available)
$(call title,Running benchmark tests)
go test -p 1 -run=^Benchmark -bench=. -count=5 -benchmem ./... | tee $(RESULTSDIR)/benchmark-$(REF_NAME).txt
(test -s $(RESULTSDIR)/benchmark-main.txt && \
$(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-main.txt $(RESULTSDIR)/benchmark-$(REF_NAME).txt || \
$(TEMPDIR)/benchstat $(RESULTSDIR)/benchmark-$(REF_NAME).txt) \
| tee $(RESULTSDIR)/benchstat.txt
.PHONY: show-benchstat
show-benchstat:
@cat $(RESULTSDIR)/benchstat.txt
.PHONY: integration
integration: ## Run integration tests
$(call title,Running integration tests)
go test -v ./test/integration
# note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted
integration-fingerprint:
find test/integration/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/integration/test-fixtures/cache.fingerprint && echo "$(INTEGRATION_CACHE_BUSTER)" >> test/integration/test-fixtures/cache.fingerprint
.PHONY: java-packages-fingerprint
java-packages-fingerprint:
@cd syft/pkg/cataloger/java/test-fixtures/java-builds && \
make packages.fingerprint
.PHONY: fixtures
fixtures:
$(call title,Generating test fixtures)
cd syft/pkg/cataloger/java/test-fixtures/java-builds && make
.PHONY: generate-json-schema
generate-json-schema: ## Generate a new json schema
cd schema/json && go run generate.go
.PHONY: generate-license-list
generate-license-list: ## Generate an updated spdx license list
go generate ./internal/spdxlicense/...
gofmt -s -w ./internal/spdxlicense
.PHONY: build
build: $(SNAPSHOTDIR) ## Build release snapshot binaries and packages
$(SNAPSHOTDIR): ## Build snapshot release binaries and packages
$(call title,Building snapshot artifacts)
# create a config with the dist dir overridden
echo "dist: $(SNAPSHOTDIR)" > $(TEMPDIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
# build release snapshots
# DOCKER_CLI_EXPERIMENTAL needed to support multi architecture builds for goreleaser
BUILD_GIT_TREE_STATE=$(GITTREESTATE) \
DOCKER_CLI_EXPERIMENTAL=enabled \
$(TEMPDIR)/goreleaser release --skip-publish --skip-sign --rm-dist --snapshot --config $(TEMPDIR)/goreleaser.yaml
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
.PHONY: acceptance-mac
acceptance-mac: $(RESULTSDIR) $(SNAPSHOTDIR) ## Run acceptance tests on build snapshot binaries and packages (Mac)
$(call title,Running acceptance test: Run on Mac)
$(ACC_DIR)/mac.sh \
$(SNAPSHOTDIR) \
$(ACC_DIR) \
$(ACC_TEST_IMAGE) \
$(RESULTSDIR)
# note: we cannot clean the snapshot directory since the pipeline builds the snapshot separately
.PHONY: acceptance-linux
acceptance-linux: acceptance-test-deb-package-install acceptance-test-rpm-package-install ## Run acceptance tests on build snapshot binaries and packages (Linux)
.PHONY: acceptance-test-deb-package-install
acceptance-test-deb-package-install: $(RESULTSDIR) $(SNAPSHOTDIR)
$(call title,Running acceptance test: DEB install)
$(ACC_DIR)/deb.sh \
$(SNAPSHOTDIR) \
$(ACC_DIR) \
$(ACC_TEST_IMAGE) \
$(RESULTSDIR)
.PHONY: acceptance-test-rpm-package-install
acceptance-test-rpm-package-install: $(RESULTSDIR) $(SNAPSHOTDIR)
$(call title,Running acceptance test: RPM install)
$(ACC_DIR)/rpm.sh \
$(SNAPSHOTDIR) \
$(ACC_DIR) \
$(ACC_TEST_IMAGE) \
$(RESULTSDIR)
# note: this is used by CI to determine if the integration test fixture cache (docker image tars) should be busted
cli-fingerprint:
find test/cli/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/cli/test-fixtures/cache.fingerprint && echo "$(CLI_CACHE_BUSTER)" >> test/cli/test-fixtures/cache.fingerprint
.PHONY: cli
cli: $(SNAPSHOTDIR) ## Run CLI tests
chmod 755 "$(SNAPSHOT_CMD)"
$(SNAPSHOT_CMD) version
SYFT_BINARY_LOCATION='$(SNAPSHOT_CMD)' \
go test -count=1 -v ./test/cli
.PHONY: changelog
changelog: clean-changelog CHANGELOG.md
@docker run -it --rm \
-v $(shell pwd)/CHANGELOG.md:/CHANGELOG.md \
rawkode/mdv \
-t 748.5989 \
/CHANGELOG.md
CHANGELOG.md:
$(TEMPDIR)/chronicle -vv > CHANGELOG.md
.PHONY: release
release: clean-dist CHANGELOG.md ## Build and publish final binaries and packages. Intended to be run only on macOS.
$(call title,Publishing release artifacts)
# Prepare for macOS-specific signing process
.github/scripts/mac-prepare-for-signing.sh
# login to docker
# note: the previous step creates a new keychain, so it is important to reauth into docker.io
@echo $${DOCKER_PASSWORD} | docker login docker.io -u $${DOCKER_USERNAME} --password-stdin
# create a config with the dist dir overridden
echo "dist: $(DISTDIR)" > $(TEMPDIR)/goreleaser.yaml
cat .goreleaser.yaml >> $(TEMPDIR)/goreleaser.yaml
# release (note the version transformation from v0.7.0 --> 0.7.0)
# DOCKER_CLI_EXPERIMENTAL needed to support multi architecture builds for goreleaser
bash -c "\
BUILD_GIT_TREE_STATE=$(GITTREESTATE) \
VERSION=$(VERSION:v%=%) \
DOCKER_CLI_EXPERIMENTAL=enabled \
$(TEMPDIR)/goreleaser \
--rm-dist \
--config $(TEMPDIR)/goreleaser.yaml \
--release-notes <(cat CHANGELOG.md)"
# verify checksum signatures
.github/scripts/verify-signature.sh "$(DISTDIR)"
# upload the version file that supports the application version update check (excluding pre-releases)
.github/scripts/update-version-file.sh "$(DISTDIR)" "$(VERSION)"
.PHONY: clean
clean: clean-dist clean-snapshot clean-test-image-cache ## Remove previous builds, result reports, and test cache
rm -rf $(RESULTSDIR)/*
.PHONY: clean-snapshot
clean-snapshot:
rm -rf $(SNAPSHOTDIR) $(TEMPDIR)/goreleaser.yaml
.PHONY: clean-dist
clean-dist: clean-changelog
rm -rf $(DISTDIR) $(TEMPDIR)/goreleaser.yaml
.PHONY: clean-changelog
clean-changelog:
rm -f CHANGELOG.md
clean-test-image-cache: clean-test-image-tar-cache clean-test-image-docker-cache
.PHONY: clear-test-image-tar-cache
clean-test-image-tar-cache: ## Delete all test cache (built docker image tars)
find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" -delete
.PHONY: clear-test-image-docker-cache
clean-test-image-docker-cache: ## Purge all test docker images
docker images --format '{{.ID}} {{.Repository}}' | grep stereoscope-fixture- | awk '{print $$1}' | uniq | xargs docker rmi --force
.PHONY: show-test-image-cache
show-test-image-cache: ## Show all docker and image tar cache
$(call title,Docker daemon cache)
@docker images --format '{{.ID}} {{.Repository}}:{{.Tag}}' | grep stereoscope-fixture- | sort
$(call title,Tar cache)
@find . -type f -wholename "**/test-fixtures/cache/stereoscope-fixture-*.tar" | sort
.PHONY: show-test-snapshots
show-test-snapshots: ## Show all test snapshots
$(call title,Test snapshots)
@find . -type f -wholename "**/test-fixtures/snapshot/*" | sort
+366 -1
View File
@@ -1 +1,366 @@
# imgbom (TBD Name)
<p align="center">
<img src="https://user-images.githubusercontent.com/5199289/136844524-1527b09f-c5cb-4aa9-be54-5aa92a6086c1.png" width="271" alt="Cute pink owl syft logo">
</p>
[![Validations](https://github.com/anchore/syft/actions/workflows/validations.yaml/badge.svg)](https://github.com/anchore/syft/actions/workflows/validations.yaml)
[![Go Report Card](https://goreportcard.com/badge/github.com/anchore/syft)](https://goreportcard.com/report/github.com/anchore/syft)
[![GitHub release](https://img.shields.io/github/release/anchore/syft.svg)](https://github.com/anchore/syft/releases/latest)
[![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/anchore/syft.svg)](https://github.com/anchore/syft)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/anchore/syft/blob/main/LICENSE)
[![Slack Invite](https://img.shields.io/badge/Slack-Join-blue?logo=slack)](https://anchore.com/slack)
A CLI tool and Go library for generating a Software Bill of Materials (SBOM) from container images and filesystems. Exceptional for vulnerability detection when used with a scanner tool like [Grype](https://github.com/anchore/grype).
### Join our community meetings!
- Calendar: https://calendar.google.com/calendar/u/0/r?cid=Y182OTM4dGt0MjRtajI0NnNzOThiaGtnM29qNEBncm91cC5jYWxlbmRhci5nb29nbGUuY29t
- Agenda: https://docs.google.com/document/d/1ZtSAa6fj2a6KRWviTn3WoJm09edvrNUp4Iz_dOjjyY8/edit?usp=sharing (join [this group](https://groups.google.com/g/anchore-oss-community) for write access)
- All are welcome!
![syft-demo](https://user-images.githubusercontent.com/590471/90277200-2a253000-de33-11ea-893f-32c219eea11a.gif)
## Features
- Catalog container images and filesystems to discover packages and libraries.
- Supports packages and libraries from various ecosystems (APK, DEB, RPM, Ruby Bundles, Python Wheel/Egg/requirements.txt, JavaScript NPM/Yarn, Java JAR/EAR/WAR, Jenkins plugins JPI/HPI, Go modules)
- Linux distribution identification (supports Alpine, BusyBox, CentOS/RedHat, Debian/Ubuntu flavored distributions)
- Supports Docker and OCI image formats
- Direct support for [Grype](https://github.com/anchore/grype), a fast and powerful vulnerability matcher.
If you encounter an issue, please [let us know using the issue tracker](https://github.com/anchore/syft/issues).
## Installation
### Recommended
```bash
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
```
...or, you can specify a release version and destination directory for the installation:
```
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b <DESTINATION_DIR> <RELEASE_VERSION>
```
### Homebrew
```bash
brew tap anchore/syft
brew install syft
```
**Note**: Currently, Syft is built only for macOS and Linux.
## Getting started
To generate an SBOM for a Docker or OCI image:
```
syft <image>
```
**Note**: This is equivalent to specifying the `packages` subcommand:
```
syft packages <image>
```
The above output includes only software that is visible in the container (i.e., the squashed representation of the image).
To include software from all image layers in the SBOM, regardless of its presence in the final image, provide `--scope all-layers`:
```
syft packages <image> --scope all-layers
```
### Supported sources
Syft can generate a SBOM from a variety of sources:
```
# catalog a container image archive (from the result of `docker image save ...`, `podman save ...`, or `skopeo copy` commands)
syft packages path/to/image.tar
# catalog a directory
syft packages path/to/dir
```
Sources can be explicitly provided with a scheme:
```
docker:yourrepo/yourimage:tag use images from the Docker daemon
docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
dir:path/to/yourproject read directly from a path on disk (any directory)
file:path/to/yourproject/file read directly from a path on disk (any single file)
registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
```
### Output formats
The output format for Syft is configurable as well:
```
syft packages <image> -o <format>
```
Where the `formats` available are:
- `json`: Use this to get as much information out of Syft as possible!
- `text`: A row-oriented, human-and-machine-friendly output.
- `cyclonedx`: A XML report conforming to the [CycloneDX 1.2 specification](https://cyclonedx.org/specification/overview/).
- `spdx`: A tag-value formatted report conforming to the [SPDX 2.2 specification](https://spdx.github.io/spdx-spec/).
- `spdx-json`: A JSON report conforming to the [SPDX 2.2 JSON Schema](https://github.com/spdx/spdx-spec/blob/v2.2/schemas/spdx-schema.json).
- `table`: A columnar summary (default).
## Private Registry Authentication
### Local Docker Credentials
When a container runtime is not present, Syft can still utilize credentials configured in common credential sources (such as `~/.docker/config.json`).
It will pull images from private registries using these credentials. The config file is where your credentials are stored when authenticating with private registries via some command like `docker login`.
For more information see the `go-containerregistry` [documentation](https://github.com/google/go-containerregistry/tree/main/pkg/authn).
An example `config.json` looks something like this:
```
// config.json
{
"auths": {
"registry.example.com": {
"username": "AzureDiamond",
"password": "hunter2"
}
}
}
```
You can run the following command as an example. It details the mount/environment configuration a container needs to access a private registry:
`docker run -v ./config.json:/config/config.json -e "DOCKER_CONFIG=/config" anchore/syft:latest <private_image>`
### Docker Credentials in Kubernetes
The below section shows a simple workflow on how to mount this config file as a secret into a container on kubernetes.
1. Create a secret. The value of `config.json` is important. It refers to the specification detailed [here](https://github.com/google/go-containerregistry/tree/main/pkg/authn#the-config-file).
Below this section is the `secret.yaml` file that the pod configuration will consume as a volume.
The key `config.json` is important. It will end up being the name of the file when mounted into the pod.
```
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: registry-config
namespace: syft
data:
config.json: <base64 encoded config.json>
```
`kubectl apply -f secret.yaml`
2. Create your pod running syft. The env `DOCKER_CONFIG` is important because it advertises where to look for the credential file.
In the below example, setting `DOCKER_CONFIG=/config` informs syft that credentials can be found at `/config/config.json`.
This is why we used `config.json` as the key for our secret. When mounted into containers the secrets' key is used as the filename.
The `volumeMounts` section mounts our secret to `/config`. The `volumes` section names our volume and leverages the secret we created in step one.
```
# pod.yaml
apiVersion: v1
kind: Pod
spec:
containers:
- image: anchore/syft:latest
name: syft-private-registry-demo
env:
- name: DOCKER_CONFIG
value: /config
volumeMounts:
- mountPath: /config
name: registry-config
readOnly: true
args:
- <private_image>
volumes:
- name: registry-config
secret:
secretName: registry-config
```
`kubectl apply -f pod.yaml`
3. The user can now run `kubectl logs syft-private-registry-demo`. The logs should show the syft analysis for the `<private_image>` provided in the pod configuration.
Using the above information, users should be able to configure private registry access without having to do so in the `grype` or `syft` configuration files.
They will also not be dependent on a docker daemon, (or some other runtime software) for registry configuration and access.
## Configuration
Configuration search paths:
- `.syft.yaml`
- `.syft/config.yaml`
- `~/.syft.yaml`
- `<XDG_CONFIG_HOME>/syft/config.yaml`
Configuration options (example values are the default):
```yaml
# the output format of the SBOM report (options: table, text, json)
# same as -o ; SYFT_OUTPUT env var
output: "table"
# suppress all output (except for the SBOM report)
# same as -q ; SYFT_QUIET env var
quiet: false
# same as --file; write output report to a file (default is to write to stdout)
file: ""
# enable/disable checking for application updates on startup
# same as SYFT_CHECK_FOR_APP_UPDATE env var
check-for-app-update: true
# cataloging packages is exposed through the packages and power-user subcommands
package:
cataloger:
# enable/disable cataloging of packages
# SYFT_PACKAGE_CATALOGER_ENABLED env var
enabled: true
# the search space to look for packages (options: all-layers, squashed)
# same as -s ; SYFT_PACKAGE_CATALOGER_SCOPE env var
scope: "squashed"
# cataloging file classifications is exposed through the power-user subcommand
file-classification:
cataloger:
# enable/disable cataloging of file classifications
# SYFT_FILE_CLASSIFICATION_CATALOGER_ENABLED env var
enabled: true
# the search space to look for file classifications (options: all-layers, squashed)
# SYFT_FILE_CLASSIFICATION_CATALOGER_SCOPE env var
scope: "squashed"
# cataloging file contents is exposed through the power-user subcommand
file-contents:
cataloger:
# enable/disable cataloging of secrets
# SYFT_FILE_CONTENTS_CATALOGER_ENABLED env var
enabled: true
# the search space to look for secrets (options: all-layers, squashed)
# SYFT_FILE_CONTENTS_CATALOGER_SCOPE env var
scope: "squashed"
# skip searching a file entirely if it is above the given size (default = 1MB; unit = bytes)
# SYFT_FILE_CONTENTS_SKIP_FILES_ABOVE_SIZE env var
skip-files-above-size: 1048576
# file globs for the cataloger to match on
# SYFT_FILE_CONTENTS_GLOBS env var
globs: []
# cataloging file metadata is exposed through the power-user subcommand
file-metadata:
cataloger:
# enable/disable cataloging of file metadata
# SYFT_FILE_METADATA_CATALOGER_ENABLED env var
enabled: true
# the search space to look for file metadata (options: all-layers, squashed)
# SYFT_FILE_METADATA_CATALOGER_SCOPE env var
scope: "squashed"
# the file digest algorithms to use when cataloging files (options: "sha256", "md5", "sha1")
# SYFT_FILE_METADATA_DIGESTS env var
digests: ["sha256"]
# cataloging secrets is exposed through the power-user subcommand
secrets:
cataloger:
# enable/disable cataloging of secrets
# SYFT_SECRETS_CATALOGER_ENABLED env var
enabled: true
# the search space to look for secrets (options: all-layers, squashed)
# SYFT_SECRETS_CATALOGER_SCOPE env var
scope: "all-layers"
# show extracted secret values in the final JSON report
# SYFT_SECRETS_REVEAL_VALUES env var
reveal-values: false
# skip searching a file entirely if it is above the given size (default = 1MB; unit = bytes)
# SYFT_SECRETS_SKIP_FILES_ABOVE_SIZE env var
skip-files-above-size: 1048576
# name-regex pairs to consider when searching files for secrets. Note: the regex must match single line patterns
# but may also have OPTIONAL multiline capture groups. Regexes with a named capture group of "value" will
# use the entire regex to match, but the secret value will be assumed to be entirely contained within the
# "value" named capture group.
additional-patterns: {}
# names to exclude from the secrets search, valid values are: "aws-access-key", "aws-secret-key", "pem-private-key",
# "docker-config-auth", and "generic-api-key". Note: this does not consider any names introduced in the
# "secrets.additional-patterns" config option.
# SYFT_SECRETS_EXCLUDE_PATTERN_NAMES env var
exclude-pattern-names: []
# options when pulling directly from a registry via the "registry:" scheme
registry:
# skip TLS verification when communicating with the registry
# SYFT_REGISTRY_INSECURE_SKIP_TLS_VERIFY env var
insecure-skip-tls-verify: false
# use http instead of https when connecting to the registry
# SYFT_REGISTRY_INSECURE_USE_HTTP env var
insecure-use-http: false
# credentials for specific registries
auth:
- # the URL to the registry (e.g. "docker.io", "localhost:5000", etc.)
# SYFT_REGISTRY_AUTH_AUTHORITY env var
authority: ""
# SYFT_REGISTRY_AUTH_USERNAME env var
username: ""
# SYFT_REGISTRY_AUTH_PASSWORD env var
password: ""
# note: token and username/password are mutually exclusive
# SYFT_REGISTRY_AUTH_TOKEN env var
token: ""
- ... # note, more credentials can be provided via config file only
log:
# use structured logging
# same as SYFT_LOG_STRUCTURED env var
structured: false
# the log level; note: detailed logging suppress the ETUI
# same as SYFT_LOG_LEVEL env var
level: "error"
# location to write the log file (default is not to have a log file)
# same as SYFT_LOG_FILE env var
file: ""
# uploading package SBOM is exposed through the packages subcommand
anchore:
# (feature-preview) the Anchore Enterprise Host or URL to upload results to (supported on Enterprise 3.0+)
# same as -H ; SYFT_ANCHORE_HOST env var
host: ""
# (feature-preview) the path after the host to the Anchore External API (supported on Enterprise 3.0+)
# same as SYFT_ANCHORE_PATH env var
path: ""
# (feature-preview) the username to authenticate against Anchore Enterprise (supported on Enterprise 3.0+)
# same as -u ; SYFT_ANCHORE_USERNAME env var
username: ""
# (feature-preview) the password to authenticate against Anchore Enterprise (supported on Enterprise 3.0+)
# same as -p ; SYFT_ANCHORE_PASSWORD env var
password: ""
# (feature-preview) path to dockerfile to be uploaded with the syft results to Anchore Enterprise (supported on Enterprise 3.0+)
# same as -d ; SYFT_ANCHORE_DOCKERFILE env var
dockerfile: ""
```
+104
View File
@@ -0,0 +1,104 @@
# Release Process
A good release process has the following qualities:
1. There is a way to plan what should be in a release
1. There is a way to see what is actually in a release
1. Allow for different kinds of releases (major breaking vs backwards compatible
enhancements vs patch updates)
1. Specify a repeatable way to build and publish software artifacts
## Planning a release
To indicate a set of features to be released together add each issue to an in-repository
Milestone named with major-minor version to be released (e.g. `v0.1`). It is OK for other
features to be in the release that were not originally planned, and these issues and PRs
do not need to be added to the Milestone in question. Only the set of features that, when
completed, would allow the release to be considered complete. A Milestone is only used to:
- Plan what is desired to be in a release
- Track progress to indicate when we may be ready to cut a new release
Not all releases need to be planned. For instance, patch releases for fixes should be
released when they are ready and when releasing would not interfere with another current
release (where some partial or breaking features have already been merged). Beta releases
and release candidates should not be independently planned from the non-beta release. That
is, the features for a `v0.1-beta.1` release should be planned under the `v0.1` Milestone,
not under a separate `v0.1-beta.1` Milestone.
Unless necessary, feature releases should be small and frequent, which may obviate the
need for regular release planning under a Milestone.
## What is in a release
Milestones are specifically for planning a release, not necessarily tracking all changes
that a release may bring (and more importantly, not all releases are necessarily planned
either).
This is one of the (many) reasons for a Changelog. A good Changelog lists changes grouped
by the type of change (new, enhancement, deprecation, breaking, bug fix, security fix), in
chronological order (within groups), linking the PR where the change was made in the
Changelog line. Furthermore, there should be a place to see all released versions, the
release date for each release, the semantic version of the release, and the set of changes
for each release.
This project auto-generates the Changelog contents for each current release and posts the
generated contents to the GitHub Release page. Leveraging the GitHub Releases feature
allows GitHub to manage the Changelog on each release outside of the git repository while
still being hosted with the released assets.
The Changelog is generated from the metadata from in-repository issues and PRs, using
labels to guide what kind of change each item is (e.g. breaking, new feature, bug fix,
etx). Only issues/PRs with select labels are included in the Changelog, and only if the
issue/PR was created after the last release. Additional labels are used to exclude items
from the Changelog.
The above suggestions imply that we should:
- Ensure there is a sufficient title for each PR and issue title to be included in the
Changelog
- The appropriate label is applied to PRs and/or issues to drive specific change type
sections (deprecated, breaking, security, bug, etc)
With this approach as we cultivate good organization of PRs and issues we automatically
get an equally good Changelog.
## Major, minor, and patch releases
The latest version of the tool is the only supported version, which implies that multiple
parallel release branches will not be a regular process (if ever). Multiple releases can
be planned in parallel, however, only one can be actively developed at a time. That is, if
PRs attached to a release Milestone have been merged into the main branch, that release is
now the "next" release. This implies that the source of truth for release lies with the
git log and Changelog, not with the release Milestones (which are purely for planning and
tracking).
Semantic versioning should be used to indicate breaking changes, new features, and fixes.
The exception to this is `< 1.0`, where the major version is not bumped for breaking changes,
instead the minor version indicates both new features and breaking changes.
## Cutting a release
Ideally releasing should be done often with small increments when possible. Unless a
breaking change is blocking the release, or no fixes/features have been merged, a good
target release cadence is between every 2 or 4 weeks.
This release process itself should be as automated as possible, and have only a few steps:
1. Tag the main branch with a full semantic-version, prefixed with a `v`. If there is a
milestone with a partial version, the full version should be used for the git tag (e.g.
with a Milestone of `v0.1` the tag should be `v0.1.0`). You can determine the changes going
into a release by running `make changelog-unreleased`. Use this change list to determine the
release increment. After determining the release increment (major, minor, patch), create the tag.
Given the above example the command to create the tag would be `git tag v0.1.0`.
1. Push the tag. Given the above example the command to push the tag would be `git push origin v0.1.0`.
1. A release admin must approve the release on the GitHub Actions release pipeline run page.
Once approved, the release pipeline will generate all assets and draft a GitHub Release.
1. Navigate to the GitHub Release draft page to review the final changelog and publish the
release. Once published, a release-follow-up pipeline will publish derivative artifacts
(docker image to DockerHub, brew formula to the external homebrew git repo, etc).
1. If there is a release Milestone, close it.
+30
View File
@@ -0,0 +1,30 @@
package cmd
import (
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft/event"
"github.com/wagoodman/go-partybus"
)
func checkForApplicationUpdate() {
if appConfig.CheckForAppUpdate {
isAvailable, newVersion, err := version.IsUpdateAvailable()
if err != nil {
// this should never stop the application
log.Errorf(err.Error())
}
if isAvailable {
log.Infof("new version of %s is available: %s (current version is %s)", internal.ApplicationName, newVersion, version.FromBuild().Version)
bus.Publish(partybus.Event{
Type: event.AppUpdateAvailable,
Value: newVersion,
})
} else {
log.Debugf("no new %s update available", internal.ApplicationName)
}
}
}
-50
View File
@@ -1,50 +0,0 @@
package cmd
import (
"fmt"
"os"
"github.com/anchore/imgbom/imgbom/presenter"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/imgbom/internal/config"
"github.com/spf13/viper"
)
var cliOpts = config.CliOnlyOptions{}
func setCliOptions() {
rootCmd.PersistentFlags().StringVarP(&cliOpts.ConfigPath, "config", "c", "", "application config file")
// scan options
flag := "scope"
rootCmd.Flags().StringP(
"scope", "s", scope.AllLayersScope.String(),
fmt.Sprintf("selection of layers to analyze, options=%v", scope.Options))
if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil {
fmt.Printf("unable to bind flag '%s': %+v", flag, err)
os.Exit(1)
}
// output & formatting options
flag = "output"
rootCmd.Flags().StringP(
flag, "o", presenter.JSONPresenter.String(),
fmt.Sprintf("report output formatter, options=%v", presenter.Options),
)
if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil {
fmt.Printf("unable to bind flag '%s': %+v", flag, err)
os.Exit(1)
}
flag = "quiet"
rootCmd.Flags().BoolP(
flag, "q", false,
"suppress all logging output",
)
if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil {
fmt.Printf("unable to bind flag '%s': %+v", flag, err)
os.Exit(1)
}
rootCmd.Flags().CountVarP(&cliOpts.Verbosity, "verbose", "v", "increase verbosity (-v = info, -vv = debug)")
}
+112
View File
@@ -0,0 +1,112 @@
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/anchore/stereoscope"
"github.com/anchore/syft/internal/config"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/logger"
"github.com/anchore/syft/syft"
"github.com/gookit/color"
"github.com/spf13/viper"
"github.com/wagoodman/go-partybus"
)
var (
appConfig *config.Application
eventBus *partybus.Bus
eventSubscription *partybus.Subscription
)
func init() {
cobra.OnInitialize(
initCmdAliasBindings,
initAppConfig,
initLogging,
logAppConfig,
initEventBus,
)
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, color.Red.Sprint(err.Error()))
os.Exit(1)
}
}
// we must setup the config-cli bindings first before the application configuration is parsed. However, this cannot
// be done without determining what the primary command that the config options should be bound to since there are
// shared concerns (the root-packages alias).
func initCmdAliasBindings() {
activeCmd, _, err := rootCmd.Find(os.Args[1:])
if err != nil {
panic(err)
}
// enable all cataloger by default if power-user command is run
if activeCmd == powerUserCmd {
config.PowerUserCatalogerEnabledDefault()
}
switch activeCmd {
case packagesCmd, rootCmd:
// note: we need to lazily bind config options since they are shared between both the root command
// and the packages command. Otherwise there will be global viper state that is in contention.
// See for more details: https://github.com/spf13/viper/issues/233 . Additionally, the bindings must occur BEFORE
// reading the application configuration, which implies that it must be an initializer (or rewrite the command
// initialization structure against typical patterns used with cobra, which is somewhat extreme for a
// temporary alias)
if err = bindPackagesConfigOptions(activeCmd.Flags()); err != nil {
panic(err)
}
default:
// even though the root command or packages command is NOT being run, we still need default bindings
// such that application config parsing passes.
if err = bindPackagesConfigOptions(packagesCmd.Flags()); err != nil {
panic(err)
}
}
}
func initAppConfig() {
cfg, err := config.LoadApplicationConfig(viper.GetViper(), persistentOpts)
if err != nil {
fmt.Printf("failed to load application config: \n\t%+v\n", err)
os.Exit(1)
}
appConfig = cfg
}
func initLogging() {
cfg := logger.LogrusConfig{
EnableConsole: (appConfig.Log.FileLocation == "" || appConfig.CliOptions.Verbosity > 0) && !appConfig.Quiet,
EnableFile: appConfig.Log.FileLocation != "",
Level: appConfig.Log.LevelOpt,
Structured: appConfig.Log.Structured,
FileLocation: appConfig.Log.FileLocation,
}
logWrapper := logger.NewLogrusLogger(cfg)
syft.SetLogger(logWrapper)
stereoscope.SetLogger(&logger.LogrusNestedLogger{
Logger: logWrapper.Logger.WithField("from-lib", "stereoscope"),
})
}
func logAppConfig() {
log.Debugf("application config:\n%+v", color.Magenta.Sprint(appConfig.String()))
}
func initEventBus() {
eventBus = partybus.NewBus()
eventSubscription = eventBus.Subscribe()
stereoscope.SetBus(eventBus)
syft.SetBus(eventBus)
}
+113
View File
@@ -0,0 +1,113 @@
package cmd
import (
"context"
"os"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/spf13/cobra"
)
// completionCmd represents the completion command
var completionCmd = &cobra.Command{
Use: "completion [bash|zsh|fish]",
Short: "Generate a shell completion for Syft (listing local docker images)",
Long: `To load completions (docker image list):
Bash:
$ source <(syft completion bash)
# To load completions for each session, execute once:
Linux:
$ syft completion bash > /etc/bash_completion.d/syft
MacOS:
$ syft completion bash > /usr/local/etc/bash_completion.d/syft
Zsh:
# If shell completion is not already enabled in your environment you will need
# to enable it. You can execute the following once:
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
# To load completions for each session, execute once:
$ syft completion zsh > "${fpath[1]}/_syft"
# You will need to start a new shell for this setup to take effect.
Fish:
$ syft completion fish | source
# To load completions for each session, execute once:
$ syft completion fish > ~/.config/fish/completions/syft.fish
`,
DisableFlagsInUseLine: true,
ValidArgs: []string{"bash", "zsh", "fish"},
Args: cobra.ExactValidArgs(1),
Run: func(cmd *cobra.Command, args []string) {
var err error
switch args[0] {
case "bash":
err = cmd.Root().GenBashCompletion(os.Stdout)
case "zsh":
err = cmd.Root().GenZshCompletion(os.Stdout)
case "fish":
err = cmd.Root().GenFishCompletion(os.Stdout, true)
}
if err != nil {
panic(err)
}
},
}
func init() {
rootCmd.AddCommand(completionCmd)
}
func dockerImageValidArgsFunction(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// Since we use ValidArgsFunction, Cobra will call this AFTER having parsed all flags and arguments provided
dockerImageRepoTags, err := listLocalDockerImages(toComplete)
if err != nil {
// Indicates that an error occurred and completions should be ignored
return []string{"completion failed"}, cobra.ShellCompDirectiveError
}
if len(dockerImageRepoTags) == 0 {
return []string{"no docker images found"}, cobra.ShellCompDirectiveError
}
// ShellCompDirectiveDefault indicates that the shell will perform its default behavior after completions have
// been provided (without implying other possible directives)
return dockerImageRepoTags, cobra.ShellCompDirectiveDefault
}
func listLocalDockerImages(prefix string) ([]string, error) {
var repoTags = make([]string, 0)
ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return repoTags, err
}
// Only want to return tagged images
imageListArgs := filters.NewArgs()
imageListArgs.Add("dangling", "false")
images, err := cli.ImageList(ctx, types.ImageListOptions{All: false, Filters: imageListArgs})
if err != nil {
return repoTags, err
}
for _, image := range images {
// image may have multiple tags
for _, tag := range image.RepoTags {
if strings.HasPrefix(tag, prefix) {
repoTags = append(repoTags, tag)
}
}
}
return repoTags, nil
}
+98
View File
@@ -0,0 +1,98 @@
package cmd
import (
"errors"
"fmt"
"os"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui"
"github.com/hashicorp/go-multierror"
"github.com/wagoodman/go-partybus"
)
// eventLoop listens to worker errors (from execution path), worker events (from a partybus subscription), and
// signal interrupts. Is responsible for handling each event relative to a given UI an to coordinate eventing until
// an eventual graceful exit.
// nolint:funlen
func eventLoop(workerErrs <-chan error, signals <-chan os.Signal, subscription *partybus.Subscription, cleanupFn func(), uxs ...ui.UI) error {
defer cleanupFn()
events := subscription.Events()
var err error
var ux ui.UI
if ux, err = setupUI(subscription.Unsubscribe, uxs...); err != nil {
return err
}
var retErr error
var forceTeardown bool
for {
if workerErrs == nil && events == nil {
break
}
select {
case err, isOpen := <-workerErrs:
if !isOpen {
workerErrs = nil
continue
}
if err != nil {
// capture the error from the worker and unsubscribe to complete a graceful shutdown
retErr = multierror.Append(retErr, err)
_ = subscription.Unsubscribe()
// the worker has exited, we may have been mid-handling events for the UI which should now be
// ignored, in which case forcing a teardown of the UI irregardless of the state is required.
forceTeardown = true
}
case e, isOpen := <-events:
if !isOpen {
events = nil
continue
}
if err := ux.Handle(e); err != nil {
if errors.Is(err, partybus.ErrUnsubscribe) {
events = nil
} else {
retErr = multierror.Append(retErr, err)
// TODO: should we unsubscribe? should we try to halt execution? or continue?
}
}
case <-signals:
// ignore further results from any event source and exit ASAP, but ensure that all cache is cleaned up.
// we ignore further errors since cleaning up the tmp directories will affect running catalogers that are
// reading/writing from/to their nested temp dirs. This is acceptable since we are bailing without result.
// TODO: potential future improvement would be to pass context into workers with a cancel function that is
// to the event loop. In this way we can have a more controlled shutdown even at the most nested levels
// of processing.
events = nil
workerErrs = nil
forceTeardown = true
}
}
if err := ux.Teardown(forceTeardown); err != nil {
retErr = multierror.Append(retErr, err)
}
return retErr
}
// setupUI takes one or more UIs that responds to events and takes a event bus unsubscribe function for use
// during teardown. With the given UIs, the first UI which the ui.Setup() function does not return an error
// will be utilized in execution. Providing a set of UIs allows for the caller to provide graceful fallbacks
// when there are environmental problem (e.g. unable to setup a TUI with the current TTY).
func setupUI(unsubscribe func() error, uis ...ui.UI) (ui.UI, error) {
for _, ux := range uis {
if err := ux.Setup(unsubscribe); err != nil {
log.Warnf("unable to setup given UI, falling back to alternative UI: %+v", err)
continue
}
return ux, nil
}
return nil, fmt.Errorf("unable to setup any UI")
}
+455
View File
@@ -0,0 +1,455 @@
package cmd
import (
"fmt"
"os"
"syscall"
"testing"
"time"
"github.com/anchore/syft/internal/ui"
"github.com/anchore/syft/syft/event"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/wagoodman/go-partybus"
)
var _ ui.UI = (*uiMock)(nil)
type uiMock struct {
t *testing.T
finalEvent partybus.Event
unsubscribe func() error
mock.Mock
}
func (u *uiMock) Setup(unsubscribe func() error) error {
u.t.Logf("UI Setup called")
u.unsubscribe = unsubscribe
return u.Called(unsubscribe).Error(0)
}
func (u *uiMock) Handle(event partybus.Event) error {
u.t.Logf("UI Handle called: %+v", event.Type)
if event == u.finalEvent {
assert.NoError(u.t, u.unsubscribe())
}
return u.Called(event).Error(0)
}
func (u *uiMock) Teardown(_ bool) error {
u.t.Logf("UI Teardown called")
return u.Called().Error(0)
}
func Test_eventLoop_gracefulExit(t *testing.T) {
test := func(t *testing.T) {
testBus := partybus.NewBus()
subscription := testBus.Subscribe()
t.Cleanup(testBus.Close)
finalEvent := partybus.Event{
Type: event.PresenterReady,
}
worker := func() <-chan error {
ret := make(chan error)
go func() {
t.Log("worker running")
// send an empty item (which is ignored) ensuring we've entered the select statement,
// then close (a partial shutdown).
ret <- nil
t.Log("worker sent nothing")
close(ret)
t.Log("worker closed")
// do the other half of the shutdown
testBus.Publish(finalEvent)
t.Log("worker published final event")
}()
return ret
}
signaler := func() <-chan os.Signal {
return nil
}
ux := &uiMock{
t: t,
finalEvent: finalEvent,
}
// ensure the mock sees at least the final event
ux.On("Handle", finalEvent).Return(nil)
// ensure the mock sees basic setup/teardown events
ux.On("Setup", mock.AnythingOfType("func() error")).Return(nil)
ux.On("Teardown").Return(nil)
var cleanupCalled bool
cleanupFn := func() {
t.Log("cleanup called")
cleanupCalled = true
}
assert.NoError(t,
eventLoop(
worker(),
signaler(),
subscription,
cleanupFn,
ux,
),
)
assert.True(t, cleanupCalled, "cleanup function not called")
ux.AssertExpectations(t)
}
// if there is a bug, then there is a risk of the event loop never returning
testWithTimeout(t, 5*time.Second, test)
}
func Test_eventLoop_workerError(t *testing.T) {
test := func(t *testing.T) {
testBus := partybus.NewBus()
subscription := testBus.Subscribe()
t.Cleanup(testBus.Close)
workerErr := fmt.Errorf("worker error")
worker := func() <-chan error {
ret := make(chan error)
go func() {
t.Log("worker running")
// send an empty item (which is ignored) ensuring we've entered the select statement,
// then close (a partial shutdown).
ret <- nil
t.Log("worker sent nothing")
ret <- workerErr
t.Log("worker sent error")
close(ret)
t.Log("worker closed")
// note: NO final event is fired
}()
return ret
}
signaler := func() <-chan os.Signal {
return nil
}
ux := &uiMock{
t: t,
}
// ensure the mock sees basic setup/teardown events
ux.On("Setup", mock.AnythingOfType("func() error")).Return(nil)
ux.On("Teardown").Return(nil)
var cleanupCalled bool
cleanupFn := func() {
t.Log("cleanup called")
cleanupCalled = true
}
// ensure we see an error returned
assert.ErrorIs(t,
eventLoop(
worker(),
signaler(),
subscription,
cleanupFn,
ux,
),
workerErr,
"should have seen a worker error, but did not",
)
assert.True(t, cleanupCalled, "cleanup function not called")
ux.AssertExpectations(t)
}
// if there is a bug, then there is a risk of the event loop never returning
testWithTimeout(t, 5*time.Second, test)
}
func Test_eventLoop_unsubscribeError(t *testing.T) {
test := func(t *testing.T) {
testBus := partybus.NewBus()
subscription := testBus.Subscribe()
t.Cleanup(testBus.Close)
finalEvent := partybus.Event{
Type: event.PresenterReady,
}
worker := func() <-chan error {
ret := make(chan error)
go func() {
t.Log("worker running")
// send an empty item (which is ignored) ensuring we've entered the select statement,
// then close (a partial shutdown).
ret <- nil
t.Log("worker sent nothing")
close(ret)
t.Log("worker closed")
// do the other half of the shutdown
testBus.Publish(finalEvent)
t.Log("worker published final event")
}()
return ret
}
signaler := func() <-chan os.Signal {
return nil
}
ux := &uiMock{
t: t,
finalEvent: finalEvent,
}
// ensure the mock sees at least the final event... note the unsubscribe error here
ux.On("Handle", finalEvent).Return(partybus.ErrUnsubscribe)
// ensure the mock sees basic setup/teardown events
ux.On("Setup", mock.AnythingOfType("func() error")).Return(nil)
ux.On("Teardown").Return(nil)
var cleanupCalled bool
cleanupFn := func() {
t.Log("cleanup called")
cleanupCalled = true
}
// unsubscribe errors should be handled and ignored, not propagated. We are additionally asserting that
// this case is handled as a controlled shutdown (this test should not timeout)
assert.NoError(t,
eventLoop(
worker(),
signaler(),
subscription,
cleanupFn,
ux,
),
)
assert.True(t, cleanupCalled, "cleanup function not called")
ux.AssertExpectations(t)
}
// if there is a bug, then there is a risk of the event loop never returning
testWithTimeout(t, 5*time.Second, test)
}
func Test_eventLoop_handlerError(t *testing.T) {
test := func(t *testing.T) {
testBus := partybus.NewBus()
subscription := testBus.Subscribe()
t.Cleanup(testBus.Close)
finalEvent := partybus.Event{
Type: event.PresenterReady,
Error: fmt.Errorf("unable to create presenter"),
}
worker := func() <-chan error {
ret := make(chan error)
go func() {
t.Log("worker running")
// send an empty item (which is ignored) ensuring we've entered the select statement,
// then close (a partial shutdown).
ret <- nil
t.Log("worker sent nothing")
close(ret)
t.Log("worker closed")
// do the other half of the shutdown
testBus.Publish(finalEvent)
t.Log("worker published final event")
}()
return ret
}
signaler := func() <-chan os.Signal {
return nil
}
ux := &uiMock{
t: t,
finalEvent: finalEvent,
}
// ensure the mock sees at least the final event... note the event error is propagated
ux.On("Handle", finalEvent).Return(finalEvent.Error)
// ensure the mock sees basic setup/teardown events
ux.On("Setup", mock.AnythingOfType("func() error")).Return(nil)
ux.On("Teardown").Return(nil)
var cleanupCalled bool
cleanupFn := func() {
t.Log("cleanup called")
cleanupCalled = true
}
// handle errors SHOULD propagate the event loop. We are additionally asserting that this case is
// handled as a controlled shutdown (this test should not timeout)
assert.ErrorIs(t,
eventLoop(
worker(),
signaler(),
subscription,
cleanupFn,
ux,
),
finalEvent.Error,
"should have seen a event error, but did not",
)
assert.True(t, cleanupCalled, "cleanup function not called")
ux.AssertExpectations(t)
}
// if there is a bug, then there is a risk of the event loop never returning
testWithTimeout(t, 5*time.Second, test)
}
func Test_eventLoop_signalsStopExecution(t *testing.T) {
test := func(t *testing.T) {
testBus := partybus.NewBus()
subscription := testBus.Subscribe()
t.Cleanup(testBus.Close)
worker := func() <-chan error {
// the worker will never return work and the event loop will always be waiting...
return make(chan error)
}
signaler := func() <-chan os.Signal {
ret := make(chan os.Signal)
go func() {
ret <- syscall.SIGINT
// note: we do NOT close the channel to ensure the event loop does not depend on that behavior to exit
}()
return ret
}
ux := &uiMock{
t: t,
}
// ensure the mock sees basic setup/teardown events
ux.On("Setup", mock.AnythingOfType("func() error")).Return(nil)
ux.On("Teardown").Return(nil)
var cleanupCalled bool
cleanupFn := func() {
t.Log("cleanup called")
cleanupCalled = true
}
assert.NoError(t,
eventLoop(
worker(),
signaler(),
subscription,
cleanupFn,
ux,
),
)
assert.True(t, cleanupCalled, "cleanup function not called")
ux.AssertExpectations(t)
}
// if there is a bug, then there is a risk of the event loop never returning
testWithTimeout(t, 5*time.Second, test)
}
func Test_eventLoop_uiTeardownError(t *testing.T) {
test := func(t *testing.T) {
testBus := partybus.NewBus()
subscription := testBus.Subscribe()
t.Cleanup(testBus.Close)
finalEvent := partybus.Event{
Type: event.PresenterReady,
}
worker := func() <-chan error {
ret := make(chan error)
go func() {
t.Log("worker running")
// send an empty item (which is ignored) ensuring we've entered the select statement,
// then close (a partial shutdown).
ret <- nil
t.Log("worker sent nothing")
close(ret)
t.Log("worker closed")
// do the other half of the shutdown
testBus.Publish(finalEvent)
t.Log("worker published final event")
}()
return ret
}
signaler := func() <-chan os.Signal {
return nil
}
ux := &uiMock{
t: t,
finalEvent: finalEvent,
}
teardownError := fmt.Errorf("sorry, dave, the UI doesn't want to be torn down")
// ensure the mock sees at least the final event... note the event error is propagated
ux.On("Handle", finalEvent).Return(nil)
// ensure the mock sees basic setup/teardown events
ux.On("Setup", mock.AnythingOfType("func() error")).Return(nil)
ux.On("Teardown").Return(teardownError)
var cleanupCalled bool
cleanupFn := func() {
t.Log("cleanup called")
cleanupCalled = true
}
// ensure we see an error returned
assert.ErrorIs(t,
eventLoop(
worker(),
signaler(),
subscription,
cleanupFn,
ux,
),
teardownError,
"should have seen a UI teardown error, but did not",
)
assert.True(t, cleanupCalled, "cleanup function not called")
ux.AssertExpectations(t)
}
// if there is a bug, then there is a risk of the event loop never returning
testWithTimeout(t, 5*time.Second, test)
}
func testWithTimeout(t *testing.T, timeout time.Duration, test func(*testing.T)) {
done := make(chan bool)
go func() {
test(t)
done <- true
}()
select {
case <-time.After(timeout):
t.Fatal("test timed out")
case <-done:
}
}
-52
View File
@@ -1,52 +0,0 @@
package cmd
import (
"fmt"
"os"
"github.com/anchore/imgbom/imgbom"
"github.com/anchore/imgbom/internal/config"
"github.com/anchore/imgbom/internal/format"
"github.com/anchore/imgbom/internal/logger"
"github.com/anchore/stereoscope"
"github.com/spf13/viper"
"go.uber.org/zap"
"gopkg.in/yaml.v2"
)
var appConfig *config.Application
var log *zap.SugaredLogger
func initAppConfig() {
cfg, err := config.LoadConfigFromFile(viper.GetViper(), &cliOpts)
if err != nil {
fmt.Printf("failed to load application config: \n\t%+v\n", err)
os.Exit(1)
}
appConfig = cfg
}
func initLogging() {
config := logger.LogConfig{
EnableConsole: (appConfig.Log.FileLocation == "" || appConfig.CliOptions.Verbosity > 0) && !appConfig.Quiet,
EnableFile: appConfig.Log.FileLocation != "",
Level: appConfig.Log.LevelOpt,
Structured: appConfig.Log.Structured,
FileLocation: appConfig.Log.FileLocation,
}
logWrapper := logger.NewZapLogger(config)
log = logWrapper.Logger
imgbom.SetLogger(logWrapper)
stereoscope.SetLogger(logWrapper)
}
func logAppConfig() {
appCfgStr, err := yaml.Marshal(&appConfig)
if err != nil {
log.Debugf("Could not display application config: %+v", err)
} else {
log.Debugf("Application config:\n%+v", format.Magenta.Format(string(appCfgStr)))
}
}
+354
View File
@@ -0,0 +1,354 @@
package cmd
import (
"context"
"fmt"
"io/ioutil"
"os"
"github.com/anchore/stereoscope"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/anchore"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/formats"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui"
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/format"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
"github.com/pkg/profile"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
"github.com/wagoodman/go-partybus"
)
const (
packagesExample = ` {{.appName}} {{.command}} alpine:latest a summary of discovered packages
{{.appName}} {{.command}} alpine:latest -o json show all possible cataloging details
{{.appName}} {{.command}} alpine:latest -o cyclonedx show a CycloneDX formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx show a SPDX 2.2 tag-value formatted SBOM
{{.appName}} {{.command}} alpine:latest -o spdx-json show a SPDX 2.2 JSON formatted SBOM
{{.appName}} {{.command}} alpine:latest -vv show verbose debug information
Supports the following image sources:
{{.appName}} {{.command}} yourrepo/yourimage:tag defaults to using images from a Docker daemon. If Docker is not present, the image is pulled directly from the registry.
{{.appName}} {{.command}} path/to/a/file/or/dir a Docker tar, OCI tar, OCI directory, or generic filesystem directory
You can also explicitly specify the scheme to use:
{{.appName}} {{.command}} docker:yourrepo/yourimage:tag explicitly use the Docker daemon
{{.appName}} {{.command}} docker-archive:path/to/yourimage.tar use a tarball from disk for archives created from "docker save"
{{.appName}} {{.command}} oci-archive:path/to/yourimage.tar use a tarball from disk for OCI archives (from Skopeo or otherwise)
{{.appName}} {{.command}} oci-dir:path/to/yourimage read directly from a path on disk for OCI layout directories (from Skopeo or otherwise)
{{.appName}} {{.command}} dir:path/to/yourproject read directly from a path on disk (any directory)
{{.appName}} {{.command}} file:path/to/yourproject/file read directly from a path on disk (any single file)
{{.appName}} {{.command}} registry:yourrepo/yourimage:tag pull image directly from a registry (no container runtime required)
`
)
var (
packagesPresenterOpt format.Option
packagesCmd = &cobra.Command{
Use: "packages [SOURCE]",
Short: "Generate a package SBOM",
Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from container images and filesystems",
Example: internal.Tprintf(packagesExample, map[string]interface{}{
"appName": internal.ApplicationName,
"command": "packages",
}),
Args: validateInputArgs,
SilenceUsage: true,
SilenceErrors: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
// set the presenter
presenterOption := format.ParseOption(appConfig.Output)
if presenterOption == format.UnknownFormatOption {
return fmt.Errorf("bad --output value '%s'", appConfig.Output)
}
packagesPresenterOpt = presenterOption
if appConfig.Dev.ProfileCPU && appConfig.Dev.ProfileMem {
return fmt.Errorf("cannot profile CPU and memory simultaneously")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if appConfig.Dev.ProfileCPU {
defer profile.Start(profile.CPUProfile).Stop()
} else if appConfig.Dev.ProfileMem {
defer profile.Start(profile.MemProfile).Stop()
}
return packagesExec(cmd, args)
},
ValidArgsFunction: dockerImageValidArgsFunction,
}
)
func init() {
setPackageFlags(packagesCmd.Flags())
rootCmd.AddCommand(packagesCmd)
}
func setPackageFlags(flags *pflag.FlagSet) {
// Formatting & Input options //////////////////////////////////////////////
flags.StringP(
"scope", "s", source.SquashedScope.String(),
fmt.Sprintf("selection of layers to catalog, options=%v", source.AllScopes))
flags.StringP(
"output", "o", string(format.TableOption),
fmt.Sprintf("report output formatter, options=%v", format.AllOptions),
)
flags.StringP(
"file", "", "",
"file to write the report output to (default is STDOUT)",
)
// Upload options //////////////////////////////////////////////////////////
flags.StringP(
"host", "H", "",
"the hostname or URL of the Anchore Enterprise instance to upload to",
)
flags.StringP(
"username", "u", "",
"the username to authenticate against Anchore Enterprise",
)
flags.StringP(
"password", "p", "",
"the password to authenticate against Anchore Enterprise",
)
flags.StringP(
"dockerfile", "d", "",
"include dockerfile for upload to Anchore Enterprise",
)
flags.Bool(
"overwrite-existing-image", false,
"overwrite an existing image during the upload to Anchore Enterprise",
)
flags.Uint(
"import-timeout", 30,
"set a timeout duration (in seconds) for the upload to Anchore Enterprise",
)
}
func bindPackagesConfigOptions(flags *pflag.FlagSet) error {
// Formatting & Input options //////////////////////////////////////////////
if err := viper.BindPFlag("package.cataloger.scope", flags.Lookup("scope")); err != nil {
return err
}
if err := viper.BindPFlag("output", flags.Lookup("output")); err != nil {
return err
}
if err := viper.BindPFlag("file", flags.Lookup("file")); err != nil {
return err
}
// Upload options //////////////////////////////////////////////////////////
if err := viper.BindPFlag("anchore.host", flags.Lookup("host")); err != nil {
return err
}
if err := viper.BindPFlag("anchore.username", flags.Lookup("username")); err != nil {
return err
}
if err := viper.BindPFlag("anchore.password", flags.Lookup("password")); err != nil {
return err
}
if err := viper.BindPFlag("anchore.dockerfile", flags.Lookup("dockerfile")); err != nil {
return err
}
if err := viper.BindPFlag("anchore.overwrite-existing-image", flags.Lookup("overwrite-existing-image")); err != nil {
return err
}
if err := viper.BindPFlag("anchore.import-timeout", flags.Lookup("import-timeout")); err != nil {
return err
}
return nil
}
func validateInputArgs(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
// in the case that no arguments are given we want to show the help text and return with a non-0 return code.
if err := cmd.Help(); err != nil {
return fmt.Errorf("unable to display help: %w", err)
}
return fmt.Errorf("an image/directory argument is required")
}
return cobra.MaximumNArgs(1)(cmd, args)
}
func packagesExec(_ *cobra.Command, args []string) error {
// could be an image or a directory, with or without a scheme
userInput := args[0]
reporter, closer, err := reportWriter()
defer func() {
if err := closer(); err != nil {
log.Warnf("unable to write to report destination: %+v", err)
}
}()
if err != nil {
return err
}
return eventLoop(
packagesExecWorker(userInput),
setupSignals(),
eventSubscription,
stereoscope.Cleanup,
ui.Select(isVerbose(), appConfig.Quiet, reporter)...,
)
}
func isVerbose() (result bool) {
isPipedInput, err := internal.IsPipedInput()
if err != nil {
// since we can't tell if there was piped input we assume that there could be to disable the ETUI
log.Warnf("unable to determine if there is piped input: %+v", err)
return true
}
// verbosity should consider if there is piped input (in which case we should not show the ETUI)
return appConfig.CliOptions.Verbosity > 0 || isPipedInput
}
func packagesExecWorker(userInput string) <-chan error {
errs := make(chan error)
go func() {
defer close(errs)
tasks, err := tasks()
if err != nil {
errs <- err
return
}
f := formats.ByOption(packagesPresenterOpt)
if f == nil {
errs <- fmt.Errorf("unknown format: %s", packagesPresenterOpt)
return
}
checkForApplicationUpdate()
src, cleanup, err := source.New(userInput, appConfig.Registry.ToOptions())
if err != nil {
errs <- fmt.Errorf("failed to determine image source: %w", err)
return
}
if cleanup != nil {
defer cleanup()
}
s := sbom.SBOM{
Source: src.Metadata,
Descriptor: sbom.Descriptor{
Name: internal.ApplicationName,
Version: version.FromBuild().Version,
Configuration: appConfig,
},
}
var relationships []<-chan artifact.Relationship
for _, task := range tasks {
c := make(chan artifact.Relationship)
relationships = append(relationships, c)
go runTask(task, &s.Artifacts, src, c, errs)
}
s.Relationships = append(s.Relationships, mergeRelationships(relationships...)...)
if appConfig.Anchore.Host != "" {
if err := runPackageSbomUpload(src, s); err != nil {
errs <- err
return
}
}
bus.Publish(partybus.Event{
Type: event.PresenterReady,
Value: f.Presenter(s),
})
}()
return errs
}
func mergeRelationships(cs ...<-chan artifact.Relationship) (relationships []artifact.Relationship) {
for _, c := range cs {
for n := range c {
relationships = append(relationships, n)
}
}
return relationships
}
func runPackageSbomUpload(src *source.Source, s sbom.SBOM) error {
log.Infof("uploading results to %s", appConfig.Anchore.Host)
if src.Metadata.Scheme != source.ImageScheme {
return fmt.Errorf("unable to upload results: only images are supported")
}
var dockerfileContents []byte
if appConfig.Anchore.Dockerfile != "" {
if _, err := os.Stat(appConfig.Anchore.Dockerfile); os.IsNotExist(err) {
return fmt.Errorf("unable dockerfile=%q does not exist: %w", appConfig.Anchore.Dockerfile, err)
}
fh, err := os.Open(appConfig.Anchore.Dockerfile)
if err != nil {
return fmt.Errorf("unable to open dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err)
}
dockerfileContents, err = ioutil.ReadAll(fh)
if err != nil {
return fmt.Errorf("unable to read dockerfile=%q: %w", appConfig.Anchore.Dockerfile, err)
}
}
c, err := anchore.NewClient(anchore.Configuration{
BaseURL: appConfig.Anchore.Host,
Username: appConfig.Anchore.Username,
Password: appConfig.Anchore.Password,
})
if err != nil {
return fmt.Errorf("failed to create anchore client: %w", err)
}
importCfg := anchore.ImportConfig{
ImageMetadata: src.Image.Metadata,
SBOM: s,
Dockerfile: dockerfileContents,
OverwriteExistingUpload: appConfig.Anchore.OverwriteExistingImage,
Timeout: appConfig.Anchore.ImportTimeout,
}
if err := c.Import(context.Background(), importCfg); err != nil {
return fmt.Errorf("failed to upload results to host=%s: %+v", appConfig.Anchore.Host, err)
}
return nil
}
+151
View File
@@ -0,0 +1,151 @@
package cmd
import (
"fmt"
"os"
"github.com/anchore/stereoscope"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/internal/formats/syftjson"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/ui"
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
"github.com/gookit/color"
"github.com/pkg/profile"
"github.com/spf13/cobra"
"github.com/wagoodman/go-partybus"
)
const powerUserExample = ` {{.appName}} {{.command}} <image>
DEPRECATED - THIS COMMAND WILL BE REMOVED in v1.0.0
Only image sources are supported (e.g. docker: , docker-archive: , oci: , etc.), the directory source (dir:) is not supported.
All behavior is controlled via application configuration and environment variables (see https://github.com/anchore/syft#configuration)
`
var powerUserOpts = struct {
configPath string
}{}
var powerUserCmd = &cobra.Command{
Use: "power-user [IMAGE]",
Short: "Run bulk operations on container images",
Example: internal.Tprintf(powerUserExample, map[string]interface{}{
"appName": internal.ApplicationName,
"command": "power-user",
}),
Args: validateInputArgs,
Hidden: true,
SilenceUsage: true,
SilenceErrors: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
if appConfig.Dev.ProfileCPU && appConfig.Dev.ProfileMem {
return fmt.Errorf("cannot profile CPU and memory simultaneously")
}
return nil
},
RunE: func(cmd *cobra.Command, args []string) error {
if appConfig.Dev.ProfileCPU {
defer profile.Start(profile.CPUProfile).Stop()
} else if appConfig.Dev.ProfileMem {
defer profile.Start(profile.MemProfile).Stop()
}
return powerUserExec(cmd, args)
},
ValidArgsFunction: dockerImageValidArgsFunction,
}
func init() {
powerUserCmd.Flags().StringVarP(&powerUserOpts.configPath, "config", "c", "", "config file path with all power-user options")
rootCmd.AddCommand(powerUserCmd)
}
func powerUserExec(_ *cobra.Command, args []string) error {
// could be an image or a directory, with or without a scheme
userInput := args[0]
reporter, closer, err := reportWriter()
defer func() {
if err := closer(); err != nil {
log.Warnf("unable to write to report destination: %+v", err)
}
// inform user at end of run that command will be removed
deprecated := color.Style{color.Red, color.OpBold}.Sprint("DEPRECATED: This command will be removed in v1.0.0")
fmt.Fprintln(os.Stderr, deprecated)
}()
if err != nil {
return err
}
return eventLoop(
powerUserExecWorker(userInput),
setupSignals(),
eventSubscription,
stereoscope.Cleanup,
ui.Select(isVerbose(), appConfig.Quiet, reporter)...,
)
}
func powerUserExecWorker(userInput string) <-chan error {
errs := make(chan error)
go func() {
defer close(errs)
appConfig.Secrets.Cataloger.Enabled = true
appConfig.FileMetadata.Cataloger.Enabled = true
appConfig.FileContents.Cataloger.Enabled = true
appConfig.FileClassification.Cataloger.Enabled = true
tasks, err := tasks()
if err != nil {
errs <- err
return
}
checkForApplicationUpdate()
src, cleanup, err := source.New(userInput, appConfig.Registry.ToOptions())
if err != nil {
errs <- err
return
}
if cleanup != nil {
defer cleanup()
}
s := sbom.SBOM{
Source: src.Metadata,
Descriptor: sbom.Descriptor{
Name: internal.ApplicationName,
Version: version.FromBuild().Version,
Configuration: appConfig,
},
}
var relationships []<-chan artifact.Relationship
for _, task := range tasks {
c := make(chan artifact.Relationship)
relationships = append(relationships, c)
go runTask(task, &s.Artifacts, src, c, errs)
}
s.Relationships = append(s.Relationships, mergeRelationships(relationships...)...)
bus.Publish(partybus.Event{
Type: event.PresenterReady,
Value: syftjson.Format().Presenter(s),
})
}()
return errs
}
+33
View File
@@ -0,0 +1,33 @@
package cmd
import (
"fmt"
"io"
"os"
"strings"
"github.com/anchore/syft/internal/log"
)
func reportWriter() (io.Writer, func() error, error) {
nop := func() error { return nil }
path := strings.TrimSpace(appConfig.File)
switch len(path) {
case 0:
return os.Stdout, nop, nil
default:
reportFile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
if err != nil {
return nil, nop, fmt.Errorf("unable to create report file: %w", err)
}
return reportFile, func() error {
log.Infof("report written to file=%q", path)
return reportFile.Close()
}, nil
}
}
+26 -52
View File
@@ -4,69 +4,43 @@ import (
"fmt"
"os"
"github.com/anchore/imgbom/imgbom"
"github.com/anchore/imgbom/imgbom/presenter"
"github.com/anchore/imgbom/internal"
"github.com/anchore/stereoscope"
"github.com/anchore/syft/internal/config"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var persistentOpts = config.CliOnlyOptions{}
// rootCmd is currently an alias for the packages command
var rootCmd = &cobra.Command{
Use: fmt.Sprintf("%s [IMAGE]", internal.ApplicationName),
Short: "A container image BOM tool", // TODO: add copy
Long: internal.Tprintf(`\
Supports the following image sources:
{{.appName}} yourrepo/yourimage:tag defaults to using images from a docker daemon
{{.appName}} docker://yourrepo/yourimage:tag explicitly use the docker daemon
{{.appName}} tar://path/to/yourimage.tar use a tarball from disk
`, map[string]interface{}{
"appName": internal.ApplicationName,
}),
Args: cobra.MaximumNArgs(1),
Run: runCmdWrapper,
Short: packagesCmd.Short,
Long: packagesCmd.Long,
Args: packagesCmd.Args,
Example: packagesCmd.Example,
SilenceUsage: true,
SilenceErrors: true,
PreRunE: packagesCmd.PreRunE,
RunE: packagesCmd.RunE,
ValidArgsFunction: packagesCmd.ValidArgsFunction,
}
func init() {
setCliOptions()
// set universal flags
rootCmd.PersistentFlags().StringVarP(&persistentOpts.ConfigPath, "config", "c", "", "application config file")
cobra.OnInitialize(initAppConfig)
cobra.OnInitialize(initLogging)
cobra.OnInitialize(logAppConfig)
}
flag := "quiet"
rootCmd.PersistentFlags().BoolP(
flag, "q", false,
"suppress all logging output",
)
func Execute() {
if err := rootCmd.Execute(); err != nil {
log.Errorf("could not start application: %w", err)
if err := viper.BindPFlag(flag, rootCmd.PersistentFlags().Lookup(flag)); err != nil {
fmt.Printf("unable to bind flag '%s': %+v", flag, err)
os.Exit(1)
}
}
func runCmdWrapper(cmd *cobra.Command, args []string) {
os.Exit(doRunCmd(cmd, args))
}
rootCmd.PersistentFlags().CountVarP(&persistentOpts.Verbosity, "verbose", "v", "increase verbosity (-v = info, -vv = debug)")
func doRunCmd(cmd *cobra.Command, args []string) int {
userImageStr := args[0]
log.Infof("Fetching image '%s'", userImageStr)
img, err := stereoscope.GetImage(userImageStr)
if err != nil {
log.Errorf("could not fetch image '%s': %w", userImageStr, err)
return 1
}
defer stereoscope.Cleanup()
log.Info("Cataloging image")
catalog, err := imgbom.CatalogImage(img, appConfig.ScopeOpt)
if err != nil {
log.Errorf("could not catalog image: %w", err)
return 1
}
log.Info("Complete!")
err = presenter.GetPresenter(appConfig.PresenterOpt).Present(os.Stdout, img, catalog)
if err != nil {
log.Errorf("could not format catalog results: %w", err)
return 1
}
return 0
// set common options that are not universal (package subcommand-alias specific)
setPackageFlags(rootCmd.Flags())
}
+20
View File
@@ -0,0 +1,20 @@
package cmd
import (
"os"
"os/signal"
"syscall"
)
func setupSignals() <-chan os.Signal {
c := make(chan os.Signal, 1) // Note: A buffered channel is recommended for this; see https://golang.org/pkg/os/signal/#Notify
interruptions := []os.Signal{
syscall.SIGINT,
syscall.SIGTERM,
}
signal.Notify(c, interruptions...)
return c
}
+231
View File
@@ -0,0 +1,231 @@
package cmd
import (
"crypto"
"fmt"
"github.com/anchore/syft/syft"
"github.com/anchore/syft/syft/artifact"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/syft/source"
)
type task func(*sbom.Artifacts, *source.Source) ([]artifact.Relationship, error)
func tasks() ([]task, error) {
var tasks []task
generators := []func() (task, error){
generateCatalogPackagesTask,
generateCatalogFileMetadataTask,
generateCatalogFileDigestsTask,
generateCatalogSecretsTask,
generateCatalogFileClassificationsTask,
generateCatalogContentsTask,
}
for _, generator := range generators {
task, err := generator()
if err != nil {
return nil, err
}
if task != nil {
tasks = append(tasks, task)
}
}
return tasks, nil
}
func generateCatalogPackagesTask() (task, error) {
if !appConfig.Package.Cataloger.Enabled {
return nil, nil
}
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
packageCatalog, relationships, theDistro, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt)
if err != nil {
return nil, err
}
results.PackageCatalog = packageCatalog
results.Distro = theDistro
return relationships, nil
}
return task, nil
}
func generateCatalogFileMetadataTask() (task, error) {
if !appConfig.FileMetadata.Cataloger.Enabled {
return nil, nil
}
metadataCataloger := file.NewMetadataCataloger()
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt)
if err != nil {
return nil, err
}
result, err := metadataCataloger.Catalog(resolver)
if err != nil {
return nil, err
}
results.FileMetadata = result
return nil, nil
}
return task, nil
}
func generateCatalogFileDigestsTask() (task, error) {
if !appConfig.FileMetadata.Cataloger.Enabled {
return nil, nil
}
supportedHashAlgorithms := make(map[string]crypto.Hash)
for _, h := range []crypto.Hash{
crypto.MD5,
crypto.SHA1,
crypto.SHA256,
} {
supportedHashAlgorithms[file.DigestAlgorithmName(h)] = h
}
var hashes []crypto.Hash
for _, hashStr := range appConfig.FileMetadata.Digests {
name := file.CleanDigestAlgorithmName(hashStr)
hashObj, ok := supportedHashAlgorithms[name]
if !ok {
return nil, fmt.Errorf("unsupported hash algorithm: %s", hashStr)
}
hashes = append(hashes, hashObj)
}
digestsCataloger, err := file.NewDigestsCataloger(hashes)
if err != nil {
return nil, err
}
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt)
if err != nil {
return nil, err
}
result, err := digestsCataloger.Catalog(resolver)
if err != nil {
return nil, err
}
results.FileDigests = result
return nil, nil
}
return task, nil
}
func generateCatalogSecretsTask() (task, error) {
if !appConfig.Secrets.Cataloger.Enabled {
return nil, nil
}
patterns, err := file.GenerateSearchPatterns(file.DefaultSecretsPatterns, appConfig.Secrets.AdditionalPatterns, appConfig.Secrets.ExcludePatternNames)
if err != nil {
return nil, err
}
secretsCataloger, err := file.NewSecretsCataloger(patterns, appConfig.Secrets.RevealValues, appConfig.Secrets.SkipFilesAboveSize)
if err != nil {
return nil, err
}
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(appConfig.Secrets.Cataloger.ScopeOpt)
if err != nil {
return nil, err
}
result, err := secretsCataloger.Catalog(resolver)
if err != nil {
return nil, err
}
results.Secrets = result
return nil, nil
}
return task, nil
}
func generateCatalogFileClassificationsTask() (task, error) {
if !appConfig.FileClassification.Cataloger.Enabled {
return nil, nil
}
// TODO: in the future we could expose out the classifiers via configuration
classifierCataloger, err := file.NewClassificationCataloger(file.DefaultClassifiers)
if err != nil {
return nil, err
}
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(appConfig.FileClassification.Cataloger.ScopeOpt)
if err != nil {
return nil, err
}
result, err := classifierCataloger.Catalog(resolver)
if err != nil {
return nil, err
}
results.FileClassifications = result
return nil, nil
}
return task, nil
}
func generateCatalogContentsTask() (task, error) {
if !appConfig.FileContents.Cataloger.Enabled {
return nil, nil
}
contentsCataloger, err := file.NewContentsCataloger(appConfig.FileContents.Globs, appConfig.FileContents.SkipFilesAboveSize)
if err != nil {
return nil, err
}
task := func(results *sbom.Artifacts, src *source.Source) ([]artifact.Relationship, error) {
resolver, err := src.FileResolver(appConfig.FileContents.Cataloger.ScopeOpt)
if err != nil {
return nil, err
}
result, err := contentsCataloger.Catalog(resolver)
if err != nil {
return nil, err
}
results.FileContents = result
return nil, nil
}
return task, nil
}
func runTask(t task, a *sbom.Artifacts, src *source.Source, c chan<- artifact.Relationship, errs chan<- error) {
defer close(c)
relationships, err := t(a, src)
if err != nil {
errs <- err
return
}
for _, relationship := range relationships {
c <- relationship
}
}
+39 -13
View File
@@ -1,19 +1,17 @@
package cmd
import (
"encoding/json"
"fmt"
"os"
"github.com/anchore/imgbom/internal"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/version"
"github.com/spf13/cobra"
)
type Version struct {
Version string
Commit string
BuildTime string
}
var version *Version
var outputFormat string
var versionCmd = &cobra.Command{
Use: "version",
@@ -22,13 +20,41 @@ var versionCmd = &cobra.Command{
}
func init() {
versionCmd.Flags().StringVarP(&outputFormat, "output", "o", "text", "format to show version information (available=[text, json])")
rootCmd.AddCommand(versionCmd)
}
func SetVersion(v *Version) {
version = v
}
func printVersion(_ *cobra.Command, _ []string) {
versionInfo := version.FromBuild()
func printVersion(cmd *cobra.Command, args []string) {
fmt.Printf("%s %s\n", internal.ApplicationName, version.Version)
switch outputFormat {
case "text":
fmt.Println("Application: ", internal.ApplicationName)
fmt.Println("Version: ", versionInfo.Version)
fmt.Println("BuildDate: ", versionInfo.BuildDate)
fmt.Println("GitCommit: ", versionInfo.GitCommit)
fmt.Println("GitTreeState: ", versionInfo.GitTreeState)
fmt.Println("Platform: ", versionInfo.Platform)
fmt.Println("GoVersion: ", versionInfo.GoVersion)
fmt.Println("Compiler: ", versionInfo.Compiler)
case "json":
enc := json.NewEncoder(os.Stdout)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
err := enc.Encode(&struct {
version.Version
Application string `json:"application"`
}{
Version: versionInfo,
Application: internal.ApplicationName,
})
if err != nil {
fmt.Printf("failed to show version information: %+v\n", err)
os.Exit(1)
}
default:
fmt.Printf("unsupported output format: %s\n", outputFormat)
os.Exit(1)
}
}
+51 -13
View File
@@ -1,21 +1,59 @@
module github.com/anchore/imgbom
module github.com/anchore/syft
go 1.14
go 1.16
require (
github.com/CycloneDX/cyclonedx-go v0.4.0
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/adrg/xdg v0.2.1
github.com/anchore/go-testutils v0.0.0-20200520222037-edc2bf1864fe
github.com/anchore/stereoscope v0.0.0-20200523232006-be5f3c18958f
github.com/go-test/deep v1.0.6
github.com/google/go-containerregistry v0.0.0-20200521151920-a873a21aff23 // indirect
github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074
github.com/anchore/client-go v0.0.0-20210222170800-9c70f9b80bcf
github.com/anchore/go-presenter v0.0.0-20211102174526-0dbf20f6c7fa
github.com/anchore/go-rpmdb v0.0.0-20210914181456-a9c52348da63
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
github.com/anchore/packageurl-go v0.0.0-20210922164639-b3fa992ebd29
github.com/anchore/stereoscope v0.0.0-20211203160213-5a5e323a5c89
// we are hinting brotli to latest due to warning when installing archiver v3:
// go: warning: github.com/andybalholm/brotli@v1.0.1: retracted by module author: occasional panics and data corruption
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/antihax/optional v1.0.0
github.com/bmatcuk/doublestar/v2 v2.0.4
github.com/docker/docker v20.10.11+incompatible
github.com/dustin/go-humanize v1.0.0
github.com/facebookincubator/nvdtools v0.1.4
github.com/go-test/deep v1.0.7
github.com/google/go-cmp v0.5.6
github.com/google/uuid v1.2.0
github.com/gookit/color v1.2.7
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-version v1.2.0
github.com/jinzhu/copier v0.3.2
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/archiver/v3 v3.5.1
github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.3.1
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/mitchellh/mapstructure v1.4.1
github.com/olekukonko/tablewriter v0.0.4
github.com/pelletier/go-toml v1.9.3
github.com/pkg/profile v1.5.0
github.com/scylladb/go-set v1.0.2
github.com/sergi/go-diff v1.1.0
github.com/spf13/cobra v1.0.0
github.com/spf13/viper v1.7.0
go.uber.org/zap v1.15.0
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
google.golang.org/genproto v0.0.0-20200521103424-e9a78aa275b7 // indirect
gopkg.in/yaml.v2 v2.3.0
github.com/sirupsen/logrus v1.8.1
github.com/spdx/tools-golang v0.1.0
github.com/spf13/afero v1.6.0
github.com/spf13/cobra v1.2.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.0
github.com/vifraa/gopom v0.1.0
github.com/wagoodman/go-partybus v0.0.0-20210627031916-db1f5573bbc5
github.com/wagoodman/go-progress v0.0.0-20200731105512-1020f39e6240
github.com/wagoodman/jotframe v0.0.0-20211129225309-56b0d0a4aebb
github.com/x-cray/logrus-prefixed-formatter v0.5.2
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/mod v0.4.2
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
gopkg.in/yaml.v2 v2.4.0
)
+917 -213
View File
File diff suppressed because it is too large Load Diff
+15
View File
@@ -0,0 +1,15 @@
source = ["./dist/syft-macos_darwin_amd64/syft"] # The 'dist' directory path should ideally reference an env var, where the source of truth is the Makefile. I wasn't able to figure out how to solve this.
bundle_id = "com.anchore.toolbox.syft"
sign {
application_identity = "Developer ID Application: ANCHORE, INC. (9MJHKYX5AT)"
}
dmg {
output_path = "./dist/output.dmg"
volume_name = "Syft"
}
zip {
output_path = "./dist/output.zip"
}
-16
View File
@@ -1,16 +0,0 @@
package analyzer
import (
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/tree"
)
type Analyzer interface {
Name() string
// TODO: add ID / Name for analyze for uniquely identifying this analyzer type
SelectFiles([]*tree.FileTree) []file.Reference
// NOTE: one of the errors which is returned is "IterationNeeded", which indicates to the driver to
// continue with another Select/Analyze pass
Analyze(map[file.Reference]string) ([]pkg.Package, error)
}
-72
View File
@@ -1,72 +0,0 @@
package analyzer
import (
"github.com/anchore/imgbom/imgbom/analyzer/dpkg"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/imgbom/internal/log"
"github.com/anchore/stereoscope/pkg/file"
"github.com/hashicorp/go-multierror"
)
var controllerInstance controller
func init() {
controllerInstance = controller{
analyzers: make([]Analyzer, 0),
}
controllerInstance.add(dpkg.NewAnalyzer())
}
func Analyze(s scope.Scope) (pkg.Catalog, error) {
return controllerInstance.analyze(s)
}
type controller struct {
analyzers []Analyzer
}
func (c *controller) add(a Analyzer) {
log.Debugf("adding analyzer: %s", a.Name())
c.analyzers = append(c.analyzers, a)
}
func (c *controller) analyze(s scope.Scope) (pkg.Catalog, error) {
catalog := pkg.NewCatalog()
fileSelection := make([]file.Reference, 0)
// ask analyzers for files to extract from the image tar
for _, a := range c.analyzers {
fileSelection = append(fileSelection, a.SelectFiles(s.Trees)...)
log.Debugf("analyzer '%s' selected '%d' files", a.Name(), len(fileSelection))
}
// fetch contents for requested selection by analyzers
contents, err := s.Image.MultipleFileContentsByRef(fileSelection...)
if err != nil {
return pkg.Catalog{}, err
}
// perform analysis, accumulating errors for each failed analysis
var errs error
for _, a := range c.analyzers {
// TODO: check for multiple rounds of analyses by Iterate error
packages, err := a.Analyze(contents)
if err != nil {
errs = multierror.Append(errs, err)
continue
}
log.Debugf("analyzer '%s' discovered '%d' packages", a.Name(), len(packages))
for _, p := range packages {
catalog.Add(p)
}
}
if errs != nil {
return pkg.Catalog{}, errs
}
return catalog, nil
}
-69
View File
@@ -1,69 +0,0 @@
package dpkg
import (
"strings"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/internal/log"
"github.com/anchore/stereoscope/pkg/file"
"github.com/anchore/stereoscope/pkg/tree"
)
type Analyzer struct {
selectedFiles []file.Reference
}
func NewAnalyzer() *Analyzer {
return &Analyzer{}
}
func (a *Analyzer) Name() string {
return "dpkg-analyzer"
}
func (a *Analyzer) SelectFiles(trees []*tree.FileTree) []file.Reference {
files := make([]file.Reference, 0)
for _, tree := range trees {
// TODO: extract into function/slice/etc
file := tree.File("/var/lib/dpkg/status")
if file != nil {
files = append(files, *file)
}
}
a.selectedFiles = files
return files
}
func (a *Analyzer) Analyze(contents map[file.Reference]string) ([]pkg.Package, error) {
packages := make([]pkg.Package, 0)
for _, reference := range a.selectedFiles {
content, ok := contents[reference]
if !ok {
// TODO: test case
log.Errorf("analyzer '%s' file content missing: %+v", a.Name(), reference)
continue
}
entries, err := ParseEntries(strings.NewReader(content))
if err != nil {
// TODO: test case
log.Errorf("analyzer failed to parse entries (reference=%+v): %w", reference, err)
continue
}
for _, entry := range entries {
packages = append(packages, pkg.Package{
Name: entry.Package,
Version: entry.Version,
Type: pkg.DebPkg,
Source: []file.Reference{reference},
Metadata: entry,
})
}
}
return packages, nil
}
-94
View File
@@ -1,94 +0,0 @@
package dpkg
import (
"bufio"
"fmt"
"io"
"strings"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/mitchellh/mapstructure"
)
var endOfPackages = fmt.Errorf("no more packages to read")
func ParseEntries(reader io.Reader) ([]pkg.DpkgMetadata, error) {
buffedReader := bufio.NewReader(reader)
var entries = make([]pkg.DpkgMetadata, 0)
for {
entry, err := parseEntry(buffedReader)
if err != nil {
if err == endOfPackages {
break
}
return nil, err
}
entries = append(entries, entry)
}
return entries, nil
}
func parseEntry(reader *bufio.Reader) (entry pkg.DpkgMetadata, err error) {
dpkgFields := make(map[string]string)
var key string
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
return pkg.DpkgMetadata{}, endOfPackages
}
return pkg.DpkgMetadata{}, err
}
line = strings.TrimRight(line, "\n")
// empty line indicates end of entry
if len(line) == 0 {
// if the entry has not started, keep parsing lines
if len(dpkgFields) == 0 {
continue
}
break
}
switch {
case strings.HasPrefix(line, " "):
// a field-body continuation
if len(key) == 0 {
return pkg.DpkgMetadata{}, fmt.Errorf("no match for continuation: line: '%s'", line)
}
val, ok := dpkgFields[key]
if !ok {
return pkg.DpkgMetadata{}, fmt.Errorf("no previous key exists, expecting: %s", key)
}
// concatenate onto previous value
val = fmt.Sprintf("%s\n %s", val, strings.TrimSpace(line))
dpkgFields[key] = val
default:
// parse a new key
if i := strings.Index(line, ":"); i > 0 {
key = strings.TrimSpace(line[0:i])
val := strings.TrimSpace(line[i+1:])
if _, ok := dpkgFields[key]; ok {
return pkg.DpkgMetadata{}, fmt.Errorf("duplicate key discovered: %s", key)
}
dpkgFields[key] = val
} else {
return pkg.DpkgMetadata{}, fmt.Errorf("cannot parse field from line: '%s'", line)
}
}
}
err = mapstructure.Decode(dpkgFields, &entry)
if err != nil {
return pkg.DpkgMetadata{}, err
}
return entry, nil
}
-145
View File
@@ -1,145 +0,0 @@
package dpkg
import (
"bufio"
"os"
"testing"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/go-test/deep"
)
func compareEntries(t *testing.T, left, right pkg.DpkgMetadata) {
t.Helper()
if diff := deep.Equal(left, right); diff != nil {
t.Error(diff)
}
}
func TestSinglePackage(t *testing.T) {
tests := []struct {
name string
expected pkg.DpkgMetadata
}{
{
name: "Test Single Package",
expected: pkg.DpkgMetadata{
Package: "apt",
Status: "install ok installed",
Priority: "required",
InstalledSize: "4064",
Maintainer: "APT Development Team <deity@lists.debian.org>",
Architecture: "amd64",
Version: "1.8.2",
ReplacesPkgs: "apt-transport-https (<< 1.5~alpha4~), apt-utils (<< 1.3~exp2~)",
ProvidesPkgs: "apt-transport-https (= 1.8.2)",
DependsPkgs: "adduser, gpgv | gpgv2 | gpgv1, debian-archive-keyring, libapt-pkg5.0 (>= 1.7.0~alpha3~), libc6 (>= 2.15), libgcc1 (>= 1:3.0), libgnutls30 (>= 3.6.6), libseccomp2 (>= 1.0.1), libstdc++6 (>= 5.2)",
RecommendsPkgs: "ca-certificates",
SuggestsPkgs: "apt-doc, aptitude | synaptic | wajig, dpkg-dev (>= 1.17.2), gnupg | gnupg2 | gnupg1, powermgmt-base",
ConfigFiles: `
/etc/apt/apt.conf.d/01autoremove 76120d358bc9037bb6358e737b3050b5
/etc/cron.daily/apt-compat 49e9b2cfa17849700d4db735d04244f3
/etc/kernel/postinst.d/apt-auto-removal 4ad976a68f045517cf4696cec7b8aa3a
/etc/logrotate.d/apt 179f2ed4f85cbaca12fa3d69c2a4a1c3`,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
file, err := os.Open("test-fixtures/single")
if err != nil {
t.Fatal("Unable to read test_fixtures/single: ", err)
}
defer func() {
err := file.Close()
if err != nil {
t.Fatal("closing file failed:", err)
}
}()
reader := bufio.NewReader(file)
entry, err := parseEntry(reader)
if err != nil {
t.Fatal("Unable to read file contents: ", err)
}
compareEntries(t, entry, test.expected)
})
}
}
func TestMultiplePackages(t *testing.T) {
tests := []struct {
name string
expected []pkg.DpkgMetadata
}{
{
name: "Test Multiple Package",
expected: []pkg.DpkgMetadata{
{
Package: "tzdata",
Status: "install ok installed",
Priority: "required",
InstalledSize: "3036",
Maintainer: "GNU Libc Maintainers <debian-glibc@lists.debian.org>",
Architecture: "all",
Version: "2020a-0+deb10u1",
ReplacesPkgs: "libc0.1, libc0.3, libc6, libc6.1",
ProvidesPkgs: "tzdata-buster",
DependsPkgs: "debconf (>= 0.5) | debconf-2.0",
},
{
Package: "util-linux",
Status: "install ok installed",
Priority: "required",
InstalledSize: "4327",
Maintainer: "LaMont Jones <lamont@debian.org>",
Architecture: "amd64",
Version: "2.33.1-0.1",
ReplacesPkgs: "bash-completion (<< 1:2.8), initscripts (<< 2.88dsf-59.2~), login (<< 1:4.5-1.1~), mount (<< 2.29.2-3~), s390-tools (<< 2.2.0-1~), setpriv (<< 2.32.1-0.2~), sysvinit-utils (<< 2.88dsf-59.1~)",
DependsPkgs: "fdisk, login (>= 1:4.5-1.1~)",
SuggestsPkgs: "dosfstools, kbd | console-tools, util-linux-locales",
ConfigFiles: `
/etc/default/hwclock 3916544450533eca69131f894db0ca12
/etc/init.d/hwclock.sh 1ca5c0743fa797ffa364db95bb8d8d8e
/etc/pam.d/runuser b8b44b045259525e0fae9e38fdb2aeeb
/etc/pam.d/runuser-l 2106ea05877e8913f34b2c77fa02be45
/etc/pam.d/su ce6dcfda3b190a27a455bb38a45ff34a
/etc/pam.d/su-l 756fef5687fecc0d986e5951427b0c4f`,
},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
file, err := os.Open("test-fixtures/multiple")
if err != nil {
t.Fatal("Unable to read: ", err)
}
defer func() {
err := file.Close()
if err != nil {
t.Fatal("closing file failed:", err)
}
}()
entries, err := ParseEntries(file)
if err != nil {
t.Fatal("Unable to read file contents: ", err)
}
if len(entries) != 2 {
t.Fatalf("unexpected number of entries: %d", len(entries))
}
for idx, entry := range entries {
compareEntries(t, entry, test.expected[idx])
}
})
}
}
-20
View File
@@ -1,20 +0,0 @@
package imgbom
import (
"github.com/anchore/imgbom/imgbom/analyzer"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/stereoscope/pkg/image"
)
// TODO: add os detection results as return value
func CatalogImage(img *image.Image, o scope.Option) (pkg.Catalog, error) {
s, err := scope.NewScope(img, o)
if err != nil {
return pkg.Catalog{}, err
}
// TODO: add OS detection here...
return analyzer.Analyze(s)
}
-4
View File
@@ -1,4 +0,0 @@
package imgbom
// note: must be a single word, all lowercase
const LibraryName = "imgbom"
-10
View File
@@ -1,10 +0,0 @@
package imgbom
import (
"github.com/anchore/imgbom/imgbom/logger"
"github.com/anchore/imgbom/internal/log"
)
func SetLogger(logger logger.Logger) {
log.Log = logger
}
-9
View File
@@ -1,9 +0,0 @@
package logger
type Logger interface {
Errorf(format string, args ...interface{})
Infof(format string, args ...interface{})
Info(args ...interface{})
Debugf(format string, args ...interface{})
Debug(args ...interface{})
}
-48
View File
@@ -1,48 +0,0 @@
package pkg
// TODO: add reader methods (by type, id, fuzzy search, etc)
type Catalog struct {
// TODO: catalog by package ID for potential indexing
packages map[Type][]Package
}
func NewCatalog() Catalog {
return Catalog{
packages: make(map[Type][]Package),
}
}
func (c *Catalog) Add(p Package) {
_, ok := c.packages[p.Type]
if !ok {
c.packages[p.Type] = make([]Package, 0)
}
c.packages[p.Type] = append(c.packages[p.Type], p)
}
func (c *Catalog) Enumerate(types ...Type) <-chan Package {
channel := make(chan Package)
go func() {
defer close(channel)
for ty, packages := range c.packages {
if len(types) != 0 {
found := false
typeCheck:
for _, t := range types {
if t == ty {
found = true
break typeCheck
}
}
if !found {
continue
}
}
for _, p := range packages {
channel <- p
}
}
}()
return channel
}
-20
View File
@@ -1,20 +0,0 @@
package pkg
// TODO: consider keeping the remaining values as an embedded map
// Available fields are described at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html
// in the --showformat section
type DpkgMetadata struct {
Package string `mapstructure:"Package"`
Architecture string `mapstructure:"Architecture"`
DependsPkgs string `mapstructure:"Depends"`
InstalledSize string `mapstructure:"Installed-Size"`
Maintainer string `mapstructure:"Maintainer"`
Priority string `mapstructure:"Priority"`
ProvidesPkgs string `mapstructure:"Provides"`
RecommendsPkgs string `mapstructure:"Recommends"`
ReplacesPkgs string `mapstructure:"Replaces"`
Status string `mapstructure:"Status"`
SuggestsPkgs string `mapstructure:"Suggests"`
Version string `mapstructure:"Version"`
ConfigFiles string `mapstructure:"Conffiles"`
}
-17
View File
@@ -1,17 +0,0 @@
package pkg
import "github.com/anchore/stereoscope/pkg/file"
// TODO: add package ID (random/incremental)
// TODO: add field to trace which analyzer detected this
type Package struct {
Name string
Version string
Source []file.Reference
Licenses []string
Type Type
Metadata interface{}
}
// TODO: stringer...
-34
View File
@@ -1,34 +0,0 @@
package pkg
const (
UnknownPkg Type = iota
ApkPkg
DebPkg
JavaPkg
NodePkg
PacmanPkg
PythonPkg
RpmPkg
RubyPkg
)
type Type uint
var typeStr = []string{
"UnknownPackage",
"apk",
"deb",
"java",
"node",
"pacman",
"python",
"rpm",
"ruby",
}
func (t Type) String() string {
if int(t) >= len(typeStr) {
return typeStr[0]
}
return typeStr[t]
}
-114
View File
@@ -1,114 +0,0 @@
package json
import (
"encoding/json"
"io"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/internal/log"
stereoscopeImg "github.com/anchore/stereoscope/pkg/image"
)
type Presenter struct{}
func NewPresenter() *Presenter {
return &Presenter{}
}
type document struct {
Image image `json:"image"`
Artifacts []artifact `json:"artifacts"`
}
type image struct {
Layers []layer `json:"layers"`
Size int64 `json:"size"`
Digest string `json:"digest"`
MediaType string `json:"mediaType"`
Tags []string `json:"tags"`
}
type layer struct {
MediaType string `json:"mediaType"`
Digest string `json:"digest"`
Size int64 `json:"size"`
}
type source struct {
Source string `json:"source"`
Layer int `json:"layer"`
Effects []string `json:"effects"`
}
type artifact struct {
Name string `json:"name"`
Version string `json:"version"`
Type string `json:"type"`
Analyzer string `json:"analyzer"`
Sources []source `json:"sources"`
Metadata interface{} `json:"metadata"`
}
func (pres *Presenter) Present(output io.Writer, img *stereoscopeImg.Image, catalog pkg.Catalog) error {
tags := make([]string, len(img.Metadata.Tags))
for idx, tag := range img.Metadata.Tags {
tags[idx] = tag.String()
}
doc := document{
Image: image{
Digest: img.Metadata.Digest,
Size: img.Metadata.Size,
MediaType: string(img.Metadata.MediaType),
Tags: tags,
Layers: make([]layer, len(img.Layers)),
},
Artifacts: make([]artifact, 0),
}
// populate image...
for idx, l := range img.Layers {
doc.Image.Layers[idx] = layer{
MediaType: string(l.Metadata.MediaType),
Digest: l.Metadata.Digest,
Size: l.Metadata.Size,
}
}
// populate artifacts...
for p := range catalog.Enumerate() {
art := artifact{
Name: p.Name,
Version: p.Version,
Type: p.Type.String(),
Analyzer: "TODO", // TODO
Sources: make([]source, len(p.Source)),
Metadata: p.Metadata,
}
for idx, src := range p.Source {
fileMetadata, err := img.FileCatalog.Get(src)
if err != nil {
// TODO: test case
log.Errorf("could not get metadata from catalog (presenter=json): %+v", src)
}
srcObj := source{
Source: "",
Layer: int(fileMetadata.Source.Metadata.Index),
Effects: []string{}, // TODO
}
art.Sources[idx] = srcObj
}
doc.Artifacts = append(doc.Artifacts, art)
}
bytes, err := json.Marshal(&doc)
if err != nil {
log.Errorf("failed to marshal json (presenter=json): %w", err)
}
_, err = output.Write(bytes)
return err
}
-90
View File
@@ -1,90 +0,0 @@
package json
import (
"bytes"
"flag"
"testing"
"github.com/anchore/go-testutils"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/stereoscope/pkg/file"
"github.com/sergi/go-diff/diffmatchpatch"
)
var update = flag.Bool("update", false, "update the *.golden files for json presenters")
// TODO: add a JSON schema and write a test that validates output against the schema
// func validateAgainstV1Schema(t *testing.T, json string) {
// fullSchemaPath, err := filepath.Abs("v1-schema.json")
// if err != nil {
// t.Fatal("could not get path to schema:", err)
// }
// schemaLoader := gojsonschema.NewReferenceLoader(fmt.Sprintf("file://%s", fullSchemaPath))
// documentLoader := gojsonschema.NewStringLoader(json)
// result, err := gojsonschema.Validate(schemaLoader, documentLoader)
// if err != nil {
// t.Fatal("unable to validate json schema:", err.Error())
// }
// if !result.Valid() {
// t.Errorf("failed json schema validation:")
// for _, desc := range result.Errors() {
// t.Errorf(" - %s\n", desc)
// }
// }
// }
func TestJsonPresenter(t *testing.T) {
pres := NewPresenter()
var buffer bytes.Buffer
testImage := "image-simple"
if *update {
testutils.UpdateGoldenFixtureImage(t, testImage)
}
catalog := pkg.NewCatalog()
img := testutils.GetGoldenFixtureImage(t, testImage)
// populate catalog with test data
catalog.Add(pkg.Package{
Name: "package-1",
Version: "1.0.1",
Source: []file.Reference{
*img.SquashedTree.File("/somefile-1.txt"),
},
Type: pkg.DebPkg,
})
catalog.Add(pkg.Package{
Name: "package-2",
Version: "2.0.1",
Source: []file.Reference{
*img.SquashedTree.File("/somefile-2.txt"),
},
Type: pkg.DebPkg,
})
// run presenter
err := pres.Present(&buffer, img, catalog)
if err != nil {
t.Fatal(err)
}
actual := buffer.Bytes()
if *update {
testutils.UpdateGoldenFileContents(t, actual)
}
var expected = testutils.GetGoldenFileContents(t)
if !bytes.Equal(expected, actual) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(actual), string(expected), true)
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
}
// TODO: add me back in when there is a JSON schema
// validateAgainstV1Schema(t, string(actual))
}
@@ -1 +0,0 @@
{"image":{"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:056c0789fa9ad629ceae6d09713fb035f84115af3c4a88a43aa60f13bc683053","size":22},{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:b461c48116592c570a66fed71d5b09662a8172e168b7938cf317af47872cdc9b","size":16},{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","digest":"sha256:00b80053e05c01da485015610d288ce3185fac00d251e2ada02b45a7a7c5f589","size":27}],"size":65,"digest":"sha256:3c53d2d891940f8d8e95acb77b58752f54dc5de9d91d19dd90ced2db76256cea","mediaType":"application/vnd.docker.distribution.manifest.v2+json","tags":["anchore-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"]},"artifacts":[{"name":"package-1","version":"1.0.1","type":"deb","analyzer":"TODO","sources":[{"source":"","layer":0,"effects":[]}],"metadata":null},{"name":"package-2","version":"2.0.1","type":"deb","analyzer":"TODO","sources":[{"source":"","layer":1,"effects":[]}],"metadata":null}]}
-36
View File
@@ -1,36 +0,0 @@
package presenter
import "strings"
const (
UnknownPresenter Option = iota
JSONPresenter
)
var optionStr = []string{
"UnknownPresenter",
"json",
}
var Options = []Option{
JSONPresenter,
}
type Option uint
func ParseOption(userStr string) Option {
switch strings.ToLower(userStr) {
case strings.ToLower(JSONPresenter.String()):
return JSONPresenter
default:
return UnknownPresenter
}
}
func (o Option) String() string {
if int(o) >= len(optionStr) {
return optionStr[0]
}
return optionStr[o]
}
-22
View File
@@ -1,22 +0,0 @@
package presenter
import (
"io"
"github.com/anchore/imgbom/imgbom/pkg"
"github.com/anchore/imgbom/imgbom/presenter/json"
"github.com/anchore/stereoscope/pkg/image"
)
type Presenter interface {
Present(io.Writer, *image.Image, pkg.Catalog) error
}
func GetPresenter(option Option) Presenter {
switch option {
case JSONPresenter:
return json.NewPresenter()
default:
return nil
}
}
-40
View File
@@ -1,40 +0,0 @@
package scope
import "strings"
const (
UnknownScope Option = iota
SquashedScope
AllLayersScope
)
type Option uint
var optionStr = []string{
"UnknownScope",
"Squashed",
"AllLayers",
}
var Options = []Option{
SquashedScope,
AllLayersScope,
}
func ParseOption(userStr string) Option {
switch strings.ToLower(userStr) {
case strings.ToLower(SquashedScope.String()):
return SquashedScope
case strings.ToLower(AllLayersScope.String()):
return AllLayersScope
}
return UnknownScope
}
func (o Option) String() string {
if int(o) >= len(optionStr) {
return optionStr[0]
}
return optionStr[o]
}
-17
View File
@@ -1,17 +0,0 @@
package scope
import (
"fmt"
"testing"
)
func TestOptionStringerBoundary(t *testing.T) {
var _ fmt.Stringer = Option(0)
for _, c := range []int{-1, 0, 3} {
option := Option(c)
if option.String() != UnknownScope.String() {
t.Errorf("expected Option(%d) to be unknown, found '%+v'", c, option)
}
}
}
-46
View File
@@ -1,46 +0,0 @@
package scope
import (
"fmt"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/stereoscope/pkg/tree"
)
type Scope struct {
Option Option
Trees []*tree.FileTree
Image *image.Image
}
func NewScope(img *image.Image, option Option) (Scope, error) {
var trees = make([]*tree.FileTree, 0)
if img == nil {
return Scope{}, fmt.Errorf("no image given")
}
switch option {
case SquashedScope:
if img.SquashedTree == nil {
return Scope{}, fmt.Errorf("the image does not have have a squashed tree")
}
trees = append(trees, img.SquashedTree)
case AllLayersScope:
if len(img.Layers) == 0 {
return Scope{}, fmt.Errorf("the image does not contain any layers")
}
for _, layer := range img.Layers {
trees = append(trees, layer.Tree)
}
default:
return Scope{}, fmt.Errorf("bad option provided: %+v", option)
}
return Scope{
Option: option,
Trees: trees,
Image: img,
}, nil
}
-91
View File
@@ -1,91 +0,0 @@
package scope
import (
"testing"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/stereoscope/pkg/tree"
)
func testScopeImage(t *testing.T) *image.Image {
t.Helper()
one := image.NewLayer(nil)
one.Tree = tree.NewFileTree()
one.Tree.AddPath("/tree/first/path.txt")
two := image.NewLayer(nil)
two.Tree = tree.NewFileTree()
two.Tree.AddPath("/tree/second/path.txt")
i := image.NewImage(nil)
i.Layers = []image.Layer{one, two}
err := i.Squash()
if err != nil {
t.Fatal("could not squash test image trees")
}
return i
}
func TestScope(t *testing.T) {
refImg := testScopeImage(t)
cases := []struct {
name string
img *image.Image
option Option
expectedTrees []*tree.FileTree
err bool
}{
{
name: "AllLayersGoCase",
option: AllLayersScope,
img: testScopeImage(t),
expectedTrees: []*tree.FileTree{refImg.Layers[0].Tree, refImg.Layers[1].Tree},
},
{
name: "SquashedGoCase",
option: SquashedScope,
img: testScopeImage(t),
expectedTrees: []*tree.FileTree{refImg.SquashedTree},
},
{
name: "MissingImage",
option: SquashedScope,
err: true,
},
{
name: "MissingSquashedTree",
option: SquashedScope,
img: image.NewImage(nil),
err: true,
},
{
name: "NoLayers",
option: AllLayersScope,
img: image.NewImage(nil),
err: true,
},
}
for _, c := range cases {
actual, err := NewScope(c.img, c.option)
if err == nil && c.err {
t.Fatal("expected an error but did not find one")
} else if err != nil && !c.err {
t.Fatal("expected no error but found one:", err)
}
if len(actual.Trees) != len(c.expectedTrees) {
t.Fatalf("mismatched tree lengths: %d!=%d", len(actual.Trees), len(c.expectedTrees))
}
for idx, at := range actual.Trees {
if !at.Equal(c.expectedTrees[idx]) {
t.Error("mismatched tree @ idx", idx)
}
}
}
}
Executable
+389
View File
@@ -0,0 +1,389 @@
#!/bin/sh
set -e
# Code generated by godownloader on 2020-08-10T20:55:46Z.
#
usage() {
this=$1
cat <<EOF
$this: download go binaries for anchore/syft
Usage: $this [-b] bindir [-d] [tag]
-b sets bindir or installation directory, Defaults to ./bin
-d turns on debug logging
[tag] is a tag from
https://github.com/anchore/syft/releases
If tag is missing, then the latest will be used.
Generated by godownloader
https://github.com/goreleaser/godownloader
EOF
exit 2
}
parse_args() {
#BINDIR is ./bin unless set be ENV
# over-ridden by flag below
BINDIR=${BINDIR:-./bin}
while getopts "b:dh?x" arg; do
case "$arg" in
b) BINDIR="$OPTARG" ;;
d) log_set_priority 10 ;;
h | \?) usage "$0" ;;
x) set -x ;;
esac
done
shift $((OPTIND - 1))
TAG=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
tmpdir=$(mktemp -d)
log_debug "downloading files into ${tmpdir}"
http_download "${tmpdir}/${ARCHIVE}" "${ARCHIVE_URL}"
http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
# macOS has its own secure verification mechanism, and checksums.txt is not used.
if [ "$OS" != "darwin" ]; then
hash_sha256_verify "${tmpdir}/${ARCHIVE}" "${tmpdir}/${CHECKSUM}"
fi
srcdir="${tmpdir}"
(cd "${tmpdir}" && unpack "${ARCHIVE}")
test ! -d "${BINDIR}" && install -d "${BINDIR}"
for binexe in $BINARIES; do
if [ "$OS" = "windows" ]; then
binexe="${binexe}.exe"
fi
install "${srcdir}/${binexe}" "${BINDIR}/"
log_info "installed ${BINDIR}/${binexe}"
done
rm -rf "${tmpdir}"
}
get_binaries() {
case "$PLATFORM" in
darwin/amd64) BINARIES="syft" ;;
linux/amd64) BINARIES="syft" ;;
windows/amd64) BINARIES="syft" ;;
*)
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
exit 1
;;
esac
}
tag_to_version() {
if [ -z "${TAG}" ]; then
log_info "checking GitHub for latest tag"
else
log_info "checking GitHub for tag '${TAG}'"
fi
REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
if test -z "$REALTAG"; then
log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
exit 1
fi
# if version starts with 'v', remove it
TAG="$REALTAG"
VERSION=${TAG#v}
}
adjust_format() {
# change format (tar.gz or zip) based on OS
case ${OS} in
darwin) FORMAT=dmg ;;
windows) FORMAT=zip ;;
esac
true
}
adjust_os() {
# adjust archive name based on OS
true
}
adjust_arch() {
# adjust archive name based on ARCH
true
}
cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
command -v "$1" >/dev/null
}
echoerr() {
echo "$@" 1>&2
}
log_prefix() {
echo "$0"
}
_logp=6
log_set_priority() {
_logp="$1"
}
log_priority() {
if test -z "$1"; then
echo "$_logp"
return
fi
[ "$1" -le "$_logp" ]
}
log_tag() {
case $1 in
0) echo "emerg" ;;
1) echo "alert" ;;
2) echo "crit" ;;
3) echo "err" ;;
4) echo "warning" ;;
5) echo "notice" ;;
6) echo "info" ;;
7) echo "debug" ;;
*) echo "$1" ;;
esac
}
log_debug() {
log_priority 7 || return 0
echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
}
log_info() {
log_priority 6 || return 0
echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
}
log_err() {
log_priority 3 || return 0
echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
}
log_crit() {
log_priority 2 || return 0
echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
}
uname_os() {
os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$os" in
cygwin_nt*) os="windows" ;;
mingw*) os="windows" ;;
msys_nt*) os="windows" ;;
esac
echo "$os"
}
uname_arch() {
arch=$(uname -m)
case $arch in
x86_64) arch="amd64" ;;
x86) arch="386" ;;
i686) arch="386" ;;
i386) arch="386" ;;
aarch64) arch="arm64" ;;
armv5*) arch="armv5" ;;
armv6*) arch="armv6" ;;
armv7*) arch="armv7" ;;
esac
echo ${arch}
}
uname_os_check() {
os=$(uname_os)
case "$os" in
darwin) return 0 ;;
dragonfly) return 0 ;;
freebsd) return 0 ;;
linux) return 0 ;;
android) return 0 ;;
nacl) return 0 ;;
netbsd) return 0 ;;
openbsd) return 0 ;;
plan9) return 0 ;;
solaris) return 0 ;;
windows) return 0 ;;
esac
log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
return 1
}
uname_arch_check() {
arch=$(uname_arch)
case "$arch" in
386) return 0 ;;
amd64) return 0 ;;
arm64) return 0 ;;
armv5) return 0 ;;
armv6) return 0 ;;
armv7) return 0 ;;
ppc64) return 0 ;;
ppc64le) return 0 ;;
mips) return 0 ;;
mipsle) return 0 ;;
mips64) return 0 ;;
mips64le) return 0 ;;
s390x) return 0 ;;
amd64p32) return 0 ;;
esac
log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
return 1
}
unpack() {
archive=$1
case "${archive}" in
*.tar.gz | *.tgz) tar --no-same-owner -xzf "${archive}" ;;
*.tar) tar --no-same-owner -xf "${archive}" ;;
*.zip) unzip "${archive}" ;;
*.dmg) extract_from_dmg "${archive}" ;;
*)
log_err "unpack unknown archive format for ${archive}"
return 1
;;
esac
}
extract_from_dmg() {
dmg_file=$1
mount_point="/Volumes/tmp-dmg"
hdiutil attach -quiet -nobrowse -mountpoint "${mount_point}" "${dmg_file}"
cp -fR "${mount_point}/" ./
hdiutil detach -quiet -force "${mount_point}"
}
http_download_curl() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
else
code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
fi
if [ "$code" != "200" ]; then
log_debug "http_download_curl received HTTP status $code"
return 1
fi
return 0
}
http_download_wget() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
wget -q -O "$local_file" "$source_url"
else
wget -q --header "$header" -O "$local_file" "$source_url"
fi
}
http_download() {
log_debug "http_download $2"
if is_command curl; then
http_download_curl "$@"
return
elif is_command wget; then
http_download_wget "$@"
return
fi
log_crit "http_download unable to find wget or curl"
return 1
}
http_copy() {
tmp=$(mktemp)
http_download "${tmp}" "$1" "$2" || return 1
body=$(cat "$tmp")
rm -f "${tmp}"
echo "$body"
}
github_release() {
owner_repo=$1
version=$2
test -z "$version" && version="latest"
giturl="https://github.com/${owner_repo}/releases/${version}"
json=$(http_copy "$giturl" "Accept:application/json")
test -z "$json" && return 1
version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
test -z "$version" && return 1
echo "$version"
}
hash_sha256() {
TARGET=${1:-/dev/stdin}
if is_command gsha256sum; then
hash=$(gsha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command sha256sum; then
hash=$(sha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command shasum; then
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command openssl; then
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f a
else
log_crit "hash_sha256 unable to find command to compute sha-256 hash"
return 1
fi
}
hash_sha256_verify() {
TARGET=$1
checksums=$2
if [ -z "$checksums" ]; then
log_err "hash_sha256_verify checksum file not specified in arg2"
return 1
fi
BASENAME=${TARGET##*/}
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
if [ -z "$want" ]; then
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
return 1
fi
got=$(hash_sha256 "$TARGET")
if [ "$want" != "$got" ]; then
log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
return 1
fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF
PROJECT_NAME="syft"
OWNER=anchore
REPO="syft"
BINARY=syft
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"
# use in logging routines
log_prefix() {
echo "$PREFIX"
}
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
uname_os_check "$OS"
uname_arch_check "$ARCH"
parse_args "$@"
get_binaries
tag_to_version
adjust_format
adjust_os
adjust_arch
log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
NAME=${PROJECT_NAME}_${VERSION}_${OS}_${ARCH}
ARCHIVE=${NAME}.${FORMAT}
ARCHIVE_URL=${GITHUB_DOWNLOAD}/${TAG}/${ARCHIVE}
CHECKSUM=${PROJECT_NAME}_${VERSION}_checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
execute
+115
View File
@@ -0,0 +1,115 @@
package anchore
import (
"context"
"errors"
"fmt"
"path"
"strings"
"unicode"
"github.com/anchore/client-go/pkg/external"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/version"
)
type Configuration struct {
BaseURL string
Username string
Password string
UserAgent string
}
type Client struct {
config Configuration
client *external.APIClient
}
func NewClient(cfg Configuration) (*Client, error) {
if cfg.UserAgent == "" {
versionInfo := version.FromBuild()
// format: product / product-version comment
cfg.UserAgent = fmt.Sprintf("%s / %s %s", internal.ApplicationName, versionInfo.Version, versionInfo.Platform)
}
baseURL, err := prepareBaseURLForClient(cfg.BaseURL)
if err != nil {
return nil, fmt.Errorf("unable to create client: %w", err)
}
return &Client{
config: cfg,
client: external.NewAPIClient(&external.Configuration{
BasePath: baseURL,
UserAgent: cfg.UserAgent,
}),
}, nil
}
func (c *Client) newRequestContext(parentContext context.Context) context.Context {
if parentContext == nil {
parentContext = context.Background()
}
return context.WithValue(
parentContext,
external.ContextBasicAuth,
external.BasicAuth{
UserName: c.config.Username,
Password: c.config.Password,
},
)
}
var ErrInvalidBaseURLInput = errors.New("invalid base URL input")
func prepareBaseURLForClient(baseURL string) (string, error) {
if err := checkBaseURLInput(baseURL); err != nil {
return "", err
}
scheme, urlWithoutScheme := splitSchemeFromURL(baseURL)
if scheme == "" {
scheme = "http"
}
urlWithoutScheme = path.Clean(urlWithoutScheme)
const requiredSuffix = "v1"
if path.Base(urlWithoutScheme) != requiredSuffix {
urlWithoutScheme = path.Join(urlWithoutScheme, requiredSuffix)
}
preparedBaseURL := scheme + "://" + urlWithoutScheme
return preparedBaseURL, nil
}
func checkBaseURLInput(url string) error {
if url == "" {
return ErrInvalidBaseURLInput
}
firstCharacter := rune(url[0])
if !(unicode.IsLetter(firstCharacter)) {
return ErrInvalidBaseURLInput
}
return nil
}
func splitSchemeFromURL(url string) (scheme, urlWithoutScheme string) {
if hasScheme(url) {
urlParts := strings.SplitN(url, "://", 2)
scheme = urlParts[0]
urlWithoutScheme = urlParts[1]
return
}
return "", url
}
func hasScheme(url string) bool {
parts := strings.Split(url, "://")
return len(parts) > 1
}
+210
View File
@@ -0,0 +1,210 @@
package anchore
import "testing"
func TestHasScheme(t *testing.T) {
cases := []struct {
url string
expected bool
}{
{
url: "http://localhost",
expected: true,
},
{
url: "https://anchore.com:8443",
expected: true,
},
{
url: "google.com",
expected: false,
},
{
url: "",
expected: false,
},
}
for _, testCase := range cases {
t.Run(testCase.url, func(t *testing.T) {
result := hasScheme(testCase.url)
if testCase.expected != result {
t.Errorf("expected %t but got %t", testCase.expected, result)
}
})
}
}
func TestPrepareBaseURLForClient(t *testing.T) {
cases := []struct {
inputURL string
expectedURL string
expectedErr error
}{
{
inputURL: "",
expectedURL: "",
expectedErr: ErrInvalidBaseURLInput,
},
{
inputURL: "localhost",
expectedURL: "http://localhost/v1",
expectedErr: nil,
},
{
inputURL: "https://localhost",
expectedURL: "https://localhost/v1",
expectedErr: nil,
},
{
inputURL: "https://localhost/",
expectedURL: "https://localhost/v1",
expectedErr: nil,
},
{
inputURL: "https://localhost/v1/",
expectedURL: "https://localhost/v1",
expectedErr: nil,
},
{
inputURL: "https://localhost/v1//",
expectedURL: "https://localhost/v1",
expectedErr: nil,
},
{
inputURL: "http://something.com/platform/v1/services/anchore",
expectedURL: "http://something.com/platform/v1/services/anchore/v1",
expectedErr: nil,
},
{
inputURL: "my-host:8228",
expectedURL: "http://my-host:8228/v1",
expectedErr: nil,
},
{
inputURL: "v1/v1",
expectedURL: "http://v1/v1",
expectedErr: nil,
},
{
inputURL: "/v1",
expectedURL: "",
expectedErr: ErrInvalidBaseURLInput,
},
{
inputURL: "/imports/images",
expectedURL: "",
expectedErr: ErrInvalidBaseURLInput,
},
}
for _, testCase := range cases {
t.Run(testCase.inputURL, func(t *testing.T) {
resultURL, err := prepareBaseURLForClient(testCase.inputURL)
if err != testCase.expectedErr {
t.Errorf("expected err to be '%v' but got '%v'", testCase.expectedErr, err)
}
if resultURL != testCase.expectedURL {
t.Errorf("expected URL to be '%v' but got '%v'", testCase.expectedURL, resultURL)
}
})
}
}
func TestCheckBaseURLInput(t *testing.T) {
cases := []struct {
input string
expected error
}{
{
input: "",
expected: ErrInvalidBaseURLInput,
},
{
input: "x",
expected: nil,
},
{
input: "localhost:8000",
expected: nil,
},
{
input: ":80",
expected: ErrInvalidBaseURLInput,
},
{
input: "/v1",
expected: ErrInvalidBaseURLInput,
},
}
for _, testCase := range cases {
t.Run(testCase.input, func(t *testing.T) {
resultErr := checkBaseURLInput(testCase.input)
if testCase.expected != resultErr {
t.Errorf("expected err to be '%v' but got '%v'", testCase.expected, resultErr)
}
})
}
}
func TestSplitSchemeFromURL(t *testing.T) {
cases := []struct {
input string
expectedScheme string
expectedURLWithoutScheme string
}{
{
input: "",
expectedScheme: "",
expectedURLWithoutScheme: "",
},
{
input: "localhost",
expectedScheme: "",
expectedURLWithoutScheme: "localhost",
},
{
input: "https://anchore.com/path",
expectedScheme: "https",
expectedURLWithoutScheme: "anchore.com/path",
},
{
input: "tcp://host:1234",
expectedScheme: "tcp",
expectedURLWithoutScheme: "host:1234",
},
{
input: "/hello",
expectedScheme: "",
expectedURLWithoutScheme: "/hello",
},
{
input: "://host",
expectedScheme: "",
expectedURLWithoutScheme: "host",
},
{
input: "http//localhost",
expectedScheme: "",
expectedURLWithoutScheme: "http//localhost",
},
}
for _, testCase := range cases {
t.Run(testCase.input, func(t *testing.T) {
resultScheme, resultURLWithoutScheme := splitSchemeFromURL(testCase.input)
if testCase.expectedScheme != resultScheme {
t.Errorf("expected scheme to be '%s' but got '%s'", testCase.expectedScheme, resultScheme)
}
if testCase.expectedURLWithoutScheme != resultURLWithoutScheme {
t.Errorf("expected urlWithoutScheme to be '%s' but got '%s'", testCase.expectedURLWithoutScheme, resultURLWithoutScheme)
}
})
}
}
+140
View File
@@ -0,0 +1,140 @@
package anchore
import (
"context"
"errors"
"fmt"
"time"
"github.com/anchore/client-go/pkg/external"
"github.com/anchore/stereoscope/pkg/image"
"github.com/anchore/syft/internal/bus"
"github.com/anchore/syft/syft/event"
"github.com/anchore/syft/syft/sbom"
"github.com/antihax/optional"
"github.com/wagoodman/go-partybus"
"github.com/wagoodman/go-progress"
)
type ImportConfig struct {
ImageMetadata image.Metadata
SBOM sbom.SBOM
Dockerfile []byte
OverwriteExistingUpload bool
Timeout uint
}
func importProgress(source string) (*progress.Stage, *progress.Manual) {
stage := &progress.Stage{}
prog := &progress.Manual{
// this is the number of stages to expect; start + individual endpoints + stop
Total: 6,
}
bus.Publish(partybus.Event{
Type: event.ImportStarted,
Source: source,
Value: progress.StagedProgressable(&struct {
progress.Stager
progress.Progressable
}{
Stager: progress.Stager(stage),
Progressable: prog,
}),
})
return stage, prog
}
// nolint:funlen
func (c *Client) Import(ctx context.Context, cfg ImportConfig) error {
stage, prog := importProgress(c.config.BaseURL)
timeout := time.Duration(cfg.Timeout) * time.Second
ctxWithTimeout, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
authedCtx := c.newRequestContext(ctxWithTimeout)
stage.Current = "starting session"
startOperation, _, err := c.client.ImportsApi.CreateOperation(authedCtx)
if err != nil {
var detail = "no details given"
var openAPIErr external.GenericOpenAPIError
if errors.As(err, &openAPIErr) {
detail = string(openAPIErr.Body())
}
return fmt.Errorf("unable to start import session: %w: %s", err, detail)
}
prog.N++
sessionID := startOperation.Uuid
packageDigest, err := importPackageSBOM(authedCtx, c.client.ImportsApi, sessionID, cfg.SBOM, stage)
if err != nil {
return fmt.Errorf("failed to import Package SBOM: %w", err)
}
prog.N++
manifestDigest, err := importManifest(authedCtx, c.client.ImportsApi, sessionID, cfg.SBOM.Source.ImageMetadata.RawManifest, stage)
if err != nil {
return fmt.Errorf("failed to import Manifest: %w", err)
}
prog.N++
configDigest, err := importConfig(authedCtx, c.client.ImportsApi, sessionID, cfg.SBOM.Source.ImageMetadata.RawConfig, stage)
if err != nil {
return fmt.Errorf("failed to import Config: %w", err)
}
prog.N++
dockerfileDigest, err := importDockerfile(authedCtx, c.client.ImportsApi, sessionID, cfg.Dockerfile, stage)
if err != nil {
return fmt.Errorf("failed to import Dockerfile: %w", err)
}
prog.N++
stage.Current = "finalizing"
imageModel := addImageModel(cfg.ImageMetadata, packageDigest, manifestDigest, dockerfileDigest, configDigest, sessionID)
opts := external.AddImageOpts{
Force: optional.NewBool(cfg.OverwriteExistingUpload),
}
_, _, err = c.client.ImagesApi.AddImage(authedCtx, imageModel, &opts)
if err != nil {
var detail = "no details given"
var openAPIErr external.GenericOpenAPIError
if errors.As(err, &openAPIErr) {
detail = string(openAPIErr.Body())
}
return fmt.Errorf("unable to complete import session=%q: %w: %s", sessionID, err, detail)
}
prog.N++
stage.Current = ""
prog.SetCompleted()
return nil
}
func addImageModel(imageMetadata image.Metadata, packageDigest, manifestDigest, dockerfileDigest, configDigest, sessionID string) external.ImageAnalysisRequest {
var tags = make([]string, len(imageMetadata.Tags))
for i, t := range imageMetadata.Tags {
tags[i] = t.String()
}
return external.ImageAnalysisRequest{
Source: external.ImageSource{
Import: &external.ImageImportManifest{
Contents: external.ImportContentDigests{
Packages: packageDigest,
Manifest: manifestDigest,
Dockerfile: dockerfileDigest,
ImageConfig: configDigest,
},
Tags: tags,
Digest: imageMetadata.ManifestDigest,
LocalImageId: imageMetadata.ID,
OperationUuid: sessionID,
},
},
}
}
+50
View File
@@ -0,0 +1,50 @@
// nolint:dupl
package anchore
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/wagoodman/go-progress"
"github.com/anchore/client-go/pkg/external"
"github.com/anchore/syft/internal/log"
)
type configImportAPI interface {
ImportImageConfig(ctx context.Context, sessionID string, contents interface{}) (external.ImageImportContentResponse, *http.Response, error)
}
func importConfig(ctx context.Context, api configImportAPI, sessionID string, config []byte, stage *progress.Stage) (string, error) {
if len(config) > 0 {
log.Debug("importing image config")
stage.Current = "image config"
// API requires an object, but we do not verify the shape of this object locally
var sender map[string]interface{}
if err := json.Unmarshal(config, &sender); err != nil {
return "", err
}
response, httpResponse, err := api.ImportImageConfig(ctx, sessionID, sender)
if err != nil {
var openAPIErr external.GenericOpenAPIError
if errors.As(err, &openAPIErr) {
log.Errorf("api response: %+v", string(openAPIErr.Body()))
}
return "", fmt.Errorf("unable to import Config: %w", err)
}
defer httpResponse.Body.Close()
if httpResponse.StatusCode != 200 {
return "", fmt.Errorf("unable to import Config: %s", httpResponse.Status)
}
return response.Digest, nil
}
return "", nil
}
+129
View File
@@ -0,0 +1,129 @@
package anchore
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/wagoodman/go-progress"
"github.com/anchore/client-go/pkg/external"
"github.com/docker/docker/pkg/ioutils"
"github.com/go-test/deep"
)
type mockConfigImportAPI struct {
sessionID string
model interface{}
httpResponse *http.Response
err error
ctx context.Context
responseDigest string
wasCalled bool
}
func (m *mockConfigImportAPI) ImportImageConfig(ctx context.Context, sessionID string, contents interface{}) (external.ImageImportContentResponse, *http.Response, error) {
m.wasCalled = true
m.model = contents
m.sessionID = sessionID
m.ctx = ctx
if m.httpResponse == nil {
m.httpResponse = &http.Response{}
}
m.httpResponse.Body = ioutils.NewReadCloserWrapper(strings.NewReader(""), func() error { return nil })
return external.ImageImportContentResponse{Digest: m.responseDigest}, m.httpResponse, m.err
}
func TestConfigImport(t *testing.T) {
sessionID := "my-session"
tests := []struct {
name string
manifestJSONStr string
api *mockConfigImportAPI
expectsError bool
expectsCall bool
}{
{
name: "Go case: import works",
manifestJSONStr: `{ "key": "the-manifest-contents!" }`,
api: &mockConfigImportAPI{
httpResponse: &http.Response{StatusCode: 200},
responseDigest: "digest!",
},
expectsCall: true,
},
{
name: "No manifest provided",
manifestJSONStr: "",
api: &mockConfigImportAPI{},
expectsCall: false,
},
{
name: "API returns an error",
manifestJSONStr: `{ "key": "the-manifest-contents!" }`,
api: &mockConfigImportAPI{
err: fmt.Errorf("api error, something went wrong"),
},
expectsError: true,
expectsCall: true,
},
{
name: "API HTTP-level error",
manifestJSONStr: `{ "key": "the-manifest-contents!" }`,
api: &mockConfigImportAPI{
httpResponse: &http.Response{StatusCode: 404},
},
expectsError: true,
expectsCall: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
digest, err := importConfig(context.TODO(), test.api, sessionID, []byte(test.manifestJSONStr), &progress.Stage{})
// validate error handling
if err != nil && !test.expectsError {
t.Fatalf("did not expect an error, but got: %+v", err)
} else if err == nil && test.expectsError {
t.Fatalf("did expect an error, but got none")
}
if !test.api.wasCalled && test.expectsCall {
t.Fatalf("was not called!")
} else if test.api.wasCalled && !test.expectsCall {
t.Fatalf("should not have been called")
}
if !test.expectsCall {
return
}
if digest != test.api.responseDigest {
t.Errorf("unexpected content digest: %q != %q", digest, test.api.responseDigest)
}
// validating that the mock got the right parameters
if test.api.sessionID != sessionID {
t.Errorf("different session ID: %s != %s", test.api.sessionID, sessionID)
}
var expected map[string]interface{}
if err := json.Unmarshal([]byte(test.manifestJSONStr), &expected); err != nil {
t.Fatalf("could not unmarshal expected results")
}
for _, d := range deep.Equal(test.api.model, expected) {
t.Errorf("model difference: %s", d)
}
})
}
}
+43
View File
@@ -0,0 +1,43 @@
package anchore
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/wagoodman/go-progress"
"github.com/anchore/syft/internal/log"
"github.com/anchore/client-go/pkg/external"
)
type dockerfileImportAPI interface {
ImportImageDockerfile(ctx context.Context, sessionID string, contents string) (external.ImageImportContentResponse, *http.Response, error)
}
func importDockerfile(ctx context.Context, api dockerfileImportAPI, sessionID string, dockerfile []byte, stage *progress.Stage) (string, error) {
if len(dockerfile) > 0 {
log.Debug("importing dockerfile")
stage.Current = "dockerfile"
response, httpResponse, err := api.ImportImageDockerfile(ctx, sessionID, string(dockerfile))
if err != nil {
var openAPIErr external.GenericOpenAPIError
if errors.As(err, &openAPIErr) {
log.Errorf("api response: %+v", string(openAPIErr.Body()))
}
return "", fmt.Errorf("unable to import Dockerfile: %w", err)
}
defer httpResponse.Body.Close()
if httpResponse.StatusCode != 200 {
return "", fmt.Errorf("unable to import Dockerfile: %s", httpResponse.Status)
}
return response.Digest, nil
}
return "", nil
}
+124
View File
@@ -0,0 +1,124 @@
package anchore
import (
"context"
"fmt"
"net/http"
"strings"
"testing"
"github.com/wagoodman/go-progress"
"github.com/docker/docker/pkg/ioutils"
"github.com/anchore/client-go/pkg/external"
"github.com/go-test/deep"
)
type mockDockerfileImportAPI struct {
sessionID string
model string
httpResponse *http.Response
err error
ctx context.Context
responseDigest string
wasCalled bool
}
func (m *mockDockerfileImportAPI) ImportImageDockerfile(ctx context.Context, sessionID string, contents string) (external.ImageImportContentResponse, *http.Response, error) {
m.wasCalled = true
m.model = contents
m.sessionID = sessionID
m.ctx = ctx
if m.httpResponse == nil {
m.httpResponse = &http.Response{}
}
m.httpResponse.Body = ioutils.NewReadCloserWrapper(strings.NewReader(""), func() error { return nil })
return external.ImageImportContentResponse{Digest: m.responseDigest}, m.httpResponse, m.err
}
func TestDockerfileImport(t *testing.T) {
sessionID := "my-session"
tests := []struct {
name string
dockerfile string
api *mockDockerfileImportAPI
expectsError bool
expectsCall bool
}{
{
name: "Go case: import works",
dockerfile: "the-manifest-contents!",
api: &mockDockerfileImportAPI{
httpResponse: &http.Response{StatusCode: 200},
responseDigest: "digest!",
},
expectsCall: true,
},
{
name: "No manifest provided",
dockerfile: "",
api: &mockDockerfileImportAPI{},
expectsCall: false,
},
{
name: "API returns an error",
dockerfile: "the-manifest-contents!",
api: &mockDockerfileImportAPI{
err: fmt.Errorf("api error, something went wrong"),
},
expectsError: true,
expectsCall: true,
},
{
name: "API HTTP-level error",
dockerfile: "the-manifest-contents!",
api: &mockDockerfileImportAPI{
httpResponse: &http.Response{StatusCode: 404},
},
expectsError: true,
expectsCall: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
digest, err := importDockerfile(context.TODO(), test.api, sessionID, []byte(test.dockerfile), &progress.Stage{})
// validate error handling
if err != nil && !test.expectsError {
t.Fatalf("did not expect an error, but got: %+v", err)
} else if err == nil && test.expectsError {
t.Fatalf("did expect an error, but got none")
}
if !test.api.wasCalled && test.expectsCall {
t.Fatalf("was not called!")
} else if test.api.wasCalled && !test.expectsCall {
t.Fatalf("should not have been called")
}
if !test.expectsCall {
return
}
if digest != test.api.responseDigest {
t.Errorf("unexpected content digest: %q != %q", digest, test.api.responseDigest)
}
// validating that the mock got the right parameters
if test.api.sessionID != sessionID {
t.Errorf("different session ID: %s != %s", test.api.sessionID, sessionID)
}
for _, d := range deep.Equal(test.api.model, test.dockerfile) {
t.Errorf("model difference: %s", d)
}
})
}
}
+50
View File
@@ -0,0 +1,50 @@
// nolint: dupl
package anchore
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/wagoodman/go-progress"
"github.com/anchore/client-go/pkg/external"
"github.com/anchore/syft/internal/log"
)
type manifestImportAPI interface {
ImportImageManifest(ctx context.Context, sessionID string, contents interface{}) (external.ImageImportContentResponse, *http.Response, error)
}
func importManifest(ctx context.Context, api manifestImportAPI, sessionID string, manifest []byte, stage *progress.Stage) (string, error) {
if len(manifest) > 0 {
log.Debug("importing image manifest")
stage.Current = "image manifest"
// API requires an object, but we do not verify the shape of this object locally
var sender map[string]interface{}
if err := json.Unmarshal(manifest, &sender); err != nil {
return "", err
}
response, httpResponse, err := api.ImportImageManifest(ctx, sessionID, sender)
if err != nil {
var openAPIErr external.GenericOpenAPIError
if errors.As(err, &openAPIErr) {
log.Errorf("api response: %+v", string(openAPIErr.Body()))
}
return "", fmt.Errorf("unable to import Manifest: %w", err)
}
defer httpResponse.Body.Close()
if httpResponse.StatusCode != 200 {
return "", fmt.Errorf("unable to import Manifest: %s", httpResponse.Status)
}
return response.Digest, nil
}
return "", nil
}
+129
View File
@@ -0,0 +1,129 @@
package anchore
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/wagoodman/go-progress"
"github.com/anchore/client-go/pkg/external"
"github.com/docker/docker/pkg/ioutils"
"github.com/go-test/deep"
)
type mockManifestImportAPI struct {
sessionID string
model interface{}
httpResponse *http.Response
err error
ctx context.Context
responseDigest string
wasCalled bool
}
func (m *mockManifestImportAPI) ImportImageManifest(ctx context.Context, sessionID string, contents interface{}) (external.ImageImportContentResponse, *http.Response, error) {
m.wasCalled = true
m.model = contents
m.sessionID = sessionID
m.ctx = ctx
if m.httpResponse == nil {
m.httpResponse = &http.Response{}
}
m.httpResponse.Body = ioutils.NewReadCloserWrapper(strings.NewReader(""), func() error { return nil })
return external.ImageImportContentResponse{Digest: m.responseDigest}, m.httpResponse, m.err
}
func TestManifestImport(t *testing.T) {
sessionID := "my-session"
tests := []struct {
name string
manifest string
api *mockManifestImportAPI
expectsError bool
expectsCall bool
}{
{
name: "Go case: import works",
manifest: `{ "key": "the-config-contents!" }`,
api: &mockManifestImportAPI{
httpResponse: &http.Response{StatusCode: 200},
responseDigest: "digest!",
},
expectsCall: true,
},
{
name: "No manifest provided",
manifest: "",
api: &mockManifestImportAPI{},
expectsCall: false,
},
{
name: "API returns an error",
manifest: `{ "key": "the-config-contents!" }`,
api: &mockManifestImportAPI{
err: fmt.Errorf("api error, something went wrong"),
},
expectsError: true,
expectsCall: true,
},
{
name: "API HTTP-level error",
manifest: `{ "key": "the-config-contents!" }`,
api: &mockManifestImportAPI{
httpResponse: &http.Response{StatusCode: 404},
},
expectsError: true,
expectsCall: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
digest, err := importManifest(context.TODO(), test.api, sessionID, []byte(test.manifest), &progress.Stage{})
// validate error handling
if err != nil && !test.expectsError {
t.Fatalf("did not expect an error, but got: %+v", err)
} else if err == nil && test.expectsError {
t.Fatalf("did expect an error, but got none")
}
if !test.api.wasCalled && test.expectsCall {
t.Fatalf("was not called!")
} else if test.api.wasCalled && !test.expectsCall {
t.Fatalf("should not have been called")
}
if !test.expectsCall {
return
}
if digest != test.api.responseDigest {
t.Errorf("unexpected content digest: %q != %q", digest, test.api.responseDigest)
}
// validating that the mock got the right parameters
if test.api.sessionID != sessionID {
t.Errorf("different session ID: %s != %s", test.api.sessionID, sessionID)
}
var expected map[string]interface{}
if err := json.Unmarshal([]byte(test.manifest), &expected); err != nil {
t.Fatalf("could not unmarshal expected results")
}
for _, d := range deep.Equal(test.api.model, expected) {
t.Errorf("model difference: %s", d)
}
})
}
}
+67
View File
@@ -0,0 +1,67 @@
package anchore
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/syft/internal/formats/syftjson"
"github.com/wagoodman/go-progress"
"github.com/anchore/client-go/pkg/external"
"github.com/anchore/syft/internal/log"
)
type packageSBOMImportAPI interface {
ImportImagePackages(context.Context, string, external.ImagePackageManifest) (external.ImageImportContentResponse, *http.Response, error)
}
func packageSbomModel(s sbom.SBOM) (*external.ImagePackageManifest, error) {
var buf bytes.Buffer
err := syftjson.Format().Presenter(s).Present(&buf)
if err != nil {
return nil, fmt.Errorf("unable to serialize results: %w", err)
}
// the model is 1:1 the JSON output of today. As the schema changes, this will need to be converted into individual mappings.
var model external.ImagePackageManifest
if err = json.Unmarshal(buf.Bytes(), &model); err != nil {
return nil, fmt.Errorf("unable to convert JSON presenter output to import model: %w", err)
}
return &model, nil
}
func importPackageSBOM(ctx context.Context, api packageSBOMImportAPI, sessionID string, s sbom.SBOM, stage *progress.Stage) (string, error) {
log.Debug("importing package SBOM")
stage.Current = "package SBOM"
model, err := packageSbomModel(s)
if err != nil {
return "", fmt.Errorf("unable to create PackageSBOM model: %w", err)
}
response, httpResponse, err := api.ImportImagePackages(ctx, sessionID, *model)
if err != nil {
var openAPIErr external.GenericOpenAPIError
if errors.As(err, &openAPIErr) {
log.Errorf("api response: %+v", string(openAPIErr.Body()))
}
return "", fmt.Errorf("unable to import PackageSBOM: %w", err)
}
defer httpResponse.Body.Close()
if httpResponse.StatusCode != 200 {
return "", fmt.Errorf("unable to import PackageSBOM: %s", httpResponse.Status)
}
return response.Digest, nil
}
@@ -0,0 +1,283 @@
package anchore
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/anchore/syft/syft/sbom"
"github.com/anchore/client-go/pkg/external"
"github.com/anchore/syft/internal/formats/syftjson"
syftjsonModel "github.com/anchore/syft/internal/formats/syftjson/model"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
"github.com/docker/docker/pkg/ioutils"
"github.com/go-test/deep"
"github.com/wagoodman/go-progress"
)
func must(c pkg.CPE, e error) pkg.CPE {
if e != nil {
panic(e)
}
return c
}
// this test is tailored towards the assumption that the import doc shape and the syft json shape are the same.
// TODO: replace this as the document shapes diverge.
func TestPackageSbomToModel(t *testing.T) {
m := source.Metadata{
Scheme: source.ImageScheme,
ImageMetadata: source.ImageMetadata{
UserInput: "user-in",
Layers: []source.LayerMetadata{
{
MediaType: "layer-metadata-type!",
Digest: "layer-digest",
Size: 20,
},
},
Size: 10,
ManifestDigest: "sha256:digest!",
MediaType: "mediatype!",
Tags: nil,
},
}
d, _ := distro.NewDistro(distro.CentOS, "8.0", "")
p := pkg.Package{
Name: "name",
Version: "version",
FoundBy: "foundBy",
Locations: []source.Location{
{
Coordinates: source.Coordinates{
RealPath: "path",
FileSystemID: "layerID",
},
},
},
Licenses: []string{"license"},
Language: pkg.Python,
Type: pkg.PythonPkg,
CPEs: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*")),
},
PURL: "purl",
}
c := pkg.NewCatalog(p)
sbomResult := sbom.SBOM{
Artifacts: sbom.Artifacts{
PackageCatalog: c,
Distro: &d,
},
Source: m,
}
model, err := packageSbomModel(sbomResult)
if err != nil {
t.Fatalf("unable to generate model from source material: %+v", err)
}
var modelJSON []byte
modelJSON, err = json.Marshal(&model)
if err != nil {
t.Fatalf("unable to marshal model: %+v", err)
}
s := sbom.SBOM{
Artifacts: sbom.Artifacts{
PackageCatalog: c,
Distro: &d,
},
Source: m,
}
var buf bytes.Buffer
pres := syftjson.Format().Presenter(s)
if err := pres.Present(&buf); err != nil {
t.Fatalf("unable to get expected json: %+v", err)
}
// unmarshal expected result
var expectedDoc syftjsonModel.Document
if err := json.Unmarshal(buf.Bytes(), &expectedDoc); err != nil {
t.Fatalf("unable to parse json doc: %+v", err)
}
// unmarshal actual result
var actualDoc syftjsonModel.Document
if err := json.Unmarshal(modelJSON, &actualDoc); err != nil {
t.Fatalf("unable to parse json doc: %+v", err)
}
for _, d := range deep.Equal(actualDoc, expectedDoc) {
if strings.HasSuffix(d, "<nil slice> != []") {
// do not consider nil vs empty collection semantics as a "difference"
continue
}
t.Errorf("diff: %+v", d)
}
}
type mockPackageSBOMImportAPI struct {
sessionID string
model external.ImagePackageManifest
httpResponse *http.Response
err error
ctx context.Context
responseDigest string
}
func (m *mockPackageSBOMImportAPI) ImportImagePackages(ctx context.Context, sessionID string, model external.ImagePackageManifest) (external.ImageImportContentResponse, *http.Response, error) {
m.model = model
m.sessionID = sessionID
m.ctx = ctx
if m.httpResponse == nil {
m.httpResponse = &http.Response{}
}
m.httpResponse.Body = ioutils.NewReadCloserWrapper(strings.NewReader(""), func() error { return nil })
return external.ImageImportContentResponse{Digest: m.responseDigest}, m.httpResponse, m.err
}
func TestPackageSbomImport(t *testing.T) {
catalog := pkg.NewCatalog(pkg.Package{
Name: "name",
Version: "version",
FoundBy: "foundBy",
Locations: []source.Location{
{
Coordinates: source.Coordinates{
RealPath: "path",
FileSystemID: "layerID",
},
},
},
Licenses: []string{"license"},
Language: pkg.Python,
Type: pkg.PythonPkg,
CPEs: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*")),
},
PURL: "purl",
MetadataType: pkg.PythonPackageMetadataType,
Metadata: pkg.PythonPackageMetadata{
Name: "p-name",
Version: "p-version",
License: "p-license",
Author: "p-author",
AuthorEmail: "p-email",
Platform: "p-platform",
Files: []pkg.PythonFileRecord{
{
Path: "p-path",
Digest: &pkg.PythonFileDigest{
Algorithm: "p-alg",
Value: "p-digest",
},
Size: "p-size",
},
},
SitePackagesRootPath: "p-site-packages-root",
TopLevelPackages: []string{"top-level"},
},
})
m := source.Metadata{
Scheme: source.ImageScheme,
ImageMetadata: source.ImageMetadata{
UserInput: "user-in",
Layers: nil,
Size: 10,
ManifestDigest: "sha256:digest!",
MediaType: "mediatype!",
Tags: nil,
},
}
d, _ := distro.NewDistro(distro.CentOS, "8.0", "")
sbomResult := sbom.SBOM{
Artifacts: sbom.Artifacts{
PackageCatalog: catalog,
Distro: &d,
},
Source: m,
}
theModel, err := packageSbomModel(sbomResult)
if err != nil {
t.Fatalf("could not get sbom model: %+v", err)
}
sessionID := "my-session"
tests := []struct {
name string
api *mockPackageSBOMImportAPI
expectsError bool
}{
{
name: "Go case: import works",
api: &mockPackageSBOMImportAPI{
httpResponse: &http.Response{StatusCode: 200},
responseDigest: "digest!",
},
},
{
name: "API returns an error",
api: &mockPackageSBOMImportAPI{
err: fmt.Errorf("API error, something went wrong."),
},
expectsError: true,
},
{
name: "API HTTP-level error",
api: &mockPackageSBOMImportAPI{
httpResponse: &http.Response{StatusCode: 404},
},
expectsError: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
digest, err := importPackageSBOM(context.TODO(), test.api, sessionID, sbomResult, &progress.Stage{})
// validate error handling
if err != nil && !test.expectsError {
t.Fatalf("did not expect an error, but got: %+v", err)
} else if err == nil && test.expectsError {
t.Fatalf("did expect an error, but got none")
}
if digest != test.api.responseDigest {
t.Errorf("unexpected content digest: %q != %q", digest, test.api.responseDigest)
}
// validating that the mock got the right parameters (api.ImportImagePackages)
if test.api.sessionID != sessionID {
t.Errorf("different session ID: %s != %s", test.api.sessionID, sessionID)
}
for _, d := range deep.Equal(&test.api.model, theModel) {
t.Errorf("model difference: %s", d)
}
})
}
}
+35
View File
@@ -0,0 +1,35 @@
/*
Package bus provides access to a singleton instance of an event bus (provided by the calling application). The event bus
is intended to allow for the syft library to publish events which library consumers can subscribe to. These events
can provide static information, but also have an object as a payload for which the consumer can poll for updates.
This is akin to a logger, except instead of only allowing strings to be logged, rich objects that can be interacted with.
Note that the singleton instance is only allowed to publish events and not subscribe to them --this is intentional.
Internal library interactions should continue to use traditional in-execution-path approaches for data sharing
(e.g. function returns and channels) and not depend on bus subscriptions for critical interactions (e.g. one part of the
lib publishes an event and another part of the lib subscribes and reacts to that event). The bus is provided only as a
means for consumers to observe events emitted from the library (such as to provide a rich UI) and not to allow
consumers to augment or otherwise change execution.
*/
package bus
import "github.com/wagoodman/go-partybus"
var publisher partybus.Publisher
var active bool
// SetPublisher sets the singleton event bus publisher. This is optional; if no bus is provided, the library will
// behave no differently than if a bus had been provided.
func SetPublisher(p partybus.Publisher) {
publisher = p
if p != nil {
active = true
}
}
// Publish an event onto the bus. If there is no bus set by the calling application, this does nothing.
func Publish(event partybus.Event) {
if active {
publisher.Publish(event)
}
}
+21
View File
@@ -0,0 +1,21 @@
package config
import "github.com/spf13/viper"
type anchore struct {
// upload options
Host string `yaml:"host" json:"host" mapstructure:"host"` // -H , hostname of the engine/enterprise instance to upload to (setting this value enables upload)
Path string `yaml:"path" json:"path" mapstructure:"path"` // override the engine/enterprise API upload path
// IMPORTANT: do not show the username in any YAML/JSON output (sensitive information)
Username string `yaml:"-" json:"-" mapstructure:"username"` // -u , username to authenticate upload
// IMPORTANT: do not show the password in any YAML/JSON output (sensitive information)
Password string `yaml:"-" json:"-" mapstructure:"password"` // -p , password to authenticate upload
Dockerfile string `yaml:"dockerfile" json:"dockerfile" mapstructure:"dockerfile"` // -d , dockerfile to attach for upload
OverwriteExistingImage bool `yaml:"overwrite-existing-image" json:"overwrite-existing-image" mapstructure:"overwrite-existing-image"` // --overwrite-existing-image , if any of the SBOM components have already been uploaded this flag will ensure they are overwritten with the current upload
ImportTimeout uint `yaml:"import-timeout" json:"import-timeout" mapstructure:"import-timeout"` // --import-timeout
// , customize the number of seconds within which the SBOM import must be completed or canceled
}
func (cfg anchore) loadDefaultValues(v *viper.Viper) {
v.SetDefault("anchore.path", "")
}
+249
View File
@@ -0,0 +1,249 @@
package config
import (
"errors"
"fmt"
"path"
"reflect"
"strings"
"github.com/adrg/xdg"
"github.com/anchore/syft/internal"
"github.com/mitchellh/go-homedir"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
"gopkg.in/yaml.v2"
)
var ErrApplicationConfigNotFound = fmt.Errorf("application config not found")
var catalogerEnabledDefault = false
type defaultValueLoader interface {
loadDefaultValues(*viper.Viper)
}
type parser interface {
parseConfigValues() error
}
// Application is the main syft application configuration.
type Application struct {
ConfigPath string `yaml:",omitempty" json:"configPath"` // the location where the application config was read from (either from -c or discovered while loading)
Output string `yaml:"output" json:"output" mapstructure:"output"` // -o, the Presenter hint string to use for report formatting
File string `yaml:"file" json:"file" mapstructure:"file"` // --file, the file to write report output to
Quiet bool `yaml:"quiet" json:"quiet" mapstructure:"quiet"` // -q, indicates to not show any status output to stderr (ETUI or logging UI)
CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not
Anchore anchore `yaml:"anchore" json:"anchore" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise
CliOptions CliOnlyOptions `yaml:"-" json:"-"` // all options only available through the CLI (not via env vars or config)
Dev development `yaml:"dev" json:"dev" mapstructure:"dev"`
Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options
Package packages `yaml:"package" json:"package" mapstructure:"package"`
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
FileClassification fileClassification `yaml:"file-classification" json:"file-classification" mapstructure:"file-classification"`
FileContents fileContents `yaml:"file-contents" json:"file-contents" mapstructure:"file-contents"`
Secrets secrets `yaml:"secrets" json:"secrets" mapstructure:"secrets"`
Registry registry `yaml:"registry" json:"registry" mapstructure:"registry"`
}
// PowerUserCatalogerEnabledDefault switches all catalogers to be enabled when running power-user command
func PowerUserCatalogerEnabledDefault() {
catalogerEnabledDefault = true
}
func newApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions) *Application {
config := &Application{
CliOptions: cliOpts,
}
config.loadDefaultValues(v)
return config
}
// LoadApplicationConfig populates the given viper object with application configuration discovered on disk
func LoadApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions) (*Application, error) {
// the user may not have a config, and this is OK, we can use the default config + default cobra cli values instead
config := newApplicationConfig(v, cliOpts)
if err := readConfig(v, cliOpts.ConfigPath); err != nil && !errors.Is(err, ErrApplicationConfigNotFound) {
return nil, err
}
if err := v.Unmarshal(config); err != nil {
return nil, fmt.Errorf("unable to parse config: %w", err)
}
config.ConfigPath = v.ConfigFileUsed()
if err := config.parseConfigValues(); err != nil {
return nil, fmt.Errorf("invalid application config: %w", err)
}
return config, nil
}
// init loads the default configuration values into the viper instance (before the config values are read and parsed).
func (cfg Application) loadDefaultValues(v *viper.Viper) {
// set the default values for primitive fields in this struct
v.SetDefault("check-for-app-update", true)
// for each field in the configuration struct, see if the field implements the defaultValueLoader interface and invoke it if it does
value := reflect.ValueOf(cfg)
for i := 0; i < value.NumField(); i++ {
// note: the defaultValueLoader method receiver is NOT a pointer receiver.
if loadable, ok := value.Field(i).Interface().(defaultValueLoader); ok {
// the field implements defaultValueLoader, call it
loadable.loadDefaultValues(v)
}
}
}
func (cfg *Application) parseConfigValues() error {
// parse application config options
for _, optionFn := range []func() error{
cfg.parseUploadOptions,
cfg.parseLogLevelOption,
} {
if err := optionFn(); err != nil {
return err
}
}
// parse nested config options
// for each field in the configuration struct, see if the field implements the parser interface
// note: the app config is a pointer, so we need to grab the elements explicitly (to traverse the address)
value := reflect.ValueOf(cfg).Elem()
for i := 0; i < value.NumField(); i++ {
// note: since the interface method of parser is a pointer receiver we need to get the value of the field as a pointer.
if parsable, ok := value.Field(i).Addr().Interface().(parser); ok {
// the field implements parser, call it
if err := parsable.parseConfigValues(); err != nil {
return err
}
}
}
return nil
}
func (cfg *Application) parseUploadOptions() error {
if cfg.Anchore.Host == "" && cfg.Anchore.Dockerfile != "" {
return fmt.Errorf("cannot provide dockerfile option without enabling upload")
}
return nil
}
func (cfg *Application) parseLogLevelOption() error {
switch {
case cfg.Quiet:
// TODO: this is bad: quiet option trumps all other logging options (such as to a file on disk)
// we should be able to quiet the console logging and leave file logging alone...
// ... this will be an enhancement for later
cfg.Log.LevelOpt = logrus.PanicLevel
case cfg.Log.Level != "":
if cfg.CliOptions.Verbosity > 0 {
return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together")
}
lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level))
if err != nil {
return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err)
}
cfg.Log.LevelOpt = lvl
if cfg.Log.LevelOpt >= logrus.InfoLevel {
cfg.CliOptions.Verbosity = 1
}
default:
switch v := cfg.CliOptions.Verbosity; {
case v == 1:
cfg.Log.LevelOpt = logrus.InfoLevel
case v >= 2:
cfg.Log.LevelOpt = logrus.DebugLevel
default:
cfg.Log.LevelOpt = logrus.ErrorLevel
}
}
if cfg.Log.Level == "" {
cfg.Log.Level = cfg.Log.LevelOpt.String()
}
return nil
}
func (cfg Application) String() string {
// yaml is pretty human friendly (at least when compared to json)
appCfgStr, err := yaml.Marshal(&cfg)
if err != nil {
return err.Error()
}
return string(appCfgStr)
}
// readConfig attempts to read the given config path from disk or discover an alternate store location
// nolint:funlen
func readConfig(v *viper.Viper, configPath string) error {
var err error
v.AutomaticEnv()
v.SetEnvPrefix(internal.ApplicationName)
// allow for nested options to be specified via environment variables
// e.g. pod.context = APPNAME_POD_CONTEXT
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
// use explicitly the given user config
if configPath != "" {
v.SetConfigFile(configPath)
if err := v.ReadInConfig(); err != nil {
return fmt.Errorf("unable to read application config=%q : %w", configPath, err)
}
// don't fall through to other options if the config path was explicitly provided
return nil
}
// start searching for valid configs in order...
// 1. look for .<appname>.yaml (in the current directory)
v.AddConfigPath(".")
v.SetConfigName("." + internal.ApplicationName)
if err = v.ReadInConfig(); err == nil {
return nil
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
}
// 2. look for .<appname>/config.yaml (in the current directory)
v.AddConfigPath("." + internal.ApplicationName)
v.SetConfigName("config")
if err = v.ReadInConfig(); err == nil {
return nil
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
}
// 3. look for ~/.<appname>.yaml
home, err := homedir.Dir()
if err == nil {
v.AddConfigPath(home)
v.SetConfigName("." + internal.ApplicationName)
if err = v.ReadInConfig(); err == nil {
return nil
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
}
}
// 4. look for <appname>/config.yaml in xdg locations (starting with xdg home config dir, then moving upwards)
v.AddConfigPath(path.Join(xdg.ConfigHome, internal.ApplicationName))
for _, dir := range xdg.ConfigDirs {
v.AddConfigPath(path.Join(dir, internal.ApplicationName))
}
v.SetConfigName("config")
if err = v.ReadInConfig(); err == nil {
return nil
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
}
return ErrApplicationConfigNotFound
}
+23
View File
@@ -0,0 +1,23 @@
package config
import (
"fmt"
"github.com/anchore/syft/syft/source"
)
type catalogerOptions struct {
Enabled bool `yaml:"enabled" json:"enabled" mapstructure:"enabled"`
Scope string `yaml:"scope" json:"scope" mapstructure:"scope"`
ScopeOpt source.Scope `yaml:"-" json:"-"`
}
func (cfg *catalogerOptions) parseConfigValues() error {
scopeOption := source.ParseScope(cfg.Scope)
if scopeOption == source.UnknownScope {
return fmt.Errorf("bad scope value %q", cfg.Scope)
}
cfg.ScopeOpt = scopeOption
return nil
}
+7
View File
@@ -0,0 +1,7 @@
package config
// CliOnlyOptions are options that are in the application config in memory, but are only exposed via CLI switches (not from unmarshaling a config file)
type CliOnlyOptions struct {
ConfigPath string // -c. where the read config is on disk
Verbosity int // -v or -vv , controlling which UI (ETUI vs logging) and what the log level should be
}
-173
View File
@@ -1,173 +0,0 @@
package config
import (
"fmt"
"path"
"strings"
"github.com/adrg/xdg"
"github.com/anchore/imgbom/imgbom/presenter"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/imgbom/internal"
"github.com/mitchellh/go-homedir"
"github.com/spf13/viper"
"go.uber.org/zap/zapcore"
)
type CliOnlyOptions struct {
ConfigPath string
Verbosity int
}
type Application struct {
ConfigPath string
PresenterOpt presenter.Option
Output string `mapstructure:"output"`
ScopeOpt scope.Option
Scope string `mapstructure:"scope"`
Quiet bool `mapstructure:"quiet"`
Log Logging `mapstructure:"log"`
CliOptions CliOnlyOptions
}
type Logging struct {
Structured bool `mapstructure:"structured"`
LevelOpt zapcore.Level
Level string `mapstructure:"level"`
FileLocation string `mapstructure:"file"`
}
func setNonCliDefaultValues(v *viper.Viper) {
v.SetDefault("log.level", "")
v.SetDefault("log.file", "")
v.SetDefault("log.structured", false)
}
func LoadConfigFromFile(v *viper.Viper, cliOpts *CliOnlyOptions) (*Application, error) {
// the user may not have a config, and this is OK, we can use the default config + default cobra cli values instead
setNonCliDefaultValues(v)
if cliOpts != nil {
_ = readConfig(v, cliOpts.ConfigPath)
} else {
_ = readConfig(v, "")
}
config := &Application{
CliOptions: *cliOpts,
}
err := v.Unmarshal(config)
if err != nil {
return nil, fmt.Errorf("unable to parse config: %w", err)
}
config.ConfigPath = v.ConfigFileUsed()
err = config.Build()
if err != nil {
return nil, fmt.Errorf("invalid config: %w", err)
}
return config, nil
}
func (cfg *Application) Build() error {
// set the presenter
presenterOption := presenter.ParseOption(cfg.Output)
if presenterOption == presenter.UnknownPresenter {
return fmt.Errorf("bad --output value '%s'", cfg.Output)
}
cfg.PresenterOpt = presenterOption
// set the scope
scopeOption := scope.ParseOption(cfg.Scope)
if scopeOption == scope.UnknownScope {
return fmt.Errorf("bad --scope value '%s'", cfg.Scope)
}
cfg.ScopeOpt = scopeOption
if cfg.Quiet {
// TODO: this is bad: quiet option trumps all other logging options
// we should be able to quiet the consol logging and leave file logging alone...
// ... this will be an enhancement for later
cfg.Log.LevelOpt = zapcore.PanicLevel
} else {
if cfg.Log.Level != "" {
if cfg.CliOptions.Verbosity > 0 {
return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together")
}
// set the log level explicitly
err := cfg.Log.LevelOpt.Set(cfg.Log.Level)
if err != nil {
return fmt.Errorf("bad log level value '%s': %+v", cfg.Log.Level, err)
}
} else {
// set the log level implicitly
switch v := cfg.CliOptions.Verbosity; {
case v == 1:
cfg.Log.LevelOpt = zapcore.InfoLevel
case v >= 2:
cfg.Log.LevelOpt = zapcore.DebugLevel
default:
cfg.Log.LevelOpt = zapcore.ErrorLevel
}
}
}
return nil
}
func readConfig(v *viper.Viper, configPath string) error {
v.AutomaticEnv()
v.SetEnvPrefix(internal.ApplicationName)
// allow for nested options to be specified via environment variables
// e.g. pod.context = APPNAME_POD_CONTEXT
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
// use explicitly the given user config
if configPath != "" {
v.SetConfigFile(configPath)
if err := v.ReadInConfig(); err == nil {
return nil
}
// don't fall through to other options if this fails
return fmt.Errorf("unable to read config: %v", configPath)
}
// start searching for valid configs in order...
// 1. look for .<appname>.yaml (in the current directory)
v.AddConfigPath(".")
v.SetConfigName(internal.ApplicationName)
if err := v.ReadInConfig(); err == nil {
return nil
}
// 2. look for .<appname>/config.yaml (in the current directory)
v.AddConfigPath("." + internal.ApplicationName)
v.SetConfigName("config")
if err := v.ReadInConfig(); err == nil {
return nil
}
// 3. look for ~/.<appname>.yaml
home, err := homedir.Dir()
if err == nil {
v.AddConfigPath(home)
v.SetConfigName("." + internal.ApplicationName)
if err := v.ReadInConfig(); err == nil {
return nil
}
}
// 4. look for <appname>/config.yaml in xdg locations (starting with xdg home config dir, then moving upwards)
v.AddConfigPath(path.Join(xdg.ConfigHome, internal.ApplicationName))
for _, dir := range xdg.ConfigDirs {
v.AddConfigPath(path.Join(dir, internal.ApplicationName))
}
v.SetConfigName("config")
if err := v.ReadInConfig(); err == nil {
return nil
}
return fmt.Errorf("application config not found")
}
+13
View File
@@ -0,0 +1,13 @@
package config
import "github.com/spf13/viper"
type development struct {
ProfileCPU bool `yaml:"profile-cpu" json:"profile-cpu" mapstructure:"profile-cpu"`
ProfileMem bool `yaml:"profile-mem" json:"profile-mem" mapstructure:"profile-mem"`
}
func (cfg development) loadDefaultValues(v *viper.Viper) {
v.SetDefault("dev.profile-cpu", false)
v.SetDefault("dev.profile-mem", false)
}
+19
View File
@@ -0,0 +1,19 @@
package config
import (
"github.com/anchore/syft/syft/source"
"github.com/spf13/viper"
)
type fileClassification struct {
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
}
func (cfg fileClassification) loadDefaultValues(v *viper.Viper) {
v.SetDefault("file-classification.cataloger.enabled", catalogerEnabledDefault)
v.SetDefault("file-classification.cataloger.scope", source.SquashedScope)
}
func (cfg *fileClassification) parseConfigValues() error {
return cfg.Cataloger.parseConfigValues()
}
+24
View File
@@ -0,0 +1,24 @@
package config
import (
"github.com/anchore/syft/internal/file"
"github.com/anchore/syft/syft/source"
"github.com/spf13/viper"
)
type fileContents struct {
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
SkipFilesAboveSize int64 `yaml:"skip-files-above-size" json:"skip-files-above-size" mapstructure:"skip-files-above-size"`
Globs []string `yaml:"globs" json:"globs" mapstructure:"globs"`
}
func (cfg fileContents) loadDefaultValues(v *viper.Viper) {
v.SetDefault("file-contents.cataloger.enabled", catalogerEnabledDefault)
v.SetDefault("file-contents.cataloger.scope", source.SquashedScope)
v.SetDefault("file-contents.skip-files-above-size", 1*file.MB)
v.SetDefault("file-contents.globs", []string{})
}
func (cfg *fileContents) parseConfigValues() error {
return cfg.Cataloger.parseConfigValues()
}
+21
View File
@@ -0,0 +1,21 @@
package config
import (
"github.com/anchore/syft/syft/source"
"github.com/spf13/viper"
)
type FileMetadata struct {
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
Digests []string `yaml:"digests" json:"digests" mapstructure:"digests"`
}
func (cfg FileMetadata) loadDefaultValues(v *viper.Viper) {
v.SetDefault("file-metadata.cataloger.enabled", catalogerEnabledDefault)
v.SetDefault("file-metadata.cataloger.scope", source.SquashedScope)
v.SetDefault("file-metadata.digests", []string{"sha256"})
}
func (cfg *FileMetadata) parseConfigValues() error {
return cfg.Cataloger.parseConfigValues()
}
+18
View File
@@ -0,0 +1,18 @@
package config
import (
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
// logging contains all logging-related configuration options available to the user via the application config.
type logging struct {
Structured bool `yaml:"structured" json:"structured" mapstructure:"structured"` // show all log entries as JSON formatted strings
LevelOpt logrus.Level `yaml:"-" json:"-"` // the native log level object used by the logger
Level string `yaml:"level" json:"level" mapstructure:"level"` // the log level string hint
FileLocation string `yaml:"file" json:"file-location" mapstructure:"file"` // the file path to write logs to
}
func (cfg logging) loadDefaultValues(v *viper.Viper) {
v.SetDefault("log.structured", false)
}
+15
View File
@@ -0,0 +1,15 @@
package config
import "github.com/spf13/viper"
type packages struct {
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
}
func (cfg packages) loadDefaultValues(v *viper.Viper) {
v.SetDefault("package.cataloger.enabled", true)
}
func (cfg *packages) parseConfigValues() error {
return cfg.Cataloger.parseConfigValues()
}
+75
View File
@@ -0,0 +1,75 @@
package config
import (
"os"
"github.com/anchore/stereoscope/pkg/image"
"github.com/spf13/viper"
)
type RegistryCredentials struct {
Authority string `yaml:"authority" json:"authority" mapstructure:"authority"`
// IMPORTANT: do not show the username in any YAML/JSON output (sensitive information)
Username string `yaml:"-" json:"-" mapstructure:"username"`
// IMPORTANT: do not show the password in any YAML/JSON output (sensitive information)
Password string `yaml:"-" json:"-" mapstructure:"password"`
// IMPORTANT: do not show the token in any YAML/JSON output (sensitive information)
Token string `yaml:"-" json:"-" mapstructure:"token"`
}
type registry struct {
InsecureSkipTLSVerify bool `yaml:"insecure-skip-tls-verify" json:"insecure-skip-tls-verify" mapstructure:"insecure-skip-tls-verify"`
InsecureUseHTTP bool `yaml:"insecure-use-http" json:"insecure-use-http" mapstructure:"insecure-use-http"`
Auth []RegistryCredentials `yaml:"auth" json:"auth" mapstructure:"auth"`
}
func (cfg registry) loadDefaultValues(v *viper.Viper) {
v.SetDefault("registry.insecure-skip-tls-verify", false)
v.SetDefault("registry.insecure-use-http", false)
v.SetDefault("registry.auth", []RegistryCredentials{})
}
// nolint: unparam
func (cfg *registry) parseConfigValues() error {
// there may be additional credentials provided by env var that should be appended to the set of credentials
authority, username, password, token :=
os.Getenv("SYFT_REGISTRY_AUTH_AUTHORITY"),
os.Getenv("SYFT_REGISTRY_AUTH_USERNAME"),
os.Getenv("SYFT_REGISTRY_AUTH_PASSWORD"),
os.Getenv("SYFT_REGISTRY_AUTH_TOKEN")
if hasNonEmptyCredentials(username, password, token) {
// note: we prepend the credentials such that the environment variables take precedence over on-disk configuration.
cfg.Auth = append([]RegistryCredentials{
{
Authority: authority,
Username: username,
Password: password,
Token: token,
},
}, cfg.Auth...)
}
return nil
}
func hasNonEmptyCredentials(username, password, token string) bool {
return password != "" && username != "" || token != ""
}
func (cfg *registry) ToOptions() *image.RegistryOptions {
var auth = make([]image.RegistryCredentials, len(cfg.Auth))
for i, a := range cfg.Auth {
auth[i] = image.RegistryCredentials{
Authority: a.Authority,
Username: a.Username,
Password: a.Password,
Token: a.Token,
}
}
return &image.RegistryOptions{
InsecureSkipTLSVerify: cfg.InsecureSkipTLSVerify,
InsecureUseHTTP: cfg.InsecureUseHTTP,
Credentials: auth,
}
}
+111
View File
@@ -0,0 +1,111 @@
package config
import (
"fmt"
"github.com/anchore/stereoscope/pkg/image"
"testing"
"github.com/stretchr/testify/assert"
)
func TestHasNonEmptyCredentials(t *testing.T) {
tests := []struct {
username, password, token string
expected bool
}{
{
"", "", "",
false,
},
{
"user", "", "",
false,
},
{
"", "pass", "",
false,
},
{
"", "pass", "tok",
true,
},
{
"user", "", "tok",
true,
},
{
"", "", "tok",
true,
},
{
"user", "pass", "tok",
true,
},
{
"user", "pass", "",
true,
},
}
for _, test := range tests {
t.Run(fmt.Sprintf("%+v", test), func(t *testing.T) {
assert.Equal(t, test.expected, hasNonEmptyCredentials(test.username, test.password, test.token))
})
}
}
func Test_registry_ToOptions(t *testing.T) {
tests := []struct {
name string
input registry
expected image.RegistryOptions
}{
{
name: "no registry options",
input: registry{},
expected: image.RegistryOptions{
Credentials: []image.RegistryCredentials{},
},
},
{
name: "set InsecureSkipTLSVerify",
input: registry{
InsecureSkipTLSVerify: true,
},
expected: image.RegistryOptions{
InsecureSkipTLSVerify: true,
Credentials: []image.RegistryCredentials{},
},
},
{
name: "set InsecureUseHTTP",
input: registry{
InsecureUseHTTP: true,
},
expected: image.RegistryOptions{
InsecureUseHTTP: true,
Credentials: []image.RegistryCredentials{},
},
},
{
name: "set all bool options",
input: registry{
InsecureSkipTLSVerify: true,
InsecureUseHTTP: true,
},
expected: image.RegistryOptions{
InsecureSkipTLSVerify: true,
InsecureUseHTTP: true,
Credentials: []image.RegistryCredentials{},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
assert.Equal(t, &test.expected, test.input.ToOptions())
})
}
}
+28
View File
@@ -0,0 +1,28 @@
package config
import (
"github.com/anchore/syft/internal/file"
"github.com/anchore/syft/syft/source"
"github.com/spf13/viper"
)
type secrets struct {
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
AdditionalPatterns map[string]string `yaml:"additional-patterns" json:"additional-patterns" mapstructure:"additional-patterns"`
ExcludePatternNames []string `yaml:"exclude-pattern-names" json:"exclude-pattern-names" mapstructure:"exclude-pattern-names"`
RevealValues bool `yaml:"reveal-values" json:"reveal-values" mapstructure:"reveal-values"`
SkipFilesAboveSize int64 `yaml:"skip-files-above-size" json:"skip-files-above-size" mapstructure:"skip-files-above-size"`
}
func (cfg secrets) loadDefaultValues(v *viper.Viper) {
v.SetDefault("secrets.cataloger.enabled", catalogerEnabledDefault)
v.SetDefault("secrets.cataloger.scope", source.AllLayersScope)
v.SetDefault("secrets.reveal-values", false)
v.SetDefault("secrets.skip-files-above-size", 1*file.MB)
v.SetDefault("secrets.additional-patterns", map[string]string{})
v.SetDefault("secrets.exclude-pattern-names", []string{})
}
func (cfg *secrets) parseConfigValues() error {
return cfg.Cataloger.parseConfigValues()
}
+8 -2
View File
@@ -1,4 +1,10 @@
package internal
// note: must be a single word, all lowercase
const ApplicationName = "imgbom"
const (
// ApplicationName is the non-capitalized name of the application (do not change this)
ApplicationName = "syft"
// JSONSchemaVersion is the current schema version output by the JSON presenter
// This is roughly following the "SchemaVer" guidelines for versioning the JSON schema. Please see schema/json/README.md for details on how to increment.
JSONSchemaVersion = "2.0.1"
)
+4
View File
@@ -0,0 +1,4 @@
/*
Package internal contains miscellaneous functions and objects useful within syft but should not be used externally.
*/
package internal
+38
View File
@@ -0,0 +1,38 @@
package internal
import (
"fmt"
"io"
"os"
"github.com/anchore/syft/internal/log"
)
// CloseAndLogError closes the given io.Closer and reports any errors found as a warning in the log
func CloseAndLogError(closer io.Closer, location string) {
if err := closer.Close(); err != nil {
log.Warnf("unable to close file for location=%q: %+v", location, err)
}
}
type ErrPath struct {
Path string
Err error
}
func (e ErrPath) Error() string {
return fmt.Sprintf("unable to observe contents of %+v: %v", e.Path, e.Err)
}
func IsErrPath(err error) bool {
_, ok := err.(ErrPath)
return ok
}
func IsErrPathPermission(err error) bool {
pathErr, ok := err.(ErrPath)
if ok {
return os.IsPermission(pathErr.Err)
}
return ok
}
+46
View File
@@ -0,0 +1,46 @@
package file
// GlobMatch evaluates the given glob pattern against the given "name" string, indicating if there is a match or not.
// Source: https://research.swtch.com/glob.go
func GlobMatch(pattern, name string) bool {
px := 0
nx := 0
nextPx := 0
nextNx := 0
for px < len(pattern) || nx < len(name) {
if px < len(pattern) {
c := pattern[px]
switch c {
default: // ordinary character
if nx < len(name) && name[nx] == c {
px++
nx++
continue
}
case '?': // single-character wildcard
if nx < len(name) {
px++
nx++
continue
}
case '*': // zero-or-more-character wildcard
// Try to match at nx.
// If that doesn't work out,
// restart at nx+1 next.
nextPx = px
nextNx = nx + 1
px++
continue
}
}
// Mismatch. Maybe restart.
if 0 < nextNx && nextNx <= len(name) {
px = nextPx
nx = nextNx
continue
}
return false
}
// Matched all of pattern to all of name. Success.
return true
}
+39
View File
@@ -0,0 +1,39 @@
package file
import (
"strings"
"testing"
)
func TestGlobMatch(t *testing.T) {
var tests = []struct {
pattern string
data string
ok bool
}{
{"", "", true},
{"x", "", false},
{"", "x", false},
{"abc", "abc", true},
{"*", "abc", true},
{"*c", "abc", true},
{"*b", "abc", false},
{"a*", "abc", true},
{"b*", "abc", false},
{"a*", "a", true},
{"*a", "a", true},
{"a*b*c*d*e*", "axbxcxdxe", true},
{"a*b*c*d*e*", "axbxcxdxexxx", true},
{"a*b?c*x", "abxbbxdbxebxczzx", true},
{"a*b?c*x", "abxbbxdbxebxczzy", false},
{"a*a*a*a*b", strings.Repeat("a", 100), false},
{"*x", "xxx", true},
{"/home/place/**", "/home/place/a/thing", true},
}
for _, test := range tests {
if GlobMatch(test.pattern, test.data) != test.ok {
t.Errorf("failed glob='%s' data='%s'", test.pattern, test.data)
}
}
}
+16
View File
@@ -0,0 +1,16 @@
package file
import (
"io"
"os"
)
// Opener is an object that stores a path to later be opened as a file.
type Opener struct {
path string
}
// Open the stored path as a io.ReadCloser.
func (o Opener) Open() (io.ReadCloser, error) {
return os.Open(o.path)
}
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -eux
# $1 —— absolute path to destination file, should end with .zip, ideally
# $2 —— absolute path to directory from which to add entries to the archive
pushd "$2" && find . -print | zip "$1" -@ && popd
@@ -0,0 +1 @@
B file...
@@ -0,0 +1 @@
A file! nice!
+115
View File
@@ -0,0 +1,115 @@
package file
import (
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"syscall"
"testing"
"github.com/stretchr/testify/assert"
)
var expectedZipArchiveEntries = []string{
"some-dir" + string(os.PathSeparator),
filepath.Join("some-dir", "a-file.txt"),
"b-file.txt",
"nested.zip",
}
// createZipArchive creates a new ZIP archive file at destinationArchivePath based on the directory found at
// sourceDirPath.
func createZipArchive(t testing.TB, sourceDirPath, destinationArchivePath string) {
t.Helper()
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("unable to get cwd: %+v", err)
}
cmd := exec.Command("./generate-zip-fixture-from-source-dir.sh", destinationArchivePath, path.Base(sourceDirPath))
cmd.Dir = filepath.Join(cwd, "test-fixtures")
if err := cmd.Start(); err != nil {
t.Fatalf("unable to start generate zip fixture script: %+v", err)
}
if err := cmd.Wait(); err != nil {
if exiterr, ok := err.(*exec.ExitError); ok {
// The program has exited with an exit code != 0
// This works on both Unix and Windows. Although package
// syscall is generally platform dependent, WaitStatus is
// defined for both Unix and Windows and in both cases has
// an ExitStatus() method with the same signature.
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
if status.ExitStatus() != 0 {
t.Fatalf("failed to generate fixture: rc=%d", status.ExitStatus())
}
}
} else {
t.Fatalf("unable to get generate fixture script result: %+v", err)
}
}
}
func assertNoError(t testing.TB, fn func() error) func() {
return func() {
assert.NoError(t, fn())
}
}
// setupZipFileTest encapsulates common test setup work for zip file tests. It returns a cleanup function,
// which should be called (typically deferred) by the caller, the path of the created zip archive, and an error,
// which should trigger a fatal test failure in the consuming test. The returned cleanup function will never be nil
// (even if there's an error), and it should always be called.
func setupZipFileTest(t testing.TB, sourceDirPath string) string {
t.Helper()
archivePrefix, err := ioutil.TempFile("", "syft-ziputil-archive-TEST-")
if err != nil {
t.Fatalf("unable to create tempfile: %+v", err)
}
t.Cleanup(
assertNoError(t,
func() error {
return os.Remove(archivePrefix.Name())
},
),
)
destinationArchiveFilePath := archivePrefix.Name() + ".zip"
t.Logf("archive path: %s", destinationArchiveFilePath)
createZipArchive(t, sourceDirPath, destinationArchiveFilePath)
t.Cleanup(
assertNoError(t,
func() error {
return os.Remove(destinationArchiveFilePath)
},
),
)
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("unable to get cwd: %+v", err)
}
t.Logf("running from: %s", cwd)
return destinationArchiveFilePath
}
// TODO: Consider moving any non-git asset generation to a task (e.g. make) that's run ahead of running go tests.
func ensureNestedZipExists(t *testing.T, sourceDirPath string) error {
t.Helper()
nestedArchiveFilePath := path.Join(sourceDirPath, "nested.zip")
createZipArchive(t, sourceDirPath, nestedArchiveFilePath)
return nil
}
+70
View File
@@ -0,0 +1,70 @@
package file
import (
"fmt"
"os"
"sort"
"strings"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/log"
)
// ZipFileManifest is a collection of paths and their file metadata.
type ZipFileManifest map[string]os.FileInfo
// NewZipFileManifest creates and returns a new ZipFileManifest populated with path and metadata from the given zip archive path.
func NewZipFileManifest(archivePath string) (ZipFileManifest, error) {
zipReader, err := OpenZip(archivePath)
manifest := make(ZipFileManifest)
if err != nil {
return manifest, fmt.Errorf("unable to open zip archive (%s): %w", archivePath, err)
}
defer func() {
err = zipReader.Close()
if err != nil {
log.Warnf("unable to close zip archive (%s): %+v", archivePath, err)
}
}()
for _, file := range zipReader.Reader.File {
manifest.Add(file.Name, file.FileInfo())
}
return manifest, nil
}
// Add a new path and it's file metadata to the collection.
func (z ZipFileManifest) Add(entry string, info os.FileInfo) {
z[entry] = info
}
// GlobMatch returns the path keys that match the given value(s).
func (z ZipFileManifest) GlobMatch(patterns ...string) []string {
uniqueMatches := internal.NewStringSet()
for _, pattern := range patterns {
for entry := range z {
// We want to match globs as if entries begin with a leading slash (akin to an absolute path)
// so that glob logic is consistent inside and outside of ZIP archives
normalizedEntry := normalizeZipEntryName(entry)
if GlobMatch(pattern, normalizedEntry) {
uniqueMatches.Add(entry)
}
}
}
results := uniqueMatches.ToSlice()
sort.Strings(results)
return results
}
// normalizeZipEntryName takes the given path entry and ensures it is prefixed with "/".
func normalizeZipEntryName(entry string) string {
if !strings.HasPrefix(entry, "/") {
return "/" + entry
}
return entry
}

Some files were not shown because too many files have changed in this diff Show More