mirror of
https://github.com/safedep/vet.git
synced 2025-12-10 00:22:08 -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 -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
|
||||
oapi-codegen -package cpv1trials -generate types ./api/cp-v1-trials.yml > ./gen/cpv1trials/trials.types.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 -I ./api \
|
||||
@ -33,7 +35,8 @@ protoc-codegen:
|
||||
setup:
|
||||
mkdir -p out \
|
||||
gen/insightapi \
|
||||
gen/controlplane \
|
||||
gen/cpv1trials \
|
||||
gen/cpv1 \
|
||||
gen/filterinput \
|
||||
gen/filtersuite \
|
||||
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
|
||||
> 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
|
||||
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
|
||||
18
auth.go
18
auth.go
@ -10,6 +10,7 @@ import (
|
||||
"golang.org/x/term"
|
||||
|
||||
"github.com/safedep/vet/internal/auth"
|
||||
"github.com/safedep/vet/internal/ui"
|
||||
)
|
||||
|
||||
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(verifyAuthCommand())
|
||||
cmd.AddCommand(trialsRegisterCommand())
|
||||
@ -45,8 +49,9 @@ func configureAuthCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
err = auth.Configure(auth.Config{
|
||||
ApiUrl: authInsightApiBaseUrl,
|
||||
ApiKey: string(key),
|
||||
ApiUrl: authInsightApiBaseUrl,
|
||||
ApiKey: string(key),
|
||||
ControlPlaneApiUrl: authControlPlaneApiBaseUrl,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@ -69,8 +74,11 @@ func verifyAuthCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "verify",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Printf("Verify auth command is currently work in progress\n")
|
||||
os.Exit(1)
|
||||
failOnError("auth/verify", auth.Verify(&auth.VerifyConfig{
|
||||
ControlPlaneApiUrl: authControlPlaneApiBaseUrl,
|
||||
}))
|
||||
|
||||
ui.PrintSuccess("Authentication key is valid!")
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@ -103,8 +111,6 @@ func trialsRegisterCommand() *cobra.Command {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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.
|
||||
package controlplane
|
||||
package cpv1trials
|
||||
|
||||
import (
|
||||
"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.
|
||||
package controlplane
|
||||
package cpv1trials
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -10,8 +10,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
apiUrlEnvKey = "VET_INSIGHTS_API_URL"
|
||||
apiKeyEnvKey = "VET_INSIGHTS_API_KEY"
|
||||
apiUrlEnvKey = "VET_INSIGHTS_API_URL"
|
||||
apiKeyEnvKey = "VET_INSIGHTS_API_KEY"
|
||||
apiKeyAlternateEnvKey = "VET_API_KEY"
|
||||
|
||||
defaultApiUrl = "https://api.safedep.io/insights/v1"
|
||||
defaultControlPlaneApiUrl = "https://api.safedep.io/control-plane/v1"
|
||||
@ -20,8 +21,9 @@ const (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ApiUrl string `yaml:"api_url"`
|
||||
ApiKey string `yaml:"api_key"`
|
||||
ApiUrl string `yaml:"api_url"`
|
||||
ApiKey string `yaml:"api_key"`
|
||||
ControlPlaneApiUrl string `yaml:"cp_api_url"`
|
||||
}
|
||||
|
||||
// Global config to be used during runtime
|
||||
@ -36,16 +38,15 @@ func Configure(m Config) error {
|
||||
return persistConfiguration()
|
||||
}
|
||||
|
||||
func Verify() error {
|
||||
// TODO: Verify by actually calling insight API
|
||||
return nil
|
||||
}
|
||||
|
||||
func DefaultApiUrl() string {
|
||||
return defaultApiUrl
|
||||
}
|
||||
|
||||
func DefaultControlPlaneApiUrl() string {
|
||||
if (globalConfig != nil) && (globalConfig.ControlPlaneApiUrl != "") {
|
||||
return globalConfig.ControlPlaneApiUrl
|
||||
}
|
||||
|
||||
return defaultControlPlaneApiUrl
|
||||
}
|
||||
|
||||
@ -66,6 +67,10 @@ func ApiKey() string {
|
||||
return key
|
||||
}
|
||||
|
||||
if key, ok := os.LookupEnv(apiKeyAlternateEnvKey); ok {
|
||||
return key
|
||||
}
|
||||
|
||||
if globalConfig != nil {
|
||||
return globalConfig.ApiKey
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/types"
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/gen/controlplane"
|
||||
"github.com/safedep/vet/gen/cpv1trials"
|
||||
"github.com/safedep/vet/pkg/common/logger"
|
||||
|
||||
apierr "github.com/safedep/dry/errors"
|
||||
@ -45,7 +45,7 @@ func (client *trialRegistrationClient) Execute() (*trialRegistrationResponse, er
|
||||
logger.Infof("Trial registrations using Control Plane: %s",
|
||||
client.config.ControlPlaneApiUrl)
|
||||
|
||||
cpClient, err := controlplane.NewClientWithResponses(client.config.ControlPlaneApiUrl)
|
||||
cpClient, err := cpv1trials.NewClientWithResponses(client.config.ControlPlaneApiUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -54,7 +54,7 @@ func (client *trialRegistrationClient) Execute() (*trialRegistrationResponse, er
|
||||
client.config.Email)
|
||||
|
||||
res, err := cpClient.RegisterTrialUserWithResponse(context.Background(),
|
||||
controlplane.RegisterTrialUserJSONRequestBody{
|
||||
cpv1trials.RegisterTrialUserJSONRequestBody{
|
||||
Email: types.Email(client.config.Email),
|
||||
})
|
||||
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)
|
||||
}
|
||||
|
||||
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) {
|
||||
msg := fmt.Sprintf(s, args...)
|
||||
fmt.Fprint(os.Stderr, text.FgRed.Sprint(msg), "\n")
|
||||
|
||||
38
scan.go
38
scan.go
@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/safedep/dry/utils"
|
||||
"github.com/safedep/vet/internal/auth"
|
||||
"github.com/safedep/vet/internal/ui"
|
||||
"github.com/safedep/vet/pkg/analyzer"
|
||||
"github.com/safedep/vet/pkg/models"
|
||||
@ -15,20 +16,21 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
lockfiles []string
|
||||
lockfileAs string
|
||||
baseDirectory string
|
||||
transitiveAnalysis bool
|
||||
transitiveDepth int
|
||||
concurrency int
|
||||
dumpJsonManifestDir string
|
||||
celFilterExpression string
|
||||
celFilterSuiteFile string
|
||||
celFilterFailOnMatch bool
|
||||
markdownReportPath string
|
||||
consoleReport bool
|
||||
summaryReport bool
|
||||
silentScan bool
|
||||
lockfiles []string
|
||||
lockfileAs string
|
||||
baseDirectory string
|
||||
transitiveAnalysis bool
|
||||
transitiveDepth int
|
||||
concurrency int
|
||||
dumpJsonManifestDir string
|
||||
celFilterExpression string
|
||||
celFilterSuiteFile string
|
||||
celFilterFailOnMatch bool
|
||||
markdownReportPath string
|
||||
consoleReport bool
|
||||
summaryReport bool
|
||||
silentScan bool
|
||||
disableAuthVerifyBeforeScan bool
|
||||
)
|
||||
|
||||
func newScanCommand() *cobra.Command {
|
||||
@ -68,6 +70,8 @@ func newScanCommand() *cobra.Command {
|
||||
"Filter packages using CEL Filter Suite from file")
|
||||
cmd.Flags().BoolVarP(&celFilterFailOnMatch, "filter-fail", "", false,
|
||||
"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", "", "",
|
||||
"Generate consolidated markdown report to file")
|
||||
cmd.Flags().BoolVarP(&consoleReport, "report-console", "", false,
|
||||
@ -97,6 +101,12 @@ func listParsersCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
func startScan() {
|
||||
if !disableAuthVerifyBeforeScan {
|
||||
failOnError("auth/verify", auth.Verify(&auth.VerifyConfig{
|
||||
ControlPlaneApiUrl: auth.DefaultControlPlaneApiUrl(),
|
||||
}))
|
||||
}
|
||||
|
||||
failOnError("scan", internalStartScan())
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user