542 lines
16 KiB
Go
542 lines
16 KiB
Go
// ©AngelaMos | 2026
|
|
// builtin_test.go
|
|
|
|
package rules
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestRegisterBuiltins(t *testing.T) {
|
|
t.Parallel()
|
|
reg := NewRegistry()
|
|
RegisterBuiltins(reg)
|
|
assert.GreaterOrEqual(t, reg.Len(), 70)
|
|
}
|
|
|
|
func TestBuiltinRuleIDs(t *testing.T) {
|
|
t.Parallel()
|
|
reg := NewRegistry()
|
|
RegisterBuiltins(reg)
|
|
seen := make(map[string]bool)
|
|
for _, r := range reg.All() {
|
|
assert.NotEmpty(t, r.ID)
|
|
assert.NotEmpty(t, r.Description)
|
|
assert.NotEmpty(t, r.Keywords)
|
|
assert.NotNil(t, r.Pattern)
|
|
assert.False(t, seen[r.ID], "duplicate ID: %s", r.ID)
|
|
seen[r.ID] = true
|
|
}
|
|
}
|
|
|
|
func TestBuiltinPatternMatches(t *testing.T) { //nolint:funlen,gocognit
|
|
t.Parallel()
|
|
|
|
tests := map[string]struct {
|
|
ruleID string
|
|
input string
|
|
wantMatch bool
|
|
wantGroup string
|
|
}{
|
|
"aws access key": { //nolint:gosec
|
|
ruleID: "aws-access-key-id",
|
|
input: `aws_key = "AKIAIOSFODNN7EXAMPLE"`,
|
|
wantMatch: true,
|
|
wantGroup: "AKIAIOSFODNN7EXAMPLE",
|
|
},
|
|
"aws access key ABIA prefix": {
|
|
ruleID: "aws-access-key-id",
|
|
input: `ABIAIOSFODNN7EXAMPL0`,
|
|
wantMatch: true,
|
|
wantGroup: "ABIAIOSFODNN7EXAMPL0",
|
|
},
|
|
"aws access key too short": {
|
|
ruleID: "aws-access-key-id",
|
|
input: `AKIA1234`,
|
|
wantMatch: false,
|
|
},
|
|
"github pat classic": {
|
|
ruleID: "github-pat-classic",
|
|
input: `ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij`,
|
|
wantMatch: true,
|
|
wantGroup: "ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij",
|
|
},
|
|
"github pat fine-grained": {
|
|
ruleID: "github-pat-fine",
|
|
input: `github_pat_abcdefghijABCDEFGHIJKL_abcdefghij0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABC`,
|
|
wantMatch: true,
|
|
},
|
|
"github oauth": {
|
|
ruleID: "github-oauth-token",
|
|
input: `gho_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij`,
|
|
wantMatch: true,
|
|
wantGroup: "gho_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij",
|
|
},
|
|
"github app token": {
|
|
ruleID: "github-app-token",
|
|
input: `ghs_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij`,
|
|
wantMatch: true,
|
|
wantGroup: "ghs_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij",
|
|
},
|
|
"github refresh token": {
|
|
ruleID: "github-refresh-token",
|
|
input: `ghr_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij`,
|
|
wantMatch: true,
|
|
wantGroup: "ghr_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij",
|
|
},
|
|
"gitlab pat": {
|
|
ruleID: "gitlab-pat",
|
|
input: `glpat-xYz1234567890AbCdEfGh`,
|
|
wantMatch: true,
|
|
wantGroup: "glpat-xYz1234567890AbCdEfGh",
|
|
},
|
|
"gitlab pipeline trigger": {
|
|
ruleID: "gitlab-pipeline-trigger",
|
|
input: `glptt-abcdefghijklmnopqrstuvwxyz0123456789ABCD`,
|
|
wantMatch: true,
|
|
wantGroup: "glptt-abcdefghijklmnopqrstuvwxyz0123456789ABCD",
|
|
},
|
|
"gitlab runner token": {
|
|
ruleID: "gitlab-runner-token",
|
|
input: `glrt-xYz1234567890AbCdEfGh`,
|
|
wantMatch: true,
|
|
wantGroup: "glrt-xYz1234567890AbCdEfGh",
|
|
},
|
|
"gcp api key": {
|
|
ruleID: "gcp-api-key",
|
|
input: `AIzaSyDabcdefghij1234567890KLMNOPQRSTUV`,
|
|
wantMatch: true,
|
|
},
|
|
"gcp service account": {
|
|
ruleID: "gcp-service-account",
|
|
input: `"type" : "service_account"`,
|
|
wantMatch: true,
|
|
},
|
|
"gcp oauth secret": {
|
|
ruleID: "gcp-oauth-client-secret",
|
|
input: `GOCSPX-aBcDeFgHiJkLmNoPqRsTuVwXyZ01`,
|
|
wantMatch: true,
|
|
},
|
|
"azure storage key": {
|
|
ruleID: "azure-storage-key",
|
|
input: `AccountKey=` +
|
|
`abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`,
|
|
wantMatch: true,
|
|
},
|
|
"slack bot token": {
|
|
ruleID: "slack-bot-token",
|
|
input: `xoxb-1234567890-9876543210-AbCdEfGhIjKlMnOpQrStUvWx`,
|
|
wantMatch: true,
|
|
},
|
|
"slack webhook": { //nolint:gosec
|
|
ruleID: "slack-webhook",
|
|
input: `https://hooks.slack.com/services/T01234567/B01234567/AbCdEfGhIjKlMnOpQrStUvWx`,
|
|
wantMatch: true,
|
|
},
|
|
"stripe live key": { //nolint:gosec
|
|
ruleID: "stripe-live-secret",
|
|
input: `sk_live_4eC39HqLyjWDarjtT1zdp7dc`,
|
|
wantMatch: true,
|
|
wantGroup: "sk_live_4eC39HqLyjWDarjtT1zdp7dc",
|
|
},
|
|
"stripe test key": {
|
|
ruleID: "stripe-test-secret",
|
|
input: `sk_test_4eC39HqLyjWDarjtT1zdp7dc`, //nolint:gosec
|
|
wantMatch: true,
|
|
wantGroup: "sk_test_4eC39HqLyjWDarjtT1zdp7dc", //nolint:gosec
|
|
},
|
|
"stripe restricted live": { //nolint:gosec
|
|
ruleID: "stripe-live-restricted",
|
|
input: `rk_live_4eC39HqLyjWDarjtT1zdp7dc`,
|
|
wantMatch: true,
|
|
wantGroup: "rk_live_4eC39HqLyjWDarjtT1zdp7dc",
|
|
},
|
|
"stripe webhook secret": {
|
|
ruleID: "stripe-webhook-secret",
|
|
input: `whsec_MfKBGsXP8r7B2cGnQ9jT6KxL12AbCdEf`,
|
|
wantMatch: true,
|
|
},
|
|
"twilio api key": {
|
|
ruleID: "twilio-api-key",
|
|
input: `SK1234567890abcdef1234567890abcdef`,
|
|
wantMatch: true,
|
|
wantGroup: "SK1234567890abcdef1234567890abcdef",
|
|
},
|
|
"twilio account sid": {
|
|
ruleID: "twilio-account-sid",
|
|
input: `AC1234567890abcdef1234567890abcdef`,
|
|
wantMatch: true,
|
|
wantGroup: "AC1234567890abcdef1234567890abcdef",
|
|
},
|
|
"sendgrid api key": {
|
|
ruleID: "sendgrid-api-key",
|
|
input: `SG.aBcDeFgHiJkLmNoPqRsTuw.xYzAbCdEfGhIjKlMnOpQrStUvWxYzAbCdEfGhIjKlMn`,
|
|
wantMatch: true,
|
|
},
|
|
"shopify access token": {
|
|
ruleID: "shopify-access-token",
|
|
input: `shpat_abcdef0123456789abcdef0123456789`,
|
|
wantMatch: true,
|
|
wantGroup: "shpat_abcdef0123456789abcdef0123456789",
|
|
},
|
|
"shopify custom app": {
|
|
ruleID: "shopify-custom-app",
|
|
input: `shpca_abcdef0123456789abcdef0123456789`,
|
|
wantMatch: true,
|
|
wantGroup: "shpca_abcdef0123456789abcdef0123456789",
|
|
},
|
|
"shopify private app": {
|
|
ruleID: "shopify-private-app",
|
|
input: `shppa_abcdef0123456789abcdef0123456789`,
|
|
wantMatch: true,
|
|
wantGroup: "shppa_abcdef0123456789abcdef0123456789",
|
|
},
|
|
"shopify shared secret": {
|
|
ruleID: "shopify-shared-secret",
|
|
input: `shpss_abcdef0123456789abcdef0123456789`,
|
|
wantMatch: true,
|
|
wantGroup: "shpss_abcdef0123456789abcdef0123456789",
|
|
},
|
|
"npm access token": {
|
|
ruleID: "npm-access-token",
|
|
input: `npm_aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789`,
|
|
wantMatch: true,
|
|
},
|
|
"pypi token": {
|
|
ruleID: "pypi-api-token",
|
|
input: `pypi-AgEIcHlwaS5vcmcCJDU5NTk5YTJhLWIwN2QtNDRkZi1iM` +
|
|
`jIxLTk2OWU4YmViZDM3NgACKlszLCJjODA0ZWE1OC1kMjFiLTQzMjMtYWR` +
|
|
`mNy0xZjQ4MGQ`,
|
|
wantMatch: true,
|
|
},
|
|
"rubygems api key": {
|
|
ruleID: "rubygems-api-key",
|
|
input: `rubygems_abcdef0123456789abcdef0123456789abcdef0123456789`,
|
|
wantMatch: true,
|
|
},
|
|
"docker hub pat": {
|
|
ruleID: "docker-hub-pat",
|
|
input: `dckr_pat_aBcDeFgHiJkLmNoPqRsTuVwXyZ01`,
|
|
wantMatch: true,
|
|
},
|
|
"jwt": {
|
|
ruleID: "jwt-token",
|
|
input: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.` +
|
|
`eyJzdWIiOiIxMjM0NTY3ODkwIn0.` +
|
|
`dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U`,
|
|
wantMatch: true,
|
|
},
|
|
"rsa private key": { //nolint:gosec
|
|
ruleID: "ssh-private-key-rsa",
|
|
input: `-----BEGIN RSA PRIVATE KEY-----`,
|
|
wantMatch: true,
|
|
},
|
|
"openssh private key": {
|
|
ruleID: "ssh-private-key-openssh",
|
|
input: `-----BEGIN OPENSSH PRIVATE KEY-----`, //nolint:gosec
|
|
wantMatch: true,
|
|
},
|
|
"ec private key": { //nolint:gosec
|
|
ruleID: "ssh-private-key-ec",
|
|
input: `-----BEGIN EC PRIVATE KEY-----`,
|
|
wantMatch: true,
|
|
},
|
|
"dsa private key": { //nolint:gosec
|
|
ruleID: "ssh-private-key-dsa",
|
|
input: `-----BEGIN DSA PRIVATE KEY-----`,
|
|
wantMatch: true,
|
|
},
|
|
"pgp private key": { //nolint:gosec
|
|
ruleID: "pgp-private-key",
|
|
input: `-----BEGIN PGP PRIVATE KEY BLOCK-----`,
|
|
wantMatch: true,
|
|
},
|
|
"pkcs8 private key": {
|
|
ruleID: "private-key-pkcs8",
|
|
input: `-----BEGIN PRIVATE KEY-----`,
|
|
wantMatch: true,
|
|
},
|
|
"generic password": {
|
|
ruleID: "generic-password",
|
|
input: `password = "my$ecretP@ss99"`,
|
|
wantMatch: true,
|
|
wantGroup: "my$ecretP@ss99",
|
|
},
|
|
"generic password no match on short": {
|
|
ruleID: "generic-password",
|
|
input: `password = "abc"`,
|
|
wantMatch: false,
|
|
},
|
|
"generic secret": {
|
|
ruleID: "generic-secret",
|
|
input: `secret_key = "xK9mP2vL5nQ8jR3tB7"`,
|
|
wantMatch: true,
|
|
wantGroup: "xK9mP2vL5nQ8jR3tB7",
|
|
},
|
|
"generic api key": {
|
|
ruleID: "generic-api-key",
|
|
input: `api_key = "aK9mP2vL5nQ8jR3tB7wX4cD"`,
|
|
wantMatch: true,
|
|
wantGroup: "aK9mP2vL5nQ8jR3tB7wX4cD",
|
|
},
|
|
"generic token": {
|
|
ruleID: "generic-token",
|
|
input: `access_token = "xK9mP2vL5nQ8jR3tB7wY"`,
|
|
wantMatch: true,
|
|
wantGroup: "xK9mP2vL5nQ8jR3tB7wY",
|
|
},
|
|
"postgres connection": { //nolint:gosec
|
|
ruleID: "postgres-connection",
|
|
input: `postgresql://admin:s3cr3t@db.example.com:5432/mydb`,
|
|
wantMatch: true,
|
|
},
|
|
"mysql connection": { //nolint:gosec
|
|
ruleID: "mysql-connection",
|
|
input: `mysql://root:password123@127.0.0.1:3306/app`,
|
|
wantMatch: true,
|
|
},
|
|
"mongodb connection": { //nolint:gosec
|
|
ruleID: "mongodb-connection",
|
|
input: `mongodb+srv://user:p4ssw0rd@cluster0.abc.mongodb.net/db`,
|
|
wantMatch: true,
|
|
},
|
|
"redis connection": { //nolint:gosec
|
|
ruleID: "redis-connection",
|
|
input: `redis://default:s3cret@redis.example.com:6379/0`,
|
|
wantMatch: true,
|
|
},
|
|
"hashicorp vault token": {
|
|
ruleID: "hashicorp-vault-token",
|
|
input: `hvs.CAESIGH3YzJfaBcDeFgHiJkLmNoPqR`,
|
|
wantMatch: true,
|
|
},
|
|
"digitalocean pat": {
|
|
ruleID: "digitalocean-pat",
|
|
input: `dop_v1_abcdef01234567890abcdef01234567890abcdef01234567890abcdef0123456`,
|
|
wantMatch: true,
|
|
wantGroup: "dop_v1_abcdef01234567890abcdef01234567890abcdef01234567890abcdef0123456",
|
|
},
|
|
"linear api key": {
|
|
ruleID: "linear-api-key",
|
|
input: `lin_api_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmN`,
|
|
wantMatch: true,
|
|
},
|
|
"age secret key": {
|
|
ruleID: "age-secret-key",
|
|
input: `AGE-SECRET-KEY-1QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ`,
|
|
wantMatch: true,
|
|
},
|
|
"doppler token": {
|
|
ruleID: "doppler-token",
|
|
input: `dp.st.aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmN`,
|
|
wantMatch: true,
|
|
},
|
|
"grafana sa token": {
|
|
ruleID: "grafana-api-key",
|
|
input: `glsa_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeF_12345678`,
|
|
wantMatch: true,
|
|
},
|
|
"grafana cloud token": {
|
|
ruleID: "grafana-cloud-token",
|
|
input: `glc_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeF1`,
|
|
wantMatch: true,
|
|
},
|
|
"databricks token": {
|
|
ruleID: "databricks-token",
|
|
input: `dapi1234567890abcdef1234567890abcdef`,
|
|
wantMatch: true,
|
|
wantGroup: "dapi1234567890abcdef1234567890abcdef",
|
|
},
|
|
"huggingface token": {
|
|
ruleID: "huggingface-token",
|
|
input: `hf_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJ`,
|
|
wantMatch: true,
|
|
wantGroup: "hf_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJ",
|
|
},
|
|
"netlify token": {
|
|
ruleID: "netlify-token",
|
|
input: `nfp_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmN`,
|
|
wantMatch: true,
|
|
},
|
|
"postman api key": {
|
|
ruleID: "postman-api-key",
|
|
input: `PMAK-abcdef0123456789abcdef01-abcdef0123456789abcdef0123456789ab`,
|
|
wantMatch: true,
|
|
},
|
|
"figma pat": {
|
|
ruleID: "figma-pat",
|
|
input: `figd_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmN`,
|
|
wantMatch: true,
|
|
},
|
|
"flyio token": {
|
|
ruleID: "flyio-token",
|
|
input: `fo1_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmN`,
|
|
wantMatch: true,
|
|
},
|
|
"planetscale token": {
|
|
ruleID: "planetscale-token",
|
|
input: `pscale_tkn_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmN`,
|
|
wantMatch: true,
|
|
},
|
|
"replicate token": {
|
|
ruleID: "replicate-api-token",
|
|
input: `r8_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqR`,
|
|
wantMatch: true,
|
|
},
|
|
"sentry auth token": {
|
|
ruleID: "sentry-auth-token",
|
|
input: `sntrys_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHi`,
|
|
wantMatch: true,
|
|
},
|
|
"atlassian token": {
|
|
ruleID: "atlassian-api-token",
|
|
input: `ATATTaBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHiJkLmNoPqRsTuVwX`,
|
|
wantMatch: true,
|
|
},
|
|
"render api key": {
|
|
ruleID: "render-api-key",
|
|
input: `rnd_aBcDeFgHiJkLmNoPqRsTuVwXyZaBcDeFgHi`,
|
|
wantMatch: true,
|
|
},
|
|
"launchdarkly sdk key": {
|
|
ruleID: "launchdarkly-sdk-key",
|
|
input: `sdk-a1b2c3d4-e5f6-7890-abcd-ef1234567890`,
|
|
wantMatch: true,
|
|
wantGroup: "sdk-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
},
|
|
"launchdarkly api key": {
|
|
ruleID: "launchdarkly-api-key",
|
|
input: `api-a1b2c3d4-e5f6-7890-abcd-ef1234567890`,
|
|
wantMatch: true,
|
|
wantGroup: "api-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
|
},
|
|
"okta api token": {
|
|
ruleID: "okta-api-token",
|
|
input: `OKTA_API_TOKEN = "00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl"`,
|
|
wantMatch: true,
|
|
wantGroup: "00ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijkl",
|
|
},
|
|
"okta ssws header": {
|
|
ruleID: "okta-api-token",
|
|
input: `SSWS = "00xK9mP2vL5nQ8jR3tB7wX4cD6eF8gH0iJ2kL"`,
|
|
wantMatch: true,
|
|
wantGroup: "00xK9mP2vL5nQ8jR3tB7wX4cD6eF8gH0iJ2kL",
|
|
},
|
|
"supabase service key": {
|
|
ruleID: "supabase-service-key",
|
|
input: `SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJzZXJ2aWNlX3JvbGUifQ.xxxxxxxx`,
|
|
wantMatch: true,
|
|
wantGroup: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJvbGUiOiJzZXJ2aWNlX3JvbGUifQ.xxxxxxxx",
|
|
},
|
|
"supabase service key quoted": {
|
|
ruleID: "supabase-service-key",
|
|
input: `SUPABASE_SERVICE_ROLE_KEY="eyJhbGciOiJIUzI1NiJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIn0.sig123"`,
|
|
wantMatch: true,
|
|
},
|
|
"no match on normal text": {
|
|
ruleID: "aws-access-key-id",
|
|
input: `this is just normal code`,
|
|
wantMatch: false,
|
|
},
|
|
}
|
|
|
|
reg := NewRegistry()
|
|
RegisterBuiltins(reg)
|
|
|
|
for name, tc := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
rule, ok := reg.Get(tc.ruleID)
|
|
require.True(t, ok, "rule %s not found", tc.ruleID)
|
|
|
|
match := rule.Pattern.FindStringSubmatch(tc.input)
|
|
if tc.wantMatch {
|
|
require.NotNil(t, match,
|
|
"expected pattern match for rule %s", tc.ruleID)
|
|
if tc.wantGroup != "" && rule.SecretGroup > 0 {
|
|
require.Greater(t, len(match), rule.SecretGroup)
|
|
assert.Equal(t, tc.wantGroup,
|
|
match[rule.SecretGroup])
|
|
}
|
|
} else {
|
|
assert.Nil(t, match,
|
|
"unexpected match for rule %s", tc.ruleID)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuiltinKeywordMatches(t *testing.T) {
|
|
t.Parallel()
|
|
reg := NewRegistry()
|
|
RegisterBuiltins(reg)
|
|
|
|
tests := map[string]struct {
|
|
content string
|
|
wantIDs []string
|
|
}{
|
|
"aws content": { //nolint:gosec
|
|
content: "found AKIAIOSFODNN7EXAMPLE in config",
|
|
wantIDs: []string{"aws-access-key-id"},
|
|
},
|
|
"github content": {
|
|
content: "token = ghp_abc123",
|
|
wantIDs: []string{"github-pat-classic"},
|
|
},
|
|
"stripe content": {
|
|
content: "key = sk_live_abc123",
|
|
wantIDs: []string{"stripe-live-secret"},
|
|
},
|
|
"private key content": { //nolint:gosec
|
|
content: "-----BEGIN RSA PRIVATE KEY-----",
|
|
wantIDs: []string{"ssh-private-key-rsa"},
|
|
},
|
|
"postgres content": { //nolint:gosec
|
|
content: "DATABASE_URL=postgres://user:pass@host/db",
|
|
wantIDs: []string{"postgres-connection"},
|
|
},
|
|
}
|
|
|
|
for name, tc := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
matched := reg.MatchKeywords(tc.content)
|
|
ids := make([]string, len(matched))
|
|
for i, r := range matched {
|
|
ids[i] = r.ID
|
|
}
|
|
for _, wantID := range tc.wantIDs {
|
|
assert.Contains(t, ids, wantID)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBuiltinNoFalsePositives(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
reg := NewRegistry()
|
|
RegisterBuiltins(reg)
|
|
|
|
benignInputs := []string{
|
|
`import os`,
|
|
`func main() {}`,
|
|
`const x = 42`,
|
|
`// this is a comment`,
|
|
`print("hello world")`,
|
|
`if err != nil { return err }`,
|
|
`for i := 0; i < 10; i++ {}`,
|
|
}
|
|
|
|
for _, rule := range reg.All() {
|
|
for _, input := range benignInputs {
|
|
match := rule.Pattern.FindString(input)
|
|
assert.Empty(t, match,
|
|
"rule %s false positive on: %s", rule.ID, input)
|
|
}
|
|
}
|
|
}
|