diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1d43335c..8bd52da0 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@a5ac7e51b41094c92402da3b24376905380afc29 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f079b8493333aace61c81488f8bd40919487bd9f + uses: github/codeql-action/init@23acc5c183826b7a8a97bce3cecc52db901f8251 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@f079b8493333aace61c81488f8bd40919487bd9f + uses: github/codeql-action/autobuild@23acc5c183826b7a8a97bce3cecc52db901f8251 # ℹī¸ 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@f079b8493333aace61c81488f8bd40919487bd9f + uses: github/codeql-action/analyze@23acc5c183826b7a8a97bce3cecc52db901f8251 diff --git a/.github/workflows/go-build.yml b/.github/workflows/go-build.yml index 35c8dce7..36218b48 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@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - name: Set up Go uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index f7c6d5b6..a24183ac 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -11,7 +11,7 @@ jobs: name: golangci-lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 with: go-version-file: ./go.mod diff --git a/.github/workflows/make-release.yaml b/.github/workflows/make-release.yaml index fae6d795..ddae929f 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@a5ac7e51b41094c92402da3b24376905380afc29 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 - name: Set up Go uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 diff --git a/go.mod b/go.mod index 18036aa0..45974edf 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/np-guard/models v0.3.2 github.com/openshift/api v0.0.0-20230502160752-c71432710382 - github.com/spf13/cobra v1.8.0 + github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 k8s.io/api v0.29.2 k8s.io/apimachinery v0.29.2 diff --git a/go.sum b/go.sum index a33f7aaa..b371b82e 100644 --- a/go.sum +++ b/go.sum @@ -5,7 +5,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -114,8 +114,8 @@ github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncj github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/pkg/netpol/connlist/connlist.go b/pkg/netpol/connlist/connlist.go index 6c9a94c7..a1148082 100644 --- a/pkg/netpol/connlist/connlist.go +++ b/pkg/netpol/connlist/connlist.go @@ -47,6 +47,7 @@ type ConnlistAnalyzer struct { focusWorkload string outputFormat string muteErrsAndWarns bool + peersList []Peer // internally used peersList used in dot formatting; in case of focusWorkload option contains only relevant peers } // The new interface @@ -240,7 +241,7 @@ func (ca *ConnlistAnalyzer) ConnlistFromK8sCluster(clientset *kubernetes.Clients // ConnectionsListToString returns a string of connections from list of Peer2PeerConnection objects in the required output format func (ca *ConnlistAnalyzer) ConnectionsListToString(conns []Peer2PeerConnection) (string, error) { - connsFormatter, err := getFormatter(ca.outputFormat) + connsFormatter, err := getFormatter(ca.outputFormat, ca.peersList) if err != nil { ca.errors = append(ca.errors, newResultFormattingError(err)) return "", err @@ -264,7 +265,7 @@ func ValidateOutputFormat(format string) error { } // returns the relevant formatter for the analyzer's outputFormat -func getFormatter(format string) (connsFormatter, error) { +func getFormatter(format string, peersList []Peer) (connsFormatter, error) { if err := ValidateOutputFormat(format); err != nil { return nil, err } @@ -274,7 +275,7 @@ func getFormatter(format string) (connsFormatter, error) { case output.TextFormat: return formatText{}, nil case output.DOTFormat: - return formatDOT{}, nil + return formatDOT{peersList: peersList}, nil case output.CSVFormat: return formatCSV{}, nil case output.MDFormat: @@ -350,7 +351,7 @@ func getPeerNsNameFormat(peer eval.Peer) string { } func (ca *ConnlistAnalyzer) isPeerFocusWorkload(peer eval.Peer) bool { - return !peer.IsPeerIPType() && (peer.Name() == ca.focusWorkload || getPeerNsNameFormat(peer) == ca.focusWorkload) + return peer.Name() == ca.focusWorkload || getPeerNsNameFormat(peer) == ca.focusWorkload } // getConnectionsList returns connections list from PolicyEngine and ingressAnalyzer objects @@ -369,14 +370,18 @@ func (ca *ConnlistAnalyzer) getConnectionsList(pe *eval.PolicyEngine, ia *ingres } // represent peerList as []connlist.Peer list to be returned peers := make([]Peer, len(peerList)) + ca.peersList = make([]Peer, 0, len(peerList)) for i, p := range peerList { peers[i] = p + if ca.focusWorkload == "" || ca.isPeerFocusWorkload(p) { + ca.peersList = append(ca.peersList, p) + } } excludeIngressAnalysis := (ia == nil || ia.IsEmpty()) // if ca.focusWorkload is not empty, check if it exists in the peers before proceeding - existFocusWorkload, warningMsg := ca.existsFocusWorkload(peers, excludeIngressAnalysis) + existFocusWorkload, warningMsg := ca.existsFocusWorkload(excludeIngressAnalysis) if ca.focusWorkload != "" && !existFocusWorkload { ca.errors = append(ca.errors, newConnlistAnalyzerWarning(errors.New(warningMsg))) ca.logWarning(warningMsg) @@ -413,7 +418,7 @@ func (ca *ConnlistAnalyzer) getConnectionsList(pe *eval.PolicyEngine, ia *ingres // existsFocusWorkload checks if the provided focus workload is ingress-controller // or if it exists in the peers list from the parsed resources // if not returns a suitable warning message -func (ca *ConnlistAnalyzer) existsFocusWorkload(peers []Peer, excludeIngressAnalysis bool) (existFocusWorkload bool, warning string) { +func (ca *ConnlistAnalyzer) existsFocusWorkload(excludeIngressAnalysis bool) (existFocusWorkload bool, warning string) { if ca.focusWorkload == common.IngressPodName { if excludeIngressAnalysis { // if the ingress-analyzer is empty, // then no routes/k8s-ingress objects -> ingrss-controller pod will not be added @@ -423,8 +428,8 @@ func (ca *ConnlistAnalyzer) existsFocusWorkload(peers []Peer, excludeIngressAnal } // check if the focusworkload is in the peers - for _, peer := range peers { - if ca.focusWorkload == peer.Name() || ca.focusWorkload == getPeerNsNameFormat(peer) { + for _, peer := range ca.peersList { + if ca.isPeerFocusWorkload(peer) { return true, "" } } diff --git a/pkg/netpol/connlist/conns_formatter_dot.go b/pkg/netpol/connlist/conns_formatter_dot.go index 5f4a6e25..e4f3a290 100644 --- a/pkg/netpol/connlist/conns_formatter_dot.go +++ b/pkg/netpol/connlist/conns_formatter_dot.go @@ -22,6 +22,7 @@ const ( // formatDOT: implements the connsFormatter interface for dot output format type formatDOT struct { + peersList []Peer // internally used peersList; in case of focusWorkload option contains only relevant peers } // formats an edge line from a singleConnFields struct , to be used for dot graph @@ -46,6 +47,20 @@ func getPeerLine(peer Peer) (string, bool) { return fmt.Sprintf("\t%q [label=%q color=%q fontcolor=%q]", peer.String(), peerNameLabel, peerColor, peerColor), isExternalPeer } +func categorizeAndAddPeerLine(peer Peer, peersVisited map[string]bool, externalPeersLines []string, nsPeers map[string][]string) []string { + peerStr := peer.String() + if !peersVisited[peerStr] { + peersVisited[peerStr] = true + peerLine, isExternalPeer := getPeerLine(peer) + if isExternalPeer { // peer that does not belong to a cluster's namespace (i.e. ip/ ingress-controller) + externalPeersLines = append(externalPeersLines, peerLine) + } else { // add to Ns group + dotformatting.AddPeerToNsGroup(peer.Namespace(), peerLine, nsPeers) + } + } + return externalPeersLines +} + // returns a dot string form of connections from list of Peer2PeerConnection objects func (d formatDOT) writeOutput(conns []Peer2PeerConnection) (string, error) { nsPeers := make(map[string][]string) // map from namespace to its peers (grouping peers by namespaces) @@ -53,27 +68,16 @@ func (d formatDOT) writeOutput(conns []Peer2PeerConnection) (string, error) { edgeLines := make([]string, len(conns)) // list of edges lines peersVisited := make(map[string]bool, 0) // acts as a set for index := range conns { - srcStr, dstStr := conns[index].Src().String(), conns[index].Dst().String() edgeLines[index] = getEdgeLine(conns[index]) - if !peersVisited[srcStr] { - peersVisited[srcStr] = true - peerLine, isExternalPeer := getPeerLine(conns[index].Src()) - if isExternalPeer { // peer that does not belong to a cluster's namespace (i.e. ip/ ingress-controller) - externalPeersLines = append(externalPeersLines, peerLine) - } else { // add to Ns group - dotformatting.AddPeerToNsGroup(conns[index].Src().Namespace(), peerLine, nsPeers) - } - } - if !peersVisited[dstStr] { - peersVisited[dstStr] = true - peerLine, isExternalPeer := getPeerLine(conns[index].Dst()) - if isExternalPeer { - externalPeersLines = append(externalPeersLines, peerLine) - } else { - dotformatting.AddPeerToNsGroup(conns[index].Dst().Namespace(), peerLine, nsPeers) - } + externalPeersLines = categorizeAndAddPeerLine(conns[index].Src(), peersVisited, externalPeersLines, nsPeers) + externalPeersLines = categorizeAndAddPeerLine(conns[index].Dst(), peersVisited, externalPeersLines, nsPeers) + } + for _, val := range d.peersList { + if !val.IsPeerIPType() { + externalPeersLines = categorizeAndAddPeerLine(val, peersVisited, externalPeersLines, nsPeers) } } + // sort graph lines sort.Strings(edgeLines) sort.Strings(externalPeersLines) diff --git a/test_outputs/connlist/acs_security_frontend_demos_connlist_output.dot b/test_outputs/connlist/acs_security_frontend_demos_connlist_output.dot index 27f36df1..6b2002b2 100644 --- a/test_outputs/connlist/acs_security_frontend_demos_connlist_output.dot +++ b/test_outputs/connlist/acs_security_frontend_demos_connlist_output.dot @@ -1,2 +1,7 @@ digraph { + subgraph cluster_frontend { + "frontend/asset-cache[Deployment]" [label="asset-cache[Deployment]" color="blue" fontcolor="blue"] + "frontend/webapp[Deployment]" [label="webapp[Deployment]" color="blue" fontcolor="blue"] + label="frontend" + } } \ No newline at end of file diff --git a/test_outputs/diff/diff_between_netpol-diff-example-minimal_and_netpol-analysis-example-minimal.dot.svg b/test_outputs/diff/diff_between_netpol-diff-example-minimal_and_netpol-analysis-example-minimal.dot.svg index abeb61ff..93d53fee 100644 --- a/test_outputs/diff/diff_between_netpol-diff-example-minimal_and_netpol-analysis-example-minimal.dot.svg +++ b/test_outputs/diff/diff_between_netpol-diff-example-minimal_and_netpol-analysis-example-minimal.dot.svg @@ -1,22 +1,22 @@ - - - - + + + cluster_default - -default + +default cluster_legend - -Legend + +Legend @@ -27,97 +27,97 @@ default/frontend[Deployment] - -frontend[Deployment] + +frontend[Deployment] default/frontend[Deployment]->default/backend[Deployment] - - -TCP 9090,UDP 53 (ref1: TCP 9090) + + +TCP 9090,UDP 53 (dir1: TCP 9090) 0.0.0.0-255.255.255.255 - -0.0.0.0-255.255.255.255 + +0.0.0.0-255.255.255.255 default/frontend[Deployment]->0.0.0.0-255.255.255.255 - - -UDP 53 + + +UDP 53 0.0.0.0-255.255.255.255->default/backend[Deployment] - - -TCP 9090 + + +TCP 9090 0.0.0.0-255.255.255.255->default/frontend[Deployment] - - -TCP 8080 + + +TCP 8080 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