Merge pull request #1 from safedep/develop

Sync Develop to Main
This commit is contained in:
Abhisek Datta 2023-01-12 20:55:03 +05:30 committed by GitHub
commit bde7df3507
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 3653 additions and 23 deletions

2
.github/workflows/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
dist/

67
.github/workflows/goreleaser.yml vendored Normal file
View File

@ -0,0 +1,67 @@
name: goreleaser
on:
push:
tags:
- "*" # triggers only if push new tag version, like `0.8.4` or else
permissions:
contents: read
jobs:
goreleaser:
outputs:
hashes: ${{ steps.hash.outputs.hashes }}
permissions:
contents: write # for goreleaser/goreleaser-action to create a GitHub release
packages: write # for goreleaser/goreleaser-action to publish docker images
runs-on: ubuntu-latest
env:
# Required for buildx on docker 19.x
DOCKER_CLI_EXPERIMENTAL: "enabled"
steps:
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
with:
fetch-depth: 0
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2
- uses: docker/setup-buildx-action@8c0edbc76e98fa90f69d9a2c020dcb50019dc325 # v2
- name: Set up Go
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
with:
go-version: 1.19
check-latest: true
- name: ghcr-login
uses: docker/login-action@dd4fa0671be5250ee6f50aedf4cb05514abda2c7 # v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Run GoReleaser
id: run-goreleaser
uses: goreleaser/goreleaser-action@8f67e590f2d095516493f017008adc464e63adb1 # v4.1.0
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Generate subject
id: hash
env:
ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}"
run: |
set -euo pipefail
checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path')
echo "hashes=$(cat $checksum_file | base64 -w0)" >> "$GITHUB_OUTPUT"
provenance:
needs: [goreleaser]
permissions:
actions: read # To read the workflow path.
id-token: write # To sign the provenance.
contents: write # To add assets to a release.
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.4.0
with:
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
upload-assets: true
private-repository: true

3
.gitignore vendored
View File

@ -13,4 +13,7 @@
# Dependency directories (remove the comment below to include it)
# vendor/
/vet
dist/

43
.goreleaser.yaml Normal file
View File

@ -0,0 +1,43 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
before:
hooks:
- go mod tidy
- go generate ./...
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- darwin
goarch:
- amd64
- arm64
archives:
- format: tar.gz
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
format_overrides:
- goos: windows
format: zip
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
# The lines beneath this are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

35
Makefile Normal file
View File

@ -0,0 +1,35 @@
SHELL := /bin/bash
GITCOMMIT := $(shell git rev-parse HEAD)
VERSION := "$(shell git describe --tags --abbrev=0)-$(shell git rev-parse --short HEAD)"
all: clean setup vet
oapi-codegen-install:
go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.10.1
oapi-codegen:
oapi-codegen -package insightapi -generate types ./api/insights-v1.yml > ./gen/insightapi/insights.types.go
oapi-codegen -package insightapi -generate client ./api/insights-v1.yml > ./gen/insightapi/insights.client.go
setup:
mkdir -p out gen/insightapi
GO_CFLAGS=-X main.commit=$(GITCOMMIT) -X main.version=$(VERSION)
GO_LDFLAGS=-ldflags "-w $(GO_CFLAGS)"
vet: oapi-codegen
go build ${GO_LDFLAGS}
.PHONY: test
test:
go test ./...
.PHONY: clean
clean:
-rm -rf out
-rm -rf gen
gosec:
-docker run --rm -it -w /app/ -v `pwd`:/app/ securego/gosec \
-exclude-dir=/app/gen -exclude-dir=/app/spec \
/app/...

View File

