mirror of
https://github.com/safedep/vet.git
synced 2025-12-11 17:44:20 -06:00
Merge pull request #30 from safedep/develop
#7: Add support for auth verify command
This commit is contained in:
commit
ab3d7e9f34
9
Makefile
9
Makefile
@ -13,8 +13,10 @@ protoc-install:
|
|||||||
oapi-codegen:
|
oapi-codegen:
|
||||||
oapi-codegen -package insightapi -generate types ./api/insights-v1.yml > ./gen/insightapi/insights.types.go
|
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 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 cpv1trials -generate types ./api/cp-v1-trials.yml > ./gen/cpv1trials/trials.types.go
|
||||||
oapi-codegen -package controlplane -generate client ./api/cp-v1-trials.yml > ./gen/controlplane/trials.client.go
|
oapi-codegen -package cpv1trials -generate client ./api/cp-v1-trials.yml > ./gen/cpv1trials/trials.client.go
|
||||||
|
oapi-codegen -package cpv1 -generate types ./api/cp-v1.yml > ./gen/cpv1/cp.types.go
|
||||||
|
oapi-codegen -package cpv1 -generate client ./api/cp-v1.yml > ./gen/cpv1/cp.client.go
|
||||||
|
|
||||||
protoc-codegen:
|
protoc-codegen:
|
||||||
protoc -I ./api \
|
protoc -I ./api \
|
||||||
@ -33,7 +35,8 @@ protoc-codegen:
|
|||||||
setup:
|
setup:
|
||||||
mkdir -p out \
|
mkdir -p out \
|
||||||
gen/insightapi \
|
gen/insightapi \
|
||||||
gen/controlplane \
|
gen/cpv1trials \
|
||||||
|
gen/cpv1 \
|
||||||
gen/filterinput \
|
gen/filterinput \
|
||||||
gen/filtersuite \
|
gen/filtersuite \
|
||||||
gen/exceptionsapi
|
gen/exceptionsapi
|
||||||
|
|||||||
11
README.md
11
README.md
@ -55,9 +55,16 @@ vet auth configure
|
|||||||
```
|
```
|
||||||
|
|
||||||
> Insights API is used to enrich OSS packages with meta-data for rich query and policy
|
> Insights API is used to enrich OSS packages with meta-data for rich query and policy
|
||||||
> decisions
|
> decisions. Alternatively, the API key can be passed through environment
|
||||||
|
> variable `VET_API_KEY`
|
||||||
|
|
||||||
Run `vet` to identify risks
|
Verify authentication token is valid
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vet auth verify
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `vet` to identify risks in a source repository
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
vet scan -D /path/to/repository
|
vet scan -D /path/to/repository
|
||||||
|
|||||||
113
api/cp-v1.yml
Normal file
113
api/cp-v1.yml
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
openapi: 3.0.2
|
||||||
|
info:
|
||||||
|
title: SafeDep Control Plane API
|
||||||
|
contact:
|
||||||
|
name: SafeDep API
|
||||||
|
url: 'https://safedep.io'
|
||||||
|
description: |
|
||||||
|
The SafeDep Control Plane API provides configuration and management plane
|
||||||
|
access to clients for the SafeDep platform
|
||||||
|
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:
|
||||||
|
/auths/me:
|
||||||
|
get:
|
||||||
|
description: |
|
||||||
|
Introspection API for getting configuration information associated
|
||||||
|
with the supplied API credentials
|
||||||
|
operationId: getApiCredentialIntrospection
|
||||||
|
tags:
|
||||||
|
- Control Plane
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: API credentials introspection information
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/CredentialIntrospectionResponse'
|
||||||
|
'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:
|
||||||
|
securitySchemes:
|
||||||
|
api_key:
|
||||||
|
type: apiKey
|
||||||
|
name: Authorization
|
||||||
|
in: header
|
||||||
|
schemas:
|
||||||
|
ApiError:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
description: A descriptive message about the error meant for developer consumption
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: An optional service or domain specific error group
|
||||||
|
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
|
||||||
|
CredentialIntrospectionResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
description: The entity type to which this credential belongs to
|
||||||
|
enum:
|
||||||
|
- TrialUser
|
||||||
|
- Organization
|
||||||
|
- Team
|
||||||
|
- User
|
||||||
|
expiry:
|
||||||
|
type: string
|
||||||
|
description: Expiry timestamp in RFC3399 format if expirable
|
||||||
|
required:
|
||||||
|
- type
|
||||||
14
auth.go
14
auth.go
@ -10,6 +10,7 @@ import (
|
|||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
|
||||||
"github.com/safedep/vet/internal/auth"
|
"github.com/safedep/vet/internal/auth"
|
||||||
|
"github.com/safedep/vet/internal/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -27,6 +28,9 @@ func newAuthCommand() *cobra.Command {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd.PersistentFlags().StringVarP(&authControlPlaneApiBaseUrl, "control-plane", "",
|
||||||
|
auth.DefaultControlPlaneApiUrl(), "Base URL of Control Plane API")
|
||||||
|
|
||||||
cmd.AddCommand(configureAuthCommand())
|
cmd.AddCommand(configureAuthCommand())
|
||||||
cmd.AddCommand(verifyAuthCommand())
|
cmd.AddCommand(verifyAuthCommand())
|
||||||
cmd.AddCommand(trialsRegisterCommand())
|
cmd.AddCommand(trialsRegisterCommand())
|
||||||
@ -47,6 +51,7 @@ func configureAuthCommand() *cobra.Command {
|
|||||||
err = auth.Configure(auth.Config{
|
err = auth.Configure(auth.Config{
|
||||||
ApiUrl: authInsightApiBaseUrl,
|
ApiUrl: authInsightApiBaseUrl,
|
||||||
ApiKey: string(key),
|
ApiKey: string(key),
|
||||||
|
ControlPlaneApiUrl: authControlPlaneApiBaseUrl,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -69,8 +74,11 @@ func verifyAuthCommand() *cobra.Command {
|
|||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "verify",
|
Use: "verify",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
fmt.Printf("Verify auth command is currently work in progress\n")
|
failOnError("auth/verify", auth.Verify(&auth.VerifyConfig{
|
||||||
os.Exit(1)
|
ControlPlaneApiUrl: authControlPlaneApiBaseUrl,
|
||||||
|
}))
|
||||||
|
|
||||||
|
ui.PrintSuccess("Authentication key is valid!")
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -103,8 +111,6 @@ func trialsRegisterCommand() *cobra.Command {
|
|||||||
|
|
||||||
cmd.Flags().StringVarP(&authTrialEmail, "email", "", "",
|
cmd.Flags().StringVarP(&authTrialEmail, "email", "", "",
|
||||||
"Email address to use for sending trial API key")
|
"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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
258
gen/cpv1/cp.client.go
Normal file
258
gen/cpv1/cp.client.go
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
// Package cpv1 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 cpv1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"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 {
|
||||||
|
// GetApiCredentialIntrospection request
|
||||||
|
GetApiCredentialIntrospection(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetApiCredentialIntrospection(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||||
|
req, err := NewGetApiCredentialIntrospectionRequest(c.Server)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req = req.WithContext(ctx)
|
||||||
|
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.Client.Do(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGetApiCredentialIntrospectionRequest generates requests for GetApiCredentialIntrospection
|
||||||
|
func NewGetApiCredentialIntrospectionRequest(server string) (*http.Request, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
serverURL, err := url.Parse(server)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
operationPath := fmt.Sprintf("/auths/me")
|
||||||
|
if operationPath[0] == '/' {
|
||||||
|
operationPath = "." + operationPath
|
||||||
|
}
|
||||||
|
|
||||||
|
queryURL, err := serverURL.Parse(operationPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", queryURL.String(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
|
||||||
|
for _, r := range c.RequestEditors {
|
||||||
|
if err := r(ctx, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, r := range additionalEditors {
|
||||||
|
if err := r(ctx, req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientWithResponses builds on ClientInterface to offer response payloads
|
||||||
|
type ClientWithResponses struct {
|
||||||
|
ClientInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientWithResponses creates a new ClientWithResponses, which wraps
|
||||||
|
// Client with return type handling
|
||||||
|
func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
|
||||||
|
client, err := NewClient(server, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ClientWithResponses{client}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithBaseURL overrides the baseURL.
|
||||||
|
func WithBaseURL(baseURL string) ClientOption {
|
||||||
|
return func(c *Client) error {
|
||||||
|
newBaseURL, err := url.Parse(baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Server = newBaseURL.String()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientWithResponsesInterface is the interface specification for the client with responses above.
|
||||||
|
type ClientWithResponsesInterface interface {
|
||||||
|
// GetApiCredentialIntrospection request
|
||||||
|
GetApiCredentialIntrospectionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetApiCredentialIntrospectionResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetApiCredentialIntrospectionResponse struct {
|
||||||
|
Body []byte
|
||||||
|
HTTPResponse *http.Response
|
||||||
|
JSON200 *CredentialIntrospectionResponse
|
||||||
|
JSON403 *ApiError
|
||||||
|
JSON429 *ApiError
|
||||||
|
JSON500 *ApiError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status returns HTTPResponse.Status
|
||||||
|
func (r GetApiCredentialIntrospectionResponse) Status() string {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.Status
|
||||||
|
}
|
||||||
|
return http.StatusText(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StatusCode returns HTTPResponse.StatusCode
|
||||||
|
func (r GetApiCredentialIntrospectionResponse) StatusCode() int {
|
||||||
|
if r.HTTPResponse != nil {
|
||||||
|
return r.HTTPResponse.StatusCode
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetApiCredentialIntrospectionWithResponse request returning *GetApiCredentialIntrospectionResponse
|
||||||
|
func (c *ClientWithResponses) GetApiCredentialIntrospectionWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetApiCredentialIntrospectionResponse, error) {
|
||||||
|
rsp, err := c.GetApiCredentialIntrospection(ctx, reqEditors...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ParseGetApiCredentialIntrospectionResponse(rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseGetApiCredentialIntrospectionResponse parses an HTTP response from a GetApiCredentialIntrospectionWithResponse call
|
||||||
|
func ParseGetApiCredentialIntrospectionResponse(rsp *http.Response) (*GetApiCredentialIntrospectionResponse, error) {
|
||||||
|
bodyBytes, err := ioutil.ReadAll(rsp.Body)
|
||||||
|
defer func() { _ = rsp.Body.Close() }()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &GetApiCredentialIntrospectionResponse{
|
||||||
|
Body: bodyBytes,
|
||||||
|
HTTPResponse: rsp,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
|
||||||
|
var dest CredentialIntrospectionResponse
|
||||||
|
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
response.JSON200 = &dest
|
||||||
|
|
||||||
|
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 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/cpv1/cp.types.go
Normal file
159
gen/cpv1/cp.types.go
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// Package cpv1 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 cpv1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines values for CredentialIntrospectionResponseType.
|
||||||
|
const (
|
||||||
|
CredentialIntrospectionResponseTypeOrganization CredentialIntrospectionResponseType = "Organization"
|
||||||
|
|
||||||
|
CredentialIntrospectionResponseTypeTeam CredentialIntrospectionResponseType = "Team"
|
||||||
|
|
||||||
|
CredentialIntrospectionResponseTypeTrialUser CredentialIntrospectionResponseType = "TrialUser"
|
||||||
|
|
||||||
|
CredentialIntrospectionResponseTypeUser CredentialIntrospectionResponseType = "User"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// CredentialIntrospectionResponse defines model for CredentialIntrospectionResponse.
|
||||||
|
type CredentialIntrospectionResponse struct {
|
||||||
|
// Expiry timestamp in RFC3399 format if expirable
|
||||||
|
Expiry *string `json:"expiry,omitempty"`
|
||||||
|
|
||||||
|
// The entity type to which this credential belongs to
|
||||||
|
Type CredentialIntrospectionResponseType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// The entity type to which this credential belongs to
|
||||||
|
type CredentialIntrospectionResponseType string
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
// Package controlplane provides primitives to interact with the openapi HTTP API.
|
// Package cpv1trials provides primitives to interact with the openapi HTTP API.
|
||||||
//
|
//
|
||||||
// Code generated by github.com/deepmap/oapi-codegen version v1.10.1 DO NOT EDIT.
|
// Code generated by github.com/deepmap/oapi-codegen version v1.10.1 DO NOT EDIT.
|
||||||
package controlplane
|
package cpv1trials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -1,7 +1,7 @@
|
|||||||
// Package controlplane provides primitives to interact with the openapi HTTP API.
|
// Package cpv1trials provides primitives to interact with the openapi HTTP API.
|
||||||
//
|
//
|
||||||
// Code generated by github.com/deepmap/oapi-codegen version v1.10.1 DO NOT EDIT.
|
// Code generated by github.com/deepmap/oapi-codegen version v1.10.1 DO NOT EDIT.
|
||||||
package controlplane
|
package cpv1trials
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -12,6 +12,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
apiUrlEnvKey = "VET_INSIGHTS_API_URL"
|
apiUrlEnvKey = "VET_INSIGHTS_API_URL"
|
||||||
apiKeyEnvKey = "VET_INSIGHTS_API_KEY"
|
apiKeyEnvKey = "VET_INSIGHTS_API_KEY"
|
||||||
|
apiKeyAlternateEnvKey = "VET_API_KEY"
|
||||||
|
|
||||||
defaultApiUrl = "https://api.safedep.io/insights/v1"
|
defaultApiUrl = "https://api.safedep.io/insights/v1"
|
||||||
defaultControlPlaneApiUrl = "https://api.safedep.io/control-plane/v1"
|
defaultControlPlaneApiUrl = "https://api.safedep.io/control-plane/v1"
|
||||||
@ -22,6 +23,7 @@ const (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
ApiUrl string `yaml:"api_url"`
|
ApiUrl string `yaml:"api_url"`
|
||||||
ApiKey string `yaml:"api_key"`
|
ApiKey string `yaml:"api_key"`
|
||||||
|
ControlPlaneApiUrl string `yaml:"cp_api_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global config to be used during runtime
|
// Global config to be used during runtime
|
||||||
@ -36,16 +38,15 @@ func Configure(m Config) error {
|
|||||||
return persistConfiguration()
|
return persistConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
func Verify() error {
|
|
||||||
// TODO: Verify by actually calling insight API
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultApiUrl() string {
|
func DefaultApiUrl() string {
|
||||||
return defaultApiUrl
|
return defaultApiUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultControlPlaneApiUrl() string {
|
func DefaultControlPlaneApiUrl() string {
|
||||||
|
if (globalConfig != nil) && (globalConfig.ControlPlaneApiUrl != "") {
|
||||||
|
return globalConfig.ControlPlaneApiUrl
|
||||||
|
}
|
||||||
|
|
||||||
return defaultControlPlaneApiUrl
|
return defaultControlPlaneApiUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +67,10 @@ func ApiKey() string {
|
|||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if key, ok := os.LookupEnv(apiKeyAlternateEnvKey); ok {
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
if globalConfig != nil {
|
if globalConfig != nil {
|
||||||
return globalConfig.ApiKey
|
return globalConfig.ApiKey
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/deepmap/oapi-codegen/pkg/types"
|
"github.com/deepmap/oapi-codegen/pkg/types"
|
||||||
"github.com/safedep/dry/utils"
|
"github.com/safedep/dry/utils"
|
||||||
"github.com/safedep/vet/gen/controlplane"
|
"github.com/safedep/vet/gen/cpv1trials"
|
||||||
"github.com/safedep/vet/pkg/common/logger"
|
"github.com/safedep/vet/pkg/common/logger"
|
||||||
|
|
||||||
apierr "github.com/safedep/dry/errors"
|
apierr "github.com/safedep/dry/errors"
|
||||||
@ -45,7 +45,7 @@ func (client *trialRegistrationClient) Execute() (*trialRegistrationResponse, er
|
|||||||
logger.Infof("Trial registrations using Control Plane: %s",
|
logger.Infof("Trial registrations using Control Plane: %s",
|
||||||
client.config.ControlPlaneApiUrl)
|
client.config.ControlPlaneApiUrl)
|
||||||
|
|
||||||
cpClient, err := controlplane.NewClientWithResponses(client.config.ControlPlaneApiUrl)
|
cpClient, err := cpv1trials.NewClientWithResponses(client.config.ControlPlaneApiUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -54,7 +54,7 @@ func (client *trialRegistrationClient) Execute() (*trialRegistrationResponse, er
|
|||||||
client.config.Email)
|
client.config.Email)
|
||||||
|
|
||||||
res, err := cpClient.RegisterTrialUserWithResponse(context.Background(),
|
res, err := cpClient.RegisterTrialUserWithResponse(context.Background(),
|
||||||
controlplane.RegisterTrialUserJSONRequestBody{
|
cpv1trials.RegisterTrialUserJSONRequestBody{
|
||||||
Email: types.Email(client.config.Email),
|
Email: types.Email(client.config.Email),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
57
internal/auth/verify.go
Normal file
57
internal/auth/verify.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
apierr "github.com/safedep/dry/errors"
|
||||||
|
"github.com/safedep/dry/utils"
|
||||||
|
"github.com/safedep/vet/gen/cpv1"
|
||||||
|
"github.com/safedep/vet/pkg/common/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VerifyConfig struct {
|
||||||
|
ControlPlaneApiUrl string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify function takes config and current API key available
|
||||||
|
// from this package and returns an error if auth is invalid
|
||||||
|
func Verify(config *VerifyConfig) error {
|
||||||
|
logger.Infof("Verifying auth token using Control Plane: %s", config.ControlPlaneApiUrl)
|
||||||
|
|
||||||
|
client, err := cpv1.NewClientWithResponses(config.ControlPlaneApiUrl)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
authKeyApplier := func(ctx context.Context, req *http.Request) error {
|
||||||
|
req.Header.Set("Authorization", ApiKey())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.GetApiCredentialIntrospectionWithResponse(context.Background(),
|
||||||
|
authKeyApplier)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode() != http.StatusOK {
|
||||||
|
if err, ok := apierr.UnmarshalApiError(resp.Body); ok {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("unexpected status code:%d from control plane",
|
||||||
|
resp.HTTPResponse.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.JSON200 == nil {
|
||||||
|
return fmt.Errorf("invalid nil response from server")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("Current auth token is valid with expiry: %s",
|
||||||
|
utils.SafelyGetValue(resp.JSON200.Expiry))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -11,6 +11,11 @@ func PrintBanner(s string) {
|
|||||||
fmt.Fprintf(os.Stderr, s)
|
fmt.Fprintf(os.Stderr, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PrintSuccess(s string, args ...any) {
|
||||||
|
msg := fmt.Sprintf(s, args...)
|
||||||
|
fmt.Fprint(os.Stderr, text.FgGreen.Sprint(msg), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
func PrintError(s string, args ...any) {
|
func PrintError(s string, args ...any) {
|
||||||
msg := fmt.Sprintf(s, args...)
|
msg := fmt.Sprintf(s, args...)
|
||||||
fmt.Fprint(os.Stderr, text.FgRed.Sprint(msg), "\n")
|
fmt.Fprint(os.Stderr, text.FgRed.Sprint(msg), "\n")
|
||||||
|
|||||||
10
scan.go
10
scan.go
@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/safedep/dry/utils"
|
"github.com/safedep/dry/utils"
|
||||||
|
"github.com/safedep/vet/internal/auth"
|
||||||
"github.com/safedep/vet/internal/ui"
|
"github.com/safedep/vet/internal/ui"
|
||||||
"github.com/safedep/vet/pkg/analyzer"
|
"github.com/safedep/vet/pkg/analyzer"
|
||||||
"github.com/safedep/vet/pkg/models"
|
"github.com/safedep/vet/pkg/models"
|
||||||
@ -29,6 +30,7 @@ var (
|
|||||||
consoleReport bool
|
consoleReport bool
|
||||||
summaryReport bool
|
summaryReport bool
|
||||||
silentScan bool
|
silentScan bool
|
||||||
|
disableAuthVerifyBeforeScan bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func newScanCommand() *cobra.Command {
|
func newScanCommand() *cobra.Command {
|
||||||
@ -68,6 +70,8 @@ func newScanCommand() *cobra.Command {
|
|||||||
"Filter packages using CEL Filter Suite from file")
|
"Filter packages using CEL Filter Suite from file")
|
||||||
cmd.Flags().BoolVarP(&celFilterFailOnMatch, "filter-fail", "", false,
|
cmd.Flags().BoolVarP(&celFilterFailOnMatch, "filter-fail", "", false,
|
||||||
"Fail the scan if the filter match any package (security gate)")
|
"Fail the scan if the filter match any package (security gate)")
|
||||||
|
cmd.Flags().BoolVarP(&disableAuthVerifyBeforeScan, "no-verify-auth", "", false,
|
||||||
|
"Do not verify auth token before starting scan")
|
||||||
cmd.Flags().StringVarP(&markdownReportPath, "report-markdown", "", "",
|
cmd.Flags().StringVarP(&markdownReportPath, "report-markdown", "", "",
|
||||||
"Generate consolidated markdown report to file")
|
"Generate consolidated markdown report to file")
|
||||||
cmd.Flags().BoolVarP(&consoleReport, "report-console", "", false,
|
cmd.Flags().BoolVarP(&consoleReport, "report-console", "", false,
|
||||||
@ -97,6 +101,12 @@ func listParsersCommand() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startScan() {
|
func startScan() {
|
||||||
|
if !disableAuthVerifyBeforeScan {
|
||||||
|
failOnError("auth/verify", auth.Verify(&auth.VerifyConfig{
|
||||||
|
ControlPlaneApiUrl: auth.DefaultControlPlaneApiUrl(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
failOnError("scan", internalStartScan())
|
failOnError("scan", internalStartScan())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user