// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 package acl import ( "strings" "testing" "github.com/stretchr/testify/require" ) func errStartsWith(t *testing.T, actual error, expected string) { t.Helper() require.Error(t, actual) require.Truef(t, strings.HasPrefix(actual.Error(), expected), "Received unexpected error: %#v\nExpecting an error with the prefix: %q", actual, expected) } func TestPolicySourceParse(t *testing.T) { cases := []struct { Name string Rules string RulesJSON string Expected *Policy Err string }{ { Name: "Basic", Rules: ` agent_prefix "bar" { policy = "write" } agent "foo" { policy = "read" } event_prefix "" { policy = "read" } event "foo" { policy = "write" } event "bar" { policy = "deny" } identity_prefix "" { policy = "write" } identity "foo" { policy = "read" } key_prefix "" { policy = "read" } key_prefix "foo/" { policy = "write" } key_prefix "foo/bar/" { policy = "read" } key "foo/bar/baz" { policy = "deny" } keyring = "deny" node_prefix "" { policy = "read" } node "foo" { policy = "write" } node "bar" { policy = "deny" } operator = "deny" mesh = "deny" peering = "deny" service_prefix "" { policy = "write" } service "foo" { policy = "read" } session "foo" { policy = "write" } session "bar" { policy = "deny" } session_prefix "baz" { policy = "deny" } query_prefix "" { policy = "read" } query "foo" { policy = "write" } query "bar" { policy = "deny" } `, RulesJSON: ` { "agent_prefix": { "bar": { "policy": "write" } }, "agent": { "foo": { "policy": "read" } }, "event_prefix": { "": { "policy": "read" } }, "event": { "foo": { "policy": "write" }, "bar": { "policy": "deny" } }, "identity_prefix": { "": { "policy": "write" } }, "identity": { "foo": { "policy": "read" } }, "key_prefix": { "": { "policy": "read" }, "foo/": { "policy": "write" }, "foo/bar/": { "policy": "read" } }, "key": { "foo/bar/baz": { "policy": "deny" } }, "keyring": "deny", "node_prefix": { "": { "policy": "read" } }, "node": { "foo": { "policy": "write" }, "bar": { "policy": "deny" } }, "operator": "deny", "mesh": "deny", "peering": "deny", "service_prefix": { "": { "policy": "write" } }, "service": { "foo": { "policy": "read" } }, "session_prefix": { "baz": { "policy": "deny" } }, "session": { "foo": { "policy": "write" }, "bar": { "policy": "deny" } }, "query_prefix": { "": { "policy": "read" } }, "query": { "foo": { "policy": "write" }, "bar": { "policy": "deny" } } } `, Expected: &Policy{PolicyRules: PolicyRules{ AgentPrefixes: []*AgentRule{ { Node: "bar", Policy: PolicyWrite, }, }, Agents: []*AgentRule{ { Node: "foo", Policy: PolicyRead, }, }, EventPrefixes: []*EventRule{ { Event: "", Policy: PolicyRead, }, }, Events: []*EventRule{ { Event: "foo", Policy: PolicyWrite, }, { Event: "bar", Policy: PolicyDeny, }, }, IdentityPrefixes: []*IdentityRule{ { Name: "", Policy: PolicyWrite, }, }, Identities: []*IdentityRule{ { Name: "foo", Policy: PolicyRead, }, }, Keyring: PolicyDeny, KeyPrefixes: []*KeyRule{ { Prefix: "", Policy: PolicyRead, }, { Prefix: "foo/", Policy: PolicyWrite, }, { Prefix: "foo/bar/", Policy: PolicyRead, }, }, Keys: []*KeyRule{ { Prefix: "foo/bar/baz", Policy: PolicyDeny, }, }, NodePrefixes: []*NodeRule{ { Name: "", Policy: PolicyRead, }, }, Nodes: []*NodeRule{ { Name: "foo", Policy: PolicyWrite, }, { Name: "bar", Policy: PolicyDeny, }, }, Operator: PolicyDeny, Mesh: PolicyDeny, Peering: PolicyDeny, PreparedQueryPrefixes: []*PreparedQueryRule{ { Prefix: "", Policy: PolicyRead, }, }, PreparedQueries: []*PreparedQueryRule{ { Prefix: "foo", Policy: PolicyWrite, }, { Prefix: "bar", Policy: PolicyDeny, }, }, ServicePrefixes: []*ServiceRule{ { Name: "", Policy: PolicyWrite, }, }, Services: []*ServiceRule{ { Name: "foo", Policy: PolicyRead, }, }, SessionPrefixes: []*SessionRule{ { Node: "baz", Policy: PolicyDeny, }, }, Sessions: []*SessionRule{ { Node: "foo", Policy: PolicyWrite, }, { Node: "bar", Policy: PolicyDeny, }, }, }}, }, { Name: "Identity No Intentions", Rules: `identity "foo" { policy = "write" }`, RulesJSON: `{ "identity": { "foo": { "policy": "write" }}}`, Expected: &Policy{PolicyRules: PolicyRules{ Identities: []*IdentityRule{ { Name: "foo", Policy: "write", }, }, }}, }, { Name: "Identity Intentions", Rules: `identity "foo" { policy = "write" intentions = "read" }`, RulesJSON: `{ "identity": { "foo": { "policy": "write", "intentions": "read" }}}`, Expected: &Policy{PolicyRules: PolicyRules{ Identities: []*IdentityRule{ { Name: "foo", Policy: "write", Intentions: "read", }, }, }}, }, { Name: "Identity Intention: invalid value", Rules: `identity "foo" { policy = "write" intentions = "foo" }`, RulesJSON: `{ "identity": { "foo": { "policy": "write", "intentions": "foo" }}}`, Err: "Invalid identity intentions policy", }, { Name: "Service No Intentions", Rules: `service "foo" { policy = "write" }`, RulesJSON: `{ "service": { "foo": { "policy": "write" }}}`, Expected: &Policy{PolicyRules: PolicyRules{ Services: []*ServiceRule{ { Name: "foo", Policy: "write", }, }, }}, }, { Name: "Service Intentions", Rules: `service "foo" { policy = "write" intentions = "read" }`, RulesJSON: `{ "service": { "foo": { "policy": "write", "intentions": "read" }}}`, Expected: &Policy{PolicyRules: PolicyRules{ Services: []*ServiceRule{ { Name: "foo", Policy: "write", Intentions: "read", }, }, }}, }, { Name: "Service Intention: invalid value", Rules: `service "foo" { policy = "write" intentions = "foo" }`, RulesJSON: `{ "service": { "foo": { "policy": "write", "intentions": "foo" }}}`, Err: "Invalid service intentions policy", }, { Name: "Bad Policy - ACL", Rules: `acl = "list"`, // there is no list policy but this helps to exercise another check in isPolicyValid RulesJSON: `{ "acl": "list" }`, // there is no list policy but this helps to exercise another check in isPolicyValid Err: "Invalid acl policy", }, { Name: "Bad Policy - Agent", Rules: `agent "foo" { policy = "nope" }`, RulesJSON: `{ "agent": { "foo": { "policy": "nope" }}}`, Err: "Invalid agent policy", }, { Name: "Bad Policy - Agent Prefix", Rules: `agent_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "agent_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid agent_prefix policy", }, { Name: "Bad Policy - Identity", Rules: `identity "foo" { policy = "nope" }`, RulesJSON: `{ "identity": { "foo": { "policy": "nope" }}}`, Err: "Invalid identity policy", }, { Name: "Bad Policy - Identity Prefix", Rules: `identity_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "identity_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid identity_prefix policy", }, { Name: "Bad Policy - Key", Rules: `key "foo" { policy = "nope" }`, RulesJSON: `{ "key": { "foo": { "policy": "nope" }}}`, Err: "Invalid key policy", }, { Name: "Bad Policy - Key Prefix", Rules: `key_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "key_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid key_prefix policy", }, { Name: "Bad Policy - Node", Rules: `node "foo" { policy = "nope" }`, RulesJSON: `{ "node": { "foo": { "policy": "nope" }}}`, Err: "Invalid node policy", }, { Name: "Bad Policy - Node Prefix", Rules: `node_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "node_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid node_prefix policy", }, { Name: "Bad Policy - Service", Rules: `service "foo" { policy = "nope" }`, RulesJSON: `{ "service": { "foo": { "policy": "nope" }}}`, Err: "Invalid service policy", }, { Name: "Bad Policy - Service Prefix", Rules: `service_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "service_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid service_prefix policy", }, { Name: "Bad Policy - Session", Rules: `session "foo" { policy = "nope" }`, RulesJSON: `{ "session": { "foo": { "policy": "nope" }}}`, Err: "Invalid session policy", }, { Name: "Bad Policy - Session Prefix", Rules: `session_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "session_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid session_prefix policy", }, { Name: "Bad Policy - Event", Rules: `event "foo" { policy = "nope" }`, RulesJSON: `{ "event": { "foo": { "policy": "nope" }}}`, Err: "Invalid event policy", }, { Name: "Bad Policy - Event Prefix", Rules: `event_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "event_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid event_prefix policy", }, { Name: "Bad Policy - Prepared Query", Rules: `query "foo" { policy = "nope" }`, RulesJSON: `{ "query": { "foo": { "policy": "nope" }}}`, Err: "Invalid query policy", }, { Name: "Bad Policy - Prepared Query Prefix", Rules: `query_prefix "foo" { policy = "nope" }`, RulesJSON: `{ "query_prefix": { "foo": { "policy": "nope" }}}`, Err: "Invalid query_prefix policy", }, { Name: "Bad Policy - Keyring", Rules: `keyring = "nope"`, RulesJSON: `{ "keyring": "nope" }`, Err: "Invalid keyring policy", }, { Name: "Bad Policy - Operator", Rules: `operator = "nope"`, RulesJSON: `{ "operator": "nope" }`, Err: "Invalid operator policy", }, { Name: "Bad Policy - Mesh", Rules: `mesh = "nope"`, RulesJSON: `{ "mesh": "nope" }`, Err: "Invalid mesh policy", }, { Name: "Bad Policy - Peering", Rules: `peering = "nope"`, RulesJSON: `{ "peering": "nope" }`, Err: "Invalid peering policy", }, { Name: "Keyring Empty", Rules: `keyring = ""`, RulesJSON: `{ "keyring": "" }`, Expected: &Policy{PolicyRules: PolicyRules{Keyring: ""}}, }, { Name: "Operator Empty", Rules: `operator = ""`, RulesJSON: `{ "operator": "" }`, Expected: &Policy{PolicyRules: PolicyRules{Operator: ""}}, }, { Name: "Mesh Empty", Rules: `mesh = ""`, RulesJSON: `{ "mesh": "" }`, Expected: &Policy{PolicyRules: PolicyRules{Mesh: ""}}, }, { Name: "Peering Empty", Rules: `peering = ""`, RulesJSON: `{ "peering": "" }`, Expected: &Policy{PolicyRules: PolicyRules{Peering: ""}}, }, } for _, tc := range cases { t.Run(tc.Name, func(t *testing.T) { require.True(t, tc.Rules != "" || tc.RulesJSON != "") if tc.Rules != "" { t.Run("hcl", func(t *testing.T) { actual, err := NewPolicyFromSource(tc.Rules, nil, nil) if tc.Err != "" { errStartsWith(t, err, tc.Err) } else { require.Equal(t, tc.Expected, actual) } }) } if tc.RulesJSON != "" { t.Run("json", func(t *testing.T) { actual, err := NewPolicyFromSource(tc.RulesJSON, nil, nil) if tc.Err != "" { errStartsWith(t, err, tc.Err) } else { require.Equal(t, tc.Expected, actual) } }) } }) } } func TestMergePolicies(t *testing.T) { type mergeTest struct { name string input []*Policy expected *Policy } tests := []mergeTest{ { name: "Agents", input: []*Policy{ {PolicyRules: PolicyRules{ Agents: []*AgentRule{ { Node: "foo", Policy: PolicyWrite, }, { Node: "bar", Policy: PolicyRead, }, { Node: "baz", Policy: PolicyWrite, }, }, AgentPrefixes: []*AgentRule{ { Node: "000", Policy: PolicyWrite, }, { Node: "111", Policy: PolicyRead, }, { Node: "222", Policy: PolicyWrite, }, }, }}, {PolicyRules: PolicyRules{ Agents: []*AgentRule{ { Node: "foo", Policy: PolicyRead, }, { Node: "baz", Policy: PolicyDeny, }, }, AgentPrefixes: []*AgentRule{ { Node: "000", Policy: PolicyRead, }, { Node: "222", Policy: PolicyDeny, }, }, }, }}, expected: &Policy{PolicyRules: PolicyRules{ Agents: []*AgentRule{ { Node: "foo", Policy: PolicyWrite, }, { Node: "bar", Policy: PolicyRead, }, { Node: "baz", Policy: PolicyDeny, }, }, AgentPrefixes: []*AgentRule{ { Node: "000", Policy: PolicyWrite, }, { Node: "111", Policy: PolicyRead, }, { Node: "222", Policy: PolicyDeny, }, }, }}, }, { name: "Events", input: []*Policy{ {PolicyRules: PolicyRules{ Events: []*EventRule{ { Event: "foo", Policy: PolicyWrite, }, { Event: "bar", Policy: PolicyRead, }, { Event: "baz", Policy: PolicyWrite, }, }, EventPrefixes: []*EventRule{ { Event: "000", Policy: PolicyWrite, }, { Event: "111", Policy: PolicyRead, }, { Event: "222", Policy: PolicyWrite, }, }, }}, {PolicyRules: PolicyRules{ Events: []*EventRule{ { Event: "foo", Policy: PolicyRead, }, { Event: "baz", Policy: PolicyDeny, }, }, EventPrefixes: []*EventRule{ { Event: "000", Policy: PolicyRead, }, { Event: "222", Policy: PolicyDeny, }, }, }}, }, expected: &Policy{PolicyRules: PolicyRules{ Events: []*EventRule{ { Event: "foo", Policy: PolicyWrite, }, { Event: "bar", Policy: PolicyRead, }, { Event: "baz", Policy: PolicyDeny, }, }, EventPrefixes: []*EventRule{ { Event: "000", Policy: PolicyWrite, }, { Event: "111", Policy: PolicyRead, }, { Event: "222", Policy: PolicyDeny, }, }, }}, }, { name: "Identities", input: []*Policy{ {PolicyRules: PolicyRules{ Identities: []*IdentityRule{ { Name: "foo", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "bar", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "baz", Policy: PolicyWrite, Intentions: PolicyWrite, }, }, IdentityPrefixes: []*IdentityRule{ { Name: "000", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "111", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "222", Policy: PolicyWrite, Intentions: PolicyWrite, }, }, }}, {PolicyRules: PolicyRules{ Identities: []*IdentityRule{ { Name: "foo", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "baz", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, IdentityPrefixes: []*IdentityRule{ { Name: "000", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "222", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, }}, }, expected: &Policy{PolicyRules: PolicyRules{ Identities: []*IdentityRule{ { Name: "foo", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "bar", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "baz", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, IdentityPrefixes: []*IdentityRule{ { Name: "000", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "111", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "222", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, }}, }, { name: "Node", input: []*Policy{ {PolicyRules: PolicyRules{ Nodes: []*NodeRule{ { Name: "foo", Policy: PolicyWrite, }, { Name: "bar", Policy: PolicyRead, }, { Name: "baz", Policy: PolicyWrite, }, }, NodePrefixes: []*NodeRule{ { Name: "000", Policy: PolicyWrite, }, { Name: "111", Policy: PolicyRead, }, { Name: "222", Policy: PolicyWrite, }, }, }}, {PolicyRules: PolicyRules{ Nodes: []*NodeRule{ { Name: "foo", Policy: PolicyRead, }, { Name: "baz", Policy: PolicyDeny, }, }, NodePrefixes: []*NodeRule{ { Name: "000", Policy: PolicyRead, }, { Name: "222", Policy: PolicyDeny, }, }, }, }}, expected: &Policy{PolicyRules: PolicyRules{ Nodes: []*NodeRule{ { Name: "foo", Policy: PolicyWrite, }, { Name: "bar", Policy: PolicyRead, }, { Name: "baz", Policy: PolicyDeny, }, }, NodePrefixes: []*NodeRule{ { Name: "000", Policy: PolicyWrite, }, { Name: "111", Policy: PolicyRead, }, { Name: "222", Policy: PolicyDeny, }, }, }}, }, { name: "Keys", input: []*Policy{ {PolicyRules: PolicyRules{ Keys: []*KeyRule{ { Prefix: "foo", Policy: PolicyWrite, }, { Prefix: "bar", Policy: PolicyRead, }, { Prefix: "baz", Policy: PolicyWrite, }, { Prefix: "zoo", Policy: PolicyList, }, }, KeyPrefixes: []*KeyRule{ { Prefix: "000", Policy: PolicyWrite, }, { Prefix: "111", Policy: PolicyRead, }, { Prefix: "222", Policy: PolicyWrite, }, { Prefix: "333", Policy: PolicyList, }, }, }}, {PolicyRules: PolicyRules{ Keys: []*KeyRule{ { Prefix: "foo", Policy: PolicyRead, }, { Prefix: "baz", Policy: PolicyDeny, }, { Prefix: "zoo", Policy: PolicyRead, }, }, KeyPrefixes: []*KeyRule{ { Prefix: "000", Policy: PolicyRead, }, { Prefix: "222", Policy: PolicyDeny, }, { Prefix: "333", Policy: PolicyRead, }, }, }}, }, expected: &Policy{PolicyRules: PolicyRules{ Keys: []*KeyRule{ { Prefix: "foo", Policy: PolicyWrite, }, { Prefix: "bar", Policy: PolicyRead, }, { Prefix: "baz", Policy: PolicyDeny, }, { Prefix: "zoo", Policy: PolicyList, }, }, KeyPrefixes: []*KeyRule{ { Prefix: "000", Policy: PolicyWrite, }, { Prefix: "111", Policy: PolicyRead, }, { Prefix: "222", Policy: PolicyDeny, }, { Prefix: "333", Policy: PolicyList, }, }, }}, }, { name: "Services", input: []*Policy{ {PolicyRules: PolicyRules{ Services: []*ServiceRule{ { Name: "foo", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "bar", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "baz", Policy: PolicyWrite, Intentions: PolicyWrite, }, }, ServicePrefixes: []*ServiceRule{ { Name: "000", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "111", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "222", Policy: PolicyWrite, Intentions: PolicyWrite, }, }, }}, {PolicyRules: PolicyRules{ Services: []*ServiceRule{ { Name: "foo", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "baz", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, ServicePrefixes: []*ServiceRule{ { Name: "000", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "222", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, }}, }, expected: &Policy{PolicyRules: PolicyRules{ Services: []*ServiceRule{ { Name: "foo", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "bar", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "baz", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, ServicePrefixes: []*ServiceRule{ { Name: "000", Policy: PolicyWrite, Intentions: PolicyWrite, }, { Name: "111", Policy: PolicyRead, Intentions: PolicyRead, }, { Name: "222", Policy: PolicyDeny, Intentions: PolicyDeny, }, }, }}, }, { name: "Sessions", input: []*Policy{ {PolicyRules: PolicyRules{ Sessions: []*SessionRule{ { Node: "foo", Policy: PolicyWrite, }, { Node: "bar", Policy: PolicyRead, }, { Node: "baz", Policy: PolicyWrite, }, }, SessionPrefixes: []*SessionRule{ { Node: "000", Policy: PolicyWrite, }, { Node: "111", Policy: PolicyRead, }, { Node: "222", Policy: PolicyWrite, }, }, }}, {PolicyRules: PolicyRules{ Sessions: []*SessionRule{ { Node: "foo", Policy: PolicyRead, }, { Node: "baz", Policy: PolicyDeny, }, }, SessionPrefixes: []*SessionRule{ { Node: "000", Policy: PolicyRead, }, { Node: "222", Policy: PolicyDeny, }, }, }}, }, expected: &Policy{PolicyRules: PolicyRules{ Sessions: []*SessionRule{ { Node: "foo", Policy: PolicyWrite, }, { Node: "bar", Policy: PolicyRead, }, { Node: "baz", Policy: PolicyDeny, }, }, SessionPrefixes: []*SessionRule{ { Node: "000", Policy: PolicyWrite, }, { Node: "111", Policy: PolicyRead, }, { Node: "222", Policy: PolicyDeny, }, }, }}, }, { name: "Prepared Queries", input: []*Policy{ {PolicyRules: PolicyRules{ PreparedQueries: []*PreparedQueryRule{ { Prefix: "foo", Policy: PolicyWrite, }, { Prefix: "bar", Policy: PolicyRead, }, { Prefix: "baz", Policy: PolicyWrite, }, }, PreparedQueryPrefixes: []*PreparedQueryRule{ { Prefix: "000", Policy: PolicyWrite, }, { Prefix: "111", Policy: PolicyRead, }, { Prefix: "222", Policy: PolicyWrite, }, }, }}, {PolicyRules: PolicyRules{ PreparedQueries: []*PreparedQueryRule{ { Prefix: "foo", Policy: PolicyRead, }, { Prefix: "baz", Policy: PolicyDeny, }, }, PreparedQueryPrefixes: []*PreparedQueryRule{ { Prefix: "000", Policy: PolicyRead, }, { Prefix: "222", Policy: PolicyDeny, }, }, }}, }, expected: &Policy{PolicyRules: PolicyRules{ PreparedQueries: []*PreparedQueryRule{ { Prefix: "foo", Policy: PolicyWrite, }, { Prefix: "bar", Policy: PolicyRead, }, { Prefix: "baz", Policy: PolicyDeny, }, }, PreparedQueryPrefixes: []*PreparedQueryRule{ { Prefix: "000", Policy: PolicyWrite, }, { Prefix: "111", Policy: PolicyRead, }, { Prefix: "222", Policy: PolicyDeny, }, }, }}, }, { name: "Write Precedence", input: []*Policy{ { PolicyRules: PolicyRules{ ACL: PolicyRead, Keyring: PolicyRead, Operator: PolicyRead, Mesh: PolicyRead, Peering: PolicyRead, }, }, { PolicyRules: PolicyRules{ ACL: PolicyWrite, Keyring: PolicyWrite, Operator: PolicyWrite, Mesh: PolicyWrite, Peering: PolicyWrite, }, }, }, expected: &Policy{ PolicyRules: PolicyRules{ ACL: PolicyWrite, Keyring: PolicyWrite, Operator: PolicyWrite, Mesh: PolicyWrite, Peering: PolicyWrite, }, }, }, { name: "Deny Precedence", input: []*Policy{ { PolicyRules: PolicyRules{ ACL: PolicyWrite, Keyring: PolicyWrite, Operator: PolicyWrite, Mesh: PolicyWrite, Peering: PolicyWrite, }, }, { PolicyRules: PolicyRules{ ACL: PolicyDeny, Keyring: PolicyDeny, Operator: PolicyDeny, Mesh: PolicyDeny, Peering: PolicyDeny, }, }, }, expected: &Policy{ PolicyRules: PolicyRules{ ACL: PolicyDeny, Keyring: PolicyDeny, Operator: PolicyDeny, Mesh: PolicyDeny, Peering: PolicyDeny, }, }, }, { name: "Read Precedence", input: []*Policy{ { PolicyRules: PolicyRules{ ACL: PolicyRead, Keyring: PolicyRead, Operator: PolicyRead, Mesh: PolicyRead, Peering: PolicyRead, }, }, {}, }, expected: &Policy{ PolicyRules: PolicyRules{ ACL: PolicyRead, Keyring: PolicyRead, Operator: PolicyRead, Mesh: PolicyRead, Peering: PolicyRead, }, }, }, } for _, tcase := range tests { t.Run(tcase.name, func(t *testing.T) { act := MergePolicies(tcase.input) exp := tcase.expected require.Equal(t, exp.ACL, act.ACL) require.Equal(t, exp.Keyring, act.Keyring) require.Equal(t, exp.Operator, act.Operator) require.Equal(t, exp.Mesh, act.Mesh) require.Equal(t, exp.Peering, act.Peering) require.ElementsMatch(t, exp.Agents, act.Agents) require.ElementsMatch(t, exp.AgentPrefixes, act.AgentPrefixes) require.ElementsMatch(t, exp.Events, act.Events) require.ElementsMatch(t, exp.EventPrefixes, act.EventPrefixes) require.ElementsMatch(t, exp.Keys, act.Keys) require.ElementsMatch(t, exp.KeyPrefixes, act.KeyPrefixes) require.ElementsMatch(t, exp.Nodes, act.Nodes) require.ElementsMatch(t, exp.NodePrefixes, act.NodePrefixes) require.ElementsMatch(t, exp.PreparedQueries, act.PreparedQueries) require.ElementsMatch(t, exp.PreparedQueryPrefixes, act.PreparedQueryPrefixes) require.ElementsMatch(t, exp.Services, act.Services) require.ElementsMatch(t, exp.ServicePrefixes, act.ServicePrefixes) require.ElementsMatch(t, exp.Sessions, act.Sessions) require.ElementsMatch(t, exp.SessionPrefixes, act.SessionPrefixes) }) } } func TestPrecedence(t *testing.T) { type testCase struct { name string a string b string expected bool } cases := []testCase{ { name: "Deny Over Write", a: PolicyDeny, b: PolicyWrite, expected: true, }, { name: "Deny Over List", a: PolicyDeny, b: PolicyList, expected: true, }, { name: "Deny Over Read", a: PolicyDeny, b: PolicyRead, expected: true, }, { name: "Deny Over Unknown", a: PolicyDeny, b: "not a policy", expected: true, }, { name: "Write Over List", a: PolicyWrite, b: PolicyList, expected: true, }, { name: "Write Over Read", a: PolicyWrite, b: PolicyRead, expected: true, }, { name: "Write Over Unknown", a: PolicyWrite, b: "not a policy", expected: true, }, { name: "List Over Read", a: PolicyList, b: PolicyRead, expected: true, }, { name: "List Over Unknown", a: PolicyList, b: "not a policy", expected: true, }, { name: "Read Over Unknown", a: PolicyRead, b: "not a policy", expected: true, }, { name: "Write Over Deny", a: PolicyWrite, b: PolicyDeny, expected: false, }, { name: "List Over Deny", a: PolicyList, b: PolicyDeny, expected: false, }, { name: "Read Over Deny", a: PolicyRead, b: PolicyDeny, expected: false, }, { name: "Deny Over Unknown", a: PolicyDeny, b: "not a policy", expected: true, }, { name: "List Over Write", a: PolicyList, b: PolicyWrite, expected: false, }, { name: "Read Over Write", a: PolicyRead, b: PolicyWrite, expected: false, }, { name: "Unknown Over Write", a: "not a policy", b: PolicyWrite, expected: false, }, { name: "Read Over List", a: PolicyRead, b: PolicyList, expected: false, }, { name: "Unknown Over List", a: "not a policy", b: PolicyList, expected: false, }, { name: "Unknown Over Read", a: "not a policy", b: PolicyRead, expected: false, }, } for _, tcase := range cases { t.Run(tcase.name, func(t *testing.T) { require.Equal(t, tcase.expected, takesPrecedenceOver(tcase.a, tcase.b)) }) } }