Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9baef0c
make the bandit transformer not throw an error when receiving an empt…
northdpole Aug 19, 2025
e061ac8
make the checkov parser not error out when receiving an empty input file
northdpole Aug 28, 2025
b251080
make the kics parser not error out when receiving an empty input file
northdpole Aug 28, 2025
cbe8017
make the codeql parser not error out when receiving one or more empty…
northdpole Aug 19, 2025
38d4b5d
make the credo parser not throw an error where the input file is empty
northdpole Aug 19, 2025
b5c0d7c
add tests to the credo scanner-- dependencies
northdpole Aug 19, 2025
3456da6
add integration tests to the credo component
northdpole Aug 19, 2025
53d72e6
make the mobsf parser not error out when receiving an empty file
northdpole Aug 19, 2025
c09f9a6
make the nancy parser not error out when receiving an empty file
northdpole Aug 20, 2025
11cadb9
make the semgrep parser not error out when receiving an empty file
northdpole Aug 20, 2025
83de279
make the snyk parser not error out when receiving an empty file
northdpole Aug 20, 2025
1fa5800
sobelow, add integration tests -- dependencies
northdpole Aug 20, 2025
af3348f
make sobelow not throw an error when the input file is empty and add …
northdpole Aug 20, 2025
019b833
make the trivy parser not error out when receiving an empty file
northdpole Aug 20, 2025
d0d77dd
make the trufflehog parser not error out when receiving an empty file
northdpole Aug 20, 2025
4f38738
make the zap parser not error out when receiving an empty file
northdpole Aug 20, 2025
fba339b
add test for osv-scan parser not erroring when receiving an empty file
northdpole Aug 28, 2025
5d711fd
pin bandit version
northdpole Aug 28, 2025
1f679ef
pin cdxgen version
northdpole Aug 28, 2025
15bc4b8
pin checkov version
northdpole Aug 28, 2025
b1bf840
document pinned codeql version
northdpole Aug 28, 2025
bb4630b
pin credo dependency
northdpole Aug 28, 2025
e33a7ca
document pinned gosec version
northdpole Aug 28, 2025
3f367cb
pin kics version
northdpole Aug 28, 2025
092551d
pin mobsfscan version
northdpole Aug 28, 2025
18ceb07
pin nancy integration
northdpole Aug 28, 2025
bbe2422
document pinned osv-scanner version
northdpole Aug 28, 2025
ac1490d
document pinned semgrep version
northdpole Aug 28, 2025
95b81e9
document pinned snyk version
northdpole Aug 28, 2025
4b894cc
pin sobelow version
northdpole Aug 28, 2025
6376fd0
pin trivy version
northdpole Aug 28, 2025
12243f2
document pinned trufflehog version
northdpole Aug 28, 2025
7230277
pin zap version
northdpole Aug 28, 2025
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
2 changes: 1 addition & 1 deletion components/scanners/bandit/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# bandit
# bandit 1.8.6 scanner component

