diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a68f1e5f..1318cdb0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,11 +41,11 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa + uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -56,7 +56,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa + uses: github/codeql-action/autobuild@f779452ac5af1c261dce0346a8f964149f49322b # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -70,4 +70,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@eb055d739abdc2e8de2e5f4ba1a8b246daa779aa + uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b diff --git a/.github/workflows/go-build.yml b/.github/workflows/go-build.yml index ecde9f8f..25885069 100644 --- a/.github/workflows/go-build.yml +++ b/.github/workflows/go-build.yml @@ -13,7 +13,7 @@ jobs: build-and-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Set up Go uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 034b3e59..44ffb796 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -11,11 +11,11 @@ jobs: name: golangci-lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 with: go-version-file: ./go.mod cache: false - - uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 + - uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 with: version: latest diff --git a/.github/workflows/make-release.yaml b/.github/workflows/make-release.yaml index 01ef2dcc..7d50aafd 100644 --- a/.github/workflows/make-release.yaml +++ b/.github/workflows/make-release.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repo - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - name: Set up Go uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 diff --git a/go.mod b/go.mod index 484de361..4d23cb61 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,10 @@ module github.com/np-guard/netpol-analyzer -go 1.21 +go 1.22 require ( github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/np-guard/models v0.3.4 + github.com/np-guard/models v0.5.2 github.com/openshift/api v0.0.0-20230502160752-c71432710382 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index 89862360..1c53e3b1 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/np-guard/models v0.3.4 h1:HOhVi6wyGvo+KmYBnQ5Km5HYCF+/PQlDs1v7mL1v05g= -github.com/np-guard/models v0.3.4/go.mod h1:mqE2Irf8r+7HWh8fII0fWbWyQRMHGEo2SgSLN/6VKs8= +github.com/np-guard/models v0.5.2 h1:lty+shExffJpMQyu36a/NBYEky/rjEddQid4GOVHnhs= +github.com/np-guard/models v0.5.2/go.mod h1:dqRdt5EQID1GmHuYsMOJzg4sS104om6NwEZ6sVO55z8= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= diff --git a/pkg/netpol/connlist/connlist_test.go b/pkg/netpol/connlist/connlist_test.go index fe23a403..2441a3a9 100644 --- a/pkg/netpol/connlist/connlist_test.go +++ b/pkg/netpol/connlist/connlist_test.go @@ -15,6 +15,7 @@ import ( "github.com/np-guard/netpol-analyzer/pkg/internal/output" "github.com/np-guard/netpol-analyzer/pkg/internal/testutils" "github.com/np-guard/netpol-analyzer/pkg/manifests/fsscanner" + "github.com/np-guard/netpol-analyzer/pkg/netpol/internal/examples" "github.com/stretchr/testify/require" ) @@ -1341,7 +1342,7 @@ var goodPathTests = []struct { }, } -func runParsedResourcesConnlistTests(t *testing.T, testList []testutils.ParsedResourcesTest) { +func runParsedResourcesConnlistTests(t *testing.T, testList []examples.ParsedResourcesTest) { t.Helper() for i := 0; i < len(testList); i++ { test := &testList[i] @@ -1359,9 +1360,9 @@ func runParsedResourcesConnlistTests(t *testing.T, testList []testutils.ParsedRe } func TestAllParsedResourcesConnlistTests(t *testing.T) { - runParsedResourcesConnlistTests(t, testutils.ANPConnectivityFromParsedResourcesTest) - runParsedResourcesConnlistTests(t, testutils.BANPConnectivityFromParsedResourcesTest) - runParsedResourcesConnlistTests(t, testutils.ANPWithNetPolV1FromParsedResourcesTest) - runParsedResourcesConnlistTests(t, testutils.BANPWithNetPolV1FromParsedResourcesTest) - runParsedResourcesConnlistTests(t, testutils.ANPWithBANPFromParsedResourcesTest) + runParsedResourcesConnlistTests(t, examples.ANPConnectivityFromParsedResourcesTest) + runParsedResourcesConnlistTests(t, examples.BANPConnectivityFromParsedResourcesTest) + runParsedResourcesConnlistTests(t, examples.ANPWithNetPolV1FromParsedResourcesTest) + runParsedResourcesConnlistTests(t, examples.BANPWithNetPolV1FromParsedResourcesTest) + runParsedResourcesConnlistTests(t, examples.ANPWithBANPFromParsedResourcesTest) } diff --git a/pkg/netpol/eval/check.go b/pkg/netpol/eval/check.go index fb15a94f..c7860444 100644 --- a/pkg/netpol/eval/check.go +++ b/pkg/netpol/eval/check.go @@ -15,7 +15,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "github.com/np-guard/models/pkg/ipblock" + "github.com/np-guard/models/pkg/netset" "github.com/np-guard/netpol-analyzer/pkg/internal/netpolerrors" "github.com/np-guard/netpol-analyzer/pkg/netpol/eval/internal/k8s" @@ -110,7 +110,7 @@ func (pe *PolicyEngine) getPoliciesSelectingPod(peer k8s.Peer, direction netv1.P // isPeerNodeIP returns true if peer1 is an IP address of a node and peer2 is a pod on that node func isPeerNodeIP(peer1, peer2 k8s.Peer) bool { if peer2.PeerType() == k8s.PodType && peer1.PeerType() == k8s.IPBlockType { - ip2, err := ipblock.FromIPAddress(peer2.GetPeerPod().HostIP) + ip2, err := netset.IPBlockFromIPAddress(peer2.GetPeerPod().HostIP) if err != nil { return peer1.GetPeerIPBlock().Equal(ip2) } @@ -133,7 +133,7 @@ func isPodToItself(peer1, peer2 k8s.Peer) bool { func (pe *PolicyEngine) getPeer(p string) (k8s.Peer, error) { // check if input peer is cidr if _, _, err := net.ParseCIDR(p); err == nil { - peerIPBlock, err := ipblock.FromCidr(p) + peerIPBlock, err := netset.IPBlockFromCidr(p) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func (pe *PolicyEngine) getPeer(p string) (k8s.Peer, error) { } // check if input peer is an ip address if net.ParseIP(p) != nil { - peerIPBlock, err := ipblock.FromIPAddress(p) + peerIPBlock, err := netset.IPBlockFromIPAddress(p) if err != nil { return nil, err } @@ -285,11 +285,14 @@ func (pe *PolicyEngine) allAllowedXgressConnections(src, dst k8s.Peer, isIngress if err != nil { return nil, err } + // optimization: if all the conns between src and dst were determined by the ANPs : return the allowed conns + if anpCaptured && anpConns.DeterminesAllConns() { + return anpConns.AllowedConns, nil + } // second get the allowed xgress conns between the src and dst from the netpols // note that : // - npConns contains only allowed connections - // - npCaptured is true iff there are policies selecting either src or dst - since network-policies' rules contain - // implicit deny on Pods selected by them. + // - npCaptured is true iff there are policies selecting either src or dst based on the checked direction (ingress/ egress) npConns, npCaptured, err := pe.getAllAllowedXgressConnsFromNetpols(src, dst, isIngress) if err != nil { return nil, err @@ -297,51 +300,41 @@ func (pe *PolicyEngine) allAllowedXgressConnections(src, dst k8s.Peer, isIngress // compute the allowed connections on the given direction considering the which policies captured the xgress connection // and precedence of each policy type: - if anpCaptured && npCaptured { + switch npCaptured { + case true: // npCaptured + if !anpCaptured { // npCaptured && !anpCaptured + // only NPs capture the peers, return allowed conns from netpols + return npConns.AllowedConns, nil + } + // else: npCaptured && anpCaptured // if conns between src and dst were captured by both the admin-network-policies and by network-policies // collect conns: // - traffic that was allowed or denied by ANPs will not be affected by the netpol conns. - // - traffic that has no match in ANPs but allowed by NPs is added to allowed conns. + // - traffic that has no match in ANPs but allowed by NPs is added to allowed conns. // - pass conns from ANPs, are determined by NPs conns; // note that allowed conns by netpols, imply deny on other traffic; // so ANPs.pass conns which intersect with NPs.allowed are added to allowed conns result; // other pass conns (which don't intersect with NPs allowed conns) are not allowed implicitly. - anpConns.CollectConnsFromLowerPrecedencePolicyType(npConns) + anpConns.CollectAllowedConnsFromNetpols(npConns) + return anpConns.AllowedConns, nil + default: // !npCaptured - netpols don't capture the connections between src and dst - delegate to banp + // get default xgress connection between src and dst from the BANP/ system-default; + // note that : + // - if there is no banp in the input resources, then default conns is system-default which is allow-all + // - if the banp captures the xgress between src and dst; then defaultConns may contain allowed and denied conns + defaultConns, err := pe.getXgressDefaultConns(src, dst, isIngress) + if err != nil { + return nil, err + } + if !anpCaptured { // !anpCaptured && !npCaptured: + return defaultConns.AllowedConns, nil + } + // else ( anpCaptured && !npCaptured) + // ANPs capture the peers, netpols don't , return the allowed conns from ANPs considering default conns + // this also determines what happens on traffic (ports) which are not mentioned in the ANPs; since ANP rules are read as is only + anpConns.CollectConnsFromBANP(defaultConns) return anpConns.AllowedConns, nil } - if !anpCaptured && npCaptured { - // only NPs capture the peers, return allowed conns from netpols - return npConns.AllowedConns, nil - } - // otherwise,n getting here means network-policies don't capture the xgress direction traffic between src and dst. - // get default xgress connection between src and dst from the BANP/ system-default; - // note that : - // - if there is no banp in the input resources, then default conns is system-default which is allow-all - // - if the banp captures the xgress between src and dst; then defaultConns may contain allowed and denied conns - defaultConns, err := pe.getXgressDefaultConns(src, dst, isIngress) - if err != nil { - return nil, err - } - if !anpCaptured && !npCaptured { // only BANP captures the xgress between src -> dst (or not captured at all) - // if no ANPs nor NPs capturing the xgress connection, return the default allowed conns (from BANP or system-default). - // note that: if conns are not captured by an ANP/NP but captured only by BANP, then: - // if BANP denies some conns but has no allow rule then, allowed conns are all but the denied conns: - if defaultConns.AllowedConns.IsEmpty() && !defaultConns.DeniedConns.IsEmpty() { - allowedConns := common.MakeConnectionSet(true) - allowedConns.Subtract(defaultConns.DeniedConns) - return allowedConns, nil - } // else return the allowed conns by BANP - return defaultConns.AllowedConns, nil - } - // else ( anpCaptured && !npCaptured) - // ANPs capture the peers, netpols don't , return the allowed conns from ANPs considering default conns - // this determines what happens on traffic (ports) which are not mentioned in the ANPs; since ANP rules are read as is only - anpConns.CollectConnsFromLowerPrecedencePolicyType(defaultConns) - // note that : BANP rules may not match all ANPs.Pass conns, remaining pass conns will be allowed as system-default - if !anpConns.PassConns.IsEmpty() { - anpConns.AllowedConns.Union(anpConns.PassConns) - } - return anpConns.AllowedConns, nil } // analyzing network-policies for conns between peers (object kind == NetworkPolicy): @@ -397,7 +390,7 @@ func (pe *PolicyEngine) getAllAllowedXgressConnsFromNetpols(src, dst k8s.Peer, i allowedConns.Union(policyAllowedConnectionsPerDirection) } // putting the result in policiesConns object to be compared with conns allowed by ANP/BANP later - policiesConns = k8s.InitEmptyPolicyConnections() + policiesConns = k8s.NewPolicyConnections() policiesConns.AllowedConns = allowedConns return policiesConns, true, nil } @@ -454,13 +447,13 @@ func updatePeerXgressClusterWideExposure(policy *k8s.NetworkPolicy, src, dst k8s // the Pods selected by the AdminNetworkPolicy, as opposed to implicit deny NetworkPolicy rules imply. func (pe *PolicyEngine) getAllAllowedXgressConnectionsFromANPs(src, dst k8s.Peer, isIngress bool) (policiesConns *k8s.PolicyConnections, captured bool, err error) { - policiesConns = k8s.InitEmptyPolicyConnections() + policiesConns = k8s.NewPolicyConnections() // iterate the sorted admin network policies in order to compute the allowed, pass, and denied xgress connections between the peers // from the admin netpols capturing the src (if !isIngress)/ capturing the dst (if isIngress true). // connections are computed considering ANPs priorities (rules of an ANP with lower priority take precedence on other ANPs rules) // and rules ordering in single ANP (coming first takes precedence). for _, anp := range pe.sortedAdminNetpols { - singleANPConns := k8s.InitEmptyPolicyConnections() + singleANPConns := k8s.NewPolicyConnections() // collect the allowed, pass, and denied connectivity from the relevant rules into policiesConns if !isIngress { // egress selectsSrc, err := anp.Selects(src, false) @@ -508,7 +501,7 @@ func (pe *PolicyEngine) getAllAllowedXgressConnectionsFromANPs(src, dst k8s.Peer // if there is no BANP or if the BANP does not capture connections between src and dst, then default allow-all connections is returned. // - note that the result may contain allowed / denied connections. func (pe *PolicyEngine) getXgressDefaultConns(src, dst k8s.Peer, isIngress bool) (*k8s.PolicyConnections, error) { - res := k8s.InitEmptyPolicyConnections() + res := k8s.NewPolicyConnections() if pe.baselineAdminNetpol == nil { res.AllowedConns = common.MakeConnectionSet(true) return res, nil @@ -524,22 +517,28 @@ func (pe *PolicyEngine) getXgressDefaultConns(src, dst k8s.Peer, isIngress bool) if err != nil { return nil, err } - } else { // egress (!isIngress) - selectsSrc, err := pe.baselineAdminNetpol.Selects(src, false) + } + } else { // egress (!isIngress) + selectsSrc, err := pe.baselineAdminNetpol.Selects(src, false) + if err != nil { + return nil, err + } + // if the banp selects the src on egress, get egress conns + if selectsSrc { + res, err = pe.baselineAdminNetpol.GetEgressPolicyConns(dst) if err != nil { return nil, err } - // if the banp selects the src on egress, get egress conns - if selectsSrc { - res, err = pe.baselineAdminNetpol.GetEgressPolicyConns(dst) - if err != nil { - return nil, err - } - } } } if res.IsEmpty() { // banp rules didn't capture xgress conn between src and dst, return system-default: allow-all res.AllowedConns = common.MakeConnectionSet(true) } + if res.AllowedConns.IsEmpty() && !res.DeniedConns.IsEmpty() { // banp rules deny some connection but don't capture other conns + allowedConns := common.MakeConnectionSet(true) + allowedConns.Subtract(res.DeniedConns) + res.AllowedConns = allowedConns + return res, nil + } return res, nil } diff --git a/pkg/netpol/eval/eval_test.go b/pkg/netpol/eval/eval_test.go index c7c4a09a..19ddfb1b 100644 --- a/pkg/netpol/eval/eval_test.go +++ b/pkg/netpol/eval/eval_test.go @@ -32,6 +32,7 @@ import ( "github.com/np-guard/netpol-analyzer/pkg/manifests/fsscanner" "github.com/np-guard/netpol-analyzer/pkg/manifests/parser" "github.com/np-guard/netpol-analyzer/pkg/netpol/internal/common" + "github.com/np-guard/netpol-analyzer/pkg/netpol/internal/examples" ) const ( @@ -1822,7 +1823,7 @@ func pickUncontainedConn(conn *common.ConnectionSet) (resProtocol, resPort strin return pickContainedConn(complementSet) } -func runParsedResourcesEvalTests(t *testing.T, testList []testutils.ParsedResourcesTest) { +func runParsedResourcesEvalTests(t *testing.T, testList []examples.ParsedResourcesTest) { t.Helper() for i := 0; i < len(testList); i++ { test := &testList[i] @@ -1863,9 +1864,9 @@ func runParsedResourcesEvalTests(t *testing.T, testList []testutils.ParsedResour } func TestAllParsedResourcesEvalTests(t *testing.T) { - runParsedResourcesEvalTests(t, testutils.ANPConnectivityFromParsedResourcesTest) - runParsedResourcesEvalTests(t, testutils.BANPConnectivityFromParsedResourcesTest) - runParsedResourcesEvalTests(t, testutils.ANPWithNetPolV1FromParsedResourcesTest) - runParsedResourcesEvalTests(t, testutils.BANPWithNetPolV1FromParsedResourcesTest) - runParsedResourcesEvalTests(t, testutils.ANPWithBANPFromParsedResourcesTest) + runParsedResourcesEvalTests(t, examples.ANPConnectivityFromParsedResourcesTest) + runParsedResourcesEvalTests(t, examples.BANPConnectivityFromParsedResourcesTest) + runParsedResourcesEvalTests(t, examples.ANPWithNetPolV1FromParsedResourcesTest) + runParsedResourcesEvalTests(t, examples.BANPWithNetPolV1FromParsedResourcesTest) + runParsedResourcesEvalTests(t, examples.ANPWithBANPFromParsedResourcesTest) } diff --git a/pkg/netpol/eval/internal/k8s/adminnetpol.go b/pkg/netpol/eval/internal/k8s/adminnetpol.go index f068c2c7..98c38456 100644 --- a/pkg/netpol/eval/internal/k8s/adminnetpol.go +++ b/pkg/netpol/eval/internal/k8s/adminnetpol.go @@ -66,33 +66,6 @@ func doesPodsFieldMatchPeer(pods *apisv1a.NamespacedPod, peer Peer) (bool, error return nsSelector.Matches(labels.Set(peer.GetPeerNamespace().Labels)) && podSelector.Matches(labels.Set(peer.GetPeerPod().Labels)), nil } -// why could not success yet with -// using generics to avoid duplicates in following two funcs `egressRuleSelectsPeer` and `ingressRuleSelectsPeer`: -// (same for updateConnsIfEgressRuleSelectsPeer and updateConnsIfIngressRuleSelectsPeer) -// -// according to https://tip.golang.org/doc/go1.18#generics : -// "The Go compiler does not support accessing a struct field x.f where x is of type parameter type even if all types in the type -// parameter’s type set have a field f. We may remove this restriction in a future release." -// till GO 1.21 this restriction is not removed yet. -// for example: -// replacing "func egressRuleSelectsPeer(rulePeers []apisv1a.AdminNetworkPolicyEgressPeer, dst Peer) (bool, error)" and -// "func ingressRuleSelectsPeer(rulePeers []apisv1a.AdminNetworkPolicyIngressPeer, src Peer) (bool, error)" -// -// with a func using generics like this : -// "func xgressRuleSelectsPeer[T apisv1a.AdminNetworkPolicyEgressPeer | apisv1a.AdminNetworkPolicyIngressPeer](rulePeers []T, -// dst Peer) (bool, error)" -// will fail with errors such as : -// "rulePeers[i].Namespaces undefined (type T has no field or method Namespaces)" -// -// a useful way to skip the errors is to define an interface with some Getter funcs to be implemented on the "inheriting types" -// of the parameters. -// but in this case : since our parameters are not of local types, we can not define new methods (like getters) on them; -// not even with using aliases since then we'll need to copy values in calling funcs into the aliases and -// this is not more efficient than current solutions. -// -// @todo: if GO is upgraded to a release that does not has this restriction on types with same fields, replace following two "duplicated" -// funcs with one func that uses generics type - // egressRuleSelectsPeer checks if the given []AdminNetworkPolicyEgressPeer rule selects the given peer // currently supposing a single egressPeer rule may contain only Namespaces/ Pods Fields, // @todo support also egress rule peer with Networks field @@ -265,7 +238,6 @@ func subjectSelectsPeer(anpSubject apisv1a.AdminNetworkPolicySubject, p Peer) (b // anpPortContains returns if the given AdminNetworkPolicyPort selects the input connection // -//nolint:gosec // memory aliasing in for loop is to fit an old func //gocyclo:ignore func anpPortContains(rulePorts *[]apisv1a.AdminNetworkPolicyPort, protocol, port string, dst Peer) (bool, error) { if rulePorts == nil { @@ -429,7 +401,7 @@ func (anp *AdminNetworkPolicy) anpRuleErr(ruleName, description string) error { // GetIngressPolicyConns returns the connections from the ingress rules selecting the src in spec of the adminNetworkPolicy func (anp *AdminNetworkPolicy) GetIngressPolicyConns(src, dst Peer) (*PolicyConnections, error) { - res := InitEmptyPolicyConnections() + res := NewPolicyConnections() for _, rule := range anp.Spec.Ingress { // rule is apisv1a.AdminNetworkPolicyIngressRule rulePeers := rule.From rulePorts := rule.Ports @@ -442,7 +414,7 @@ func (anp *AdminNetworkPolicy) GetIngressPolicyConns(src, dst Peer) (*PolicyConn // GetEgressPolicyConns returns the connections from the egress rules selecting the dst in spec of the adminNetworkPolicy func (anp *AdminNetworkPolicy) GetEgressPolicyConns(dst Peer) (*PolicyConnections, error) { - res := InitEmptyPolicyConnections() + res := NewPolicyConnections() for _, rule := range anp.Spec.Egress { // rule is apisv1a.AdminNetworkPolicyEgressRule rulePeers := rule.To rulePorts := rule.Ports @@ -456,8 +428,8 @@ func (anp *AdminNetworkPolicy) GetEgressPolicyConns(dst Peer) (*PolicyConnection const ( // according to this: https://network-policy-api.sigs.k8s.io/api-overview/#adminnetworkpolicy-priorities // The Priority field in the ANP spec is defined as an integer value within the range 0 to 1000 - minPriority = 0 - maxPriority = 1000 + minANPPriority = 0 + maxANPPriority = 1000 ) // HasValidPriority returns if the priority in a valid range @@ -465,7 +437,7 @@ func (anp *AdminNetworkPolicy) HasValidPriority() bool { // note: k8s defines "1000" as the maximum numeric value for priority // but openshift currently only support priority values between 0 and 99 // current implementation satisfies k8s requirement - return anp.Spec.Priority >= minPriority && anp.Spec.Priority <= maxPriority + return anp.Spec.Priority >= minANPPriority && anp.Spec.Priority <= maxANPPriority } // CheckEgressConnAllowed checks if the input conn is allowed/passed/denied or not captured on egress diff --git a/pkg/netpol/eval/internal/k8s/baseline_admin_netpol.go b/pkg/netpol/eval/internal/k8s/baseline_admin_netpol.go index 625d3ce7..4baa3167 100644 --- a/pkg/netpol/eval/internal/k8s/baseline_admin_netpol.go +++ b/pkg/netpol/eval/internal/k8s/baseline_admin_netpol.go @@ -48,7 +48,7 @@ func banpRuleErr(ruleName, description string) error { // GetEgressPolicyConns returns the connections from the egress rules selecting the dst in spec of the baselineAdminNetworkPolicy func (banp *BaselineAdminNetworkPolicy) GetEgressPolicyConns(dst Peer) (*PolicyConnections, error) { - res := InitEmptyPolicyConnections() + res := NewPolicyConnections() for _, rule := range banp.Spec.Egress { // rule is apisv1a.BaselineAdminNetworkPolicyEgressRule rulePeers := rule.To rulePorts := rule.Ports @@ -61,7 +61,7 @@ func (banp *BaselineAdminNetworkPolicy) GetEgressPolicyConns(dst Peer) (*PolicyC // GetIngressPolicyConns returns the connections from the ingress rules selecting the src in spec of the baselineAdminNetworkPolicy func (banp *BaselineAdminNetworkPolicy) GetIngressPolicyConns(src, dst Peer) (*PolicyConnections, error) { - res := InitEmptyPolicyConnections() + res := NewPolicyConnections() for _, rule := range banp.Spec.Ingress { // rule is apisv1a.BaselineAdminNetworkPolicyIngressRule rulePeers := rule.From rulePorts := rule.Ports diff --git a/pkg/netpol/eval/internal/k8s/netpol.go b/pkg/netpol/eval/internal/k8s/netpol.go index 475087cb..fc460eb5 100644 --- a/pkg/netpol/eval/internal/k8s/netpol.go +++ b/pkg/netpol/eval/internal/k8s/netpol.go @@ -18,7 +18,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" - "github.com/np-guard/models/pkg/ipblock" + "github.com/np-guard/models/pkg/netset" "github.com/np-guard/netpol-analyzer/pkg/internal/netpolerrors" "github.com/np-guard/netpol-analyzer/pkg/netpol/internal/common" @@ -263,7 +263,7 @@ func (np *NetworkPolicy) ruleSelectsPeer(rulePeers []netv1.NetworkPolicyPeer, pe } peerIPBlock := peer.GetPeerIPBlock() - res := peerIPBlock.ContainedIn(ruleIPBlock) + res := peerIPBlock.IsSubset(ruleIPBlock) if res { return true, nil } @@ -397,8 +397,8 @@ func (np *NetworkPolicy) netpolErr(title, description string) error { return fmt.Errorf("network policy %s %s: %s", np.fullName(), title, description) } -func (np *NetworkPolicy) parseNetpolCIDR(cidr string, except []string) (*ipblock.IPBlock, error) { - ipb, err := ipblock.FromCidr(cidr) +func (np *NetworkPolicy) parseNetpolCIDR(cidr string, except []string) (*netset.IPBlock, error) { + ipb, err := netset.IPBlockFromCidr(cidr) if err != nil { return nil, np.netpolErr(netpolerrors.CidrErrTitle, err.Error()) } @@ -417,8 +417,8 @@ func (np *NetworkPolicy) parseNetpolLabelSelector(selector *metav1.LabelSelector return selectorRes, nil } -func (np *NetworkPolicy) rulePeersReferencedIPBlocks(rulePeers []netv1.NetworkPolicyPeer) ([]*ipblock.IPBlock, error) { - res := []*ipblock.IPBlock{} +func (np *NetworkPolicy) rulePeersReferencedIPBlocks(rulePeers []netv1.NetworkPolicyPeer) ([]*netset.IPBlock, error) { + res := []*netset.IPBlock{} for _, peerObj := range rulePeers { if peerObj.IPBlock != nil { ipb, err := np.parseNetpolCIDR(peerObj.IPBlock.CIDR, peerObj.IPBlock.Except) @@ -432,8 +432,8 @@ func (np *NetworkPolicy) rulePeersReferencedIPBlocks(rulePeers []netv1.NetworkPo } // GetReferencedIPBlocks: return list of IPBlock objects referenced in the current network policy -func (np *NetworkPolicy) GetReferencedIPBlocks() ([]*ipblock.IPBlock, error) { - res := []*ipblock.IPBlock{} +func (np *NetworkPolicy) GetReferencedIPBlocks() ([]*netset.IPBlock, error) { + res := []*netset.IPBlock{} for _, rule := range np.Spec.Ingress { ruleRes, err := np.rulePeersReferencedIPBlocks(rule.From) if err != nil { diff --git a/pkg/netpol/eval/internal/k8s/peer.go b/pkg/netpol/eval/internal/k8s/peer.go index 0cd6de3d..21203d3a 100644 --- a/pkg/netpol/eval/internal/k8s/peer.go +++ b/pkg/netpol/eval/internal/k8s/peer.go @@ -9,7 +9,7 @@ package k8s import ( "k8s.io/apimachinery/pkg/types" - "github.com/np-guard/models/pkg/ipblock" + "github.com/np-guard/models/pkg/netset" ) // PeerType is a type to indicate the type of a Peer object (Pod or IP address) @@ -32,7 +32,7 @@ type Peer interface { // else returns nil GetPeerNamespace() *Namespace // GetPeerIPBlock returns a reference to IPBlock if the peer is IP address, else returns nil - GetPeerIPBlock() *ipblock.IPBlock + GetPeerIPBlock() *netset.IPBlock } // PodPeer implements k8s.Peer interface and eval.Peer interface @@ -43,7 +43,7 @@ type PodPeer struct { // IPBlockPeer implements k8s.Peer interface and eval.Peer interface type IPBlockPeer struct { - IPBlock *ipblock.IPBlock + IPBlock *netset.IPBlock } // WorkloadPeer implements eval.Peer interface @@ -118,7 +118,7 @@ func (p *PodPeer) GetPeerNamespace() *Namespace { return p.NamespaceObject } -func (p *PodPeer) GetPeerIPBlock() *ipblock.IPBlock { +func (p *PodPeer) GetPeerIPBlock() *netset.IPBlock { return nil } @@ -160,7 +160,7 @@ func (p *IPBlockPeer) GetPeerNamespace() *Namespace { return nil } -func (p *IPBlockPeer) GetPeerIPBlock() *ipblock.IPBlock { +func (p *IPBlockPeer) GetPeerIPBlock() *netset.IPBlock { return p.IPBlock } diff --git a/pkg/netpol/eval/internal/k8s/policy_connections.go b/pkg/netpol/eval/internal/k8s/policy_connections.go index 455789f0..99afc118 100644 --- a/pkg/netpol/eval/internal/k8s/policy_connections.go +++ b/pkg/netpol/eval/internal/k8s/policy_connections.go @@ -23,15 +23,15 @@ import ( type PolicyConnections struct { // AllowedConns allowed connections-set between two peers AllowedConns *common.ConnectionSet - // PassConns connections between two peers that was passed by admin-network-policy to policies with lower priority - // (network-policies/ baseline-admin-network-policies) + // PassConns connections-set between two peers that was passed by admin-network-policy; + // i.e. delegate decision about them to next layer of policies, NetworkPolicies or BaselineAdminNetworkPolicies resources PassConns *common.ConnectionSet // DeniedConns denied connections between two peers DeniedConns *common.ConnectionSet } -// InitEmptyPolicyConnections - returns a new PolicyConnections object with empty connection-sets -func InitEmptyPolicyConnections() *PolicyConnections { +// NewPolicyConnections - returns a new PolicyConnections object with empty connection-sets +func NewPolicyConnections() *PolicyConnections { return &PolicyConnections{ AllowedConns: common.MakeConnectionSet(false), DeniedConns: common.MakeConnectionSet(false), @@ -84,46 +84,78 @@ func (pc *PolicyConnections) CollectANPConns(newAdminPolicyConns *PolicyConnecti pc.PassConns.Union(newAdminPolicyConns.PassConns) } -// CollectConnsFromLowerPrecedencePolicyType updates current PolicyConnections object with connections from a -// policy with lower priority than ANP. (e.g. network-policy or baseline-admin-network-policy or instead system-default connection) -// allowed and denied connections of current PolicyConnections object (admin-network-policy) are non-overridden. -// but pass connections in current PolicyConnections object will be determined by the input PolicyConnections parameter. -// note that: passConns in otherConns will always be empty. (np and banp don't contain pass connections) -func (pc *PolicyConnections) CollectConnsFromLowerPrecedencePolicyType(otherConns *PolicyConnections) { +// CollectAllowedConnsFromNetpols updates allowed conns of current PolicyConnections object with allowed connections from +// k8s NetworkPolicy objects. +// Allowed and Denied connections of current PolicyConnections object (admin-network-policy) are non-overridden. +// note that: +// 1. the input connections will include only non-empty allowed conns (since its source is netpols); +// and any connection that is not allowed by the netpols is denied. +// 2. pass connections in current PolicyConnections object will be determined by the input PolicyConnections parameter. +func (pc *PolicyConnections) CollectAllowedConnsFromNetpols(npConns *PolicyConnections) { + // subtract the denied conns (which are non-overridden) from input conns + npConns.AllowedConns.Subtract(pc.DeniedConns) + // PASS conns are determined by npConns + // currently, npConns.AllowedConns contains: + // 1. traffic that was passed by ANPs (if there are such conns) + // 2. traffic that had no match in ANPs + // so we can update current allowed conns with them + pc.AllowedConns.Union(npConns.AllowedConns) + // now pc.AllowedConns contains all allowed conns by the ANPs and NPs + // the content of pc.Denied and pc.Pass is not relevant anymore; + // all the connections that are not allowed by the ANPs and NPs are denied. +} + +// CollectConnsFromBANP updates current PolicyConnections object with connections from a BANP. +// Allowed and Denied connections of current PolicyConnections object (admin-network-policy) are non-overridden. +// note that: +// 1. passConns of the input connections will always be empty. (may contain non-empty allowed/ denied conns) +// 2. pass connections in current PolicyConnections object will be determined by the input PolicyConnections +// parameter or system-default value. +func (pc *PolicyConnections) CollectConnsFromBANP(banpConns *PolicyConnections) { // allowed and denied conns of current pc are non-overridden - otherConns.AllowedConns.Subtract(pc.DeniedConns) - otherConns.DeniedConns.Subtract(pc.AllowedConns) - // PASS conns are determined by otherConns - // currently, otherConns.AllowedConns contains: - // 1. traffic that was passed by ANP (if there are such conns) - // 2. traffic that had no match in ANP (or higher priority policies) + banpConns.AllowedConns.Subtract(pc.DeniedConns) + banpConns.DeniedConns.Subtract(pc.AllowedConns) + // PASS conns are determined by banpConns + // currently, banpConns.AllowedConns contains: + // 1. traffic that was passed by ANPs (if there are such conns) + // 2. traffic that had no match in ANPs // so we can update current allowed conns with them - pc.AllowedConns.Union(otherConns.AllowedConns) - // also, otherConns.DeniedConns currently contains: - // 1. traffic that was passed by ANP (if there are such conns) - // 2. traffic that had no match in ANP (or higher priority policies) - // so we can update current denied conns with otherConns.DeniedConns - pc.DeniedConns.Union(otherConns.DeniedConns) + pc.AllowedConns.Union(banpConns.AllowedConns) + // also, banpConns.DeniedConns currently contains: + // 1. traffic that was passed by ANPs (if there are such conns) + // 2. traffic that had no match in ANPs + // so we can update current denied conns with banpConns.DeniedConns + pc.DeniedConns.Union(banpConns.DeniedConns) // in order to update pc.PassConns we need: - // to find intersection of current pass connections with otherConns's allowedConns and deniedConns + // to find intersection of current pass connections with banpConns's allowedConns and deniedConns passAllowCopy := pc.PassConns.Copy() // using a copy since Intersection changes the object, but we want to keep also // non-intersected conns - passAllowCopy.Intersection(otherConns.AllowedConns) // pass conns to be allowed - // pc.AllowedConns.Union(passAllowCopy) - redundant since passAllowCopy is contained in otherConns.AllowedConns, already updated + passAllowCopy.Intersection(banpConns.AllowedConns) // pass conns to be allowed + // pc.AllowedConns.Union(passAllowCopy) - redundant since passAllowCopy is contained in banpConns.AllowedConns, already updated passDenyCopy := pc.PassConns.Copy() - passDenyCopy.Intersection(otherConns.DeniedConns) // pass conns to be denied - // pc.DeniedConns.Union(passDenyCopy) - redundant since passDenyCopy is contained in otherConns.DeniedConns + passDenyCopy.Intersection(banpConns.DeniedConns) // pass conns to be denied + // pc.DeniedConns.Union(passDenyCopy) - redundant since passDenyCopy is contained in banpConns.DeniedConns // subtract pass-deny and pass-allow from the current Pass conns; - // note that the updated pc conns may still have non-empty Pass connections (intersection with allow and deny are not full) - // - this will not affect evaluated netpols conns, as the allowed conns of netpols implicitly deny other conns. - // - this should be considered with banp - so remaining pass conns will get system default. pc.PassConns.Subtract(passAllowCopy) pc.PassConns.Subtract(passDenyCopy) + // note that the updated pc conns may still have non-empty Pass connections (BANP rules may did not capture all ANPs.Pass conns). + // so, since the BANP is the last evaluated policy of all policy layers, remaining pass conns will be allowed as system-default + if !pc.PassConns.IsEmpty() { + pc.AllowedConns.Union(pc.PassConns) + } } // IsEmpty : returns true iff all connection sets in current policy-connections are empty func (pc *PolicyConnections) IsEmpty() bool { return pc.AllowedConns.IsEmpty() && pc.DeniedConns.IsEmpty() && pc.PassConns.IsEmpty() } + +// DeterminesAllConns : returns true if the allowed and denied connections of the current PolicyConnections object +// selects all the connections +func (pc *PolicyConnections) DeterminesAllConns() bool { + selectedConns := pc.AllowedConns.Copy() + selectedConns.Union(pc.DeniedConns) + return selectedConns.AllConnections() +} diff --git a/pkg/netpol/eval/peer.go b/pkg/netpol/eval/peer.go index 12795650..bdbc995f 100644 --- a/pkg/netpol/eval/peer.go +++ b/pkg/netpol/eval/peer.go @@ -9,7 +9,7 @@ package eval import ( "fmt" - "github.com/np-guard/models/pkg/ipblock" + "github.com/np-guard/models/pkg/netset" "github.com/np-guard/netpol-analyzer/pkg/netpol/eval/internal/k8s" ) @@ -35,7 +35,7 @@ type Peer interface { // then in the result map there would be entries for (str(A), str(A1), A1) and for (str(A), str(A2), A2) func DisjointPeerIPMap(set1, set2 []Peer) (map[string]map[string]Peer, error) { res := map[string]map[string]Peer{} - var ipSet1, ipSet2 []*ipblock.IPBlock + var ipSet1, ipSet2 []*netset.IPBlock var err error if ipSet1, err = peerIPSetToIPBlockSet(set1); err != nil { return nil, err @@ -43,7 +43,7 @@ func DisjointPeerIPMap(set1, set2 []Peer) (map[string]map[string]Peer, error) { if ipSet2, err = peerIPSetToIPBlockSet(set2); err != nil { return nil, err } - disjointIPset := ipblock.DisjointIPBlocks(ipSet1, ipSet2) + disjointIPset := netset.DisjointIPBlocks(ipSet1, ipSet2) for _, ipb := range disjointIPset { addDisjointIPBlockToMap(ipSet1, ipb, res) @@ -54,9 +54,9 @@ func DisjointPeerIPMap(set1, set2 []Peer) (map[string]map[string]Peer, error) { } // addDisjointIPBlockToMap updates input map (from peer-str to its disjoint peers) by adding a new disjoint ip -func addDisjointIPBlockToMap(ipSet []*ipblock.IPBlock, disjointIP *ipblock.IPBlock, m map[string]map[string]Peer) { +func addDisjointIPBlockToMap(ipSet []*netset.IPBlock, disjointIP *netset.IPBlock, m map[string]map[string]Peer) { for _, ipb1 := range ipSet { - if disjointIP.ContainedIn(ipb1) { + if disjointIP.IsSubset(ipb1) { updatePeerIPMap(m, ipb1, disjointIP) break } @@ -65,7 +65,7 @@ func addDisjointIPBlockToMap(ipSet []*ipblock.IPBlock, disjointIP *ipblock.IPBlo // updatePeerIPMap updates input map (from peer-str to its disjoint peers), given a new disjoint ip (ipb), and its // associated original ip-range key from the map (ipb1) -func updatePeerIPMap(m map[string]map[string]Peer, ipb1, ipb *ipblock.IPBlock) { +func updatePeerIPMap(m map[string]map[string]Peer, ipb1, ipb *netset.IPBlock) { ipb1Str := ipb1.ToIPRanges() if _, ok := m[ipb1Str]; !ok { m[ipb1Str] = map[string]Peer{} @@ -74,8 +74,8 @@ func updatePeerIPMap(m map[string]map[string]Peer, ipb1, ipb *ipblock.IPBlock) { } // peerIPSetToIPBlockSet is given as input a list of peers of type ip-block, and returns a list matching IPBlock objects -func peerIPSetToIPBlockSet(peerSet []Peer) ([]*ipblock.IPBlock, error) { - res := make([]*ipblock.IPBlock, len(peerSet)) +func peerIPSetToIPBlockSet(peerSet []Peer) ([]*netset.IPBlock, error) { + res := make([]*netset.IPBlock, len(peerSet)) for i, p := range peerSet { ipBlock, err := peerIPToIPBlock(p) if err != nil { @@ -87,7 +87,7 @@ func peerIPSetToIPBlockSet(peerSet []Peer) ([]*ipblock.IPBlock, error) { } // peerIPToIPBlock returns an IPBlock object from a Peer object of IP type -func peerIPToIPBlock(p Peer) (*ipblock.IPBlock, error) { +func peerIPToIPBlock(p Peer) (*netset.IPBlock, error) { peerIP, ok := p.(*k8s.IPBlockPeer) if !ok { return nil, fmt.Errorf("input peer not IP block: %s", p.String()) @@ -95,9 +95,9 @@ func peerIPToIPBlock(p Peer) (*ipblock.IPBlock, error) { return peerIP.IPBlock, nil } -func mergeIPBlocksList(inputList []*ipblock.IPBlock) []*ipblock.IPBlock { +func mergeIPBlocksList(inputList []*netset.IPBlock) []*netset.IPBlock { if len(inputList) == 0 { - return []*ipblock.IPBlock{} + return []*netset.IPBlock{} } union := inputList[0].Copy() for i := 1; i < len(inputList); i++ { diff --git a/pkg/netpol/eval/resources.go b/pkg/netpol/eval/resources.go index 2a470ce2..e30f6f07 100644 --- a/pkg/netpol/eval/resources.go +++ b/pkg/netpol/eval/resources.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/types" apisv1a "sigs.k8s.io/network-policy-api/apis/v1alpha1" - "github.com/np-guard/models/pkg/ipblock" + "github.com/np-guard/models/pkg/netset" "github.com/np-guard/netpol-analyzer/pkg/internal/netpolerrors" "github.com/np-guard/netpol-analyzer/pkg/manifests/parser" @@ -652,8 +652,8 @@ func (pe *PolicyEngine) GetRepresentativePeersList() []Peer { } // getDisjointIPBlocks returns a slice of disjoint ip-blocks from all netpols resources -func (pe *PolicyEngine) getDisjointIPBlocks() ([]*ipblock.IPBlock, error) { - var ipbList []*ipblock.IPBlock +func (pe *PolicyEngine) getDisjointIPBlocks() ([]*netset.IPBlock, error) { + var ipbList []*netset.IPBlock for _, nsMap := range pe.netpolsMap { for _, policy := range nsMap { policyIPBlocksList, err := policy.GetReferencedIPBlocks() @@ -663,8 +663,8 @@ func (pe *PolicyEngine) getDisjointIPBlocks() ([]*ipblock.IPBlock, error) { ipbList = append(ipbList, policyIPBlocksList...) } } - newAll := ipblock.GetCidrAll() - disjointRes := ipblock.DisjointIPBlocks(ipbList, []*ipblock.IPBlock{newAll}) + newAll := netset.GetCidrAll() + disjointRes := netset.DisjointIPBlocks(ipbList, []*netset.IPBlock{newAll}) return disjointRes, nil } diff --git a/pkg/netpol/internal/common/portset.go b/pkg/netpol/internal/common/portset.go index 7fe56d56..fd0b7417 100644 --- a/pkg/netpol/internal/common/portset.go +++ b/pkg/netpol/internal/common/portset.go @@ -110,7 +110,7 @@ func (p *PortSet) Union(other *PortSet) { // ContainedIn: return true if current PortSet object is contained in input PortSet object func (p *PortSet) ContainedIn(other *PortSet) bool { - return p.Ports.ContainedIn(other.Ports) + return p.Ports.IsSubset(other.Ports) } // Intersection: update current PortSet object as intersection with input PortSet object diff --git a/pkg/internal/testutils/parsed_resources_tests.go b/pkg/netpol/internal/examples/anp_examples.go similarity index 90% rename from pkg/internal/testutils/parsed_resources_tests.go rename to pkg/netpol/internal/examples/anp_examples.go index de67ade6..cfc39215 100644 --- a/pkg/internal/testutils/parsed_resources_tests.go +++ b/pkg/netpol/internal/examples/anp_examples.go @@ -2,27 +2,21 @@ Copyright 2023- IBM Inc. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 - */ - -package testutils +package examples import ( - "fmt" - "strings" - v1 "k8s.io/api/core/v1" netv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/intstr" "sigs.k8s.io/network-policy-api/apis/v1alpha1" "github.com/np-guard/netpol-analyzer/pkg/internal/output" - "github.com/np-guard/netpol-analyzer/pkg/manifests/parser" ) -// /////////////////////////////////////// ParsedResourcesTests //////////////////////////////////// +//////////////////////////////////// The following tests are taken from or tested also with ///////////////////////////////////// +// https://github.com/kubernetes-sigs/network-policy-api/blob/main/cmd/policy-assistant/test/integration/integration_test.go const ( podKind = "Pod" @@ -38,180 +32,14 @@ const ( priority100 = 100 ) +// variables which are used by the anp examples below: var ( udp = v1.ProtocolUDP serve80tcp = "serve-80-tcp" - genCnt = 0 -) - -func newDefaultPod(namespace, name string, ports []int32, protocols []v1.Protocol) *v1.Pod { - podObj := v1.Pod{} - podObj.TypeMeta.APIVersion = "v1" - podObj.TypeMeta.Kind = podKind - podObj.ObjectMeta.Name = name - podObj.ObjectMeta.Namespace = namespace - podObj.Status.HostIP = parser.IPv4LoopbackAddr - podObj.Status.PodIPs = []v1.PodIP{{IP: parser.IPv4LoopbackAddr}} - podObj.Labels = map[string]string{"pod": name} - for _, port := range ports { - for _, protocol := range protocols { - podObj.Spec.Containers = append(podObj.Spec.Containers, newDefaultContainer(port, protocol)) - } - } - addMetaData(&podObj.ObjectMeta, true) - return &podObj -} - -func newDefaultContainer(port int32, protocol v1.Protocol) v1.Container { - contObj := v1.Container{} - contObj.Name = fmt.Sprintf("cont-%d-%s", port, strings.ToLower(string(protocol))) - contObj.Ports = make([]v1.ContainerPort, 1) - contObj.Ports[0].Name = fmt.Sprintf("serve-%d-%s", port, strings.ToLower(string(protocol))) - contObj.Ports[0].ContainerPort = port - contObj.Ports[0].Protocol = protocol - return contObj -} - -// The following struct holds information for pod creation for tests; -// the pods will be created for every namespace and every pod name below (the Cartesian product), -// having all ports/protocols below in their containers specs -type PodInfo struct { - Namespaces []string - PodNames []string - Ports []int32 - Protocols []v1.Protocol -} - -type Resources struct { - NsList []*v1.Namespace - PodList []*v1.Pod -} - -type EvalAllowedConnTest struct { - Src string - Dst string - ExpResult string -} - -// The following struct holds all test data needed for running a test -// and for verifying its results -type ParsedResourcesTest struct { - Name string - OutputFormat string - ExpectedOutputFileName string - EvalTests []EvalAllowedConnTest - Resources *Resources - AnpList []*v1alpha1.AdminNetworkPolicy - Banp *v1alpha1.BaselineAdminNetworkPolicy - NpList []*netv1.NetworkPolicy - TestInfo string -} - -func addMetaData(meta *metav1.ObjectMeta, addNsName bool) { - if meta.Name == "" { - meta.Name = fmt.Sprintf("generated_name_%q", genCnt) - genCnt++ - } - if addNsName && meta.Namespace == "" { - meta.Namespace = metav1.NamespaceDefault - } -} - -func initResources(podInfo *PodInfo) *Resources { - res := &Resources{[]*v1.Namespace{}, []*v1.Pod{}} - for _, ns := range podInfo.Namespaces { - res.NsList = append(res.NsList, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns, Labels: map[string]string{"ns": ns}}}) - for _, pod := range podInfo.PodNames { - res.PodList = append(res.PodList, newDefaultPod(ns, pod, podInfo.Ports, podInfo.Protocols)) - } - } - return res -} - -func initNpList(npList []*netv1.NetworkPolicy) []*netv1.NetworkPolicy { - for _, np := range npList { - addMetaData(&np.ObjectMeta, true) - } - return npList -} - -func initAnpList(anpList []*v1alpha1.AdminNetworkPolicy) []*v1alpha1.AdminNetworkPolicy { - for _, anp := range anpList { - // ANPs are cluster scoped (has no namespace name) - addMetaData(&anp.ObjectMeta, false) - } - return anpList -} - -func initBanp(banp *v1alpha1.BaselineAdminNetworkPolicy) *v1alpha1.BaselineAdminNetworkPolicy { - banp.Name = "default" // "must use default as the name when creating a BaselineAdminNetworkPolicy object." - return banp -} - -func (test *ParsedResourcesTest) GetK8sObjects() []parser.K8sObject { - res := []parser.K8sObject{} - test.TestInfo = fmt.Sprintf("test: %q, output format: %q", test.Name, test.OutputFormat) - for _, ns := range test.Resources.NsList { - res = append(res, createNamespaceK8sObject(ns)) - } - for _, pod := range test.Resources.PodList { - res = append(res, createPodK8sObject(pod)) - } - for _, np := range test.NpList { - res = append(res, createNetworkPolicyK8sObject(np)) - } - for _, anp := range test.AnpList { - res = append(res, createAdminNetworkPolicyK8sObject(anp)) - } - if test.Banp != nil { - res = append(res, createBaselineAdminNetworkPolicyK8sObject(test.Banp)) - } - return res -} - -func createPodK8sObject(pod *v1.Pod) parser.K8sObject { - k8sObj := parser.K8sObject{} - k8sObj.Kind = podKind - k8sObj.Pod = pod - return k8sObj -} - -func createNamespaceK8sObject(ns *v1.Namespace) parser.K8sObject { - k8sObj := parser.K8sObject{} - k8sObj.Kind = "Namespace" - k8sObj.Namespace = ns - return k8sObj -} - -func createNetworkPolicyK8sObject(np *netv1.NetworkPolicy) parser.K8sObject { - k8sObj := parser.K8sObject{} - k8sObj.Kind = "NetworkPolicy" - k8sObj.NetworkPolicy = np - return k8sObj -} - -func createAdminNetworkPolicyK8sObject(anp *v1alpha1.AdminNetworkPolicy) parser.K8sObject { - k8sObj := parser.K8sObject{} - k8sObj.Kind = "AdminNetworkPolicy" - k8sObj.AdminNetworkPolicy = anp - return k8sObj -} - -func createBaselineAdminNetworkPolicyK8sObject(banp *v1alpha1.BaselineAdminNetworkPolicy) parser.K8sObject { - k8sObj := parser.K8sObject{} - k8sObj.Kind = "BaselineAdminNetworkPolicy" - k8sObj.BaselineAdminNetworkPolicy = banp - return k8sObj -} - -//////////////////////////////////// The following tests are taken from ///////////////////////////////////// -// https://github.com/kubernetes-sigs/network-policy-api/blob/main/cmd/policy-assistant/test/integration/integration_test.go - -var ( - podInfo1 = &PodInfo{Namespaces: []string{"x", "y"}, PodNames: []string{"a", "b"}, - Ports: []int32{80, 81}, Protocols: []v1.Protocol{v1.ProtocolTCP, v1.ProtocolUDP}} - podInfo2 = &PodInfo{Namespaces: []string{"x", "y"}, PodNames: []string{"a", "b"}, - Ports: []int32{80}, Protocols: []v1.Protocol{v1.ProtocolTCP}} + podInfo1 = &podInfo{namespaces: []string{"x", "y"}, podNames: []string{"a", "b"}, + ports: []int32{80, 81}, protocols: []v1.Protocol{v1.ProtocolTCP, v1.ProtocolUDP}} + podInfo2 = &podInfo{namespaces: []string{"x", "y"}, podNames: []string{"a", "b"}, + ports: []int32{80}, protocols: []v1.Protocol{v1.ProtocolTCP}} pods1 = &v1alpha1.NamespacedPod{ NamespaceSelector: metav1.LabelSelector{ MatchLabels: map[string]string{"ns": "x"}, @@ -468,7 +296,10 @@ var ( }, }, }) +) +// testing examples for K8S Network Policy API +var ( ANPConnectivityFromParsedResourcesTest = []ParsedResourcesTest{ { Name: "egress port number protocol unspecified", @@ -583,8 +414,8 @@ var ( ExpResult: allConnsStr, }, }, - Resources: initResources(&PodInfo{Namespaces: []string{"x", "y", "z"}, PodNames: []string{"a", "b", "c"}, - Ports: []int32{80, 81}, Protocols: []v1.Protocol{v1.ProtocolTCP, v1.ProtocolUDP}}), + Resources: initResources(&podInfo{namespaces: []string{"x", "y", "z"}, podNames: []string{"a", "b", "c"}, + ports: []int32{80, 81}, protocols: []v1.Protocol{v1.ProtocolTCP, v1.ProtocolUDP}}), AnpList: initAnpList([]*v1alpha1.AdminNetworkPolicy{ { Spec: v1alpha1.AdminNetworkPolicySpec{ @@ -1468,8 +1299,8 @@ var ( }, }, // note that resources contain only one namespace x - Resources: initResources(&PodInfo{Namespaces: []string{"x"}, PodNames: []string{"a", "b"}, - Ports: []int32{80, 81}, Protocols: []v1.Protocol{v1.ProtocolTCP, v1.ProtocolUDP}}), + Resources: initResources(&podInfo{namespaces: []string{"x"}, podNames: []string{"a", "b"}, + ports: []int32{80, 81}, protocols: []v1.Protocol{v1.ProtocolTCP, v1.ProtocolUDP}}), NpList: initNpList([]*netv1.NetworkPolicy{ { ObjectMeta: metav1.ObjectMeta{ diff --git a/pkg/netpol/internal/examples/parsed_resources_tests.go b/pkg/netpol/internal/examples/parsed_resources_tests.go new file mode 100644 index 00000000..c616ea79 --- /dev/null +++ b/pkg/netpol/internal/examples/parsed_resources_tests.go @@ -0,0 +1,188 @@ +/* +Copyright 2023- IBM Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 + +*/ + +package examples + +import ( + "fmt" + "strings" + + v1 "k8s.io/api/core/v1" + netv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/network-policy-api/apis/v1alpha1" + + "github.com/np-guard/netpol-analyzer/pkg/manifests/parser" +) + +// /////////////////////////////////////// ParsedResourcesTests //////////////////////////////////// +// this file contains pattern for adding tests from parsed resources for netpol packages (api tests) + +var ( + genCnt = 0 +) + +func newDefaultPod(namespace, name string, ports []int32, protocols []v1.Protocol) *v1.Pod { + podObj := v1.Pod{} + podObj.TypeMeta.APIVersion = "v1" + podObj.TypeMeta.Kind = podKind + podObj.ObjectMeta.Name = name + podObj.ObjectMeta.Namespace = namespace + podObj.Status.HostIP = parser.IPv4LoopbackAddr + podObj.Status.PodIPs = []v1.PodIP{{IP: parser.IPv4LoopbackAddr}} + podObj.Labels = map[string]string{"pod": name} + for _, port := range ports { + for _, protocol := range protocols { + podObj.Spec.Containers = append(podObj.Spec.Containers, newDefaultContainer(port, protocol)) + } + } + addMetaData(&podObj.ObjectMeta, true) + return &podObj +} + +func newDefaultContainer(port int32, protocol v1.Protocol) v1.Container { + contObj := v1.Container{} + contObj.Name = fmt.Sprintf("cont-%d-%s", port, strings.ToLower(string(protocol))) + contObj.Ports = make([]v1.ContainerPort, 1) + contObj.Ports[0].Name = fmt.Sprintf("serve-%d-%s", port, strings.ToLower(string(protocol))) + contObj.Ports[0].ContainerPort = port + contObj.Ports[0].Protocol = protocol + return contObj +} + +// The following struct holds information for pod creation for tests; +// the pods will be created for every namespace and every pod name below (the Cartesian product), +// having all ports/protocols below in their containers specs +type podInfo struct { + namespaces []string + podNames []string + ports []int32 + protocols []v1.Protocol +} + +type resources struct { + nsList []*v1.Namespace + podList []*v1.Pod +} + +type EvalAllowedConnTest struct { + Src string + Dst string + ExpResult string +} + +// The following struct holds all test data needed for running a test from parsed resources +// and for verifying its results +type ParsedResourcesTest struct { + Name string + OutputFormat string + ExpectedOutputFileName string + EvalTests []EvalAllowedConnTest + Resources *resources + AnpList []*v1alpha1.AdminNetworkPolicy + Banp *v1alpha1.BaselineAdminNetworkPolicy + NpList []*netv1.NetworkPolicy + TestInfo string +} + +func addMetaData(meta *metav1.ObjectMeta, addNsName bool) { + if meta.Name == "" { + meta.Name = fmt.Sprintf("generated_name_%q", genCnt) + genCnt++ + } + if addNsName && meta.Namespace == "" { + meta.Namespace = metav1.NamespaceDefault + } +} + +func initResources(podInfo *podInfo) *resources { + res := &resources{[]*v1.Namespace{}, []*v1.Pod{}} + for _, ns := range podInfo.namespaces { + res.nsList = append(res.nsList, &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns, Labels: map[string]string{"ns": ns}}}) + for _, pod := range podInfo.podNames { + res.podList = append(res.podList, newDefaultPod(ns, pod, podInfo.ports, podInfo.protocols)) + } + } + return res +} + +func initNpList(npList []*netv1.NetworkPolicy) []*netv1.NetworkPolicy { + for _, np := range npList { + addMetaData(&np.ObjectMeta, true) + } + return npList +} + +func initAnpList(anpList []*v1alpha1.AdminNetworkPolicy) []*v1alpha1.AdminNetworkPolicy { + for _, anp := range anpList { + // ANPs are cluster scoped (has no namespace name) + addMetaData(&anp.ObjectMeta, false) + } + return anpList +} + +func initBanp(banp *v1alpha1.BaselineAdminNetworkPolicy) *v1alpha1.BaselineAdminNetworkPolicy { + banp.Name = "default" // "must use default as the name when creating a BaselineAdminNetworkPolicy object." + return banp +} + +func (test *ParsedResourcesTest) GetK8sObjects() []parser.K8sObject { + res := []parser.K8sObject{} + test.TestInfo = fmt.Sprintf("test: %q, output format: %q", test.Name, test.OutputFormat) + for _, ns := range test.Resources.nsList { + res = append(res, createNamespaceK8sObject(ns)) + } + for _, pod := range test.Resources.podList { + res = append(res, createPodK8sObject(pod)) + } + for _, np := range test.NpList { + res = append(res, createNetworkPolicyK8sObject(np)) + } + for _, anp := range test.AnpList { + res = append(res, createAdminNetworkPolicyK8sObject(anp)) + } + if test.Banp != nil { + res = append(res, createBaselineAdminNetworkPolicyK8sObject(test.Banp)) + } + return res +} + +func createPodK8sObject(pod *v1.Pod) parser.K8sObject { + k8sObj := parser.K8sObject{} + k8sObj.Kind = podKind + k8sObj.Pod = pod + return k8sObj +} + +func createNamespaceK8sObject(ns *v1.Namespace) parser.K8sObject { + k8sObj := parser.K8sObject{} + k8sObj.Kind = "Namespace" + k8sObj.Namespace = ns + return k8sObj +} + +func createNetworkPolicyK8sObject(np *netv1.NetworkPolicy) parser.K8sObject { + k8sObj := parser.K8sObject{} + k8sObj.Kind = "NetworkPolicy" + k8sObj.NetworkPolicy = np + return k8sObj +} + +func createAdminNetworkPolicyK8sObject(anp *v1alpha1.AdminNetworkPolicy) parser.K8sObject { + k8sObj := parser.K8sObject{} + k8sObj.Kind = "AdminNetworkPolicy" + k8sObj.AdminNetworkPolicy = anp + return k8sObj +} + +func createBaselineAdminNetworkPolicyK8sObject(banp *v1alpha1.BaselineAdminNetworkPolicy) parser.K8sObject { + k8sObj := parser.K8sObject{} + k8sObj.Kind = "BaselineAdminNetworkPolicy" + k8sObj.BaselineAdminNetworkPolicy = banp + return k8sObj +} diff --git a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.csv b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.csv index 5cd03c71..815f6c25 100644 --- a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.csv +++ b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.csv @@ -2,6 +2,7 @@ src,dst,conn 0.0.0.0-255.255.255.255,network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet],All Connections 0.0.0.0-255.255.255.255,network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet],All Connections 0.0.0.0-255.255.255.255,network-policy-conformance-slytherin/draco-malfoy[StatefulSet],All Connections +network-policy-conformance-gryffindor/harry-potter[StatefulSet],network-policy-conformance-slytherin/draco-malfoy[StatefulSet],All Connections network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet],0.0.0.0-255.255.255.255,All Connections network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet],network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet],All Connections network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet],network-policy-conformance-slytherin/draco-malfoy[StatefulSet],All Connections diff --git a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot index e800abca..a6672324 100644 --- a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot +++ b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot @@ -27,6 +27,7 @@ digraph { "0.0.0.0-255.255.255.255" -> "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" [label="All Connections" color="gold2" fontcolor="darkgreen" weight=0.5] "0.0.0.0-255.255.255.255" -> "network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]" [label="All Connections" color="gold2" fontcolor="darkgreen" weight=0.5] "0.0.0.0-255.255.255.255" -> "network-policy-conformance-slytherin/draco-malfoy[StatefulSet]" [label="All Connections" color="gold2" fontcolor="darkgreen" weight=0.5] + "network-policy-conformance-gryffindor/harry-potter[StatefulSet]" -> "network-policy-conformance-slytherin/draco-malfoy[StatefulSet]" [label="All Connections" color="gold2" fontcolor="darkgreen" weight=0.5] "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" -> "0.0.0.0-255.255.255.255" [label="All Connections" color="gold2" fontcolor="darkgreen" weight=1] "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" -> "network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]" [label="All Connections" color="gold2" fontcolor="darkgreen" weight=0.5] "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" -> "network-policy-conformance-slytherin/draco-malfoy[StatefulSet]" [label="All Connections" color="gold2" fontcolor="darkgreen" weight=0.5] diff --git a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.png b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.png index 957d21de..65e8576a 100644 Binary files a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.png and b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.png differ diff --git a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.svg b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.svg index e7c78b65..f4323caa 100644 --- a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.svg +++ b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.dot.svg @@ -4,150 +4,157 @@ - + - - -cluster_network_policy_conformance_slytherin - -network-policy-conformance-slytherin + + +cluster_network_policy_conformance_ravenclaw + +network-policy-conformance-ravenclaw cluster_network_policy_conformance_hufflepuff - -network-policy-conformance-hufflepuff + +network-policy-conformance-hufflepuff cluster_network_policy_conformance_gryffindor - -network-policy-conformance-gryffindor + +network-policy-conformance-gryffindor - -cluster_network_policy_conformance_ravenclaw - -network-policy-conformance-ravenclaw + +cluster_network_policy_conformance_slytherin + +network-policy-conformance-slytherin network-policy-conformance-gryffindor/harry-potter[StatefulSet] - -harry-potter[StatefulSet] + +harry-potter[StatefulSet] + + + +network-policy-conformance-slytherin/draco-malfoy[StatefulSet] + +draco-malfoy[StatefulSet] + + + +network-policy-conformance-gryffindor/harry-potter[StatefulSet]->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] + + +All Connections network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - -cedric-diggory[StatefulSet] + +cedric-diggory[StatefulSet] network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - -luna-lovegood[StatefulSet] + +luna-lovegood[StatefulSet] - + network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]->network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - - -All Connections - - - -network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - -draco-malfoy[StatefulSet] + + +All Connections - + network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255 - -0.0.0.0-255.255.255.255 + +0.0.0.0-255.255.255.255 - + network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]->0.0.0.0-255.255.255.255 - - -All Connections + + +All Connections - + network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]->network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]->0.0.0.0-255.255.255.255 - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->network-policy-conformance-gryffindor/harry-potter[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->0.0.0.0-255.255.255.255 - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255->network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255->network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - - -All Connections + + +All Connections diff --git a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.json b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.json index b6823eff..97a33df9 100644 --- a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.json +++ b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.json @@ -14,6 +14,11 @@ "dst": "network-policy-conformance-slytherin/draco-malfoy[StatefulSet]", "conn": "All Connections" }, + { + "src": "network-policy-conformance-gryffindor/harry-potter[StatefulSet]", + "dst": "network-policy-conformance-slytherin/draco-malfoy[StatefulSet]", + "conn": "All Connections" + }, { "src": "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]", "dst": "0.0.0.0-255.255.255.255", diff --git a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.md b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.md index 7f60ca72..04250a7a 100644 --- a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.md +++ b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.md @@ -3,6 +3,7 @@ | 0.0.0.0-255.255.255.255 | network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] | All Connections | | 0.0.0.0-255.255.255.255 | network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] | All Connections | | 0.0.0.0-255.255.255.255 | network-policy-conformance-slytherin/draco-malfoy[StatefulSet] | All Connections | +| network-policy-conformance-gryffindor/harry-potter[StatefulSet] | network-policy-conformance-slytherin/draco-malfoy[StatefulSet] | All Connections | | network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] | 0.0.0.0-255.255.255.255 | All Connections | | network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] | network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] | All Connections | | network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] | network-policy-conformance-slytherin/draco-malfoy[StatefulSet] | All Connections | diff --git a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.txt b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.txt index 784cbe7b..42d61601 100644 --- a/test_outputs/connlist/anp_np_banp_core_test_connlist_output.txt +++ b/test_outputs/connlist/anp_np_banp_core_test_connlist_output.txt @@ -1,6 +1,7 @@ 0.0.0.0-255.255.255.255 => network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] : All Connections 0.0.0.0-255.255.255.255 => network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] : All Connections 0.0.0.0-255.255.255.255 => network-policy-conformance-slytherin/draco-malfoy[StatefulSet] : All Connections +network-policy-conformance-gryffindor/harry-potter[StatefulSet] => network-policy-conformance-slytherin/draco-malfoy[StatefulSet] : All Connections network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] => 0.0.0.0-255.255.255.255 : All Connections network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] => network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] : All Connections network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] => network-policy-conformance-slytherin/draco-malfoy[StatefulSet] : All Connections diff --git a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.csv b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.csv index e7c07d91..6ef75e47 100644 --- a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.csv +++ b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.csv @@ -5,4 +5,5 @@ added,network-policy-conformance-gryffindor/harry-potter[StatefulSet],network-po added,network-policy-conformance-gryffindor/harry-potter[StatefulSet],network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet],No Connections,All Connections, added,network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet],network-policy-conformance-gryffindor/harry-potter[StatefulSet],No Connections,All Connections, added,network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet],network-policy-conformance-gryffindor/harry-potter[StatefulSet],No Connections,All Connections, +removed,network-policy-conformance-gryffindor/harry-potter[StatefulSet],network-policy-conformance-slytherin/draco-malfoy[StatefulSet],All Connections,No Connections, removed,network-policy-conformance-slytherin/draco-malfoy[StatefulSet],network-policy-conformance-gryffindor/harry-potter[StatefulSet],All Connections,No Connections, diff --git a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot index 164e19e7..5d7c40f8 100644 --- a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot +++ b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot @@ -31,6 +31,7 @@ digraph { "network-policy-conformance-gryffindor/harry-potter[StatefulSet]" -> "0.0.0.0-255.255.255.255" [label="All Connections" color="#008000" fontcolor="#008000" weight=1] "network-policy-conformance-gryffindor/harry-potter[StatefulSet]" -> "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" [label="All Connections" color="#008000" fontcolor="#008000" weight=0.5] "network-policy-conformance-gryffindor/harry-potter[StatefulSet]" -> "network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]" [label="All Connections" color="#008000" fontcolor="#008000" weight=0.5] + "network-policy-conformance-gryffindor/harry-potter[StatefulSet]" -> "network-policy-conformance-slytherin/draco-malfoy[StatefulSet]" [label="All Connections" color="red2" fontcolor="red2" weight=0.5] "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" -> "0.0.0.0-255.255.255.255" [label="All Connections" color="grey" fontcolor="grey" weight=1] "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" -> "network-policy-conformance-gryffindor/harry-potter[StatefulSet]" [label="All Connections" color="#008000" fontcolor="#008000" weight=1] "network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]" -> "network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]" [label="All Connections" color="grey" fontcolor="grey" weight=0.5] diff --git a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.png b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.png index d1b25531..9ef0722f 100644 Binary files a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.png and b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.png differ diff --git a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.svg b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.svg index 6f76ac7d..517a4593 100644 --- a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.svg +++ b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.dot.svg @@ -4,252 +4,259 @@ - + - - -cluster_network_policy_conformance_ravenclaw - -network-policy-conformance-ravenclaw - + cluster_network_policy_conformance_slytherin - -network-policy-conformance-slytherin + +network-policy-conformance-slytherin cluster_network_policy_conformance_hufflepuff - -network-policy-conformance-hufflepuff + +network-policy-conformance-hufflepuff cluster_network_policy_conformance_gryffindor - -network-policy-conformance-gryffindor + +network-policy-conformance-gryffindor + + +cluster_network_policy_conformance_ravenclaw + +network-policy-conformance-ravenclaw cluster_legend - -Legend + +Legend network-policy-conformance-gryffindor/harry-potter[StatefulSet] - -harry-potter[StatefulSet] + +harry-potter[StatefulSet] network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - -cedric-diggory[StatefulSet] + +cedric-diggory[StatefulSet] network-policy-conformance-gryffindor/harry-potter[StatefulSet]->network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - - -All Connections + + +All Connections network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - -luna-lovegood[StatefulSet] + +luna-lovegood[StatefulSet] network-policy-conformance-gryffindor/harry-potter[StatefulSet]->network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - - -All Connections + + +All Connections + + + +network-policy-conformance-slytherin/draco-malfoy[StatefulSet] + +draco-malfoy[StatefulSet] + + + +network-policy-conformance-gryffindor/harry-potter[StatefulSet]->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] + + +All Connections 0.0.0.0-255.255.255.255 - -0.0.0.0-255.255.255.255 + +0.0.0.0-255.255.255.255 network-policy-conformance-gryffindor/harry-potter[StatefulSet]->0.0.0.0-255.255.255.255 - - -All Connections + + +All Connections - + network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]->network-policy-conformance-gryffindor/harry-potter[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]->network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - - -All Connections - - - -network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - -draco-malfoy[StatefulSet] + + +All Connections - + network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet]->0.0.0.0-255.255.255.255 - - -All Connections + + +All Connections - + network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]->network-policy-conformance-gryffindor/harry-potter[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]->network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet]->0.0.0.0-255.255.255.255 - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->network-policy-conformance-gryffindor/harry-potter[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - - -All Connections + + +All Connections - + network-policy-conformance-slytherin/draco-malfoy[StatefulSet]->0.0.0.0-255.255.255.255 - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255->network-policy-conformance-gryffindor/harry-potter[StatefulSet] - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255->network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255->network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] - - -All Connections + + +All Connections 0.0.0.0-255.255.255.255->network-policy-conformance-slytherin/draco-malfoy[StatefulSet] - - -All Connections + + +All Connections - + a->b - - -added connection + + +added connection - + c->d - - -removed connection + + +removed connection - + e->f - - -changed connection + + +changed connection - + g->h - - -unchanged connection + + +unchanged connection np - -new peer + +new peer lp - -lost peer + +lost peer pp - -persistent peer + +persistent peer diff --git a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.md b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.md index 7bbf22a8..589d4693 100644 --- a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.md +++ b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.md @@ -6,4 +6,5 @@ | added | network-policy-conformance-gryffindor/harry-potter[StatefulSet] | network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] | No Connections | All Connections | | | added | network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet] | network-policy-conformance-gryffindor/harry-potter[StatefulSet] | No Connections | All Connections | | | added | network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet] | network-policy-conformance-gryffindor/harry-potter[StatefulSet] | No Connections | All Connections | | +| removed | network-policy-conformance-gryffindor/harry-potter[StatefulSet] | network-policy-conformance-slytherin/draco-malfoy[StatefulSet] | All Connections | No Connections | | | removed | network-policy-conformance-slytherin/draco-malfoy[StatefulSet] | network-policy-conformance-gryffindor/harry-potter[StatefulSet] | All Connections | No Connections | | \ No newline at end of file diff --git a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.txt b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.txt index 69e5deec..55e8cedb 100644 --- a/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.txt +++ b/test_outputs/diff/diff_between_anp_banp_core_test_and_anp_np_banp_core_test.txt @@ -5,4 +5,5 @@ diff-type: added, source: network-policy-conformance-gryffindor/harry-potter[Sta diff-type: added, source: network-policy-conformance-gryffindor/harry-potter[StatefulSet], destination: network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet], ref1: No Connections, ref2: All Connections diff-type: added, source: network-policy-conformance-hufflepuff/cedric-diggory[StatefulSet], destination: network-policy-conformance-gryffindor/harry-potter[StatefulSet], ref1: No Connections, ref2: All Connections diff-type: added, source: network-policy-conformance-ravenclaw/luna-lovegood[StatefulSet], destination: network-policy-conformance-gryffindor/harry-potter[StatefulSet], ref1: No Connections, ref2: All Connections +diff-type: removed, source: network-policy-conformance-gryffindor/harry-potter[StatefulSet], destination: network-policy-conformance-slytherin/draco-malfoy[StatefulSet], ref1: All Connections, ref2: No Connections diff-type: removed, source: network-policy-conformance-slytherin/draco-malfoy[StatefulSet], destination: network-policy-conformance-gryffindor/harry-potter[StatefulSet], ref1: All Connections, ref2: No Connections \ No newline at end of file