Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal: support scanning path #34

Merged
merged 4 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions internal/assettype/assettype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2023 Adevinta

// Package assettype defines a set of asset types that are valid in
// the context of Lava.
package assettype

import (
"slices"

types "github.com/adevinta/vulcan-types"
)

// Lava asset types.
const (
Path = types.AssetType("Path")
)

// vulcanMap is the mapping between Lava and Vulcan asset types.
var vulcanMap = map[types.AssetType]types.AssetType{
Path: types.GitRepository,
}

// lavaTypes is the list of all Lava asset types.
var lavaTypes = []types.AssetType{Path}

// IsValid reports whether the provided asset type is valid in the
// context of Lava.
func IsValid(at types.AssetType) bool {
return slices.Contains(lavaTypes, at)
}

// ToVulcan maps a Lava asset type to a Vulcan asset type. If there is
// no such mapping, the provided asset type is returned.
func ToVulcan(at types.AssetType) types.AssetType {
if vt, ok := vulcanMap[at]; ok {
return vt
}
return at
}
75 changes: 75 additions & 0 deletions internal/assettype/assettype_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2023 Adevinta

package assettype

import (
"testing"

types "github.com/adevinta/vulcan-types"
)

func TestIsValid(t *testing.T) {
tests := []struct {
name string
at types.AssetType
want bool
}{
{
name: "lava type",
at: Path,
want: true,
},
{
name: "vulcan type",
at: types.Hostname,
want: false,
},
{
name: "zero value",
at: types.AssetType(""),
want: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := IsValid(tt.at)
if got != tt.want {
t.Errorf("unexpected value: want: %v, got: %v", tt.want, got)
}
})
}
}

func TestToVulcan(t *testing.T) {
tests := []struct {
name string
at types.AssetType
want types.AssetType
}{
{
name: "lava type",
at: Path,
want: types.GitRepository,
},
{
name: "vulcan type",
at: types.Hostname,
want: types.Hostname,
},
{
name: "zero value",
at: types.AssetType(""),
want: types.AssetType(""),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ToVulcan(tt.at)
if got != tt.want {
t.Errorf("unexpected value: want: %v, got: %v", tt.want, got)
}
})
}
}
30 changes: 20 additions & 10 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (
types "github.com/adevinta/vulcan-types"
"golang.org/x/mod/semver"
"gopkg.in/yaml.v3"

"github.com/adevinta/lava/internal/assettype"
)

