Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
eafb3a6
feat: add --exclude flag to skip paths during scanning
Ankitsinghsisodya Jan 10, 2026
f0aa799
feat: add --exclude flag with glob and regex support
Ankitsinghsisodya Jan 10, 2026
d7e12fd
Merge remote-tracking branch 'origin/feat/exclude-paths-flag' into fe…
Ankitsinghsisodya Jan 14, 2026
f634bd1
fix: address lint issues for --exclude flag implementation
Ankitsinghsisodya Jan 14, 2026
d35d194
Merge branch 'main' into feat/exclude-paths-flag
Ankitsinghsisodya Jan 20, 2026
4223e6c
feat: Implement experimental skip directory functionality with explic…
Ankitsinghsisodya Jan 20, 2026
eab9cc8
feat: Add tests for the experimental `--skip-dir` flag with support f…
Ankitsinghsisodya Jan 20, 2026
65a8186
feat: Implement and test directory exclusion functionality using skip…
Ankitsinghsisodya Jan 20, 2026
edbbe2d
feat: Add `--experimental-skip-dir` flag with regex pattern support t…
Ankitsinghsisodya Jan 20, 2026
1138b63
refactor: rename skip directory patterns to exclude patterns and move…
Ankitsinghsisodya Jan 20, 2026
b508b49
refactor: streamline exclude patterns initialization and error handling
Ankitsinghsisodya Jan 20, 2026
a954c7e
refactor: Rename test case names to snake_case for consistency.
Ankitsinghsisodya Jan 20, 2026
cd30159
refactor: unexport exclude pattern types and functions for internal use.
Ankitsinghsisodya Jan 20, 2026
772c5a0
chore: Remove redundant vulnerability ID check and unused import from…
Ankitsinghsisodya Jan 20, 2026
0bc9ca0
build: Exclude `pkg/osvscanner/exclude.go` from the `forbidigo` linte…
Ankitsinghsisodya Jan 20, 2026
c783f97
Update pkg/osvscanner/exclude_test.go
Ankitsinghsisodya Jan 20, 2026
78d51d8
Update pkg/osvscanner/exclude_test.go
Ankitsinghsisodya Jan 20, 2026
e7ac260
refactor: rename `experimental-skip-dir` flag to `experimental-exclud…
Ankitsinghsisodya Jan 20, 2026
0ef512f
test: update `experimental-exclude` flag test names and add cases for…
Ankitsinghsisodya Jan 20, 2026
c8e92a9
refactor: Remove redundant boolean flags and simplify assertions in `…
Ankitsinghsisodya Jan 20, 2026
a2aeb05
Merge branch 'main' into feat/exclude-paths-flag
Ankitsinghsisodya Jan 20, 2026
3dc8bac
Update cmd/osv-scanner/scan/source/command.go
another-rex Jan 21, 2026
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
1 change: 1 addition & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ linters:
files:
- "!**/internal/cachedregexp/**"
- "!**/internal/testutility/normalize.go"
- "!**/pkg/osvscanner/exclude.go"
deny:
- pkg: regexp
desc: Use github.com/google/osv-scanner/v2/internal/cachedregexp instead
Expand Down
44 changes: 44 additions & 0 deletions cmd/osv-scanner/scan/source/__snapshots__/command_test.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1471,6 +1471,50 @@ Total 11 packages affected by 45 known vulnerabilities (5 Critical, 19 High, 20

---

[TestCommand/skip-dir_with_exact_directory_name - 1]
Scanning dir ./testdata/locks-one-with-nested
Scanned <rootdir>/testdata/locks-one-with-nested/nested/composer.lock file and found 1 package
Scanned <rootdir>/testdata/locks-one-with-nested/yarn.lock file and found 1 package
No issues found

---

[TestCommand/skip-dir_with_exact_directory_name - 2]

---

[TestCommand/skip-dir_with_glob_pattern - 1]
Scanning dir ./testdata/locks-one-with-nested
Scanned <rootdir>/testdata/locks-one-with-nested/nested/composer.lock file and found 1 package
Scanned <rootdir>/testdata/locks-one-with-nested/yarn.lock file and found 1 package
No issues found

---

[TestCommand/skip-dir_with_glob_pattern - 2]

---

[TestCommand/skip-dir_with_invalid_regex_returns_error - 1]
Scanning dir ./testdata/locks-many
---

[TestCommand/skip-dir_with_invalid_regex_returns_error - 2]
failed to parse skip directory patterns: invalid regex pattern "[invalid": error parsing regexp: missing closing ]: `[invalid`

---

[TestCommand/skip-dir_with_regex_pattern - 1]
Scanning dir ./testdata/locks-one-with-nested
Scanned <rootdir>/testdata/locks-one-with-nested/yarn.lock file and found 1 package
No issues found

---

[TestCommand/skip-dir_with_regex_pattern - 2]

---