This component implements a [scanner](https://github.com/smithy-security/smithy/blob/main/sdk/component/component.go)
that parses json reports output by [bandit](https://github.com/securego/gosec) into [ocsf](https://github.com/ocsf) format.
Expand Down
10 changes: 9 additions & 1 deletion components/scanners/bandit/internal/transformer/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ var (
ErrEmptyRawOutfileContents = errors.Errorf("empty raw out file contents")
// ErrBadTargetType is thrown when the option set target type is called with an unspecified or empty target type
ErrBadTargetType = errors.New("invalid empty target type")
// ErrFileNotFound is thrown when the raw output file is not found
ErrFileNotFound = errors.Errorf("raw output file not found")

// Bandit Parser Specific Errors

Expand Down Expand Up @@ -174,10 +176,16 @@ func (b *BanditTransformer) Transform(ctx context.Context) ([]*ocsf.Vulnerabilit
inFile, err := os.ReadFile(b.rawOutFilePath)
if err != nil {
if os.IsNotExist(err) {
return nil, errors.Errorf("raw output file '%s' not found", b.rawOutFilePath)
return nil, errors.Errorf("%w: %s Original Error: %w", ErrFileNotFound, b.rawOutFilePath, err)
}
return nil, errors.Errorf("failed to read raw output file '%s': %w", b.rawOutFilePath, err)
}

if len(inFile) == 0 {
logger.Info("Scanner SARIF file is empty, exiting")
return []*ocsf.VulnerabilityFinding{}, nil
}

b.fileContents = inFile
}
var results BanditOut
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package transformer
import (
_ "embed"
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -33,7 +34,7 @@ func TestBanditTransformer_Transform(t *testing.T) {
BanditTransformerWithClock(&clock),
)
require.NoError(t, err)
transformMethodTest(t, ocsfTransformer.Transform, nil)
transformMethodTest(t, ocsfTransformer.Transform, nil, 10)
})

t.Run("it should error for findings without a line range", func(t *testing.T) {
Expand All @@ -44,7 +45,7 @@ func TestBanditTransformer_Transform(t *testing.T) {
BanditRawOutFileContents([]byte(noLineRangeInput)),
)
require.NoError(t, err)
transformMethodTest(t, ocsfTransformer.Transform, ErrNoLineRange)
transformMethodTest(t, ocsfTransformer.Transform, ErrNoLineRange, 0)
})

t.Run("it should error for findings with an invalid data source", func(t *testing.T) {
Expand All @@ -55,7 +56,27 @@ func TestBanditTransformer_Transform(t *testing.T) {
BanditRawOutFileContents([]byte(noDataSourceInput)),
)
require.NoError(t, err)
transformMethodTest(t, ocsfTransformer.Transform, ErrBadDataSource)
transformMethodTest(t, ocsfTransformer.Transform, ErrBadDataSource, 0)
})
t.Run("it should not error when receiving an empty inFile", func(t *testing.T) {
emptyFilePath := filepath.Join(t.TempDir(), "empty.sarif")
os.Setenv("BANDIT_RAW_OUT_FILE_PATH", emptyFilePath)
require.NoError(t, os.WriteFile(os.Getenv("BANDIT_RAW_OUT_FILE_PATH"), []byte("{}"), 0644))
ocsfTransformer, err := New(
BanditTransformerWithTarget(ocsffindinginfo.DataSource_TARGET_TYPE_REPOSITORY),
BanditTransformerWithClock(&clock),
)
require.NoError(t, err)
transformMethodTest(t, ocsfTransformer.Transform, nil, 0)
})
t.Run("it should error when receiving a non existing inFile", func(t *testing.T) {
os.Setenv("BANDIT_RAW_OUT_FILE_PATH", "./testdata/foobar.json")
ocsfTransformer, err := New(
BanditTransformerWithTarget(ocsffindinginfo.DataSource_TARGET_TYPE_REPOSITORY),
BanditTransformerWithClock(&clock),
)
require.NoError(t, err)
transformMethodTest(t, ocsfTransformer.Transform, ErrFileNotFound, 0)
})
}

Expand Down Expand Up @@ -224,7 +245,7 @@ func assertValid(t *testing.T, finding *ocsf.VulnerabilityFinding, idx int, nowU
assert.NotEmptyf(t, vulnerability.Cwe.Uid, "Unexpected empty value for uid in vulnerability for finding %d", idx)
}

func transformMethodTest(t *testing.T, transformCallback func(ctx context.Context) ([]*ocsf.VulnerabilityFinding, error), expectedError error) {
func transformMethodTest(t *testing.T, transformCallback func(ctx context.Context) ([]*ocsf.VulnerabilityFinding, error), expectedError error, expectedFindingsLength int) {
var (
ctx, cancel = context.WithTimeout(context.Background(), time.Minute)
clock = clockwork.NewFakeClockAt(time.Date(2024, 11, 1, 0, 0, 0, 0, time.UTC))
Expand Down Expand Up @@ -253,7 +274,7 @@ func transformMethodTest(t *testing.T, transformCallback func(ctx context.Contex
return
}
require.NoError(t, err)
require.NotEmpty(t, findings)
require.Equal(t, expectedFindingsLength, len(findings))

for idx, finding := range findings {
assertValid(t, finding, idx, nowUnix, typeUID)
Expand Down
2 changes: 1 addition & 1 deletion components/scanners/bandit/scanner/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
FROM python:3.10-slim

RUN pip3 install bandit
RUN pip3 install bandit==1.8.6

ENTRYPOINT [ "bandit" ]
3 changes: 1 addition & 2 deletions components/scanners/cdxgen/component.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ parameters:
value: ""
steps:
- name: run-cdxgen
image: ghcr.io/cyclonedx/cdxgen:latest

image: ghcr.io/cyclonedx/cdxgen:v11.6.0
executable: "/bin/bash"
args:
- -c
Expand Down
44 changes: 32 additions & 12 deletions components/scanners/checkov/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
# semgrep
# Checkov Scanner

This component implements a [scanner](https://github.com/smithy-security/smithy/blob/main/sdk/component/component.go)
that parses [sarif](https://sarifweb.azurewebsites.net/) reports output
by [semgrep](https://github.com/semgrep/semgrep) into [ocsf](https://github.com/ocsf) format.
## Overview

## Parser Environment variables
Checkov is a static code analysis tool for infrastructure-as-code (IaC) to detect security and compliance misconfigurations. This component integrates Checkov and parses its findings into the OCSF format.

The component uses environment variables for configuration.
## Version

It requires the component
environment variables defined [here](https://github.com/smithy-security/smithy/blob/main/sdk/README.md#component) as well
as the following:
This component uses Checkov version `3.2.467`.

| Environment Variable | Type | Required | Default | Description |
|--------------------------|--------|----------|------------|---------------------------------------------------------|
| SEMGREP\_RAW\_OUT\_FILE\_PATH | string | yes | - | The path where to find the semgrep sarif report |
## How to Run

To run the Checkov scanner, follow these steps:

1. Ensure you have Docker installed and running on your system.

2. Execute the following command to run Checkov:

```bash
docker run --rm \
-v $(pwd):/src \
bridgecrew/checkov:3.2.467 \
-d=/src \
-o=sarif \
--output-file-path=/tmp/results_sarif.sarif \
--soft-fail
```

3. The results will be saved in SARIF format at `/tmp/results_sarif.sarif`.

## How to Test

To test the Checkov scanner run the relevant example workflow.

```bash
smithyctl workflow run --build-component-images=true --overrides=./examples/checkov/overrides.yaml ./examples/checkov/workflow.yaml
```
2 changes: 1 addition & 1 deletion components/scanners/checkov/component.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: "Runs Checkov then parses findings into the OCSF format"
type: "scanner"
steps:
- name: "run-checkov"
image: "bridgecrew/checkov"
image: "bridgecrew/checkov:3.2.467"
executable: "/usr/local/bin/checkov"
args:
- "-d={{ sourceCodeWorkspace }}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ func (g *checkovTransformer) Transform(ctx context.Context) ([]*ocsf.Vulnerabili
return nil, errors.Errorf("failed to read raw output file '%s': %w", g.rawOutFilePath, err)
}

if len(b) == 0 {
logger.Info("Scanner SARIF file is empty, exiting")
return []*ocsf.VulnerabilityFinding{}, nil
}

var report sarifschemav210.SchemaJson
if err := report.UnmarshalJSON(b); err != nil {
return nil, errors.Errorf("failed to parse raw checkov output: %w", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package transformer_test
import (
"context"
_ "embed"
"os"
"path/filepath"
"testing"
"time"

Expand Down Expand Up @@ -48,7 +50,23 @@ func TestCheckovTransformer_Transform(t *testing.T) {
transformer.CheckovTransformerWithClock(clock),
)
require.NoError(t, err)
t.Run("it should return 0 findings when the output file exists but is empty", func(t *testing.T) {
// Create an empty SARIF file for testing
emptyFilePath := filepath.Join(t.TempDir(), "empty_results_sarif.sarif")
err := os.WriteFile(emptyFilePath, []byte{}, 0644)
require.NoError(t, err)

ocsfTransformer, err := transformer.New(
transformer.CheckovRawOutFilePath(emptyFilePath),
transformer.CheckovTransformerWithTarget(transformer.TargetTypeRepository),
transformer.CheckovTransformerWithClock(clock),
)
require.NoError(t, err)

findings, err := ocsfTransformer.Transform(ctx)
require.NoError(t, err)
assert.Empty(t, findings, "Expected no findings for an empty SARIF file")
})
t.Run("it should transform correctly the finding to ocsf format", func(t *testing.T) {
findings, err := ocsfTransformer.Transform(ctx)
require.NoError(t, err)
Expand Down
4 changes: 4 additions & 0 deletions components/scanners/codeql/codeql-image/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ in a repository tree and for every language prepare a codeql database and analyz
* codeql runs with build-mode = none unless the language is go where it runs with build-mode='autobuild'
* C and Cpp are not supported
* in the current configuration codeql command line args cannot be customized

## Version

This component uses Codeql version `v2.20.4`
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ func New(opts ...CodeqlTransformerOption) (*codeqlTransformer, error) {
// Transform transforms raw sarif findings into ocsf vulnerability findings.
func (g *codeqlTransformer) Transform(ctx context.Context) ([]*ocsf.VulnerabilityFinding, error) {
logger := componentlogger.LoggerFromContext(ctx)
logger.Debug("preparing to parse raw codeql output...")

var result []*ocsf.VulnerabilityFinding

matches, err := filepath.Glob(g.rawOutDirPathGlob)
Expand All @@ -133,6 +131,8 @@ func (g *codeqlTransformer) Transform(ctx context.Context) ([]*ocsf.Vulnerabilit
}

for _, file := range fileNames {
logger.Debug("preparing to parse raw codeql output...", slog.String("filename", file))

b, err := os.ReadFile(file)
if err != nil {
if os.IsNotExist(err) {
Expand All @@ -141,6 +141,11 @@ func (g *codeqlTransformer) Transform(ctx context.Context) ([]*ocsf.Vulnerabilit
return nil, errors.Errorf("failed to read raw output file '%s': %w", file, err)
}

if len(b) == 0 {
logger.Info("Scanner SARIF file is empty, continuing")
continue
}

var report sarifschemav210.SchemaJson
if err := report.UnmarshalJSON(b); err != nil {
return nil, errors.Errorf("failed to parse raw codeql output: %w", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package transformer_test
import (
"context"
_ "embed"
"os"
"path/filepath"
"testing"
"time"

Expand All @@ -15,7 +17,7 @@ import (
ocsffindinginfo "github.com/smithy-security/smithy/sdk/gen/ocsf_ext/finding_info/v1"
ocsf "github.com/smithy-security/smithy/sdk/gen/ocsf_schema/v1"

"github.com/smithy-security/smithy/components/scanners/codeql/internal/transformer"
"github.com/smithy-security/smithy/components/scanners/codeql/parser/internal/transformer"
)

func TestCodeQLTransformer_Transform(t *testing.T) {
Expand Down Expand Up @@ -213,4 +215,41 @@ func TestCodeQLTransformer_Transform(t *testing.T) {
assert.NotNilf(t, affectedCode.StartLine, "Unexpected nil start line for vulnerability for finding %d", idx)
}
})
t.Run("it should return 0 findings when the output file exists but is empty", func(t *testing.T) {
// Create an empty SARIF file for testing
emptyFilePath := filepath.Join(t.TempDir(), "empty_results_sarif.json")
err := os.WriteFile(emptyFilePath, []byte{}, 0644)
require.NoError(t, err)

ocsfTransformer, err := transformer.New(
transformer.CodeqlRawOutDirGlob(emptyFilePath),
transformer.CodeqlTransformerWithTarget(transformer.TargetTypeRepository),
transformer.CodeqlTransformerWithClock(clock),
)
require.NoError(t, err)

findings, err := ocsfTransformer.Transform(ctx)
require.NoError(t, err)
assert.Empty(t, findings, "Expected no findings for an empty SARIF file")
})
t.Run("it should parse globs with files that are potentially empty but also have files with results", func(t *testing.T) {
// Create an empty SARIF file for testing
tmpDir := t.TempDir()
emptyFilePath := filepath.Join(tmpDir, "empty_results_sarif.json")
err := os.WriteFile(emptyFilePath, []byte{}, 0644)
require.NoError(t, err)
os.CopyFS(tmpDir, os.DirFS("testdata/"))

ocsfTransformer, err := transformer.New(
transformer.CodeqlRawOutDirGlob(filepath.Join(tmpDir, "/*.json")),
transformer.CodeqlTransformerWithTarget(transformer.TargetTypeRepository),
transformer.CodeqlTransformerWithClock(clock),
)
require.NoError(t, err)

findings, err := ocsfTransformer.Transform(ctx)
require.NoError(t, err)
assert.Equal(t, 111, len(findings))
})

}
4 changes: 4 additions & 0 deletions components/scanners/credo/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/smithy-security/pkg/env v0.0.3
github.com/smithy-security/pkg/sarif v0.0.11
github.com/smithy-security/smithy/sdk v0.0.19-alpha
github.com/stretchr/testify v1.10.0
)

require (
Expand All @@ -20,6 +21,7 @@ require (
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/bmatcuk/doublestar v1.3.4 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/inflect v0.19.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/go-cmp v0.6.0 // indirect
Expand All @@ -40,6 +42,7 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/package-url/packageurl-go v0.1.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/smithy-security/pkg/utils v0.0.2 // indirect
Expand All @@ -60,4 +63,5 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
2 changes: 2 additions & 0 deletions components/scanners/credo/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjr
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
Expand Down
Loading
Loading