var (
Expand Down Expand Up @@ -91,7 +93,7 @@ func ParseFile(path string) (Config, error) {
}

// validate validates the Lava configuration.
func (c *Config) validate() error {
func (c Config) validate() error {
// Lava version validation.
if !semver.IsValid(c.LavaVersion) {
return ErrInvalidLavaVersion
Expand All @@ -101,15 +103,9 @@ func (c *Config) validate() error {
if len(c.Targets) == 0 {
return ErrNoTargets
}
for _, target := range c.Targets {
if target.Identifier == "" {
return ErrNoTargetIdentifier
}
if target.AssetType == "" {
return ErrNoTargetAssetType
}
if !target.AssetType.IsValid() {
return fmt.Errorf("%w: %v", ErrInvalidAssetType, target.AssetType)
for _, t := range c.Targets {
if err := t.validate(); err != nil {
return err
}
}
return nil
Expand Down Expand Up @@ -168,6 +164,20 @@ type Target struct {
Options map[string]any `yaml:"options"`
}

// validate reports whether the target is a valid configuration value.
func (t Target) validate() error {
if t.Identifier == "" {
return ErrNoTargetIdentifier
}
if t.AssetType == "" {
return ErrNoTargetAssetType
}
if !t.AssetType.IsValid() && !assettype.IsValid(t.AssetType) {
return fmt.Errorf("%w: %v", ErrInvalidAssetType, t.AssetType)
}
return nil
}

// RegistryAuth contains the credentials for a container registry.
type RegistryAuth struct {
// Server is the URL of the registry.
Expand Down
11 changes: 6 additions & 5 deletions internal/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,14 @@ func mkReport(rs *reportStore, srv *targetServer) (Report, error) {

tmAddrs := tm.Addrs()

slog.Info("applying target map", "check", checkID, "map", tm, "tmAddr", tmAddrs)
slog.Info("applying target map", "check", checkID, "tm", tm, "tmAddr", tmAddrs)

r.Target = tm.Old
r.Target = tm.OldIdentifier

var vulns []report.Vulnerability
for _, vuln := range r.Vulnerabilities {
vuln = vulnReplaceAll(vuln, tm.New, tm.Old)
vuln = vulnReplaceAll(vuln, tmAddrs.New, tmAddrs.Old)
vuln = vulnReplaceAll(vuln, tm.NewIdentifier, tm.OldIdentifier)
vuln = vulnReplaceAll(vuln, tmAddrs.NewIdentifier, tmAddrs.OldIdentifier)
vulns = append(vulns, vuln)
}
r.Vulnerabilities = vulns
Expand Down Expand Up @@ -323,7 +323,8 @@ func beforeRun(params backend.RunParams, rc *docker.RunConfig, srv *targetServer
}
if tm, err := srv.Handle(params.CheckID, target); err == nil {
if !tm.IsZero() {
rc.ContainerConfig.Env = setenv(rc.ContainerConfig.Env, "VULCAN_CHECK_TARGET", tm.New)
rc.ContainerConfig.Env = setenv(rc.ContainerConfig.Env, "VULCAN_CHECK_TARGET", tm.NewIdentifier)
rc.ContainerConfig.Env = setenv(rc.ContainerConfig.Env, "VULCAN_CHECK_ASSET_TYPE", string(tm.NewAssetType))
}
} else {
slog.Warn("could not handle target", "target", target, "err", err)
Expand Down
22 changes: 7 additions & 15 deletions internal/engine/jobs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,15 @@ import (
"github.com/adevinta/vulcan-agent/queue"
"github.com/google/uuid"

"github.com/adevinta/lava/internal/assettype"
"github.com/adevinta/lava/internal/checktype"
"github.com/adevinta/lava/internal/config"
)

// generateJobs generates the jobs to be sent to the agent.
func generateJobs(checktypes checktype.Catalog, targets []config.Target) ([]jobrunner.Job, error) {
checks, err := generateChecks(checktypes, targets)
if err != nil {
return nil, fmt.Errorf("generate checks: %w", err)
}

var jobs []jobrunner.Job
for _, check := range checks {
for _, check := range generateChecks(checktypes, targets) {
// Convert the options to a marshalled json string.
jsonOpts, err := json.Marshal(check.options)
if err != nil {
Expand Down Expand Up @@ -74,17 +70,13 @@ type check struct {
}

// generateChecks generates a list of checks combining a map of
// checktypes and a list of targets. It returns an error if any of the
// targets has an empty or invalid asset type.
func generateChecks(checktypes checktype.Catalog, targets []config.Target) ([]check, error) {
// checktypes and a list of targets.
func generateChecks(checktypes checktype.Catalog, targets []config.Target) []check {
var checks []check
for _, t := range dedup(targets) {
if t.AssetType == "" || !t.AssetType.IsValid() {
return nil, fmt.Errorf("invalid target asset type: %v", t.AssetType)
}

for _, c := range checktypes {
if !c.Accepts(t.AssetType) {
at := assettype.ToVulcan(t.AssetType)
if !c.Accepts(at) {
continue
}

Expand All @@ -102,7 +94,7 @@ func generateChecks(checktypes checktype.Catalog, targets []config.Target) ([]ch
})
}
}
return checks, nil
return checks
}

// dedup returns a deduplicated slice.
Expand Down
Loading