@ -1,2 +1,42 @@
# vet
Tool for identifying software supply chain risks using Insights API
# vet : The dependency vetting tool
Tool for identifying software supply chain risks
## TL;DR
Build this repository
> Ensure `$(go env GOPATH)/bin` is in your `$PATH`
```bash
make oapi-codegen-install && make
```
Alternatively install using
```bash
go install github.com/safedep/vet@latest
```
Configure `vet` to use API Key to access [Insights API](#)
```bash
vet auth configure
```
> Alternatively pass the API key as environment to skip configuration
Run `vet` to identify risks
```bash
vet scan
```
## Usage
### Configuration
Insights API Key can be passed at runtime using environment variable
```bash
VET_INSIGHTS_API_KEY=... vet scan
```

780
api/insights-v1.yml Normal file
View File

@ -0,0 +1,780 @@
openapi: 3.0.2
info:
title: SafeDep OSS Insights API
contact:
name: SafeDep API
url: 'https://safedep.io'
description: |
The Insights API expose various metadata about OSS artifacts. Clients can
query this API to gather the data required for rich policy decision making
for various use-cases.
version: 1.0.0
servers:
- url: 'https://{apiHost}/{apiBase}'
variables:
apiHost:
default: api.safedep.io
apiBase:
default: insights/v1
tags:
- name: Package Meta Data
description: Package meta data related operations
- name: Infrastructure
description: Infrastructure support operations
paths:
/healthz:
get:
description: Get health check status
operationId: getHealthCheckStatus
tags:
- Infrastructure
security: []
responses:
'200':
description: Server is operational
'/{ecosystem}/packages/{name}/versions/{version}':
get:
description: Get metadata for a package version
operationId: getPackageVersionInsight
tags:
- Package Meta Data
security:
- api_key: []
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/PackageVersionInsight'
'404':
description: Requested resource was not found
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'429':
description: Rate limit block
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Failed due to internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ApiError'
parameters:
- name: ecosystem
in: path
required: true
schema:
type: string
description: Case insensitive ecosystem name
enum:
- Maven
- RubyGems
- Go
- npm
- PyPI
- Cargo
- NuGet
- Linux
- Debian
- Github Actions
- name: name
in: path
required: true
schema:
type: string
- name: version
in: path
required: true
schema:
type: string
components:
securitySchemes:
api_key:
type: apiKey
name: Authorization
in: header
schemas:
ApiError:
type: object
properties:
message:
type: string
description: A descriptive message about the error meant for developer consumption
type:
type: string
description: An optional service or domain specific error group
code:
type: string
description: An error code identifying the error
params:
type: object
description: Optional error specific attributes
additionalProperties:
type: object
properties:
key:
type: string
value:
type: string
PackageVersion:
type: object
required:
- ecosystem
- name
- version
properties:
ecosystem:
type: string
description: The ecosystem where this package belongs to
name:
type: string
description: The name of the package
version:
type: string
description: The version of the package
License:
type: string
description: License SPDX code
enum:
- 0BSD
- AAL
- Abstyles
- Adobe-2006
- Adobe-Glyph
- ADSL
- AFL-1.1
- AFL-1.2
- AFL-2.0
- AFL-2.1
- AFL-3.0
- Afmparse
- AGPL-1.0
- AGPL-1.0-only
- AGPL-1.0-or-later
- AGPL-3.0
- AGPL-3.0-only
- AGPL-3.0-or-later
- Aladdin
- AMDPLPA
- AML
- AMPAS
- ANTLR-PD
- ANTLR-PD-fallback
- Apache-1.0
- Apache-1.1
- Apache-2.0
- APAFML
- APL-1.0
- App-s2p
- APSL-1.0
- APSL-1.1
- APSL-1.2
- APSL-2.0
- Arphic-1999
- Artistic-1.0
- Artistic-1.0-cl8
- Artistic-1.0-Perl
- Artistic-2.0
- Baekmuk
- Bahyph
- Barr
- Beerware
- Bitstream-Vera
- BitTorrent-1.0
- BitTorrent-1.1
- blessing
- BlueOak-1.0.0
- Borceux
- BSD-1-Clause
- BSD-2-Clause
- BSD-2-Clause-FreeBSD
- BSD-2-Clause-NetBSD
- BSD-2-Clause-Patent
- BSD-2-Clause-Views
- BSD-3-Clause
- BSD-3-Clause-Attribution
- BSD-3-Clause-Clear
- BSD-3-Clause-LBNL
- BSD-3-Clause-Modification
- BSD-3-Clause-No-Military-License
- BSD-3-Clause-No-Nuclear-License
- BSD-3-Clause-No-Nuclear-License-2014
- BSD-3-Clause-No-Nuclear-Warranty
- BSD-3-Clause-Open-MPI
- BSD-4-Clause
- BSD-4-Clause-Shortened
- BSD-4-Clause-UC
- BSD-Protection
- BSD-Source-Code
- BSL-1.0
- BUSL-1.1
- bzip2-1.0.5
- bzip2-1.0.6
- C-UDA-1.0
- CAL-1.0
- CAL-1.0-Combined-Work-Exception
- Caldera
- CATOSL-1.1
- CC-BY-1.0
- CC-BY-2.0
- CC-BY-2.5
- CC-BY-2.5-AU
- CC-BY-3.0
- CC-BY-3.0-AT
- CC-BY-3.0-DE
- CC-BY-3.0-IGO
- CC-BY-3.0-NL
- CC-BY-3.0-US
- CC-BY-4.0
- CC-BY-NC-1.0
- CC-BY-NC-2.0
- CC-BY-NC-2.5
- CC-BY-NC-3.0
- CC-BY-NC-3.0-DE
- CC-BY-NC-4.0
- CC-BY-NC-ND-1.0
- CC-BY-NC-ND-2.0
- CC-BY-NC-ND-2.5
- CC-BY-NC-ND-3.0
- CC-BY-NC-ND-3.0-DE
- CC-BY-NC-ND-3.0-IGO
- CC-BY-NC-ND-4.0
- CC-BY-NC-SA-1.0
- CC-BY-NC-SA-2.0
- CC-BY-NC-SA-2.0-FR
- CC-BY-NC-SA-2.0-UK
- CC-BY-NC-SA-2.5
- CC-BY-NC-SA-3.0
- CC-BY-NC-SA-3.0-DE
- CC-BY-NC-SA-3.0-IGO
- CC-BY-NC-SA-4.0
- CC-BY-ND-1.0
- CC-BY-ND-2.0
- CC-BY-ND-2.5
- CC-BY-ND-3.0
- CC-BY-ND-3.0-DE
- CC-BY-ND-4.0
- CC-BY-SA-1.0
- CC-BY-SA-2.0
- CC-BY-SA-2.0-UK
- CC-BY-SA-2.1-JP
- CC-BY-SA-2.5
- CC-BY-SA-3.0
- CC-BY-SA-3.0-AT
- CC-BY-SA-3.0-DE
- CC-BY-SA-4.0
- CC-PDDC
- CC0-1.0
- CDDL-1.0
- CDDL-1.1
- CDL-1.0
- CDLA-Permissive-1.0
- CDLA-Permissive-2.0
- CDLA-Sharing-1.0
- CECILL-1.0
- CECILL-1.1
- CECILL-2.0
- CECILL-2.1
- CECILL-B
- CECILL-C
- CERN-OHL-1.1
- CERN-OHL-1.2
- CERN-OHL-P-2.0
- CERN-OHL-S-2.0
- CERN-OHL-W-2.0
- checkmk
- ClArtistic
- CNRI-Jython
- CNRI-Python
- CNRI-Python-GPL-Compatible
- COIL-1.0
- Community-Spec-1.0
- Condor-1.1
- copyleft-next-0.3.0
- copyleft-next-0.3.1
- CPAL-1.0
- CPL-1.0
- CPOL-1.02
- Crossword
- CrystalStacker
- CUA-OPL-1.0
- Cube
- curl
- D-FSL-1.0
- diffmark
- DL-DE-BY-2.0
- DOC
- Dotseqn
- DRL-1.0
- DSDP
- dvipdfm
- ECL-1.0
- ECL-2.0
- eCos-2.0
- EFL-1.0
- EFL-2.0
- eGenix
- Elastic-2.0
- Entessa
- EPICS
- EPL-1.0
- EPL-2.0
- ErlPL-1.1
- etalab-2.0
- EUDatagrid
- EUPL-1.0
- EUPL-1.1
- EUPL-1.2
- Eurosym
- Fair
- FDK-AAC
- Frameworx-1.0
- FreeBSD-DOC
- FreeImage
- FSFAP
- FSFUL
- FSFULLR
- FSFULLRWD
- FTL
- GD
- GFDL-1.1
- GFDL-1.1-invariants-only
- GFDL-1.1-invariants-or-later
- GFDL-1.1-no-invariants-only
- GFDL-1.1-no-invariants-or-later
- GFDL-1.1-only
- GFDL-1.1-or-later
- GFDL-1.2
- GFDL-1.2-invariants-only
- GFDL-1.2-invariants-or-later
- GFDL-1.2-no-invariants-only
- GFDL-1.2-no-invariants-or-later
- GFDL-1.2-only
- GFDL-1.2-or-later
- GFDL-1.3
- GFDL-1.3-invariants-only
- GFDL-1.3-invariants-or-later
- GFDL-1.3-no-invariants-only
- GFDL-1.3-no-invariants-or-later
- GFDL-1.3-only
- GFDL-1.3-or-later
- Giftware
- GL2PS
- Glide
- Glulxe
- GLWTPL
- gnuplot
- GPL-1.0
- GPL-1.0+
- GPL-1.0-only
- GPL-1.0-or-later
- GPL-2.0
- GPL-2.0+
- GPL-2.0-only
- GPL-2.0-or-later
- GPL-2.0-with-autoconf-exception
- GPL-2.0-with-bison-exception
- GPL-2.0-with-classpath-exception
- GPL-2.0-with-font-exception
- GPL-2.0-with-GCC-exception
- GPL-3.0
- GPL-3.0+
- GPL-3.0-only
- GPL-3.0-or-later
- GPL-3.0-with-autoconf-exception
- GPL-3.0-with-GCC-exception
- gSOAP-1.3b
- HaskellReport
- Hippocratic-2.1
- HPND
- HPND-sell-variant
- HTMLTIDY
- IBM-pibs
- ICU
- IJG
- ImageMagick
- iMatix
- Imlib2
- Info-ZIP
- Intel
- Intel-ACPI
- Interbase-1.0
- IPA
- IPL-1.0
- ISC
- Jam
- JasPer-2.0
- JPNIC
- JSON
- Knuth-CTAN
- LAL-1.2
- LAL-1.3
- Latex2e
- Leptonica
- LGPL-2.0
- LGPL-2.0+
- LGPL-2.0-only
- LGPL-2.0-or-later
- LGPL-2.1
- LGPL-2.1+
- LGPL-2.1-only
- LGPL-2.1-or-later
- LGPL-3.0
- LGPL-3.0+
- LGPL-3.0-only
- LGPL-3.0-or-later
- LGPLLR
- Libpng
- libpng-2.0
- libselinux-1.0
- libtiff
- libutil-David-Nugent
- LiLiQ-P-1.1
- LiLiQ-R-1.1
- LiLiQ-Rplus-1.1
- Linux-man-pages-copyleft
- Linux-OpenIB
- LOOP
- LPL-1.0
- LPL-1.02
- LPPL-1.0
- LPPL-1.1
- LPPL-1.2
- LPPL-1.3a
- LPPL-1.3c
- LZMA-SDK-9.11-to-9.20
- LZMA-SDK-9.22
- MakeIndex
- Minpack
- MirOS
- MIT
- MIT-0
- MIT-advertising
- MIT-CMU
- MIT-enna
- MIT-feh
- MIT-Modern-Variant
- MIT-open-group
- MITNFA
- Motosoto
- mpi-permissive
- mpich2
- MPL-1.0
- MPL-1.1
- MPL-2.0
- MPL-2.0-no-copyleft-exception
- mplus
- MS-LPL
- MS-PL
- MS-RL
- MTLL
- MulanPSL-1.0
- MulanPSL-2.0
- Multics
- Mup
- NAIST-2003
- NASA-1.3
- Naumen
- NBPL-1.0
- NCGL-UK-2.0
- NCSA
- Net-SNMP
- NetCDF
- Newsletr
- NGPL
- NICTA-1.0
- NIST-PD
- NIST-PD-fallback
- NLOD-1.0
- NLOD-2.0
- NLPL
- Nokia
- NOSL
- Noweb
- NPL-1.0
- NPL-1.1
- NPOSL-3.0
- NRL
- NTP
- NTP-0
- Nunit
- O-UDA-1.0
- OCCT-PL
- OCLC-2.0
- ODbL-1.0
- ODC-By-1.0
- OFL-1.0
- OFL-1.0-no-RFN
- OFL-1.0-RFN
- OFL-1.1
- OFL-1.1-no-RFN
- OFL-1.1-RFN
- OGC-1.0
- OGDL-Taiwan-1.0
- OGL-Canada-2.0
- OGL-UK-1.0
- OGL-UK-2.0
- OGL-UK-3.0
- OGTSL
- OLDAP-1.1
- OLDAP-1.2
- OLDAP-1.3
- OLDAP-1.4
- OLDAP-2.0
- OLDAP-2.0.1
- OLDAP-2.1
- OLDAP-2.2
- OLDAP-2.2.1
- OLDAP-2.2.2
- OLDAP-2.3
- OLDAP-2.4
- OLDAP-2.5
- OLDAP-2.6
- OLDAP-2.7
- OLDAP-2.8
- OML
- OpenSSL
- OPL-1.0
- OPUBL-1.0
- OSET-PL-2.1
- OSL-1.0
- OSL-1.1
- OSL-2.0
- OSL-2.1
- OSL-3.0
- Parity-6.0.0
- Parity-7.0.0
- PDDL-1.0
- PHP-3.0
- PHP-3.01
- Plexus
- PolyForm-Noncommercial-1.0.0
- PolyForm-Small-Business-1.0.0
- PostgreSQL
- PSF-2.0
- psfrag
- psutils
- Python-2.0
- Python-2.0.1
- Qhull
- QPL-1.0
- Rdisc
- RHeCos-1.1
- RPL-1.1
- RPL-1.5
- RPSL-1.0
- RSA-MD
- RSCPL
- Ruby
- SAX-PD
- Saxpath
- SCEA
- SchemeReport
- Sendmail
- Sendmail-8.23
- SGI-B-1.0
- SGI-B-1.1
- SGI-B-2.0
- SHL-0.5
- SHL-0.51
- SimPL-2.0
- SISSL
- SISSL-1.2
- Sleepycat
- SMLNJ
- SMPPL
- SNIA
- Spencer-86
- Spencer-94
- Spencer-99
- SPL-1.0
- SSH-OpenSSH
- SSH-short
- SSPL-1.0
- StandardML-NJ
- SugarCRM-1.1.3
- SWL
- Symlinks
- TAPR-OHL-1.0
- TCL
- TCP-wrappers
- TMate
- TORQUE-1.1
- TOSL
- TU-Berlin-1.0
- TU-Berlin-2.0
- UCL-1.0
- Unicode-DFS-2015
- Unicode-DFS-2016
- Unicode-TOU
- Unlicense
- UPL-1.0
- Vim
- VOSTROM
- VSL-1.0
- W3C
- W3C-19980720
- W3C-20150513
- Watcom-1.0
- Wsuipa
- WTFPL
- wxWindows
- X11
- X11-distribute-modifications-variant
- Xerox
- XFree86-1.1
- xinetd
- Xnet
- xpp
- XSkat
- YPL-1.0
- YPL-1.1
- Zed
- Zend-2.0
- Zimbra-1.3
- Zimbra-1.4
- Zlib
- zlib-acknowledgement
- ZPL-1.1
- ZPL-2.0
- ZPL-2.1
ScorecardContentV2Version:
type: object
properties:
version:
type: string
commit:
type: string
ScorecardContentV2Repository:
type: object
properties:
name:
type: string
commit:
type: string
description: Commit SHA where the scorecard checks where executed
ScorecardV2Check:
type: object
properties:
name:
type: string
enum:
- CII-Best-Practices
- Fuzzing
- Pinned-Dependencies
- CI-Tests
- Maintained
- Packaging
- SAST
- Dependency-Update-Tool
- Token-Permissions
- Security-Policy
- Signed-Releases
- Binary-Artifacts
- Branch-Protection
- Code-Review
- Contributors
- Vulnerabilities
- Dangerous-Workflow
- License
- Webhooks
score:
type: number
reason:
type: string
details:
type: array
items:
type: string
ScorecardContentV2:
type: object
properties:
date:
type: string
example: '2010-01-01'
format: date
repository:
$ref: '#/components/schemas/ScorecardContentV2Repository'
scorecard:
$ref: '#/components/schemas/ScorecardContentV2Version'
score:
type: number
checks:
type: array
items:
$ref: '#/components/schemas/ScorecardV2Check'
Scorecard:
type: object
properties:
version:
type: string
enum:
- V2
content:
$ref: '#/components/schemas/ScorecardContentV2'
PackageDependency:
type: object
properties:
package_version:
$ref: '#/components/schemas/PackageVersion'
description:
type: string
licenses:
type: array
items:
$ref: '#/components/schemas/License'
distance:
type: integer
PackageDependents:
type: object
properties:
total_dependents:
type: integer
direct_dependents:
type: integer
indirect_dependents:
type: integer
PackageProjectInfo:
type: object
properties:
type:
type: string
name:
type: string
display_name:
type: string
issues:
type: integer
forks:
type: integer
stars:
type: integer
link:
type: string
PackageVersionInsight:
type: object
properties:
package_version:
$ref: '#/components/schemas/PackageVersion'
projects:
type: array
items:
$ref: '#/components/schemas/PackageProjectInfo'
licenses:
type: array
items:
$ref: '#/components/schemas/License'
dependents:
$ref: '#/components/schemas/PackageDependents'
dependencies:
type: array
items:
$ref: '#/components/schemas/PackageDependency'
scorecard:
$ref: '#/components/schemas/Scorecard'

22
auth.go
View File

@ -3,8 +3,12 @@ package main
import (
"fmt"
"os"
"syscall"
"github.com/spf13/cobra"
"golang.org/x/term"
"github.com/safedep/vet/internal/auth"
)
var (
@ -13,7 +17,8 @@ var (
func newAuthCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "auth",
Use: "auth",
Short: "Configure and verify Insights API authentication",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Printf("You must choose an appropriate command: configure, verify\n")
os.Exit(1)
@ -31,7 +36,20 @@ func configureAuthCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "configure",
RunE: func(cmd *cobra.Command, args []string) error {
// Run auth.Configure()
fmt.Print("Enter API Key: ")
key, err := term.ReadPassword(syscall.Stdin)
if err != nil {
panic(err)
}
err = auth.Configure(auth.Config{
ApiUrl: authInsightApiBaseUrl,
ApiKey: string(key),
})
if err != nil {
panic(err)
}
os.Exit(1)
return nil
},

View File

@ -0,0 +1,372 @@
// Package insightapi provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen version v1.10.1 DO NOT EDIT.
package insightapi
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"github.com/deepmap/oapi-codegen/pkg/runtime"
)
// RequestEditorFn is the function signature for the RequestEditor callback function
type RequestEditorFn func(ctx context.Context, req *http.Request) error
// Doer performs HTTP requests.
//
// The standard http.Client implements this interface.
type HttpRequestDoer interface {
Do(req *http.Request) (*http.Response, error)
}
// Client which conforms to the OpenAPI3 specification for this service.
type Client struct {
// The endpoint of the server conforming to this interface, with scheme,
// https://api.deepmap.com for example. This can contain a path relative
// to the server, such as https://api.deepmap.com/dev-test, and all the
// paths in the swagger spec will be appended to the server.
Server string
// Doer for performing requests, typically a *http.Client with any
// customized settings, such as certificate chains.
Client HttpRequestDoer
// A list of callbacks for modifying requests which are generated before sending over
// the network.
RequestEditors []RequestEditorFn
}
// ClientOption allows setting custom parameters during construction
type ClientOption func(*Client) error
// Creates a new Client, with reasonable defaults
func NewClient(server string, opts ...ClientOption) (*Client, error) {
// create a client with sane default values
client := Client{
Server: server,
}
// mutate client and add all optional params
for _, o := range opts {
if err := o(&client); err != nil {
return nil, err
}
}
// ensure the server URL always has a trailing slash
if !strings.HasSuffix(client.Server, "/") {
client.Server += "/"
}
// create httpClient, if not already present
if client.Client == nil {
client.Client = &http.Client{}
}
return &client, nil
}
// WithHTTPClient allows overriding the default Doer, which is
// automatically created using http.Client. This is useful for tests.
func WithHTTPClient(doer HttpRequestDoer) ClientOption {
return func(c *Client) error {
c.Client = doer
return nil
}
}
// WithRequestEditorFn allows setting up a callback function, which will be
// called right before sending the request. This can be used to mutate the request.
func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
return func(c *Client) error {
c.RequestEditors = append(c.RequestEditors, fn)
return nil
}
}
// The interface specification for the client above.
type ClientInterface interface {
// GetHealthCheckStatus request
GetHealthCheckStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetPackageVersionInsight request
GetPackageVersionInsight(ctx context.Context, ecosystem string, name string, version string, reqEditors ...RequestEditorFn) (*http.Response, error)
}
func (c *Client) GetHealthCheckStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetHealthCheckStatusRequest(c.Server)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *Client) GetPackageVersionInsight(ctx context.Context, ecosystem string, name string, version string, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetPackageVersionInsightRequest(c.Server, ecosystem, name, version)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
// NewGetHealthCheckStatusRequest generates requests for GetHealthCheckStatus
func NewGetHealthCheckStatusRequest(server string) (*http.Request, error) {
var err error
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/healthz")
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
}
return req, nil
}
// NewGetPackageVersionInsightRequest generates requests for GetPackageVersionInsight
func NewGetPackageVersionInsightRequest(server string, ecosystem string, name string, version string) (*http.Request, error) {
var err error
var pathParam0 string
pathParam0, err = runtime.StyleParamWithLocation("simple", false, "ecosystem", runtime.ParamLocationPath, ecosystem)
if err != nil {
return nil, err
}
var pathParam1 string
pathParam1, err = runtime.StyleParamWithLocation("simple", false, "name", runtime.ParamLocationPath, name)
if err != nil {
return nil, err
}
var pathParam2 string
pathParam2, err = runtime.StyleParamWithLocation("simple", false, "version", runtime.ParamLocationPath, version)
if err != nil {
return nil, err
}
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/%s/packages/%s/versions/%s", pathParam0, pathParam1, pathParam2)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("GET", queryURL.String(), nil)
if err != nil {
return nil, err
}
return req, nil
}
func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
for _, r := range c.RequestEditors {
if err := r(ctx, req); err != nil {
return err
}
}
for _, r := range additionalEditors {
if err := r(ctx, req); err != nil {
return err
}
}
return nil
}
// ClientWithResponses builds on ClientInterface to offer response payloads
type ClientWithResponses struct {
ClientInterface
}
// NewClientWithResponses creates a new ClientWithResponses, which wraps
// Client with return type handling
func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
client, err := NewClient(server, opts...)
if err != nil {
return nil, err
}
return &ClientWithResponses{client}, nil
}
// WithBaseURL overrides the baseURL.
func WithBaseURL(baseURL string) ClientOption {
return func(c *Client) error {
newBaseURL, err := url.Parse(baseURL)
if err != nil {
return err
}
c.Server = newBaseURL.String()
return nil
}
}
// ClientWithResponsesInterface is the interface specification for the client with responses above.
type ClientWithResponsesInterface interface {
// GetHealthCheckStatus request
GetHealthCheckStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetHealthCheckStatusResponse, error)
// GetPackageVersionInsight request
GetPackageVersionInsightWithResponse(ctx context.Context, ecosystem string, name string, version string, reqEditors ...RequestEditorFn) (*GetPackageVersionInsightResponse, error)
}
type GetHealthCheckStatusResponse struct {
Body []byte
HTTPResponse *http.Response
}
// Status returns HTTPResponse.Status
func (r GetHealthCheckStatusResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r GetHealthCheckStatusResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type GetPackageVersionInsightResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *PackageVersionInsight
JSON404 *ApiError
JSON429 *ApiError
JSON500 *ApiError
}
// Status returns HTTPResponse.Status
func (r GetPackageVersionInsightResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r GetPackageVersionInsightResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
// GetHealthCheckStatusWithResponse request returning *GetHealthCheckStatusResponse
func (c *ClientWithResponses) GetHealthCheckStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetHealthCheckStatusResponse, error) {
rsp, err := c.GetHealthCheckStatus(ctx, reqEditors...)
if err != nil {
return nil, err
}
return ParseGetHealthCheckStatusResponse(rsp)
}
// GetPackageVersionInsightWithResponse request returning *GetPackageVersionInsightResponse
func (c *ClientWithResponses) GetPackageVersionInsightWithResponse(ctx context.Context, ecosystem string, name string, version string, reqEditors ...RequestEditorFn) (*GetPackageVersionInsightResponse, error) {
rsp, err := c.GetPackageVersionInsight(ctx, ecosystem, name, version, reqEditors...)
if err != nil {
return nil, err
}
return ParseGetPackageVersionInsightResponse(rsp)
}
// ParseGetHealthCheckStatusResponse parses an HTTP response from a GetHealthCheckStatusWithResponse call
func ParseGetHealthCheckStatusResponse(rsp *http.Response) (*GetHealthCheckStatusResponse, error) {
bodyBytes, err := ioutil.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &GetHealthCheckStatusResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
return response, nil
}
// ParseGetPackageVersionInsightResponse parses an HTTP response from a GetPackageVersionInsightWithResponse call
func ParseGetPackageVersionInsightResponse(rsp *http.Response) (*GetPackageVersionInsightResponse, error) {
bodyBytes, err := ioutil.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &GetPackageVersionInsightResponse{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
var dest PackageVersionInsight
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON200 = &dest
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
var dest ApiError
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON404 = &dest
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 429:
var dest ApiError
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON429 = &dest
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500:
var dest ApiError
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON500 = &dest
}
return response, nil
}

