Skip to content

Commit

Permalink
Added tests for rule regexes
Browse files Browse the repository at this point in the history
  • Loading branch information
hectorm committed Apr 21, 2022
1 parent 9707f27 commit cc298d1
Show file tree
Hide file tree
Showing 2 changed files with 284 additions and 43 deletions.
66 changes: 35 additions & 31 deletions cetusguard/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,54 +32,58 @@ var (
"DOMAIN_OR_IP": `(?:%DOMAIN%|%IP%)`,
"HOST": `(?:%DOMAIN_OR_IP%(?::[0-9]+)?)`,

"IMAGE_ID": `(?:[a-fA-F0-9]+)`,
"IMAGE_ID": `%_OBJECT_ID%`,
"IMAGE_COMPONENT": `(?:[a-zA-Z0-9]+(?:(?:\.|_{1,2}|-+)[a-zA-Z0-9]+)*)`,
"IMAGE_TAG": `(?:[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127})`,
"IMAGE_DIGEST": `(?:[a-zA-Z][a-zA-Z0-9]*(?:[_.+-][a-zA-Z][a-zA-Z0-9]*)*:[a-fA-F0-9]{32,})`,
"IMAGE_NAME": `(?:(?:%HOST%/)?%IMAGE_COMPONENT%(?:/%IMAGE_COMPONENT%)*)`,
"IMAGE_REFERENCE": `(?:%IMAGE_NAME%(?::%IMAGE_TAG%)?(?:@%IMAGE_DIGEST%)?)`,
"IMAGE_ID_OR_REFERENCE": `(?:%IMAGE_ID%|%IMAGE_REFERENCE%)`,

"CONTAINER_ID": `(?:[a-fA-F0-9]+)`,
"CONTAINER_NAME": `(?:[a-zA-Z0-9][a-zA-Z0-9_.-]+)`,
"CONTAINER_ID": `%_OBJECT_ID%`,
"CONTAINER_NAME": `%_OBJECT_NAME%`,
"CONTAINER_ID_OR_NAME": `(?:%CONTAINER_ID%|%CONTAINER_NAME%)`,

"VOLUME_ID": `(?:[a-fA-F0-9]+)`,
"VOLUME_NAME": `(?:[a-zA-Z0-9][a-zA-Z0-9_.-]+)`,
"VOLUME_ID": `%_OBJECT_ID%`,
"VOLUME_NAME": `%_OBJECT_NAME%`,
"VOLUME_ID_OR_NAME": `(?:%VOLUME_ID%|%VOLUME_NAME%)`,

"NETWORK_ID": `(?:[a-fA-F0-9]+)`,
"NETWORK_ID": `%_OBJECT_ID%`,
"NETWORK_NAME": `(?:[^/]+)`,
"NETWORK_ID_OR_NAME": `(?:%NETWORK_ID%|%NETWORK_NAME%)`,

"PLUGIN_ID": `(?:[a-fA-F0-9]+)`,
"PLUGIN_ID": `%_OBJECT_ID%`,
"PLUGIN_NAME": `%IMAGE_NAME%`,
"PLUGIN_ID_OR_NAME": `(?:%PLUGIN_ID%|%PLUGIN_NAME%)`,

"API_PREFIX": `(?:/v[0-9]+(?:\.[0-9]+)*)?`,
"API_PREFIX_AUTH": `%API_PREFIX%/auth`,
"API_PREFIX_BUILD": `%API_PREFIX%/build`,
"API_PREFIX_COMMIT": `%API_PREFIX%/commit`,
"API_PREFIX_CONFIGS": `%API_PREFIX%/configs`,
"API_PREFIX_CONTAINERS": `%API_PREFIX%/containers`,
"API_PREFIX_DISTRIBUTION": `%API_PREFIX%/distribution`,
"API_PREFIX_EVENTS": `%API_PREFIX%/events`,
"API_PREFIX_EXEC": `%API_PREFIX%/exec`,
"API_PREFIX_GRPC": `%API_PREFIX%/grpc`,
"API_PREFIX_IMAGES": `%API_PREFIX%/images`,
"API_PREFIX_INFO": `%API_PREFIX%/info`,
"API_PREFIX_NETWORKS": `%API_PREFIX%/networks`,
"API_PREFIX_NODES": `%API_PREFIX%/nodes`,
"API_PREFIX_PING": `%API_PREFIX%/_ping`,
"API_PREFIX_PLUGINS": `%API_PREFIX%/plugins`,
"API_PREFIX_SECRETS": `%API_PREFIX%/secrets`,
"API_PREFIX_SERVICES": `%API_PREFIX%/services`,
"API_PREFIX_SESSION": `%API_PREFIX%/session`,
"API_PREFIX_SWARM": `%API_PREFIX%/swarm`,
"API_PREFIX_SYSTEM": `%API_PREFIX%/system`,
"API_PREFIX_TASKS": `%API_PREFIX%/tasks`,
"API_PREFIX_VERSION": `%API_PREFIX%/version`,
"API_PREFIX_VOLUMES": `%API_PREFIX%/volumes`,
"API_PREFIX": `(?:/v[0-9]+(?:\.[0-9]+)*)`,
"API_PREFIX_AUTH": `%API_PREFIX%?/auth`,
"API_PREFIX_BUILD": `%API_PREFIX%?/build`,
"API_PREFIX_COMMIT": `%API_PREFIX%?/commit`,
"API_PREFIX_CONFIGS": `%API_PREFIX%?/configs`,
"API_PREFIX_CONTAINERS": `%API_PREFIX%?/containers`,
"API_PREFIX_DISTRIBUTION": `%API_PREFIX%?/distribution`,
"API_PREFIX_EVENTS": `%API_PREFIX%?/events`,
"API_PREFIX_EXEC": `%API_PREFIX%?/exec`,
"API_PREFIX_GRPC": `%API_PREFIX%?/grpc`,
"API_PREFIX_IMAGES": `%API_PREFIX%?/images`,
"API_PREFIX_INFO": `%API_PREFIX%?/info`,
"API_PREFIX_NETWORKS": `%API_PREFIX%?/networks`,
"API_PREFIX_NODES": `%API_PREFIX%?/nodes`,
"API_PREFIX_PING": `%API_PREFIX%?/_ping`,
"API_PREFIX_PLUGINS": `%API_PREFIX%?/plugins`,
"API_PREFIX_SECRETS": `%API_PREFIX%?/secrets`,
"API_PREFIX_SERVICES": `%API_PREFIX%?/services`,
"API_PREFIX_SESSION": `%API_PREFIX%?/session`,
"API_PREFIX_SWARM": `%API_PREFIX%?/swarm`,
"API_PREFIX_SYSTEM": `%API_PREFIX%?/system`,
"API_PREFIX_TASKS": `%API_PREFIX%?/tasks`,
"API_PREFIX_VERSION": `%API_PREFIX%?/version`,
"API_PREFIX_VOLUMES": `%API_PREFIX%?/volumes`,

// Private built-ins, may change in any version
"_OBJECT_ID": `(?:[a-fA-F0-9]+)`,
"_OBJECT_NAME": `(?:[a-zA-Z0-9][a-zA-Z0-9_.-]+)`,
}
)

