mirror of
https://github.com/safedep/vet.git
synced 2025-12-10 00:22:08 -06:00
Sync Develop to Main (#4)
* Update Insight service API and client * Add cli banner * Show API errors from insight API * Use standard error model * Add reporting interface * Update markdown template * Add trials registration client * Add trials registration support * Add supported ecosystem filter to parsers * Update OSV scanner * Use table renderer for CEL filter output * Rename filter opt to filter * Add an opinionated console summary reporter * Update README * Update README * Update README * Add filter spec * Update spec driven CEL filtering * Add query workflow with docs * Add secrets scan workflow
This commit is contained in:
parent
bde7df3507
commit
a18c204b5d
20
.github/workflows/secret_scan.yml
vendored
Normal file
20
.github/workflows/secret_scan.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: Secrets Scan
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
trufflehog:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Source
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
- name: TruffleHog OSS
|
||||
uses: trufflesecurity/trufflehog@main
|
||||
with:
|
||||
path: ./
|
||||
base: main
|
||||
head: HEAD
|
||||
|
||||
15
Makefile
15
Makefile
@ -7,17 +7,28 @@ all: clean setup vet
|
||||
oapi-codegen-install:
|
||||
go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@v1.10.1
|
||||
|
||||
protoc-install:
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
|
||||
|
||||
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
|
||||
oapi-codegen -package controlplane -generate types ./api/cp-v1-trials.yml > ./gen/controlplane/trials.types.go
|
||||
oapi-codegen -package controlplane -generate client ./api/cp-v1-trials.yml > ./gen/controlplane/trials.client.go
|
||||
|
||||
protoc-codegen:
|
||||
protoc -I ./api \
|
||||
--go_out=./gen/filterinput \
|
||||
--go_opt=paths=source_relative \
|
||||
./api/filter_input_spec.proto
|
||||
|
||||
setup:
|
||||
mkdir -p out gen/insightapi
|
||||
mkdir -p out gen/insightapi gen/controlplane gen/filterinput
|
||||
|
||||
GO_CFLAGS=-X main.commit=$(GITCOMMIT) -X main.version=$(VERSION)
|
||||
GO_LDFLAGS=-ldflags "-w $(GO_CFLAGS)"
|
||||
|
||||
vet: oapi-codegen
|
||||
vet: oapi-codegen protoc-codegen
|
||||
go build ${GO_LDFLAGS}
|
||||
|
||||
.PHONY: test
|
||||
|
||||
98
README.md
98
README.md
@ -1,42 +1,104 @@
|
||||
# vet : The dependency vetting tool
|
||||
Tool for identifying software supply chain risks
|
||||
# vet
|
||||
|
||||
`vet` is a tool for identifying risks in open source software supply chain. It
|
||||
helps engineering and security teams to identify potential issues in their open
|
||||
source dependencies and evaluate them against organizational policies.
|
||||
|
||||
## TL;DR
|
||||
|
||||
Build this repository
|
||||
|
||||
> Ensure `$(go env GOPATH)/bin` is in your `$PATH`
|
||||
|
||||
```bash
|
||||
make oapi-codegen-install && make
|
||||
```
|
||||
|
||||
Alternatively install using
|
||||
Install using `go get`
|
||||
|
||||
```bash
|
||||
go install github.com/safedep/vet@latest
|
||||
```
|
||||
|
||||
Configure `vet` to use API Key to access [Insights API](#)
|
||||
Alternatively, look at [Releases](https://github.com/safedep/vet/releases) for
|
||||
a pre-built binary for your platform. [SLSA Provenance](https://slsa.dev/provenance/v0.1) is published
|
||||
along with each binary release.
|
||||
|
||||
Get a trial API key for [Insights API](https://safedep.io/docs/concepts/raya-data-platform-overview) access
|
||||
|
||||
```bash
|
||||
vet auth trial --email john.doe@example.com
|
||||
```
|
||||
|
||||
> A time limited trial API key will be sent over email.
|
||||
|
||||
Configure `vet` to use API Key to access [Insights API](https://safedep.io/docs/concepts/raya-data-platform-overview)
|
||||
|
||||
```bash
|
||||
vet auth configure
|
||||
```
|
||||
|
||||
> Alternatively pass the API key as environment to skip configuration
|
||||
> Insights API is used to enrich OSS packages with meta-data for rich query and policy
|
||||
> decisions
|
||||
|
||||
Run `vet` to identify risks
|
||||
|
||||
```bash
|
||||
vet scan
|
||||
vet scan -D /path/to/repository
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Configuration
|
||||
|
||||
Insights API Key can be passed at runtime using environment variable
|
||||
or scan a specific (supported) package manifest
|
||||
|
||||
```bash
|
||||
VET_INSIGHTS_API_KEY=... vet scan
|
||||
vet scan --lockfiles /path/to/pom.xml
|
||||
vet scan --lockfiles /path/to/requirements.txt
|
||||
vet scan --lockfiles /path/to/package-lock.json
|
||||
```
|
||||
|
||||
> Use `vet scan parsers` to list supported package manifest parsers
|
||||
|
||||
The default scan uses an opinionated [Console Reporter](#) which presents
|
||||
a summary of findings per package manifest. Thats NOT about it. Read more for
|
||||
expression based filtering and policy evaluation.
|
||||
|
||||
## Filtering
|
||||
|
||||
Find dependencies that seems not very popular
|
||||
|
||||
```bash
|
||||
vet scan --lockfiles /path/to/pom.xml --report-console=false \
|
||||
--filter='projects.exists(x, x.stars < 10)'
|
||||
```
|
||||
|
||||
Find dependencies with a critical vulnerability
|
||||
|
||||
```bash
|
||||
vet scan --lockfiles /path/to/pom.xml --report-console=false \
|
||||
--filter='vulns.critical.exists_one(x, true)'
|
||||
```
|
||||
|
||||
> Use filtering along with `query` command for offline slicing and dicing of
|
||||
> enriched package manifests. Read [filtering guide](docs/filtering.md)
|
||||
|
||||
[Common Expressions Language](https://github.com/google/cel-spec) is used to
|
||||
evaluate filters on packages. Learn more about [filtering with vet](docs/filtering.md).
|
||||
Look at [filter input spec](api/filter_input_spec.proto) on attributes
|
||||
available to the filter expression.
|
||||
|
||||
## Policy Evaluation
|
||||
|
||||
TODO
|
||||
|
||||
## FAQ
|
||||
|
||||
### How do I disable the stupid banner?
|
||||
|
||||
Set environment variable `VET_DISABLE_BANNER=1`
|
||||
|
||||
### Can I use this tool without an API Key for Insight Service?
|
||||
|
||||
Probably no. All useful data (enrichments) for a detected package comes from
|
||||
a backend service. The service is rate limited with quotas to prevent abuse.
|
||||
|
||||
Look at `api/insights-v1.yml`. It contains the contract expected for Insights
|
||||
API. You can perhaps consider rolling out your own to avoid dependency with our
|
||||
backend.
|
||||
|
||||
## References
|
||||
|
||||
* https://github.com/google/osv-scanner
|
||||
|
||||
|
||||
123
api/cp-v1-trials.yml
Normal file
123
api/cp-v1-trials.yml
Normal file
@ -0,0 +1,123 @@
|
||||
openapi: 3.0.2
|
||||
info:
|
||||
title: SafeDep Control Plane API for Trials Registration
|
||||
contact:
|
||||
name: SafeDep API
|
||||
url: 'https://safedep.io'
|
||||
description: |
|
||||
Trials API provide a way for obtaining an API Key for data plane service access
|
||||
using an Email Address. Trials is different from Registrations as the later
|
||||
allows full access to the control plane while Trials is meant to allow access
|
||||
only to a time bounded (expirable) API key for quick evaluation of tools.
|
||||
version: 0.0.1
|
||||
servers:
|
||||
- url: 'https://{apiHost}/{apiBase}'
|
||||
variables:
|
||||
apiHost:
|
||||
default: api.safedep.io
|
||||
apiBase:
|
||||
default: control-plane/v1
|
||||
tags:
|
||||
- name: Control Plane
|
||||
description: Control Plane API
|
||||
paths:
|
||||
/trials:
|
||||
post:
|
||||
description: |
|
||||
Register a trial user to obtain an expirable API Key. The API key will
|
||||
be generated and sent to the user over Email to ensure validity and access
|
||||
to the email by the requester. System defined limits will be applied to
|
||||
maximum number of trial API keys that can be generated for an email.
|
||||
operationId: registerTrialUser
|
||||
tags:
|
||||
- Control Plane
|
||||
requestBody:
|
||||
description: Trial registration request
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TrialRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Successfully created an API key request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TrialResponse'
|
||||
'403':
|
||||
description: Access to the API is denied
|
||||
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'
|
||||
components:
|
||||
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
|
||||
enum:
|
||||
- invalid_request
|
||||
- operation_failed
|
||||
- internal_error
|
||||
code:
|
||||
type: string
|
||||
description: An error code identifying the error
|
||||
enum:
|
||||
- api_guard_invalid_credentials
|
||||
- api_guard_rate_limit_exceeded
|
||||
- api_guard_unauthorized
|
||||
- api_guard_error
|
||||
- app_generic_error
|
||||
- app_security_error
|
||||
- app_insufficient_parameters
|
||||
- app_feature_not_enabled
|
||||
- app_package_version_not_found
|
||||
params:
|
||||
type: object
|
||||
description: Optional error specific attributes
|
||||
additionalProperties:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
value:
|
||||
type: string
|
||||
TrialRequest:
|
||||
type: object
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
required:
|
||||
- email
|
||||
TrialResponse:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
minLength: 6
|
||||
maxLength: 512
|
||||
description: The ID of the trial registration request created in the system
|
||||
expires_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: The expiry time of the API key
|
||||
50
api/filter_input_spec.proto
Normal file
50
api/filter_input_spec.proto
Normal file
@ -0,0 +1,50 @@
|
||||
syntax = "proto3";
|
||||
|
||||
/* Specifcations for filter input that can be used for query by CEL */
|
||||
option go_package = "github.com/safedep/vet/gen/filterinput";
|
||||
|
||||
message Vulnerability {
|
||||
string id = 1; // OSV ID
|
||||
string cve = 2; // CVE ID
|
||||
}
|
||||
|
||||
// Only hold vulnerability IDs
|
||||
message Vulnerabilities {
|
||||
repeated Vulnerability all = 1;
|
||||
repeated Vulnerability critical = 2;
|
||||
repeated Vulnerability high = 3;
|
||||
repeated Vulnerability medium = 4;
|
||||
repeated Vulnerability low = 5;
|
||||
}
|
||||
|
||||
// OpenSSF Scorecard
|
||||
message Scorecard {
|
||||
map<string, float> scores = 1;
|
||||
}
|
||||
|
||||
enum ProjectType {
|
||||
UNKNOWN = 0;
|
||||
GITHUB = 1;
|
||||
}
|
||||
|
||||
message ProjectInfo {
|
||||
string name = 1;
|
||||
ProjectType type = 2;
|
||||
int32 stars = 3;
|
||||
int32 forks = 4;
|
||||
int32 issues = 5;
|
||||
}
|
||||
|
||||
message PackageVersion {
|
||||
string ecosystem = 1;
|
||||
string name = 2;
|
||||
string version = 3;
|
||||
}
|
||||
|
||||
message FilterInput {
|
||||
PackageVersion pkg = 1;
|
||||
Vulnerabilities vulns = 2;
|
||||
Scorecard scorecard = 3;
|
||||
repeated ProjectInfo projects = 4;
|
||||
repeated string licenses = 5;
|
||||
}
|
||||
@ -47,6 +47,12 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PackageVersionInsight'
|
||||
'403':
|
||||
description: Access to the API is denied
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ApiError'
|
||||
'404':
|
||||
description: Requested resource was not found
|
||||
content:
|
||||
@ -757,11 +763,63 @@ components:
|
||||
type: integer
|
||||
link:
|
||||
type: string
|
||||
PackageVulnerability:
|
||||
type: object
|
||||
description: |
|
||||
Subset of OSV schema required to perform policy
|
||||
decision by various tools
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: Vulnerability identifier
|
||||
summary:
|
||||
type: string
|
||||
description: Short summary of vulnerability
|
||||
aliases:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: |
|
||||
Alias identifiers of the same vulnerability in
|
||||
other databases
|
||||
related:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: |
|
||||
Related vulnerability identifiers for similar issues
|
||||
in
|
||||
severities:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum:
|
||||
- UNSPECIFIED
|
||||
- CVSS_V3
|
||||
- CVSS_V2
|
||||
score:
|
||||
type: string
|
||||
description: Type specific vulnerability score
|
||||
risk:
|
||||
type: string
|
||||
enum:
|
||||
- CRITICAL
|
||||
- HIGH
|
||||
- MEDIUM
|
||||
- LOW
|
||||
- UNKNOWN
|
||||
description: Normalized risk rating computed from score
|
||||
PackageVersionInsight:
|
||||
type: object
|
||||
properties:
|
||||
package_version:
|
||||
$ref: '#/components/schemas/PackageVersion'
|
||||
package_current_version:
|
||||
type: string
|
||||
description: The latest version available for the package
|
||||
projects:
|
||||
type: array
|
||||
items:
|
||||
@ -778,3 +836,7 @@ components:
|
||||
$ref: '#/components/schemas/PackageDependency'
|
||||
scorecard:
|
||||
$ref: '#/components/schemas/Scorecard'
|
||||
vulnerabilities:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/PackageVulnerability'
|
||||
|
||||
41
auth.go
41
auth.go
@ -12,7 +12,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
authInsightApiBaseUrl string
|
||||
authInsightApiBaseUrl string
|
||||
authControlPlaneApiBaseUrl string
|
||||
authTrialEmail string
|
||||
)
|
||||
|
||||
func newAuthCommand() *cobra.Command {
|
||||
@ -28,6 +30,7 @@ func newAuthCommand() *cobra.Command {
|
||||
|
||||
cmd.AddCommand(configureAuthCommand())
|
||||
cmd.AddCommand(verifyAuthCommand())
|
||||
cmd.AddCommand(trialsRegisterCommand())
|
||||
|
||||
return cmd
|
||||
}
|
||||
@ -46,6 +49,7 @@ func configureAuthCommand() *cobra.Command {
|
||||
ApiUrl: authInsightApiBaseUrl,
|
||||
ApiKey: string(key),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -55,7 +59,7 @@ func configureAuthCommand() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&authInsightApiBaseUrl, "api", "", "https://api.safedep.io/insights/v1",
|
||||
cmd.Flags().StringVarP(&authInsightApiBaseUrl, "api", "", auth.DefaultApiUrl(),
|
||||
"Base URL of Insights API")
|
||||
|
||||
return cmd
|
||||
@ -66,7 +70,7 @@ func verifyAuthCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "verify",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
// Run auth.Verify()
|
||||
fmt.Printf("Verify auth command is currently work in progress\n")
|
||||
os.Exit(1)
|
||||
return nil
|
||||
},
|
||||
@ -74,3 +78,34 @@ func verifyAuthCommand() *cobra.Command {
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func trialsRegisterCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "trial",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
client := auth.NewTrialRegistrationClient(auth.TrialConfig{
|
||||
Email: authTrialEmail,
|
||||
ControlPlaneApiUrl: authControlPlaneApiBaseUrl,
|
||||
})
|
||||
|
||||
res, err := client.Execute()
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("Trial registration successful with Id:%s\n", res.Id)
|
||||
fmt.Printf("Check your email (%s) for API key and usage instructions\n", authTrialEmail)
|
||||
fmt.Printf("The trial API key will expire on %s\n", res.ExpiresAt.String())
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&authTrialEmail, "email", "", "",
|
||||
"Email address to use for sending trial API key")
|
||||
cmd.Flags().StringVarP(&authControlPlaneApiBaseUrl, "control-plane", "",
|
||||
auth.DefaultControlPlaneApiUrl(), "Base URL of Control Plane API for registrations")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
115
docs/filtering.md
Normal file
115
docs/filtering.md
Normal file
@ -0,0 +1,115 @@
|
||||
# Filtering
|
||||
|
||||
Filter command helps solve the problem of visibility for OSS dependencies in an
|
||||
application. To support various requirements, we adopt a generic [expressions
|
||||
language](https://github.com/google/cel-spec) for flexible filtering.
|
||||
|
||||
## Input
|
||||
|
||||
Filter expressions work on packages (aka. dependencies) and evaluates to
|
||||
a boolean result. The package is included in the results table if the
|
||||
expression evaluates to `true`.
|
||||
|
||||
Filter expressions get the following input data to work with
|
||||
|
||||
| Variable | Content |
|
||||
|-------------|-------------------------------------------------------------|
|
||||
| `_` | The root variable, holding other variables |
|
||||
| `vulns` | Holds a map of vulnerabiliteis by severity |
|
||||
| `scorecard` | Holds OpenSSF scorecard |
|
||||
| `projects` | Holds a list of source projects associated with the package |
|
||||
| `licenses` | Holds a list of liceses in SPDX license code format |
|
||||
|
||||
|
||||
## Expressions
|
||||
|
||||
Expressions are [CEL](https://github.com/google/cel-spec) statements. While
|
||||
CEL internals are not required, an [introductory](https://github.com/google/cel-spec/blob/master/doc/intro.md)
|
||||
knowledge of CEL will help formulating queries.
|
||||
|
||||
### Example Queries
|
||||
|
||||
| Description | Query |
|
||||
|----------------------------------------------|---------------------------------------|
|
||||
| Find packages with a critical vulnerability | `vulns.critical.exists(x, true)` |
|
||||
| Find unmaintained packages as per OpenSSF SC | `scorecard.score["Maintenance"] == 0` |
|
||||
| Find packages with low stars | `projects.exists(x, x.stars < 10)` |
|
||||
| Find packages with GPL-2.0 license | `licenses.exists(x, x == "GPL-2.0")`
|
||||
|
||||
Refer to [scorecard checks](https://github.com/ossf/scorecard#checks-1) for
|
||||
a list of checks available from OpenSSF Scorecards project.
|
||||
|
||||
## Query Workflow
|
||||
|
||||
Scanning a package manifest is a resource intensive process as it involves
|
||||
enriching package metadata by queryin [Insights API](https://safedep.io/docs/concepts/raya-data-platform-overview).
|
||||
However, for filtering and reporting may be done multiple times on the same
|
||||
manifest. To speed up the process, we can dump the enriched data as JSON and
|
||||
load the same for filtering and reporting.
|
||||
|
||||
Dump enriched JSON manifests to a directory (example)
|
||||
|
||||
```bash
|
||||
vet scan --lockfile /path/to/package-lock.json --json-dump-dir /tmp/dump
|
||||
vet scan -D /path/to/repository --json-dump-dir /tmp/dump-many
|
||||
```
|
||||
|
||||
Load the enriched metadata for filtering and reporting
|
||||
|
||||
```bash
|
||||
vet query --from /tmp/dump --report-console
|
||||
vet query --from /tmp/dump --filter 'scorecard.score["Maintenance"] == 0'
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
### How does the filter input JSON look like?
|
||||
|
||||
```json
|
||||
{
|
||||
"pkg": {
|
||||
"ecosystem": "npm",
|
||||
"name": "lodash.camelcase",
|
||||
"version": "4.3.0"
|
||||
},
|
||||
"vulns": {
|
||||
"all": [],
|
||||
"critical": [],
|
||||
"high": [],
|
||||
"medium": [],
|
||||
"low": []
|
||||
},
|
||||
"scorecard": {
|
||||
"scores": {
|
||||
"Binary-Artifacts": 10,
|
||||
"Branch-Protection": 0,
|
||||
"CII-Best-Practices": 0,
|
||||
"Code-Review": 8,
|
||||
"Dangerous-Workflow": 10,
|
||||
"Dependency-Update-Tool": 0,
|
||||
"Fuzzing": 0,
|
||||
"License": 10,
|
||||
"Maintained": 0,
|
||||
"Packaging": -1,
|
||||
"Pinned-Dependencies": 9,
|
||||
"SAST": 0,
|
||||
"Security-Policy": 10,
|
||||
"Signed-Releases": -1,
|
||||
"Token-Permissions": 0,
|
||||
"Vulnerabilities": 10
|
||||
}
|
||||
},
|
||||
"projects": [
|
||||
{
|
||||
"name": "lodash/lodash",
|
||||
"type": "GITHUB",
|
||||
"stars": 55518,
|
||||
"forks": 6787,
|
||||
"issues": 464
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
"MIT"
|
||||
]
|
||||
}
|
||||
```
|
||||
297
gen/controlplane/trials.client.go
Normal file
297
gen/controlplane/trials.client.go
Normal file
@ -0,0 +1,297 @@
|
||||
// Package controlplane 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 controlplane
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
// RegisterTrialUser request with any body
|
||||
RegisterTrialUserWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
RegisterTrialUser(ctx context.Context, body RegisterTrialUserJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
}
|
||||
|
||||
func (c *Client) RegisterTrialUserWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewRegisterTrialUserRequestWithBody(c.Server, contentType, body)
|
||||
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) RegisterTrialUser(ctx context.Context, body RegisterTrialUserJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewRegisterTrialUserRequest(c.Server, body)
|
||||
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)
|
||||
}
|
||||
|
||||
// NewRegisterTrialUserRequest calls the generic RegisterTrialUser builder with application/json body
|
||||
func NewRegisterTrialUserRequest(server string, body RegisterTrialUserJSONRequestBody) (*http.Request, error) {
|
||||
var bodyReader io.Reader
|
||||
buf, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bodyReader = bytes.NewReader(buf)
|
||||
return NewRegisterTrialUserRequestWithBody(server, "application/json", bodyReader)
|
||||
}
|
||||
|
||||
// NewRegisterTrialUserRequestWithBody generates requests for RegisterTrialUser with any type of body
|
||||
func NewRegisterTrialUserRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
|
||||
var err error
|
||||
|
||||
serverURL, err := url.Parse(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
operationPath := fmt.Sprintf("/trials")
|
||||
if operationPath[0] == '/' {
|
||||
operationPath = "." + operationPath
|
||||
}
|
||||
|
||||
queryURL, err := serverURL.Parse(operationPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", queryURL.String(), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", contentType)
|
||||
|
||||
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 {
|
||||
// RegisterTrialUser request with any body
|
||||
RegisterTrialUserWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RegisterTrialUserResponse, error)
|
||||
|
||||
RegisterTrialUserWithResponse(ctx context.Context, body RegisterTrialUserJSONRequestBody, reqEditors ...RequestEditorFn) (*RegisterTrialUserResponse, error)
|
||||
}
|
||||
|
||||
type RegisterTrialUserResponse struct {
|
||||
Body []byte
|
||||
HTTPResponse *http.Response
|
||||
JSON201 *TrialResponse
|
||||
JSON403 *ApiError
|
||||
JSON429 *ApiError
|
||||
JSON500 *ApiError
|
||||
}
|
||||
|
||||
// Status returns HTTPResponse.Status
|
||||
func (r RegisterTrialUserResponse) Status() string {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.Status
|
||||
}
|
||||
return http.StatusText(0)
|
||||
}
|
||||
|
||||
// StatusCode returns HTTPResponse.StatusCode
|
||||
func (r RegisterTrialUserResponse) StatusCode() int {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.StatusCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// RegisterTrialUserWithBodyWithResponse request with arbitrary body returning *RegisterTrialUserResponse
|
||||
func (c *ClientWithResponses) RegisterTrialUserWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RegisterTrialUserResponse, error) {
|
||||
rsp, err := c.RegisterTrialUserWithBody(ctx, contentType, body, reqEditors...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParseRegisterTrialUserResponse(rsp)
|
||||
}
|
||||
|
||||
func (c *ClientWithResponses) RegisterTrialUserWithResponse(ctx context.Context, body RegisterTrialUserJSONRequestBody, reqEditors ...RequestEditorFn) (*RegisterTrialUserResponse, error) {
|
||||
rsp, err := c.RegisterTrialUser(ctx, body, reqEditors...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParseRegisterTrialUserResponse(rsp)
|
||||
}
|
||||
|
||||
// ParseRegisterTrialUserResponse parses an HTTP response from a RegisterTrialUserWithResponse call
|
||||
func ParseRegisterTrialUserResponse(rsp *http.Response) (*RegisterTrialUserResponse, error) {
|
||||
bodyBytes, err := ioutil.ReadAll(rsp.Body)
|
||||
defer func() { _ = rsp.Body.Close() }()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &RegisterTrialUserResponse{
|
||||
Body: bodyBytes,
|
||||
HTTPResponse: rsp,
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201:
|
||||
var dest TrialResponse
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON201 = &dest
|
||||
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403:
|
||||
var dest ApiError
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON403 = &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
|
||||
}
|
||||
159
gen/controlplane/trials.types.go
Normal file
159
gen/controlplane/trials.types.go
Normal file
@ -0,0 +1,159 @@
|
||||
// Package controlplane 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 controlplane
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
openapi_types "github.com/deepmap/oapi-codegen/pkg/types"
|
||||
)
|
||||
|
||||
// Defines values for ApiErrorCode.
|
||||
const (
|
||||
ApiErrorCodeApiGuardError ApiErrorCode = "api_guard_error"
|
||||
|
||||
ApiErrorCodeApiGuardInvalidCredentials ApiErrorCode = "api_guard_invalid_credentials"
|
||||
|
||||
ApiErrorCodeApiGuardRateLimitExceeded ApiErrorCode = "api_guard_rate_limit_exceeded"
|
||||
|
||||
ApiErrorCodeApiGuardUnauthorized ApiErrorCode = "api_guard_unauthorized"
|
||||
|
||||
ApiErrorCodeAppFeatureNotEnabled ApiErrorCode = "app_feature_not_enabled"
|
||||
|
||||
ApiErrorCodeAppGenericError ApiErrorCode = "app_generic_error"
|
||||
|
||||
ApiErrorCodeAppInsufficientParameters ApiErrorCode = "app_insufficient_parameters"
|
||||
|
||||
ApiErrorCodeAppPackageVersionNotFound ApiErrorCode = "app_package_version_not_found"
|
||||
|
||||
ApiErrorCodeAppSecurityError ApiErrorCode = "app_security_error"
|
||||
)
|
||||
|
||||
// Defines values for ApiErrorType.
|
||||
const (
|
||||
ApiErrorTypeInternalError ApiErrorType = "internal_error"
|
||||
|
||||
ApiErrorTypeInvalidRequest ApiErrorType = "invalid_request"
|
||||
|
||||
ApiErrorTypeOperationFailed ApiErrorType = "operation_failed"
|
||||
)
|
||||
|
||||
// ApiError defines model for ApiError.
|
||||
type ApiError struct {
|
||||
// An error code identifying the error
|
||||
Code *ApiErrorCode `json:"code,omitempty"`
|
||||
|
||||
// A descriptive message about the error meant for developer consumption
|
||||
Message *string `json:"message,omitempty"`
|
||||
|
||||
// Optional error specific attributes
|
||||
Params *ApiError_Params `json:"params,omitempty"`
|
||||
|
||||
// An optional service or domain specific error group
|
||||
Type *ApiErrorType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// An error code identifying the error
|
||||
type ApiErrorCode string
|
||||
|
||||
// Optional error specific attributes
|
||||
type ApiError_Params struct {
|
||||
AdditionalProperties map[string]struct {
|
||||
Key *string `json:"key,omitempty"`
|
||||
Value *string `json:"value,omitempty"`
|
||||
} `json:"-"`
|
||||
}
|
||||
|
||||
// An optional service or domain specific error group
|
||||
type ApiErrorType string
|
||||
|
||||
// TrialRequest defines model for TrialRequest.
|
||||
type TrialRequest struct {
|
||||
Email openapi_types.Email `json:"email"`
|
||||
}
|
||||
|
||||
// TrialResponse defines model for TrialResponse.
|
||||
type TrialResponse struct {
|
||||
// The expiry time of the API key
|
||||
ExpiresAt *time.Time `json:"expires_at,omitempty"`
|
||||
|
||||
// The ID of the trial registration request created in the system
|
||||
Id *string `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// RegisterTrialUserJSONBody defines parameters for RegisterTrialUser.
|
||||
type RegisterTrialUserJSONBody TrialRequest
|
||||
|
||||
// RegisterTrialUserJSONRequestBody defines body for RegisterTrialUser for application/json ContentType.
|
||||
type RegisterTrialUserJSONRequestBody RegisterTrialUserJSONBody
|
||||
|
||||
// Getter for additional properties for ApiError_Params. Returns the specified
|
||||
// element and whether it was found
|
||||
func (a ApiError_Params) Get(fieldName string) (value struct {
|
||||
Key *string `json:"key,omitempty"`
|
||||
Value *string `json:"value,omitempty"`
|
||||
}, found bool) {
|
||||
if a.AdditionalProperties != nil {
|
||||
value, found = a.AdditionalProperties[fieldName]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Setter for additional properties for ApiError_Params
|
||||
func (a *ApiError_Params) Set(fieldName string, value struct {
|
||||
Key *string `json:"key,omitempty"`
|
||||
Value *string `json:"value,omitempty"`
|
||||
}) {
|
||||
if a.AdditionalProperties == nil {
|
||||
a.AdditionalProperties = make(map[string]struct {
|
||||
Key *string `json:"key,omitempty"`
|
||||
Value *string `json:"value,omitempty"`
|
||||
})
|
||||
}
|
||||
a.AdditionalProperties[fieldName] = value
|
||||
}
|
||||
|
||||
// Override default JSON handling for ApiError_Params to handle AdditionalProperties
|
||||
func (a *ApiError_Params) UnmarshalJSON(b []byte) error {
|
||||
object := make(map[string]json.RawMessage)
|
||||
err := json.Unmarshal(b, &object)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(object) != 0 {
|
||||
a.AdditionalProperties = make(map[string]struct {
|
||||
Key *string `json:"key,omitempty"`
|
||||
Value *string `json:"value,omitempty"`
|
||||
})
|
||||
for fieldName, fieldBuf := range object {
|
||||
var fieldVal struct {
|
||||
Key *string `json:"key,omitempty"`
|
||||
Value *string `json:"value,omitempty"`
|
||||
}
|
||||
err := json.Unmarshal(fieldBuf, &fieldVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
|
||||
}
|
||||
a.AdditionalProperties[fieldName] = fieldVal
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Override default JSON handling for ApiError_Params to handle AdditionalProperties
|
||||
func (a ApiError_Params) MarshalJSON() ([]byte, error) {
|
||||
var err error
|
||||
object := make(map[string]json.RawMessage)
|
||||
|
||||
for fieldName, field := range a.AdditionalProperties {
|
||||
object[fieldName], err = json.Marshal(field)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
|
||||
}
|
||||
}
|
||||
return json.Marshal(object)
|
||||
}
|
||||
678
gen/filterinput/filter_input_spec.pb.go
Normal file
678
gen/filterinput/filter_input_spec.pb.go
Normal file
@ -0,0 +1,678 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.28.0
|
||||
// protoc v3.18.0
|
||||
// source: filter_input_spec.proto
|
||||
|
||||
package filterinput
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ProjectType int32
|
||||
|
||||
const (
|
||||
ProjectType_UNKNOWN ProjectType = 0
|
||||
ProjectType_GITHUB ProjectType = 1
|
||||
)
|
||||
|
||||
// Enum value maps for ProjectType.
|
||||
var (
|
||||
ProjectType_name = map[int32]string{
|
||||
0: "UNKNOWN",
|
||||
1: "GITHUB",
|
||||
}
|
||||
ProjectType_value = map[string]int32{
|
||||
"UNKNOWN": 0,
|
||||
"GITHUB": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ProjectType) Enum() *ProjectType {
|
||||
p := new(ProjectType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ProjectType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ProjectType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_filter_input_spec_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (ProjectType) Type() protoreflect.EnumType {
|
||||
return &file_filter_input_spec_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x ProjectType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ProjectType.Descriptor instead.
|
||||
func (ProjectType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_filter_input_spec_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type Vulnerability struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // OSV ID
|
||||
Cve string `protobuf:"bytes,2,opt,name=cve,proto3" json:"cve,omitempty"` // CVE ID
|
||||
}
|
||||
|
||||
func (x *Vulnerability) Reset() {
|
||||
*x = Vulnerability{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Vulnerability) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Vulnerability) ProtoMessage() {}
|
||||
|
||||
func (x *Vulnerability) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Vulnerability.ProtoReflect.Descriptor instead.
|
||||
func (*Vulnerability) Descriptor() ([]byte, []int) {
|
||||
return file_filter_input_spec_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Vulnerability) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Vulnerability) GetCve() string {
|
||||
if x != nil {
|
||||
return x.Cve
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Only hold vulnerability IDs
|
||||
type Vulnerabilities struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
All []*Vulnerability `protobuf:"bytes,1,rep,name=all,proto3" json:"all,omitempty"`
|
||||
Critical []*Vulnerability `protobuf:"bytes,2,rep,name=critical,proto3" json:"critical,omitempty"`
|
||||
High []*Vulnerability `protobuf:"bytes,3,rep,name=high,proto3" json:"high,omitempty"`
|
||||
Medium []*Vulnerability `protobuf:"bytes,4,rep,name=medium,proto3" json:"medium,omitempty"`
|
||||
Low []*Vulnerability `protobuf:"bytes,5,rep,name=low,proto3" json:"low,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Vulnerabilities) Reset() {
|
||||
*x = Vulnerabilities{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Vulnerabilities) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Vulnerabilities) ProtoMessage() {}
|
||||
|
||||
func (x *Vulnerabilities) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Vulnerabilities.ProtoReflect.Descriptor instead.
|
||||
func (*Vulnerabilities) Descriptor() ([]byte, []int) {
|
||||
return file_filter_input_spec_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Vulnerabilities) GetAll() []*Vulnerability {
|
||||
if x != nil {
|
||||
return x.All
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Vulnerabilities) GetCritical() []*Vulnerability {
|
||||
if x != nil {
|
||||
return x.Critical
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Vulnerabilities) GetHigh() []*Vulnerability {
|
||||
if x != nil {
|
||||
return x.High
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Vulnerabilities) GetMedium() []*Vulnerability {
|
||||
if x != nil {
|
||||
return x.Medium
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Vulnerabilities) GetLow() []*Vulnerability {
|
||||
if x != nil {
|
||||
return x.Low
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpenSSF Scorecard
|
||||
type Scorecard struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Scores map[string]float32 `protobuf:"bytes,1,rep,name=scores,proto3" json:"scores,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"fixed32,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *Scorecard) Reset() {
|
||||
*x = Scorecard{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Scorecard) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Scorecard) ProtoMessage() {}
|
||||
|
||||
func (x *Scorecard) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Scorecard.ProtoReflect.Descriptor instead.
|
||||
func (*Scorecard) Descriptor() ([]byte, []int) {
|
||||
return file_filter_input_spec_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Scorecard) GetScores() map[string]float32 {
|
||||
if x != nil {
|
||||
return x.Scores
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ProjectInfo struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type ProjectType `protobuf:"varint,2,opt,name=type,proto3,enum=ProjectType" json:"type,omitempty"`
|
||||
Stars int32 `protobuf:"varint,3,opt,name=stars,proto3" json:"stars,omitempty"`
|
||||
Forks int32 `protobuf:"varint,4,opt,name=forks,proto3" json:"forks,omitempty"`
|
||||
Issues int32 `protobuf:"varint,5,opt,name=issues,proto3" json:"issues,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ProjectInfo) Reset() {
|
||||
*x = ProjectInfo{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *ProjectInfo) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ProjectInfo) ProtoMessage() {}
|
||||
|
||||
func (x *ProjectInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ProjectInfo.ProtoReflect.Descriptor instead.
|
||||
func (*ProjectInfo) Descriptor() ([]byte, []int) {
|
||||
return file_filter_input_spec_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ProjectInfo) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ProjectInfo) GetType() ProjectType {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ProjectType_UNKNOWN
|
||||
}
|
||||
|
||||
func (x *ProjectInfo) GetStars() int32 {
|
||||
if x != nil {
|
||||
return x.Stars
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProjectInfo) GetForks() int32 {
|
||||
if x != nil {
|
||||
return x.Forks
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ProjectInfo) GetIssues() int32 {
|
||||
if x != nil {
|
||||
return x.Issues
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type PackageVersion struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Ecosystem string `protobuf:"bytes,1,opt,name=ecosystem,proto3" json:"ecosystem,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PackageVersion) Reset() {
|
||||
*x = PackageVersion{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PackageVersion) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PackageVersion) ProtoMessage() {}
|
||||
|
||||
func (x *PackageVersion) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[4]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PackageVersion.ProtoReflect.Descriptor instead.
|
||||
func (*PackageVersion) Descriptor() ([]byte, []int) {
|
||||
return file_filter_input_spec_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *PackageVersion) GetEcosystem() string {
|
||||
if x != nil {
|
||||
return x.Ecosystem
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PackageVersion) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PackageVersion) GetVersion() string {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type FilterInput struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Pkg *PackageVersion `protobuf:"bytes,1,opt,name=pkg,proto3" json:"pkg,omitempty"`
|
||||
Vulns *Vulnerabilities `protobuf:"bytes,2,opt,name=vulns,proto3" json:"vulns,omitempty"`
|
||||
Scorecard *Scorecard `protobuf:"bytes,3,opt,name=scorecard,proto3" json:"scorecard,omitempty"`
|
||||
Projects []*ProjectInfo `protobuf:"bytes,4,rep,name=projects,proto3" json:"projects,omitempty"`
|
||||
Licenses []string `protobuf:"bytes,5,rep,name=licenses,proto3" json:"licenses,omitempty"`
|
||||
}
|
||||
|
||||
func (x *FilterInput) Reset() {
|
||||
*x = FilterInput{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *FilterInput) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*FilterInput) ProtoMessage() {}
|
||||
|
||||
func (x *FilterInput) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_filter_input_spec_proto_msgTypes[5]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use FilterInput.ProtoReflect.Descriptor instead.
|
||||
func (*FilterInput) Descriptor() ([]byte, []int) {
|
||||
return file_filter_input_spec_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *FilterInput) GetPkg() *PackageVersion {
|
||||
if x != nil {
|
||||
return x.Pkg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *FilterInput) GetVulns() *Vulnerabilities {
|
||||
if x != nil {
|
||||
return x.Vulns
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *FilterInput) GetScorecard() *Scorecard {
|
||||
if x != nil {
|
||||
return x.Scorecard
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *FilterInput) GetProjects() []*ProjectInfo {
|
||||
if x != nil {
|
||||
return x.Projects
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *FilterInput) GetLicenses() []string {
|
||||
if x != nil {
|
||||
return x.Licenses
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_filter_input_spec_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_filter_input_spec_proto_rawDesc = []byte{
|
||||
0x0a, 0x17, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x73,
|
||||
0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x31, 0x0a, 0x0d, 0x56, 0x75, 0x6c,
|
||||
0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x76,
|
||||
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, 0x76, 0x65, 0x22, 0xcd, 0x01, 0x0a,
|
||||
0x0f, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73,
|
||||
0x12, 0x20, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
|
||||
0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x03, 0x61,
|
||||
0x6c, 0x6c, 0x12, 0x2a, 0x0a, 0x08, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x18, 0x02,
|
||||
0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69,
|
||||
0x6c, 0x69, 0x74, 0x79, 0x52, 0x08, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x12, 0x22,
|
||||
0x0a, 0x04, 0x68, 0x69, 0x67, 0x68, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x56,
|
||||
0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x04, 0x68, 0x69,
|
||||
0x67, 0x68, 0x12, 0x26, 0x0a, 0x06, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69,
|
||||
0x74, 0x79, 0x52, 0x06, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x12, 0x20, 0x0a, 0x03, 0x6c, 0x6f,
|
||||
0x77, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72,
|
||||
0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x03, 0x6c, 0x6f, 0x77, 0x22, 0x76, 0x0a, 0x09,
|
||||
0x53, 0x63, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x72, 0x64, 0x12, 0x2e, 0x0a, 0x06, 0x73, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x53, 0x63, 0x6f, 0x72,
|
||||
0x65, 0x63, 0x61, 0x72, 0x64, 0x2e, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72,
|
||||
0x79, 0x52, 0x06, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x1a, 0x39, 0x0a, 0x0b, 0x53, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x02, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x3a, 0x02, 0x38, 0x01, 0x22, 0x87, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74,
|
||||
0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74,
|
||||
0x61, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x73,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x05, 0x66, 0x6f, 0x72, 0x6b, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x73, 0x22, 0x5c,
|
||||
0x0a, 0x0e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x1c, 0x0a, 0x09, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x63, 0x6f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xc8, 0x01, 0x0a,
|
||||
0x0b, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x21, 0x0a, 0x03,
|
||||
0x70, 0x6b, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x50, 0x61, 0x63, 0x6b,
|
||||
0x61, 0x67, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x03, 0x70, 0x6b, 0x67, 0x12,
|
||||
0x26, 0x0a, 0x05, 0x76, 0x75, 0x6c, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10,
|
||||
0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73,
|
||||
0x52, 0x05, 0x76, 0x75, 0x6c, 0x6e, 0x73, 0x12, 0x28, 0x0a, 0x09, 0x73, 0x63, 0x6f, 0x72, 0x65,
|
||||
0x63, 0x61, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x53, 0x63, 0x6f,
|
||||
0x72, 0x65, 0x63, 0x61, 0x72, 0x64, 0x52, 0x09, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x63, 0x61, 0x72,
|
||||
0x64, 0x12, 0x28, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x66,
|
||||
0x6f, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6c,
|
||||
0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6c,
|
||||
0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x2a, 0x26, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x6a, 0x65,
|
||||
0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57,
|
||||
0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x10, 0x01, 0x42,
|
||||
0x28, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x61,
|
||||
0x66, 0x65, 0x64, 0x65, 0x70, 0x2f, 0x76, 0x65, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x66, 0x69,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_filter_input_spec_proto_rawDescOnce sync.Once
|
||||
file_filter_input_spec_proto_rawDescData = file_filter_input_spec_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_filter_input_spec_proto_rawDescGZIP() []byte {
|
||||
file_filter_input_spec_proto_rawDescOnce.Do(func() {
|
||||
file_filter_input_spec_proto_rawDescData = protoimpl.X.CompressGZIP(file_filter_input_spec_proto_rawDescData)
|
||||
})
|
||||
return file_filter_input_spec_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_filter_input_spec_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_filter_input_spec_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_filter_input_spec_proto_goTypes = []interface{}{
|
||||
(ProjectType)(0), // 0: ProjectType
|
||||
(*Vulnerability)(nil), // 1: Vulnerability
|
||||
(*Vulnerabilities)(nil), // 2: Vulnerabilities
|
||||
(*Scorecard)(nil), // 3: Scorecard
|
||||
(*ProjectInfo)(nil), // 4: ProjectInfo
|
||||
(*PackageVersion)(nil), // 5: PackageVersion
|
||||
(*FilterInput)(nil), // 6: FilterInput
|
||||
nil, // 7: Scorecard.ScoresEntry
|
||||
}
|
||||
var file_filter_input_spec_proto_depIdxs = []int32{
|
||||
1, // 0: Vulnerabilities.all:type_name -> Vulnerability
|
||||
1, // 1: Vulnerabilities.critical:type_name -> Vulnerability
|
||||
1, // 2: Vulnerabilities.high:type_name -> Vulnerability
|
||||
1, // 3: Vulnerabilities.medium:type_name -> Vulnerability
|
||||
1, // 4: Vulnerabilities.low:type_name -> Vulnerability
|
||||
7, // 5: Scorecard.scores:type_name -> Scorecard.ScoresEntry
|
||||
0, // 6: ProjectInfo.type:type_name -> ProjectType
|
||||
5, // 7: FilterInput.pkg:type_name -> PackageVersion
|
||||
2, // 8: FilterInput.vulns:type_name -> Vulnerabilities
|
||||
3, // 9: FilterInput.scorecard:type_name -> Scorecard
|
||||
4, // 10: FilterInput.projects:type_name -> ProjectInfo
|
||||
11, // [11:11] is the sub-list for method output_type
|
||||
11, // [11:11] is the sub-list for method input_type
|
||||
11, // [11:11] is the sub-list for extension type_name
|
||||
11, // [11:11] is the sub-list for extension extendee
|
||||
0, // [0:11] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_filter_input_spec_proto_init() }
|
||||
func file_filter_input_spec_proto_init() {
|
||||
if File_filter_input_spec_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_filter_input_spec_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Vulnerability); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_filter_input_spec_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Vulnerabilities); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_filter_input_spec_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Scorecard); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_filter_input_spec_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*ProjectInfo); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_filter_input_spec_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PackageVersion); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_filter_input_spec_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*FilterInput); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_filter_input_spec_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 7,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_filter_input_spec_proto_goTypes,
|
||||
DependencyIndexes: file_filter_input_spec_proto_depIdxs,
|
||||
EnumInfos: file_filter_input_spec_proto_enumTypes,
|
||||
MessageInfos: file_filter_input_spec_proto_msgTypes,
|
||||
}.Build()
|
||||
File_filter_input_spec_proto = out.File
|
||||
file_filter_input_spec_proto_rawDesc = nil
|
||||
file_filter_input_spec_proto_goTypes = nil
|
||||
file_filter_input_spec_proto_depIdxs = nil
|
||||
}
|
||||
@ -269,6 +269,7 @@ type GetPackageVersionInsightResponse struct {
|
||||
Body []byte
|
||||
HTTPResponse *http.Response
|
||||
JSON200 *PackageVersionInsight
|
||||
JSON403 *ApiError
|
||||
JSON404 *ApiError
|
||||
JSON429 *ApiError
|
||||
JSON500 *ApiError
|
||||
@ -345,6 +346,13 @@ func ParseGetPackageVersionInsightResponse(rsp *http.Response) (*GetPackageVersi
|
||||
}
|
||||
response.JSON200 = &dest
|
||||
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403:
|
||||
var dest ApiError
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON403 = &dest
|
||||
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
|
||||
var dest ApiError
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
|
||||
@ -1021,6 +1021,28 @@ const (
|
||||
LicenseZlibAcknowledgement License = "zlib-acknowledgement"
|
||||
)
|
||||
|
||||
// Defines values for PackageVulnerabilitySeveritiesRisk.
|
||||
const (
|
||||
PackageVulnerabilitySeveritiesRiskCRITICAL PackageVulnerabilitySeveritiesRisk = "CRITICAL"
|
||||
|
||||
PackageVulnerabilitySeveritiesRiskHIGH PackageVulnerabilitySeveritiesRisk = "HIGH"
|
||||
|
||||
PackageVulnerabilitySeveritiesRiskLOW PackageVulnerabilitySeveritiesRisk = "LOW"
|
||||
|
||||
PackageVulnerabilitySeveritiesRiskMEDIUM PackageVulnerabilitySeveritiesRisk = "MEDIUM"
|
||||
|
||||
PackageVulnerabilitySeveritiesRiskUNKNOWN PackageVulnerabilitySeveritiesRisk = "UNKNOWN"
|
||||
)
|
||||
|
||||
// Defines values for PackageVulnerabilitySeveritiesType.
|
||||
const (
|
||||
PackageVulnerabilitySeveritiesTypeCVSSV2 PackageVulnerabilitySeveritiesType = "CVSS_V2"
|
||||
|
||||
PackageVulnerabilitySeveritiesTypeCVSSV3 PackageVulnerabilitySeveritiesType = "CVSS_V3"
|
||||
|
||||
PackageVulnerabilitySeveritiesTypeUNSPECIFIED PackageVulnerabilitySeveritiesType = "UNSPECIFIED"
|
||||
)
|
||||
|
||||
// Defines values for ScorecardVersion.
|
||||
const (
|
||||
ScorecardVersionV2 ScorecardVersion = "V2"
|
||||
@ -1133,14 +1155,50 @@ type PackageVersion struct {
|
||||
|
||||
// PackageVersionInsight defines model for PackageVersionInsight.
|
||||
type PackageVersionInsight struct {
|
||||
Dependencies *[]PackageDependency `json:"dependencies,omitempty"`
|
||||
Dependents *PackageDependents `json:"dependents,omitempty"`
|
||||
Licenses *[]License `json:"licenses,omitempty"`
|
||||
PackageVersion *PackageVersion `json:"package_version,omitempty"`
|
||||
Projects *[]PackageProjectInfo `json:"projects,omitempty"`
|
||||
Scorecard *Scorecard `json:"scorecard,omitempty"`
|
||||
Dependencies *[]PackageDependency `json:"dependencies,omitempty"`
|
||||
Dependents *PackageDependents `json:"dependents,omitempty"`
|
||||
Licenses *[]License `json:"licenses,omitempty"`
|
||||
|
||||
// The latest version available for the package
|
||||
PackageCurrentVersion *string `json:"package_current_version,omitempty"`
|
||||
PackageVersion *PackageVersion `json:"package_version,omitempty"`
|
||||
Projects *[]PackageProjectInfo `json:"projects,omitempty"`
|
||||
Scorecard *Scorecard `json:"scorecard,omitempty"`
|
||||
Vulnerabilities *[]PackageVulnerability `json:"vulnerabilities,omitempty"`
|
||||
}
|
||||
|
||||
// Subset of OSV schema required to perform policy
|
||||
// decision by various tools
|
||||
type PackageVulnerability struct {
|
||||
// Alias identifiers of the same vulnerability in
|
||||
// other databases
|
||||
Aliases *[]string `json:"aliases,omitempty"`
|
||||
|
||||
// Vulnerability identifier
|
||||
Id *string `json:"id,omitempty"`
|
||||
|
||||
// Related vulnerability identifiers for similar issues
|
||||
// in
|
||||
Related *[]string `json:"related,omitempty"`
|
||||
Severities *[]struct {
|
||||
// Normalized risk rating computed from score
|
||||
Risk *PackageVulnerabilitySeveritiesRisk `json:"risk,omitempty"`
|
||||
|
||||
// Type specific vulnerability score
|
||||
Score *string `json:"score,omitempty"`
|
||||
Type *PackageVulnerabilitySeveritiesType `json:"type,omitempty"`
|
||||
} `json:"severities,omitempty"`
|
||||
|
||||
// Short summary of vulnerability
|
||||
Summary *string `json:"summary,omitempty"`
|
||||
}
|
||||
|
||||
// Normalized risk rating computed from score
|
||||
type PackageVulnerabilitySeveritiesRisk string
|
||||
|
||||
// PackageVulnerabilitySeveritiesType defines model for PackageVulnerability.Severities.Type.
|
||||
type PackageVulnerabilitySeveritiesType string
|
||||
|
||||
// Scorecard defines model for Scorecard.
|
||||
type Scorecard struct {
|
||||
Content *ScorecardContentV2 `json:"content,omitempty"`
|
||||
|
||||
14
go.mod
14
go.mod
@ -5,11 +5,13 @@ 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/google/osv-scanner v1.1.0
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.4
|
||||
github.com/safedep/dry v0.0.0-20230202121135-2225c66946de
|
||||
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
|
||||
golang.org/x/term v0.4.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
@ -18,13 +20,19 @@ require (
|
||||
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/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/masterminds/semver v1.5.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/oklog/ulid/v2 v2.1.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // 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/sys v0.4.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
|
||||
|
||||
34
go.sum
34
go.sum
@ -1,5 +1,6 @@
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
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=
|
||||
@ -13,20 +14,38 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
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/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
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/osv-scanner v1.1.0 h1:6XL8tD8u4w8NFyiMo03Yd4xGG1VXhZXyrBESBuyWeUY=
|
||||
github.com/google/osv-scanner v1.1.0/go.mod h1:w8BdEP4PJSosGhDfZ6W5RGMfIGb73rW38vCXB9DWA4c=
|
||||
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/jedib0t/go-pretty/v6 v6.4.4 h1:N+gz6UngBPF4M288kiMURPHELDMIhF/Em35aYuKrsSc=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.4/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
github.com/masterminds/semver v1.5.0 h1:hTxJTTY7tjvnWMrl08O6u3G6BLlKVwxSz01lVac9P8U=
|
||||
github.com/masterminds/semver v1.5.0/go.mod h1:s7KNT9fnd7edGzwwP7RBX4H0v/CYd5qdOLfkL1V75yg=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
|
||||
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
|
||||
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
|
||||
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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/safedep/dry v0.0.0-20230202121135-2225c66946de h1:07LwA5P5bxaVK8SXtoBfP8qZGcWAtqiFbq54UZnMcyg=
|
||||
github.com/safedep/dry v0.0.0-20230202121135-2225c66946de/go.mod h1:H111d9khzpHFEqKXb9lgAZ1W5eeK7yEN7ToWu0ak+JI=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
@ -43,22 +62,25 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
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=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.4.0 h1:O7UWfv5+A2qiuulQk30kVinPoMtoIPeVaKLEgLpVkvg=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
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.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
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=
|
||||
|
||||
@ -13,7 +13,8 @@ const (
|
||||
apiUrlEnvKey = "VET_INSIGHTS_API_URL"
|
||||
apiKeyEnvKey = "VET_INSIGHTS_API_KEY"
|
||||
|
||||
defaultApiUrl = "https://api.safedep.io/insights/v1"
|
||||
defaultApiUrl = "https://api.safedep.io/insights/v1"
|
||||
defaultControlPlaneApiUrl = "https://api.safedep.io/control-plane/v1"
|
||||
|
||||
homeRelativeConfigPath = ".safedep/vet-auth.yml"
|
||||
)
|
||||
@ -40,6 +41,14 @@ func Verify() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func DefaultApiUrl() string {
|
||||
return defaultApiUrl
|
||||
}
|
||||
|
||||
func DefaultControlPlaneApiUrl() string {
|
||||
return defaultControlPlaneApiUrl
|
||||
}
|
||||
|
||||
func ApiUrl() string {
|
||||
if url, ok := os.LookupEnv(apiUrlEnvKey); ok {
|
||||
return url
|
||||
|
||||
77
internal/auth/trial.go
Normal file
77
internal/auth/trial.go
Normal file
@ -0,0 +1,77 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/types"
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/gen/controlplane"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
|
||||
apierr "github.com/safedep/dry/errors"
|
||||
)
|
||||
|
||||
type TrialConfig struct {
|
||||
Email string
|
||||
ControlPlaneApiUrl string
|
||||
}
|
||||
|
||||
type trialRegistrationResponse struct {
|
||||
Id string
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
type trialRegistrationClient struct {
|
||||
config TrialConfig
|
||||
}
|
||||
|
||||
func NewTrialRegistrationClient(config TrialConfig) *trialRegistrationClient {
|
||||
return &trialRegistrationClient{config: config}
|
||||
}
|
||||
|
||||
func (client *trialRegistrationClient) Execute() (*trialRegistrationResponse, error) {
|
||||
if utils.IsEmptyString(client.config.Email) {
|
||||
return nil, errors.New("email is required")
|
||||
}
|
||||
|
||||
if utils.IsEmptyString(client.config.ControlPlaneApiUrl) {
|
||||
return nil, errors.New("control plane API is required")
|
||||
}
|
||||
|
||||
logger.Infof("Trial registrations using Control Plane: %s",
|
||||
client.config.ControlPlaneApiUrl)
|
||||
|
||||
cpClient, err := controlplane.NewClientWithResponses(client.config.ControlPlaneApiUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Infof("Trial registration requesting API key for: %s",
|
||||
client.config.Email)
|
||||
|
||||
res, err := cpClient.RegisterTrialUserWithResponse(context.Background(),
|
||||
controlplane.RegisterTrialUserJSONRequestBody{
|
||||
Email: types.Email(client.config.Email),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.HTTPResponse.StatusCode != http.StatusCreated {
|
||||
if err, ok := apierr.UnmarshalApiError(res.Body); ok {
|
||||
return nil, err
|
||||
} else {
|
||||
return nil, fmt.Errorf("unexpected status code:%d from control plane",
|
||||
res.HTTPResponse.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
return &trialRegistrationResponse{
|
||||
Id: utils.SafelyGetValue(res.JSON201.Id),
|
||||
ExpiresAt: utils.SafelyGetValue(res.JSON201.ExpiresAt),
|
||||
}, nil
|
||||
}
|
||||
27
main.go
27
main.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
"github.com/spf13/cobra"
|
||||
@ -13,10 +14,25 @@ var (
|
||||
debug bool
|
||||
)
|
||||
|
||||
var banner string = `
|
||||
.----------------. .----------------. .----------------.
|
||||
| .--------------. || .--------------. || .--------------. |
|
||||
| | ____ ____ | || | _________ | || | _________ | |
|
||||
| ||_ _| |_ _| | || | |_ ___ | | || | | _ _ | | |
|
||||
| | \ \ / / | || | | |_ \_| | || | |_/ | | \_| | |
|
||||
| | \ \ / / | || | | _| _ | || | | | | |
|
||||
| | \ ' / | || | _| |___/ | | || | _| |_ | |
|
||||
| | \_/ | || | |_________| | || | |_____| | |
|
||||
| | | || | | || | | |
|
||||
| '--------------' || '--------------' || '--------------' |
|
||||
'----------------' '----------------' '----------------'
|
||||
|
||||
`
|
||||
|
||||
func main() {
|
||||
cmd := &cobra.Command{
|
||||
Use: "vet [OPTIONS] COMMAND [ARG...]",
|
||||
Short: "Vet your 3rd party dependencies for security risks",
|
||||
Short: "[ Establish trust in open source software supply chain ]",
|
||||
TraverseChildren: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) == 0 {
|
||||
@ -32,9 +48,11 @@ func main() {
|
||||
|
||||
cmd.AddCommand(newAuthCommand())
|
||||
cmd.AddCommand(newScanCommand())
|
||||
cmd.AddCommand(newQueryCommand())
|
||||
cmd.AddCommand(newVersionCommand())
|
||||
|
||||
cobra.OnInitialize(func() {
|
||||
printBanner()
|
||||
logger.SetLogLevel(verbose, debug)
|
||||
})
|
||||
|
||||
@ -42,3 +60,10 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func printBanner() {
|
||||
bRet, err := strconv.ParseBool(os.Getenv("VET_DISABLE_BANNER"))
|
||||
if (err != nil) || (!bRet) {
|
||||
fmt.Print(banner)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,21 +3,42 @@ package analyzer
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/gen/filterinput"
|
||||
"github.com/safedep/vet/gen/insightapi"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
)
|
||||
|
||||
const (
|
||||
filterInputVarRoot = "_"
|
||||
filterInputVarPkg = "pkg"
|
||||
filterInputVarVulns = "vulns"
|
||||
filterInputVarScorecard = "scorecard"
|
||||
filterInputVarProjects = "projects"
|
||||
filterInputVarLicenses = "licenses"
|
||||
)
|
||||
|
||||
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),
|
||||
cel.Variable(filterInputVarPkg, cel.DynType),
|
||||
cel.Variable(filterInputVarVulns, cel.DynType),
|
||||
cel.Variable(filterInputVarProjects, cel.DynType),
|
||||
cel.Variable(filterInputVarScorecard, cel.DynType),
|
||||
cel.Variable(filterInputVarLicenses, cel.DynType),
|
||||
cel.Variable(filterInputVarRoot, cel.DynType),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
@ -44,25 +65,47 @@ func (f *celFilterAnalyzer) Name() string {
|
||||
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)
|
||||
}
|
||||
tbl := table.NewWriter()
|
||||
tbl.SetStyle(table.StyleLight)
|
||||
tbl.SetOutputMirror(os.Stdout)
|
||||
tbl.AppendHeader(table.Row{"Ecosystem", "Package", "Version",
|
||||
"Latest", "Source"})
|
||||
|
||||
filterStat := struct {
|
||||
total int
|
||||
matched int
|
||||
err int
|
||||
}{}
|
||||
|
||||
logger.Infof("CEL filtering manifest: %s", manifest.Path)
|
||||
for _, pkg := range manifest.Packages {
|
||||
pkgVal, err := f.valType(pkg)
|
||||
filterStat.total += 1
|
||||
|
||||
filterInput, err := f.buildFilterInput(pkg)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to convert package to val: %v", err)
|
||||
filterStat.err += 1
|
||||
logger.Errorf("Failed to convert package to filter input: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
serializedInput, err := f.serializeFilterInput(filterInput)
|
||||
if err != nil {
|
||||
filterStat.err += 1
|
||||
logger.Errorf("Failed to serialize filter input: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
out, _, err := f.program.Eval(map[string]interface{}{
|
||||
"pkg": pkgVal,
|
||||
"manifest": pkgManifestVal,
|
||||
filterInputVarRoot: serializedInput,
|
||||
filterInputVarPkg: serializedInput["pkg"],
|
||||
filterInputVarProjects: serializedInput["projects"],
|
||||
filterInputVarVulns: serializedInput["vulns"],
|
||||
filterInputVarScorecard: serializedInput["scorecard"],
|
||||
filterInputVarLicenses: serializedInput["licenses"],
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
filterStat.err += 1
|
||||
logger.Errorf("Failed to evaluate CEL for %s:%v : %v",
|
||||
pkg.PackageDetails.Name,
|
||||
pkg.PackageDetails.Version, err)
|
||||
@ -71,25 +114,162 @@ func (f *celFilterAnalyzer) Analyze(manifest *models.PackageManifest,
|
||||
|
||||
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)
|
||||
filterStat.matched += 1
|
||||
tbl.AppendRow(table.Row{pkg.PackageDetails.Ecosystem,
|
||||
pkg.PackageDetails.Name,
|
||||
pkg.PackageDetails.Version,
|
||||
f.pkgLatestVersion(pkg),
|
||||
f.pkgSource(pkg),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%s\n", text.Bold.Sprint("Filter evaluated with ",
|
||||
filterStat.matched, " out of ", filterStat.total, " matched and ",
|
||||
filterStat.err, " error(s)"))
|
||||
|
||||
tbl.Render()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *celFilterAnalyzer) valType(i any) (any, error) {
|
||||
data, err := json.Marshal(i)
|
||||
// TODO: Fix this JSON round-trip problem by directly configuring CEL env to
|
||||
// work with Protobuf messages
|
||||
func (f *celFilterAnalyzer) serializeFilterInput(fi *filterinput.FilterInput) (map[string]interface{}, error) {
|
||||
var ret map[string]interface{}
|
||||
m := jsonpb.Marshaler{OrigName: true, EnumsAsInts: false, EmitDefaults: true}
|
||||
|
||||
data, err := m.MarshalToString(fi)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return ret, err
|
||||
}
|
||||
|
||||
ret := make(map[string]interface{})
|
||||
err = json.Unmarshal(data, &ret)
|
||||
logger.Debugf("Serialized filter input: %s", data)
|
||||
|
||||
err = json.Unmarshal([]byte(data), &ret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return ret, err
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (f *celFilterAnalyzer) pkgLatestVersion(pkg *models.Package) string {
|
||||
insight := utils.SafelyGetValue(pkg.Insights)
|
||||
return utils.SafelyGetValue(insight.PackageCurrentVersion)
|
||||
}
|
||||
|
||||
func (f *celFilterAnalyzer) pkgSource(pkg *models.Package) string {
|
||||
insight := utils.SafelyGetValue(pkg.Insights)
|
||||
projects := utils.SafelyGetValue(insight.Projects)
|
||||
|
||||
if len(projects) > 0 {
|
||||
return utils.SafelyGetValue(projects[0].Link)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (f *celFilterAnalyzer) buildFilterInput(pkg *models.Package) (*filterinput.FilterInput, error) {
|
||||
fi := filterinput.FilterInput{
|
||||
Pkg: &filterinput.PackageVersion{
|
||||
Ecosystem: strings.ToLower(string(pkg.PackageDetails.Ecosystem)),
|
||||
Name: pkg.PackageDetails.Name,
|
||||
Version: pkg.PackageDetails.Version,
|
||||
},
|
||||
Projects: []*filterinput.ProjectInfo{},
|
||||
Vulns: &filterinput.Vulnerabilities{
|
||||
All: []*filterinput.Vulnerability{},
|
||||
Critical: []*filterinput.Vulnerability{},
|
||||
High: []*filterinput.Vulnerability{},
|
||||
Medium: []*filterinput.Vulnerability{},
|
||||
Low: []*filterinput.Vulnerability{},
|
||||
},
|
||||
Scorecard: &filterinput.Scorecard{
|
||||
Scores: map[string]float32{},
|
||||
},
|
||||
Licenses: []string{},
|
||||
}
|
||||
|
||||
// Safely get insight
|
||||
insight := utils.SafelyGetValue(pkg.Insights)
|
||||
|
||||
// Add projects
|
||||
projectTypeMapper := func(tp string) filterinput.ProjectType {
|
||||
tp = strings.ToLower(tp)
|
||||
if tp == "github" {
|
||||
return filterinput.ProjectType_GITHUB
|
||||
} else {
|
||||
return filterinput.ProjectType_UNKNOWN
|
||||
}
|
||||
}
|
||||
|
||||
for _, project := range utils.SafelyGetValue(insight.Projects) {
|
||||
fi.Projects = append(fi.Projects, &filterinput.ProjectInfo{
|
||||
Name: utils.SafelyGetValue(project.Name),
|
||||
Stars: int32(utils.SafelyGetValue(project.Stars)),
|
||||
Forks: int32(utils.SafelyGetValue(project.Forks)),
|
||||
Issues: int32(utils.SafelyGetValue(project.Issues)),
|
||||
Type: projectTypeMapper(utils.SafelyGetValue(project.Type)),
|
||||
})
|
||||
}
|
||||
|
||||
// Add vulnerabilities
|
||||
cveFilter := func(aliases []string) string {
|
||||
for _, alias := range aliases {
|
||||
if strings.HasPrefix(strings.ToUpper(alias), "CVE-") {
|
||||
return alias
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
for _, vuln := range utils.SafelyGetValue(insight.Vulnerabilities) {
|
||||
fiv := filterinput.Vulnerability{
|
||||
Id: utils.SafelyGetValue(vuln.Id),
|
||||
Cve: cveFilter(utils.SafelyGetValue(vuln.Aliases)),
|
||||
}
|
||||
|
||||
fi.Vulns.All = append(fi.Vulns.All, &fiv)
|
||||
|
||||
risk := insightapi.PackageVulnerabilitySeveritiesRiskUNKNOWN
|
||||
for _, s := range utils.SafelyGetValue(vuln.Severities) {
|
||||
sType := utils.SafelyGetValue(s.Type)
|
||||
if (sType == insightapi.PackageVulnerabilitySeveritiesTypeCVSSV3) ||
|
||||
(sType == insightapi.PackageVulnerabilitySeveritiesTypeCVSSV2) {
|
||||
risk = utils.SafelyGetValue(s.Risk)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
switch risk {
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskCRITICAL:
|
||||
fi.Vulns.Critical = append(fi.Vulns.Critical, &fiv)
|
||||
break
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskHIGH:
|
||||
fi.Vulns.High = append(fi.Vulns.High, &fiv)
|
||||
break
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskMEDIUM:
|
||||
fi.Vulns.Medium = append(fi.Vulns.Medium, &fiv)
|
||||
break
|
||||
case insightapi.PackageVulnerabilitySeveritiesRiskLOW:
|
||||
fi.Vulns.Low = append(fi.Vulns.Low, &fiv)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Add licenses
|
||||
for _, lic := range utils.SafelyGetValue(insight.Licenses) {
|
||||
fi.Licenses = append(fi.Licenses, string(lic))
|
||||
}
|
||||
|
||||
// Scorecard
|
||||
scorecard := utils.SafelyGetValue(insight.Scorecard)
|
||||
checks := utils.SafelyGetValue(utils.SafelyGetValue(scorecard.Content).Checks)
|
||||
for _, check := range checks {
|
||||
fi.Scorecard.Scores[string(utils.SafelyGetValue(check.Name))] =
|
||||
utils.SafelyGetValue(check.Score)
|
||||
}
|
||||
|
||||
return &fi, nil
|
||||
}
|
||||
|
||||
@ -25,12 +25,10 @@ func NewJsonDumperAnalyzer(dir string) (Analyzer, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create dir: %w", err)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("cannot stat dir: %w", err)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("cannot stat dir: %w", err)
|
||||
}
|
||||
|
||||
if !fi.IsDir() {
|
||||
} else if !fi.IsDir() {
|
||||
return nil, fmt.Errorf("%s is not a dir", dir)
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,15 @@ func init() {
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
}
|
||||
|
||||
func LogToFile(path string) {
|
||||
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logrus.SetOutput(file)
|
||||
}
|
||||
|
||||
func SetLogLevel(verbose, debug bool) {
|
||||
if verbose {
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
@ -8,6 +8,16 @@ import (
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
)
|
||||
|
||||
// We are supporting only those ecosystems for which we have data
|
||||
// for enrichment. More ecosystems will be supported as we improve
|
||||
// the capability of our Insights API
|
||||
var supportedEcosystems map[string]bool = map[string]bool{
|
||||
models.EcosystemGo: true,
|
||||
models.EcosystemMaven: true,
|
||||
models.EcosystemNpm: true,
|
||||
models.EcosystemPyPI: true,
|
||||
}
|
||||
|
||||
type Parser interface {
|
||||
Ecosystem() string
|
||||
Parse(lockfilePath string) (models.PackageManifest, error)
|
||||
@ -19,19 +29,38 @@ type parserWrapper struct {
|
||||
}
|
||||
|
||||
func List() []string {
|
||||
return lockfile.ListParsers()
|
||||
supportedParsers := make([]string, 0, 0)
|
||||
parsers := lockfile.ListParsers()
|
||||
|
||||
for _, p := range parsers {
|
||||
_, err := FindParser("", p)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
supportedParsers = append(supportedParsers, p)
|
||||
}
|
||||
|
||||
return supportedParsers
|
||||
}
|
||||
|
||||
func FindParser(lockfilePath, lockfileAs string) (Parser, error) {
|
||||
p, pa := lockfile.FindParser(lockfilePath, lockfileAs)
|
||||
if p != nil {
|
||||
return &parserWrapper{parser: p, parseAs: pa}, nil
|
||||
pw := &parserWrapper{parser: p, parseAs: pa}
|
||||
if pw.supported() {
|
||||
return pw, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("no parser found with: %s for: %s", lockfileAs,
|
||||
lockfilePath)
|
||||
}
|
||||
|
||||
func (pw *parserWrapper) supported() bool {
|
||||
return supportedEcosystems[pw.Ecosystem()]
|
||||
}
|
||||
|
||||
func (pw *parserWrapper) Ecosystem() string {
|
||||
switch pw.parseAs {
|
||||
case "Cargo.lock":
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
|
||||
func TestListParser(t *testing.T) {
|
||||
parsers := List()
|
||||
assert.Equal(t, 14, len(parsers))
|
||||
assert.Equal(t, 9, len(parsers))
|
||||
}
|
||||
|
||||
func TestInvalidEcosystemMapping(t *testing.T) {
|
||||
|
||||
6
pkg/policy/policy.go
Normal file
6
pkg/policy/policy.go
Normal file
@ -0,0 +1,6 @@
|
||||
package policy
|
||||
|
||||
type PolicyEvent struct {
|
||||
}
|
||||
|
||||
type PolicyEventHandler func(event *PolicyEvent) error
|
||||
121
pkg/reporter/console.go
Normal file
121
pkg/reporter/console.go
Normal file
@ -0,0 +1,121 @@
|
||||
package reporter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"github.com/jedib0t/go-pretty/v6/text"
|
||||
"github.com/safedep/dry/semver"
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/pkg/analyzer"
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
"github.com/safedep/vet/pkg/policy"
|
||||
)
|
||||
|
||||
type consoleReporter struct{}
|
||||
|
||||
func NewConsoleReporter() (Reporter, error) {
|
||||
return &consoleReporter{}, nil
|
||||
}
|
||||
|
||||
func (r *consoleReporter) Name() string {
|
||||
return "Console Report Generator"
|
||||
}
|
||||
|
||||
func (r *consoleReporter) AddManifest(manifest *models.PackageManifest) {
|
||||
tbl := table.NewWriter()
|
||||
tbl.SetOutputMirror(os.Stdout)
|
||||
tbl.SetStyle(table.StyleLight)
|
||||
|
||||
tbl.AppendHeader(table.Row{"Package", "Attribute", "Summary"})
|
||||
for _, pkg := range manifest.Packages {
|
||||
r.report(tbl, pkg)
|
||||
}
|
||||
|
||||
fmt.Print(text.Bold.Sprint("Manifest: ", text.FgBlue.Sprint(manifest.Path)))
|
||||
fmt.Print("\n")
|
||||
|
||||
tbl.Render()
|
||||
}
|
||||
|
||||
func (r *consoleReporter) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {
|
||||
}
|
||||
|
||||
func (r *consoleReporter) AddPolicyEvent(event *policy.PolicyEvent) {
|
||||
}
|
||||
|
||||
func (r *consoleReporter) Finish() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *consoleReporter) report(tbl table.Writer, pkg *models.Package) {
|
||||
insight := utils.SafelyGetValue(pkg.Insights)
|
||||
|
||||
headerAppended := false
|
||||
headerAppender := func() {
|
||||
if headerAppended {
|
||||
return
|
||||
}
|
||||
|
||||
// Header for this package
|
||||
tbl.AppendRow(table.Row{
|
||||
fmt.Sprintf("%s/%s", pkg.PackageDetails.Name, pkg.PackageDetails.Version),
|
||||
"", "",
|
||||
})
|
||||
|
||||
headerAppended = true
|
||||
}
|
||||
|
||||
// Report vulnerabilities
|
||||
sm := map[string]int{"CRITICAL": 0, "HIGH": 0}
|
||||
for _, vuln := range utils.SafelyGetValue(insight.Vulnerabilities) {
|
||||
for _, s := range utils.SafelyGetValue(vuln.Severities) {
|
||||
risk := string(utils.SafelyGetValue(s.Risk))
|
||||
if (risk == "CRITICAL") || (risk == "HIGH") {
|
||||
sm[risk] += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sm["CRITICAL"] > 0) || (sm["HIGH"] > 0) {
|
||||
headerAppender()
|
||||
tbl.AppendRow(table.Row{"",
|
||||
text.Bold.Sprint(text.BgRed.Sprint("Vulnerability")),
|
||||
fmt.Sprintf("Critical:%d High:%d",
|
||||
sm["CRITICAL"], sm["HIGH"])})
|
||||
}
|
||||
|
||||
// Popularity
|
||||
projects := utils.SafelyGetValue(insight.Projects)
|
||||
if len(projects) > 0 {
|
||||
p := projects[0]
|
||||
|
||||
sc := utils.SafelyGetValue(p.Stars)
|
||||
ic := utils.SafelyGetValue(p.Issues)
|
||||
|
||||
if (sc > 0) && (sc < 10) && (ic > 0) && (ic < 5) {
|
||||
headerAppender()
|
||||
tbl.AppendRow(table.Row{"",
|
||||
text.Bold.Sprint("Low Popularity"),
|
||||
fmt.Sprintf("Stars:%d Issues:%d", sc, ic)})
|
||||
}
|
||||
}
|
||||
|
||||
// High version drift
|
||||
version := pkg.PackageDetails.Version
|
||||
latestVersion := utils.SafelyGetValue(insight.PackageCurrentVersion)
|
||||
|
||||
driftType, _ := semver.Diff(version, latestVersion)
|
||||
if driftType.IsMajor() {
|
||||
headerAppender()
|
||||
tbl.AppendRow(table.Row{"",
|
||||
text.Bold.Sprint("Version Drift"),
|
||||
fmt.Sprintf("%s > %s", version, latestVersion),
|
||||
})
|
||||
}
|
||||
|
||||
if headerAppended {
|
||||
tbl.AppendSeparator()
|
||||
}
|
||||
}
|
||||
83
pkg/reporter/markdown.go
Normal file
83
pkg/reporter/markdown.go
Normal file
@ -0,0 +1,83 @@
|
||||
package reporter
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
"text/template"
|
||||
|
||||
"github.com/safedep/vet/pkg/analyzer"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
"github.com/safedep/vet/pkg/policy"
|
||||
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed markdown.template.md
|
||||
var markdownTemplate string
|
||||
|
||||
type MarkdownReportingConfig struct {
|
||||
Path string
|
||||
}
|
||||
|
||||
type markdownTemplateInput struct {
|
||||
Manifests []*models.PackageManifest
|
||||
AnalyzerEvents []*analyzer.AnalyzerEvent
|
||||
PolicyEvents []*policy.PolicyEvent
|
||||
}
|
||||
|
||||
type markdownReportGenerator struct {
|
||||
m sync.Mutex
|
||||
config MarkdownReportingConfig
|
||||
templateInput markdownTemplateInput
|
||||
}
|
||||
|
||||
func NewMarkdownReportGenerator(config MarkdownReportingConfig) (Reporter, error) {
|
||||
return &markdownReportGenerator{
|
||||
config: config,
|
||||
templateInput: markdownTemplateInput{
|
||||
Manifests: make([]*models.PackageManifest, 0),
|
||||
AnalyzerEvents: make([]*analyzer.AnalyzerEvent, 0),
|
||||
PolicyEvents: make([]*policy.PolicyEvent, 0),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *markdownReportGenerator) Name() string {
|
||||
return "Markdown Report Generator"
|
||||
}
|
||||
|
||||
func (r *markdownReportGenerator) AddManifest(manifest *models.PackageManifest) {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
r.templateInput.Manifests = append(r.templateInput.Manifests, manifest)
|
||||
}
|
||||
|
||||
func (r *markdownReportGenerator) AddAnalyzerEvent(event *analyzer.AnalyzerEvent) {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
r.templateInput.AnalyzerEvents = append(r.templateInput.AnalyzerEvents, event)
|
||||
}
|
||||
|
||||
func (r *markdownReportGenerator) AddPolicyEvent(event *policy.PolicyEvent) {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
r.templateInput.PolicyEvents = append(r.templateInput.PolicyEvents, event)
|
||||
}
|
||||
|
||||
func (r *markdownReportGenerator) Finish() error {
|
||||
logger.Infof("Generating consolidated markdown report: %s", r.config.Path)
|
||||
|
||||
tmpl, err := template.New("markdown").Parse(markdownTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Create(r.config.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
return tmpl.Execute(file, r.templateInput)
|
||||
}
|
||||
30
pkg/reporter/markdown.template.md
Normal file
30
pkg/reporter/markdown.template.md
Normal file
@ -0,0 +1,30 @@
|
||||
# Vet Report
|
||||
|
||||
## Summary
|
||||
|
||||
* {{ len .Manifests }} manifest(s) were scanned
|
||||
* {{ len .AnalyzerEvents }} analyzer event(s) were generated
|
||||
* {{ len .PolicyEvents }} policy violation(s) were observed
|
||||
|
||||
## Details
|
||||
|
||||
The scan was performed on following manifests:
|
||||
{{ range $m := .Manifests }}
|
||||
* [{{ $m.Ecosystem }}] {{ $m.Path }}
|
||||
{{ end }}
|
||||
|
||||
## Packages
|
||||
|
||||
{{ range $m := .Manifests }}
|
||||
### [{{ $m.Ecosystem }}] {{ $m.Path }}
|
||||
{{ range $p := $m.Packages }}
|
||||
#### {{ $p.PackageDetails.Name }} / {{ $p.PackageDetails.Version }}
|
||||
|
||||
{{ if and $p.Insights $p.Insights.Vulnerabilities }}
|
||||
* {{ len *$p.Insights.Vulnerabilites }} vulnerabilities were identified
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
19
pkg/reporter/reporter.go
Normal file
19
pkg/reporter/reporter.go
Normal file
@ -0,0 +1,19 @@
|
||||
package reporter
|
||||
|
||||
import (
|
||||
"github.com/safedep/vet/pkg/analyzer"
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
"github.com/safedep/vet/pkg/policy"
|
||||
)
|
||||
|
||||
type Reporter interface {
|
||||
Name() string
|
||||
|
||||
// Feed collected data to reporting module
|
||||
AddManifest(manifest *models.PackageManifest)
|
||||
AddAnalyzerEvent(event *analyzer.AnalyzerEvent)
|
||||
AddPolicyEvent(event *policy.PolicyEvent)
|
||||
|
||||
// Inform reporting module to finalise (e.g. write report to file)
|
||||
Finish() error
|
||||
}
|
||||
@ -6,6 +6,8 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/safedep/dry/errors"
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/gen/insightapi"
|
||||
"github.com/safedep/vet/internal/auth"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
@ -62,15 +64,16 @@ func (e *insightsBasedPackageEnricher) Enrich(pkg *models.Package,
|
||||
}
|
||||
|
||||
if res.HTTPResponse.StatusCode != 200 {
|
||||
return fmt.Errorf("bad response: %d: %s", res.HTTPResponse.StatusCode,
|
||||
res.HTTPResponse.Status)
|
||||
err, _ = errors.UnmarshalApiError(res.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
if (res.JSON200 == nil) || (res.JSON200.Dependencies == nil) {
|
||||
return fmt.Errorf("unexpected nil response from Insight API")
|
||||
if res.JSON200 == nil {
|
||||
return fmt.Errorf("unexpected nil response for: %s/%s/%s",
|
||||
pkg.Manifest.Ecosystem, pkg.PackageDetails.Name, pkg.Insights.PackageVersion.Version)
|
||||
}
|
||||
|
||||
for _, dep := range *res.JSON200.Dependencies {
|
||||
for _, dep := range utils.SafelyGetValue(res.JSON200.Dependencies) {
|
||||
if strings.EqualFold(dep.PackageVersion.Name, pkg.PackageDetails.Name) {
|
||||
// Skip self references in dependency
|
||||
continue
|
||||
@ -85,7 +88,7 @@ func (e *insightsBasedPackageEnricher) Enrich(pkg *models.Package,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to invoke package dependency callback: %v", err)
|
||||
logger.Errorf("package dependency callback failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
43
pkg/scanner/load.go
Normal file
43
pkg/scanner/load.go
Normal file
@ -0,0 +1,43 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
)
|
||||
|
||||
func scanDumpFilesForManifest(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() {
|
||||
return nil
|
||||
}
|
||||
|
||||
path, err = filepath.Abs(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var manifest models.PackageManifest
|
||||
err = json.Unmarshal(data, &manifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
manifests = append(manifests, &manifest)
|
||||
return nil
|
||||
})
|
||||
|
||||
return manifests, err
|
||||
}
|
||||
@ -5,6 +5,7 @@ import (
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
"github.com/safedep/vet/pkg/common/utils"
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
"github.com/safedep/vet/pkg/reporter"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@ -17,15 +18,18 @@ type packageManifestScanner struct {
|
||||
config Config
|
||||
enrichers []PackageMetaEnricher
|
||||
analyzers []analyzer.Analyzer
|
||||
reporters []reporter.Reporter
|
||||
}
|
||||
|
||||
func NewPackageManifestScanner(config Config,
|
||||
enrichers []PackageMetaEnricher,
|
||||
analyzers []analyzer.Analyzer) *packageManifestScanner {
|
||||
analyzers []analyzer.Analyzer,
|
||||
reporters []reporter.Reporter) *packageManifestScanner {
|
||||
return &packageManifestScanner{
|
||||
config: config,
|
||||
enrichers: enrichers,
|
||||
analyzers: analyzers,
|
||||
reporters: reporters,
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +39,6 @@ func (s *packageManifestScanner) ScanDirectory(dir string) error {
|
||||
|
||||
manifests, err := scanDirectoryForManifests(dir)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to scan directory: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -51,7 +54,6 @@ func (s *packageManifestScanner) ScanLockfiles(lockfiles []string,
|
||||
|
||||
manifests, err := scanLockfilesForManifests(lockfiles, lockfileAs)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to scan lockfiles: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@ -59,6 +61,19 @@ func (s *packageManifestScanner) ScanLockfiles(lockfiles []string,
|
||||
return s.analyzeManifests(manifests)
|
||||
}
|
||||
|
||||
// Load the manifests from a previous dumped JSON file
|
||||
func (s *packageManifestScanner) ScanDumpDirectory(dir string) error {
|
||||
logger.Infof("Scan dump files to load as manifests: %s", dir)
|
||||
|
||||
manifests, err := scanDumpFilesForManifest(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Infof("Loaded %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,
|
||||
@ -72,18 +87,28 @@ func (s *packageManifestScanner) analyzeManifests(manifests []*models.PackageMan
|
||||
|
||||
err = s.analyzeManifest(manifest)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to analyze %s manifest %v : %v",
|
||||
logger.Errorf("Failed to analyze %s manifest %s : %v",
|
||||
manifest.Ecosystem, manifest.Path, err)
|
||||
}
|
||||
|
||||
err = s.reportManifest(manifest)
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to report %s manifest %s : %v",
|
||||
manifest.Ecosystem, manifest.Path, err)
|
||||
}
|
||||
}
|
||||
|
||||
s.finishReporting()
|
||||
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
|
||||
for _, r := range s.reporters {
|
||||
r.AddAnalyzerEvent(event)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@ -94,7 +119,28 @@ func (s *packageManifestScanner) analyzeManifest(manifest *models.PackageManifes
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *packageManifestScanner) reportManifest(manifest *models.PackageManifest) error {
|
||||
for _, r := range s.reporters {
|
||||
r.AddManifest(manifest)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *packageManifestScanner) finishReporting() {
|
||||
for _, r := range s.reporters {
|
||||
err := r.Finish()
|
||||
if err != nil {
|
||||
logger.Errorf("Reporter: %s failed with %v", r.Name(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *packageManifestScanner) enrichManifest(manifest *models.PackageManifest) error {
|
||||
if len(s.enrichers) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
72
query.go
Normal file
72
query.go
Normal file
@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/pkg/analyzer"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
"github.com/safedep/vet/pkg/reporter"
|
||||
"github.com/safedep/vet/pkg/scanner"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// We will re-use the variable declarations in scan.go
|
||||
// since query.go is a subset of scan function where
|
||||
// data is loaded from JSON instead of lockfiles and enriched
|
||||
// with backend
|
||||
|
||||
func newQueryCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "query",
|
||||
Short: "Query JSON dump and run filters or render reports",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
startQuery()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&dumpJsonManifestDir, "from", "F", "",
|
||||
"The directory to load JSON dump files")
|
||||
cmd.Flags().StringVarP(&celFilterExpression, "filter", "", "",
|
||||
"Filter and print packages using CEL")
|
||||
cmd.Flags().BoolVarP(&consoleReport, "report-console", "", false,
|
||||
"Minimal summary of package manifest")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func startQuery() {
|
||||
err := internalStartQuery()
|
||||
if err != nil {
|
||||
logger.Errorf("Query completed with error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func internalStartQuery() error {
|
||||
analyzers := []analyzer.Analyzer{}
|
||||
reporters := []reporter.Reporter{}
|
||||
enrichers := []scanner.PackageMetaEnricher{}
|
||||
|
||||
if !utils.IsEmptyString(celFilterExpression) {
|
||||
task, err := analyzer.NewCelFilterAnalyzer(celFilterExpression)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
analyzers = append(analyzers, task)
|
||||
}
|
||||
|
||||
if consoleReport {
|
||||
rp, err := reporter.NewConsoleReporter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reporters = append(reporters, rp)
|
||||
}
|
||||
|
||||
pmScanner := scanner.NewPackageManifestScanner(scanner.Config{
|
||||
TransitiveAnalysis: false,
|
||||
}, enrichers, analyzers, reporters)
|
||||
|
||||
return pmScanner.ScanDumpDirectory(dumpJsonManifestDir)
|
||||
}
|
||||
48
scan.go
48
scan.go
@ -4,9 +4,11 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/pkg/analyzer"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
"github.com/safedep/vet/pkg/parser"
|
||||
"github.com/safedep/vet/pkg/reporter"
|
||||
"github.com/safedep/vet/pkg/scanner"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@ -18,9 +20,10 @@ var (
|
||||
transitiveAnalysis bool
|
||||
transitiveDepth int
|
||||
concurrency int
|
||||
dumpJsonManifest bool
|
||||
dumpJsonManifestDir string
|
||||
celFilterExpression string
|
||||
markdownReportPath string
|
||||
consoleReport bool
|
||||
)
|
||||
|
||||
func newScanCommand() *cobra.Command {
|
||||
@ -44,18 +47,20 @@ func newScanCommand() *cobra.Command {
|
||||
"List of lockfiles to scan")
|
||||
cmd.Flags().StringVarP(&lockfileAs, "lockfile-as", "", "",
|
||||
"Parser to use for the lockfile (vet scan parsers to list)")
|
||||
cmd.Flags().BoolVarP(&transitiveAnalysis, "transitive", "", true,
|
||||
cmd.Flags().BoolVarP(&transitiveAnalysis, "transitive", "", false,
|
||||
"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().IntVarP(&concurrency, "concurrency", "C", 5,
|
||||
"Number of concurrent analysis to run")
|
||||
cmd.Flags().StringVarP(&dumpJsonManifestDir, "json-dump-dir", "", "",
|
||||
"Dump dir for enriched JSON docs")
|
||||
cmd.Flags().StringVarP(&celFilterExpression, "filter-cel", "", "",
|
||||
"Dump enriched package manifests as JSON files to dir")
|
||||
cmd.Flags().StringVarP(&celFilterExpression, "filter", "", "",
|
||||
"Filter and print packages using CEL")
|
||||
cmd.Flags().StringVarP(&markdownReportPath, "report-markdown", "", "",
|
||||
"Generate consolidated markdown report to file")
|
||||
cmd.Flags().BoolVarP(&consoleReport, "report-console", "", true,
|
||||
"Minimal summary of package manifest")
|
||||
|
||||
cmd.AddCommand(listParsersCommand())
|
||||
return cmd
|
||||
@ -87,7 +92,7 @@ func startScan() {
|
||||
|
||||
func internalStartScan() error {
|
||||
analyzers := []analyzer.Analyzer{}
|
||||
if dumpJsonManifest {
|
||||
if !utils.IsEmptyString(dumpJsonManifestDir) {
|
||||
task, err := analyzer.NewJsonDumperAnalyzer(dumpJsonManifestDir)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -96,7 +101,7 @@ func internalStartScan() error {
|
||||
analyzers = append(analyzers, task)
|
||||
}
|
||||
|
||||
if len(celFilterExpression) > 0 {
|
||||
if !utils.IsEmptyString(celFilterExpression) {
|
||||
task, err := analyzer.NewCelFilterAnalyzer(celFilterExpression)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -105,6 +110,27 @@ func internalStartScan() error {
|
||||
analyzers = append(analyzers, task)
|
||||
}
|
||||
|
||||
reporters := []reporter.Reporter{}
|
||||
if consoleReport {
|
||||
rp, err := reporter.NewConsoleReporter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reporters = append(reporters, rp)
|
||||
}
|
||||
|
||||
if !utils.IsEmptyString(markdownReportPath) {
|
||||
rp, err := reporter.NewMarkdownReportGenerator(reporter.MarkdownReportingConfig{
|
||||
Path: markdownReportPath,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reporters = append(reporters, rp)
|
||||
}
|
||||
|
||||
enrichers := []scanner.PackageMetaEnricher{
|
||||
scanner.NewInsightBasedPackageEnricher(),
|
||||
}
|
||||
@ -113,7 +139,7 @@ func internalStartScan() error {
|
||||
TransitiveAnalysis: transitiveAnalysis,
|
||||
TransitiveDepth: transitiveDepth,
|
||||
ConcurrentAnalyzer: concurrency,
|
||||
}, enrichers, analyzers)
|
||||
}, enrichers, analyzers, reporters)
|
||||
|
||||
var err error
|
||||
if len(lockfiles) > 0 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user