File diff suppressed because it is too large Load Diff

20
go.mod
View File

@ -3,12 +3,30 @@ module github.com/safedep/vet
go 1.18
require (
github.com/deepmap/oapi-codegen v1.12.4
github.com/google/cel-go v0.13.0
github.com/google/osv-scanner v1.0.2
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
golang.org/x/term v0.3.0
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
golang.org/x/mod v0.7.0 // indirect
golang.org/x/sys v0.3.0 // indirect
golang.org/x/text v0.5.0 // indirect
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

51
go.sum
View File

@ -1,9 +1,29 @@
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deepmap/oapi-codegen v1.12.4 h1:pPmn6qI9MuOtCz82WY2Xaw46EQjgvxednXXrP7g5Q2s=
github.com/deepmap/oapi-codegen v1.12.4/go.mod h1:3lgHGMu6myQ2vqbbTXH2H1o4eXFTGnFiDaOaKKl5yas=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/cel-go v0.13.0 h1:z+8OBOcmh7IeKyqwT/6IlnMvy621fYUqnTVPEdegGlU=
github.com/google/cel-go v0.13.0/go.mod h1:K2hpQgEjDp18J76a2DKFRlPBPpgRZgi6EbnpDgIhJ8s=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/osv-scanner v1.0.2 h1:EiDbP8XQhEvo9I7WZMvA7OkJinyOULhNTD7SITS2tBY=
github.com/google/osv-scanner v1.0.2/go.mod h1:KTYFW64rATMvw7MtWAVXxIkG7u0R86n6VUKM8pzOzF0=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@ -13,12 +33,39 @@ github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo=
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

97
internal/auth/auth.go Normal file
View File

@ -0,0 +1,97 @@
package auth
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"gopkg.in/yaml.v2"
)
const (
apiUrlEnvKey = "VET_INSIGHTS_API_URL"
apiKeyEnvKey = "VET_INSIGHTS_API_KEY"
defaultApiUrl = "https://api.safedep.io/insights/v1"
homeRelativeConfigPath = ".safedep/vet-auth.yml"
)
type Config struct {
ApiUrl string `yaml:"api_url"`
ApiKey string `yaml:"api_key"`
}
// Global config to be used during runtime
var globalConfig *Config
func init() {
loadConfiguration()
}
func Configure(m Config) error {
globalConfig = &m
return persistConfiguration()
}
func Verify() error {
// TODO: Verify by actually calling insight API
return nil
}
func ApiUrl() string {
if url, ok := os.LookupEnv(apiUrlEnvKey); ok {
return url
}
if globalConfig != nil {
return globalConfig.ApiUrl
}
return defaultApiUrl
}
func ApiKey() string {
if key, ok := os.LookupEnv(apiKeyEnvKey); ok {
return key
}
if globalConfig != nil {
return globalConfig.ApiKey
}
return ""
}
func loadConfiguration() error {
path, err := os.UserHomeDir()
path = filepath.Join(path, homeRelativeConfigPath)
data, err := ioutil.ReadFile(path)
if err != nil {
return err
}
var config Config
err = yaml.Unmarshal(data, &config)
if err != nil {
return fmt.Errorf("config deserialization failed: %w", err)
}
globalConfig = &config
return nil
}
func persistConfiguration() error {
data, err := yaml.Marshal(globalConfig)
if err != nil {
return fmt.Errorf("config serialization failed: %w", err)
}
path, err := os.UserHomeDir()
path = filepath.Join(path, homeRelativeConfigPath)
os.MkdirAll(filepath.Dir(path), os.ModePerm)
return ioutil.WriteFile(path, data, 0600)
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"github.com/safedep/vet/pkg/common/logger"
"github.com/spf13/cobra"
)
@ -33,6 +34,10 @@ func main() {
cmd.AddCommand(newScanCommand())
cmd.AddCommand(newVersionCommand())
cobra.OnInitialize(func() {
logger.SetLogLevel(verbose, debug)
})
if err := cmd.Execute(); err != nil {
os.Exit(1)
}

32
pkg/analyzer/analyzer.go Normal file
View File

@ -0,0 +1,32 @@
package analyzer
import "github.com/safedep/vet/pkg/models"
type AnalyzerEventType string
const (
ET_FilterExpressionMatched = AnalyzerEventType("ev_pkg_filter_match")
)
type AnalyzerEvent struct {
// Analyzer generating this event
Source string
// Type of the event
Type AnalyzerEventType
// Entities on which event was generated
Manifest *models.PackageManifest
Package *models.Package
}
// Callback to receive events from analyzer
type AnalyzerEventHandler func(event *AnalyzerEvent) error
// Contract for an analyzer
type Analyzer interface {
Name() string
Analyze(manifest *models.PackageManifest,
handler AnalyzerEventHandler) error
}

View File

@ -0,0 +1,95 @@
package analyzer
import (
"encoding/json"
"fmt"
"reflect"
"github.com/google/cel-go/cel"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/models"
)
type celFilterAnalyzer struct {
program cel.Program
}
func NewCelFilterAnalyzer(filter string) (Analyzer, error) {
env, err := cel.NewEnv(
cel.Variable("pkg", cel.DynType),
cel.Variable("manifest", cel.DynType),
)
if err != nil {
return nil, err
}
ast, issues := env.Compile(filter)
if issues != nil && issues.Err() != nil {
return nil, issues.Err()
}
prog, err := env.Program(ast)
if err != nil {
return nil, err
}
return &celFilterAnalyzer{program: prog}, nil
}
func (f *celFilterAnalyzer) Name() string {
return "CEL Filter Analyzer"
}
func (f *celFilterAnalyzer) Analyze(manifest *models.PackageManifest,
handler AnalyzerEventHandler) error {
pkgManifestVal, err := f.valType(manifest)
if err != nil {
logger.Errorf("Failed to convert manifest to val: %v", err)
}
logger.Infof("CEL filtering manifest: %s", manifest.Path)
for _, pkg := range manifest.Packages {
pkgVal, err := f.valType(pkg)
if err != nil {
logger.Errorf("Failed to convert package to val: %v", err)
continue
}
out, _, err := f.program.Eval(map[string]interface{}{
"pkg": pkgVal,
"manifest": pkgManifestVal,
})
if err != nil {
logger.Errorf("Failed to evaluate CEL for %s:%v : %v",
pkg.PackageDetails.Name,
pkg.PackageDetails.Version, err)
continue
}
if (reflect.TypeOf(out).Kind() == reflect.Bool) &&
(reflect.ValueOf(out).Bool()) {
fmt.Printf("[%s] %s %v\n", pkg.PackageDetails.Ecosystem,
pkg.PackageDetails.Name, pkg.PackageDetails.Version)
}
}
return nil
}
func (f *celFilterAnalyzer) valType(i any) (any, error) {
data, err := json.Marshal(i)
if err != nil {
return nil, err
}
ret := make(map[string]interface{})
err = json.Unmarshal(data, &ret)
if err != nil {
return nil, err
}
return ret, nil
}

60
pkg/analyzer/json_dump.go Normal file
View File

@ -0,0 +1,60 @@
package analyzer
import (
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"os"
"path/filepath"
"time"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/models"
)
type jsonDumperAnalyzer struct {
dir string
}
func NewJsonDumperAnalyzer(dir string) (Analyzer, error) {
fi, err := os.Stat(dir)
if err != nil {
if os.IsNotExist(err) {
err = os.MkdirAll(dir, os.ModePerm)
if err != nil {
return nil, fmt.Errorf("cannot create dir: %w", err)
}
}
return nil, fmt.Errorf("cannot stat dir: %w", err)
}
if !fi.IsDir() {
return nil, fmt.Errorf("%s is not a dir", dir)
}
return &jsonDumperAnalyzer{dir: dir}, nil
}
func (j *jsonDumperAnalyzer) Name() string {
return "JSON Dump Generator"
}
func (j *jsonDumperAnalyzer) Analyze(manifest *models.PackageManifest,
handler AnalyzerEventHandler) error {
logger.Infof("Running analyzer: %s", j.Name())
data, err := json.MarshalIndent(manifest, "", " ")
if err != nil {
return fmt.Errorf("Failed to JSON serialize manifest: %w", err)
}
rand.Seed(time.Now().UnixNano())
path := filepath.Join(j.dir, fmt.Sprintf("%s-%s--%d-dump.json",
manifest.Ecosystem,
filepath.Base(manifest.Path),
rand.Intn(2<<15)))
return ioutil.WriteFile(path, data, 0600)
}

View File

@ -8,7 +8,7 @@ import (
func init() {
logrus.SetOutput(os.Stdout)
logrus.SetLevel(logrus.InfoLevel)
logrus.SetLevel(logrus.WarnLevel)
}
func SetLogLevel(verbose, debug bool) {
@ -18,7 +18,6 @@ func SetLogLevel(verbose, debug bool) {
if debug {
logrus.SetLevel(logrus.DebugLevel)
logrus.SetReportCaller(true)
}
}

73
pkg/common/utils/workq.go Normal file
View File

@ -0,0 +1,73 @@
package utils
import (
"sync"
"github.com/safedep/vet/pkg/common/logger"
)
type WorkQueueItem interface {
Id() string
}
type WorkQueueFn[T WorkQueueItem] func(q *WorkQueue[T], item T) error
type WorkQueue[T WorkQueueItem] struct {
done chan bool
m sync.Mutex
concurrency int
wg sync.WaitGroup
handler WorkQueueFn[T]
status sync.Map
items chan T
}
func NewWorkQueue[T WorkQueueItem](bufferSize int, concurrency int,
handler WorkQueueFn[T]) *WorkQueue[T] {
return &WorkQueue[T]{
handler: handler,
concurrency: concurrency,
items: make(chan T, bufferSize),
done: make(chan bool),
}
}
func (q *WorkQueue[T]) Start() {
for i := 0; i < q.concurrency; i++ {
go func() {
for {
select {
case <-q.done:
return
case item := <-q.items:
err := q.handler(q, item)
if err != nil {
logger.Errorf("Handler fn failed with %v", err)
}
q.wg.Done()
}
}
}()
}
}
func (q *WorkQueue[T]) Wait() {
q.wg.Wait()
}
func (q *WorkQueue[T]) Stop() {
close(q.done)
}
func (q *WorkQueue[T]) Add(item T) bool {
if _, ok := q.status.Load(item.Id()); ok {
return false
}
q.status.Store(item.Id(), true)
q.wg.Add(1)
q.items <- item
return true
}

85
pkg/models/models.go Normal file
View File

@ -0,0 +1,85 @@
package models
import (
"fmt"
"hash/fnv"
"strconv"
"strings"
"sync"
"github.com/google/osv-scanner/pkg/lockfile"
"github.com/safedep/vet/gen/insightapi"
)
const (
EcosystemMaven = "Maven"
EcosystemRubyGems = "RubyGems"
EcosystemGo = "Go"
EcosystemNpm = "npm"
EcosystemPyPI = "PyPI"
EcosystemCargo = "Cargo"
EcosystemNuGet = "NuGet"
EcosystemPackagist = "Packagist"
EcosystemHex = "Hex"
EcosystemPub = "Pub"
)
// Represents a package manifest that contains a list
// of packages. Example: pom.xml, requirements.txt
type PackageManifest struct {
// Filesystem path of this manifest
Path string `json:"path"`
// Ecosystem to interpret this manifest
Ecosystem string `json:"ecosystem"`
// List of packages obtained by parsing the manifest
Packages []*Package `json:"packages"`
// Lock to serialize updating packages
m sync.Mutex
}
func (pm *PackageManifest) AddPackage(pkg *Package) {
pm.m.Lock()
defer pm.m.Unlock()
pm.Packages = append(pm.Packages, pkg)
}
// Represents a package such as a version of a library defined as a dependency
// in Gemfile.lock, pom.xml etc.
type Package struct {
lockfile.PackageDetails `json:"package_detail"`
// Insights obtained for this package
Insights *insightapi.PackageVersionInsight `json:"insights"`
// This package is a transitive dependency of parent package
Parent *Package `json:"-"`
// Depth of this package in dependency tree
Depth int `json:"depth"`
// Manifest from where this package was found directly or indirectly
Manifest *PackageManifest `json:"-"`
}
func (p *Package) Id() string {
h := fnv.New64a()
h.Write([]byte(fmt.Sprintf("%s/%s/%s",
strings.ToLower(p.Manifest.Ecosystem),
strings.ToLower(p.PackageDetails.Name),
strings.ToLower(p.PackageDetails.Version))))
return strconv.FormatUint(h.Sum64(), 16)
}
func NewPackageDetail(e, n, v string) lockfile.PackageDetails {
return lockfile.PackageDetails{
Ecosystem: lockfile.Ecosystem(e),
CompareAs: lockfile.Ecosystem(e),
Name: n,
Version: v,
}
}

89
pkg/parser/parser.go Normal file
View File

@ -0,0 +1,89 @@
package parser
import (
"fmt"
"github.com/google/osv-scanner/pkg/lockfile"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/models"
)
type Parser interface {
Ecosystem() string
Parse(lockfilePath string) (models.PackageManifest, error)
}
type parserWrapper struct {
parser lockfile.PackageDetailsParser
parseAs string
}
func List() []string {
return lockfile.ListParsers()
}
func FindParser(lockfilePath, lockfileAs string) (Parser, error) {
p, pa := lockfile.FindParser(lockfilePath, lockfileAs)
if p != nil {
return &parserWrapper{parser: p, parseAs: pa}, nil
}
return nil, fmt.Errorf("no parser found with: %s for: %s", lockfileAs,
lockfilePath)
}
func (pw *parserWrapper) Ecosystem() string {
switch pw.parseAs {
case "Cargo.lock":
return models.EcosystemCargo
case "composer.lock":
return models.EcosystemPackagist
case "Gemfile.lock":
return models.EcosystemRubyGems
case "go.mod":
return models.EcosystemGo
case "mix.lock":
return models.EcosystemHex
case "package-lock.json":
return models.EcosystemNpm
case "pnpm-lock.yaml":
return models.EcosystemNpm
case "poetry.lock":
return models.EcosystemPyPI
case "pom.xml":
return models.EcosystemMaven
case "pubspec.lock":
return models.EcosystemPub
case "requirements.txt":
return models.EcosystemPyPI
case "yarn.lock":
return models.EcosystemNpm
case "gradle.lockfile":
return models.EcosystemMaven
case "buildscript-gradle.lockfile":
return models.EcosystemMaven
default:
return ""
}
}
func (pw *parserWrapper) Parse(lockfilePath string) (models.PackageManifest, error) {
pm := models.PackageManifest{Path: lockfilePath,
Ecosystem: pw.Ecosystem()}
logger.Infof("[%s] Parsing %s", pw.parseAs, lockfilePath)
packages, err := pw.parser(lockfilePath)
if err != nil {
return pm, err
}
for _, pkg := range packages {
pm.AddPackage(&models.Package{
PackageDetails: pkg,
Manifest: &pm,
})
}
return pm, nil
}

26
pkg/parser/parser_test.go Normal file
View File

@ -0,0 +1,26 @@
package parser
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestListParser(t *testing.T) {
parsers := List()
assert.Equal(t, 14, len(parsers))
}
func TestInvalidEcosystemMapping(t *testing.T) {
pw := &parserWrapper{parseAs: "nothing"}
assert.Empty(t, pw.Ecosystem())
}
func TestEcosystemMapping(t *testing.T) {
for _, lf := range List() {
t.Run(lf, func(t *testing.T) {
pw := &parserWrapper{parseAs: lf}
assert.NotEmpty(t, pw.Ecosystem())
})
}
}

94
pkg/scanner/enrich.go Normal file
View File

@ -0,0 +1,94 @@
package scanner
import (
"context"
"fmt"
"net/http"
"strings"
"github.com/safedep/vet/gen/insightapi"
"github.com/safedep/vet/internal/auth"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/models"
)
// Callback to receive a discovery package dependency
type PackageDependencyCallbackFn func(pkg *models.Package) error
// Enrich meta information associated with
// the package
type PackageMetaEnricher interface {
Name() string
Enrich(pkg *models.Package, cb PackageDependencyCallbackFn) error
}
type insightsBasedPackageEnricher struct {
client *insightapi.ClientWithResponses
}
func NewInsightBasedPackageEnricher() PackageMetaEnricher {
apiKeyApplier := func(ctx context.Context, req *http.Request) error {
req.Header.Set("Authorization", auth.ApiKey())
return nil
}
client, err := insightapi.NewClientWithResponses(auth.ApiUrl(),
insightapi.WithRequestEditorFn(apiKeyApplier))
if err != nil {
// TODO: Handle
panic(err)
}
return &insightsBasedPackageEnricher{
client: client,
}
}
func (e *insightsBasedPackageEnricher) Name() string {
return "Insights API"
}
func (e *insightsBasedPackageEnricher) Enrich(pkg *models.Package,
cb PackageDependencyCallbackFn) error {
logger.Infof("[%s] Enriching %s/%s", pkg.Manifest.Ecosystem,
pkg.PackageDetails.Name, pkg.PackageDetails.Version)
res, err := e.client.GetPackageVersionInsightWithResponse(context.Background(),
pkg.Manifest.Ecosystem, pkg.Name, pkg.Version)
if err != nil {
logger.Errorf("Failed to enrich package: %v", err)
return err
}
if res.HTTPResponse.StatusCode != 200 {
return fmt.Errorf("bad response: %d: %s", res.HTTPResponse.StatusCode,
res.HTTPResponse.Status)
}
if (res.JSON200 == nil) || (res.JSON200.Dependencies == nil) {
return fmt.Errorf("unexpected nil response from Insight API")
}
for _, dep := range *res.JSON200.Dependencies {
if strings.EqualFold(dep.PackageVersion.Name, pkg.PackageDetails.Name) {
// Skip self references in dependency
continue
}
err := cb(&models.Package{
Manifest: pkg.Manifest,
Parent: pkg,
Depth: pkg.Depth + 1,
PackageDetails: models.NewPackageDetail(dep.PackageVersion.Ecosystem,
dep.PackageVersion.Name, dep.PackageVersion.Version),
})
if err != nil {
logger.Errorf("Failed to invoke package dependency callback: %v", err)
}
}
pkg.Insights = res.JSON200
return nil
}

150
pkg/scanner/scanner.go Normal file
View File

@ -0,0 +1,150 @@
package scanner
import (
"github.com/safedep/vet/pkg/analyzer"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/common/utils"
"github.com/safedep/vet/pkg/models"
)
type Config struct {
ConcurrentAnalyzer int
TransitiveAnalysis bool
TransitiveDepth int
}
type packageManifestScanner struct {
config Config
enrichers []PackageMetaEnricher
analyzers []analyzer.Analyzer
}
func NewPackageManifestScanner(config Config,
enrichers []PackageMetaEnricher,
analyzers []analyzer.Analyzer) *packageManifestScanner {
return &packageManifestScanner{
config: config,
enrichers: enrichers,
analyzers: analyzers,
}
}
// Autodiscover lockfiles
func (s *packageManifestScanner) ScanDirectory(dir string) error {
logger.Infof("Starting package manifest scanner on dir: %s", dir)
manifests, err := scanDirectoryForManifests(dir)
if err != nil {
logger.Errorf("Failed to scan directory: %v", err)
return err
}
logger.Infof("Discovered %d manifest(s)", len(manifests))
return s.analyzeManifests(manifests)
}
// Scan specific lockfiles, optionally interpreted as instead of
// automatic parser selection
func (s *packageManifestScanner) ScanLockfiles(lockfiles []string,
lockfileAs string) error {
logger.Infof("Scannding %d lockfiles as %s", len(lockfiles), lockfileAs)
manifests, err := scanLockfilesForManifests(lockfiles, lockfileAs)
if err != nil {
logger.Errorf("Failed to scan lockfiles: %v", err)
return err
}
logger.Infof("Discovered %d manifest(s)", len(manifests))
return s.analyzeManifests(manifests)
}
func (s *packageManifestScanner) analyzeManifests(manifests []*models.PackageManifest) error {
for _, manifest := range manifests {
logger.Infof("Analysing %s as %s ecosystem with %d packages", manifest.Path,
manifest.Ecosystem, len(manifest.Packages))
err := s.enrichManifest(manifest)
if err != nil {
logger.Errorf("Failed to enrich %s manifest %s : %v",
manifest.Ecosystem, manifest.Path, err)
}
err = s.analyzeManifest(manifest)
if err != nil {
logger.Errorf("Failed to analyze %s manifest %v : %v",
manifest.Ecosystem, manifest.Path, err)
}
}
return nil
}
func (s *packageManifestScanner) analyzeManifest(manifest *models.PackageManifest) error {
for _, task := range s.analyzers {
err := task.Analyze(manifest, func(event *analyzer.AnalyzerEvent) error {
// Handle analyzer event
return nil
})
if err != nil {
logger.Errorf("Analyzer %s failed: %v", task.Name(), err)
}
}
return nil
}
func (s *packageManifestScanner) enrichManifest(manifest *models.PackageManifest) error {
// FIXME: Potential deadlock situation in case of channel buffer is full
// because the goroutines perform both read and write to channel. Write occurs
// when goroutine invokes the work queue handler and the handler pushes back
// the dependencies
q := utils.NewWorkQueue[*models.Package](100000,
s.config.ConcurrentAnalyzer,
s.packageEnrichWorkQueueHandler(manifest))
q.Start()
for _, pkg := range manifest.Packages {
q.Add(pkg)
}
q.Wait()
q.Stop()
return nil
}
func (s *packageManifestScanner) packageEnrichWorkQueueHandler(pm *models.PackageManifest) utils.WorkQueueFn[*models.Package] {
return func(q *utils.WorkQueue[*models.Package], item *models.Package) error {
for _, enricher := range s.enrichers {
err := enricher.Enrich(item, s.packageDependencyHandler(pm, q))
if err != nil {
logger.Errorf("Enricher %s failed with %v", enricher.Name(), err)
}
}
return nil
}
}
func (s *packageManifestScanner) packageDependencyHandler(pm *models.PackageManifest,
q *utils.WorkQueue[*models.Package]) PackageDependencyCallbackFn {
return func(pkg *models.Package) error {
if !s.config.TransitiveAnalysis {
return nil
}
if pkg.Depth >= s.config.TransitiveDepth {
return nil
}
logger.Debugf("Adding transitive dependency %s/%v to work queue",
pkg.PackageDetails.Name, pkg.PackageDetails.Version)
if q.Add(pkg) {
pm.AddPackage(pkg)
}
return nil
}
}

64
pkg/scanner/utils.go Normal file
View File

@ -0,0 +1,64 @@
package scanner
import (
"os"
"path/filepath"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/models"
"github.com/safedep/vet/pkg/parser"
)
func scanDirectoryForManifests(dir string) ([]*models.PackageManifest, error) {
var manifests []*models.PackageManifest
err := filepath.WalkDir(dir, func(path string, info os.DirEntry, err error) error {
if err != nil {
return err
}
if info.IsDir() && info.Name() == ".git" {
return filepath.SkipDir
}
path, err = filepath.Abs(path)
if err != nil {
return err
}
p, err := parser.FindParser(path, "")
if err == nil {
// We have a parseable file
manifest, err := p.Parse(path)
if err != nil {
logger.Warnf("Failed to parse: %s due to %v", path, err)
} else {
manifests = append(manifests, &manifest)
}
}
return nil
})
return manifests, err
}
func scanLockfilesForManifests(lockfiles []string, lockfileAs string) ([]*models.PackageManifest, error) {
var manifests []*models.PackageManifest
for _, lf := range lockfiles {
p, err := parser.FindParser(lf, lockfileAs)
if err != nil {
logger.Warnf("Failed to parse %s as %s", lf, lockfileAs)
continue
}
manifest, err := p.Parse(lf)
if err != nil {
logger.Warnf("Failed to parse: %s due to %v", lf, err)
continue
}
manifests = append(manifests, &manifest)
}
return manifests, nil
}

101
scan.go
View File

@ -1,21 +1,32 @@
package main
import (
"fmt"
"os"
"github.com/safedep/vet/pkg/analyzer"
"github.com/safedep/vet/pkg/common/logger"
"github.com/safedep/vet/pkg/parser"
"github.com/safedep/vet/pkg/scanner"
"github.com/spf13/cobra"
)
var (
lockfiles []string
lockfileAs string
baseDirectory string
lockfiles []string
lockfileAs string
baseDirectory string
transitiveAnalysis bool
transitiveDepth int
concurrency int
dumpJsonManifest bool
dumpJsonManifestDir string
celFilterExpression string
)
func newScanCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "scan",
Use: "scan",
Short: "Scan and analyse package manifests",
RunE: func(cmd *cobra.Command, args []string) error {
startScan()
return nil
@ -31,13 +42,85 @@ func newScanCommand() *cobra.Command {
"The directory to scan for lockfiles")
cmd.Flags().StringArrayVarP(&lockfiles, "lockfiles", "L", []string{},
"List of lockfiles to scan")
cmd.Flags().StringVarP(&baseDirectory, "lockfile-as", "", "",
"Ecosystem to interpret the lockfile as")
cmd.Flags().StringVarP(&lockfileAs, "lockfile-as", "", "",
"Parser to use for the lockfile (vet scan parsers to list)")
cmd.Flags().BoolVarP(&transitiveAnalysis, "transitive", "", true,
"Analyze transitive dependencies")
cmd.Flags().IntVarP(&transitiveDepth, "transitive-depth", "", 2,
"Analyze transitive dependencies till depth")
cmd.Flags().IntVarP(&concurrency, "concurrency", "C", 10,
"Number of goroutines to use for analysis")
cmd.Flags().BoolVarP(&dumpJsonManifest, "json-dump", "", false,
"Dump enriched manifests as JSON docs")
cmd.Flags().StringVarP(&dumpJsonManifestDir, "json-dump-dir", "", "",
"Dump dir for enriched JSON docs")
cmd.Flags().StringVarP(&celFilterExpression, "filter-cel", "", "",
"Filter and print packages using CEL")
cmd.AddCommand(listParsersCommand())
return cmd
}
func startScan() {
logger.SetLogLevel(verbose, debug)
logger.Infof("Starting vet scanner")
func listParsersCommand() *cobra.Command {
return &cobra.Command{
Use: "parsers",
Short: "List available lockfile parsers",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Printf("Available Lockfile Parsers\n")
fmt.Printf("==========================\n\n")
for idx, p := range parser.List() {
fmt.Printf("[%d] %s\n", idx, p)
}
return nil
},
}
}
func startScan() {
err := internalStartScan()
if err != nil {
logger.Errorf("Scan completed with error: %v", err)
}
}
func internalStartScan() error {
analyzers := []analyzer.Analyzer{}
if dumpJsonManifest {
task, err := analyzer.NewJsonDumperAnalyzer(dumpJsonManifestDir)
if err != nil {
return err
}
analyzers = append(analyzers, task)
}
if len(celFilterExpression) > 0 {
task, err := analyzer.NewCelFilterAnalyzer(celFilterExpression)
if err != nil {
return err
}
analyzers = append(analyzers, task)
}
enrichers := []scanner.PackageMetaEnricher{
scanner.NewInsightBasedPackageEnricher(),
}
pmScanner := scanner.NewPackageManifestScanner(scanner.Config{
TransitiveAnalysis: transitiveAnalysis,
TransitiveDepth: transitiveDepth,
ConcurrentAnalyzer: concurrency,
}, enrichers, analyzers)
var err error
if len(lockfiles) > 0 {
err = pmScanner.ScanLockfiles(lockfiles, lockfileAs)
} else {
err = pmScanner.ScanDirectory(baseDirectory)
}
return err
}

View File

@ -7,15 +7,16 @@ import (
"github.com/spf13/cobra"
)
var GITCOMMIT string
var VERSION string
var version string
var commit string
func newVersionCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "version",
Use: "version",
Short: "Show version and build information",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Fprintf(os.Stdout, "Version: %s\n", VERSION)
fmt.Fprintf(os.Stdout, "CommitSHA: %s\n", GITCOMMIT)
fmt.Fprintf(os.Stdout, "Version: %s\n", version)
fmt.Fprintf(os.Stdout, "CommitSHA: %s\n", commit)
os.Exit(1)
return nil