Expand Down
261 changes: 249 additions & 12 deletions cetusguard/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,19 @@ func TestBuildDefaultRules(t *testing.T) {

func TestBuildValidRules(t *testing.T) {
rawRules := map[string]Rule{
"! Comment\nGET,HEAD %API_PREFIX%/test01\n": {
"! Comment\nGET,HEAD %API_PREFIX%?/test01\n": {
Methods: map[string]bool{"GET": true, "HEAD": true},
Pattern: regexp.MustCompile(`^(?:/v[0-9]+(?:\.[0-9]+)*)?/test01$`),
},
"! Comment\r\nGET,HEAD %API_PREFIX%/test02\r\n": {
"! Comment\r\nGET,HEAD %API_PREFIX%?/test02\r\n": {
Methods: map[string]bool{"GET": true, "HEAD": true},
Pattern: regexp.MustCompile(`^(?:/v[0-9]+(?:\.[0-9]+)*)?/test02$`),
},
"\n\n\n! Comment\n\n\nGET,HEAD %API_PREFIX%/test03\n\n\n": {
"\n\n\n! Comment\n\n\nGET,HEAD %API_PREFIX%?/test03\n\n\n": {
Methods: map[string]bool{"GET": true, "HEAD": true},
Pattern: regexp.MustCompile(`^(?:/v[0-9]+(?:\.[0-9]+)*)?/test03$`),
},
" \t ! Comment\n \t GET,HEAD \t %API_PREFIX%/test04 \t ": {
" \t ! Comment\n \t GET,HEAD \t %API_PREFIX%?/test04 \t ": {
Methods: map[string]bool{"GET": true, "HEAD": true},
Pattern: regexp.MustCompile(`^(?:/v[0-9]+(?:\.[0-9]+)*)?/test04$`),
},
Expand All @@ -78,14 +78,14 @@ func TestBuildValidRules(t *testing.T) {

func TestBuildInvalidRules(t *testing.T) {
rawRules := []string{
"%API_PREFIX%/test01",
", %API_PREFIX%/test02",
"GET, %API_PREFIX%/test03",
"GET,HEAD, %API_PREFIX%/test04",
"GET %API_PREFIX%/[9-0]+/test05",
"GET %API_PREFIX%/\x81/test06",
"GET\n%API_PREFIX%/test07",
"GET\r\n%API_PREFIX%/test08",
"%API_PREFIX%?/test01",
", %API_PREFIX%?/test02",
"GET, %API_PREFIX%?/test03",
"GET,HEAD, %API_PREFIX%?/test04",
"GET %API_PREFIX%?/[9-0]+/test05",
"GET %API_PREFIX%?/\x81/test06",
"GET\n%API_PREFIX%?/test07",
"GET\r\n%API_PREFIX%?/test08",
}

for _, v := range rawRules {
Expand Down Expand Up @@ -171,3 +171,240 @@ func TestBuildRulesFromNonexistentPath(t *testing.T) {
t.Errorf("builtRules = %v, want an error", builtRules)
}
}

func TestDomainRegex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["DOMAIN"] + "$")

testCases := map[string]bool{
"": false,
"l": true,
"localhost": true,
"-localhost": false,
"localhost-": false,
"sub.example.test": true,
"sub.-example.test": false,
"sub.example-.test": false,
"001.test": true,
"xn--7o8h.test": true,
"a.a.a.a.a.a.a": true,
"a.a.a...a.a.a": false,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestIpv4Regex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["IPV4"] + "$")

testCases := map[string]bool{
"": false,
"0": false,
"0.0": false,
"0.0.0.0.0": false,
"0.0.0.0": true,
"255.255.255.255": true,
"1111.0.0.0": false,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestIpv6Regex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["IPV6"] + "$")

testCases := map[string]bool{
"": false,
"::": false,
"[]": false,
"[::]": true,
"[::1]": true,
"[f:f:f:f:f:f:f:f]": true,
"[f:f:f:f:f:f:f:x]": false,
"[f:f:f:f:f:f:f:f:f]": false,
"[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]": true,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestHostRegex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["HOST"] + "$")

testCases := map[string]bool{
"": false,
"localhost": true,
"localhost:": false,
"localhost:2375": true,
"localhost:aaaa": false,
"sub.example.test": true,
"sub.example.test:": false,
"sub.example.test:2375": true,
"sub.example.test:aaaa": false,
"127.0.0.1": true,
"127.0.0.1:": false,
"127.0.0.1:2375": true,
"127.0.0.1:aaaa": false,
"[::1]": true,
"[::1]:": false,
"[::1]:2375": true,
"[::1]:aaaa": false,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestObjectIdRegex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["_OBJECT_ID"] + "$")

testCases := map[string]bool{
"": false,
"0123456789abcdef": true,
"0123456789x": false,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestObjectNameRegex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["_OBJECT_NAME"] + "$")

testCases := map[string]bool{
"": false,
"x": false,
"x0": true,
"0x": true,
"xx": true,
"xx_.-": true,
"-xx": false,
"busybox": true,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestImageReferenceRegex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["IMAGE_REFERENCE"] + "$")

testCases := map[string]bool{
"": false,
"b": true,
"busybox": true,
"busybox:": false,
"busybox:l": true,
"busybox:latest": true,
"busybox:latest@": false,
"busybox:latest@sha256": false,
"busybox:latest@sha256:": false,
"busybox:latest@sha256:x": false,
"busybox:latest@sha256:09c731d73926315908778730f9e6068": false,
"busybox:latest@sha256:09c731d73926315908778730f9e60686": true,
"busybox:latest@sha256:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": true,
"busybox@sha256:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": true,
"busybox@sha256-:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": false,
"busybox@sha256-test:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": true,
"busybox@sha256--test:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": false,
"busybox@sha256-0test:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": false,
"busybox@sha256-test0:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": true,
"busybox@sha256_test:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": true,
"[email protected]:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": true,
"busybox@sha256+test:09c731d73926315908778730f9e606864fb72f1523d5c1c81c02dc51563885ba": true,
"docker.io/busybox:latest": true,
"docker.io/library/busybox:latest": true,
"localhost:5000/library/busybox:latest": true,
"127.0.0.1:5000/library/busybox:latest": true,
"[::1]:5000/library/busybox:latest": true,
"-busybox:latest": false,
"busybox:-latest": false,
"docker.io/-library/busybox:latest": false,
"docker.io/foo/bar/busybox:latest": true,
"docker.io/foo.bar/busybox:latest": true,
"docker.io/foo..bar/busybox:latest": false,
"docker.io/foo_bar/busybox:latest": true,
"docker.io/foo__bar/busybox:latest": true,
"docker.io/foo___bar/busybox:latest": false,
"docker.io/foo-bar/busybox:latest": true,
"docker.io/foo--bar/busybox:latest": true,
"docker.io/foo---bar/busybox:latest": true,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestApiPrefixRegex(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["API_PREFIX"] + "$")

testCases := map[string]bool{
"": false,
"/": false,
"/v": false,
"/v9": true,
"/v99": true,
"/v99.9": true,
"/v99.99": true,
"/v99.99.9": true,
"/v99.99.99": true,
"/9.9": false,
"/v9.9/": false,
"/v9.9.": false,
"/v.9.9": false,
"/v9..9": false,
"/va.a": false,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

func TestApiPrefixPing(t *testing.T) {
re := regexp.MustCompile("^" + ruleBuiltins["API_PREFIX_PING"] + "$")

testCases := map[string]bool{
"": false,
"/": false,
"/_ping": true,
"/_ping/": false,
"/_pong": false,
"_ping": false,
"//_ping": false,
"/v9.9/": false,
"/v9.9/_ping": true,
"v9.9/_ping": false,
}

for input, wanted := range testCases {
if result := re.MatchString(input); result != wanted {
t.Errorf("\"%s\" match = %t, want = %t", input, result, wanted)
}
}
}

0 comments on commit cc298d1

Please sign in to comment.