-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathedge_cases_test.go
More file actions
157 lines (136 loc) · 5.29 KB
/
Copy pathedge_cases_test.go
File metadata and controls
157 lines (136 loc) · 5.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package portcullis_test
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/docker/portcullis"
)
// TestNoisyKeywordsFalsePositives verifies that common text patterns
// containing the noisy keywords don't trigger false positives.
func TestNoisyKeywordsFalsePositives(t *testing.T) {
t.Parallel()
cases := []struct {
name string
text string
}{
// :AA keyword - should NOT match times or other contexts
{"time_with_AA", "Meeting at 12:00 AA tomorrow"},
{"AA_abbreviation", "The AA battery is dead"},
{"AA_in_text", "AA is a common abbreviation"},
// sk. keyword - should NOT match common English words
{"ask_sentence", "I ask. Can you help?"},
{"disk_sentence", "The disk. is full"},
{"risk_sentence", "The risk. is high"},
// 1/ keyword - should NOT match simple fractions or paths
{"simple_fraction", "1/2 cup of sugar"},
{"short_path", "1/home/user"},
{"date_like", "1/1/2024"},
// v1.0- keyword - should NOT match version strings without the full pattern
{"version_string", "v1.0-beta"},
{"version_release", "v1.0-rc1"},
// Vendor names mentioned in prose without an assignment must
// not trigger the contextual rules added in the sixth batch.
// Each rule's regex requires `<vendor>...=...<value>` shape;
// a bare mention should slip through the keyword filter and
// the regex without matching.
{"datadog_in_prose", "We monitor the cluster with Datadog dashboards."},
{"snyk_in_prose", "Snyk found three high-severity issues this week."},
{"cloudflare_in_prose", "Cloudflare DDOS protection is enabled."},
{"travis_in_prose", "Travis CI is now archived; we moved to GitHub Actions."},
{"sumo_in_prose", "sumo wrestling is a Japanese sport."},
{"airtable_in_prose", "Airtable bases are like spreadsheets."},
// New seventh-batch keywords that could be noisy.
{"sdk_in_prose", "Install the android-sdk-tools package."},
{"mysql_without_password", "mysql://localhost:3306/mydb"},
{"redis_without_password", "redis://localhost:6379"},
{"amqp_without_password", "amqp://localhost:5672"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
result := portcullis.Contains(tc.text)
assert.Falsef(t, result, "should not detect secret in: %q", tc.text)
})
}
}
// TestDiscordTokenPrefixes verifies all documented Discord bot token prefixes.
func TestDiscordTokenPrefixes(t *testing.T) {
t.Parallel()
// Test all documented prefixes
prefixes := []string{"MT", "Mz", "ND", "NT", "Nz", "OD"}
for _, prefix := range prefixes {
t.Run("prefix_"+prefix, func(t *testing.T) {
t.Parallel()
token := prefix + strings.Repeat("A", 22) + "." + strings.Repeat("B", 6) + "." + strings.Repeat("C", 30)
assert.Truef(t, portcullis.Contains(token),
"should detect Discord token with prefix %s", prefix)
})
}
}
// TestConnectionStringContextPreservation verifies that MongoDB, Postgres,
// and Azure Storage connection strings only redact the password/key portion.
func TestConnectionStringContextPreservation(t *testing.T) {
t.Parallel()
cases := []struct {
name string
input string
mustHave []string
mustNotHave string
}{
{
name: "mongodb_preserves_user_and_host",
input: "mongodb://myuser:secretpassword123@cluster.mongodb.net/mydb",
mustHave: []string{"mongodb://", "myuser", "@cluster.mongodb.net"},
mustNotHave: "secretpassword123",
},
{
name: "postgres_preserves_user_and_host",
input: "postgresql://dbuser:secretpass456@db.example.com:5432/mydb",
mustHave: []string{"postgresql://", "dbuser", "@db.example.com"},
mustNotHave: "secretpass456",
},
{
name: "azure_storage_preserves_account_name",
input: "DefaultEndpointsProtocol=https;AccountName=mystorage;AccountKey=" + strings.Repeat("a", 86) + "==",
mustHave: []string{"DefaultEndpointsProtocol=https", "AccountName=mystorage", "AccountKey="},
mustNotHave: strings.Repeat("a", 86) + "==",
},
{
name: "mysql_preserves_user_and_host",
input: "mysql://appuser:secretpass789@db.example.com:3306/mydb",
mustHave: []string{"mysql://", "appuser", "@db.example.com"},
mustNotHave: "secretpass789",
},
{
name: "redis_preserves_user_and_host",
input: "redis://default:redispass123@cache.example.com:6379/0",
mustHave: []string{"redis://", "default", "@cache.example.com"},
mustNotHave: "redispass123",
},
{
name: "redis_no_user_preserves_host",
input: "redis://:redispass456@cache.example.com:6379",
mustHave: []string{"redis://", "@cache.example.com"},
mustNotHave: "redispass456",
},
{
name: "amqp_preserves_user_and_host",
input: "amqp://guest:rabbitpass789@rabbit.example.com:5672/vhost",
mustHave: []string{"amqp://", "guest", "@rabbit.example.com"},
mustNotHave: "rabbitpass789",
},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
assert.True(t, portcullis.Contains(tc.input), "should detect secret")
redacted := portcullis.Redact(tc.input)
for _, must := range tc.mustHave {
assert.Containsf(t, redacted, must,
"redacted output should preserve: %s", must)
}
assert.NotContainsf(t, redacted, tc.mustNotHave,
"redacted output must not contain secret: %s", tc.mustNotHave)
})
}
}