[TestCommand/spdx_2.3_output - 1]
{
"spdxVersion": "SPDX-2.3",
Expand Down
5 changes: 5 additions & 0 deletions cmd/osv-scanner/scan/source/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ func Command(stdout, stderr io.Writer, client *http.Client) *cli.Command {
Usage: "include scanning git root (non-submoduled) repositories",
Value: false,
},
&cli.StringSliceFlag{
Name: "experimental-exclude",
Usage: "exclude directory paths during scanning; use g:pattern for glob, r:pattern for regex, or just dirname for exact match (can be repeated)",
},
&cli.StringFlag{
Name: "data-source",
Usage: "source to fetch package information from; value can be: deps.dev, native",
Expand Down Expand Up @@ -109,6 +113,7 @@ func action(_ context.Context, cmd *cli.Command, stdout, stderr io.Writer, clien

experimentalScannerActions := helper.GetExperimentalScannerActions(cmd, client)
experimentalScannerActions.RequestUserAgent = "osv-scanner_scan-source/" + version.OSVVersion
experimentalScannerActions.ExcludePatterns = cmd.StringSlice("experimental-exclude")
// Add `source` specific experimental configs
experimentalScannerActions.TransitiveScanning = osvscanner.TransitiveScanningActions{
Disabled: cmd.Bool("no-resolve"),
Expand Down
31 changes: 31 additions & 0 deletions cmd/osv-scanner/scan/source/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,37 @@ func TestCommand(t *testing.T) {
Args: []string{"", "source", "--recursive", "--no-ignore", "./testdata/locks-gitignore"},
Exit: 0,
},
// experimental exclude flag tests
{
Name: "exclude_with_exact_directory_name",
Args: []string{"", "source", "--recursive", "--experimental-exclude=nested", "./testdata/locks-one-with-nested"},
Exit: 0,
},
{
Name: "exclude_with_glob_pattern",
Args: []string{"", "source", "--recursive", "--experimental-exclude=g:**/nested/**", "./testdata/locks-one-with-nested"},
Exit: 0,
},
{
Name: "exclude_with_regex_pattern",
Args: []string{"", "source", "--recursive", "--experimental-exclude=r:/nested$", "./testdata/locks-one-with-nested"},
Exit: 0,
},
{
Name: "exclude_with_invalid_regex_returns_error",
Args: []string{"", "source", "--experimental-exclude=r:[invalid", "./testdata/locks-many"},
Exit: 127,
},
{
Name: "exclude_with_multiple_exact_directories",
Args: []string{"", "source", "--recursive", "--experimental-exclude=nested", "--experimental-exclude=other", "./testdata/locks-one-with-nested"},
Exit: 0,
},
{
Name: "exclude_with_multiple_pattern_types",
Args: []string{"", "source", "--recursive", "--experimental-exclude=nested", "--experimental-exclude=g:**/vendor/**", "--experimental-exclude=r:\\.cache$", "./testdata/locks-one-with-nested"},
Exit: 0,
},
{
Name: "json output",
Args: []string{"", "source", "--format", "json", "./testdata/locks-many/composer.lock"},
Expand Down
155 changes: 153 additions & 2 deletions cmd/osv-scanner/scan/source/testdata/cassettes/TestCommand.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6698,6 +6698,157 @@ interactions:
code: 200
duration: 0s
- id: 41
request:
proto: HTTP/1.1
proto_major: 1
proto_minor: 1
content_length: 278
host: api.osv.dev
body: |
{
"queries": [
{
"package": {
"ecosystem": "Packagist",
"name": "sentry/sdk"
},
"version": "2.0.4"
},
{
"package": {
"ecosystem": "npm",
"name": "balanced-match"
},
"version": "1.0.2"
}
]
}
headers:
Content-Type:
- application/json
X-Test-Name:
- TestCommand/skip-dir_with_exact_directory_name
url: https://api.osv.dev/v1/querybatch
method: POST
response:
proto: HTTP/2.0
proto_major: 2
proto_minor: 0
content_length: 19
body: |
{
"results": [
{},
{}
]
}
headers:
Content-Length:
- "19"
Content-Type:
- application/json
status: 200 OK
code: 200
duration: 0s
- id: 42
request:
proto: HTTP/1.1
proto_major: 1
proto_minor: 1
content_length: 278
host: api.osv.dev
body: |
{
"queries": [
{
"package": {
"ecosystem": "Packagist",
"name": "sentry/sdk"
},
"version": "2.0.4"
},
{
"package": {
"ecosystem": "npm",
"name": "balanced-match"
},
"version": "1.0.2"
}
]
}
headers:
Content-Type:
- application/json
X-Test-Name:
- TestCommand/skip-dir_with_glob_pattern
url: https://api.osv.dev/v1/querybatch
method: POST
response:
proto: HTTP/2.0
proto_major: 2
proto_minor: 0
content_length: 19
body: |
{
"results": [
{},
{}
]
}
headers:
Content-Length:
- "19"
Content-Type:
- application/json
status: 200 OK
code: 200
duration: 0s
- id: 43
request:
proto: HTTP/1.1
proto_major: 1
proto_minor: 1
content_length: 149
host: api.osv.dev
body: |
{
"queries": [
{
"package": {
"ecosystem": "npm",
"name": "balanced-match"
},
"version": "1.0.2"
}
]
}
headers:
Content-Type:
- application/json
X-Test-Name:
- TestCommand/skip-dir_with_regex_pattern
url: https://api.osv.dev/v1/querybatch
method: POST
response:
proto: HTTP/2.0
proto_major: 2
proto_minor: 0
content_length: 16
body: |
{
"results": [
{}
]
}
headers:
Content-Length:
- "16"
Content-Type:
- application/json
status: 200 OK
code: 200
duration: 0s
- id: 44
request:
proto: HTTP/1.1
proto_major: 1
Expand Down Expand Up @@ -6781,7 +6932,7 @@ interactions:
status: 200 OK
code: 200
duration: 0s
- id: 42
- id: 45
request:
proto: HTTP/1.1
proto_major: 1
Expand Down Expand Up @@ -6826,7 +6977,7 @@ interactions:
status: 200 OK
code: 200
duration: 0s
- id: 43
- id: 46
request:
proto: HTTP/1.1
proto_major: 1
Expand Down
44 changes: 44 additions & 0 deletions docs/scan-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,50 @@ There is a [known issue](https://github.com/google/osv-scanner/issues/209) that

The `--no-ignore` flag can be used to force the scanner to scan ignored files.

## Excluding Paths

Experimental
{: .label }

You can exclude specific paths from scanning using the `--experimental-exclude` flag. This is useful for excluding test directories, documentation, or vendor directories from vulnerability scans.

**Note:** This flag currently only excludes directories, not individual files. This is an experimental feature and the syntax may change in future versions.

### Syntax

The flag supports three pattern types, matching the `--lockfile` flag syntax:

- **Exact directory name** (no prefix or `:` prefix): Matches directories with the exact name
- **Glob pattern** (`g:` prefix): Matches using glob patterns
- **Regex pattern** (`r:` prefix): Matches using regular expressions

### Examples

```bash
# Exclude directories named "test" or "docs" (exact match)
osv-scanner scan source -r --experimental-exclude=test --experimental-exclude=docs /path/to/your/dir

# Exclude using glob patterns
osv-scanner scan source -r --experimental-exclude="g:**/test/**" --experimental-exclude="g:**/docs/**" /path/to/your/dir

# Exclude using regex patterns
osv-scanner scan source -r --experimental-exclude="r:.*_test$" /path/to/your/dir

# Mix different pattern types
osv-scanner scan source -r --experimental-exclude=vendor --experimental-exclude="g:**/test/**" --experimental-exclude="r:\\.cache" /path/to/your/dir

# Escape directory names containing colons using : prefix
osv-scanner scan source -r --experimental-exclude=":my:project" /path/to/your/dir
```

### Common use cases

- Excluding test directories: `--experimental-exclude=test` or `--experimental-exclude="g:**/test/**"`
- Excluding documentation: `--experimental-exclude=docs`
- Excluding vendor directories: `--experimental-exclude=vendor`

Alternatively, you can use the `osv-scanner.toml` configuration file with `[[PackageOverrides]]` to ignore specific packages or directories. See [Configuration](./configuration.md) for more details.

## SBOM scanning

SBOMs will be automatically identified so long as their name follows the specification for the particular format:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
github.com/gkampitakis/go-snaps v0.5.19
github.com/go-git/go-git/v5 v5.16.4
github.com/gobwas/glob v0.2.3
github.com/goccy/go-yaml v1.19.2
github.com/google/go-cmp v0.7.0
github.com/google/osv-scalibr v0.4.3-0.20260119170449-c743cb685a10
Expand Down Expand Up @@ -115,7 +116,6 @@ require (
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-restruct/restruct v1.2.0-alpha // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/google/go-containerregistry v0.20.6 // indirect
Expand Down
20 changes: 19 additions & 1 deletion internal/cachedregexp/regex.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Package cachedregexp provides a cached version of regexp.MustCompile.
// Package cachedregexp provides a cached version of regexp.MustCompile and regexp.Compile.
package cachedregexp

import (
Expand All @@ -16,3 +16,21 @@ func MustCompile(exp string) *regexp.Regexp {

return compiled.(*regexp.Regexp)
}

// Compile returns a compiled regexp or an error if the pattern is invalid.
// Results are cached for performance.
func Compile(exp string) (*regexp.Regexp, error) {
compiled, ok := cache.Load(exp)
if ok {
return compiled.(*regexp.Regexp), nil
}

r, err := regexp.Compile(exp)
if err != nil {
return nil, err
}

cache.LoadOrStore(exp, r)

return r, nil
}
Loading
Loading