Repository: yonahd/kor
Pull request #327 (2024-07-08 18:04:55)

chore: move slack to utils directory

## What this PR does / why we need it?

This organizes the code in a better fashion moving the slack out of the core functionality directory

## PR Checklist

[x] This PR move the slack related code to utils





Patch:
diff --git a/README.md b/README.md
index 80fdee8..748a2da 100644
--- a/README.md
+++ b/README.md
@@ -177,7 +177,7 @@ kor [subcommand] --help
 | ReplicaSets     | replicaSets that specify replicas to 0 and has already completed it's work                                                                                                                                                        |
 | DaemonSets      | DaemonSets not scheduled on any nodes                                                                                                                                                                                             |
 | StorageClasses  | StorageClasses not used by any PVs/PVCs                                                                                                                                                                                           |
-| NetworkPolicies  | NetworkPolicies with no Pods selected                                                                                                                                                                                           |
+| NetworkPolicies  | NetworkPolicies with no Pods selected by podSelector or Ingress/Egress rules                                                                                                                                                                                           |
 
 ### Deleting Unused resources
 
diff --git a/charts/kor/Chart.yaml b/charts/kor/Chart.yaml
index 18a2797..fffea60 100644
--- a/charts/kor/Chart.yaml
+++ b/charts/kor/Chart.yaml
@@ -2,8 +2,8 @@ apiVersion: v2
 name: kor
 description: A Kubernetes Helm Chart to discover orphaned resources using kor
 type: application
-version: 0.1.9
-appVersion: "0.5.1"
+version: 0.1.10
+appVersion: "0.5.2"
 maintainers:
   - name: "yonahd"
     url: "https://github.com/yonahd/kor"
diff --git a/charts/kor/README.md b/charts/kor/README.md
index d329280..7eb79fd 100644
--- a/charts/kor/README.md
+++ b/charts/kor/README.md
@@ -1,6 +1,6 @@
 # kor
 
-![Version: 0.1.9](https://img.shields.io/badge/Version-0.1.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.1](https://img.shields.io/badge/AppVersion-0.5.1-informational?style=flat-square)
+![Version: 0.1.10](https://img.shields.io/badge/Version-0.1.10-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.2](https://img.shields.io/badge/AppVersion-0.5.2-informational?style=flat-square)
 
 A Kubernetes Helm Chart to discover orphaned resources using kor
 
@@ -61,4 +61,4 @@ A Kubernetes Helm Chart to discover orphaned resources using kor
 | serviceAccount.name | string | `""` | If not set and create is true, a name is generated using the fullname template |
 
 ----------------------------------------------
-Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1)
+Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2)
diff --git a/cmd/kor/root.go b/cmd/kor/root.go
index 48b0500..17c818e 100644
--- a/cmd/kor/root.go
+++ b/cmd/kor/root.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/spf13/cobra"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 	"github.com/yonahd/kor/pkg/kor"
 	"github.com/yonahd/kor/pkg/utils"
@@ -46,7 +47,7 @@ var rootCmd = &cobra.Command{
 var (
 	outputFormat  string
 	kubeconfig    string
-	opts          kor.Opts
+	opts          common.Opts
 	filterOptions = &filters.Options{}
 )
 
diff --git a/go.mod b/go.mod
index b449470..5aafc87 100644
--- a/go.mod
+++ b/go.mod
@@ -9,10 +9,10 @@ require (
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/prometheus/client_golang v1.19.1
 	github.com/spf13/cobra v1.8.1
-	k8s.io/api v0.30.2
-	k8s.io/apiextensions-apiserver v0.30.2
-	k8s.io/apimachinery v0.30.2
-	k8s.io/client-go v0.30.2
+	k8s.io/api v0.30.3
+	k8s.io/apiextensions-apiserver v0.30.3
+	k8s.io/apimachinery v0.30.3
+	k8s.io/client-go v0.30.3
 	k8s.io/utils v0.0.0-20230726121419-3b25d923346b
 	sigs.k8s.io/yaml v1.4.0
 )
diff --git a/go.sum b/go.sum
index fdca198..5de1ff1 100644
--- a/go.sum
+++ b/go.sum
@@ -173,14 +173,14 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
-k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
-k8s.io/apiextensions-apiserver v0.30.2 h1:l7Eue2t6QiLHErfn2vwK4KgF4NeDgjQkCXtEbOocKIE=
-k8s.io/apiextensions-apiserver v0.30.2/go.mod h1:lsJFLYyK40iguuinsb3nt+Sj6CmodSI4ACDLep1rgjw=
-k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
-k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
-k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=
-k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs=
+k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
+k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
+k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U=
+k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4=
+k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc=
+k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
+k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k=
+k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U=
 k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
 k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
diff --git a/pkg/common/params.go b/pkg/common/params.go
new file mode 100644
index 0000000..2effe96
--- /dev/null
+++ b/pkg/common/params.go
@@ -0,0 +1,12 @@
+package common
+
+type Opts struct {
+	DeleteFlag    bool
+	NoInteractive bool
+	Verbose       bool
+	WebhookURL    string
+	Channel       string
+	Token         string
+	GroupBy       string
+	ShowReason    bool
+}
diff --git a/pkg/kor/all.go b/pkg/kor/all.go
index 1d8a81d..37af741 100644
--- a/pkg/kor/all.go
+++ b/pkg/kor/all.go
@@ -10,6 +10,7 @@ import (
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -263,7 +264,7 @@ func getUnusedNetworkPolicies(clientset kubernetes.Interface, namespace string,
 	return namespaceNetpolDiff
 }
 
-func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		switch opts.GroupBy {
@@ -325,7 +326,7 @@ func GetUnusedAllNamespaced(filterOpts *filters.Options, clientset kubernetes.In
 	return unusedAllNamespaced, nil
 }
 
-func GetUnusedAllNonNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedAllNonNamespaced(filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	switch opts.GroupBy {
 	case "namespace":
@@ -361,7 +362,7 @@ func GetUnusedAllNonNamespaced(filterOpts *filters.Options, clientset kubernetes
 	return unusedAllNonNamespaced, nil
 }
 
-func GetUnusedAll(filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedAll(filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
 	unusedAllNamespaced, err := GetUnusedAllNamespaced(filterOpts, clientset, outputFormat, opts)
 	if err != nil {
 		fmt.Printf("err: %v\n", err)
diff --git a/pkg/kor/clusterroles.go b/pkg/kor/clusterroles.go
index ee3dd6d..d11f54a 100644
--- a/pkg/kor/clusterroles.go
+++ b/pkg/kor/clusterroles.go
@@ -15,6 +15,7 @@ import (
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 	"k8s.io/utils/strings/slices"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -179,7 +180,7 @@ func processClusterRoles(clientset kubernetes.Interface, filterOpts *filters.Opt
 
 }
 
-func GetUnusedClusterRoles(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedClusterRoles(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	diff, err := processClusterRoles(clientset, filterOpts)
 	if err != nil {
diff --git a/pkg/kor/configmaps.go b/pkg/kor/configmaps.go
index fe9e5cf..44b57fd 100644
--- a/pkg/kor/configmaps.go
+++ b/pkg/kor/configmaps.go
@@ -12,6 +12,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -158,7 +159,7 @@ func processNamespaceCM(clientset kubernetes.Interface, namespace string, filter
 	return diff, nil
 }
 
-func GetUnusedConfigmaps(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedConfigmaps(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceCM(clientset, namespace, filterOpts)
diff --git a/pkg/kor/crds.go b/pkg/kor/crds.go
index af61b52..1975b2e 100644
--- a/pkg/kor/crds.go
+++ b/pkg/kor/crds.go
@@ -14,6 +14,7 @@ import (
 	"k8s.io/client-go/dynamic"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -65,7 +66,7 @@ func processCrds(apiExtClient apiextensionsclientset.Interface, dynamicClient dy
 	return unusedCRDs, nil
 }
 
-func GetUnusedCrds(_ *filters.Options, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedCrds(_ *filters.Options, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	diff, err := processCrds(apiExtClient, dynamicClient, &filters.Options{})
 	if err != nil {
diff --git a/pkg/kor/daemonsets.go b/pkg/kor/daemonsets.go
index 7437ff9..1c88d6b 100644
--- a/pkg/kor/daemonsets.go
+++ b/pkg/kor/daemonsets.go
@@ -11,6 +11,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -59,7 +60,7 @@ func processNamespaceDaemonSets(clientset kubernetes.Interface, namespace string
 	return daemonSetsWithoutReplicas, nil
 }
 
-func GetUnusedDaemonSets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedDaemonSets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceDaemonSets(clientset, namespace, filterOpts)
diff --git a/pkg/kor/deployments.go b/pkg/kor/deployments.go
index 50d6784..efc7c05 100644
--- a/pkg/kor/deployments.go
+++ b/pkg/kor/deployments.go
@@ -10,6 +10,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -41,7 +42,7 @@ func processNamespaceDeployments(clientset kubernetes.Interface, namespace strin
 	return deploymentsWithoutReplicas, nil
 }
 
-func GetUnusedDeployments(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedDeployments(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceDeployments(clientset, namespace, filterOpts)
diff --git a/pkg/kor/exporter.go b/pkg/kor/exporter.go
index 830e650..39b66c3 100644
--- a/pkg/kor/exporter.go
+++ b/pkg/kor/exporter.go
@@ -15,6 +15,7 @@ import (
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -33,7 +34,7 @@ func init() {
 }
 
 // TODO: add option to change port / url !?
-func Exporter(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts, resourceList []string) {
+func Exporter(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts, resourceList []string) {
 	http.Handle("/metrics", promhttp.Handler())
 	fmt.Println("Server listening on :8080")
 	go exportMetrics(filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts, resourceList) // Start exporting metrics in the background
@@ -42,7 +43,7 @@ func Exporter(filterOptions *filters.Options, clientset kubernetes.Interface, ap
 	}
 }
 
-func exportMetrics(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts, resourceList []string) {
+func exportMetrics(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts, resourceList []string) {
 	exporterInterval := os.Getenv("EXPORTER_INTERVAL")
 	if exporterInterval == "" {
 		exporterInterval = "10"
@@ -79,7 +80,7 @@ func exportMetrics(filterOptions *filters.Options, clientset kubernetes.Interfac
 	}
 }
 
-func getUnusedResources(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts, resourceList []string) (string, error) {
+func getUnusedResources(filterOptions *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts, resourceList []string) (string, error) {
 	if len(resourceList) == 0 || (len(resourceList) == 1 && resourceList[0] == "all") {
 		return GetUnusedAll(filterOptions, clientset, apiExtClient, dynamicClient, outputFormat, opts)
 	}
diff --git a/pkg/kor/finalizers.go b/pkg/kor/finalizers.go
index 7c80598..198206a 100644
--- a/pkg/kor/finalizers.go
+++ b/pkg/kor/finalizers.go
@@ -14,6 +14,7 @@ import (
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 	"k8s.io/utils/strings/slices"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -78,7 +79,7 @@ func getResourcesWithFinalizersPendingDeletion(clientset kubernetes.Interface, d
 	return retrievePendingDeletionResources(resourceTypes, dynamicClient, filterOpts)
 }
 
-func GetUnusedfinalizers(filterOpts *filters.Options, clientset kubernetes.Interface, dynamicClient *dynamic.DynamicClient, outputFormat string, opts Opts) (string, error) {
+func GetUnusedfinalizers(filterOpts *filters.Options, clientset kubernetes.Interface, dynamicClient *dynamic.DynamicClient, outputFormat string, opts common.Opts) (string, error) {
 	var outputBuffer bytes.Buffer
 	namespaces := filterOpts.Namespaces(clientset)
 	response := make(map[string]map[string][]ResourceInfo)
diff --git a/pkg/kor/formatter.go b/pkg/kor/formatter.go
index 092593b..cec7a0c 100644
--- a/pkg/kor/formatter.go
+++ b/pkg/kor/formatter.go
@@ -8,6 +8,9 @@ import (
 
 	"github.com/olekukonko/tablewriter"
 	"sigs.k8s.io/yaml"
+
+	"github.com/yonahd/kor/pkg/common"
+	"github.com/yonahd/kor/pkg/utils"
 )
 
 type ResourceInfo struct {
@@ -22,13 +25,13 @@ func getTableRow(index int, columns ...string) []string {
 	return row
 }
 
-func unusedResourceFormatter(outputFormat string, outputBuffer bytes.Buffer, opts Opts, jsonResponse []byte) (string, error) {
+func unusedResourceFormatter(outputFormat string, outputBuffer bytes.Buffer, opts common.Opts, jsonResponse []byte) (string, error) {
 	switch outputFormat {
 	case "table":
 		if opts.WebhookURL == "" || opts.Channel == "" || opts.Token != "" {
 			return outputBuffer.String(), nil
 		}
-		if err := SendToSlack(SlackMessage{}, opts, outputBuffer.String()); err != nil {
+		if err := utils.SendToSlack(utils.SlackMessage{}, opts, outputBuffer.String()); err != nil {
 			return "", fmt.Errorf("failed to send message to slack: %w", err)
 		}
 	case "json", "yaml":
@@ -81,7 +84,7 @@ func unusedResourceFormatter(outputFormat string, outputBuffer bytes.Buffer, opt
 	return "", fmt.Errorf("unsupported output format: %s", outputFormat)
 }
 
-func FormatOutput(resources map[string]map[string][]ResourceInfo, opts Opts) bytes.Buffer {
+func FormatOutput(resources map[string]map[string][]ResourceInfo, opts common.Opts) bytes.Buffer {
 	var output bytes.Buffer
 	switch opts.GroupBy {
 	case "namespace":
@@ -96,7 +99,7 @@ func FormatOutput(resources map[string]map[string][]ResourceInfo, opts Opts) byt
 	return output
 }
 
-func formatOutputForNamespace(namespace string, resources map[string][]ResourceInfo, opts Opts) string {
+func formatOutputForNamespace(namespace string, resources map[string][]ResourceInfo, opts common.Opts) string {
 	var buf strings.Builder
 	table := tablewriter.NewWriter(&buf)
 	table.SetColWidth(60)
@@ -125,7 +128,7 @@ func formatOutputForNamespace(namespace string, resources map[string][]ResourceI
 	return fmt.Sprintf("Unused resources in namespace: %q\n%s\n", namespace, buf.String())
 }
 
-func formatOutputForResource(resource string, resources map[string][]ResourceInfo, opts Opts) string {
+func formatOutputForResource(resource string, resources map[string][]ResourceInfo, opts common.Opts) string {
 	if len(resources) == 0 {
 		if opts.Verbose {
 			return fmt.Sprintf("No unused %ss found\n", resource)
@@ -207,7 +210,7 @@ func getTableRowResourceInfo(index int, resourceType string, resource ResourceIn
 	return row
 }
 
-func FormatOutputAll(namespace string, allDiffs []ResourceDiff, opts Opts) string {
+func FormatOutputAll(namespace string, allDiffs []ResourceDiff, opts common.Opts) string {
 	var buf strings.Builder
 	table := tablewriter.NewWriter(&buf)
 	table.SetColWidth(60)
diff --git a/pkg/kor/hpas.go b/pkg/kor/hpas.go
index 572cdae..2787671 100644
--- a/pkg/kor/hpas.go
+++ b/pkg/kor/hpas.go
@@ -12,6 +12,7 @@ import (
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 	"k8s.io/utils/strings/slices"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -80,7 +81,7 @@ func processNamespaceHpas(clientset kubernetes.Interface, namespace string, filt
 	return unusedHpas, nil
 }
 
-func GetUnusedHpas(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedHpas(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceHpas(clientset, namespace, filterOpts)
diff --git a/pkg/kor/ingresses.go b/pkg/kor/ingresses.go
index f73b070..11951b3 100644
--- a/pkg/kor/ingresses.go
+++ b/pkg/kor/ingresses.go
@@ -12,6 +12,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -116,7 +117,7 @@ func processNamespaceIngresses(clientset kubernetes.Interface, namespace string,
 
 }
 
-func GetUnusedIngresses(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedIngresses(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceIngresses(clientset, namespace, filterOpts)
diff --git a/pkg/kor/jobs.go b/pkg/kor/jobs.go
index f203e54..d25757f 100644
--- a/pkg/kor/jobs.go
+++ b/pkg/kor/jobs.go
@@ -12,6 +12,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -65,7 +66,7 @@ func processNamespaceJobs(clientset kubernetes.Interface, namespace string, filt
 	return unusedJobNames, nil
 }
 
-func GetUnusedJobs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedJobs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceJobs(clientset, namespace, filterOpts)
diff --git a/pkg/kor/kor.go b/pkg/kor/kor.go
index 5e65a0e..2be6a72 100644
--- a/pkg/kor/kor.go
+++ b/pkg/kor/kor.go
@@ -41,17 +41,6 @@ type Config struct {
 	// Add other configurations if needed
 }
 
-type Opts struct {
-	DeleteFlag    bool
-	NoInteractive bool
-	Verbose       bool
-	WebhookURL    string
-	Channel       string
-	Token         string
-	GroupBy       string
-	ShowReason    bool
-}
-
 func RemoveDuplicatesAndSort(slice []string) []string {
 	uniqueSet := make(map[string]bool)
 	for _, item := range slice {
diff --git a/pkg/kor/multi.go b/pkg/kor/multi.go
index 2d29c0e..38aa5b9 100644
--- a/pkg/kor/multi.go
+++ b/pkg/kor/multi.go
@@ -11,6 +11,7 @@ import (
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -96,7 +97,7 @@ func retrieveNamespaceDiffs(clientset kubernetes.Interface, namespace string, re
 	return allDiffs
 }
 
-func GetUnusedMulti(resourceNames string, filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedMulti(resourceNames string, filterOpts *filters.Options, clientset kubernetes.Interface, apiExtClient apiextensionsclientset.Interface, dynamicClient dynamic.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resourceList := strings.Split(resourceNames, ",")
 	namespaces := filterOpts.Namespaces(clientset)
 	resources := make(map[string]map[string][]ResourceInfo)
diff --git a/pkg/kor/networkpolicies.go b/pkg/kor/networkpolicies.go
index 03a89e1..71a975a 100644
--- a/pkg/kor/networkpolicies.go
+++ b/pkg/kor/networkpolicies.go
@@ -6,13 +6,116 @@ import (
 	"encoding/json"
 	"fmt"
 	"os"
+	"slices"
 
+	v1 "k8s.io/api/core/v1"
+	networkingv1 "k8s.io/api/networking/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
+const (
+	unusedLabelReason         = "Marked with unused label"
+	noPodAppliedReason        = "NetworkPolicy applies to 0 pods"
+	noPodAppliedByRulesReason = "NetworkPolicy Ingress and Egress rules apply to 0 pods"
+)
+
+func retrievePodsForSelector(clientset kubernetes.Interface, namespace string, selector *metav1.LabelSelector) ([]v1.Pod, error) {
+	labelSelector, err := metav1.LabelSelectorAsSelector(selector)
+	if err != nil {
+		return nil, err
+	}
+	podList, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
+		LabelSelector: labelSelector.String(),
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return podList.Items, nil
+}
+
+func isAnyPodMatchedInSources(clientset kubernetes.Interface, sources []networkingv1.NetworkPolicyPeer) (bool, error) {
+	// If this field is empty or missing, this rule matches all pods
+	if len(sources) == 0 {
+		return true, nil
+	}
+
+	for _, netpolPeer := range sources {
+		// If ipBlock is specified, assume the source is in use
+		if netpolPeer.IPBlock != nil {
+			return true, nil
+		}
+
+		labelSelector, err := metav1.LabelSelectorAsSelector(netpolPeer.NamespaceSelector)
+		if err != nil {
+			return false, err
+		}
+
+		nsList, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{
+			LabelSelector: labelSelector.String(),
+		})
+		if err != nil {
+			return false, err
+		}
+
+		for _, ns := range nsList.Items {
+			podList, err := retrievePodsForSelector(clientset, ns.Name, netpolPeer.PodSelector)
+			if err != nil {
+				return false, err
+			}
+
+			if len(podList) > 0 {
+				return true, nil
+			}
+		}
+	}
+
+	return false, nil
+}
+
+func isAnyIngressRuleUsed(clientset kubernetes.Interface, netpol networkingv1.NetworkPolicy) (bool, error) {
+	// Deny all ingress traffic
+	if len(netpol.Spec.Ingress) == 0 && slices.Contains(netpol.Spec.PolicyTypes, networkingv1.PolicyTypeIngress) {
+		return true, nil
+	}
+	for _, ingressRule := range netpol.Spec.Ingress {
+		podsMatched, err := isAnyPodMatchedInSources(clientset, ingressRule.From)
+		if err != nil {
+			return false, err
+		}
+
+		if podsMatched {
+			return true, nil
+		}
+	}
+
+	return false, nil
+}
+
+func isAnyEgressRuleUsed(clientset kubernetes.Interface, netpol networkingv1.NetworkPolicy) (bool, error) {
+	// Deny all egress traffic
+	if len(netpol.Spec.Egress) == 0 && slices.Contains(netpol.Spec.PolicyTypes, networkingv1.PolicyTypeEgress) {
+		return true, nil
+	}
+
+	for _, egressRule := range netpol.Spec.Egress {
+		podsMatched, err := isAnyPodMatchedInSources(clientset, egressRule.To)
+		if err != nil {
+			return false, err
+		}
+
+		if podsMatched {
+			return true, nil
+		}
+	}
+
+	return false, nil
+}
+
 func processNamespaceNetworkPolicies(clientset kubernetes.Interface, namespace string, filterOpts *filters.Options) ([]ResourceInfo, error) {
 	netpolList, err := clientset.NetworkingV1().NetworkPolicies(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: filterOpts.IncludeLabels})
 	if err != nil {
@@ -27,33 +130,39 @@ func processNamespaceNetworkPolicies(clientset kubernetes.Interface, namespace s
 		}
 
 		if netpol.Labels["kor/used"] == "false" {
-			reason := "Marked with unused label"
-			unusedNetpols = append(unusedNetpols, ResourceInfo{Name: netpol.Name, Reason: reason})
+			unusedNetpols = append(unusedNetpols, ResourceInfo{Name: netpol.Name, Reason: unusedLabelReason})
 			continue
 		}
 
-		// retrieve pods selected by the NetworkPolicy
-		labelSelector, err := metav1.LabelSelectorAsSelector(&netpol.Spec.PodSelector)
+		pods, err := retrievePodsForSelector(clientset, namespace, &netpol.Spec.PodSelector)
 		if err != nil {
 			return nil, err
 		}
-		podList, err := clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
-			LabelSelector: labelSelector.String(),
-		})
-		if err != nil {
+
+		if len(pods) == 0 {
+			unusedNetpols = append(unusedNetpols, ResourceInfo{Name: netpol.Name, Reason: noPodAppliedReason})
+			continue
+		}
+
+		if used, err := isAnyIngressRuleUsed(clientset, netpol); err != nil {
 			return nil, err
+		} else if used {
+			continue
 		}
 
-		if len(podList.Items) == 0 {
-			reason := "NetworkPolicy selects no pods"
-			unusedNetpols = append(unusedNetpols, ResourceInfo{Name: netpol.Name, Reason: reason})
+		if used, err := isAnyEgressRuleUsed(clientset, netpol); err != nil {
+			return nil, err
+		} else if used {
+			continue
 		}
+
+		unusedNetpols = append(unusedNetpols, ResourceInfo{Name: netpol.Name, Reason: noPodAppliedByRulesReason})
 	}
 
 	return unusedNetpols, nil
 }
 
-func GetUnusedNetworkPolicies(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedNetworkPolicies(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 
 	for _, namespace := range filterOpts.Namespaces(clientset) {
diff --git a/pkg/kor/pdbs.go b/pkg/kor/pdbs.go
index 3836a16..c700145 100644
--- a/pkg/kor/pdbs.go
+++ b/pkg/kor/pdbs.go
@@ -12,6 +12,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -81,7 +82,7 @@ func processNamespacePdbs(clientset kubernetes.Interface, namespace string, filt
 	return unusedPdbs, nil
 }
 
-func GetUnusedPdbs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedPdbs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespacePdbs(clientset, namespace, filterOpts)
diff --git a/pkg/kor/pods.go b/pkg/kor/pods.go
index 70e1740..8a1f0aa 100644
--- a/pkg/kor/pods.go
+++ b/pkg/kor/pods.go
@@ -11,6 +11,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -43,7 +44,7 @@ func processNamespacePods(clientset kubernetes.Interface, namespace string, filt
 	return evictedPods, nil
 }
 
-func GetUnusedPods(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedPods(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespacePods(clientset, namespace, filterOpts)
diff --git a/pkg/kor/pv.go b/pkg/kor/pv.go
index e9419c6..440cf00 100644
--- a/pkg/kor/pv.go
+++ b/pkg/kor/pv.go
@@ -11,6 +11,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -44,7 +45,7 @@ func processPvs(clientset kubernetes.Interface, filterOpts *filters.Options) ([]
 
 }
 
-func GetUnusedPvs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedPvs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	diff, err := processPvs(clientset, filterOpts)
 	if err != nil {
diff --git a/pkg/kor/pvc.go b/pkg/kor/pvc.go
index 01054ee..33ad170 100644
--- a/pkg/kor/pvc.go
+++ b/pkg/kor/pvc.go
@@ -11,6 +11,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -72,7 +73,7 @@ func processNamespacePvcs(clientset kubernetes.Interface, namespace string, filt
 	return diff, nil
 }
 
-func GetUnusedPvcs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedPvcs(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespacePvcs(clientset, namespace, filterOpts)
diff --git a/pkg/kor/replicaset.go b/pkg/kor/replicaset.go
index 1dab798..96e1ece 100644
--- a/pkg/kor/replicaset.go
+++ b/pkg/kor/replicaset.go
@@ -10,6 +10,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -36,7 +37,7 @@ func processNamespaceReplicaSets(clientset kubernetes.Interface, namespace strin
 	return unusedReplicaSetNames, nil
 }
 
-func GetUnusedReplicaSets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedReplicaSets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceReplicaSets(clientset, namespace, filterOpts)
diff --git a/pkg/kor/roles.go b/pkg/kor/roles.go
index 3fe837a..71b8694 100644
--- a/pkg/kor/roles.go
+++ b/pkg/kor/roles.go
@@ -12,6 +12,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -101,7 +102,7 @@ func processNamespaceRoles(clientset kubernetes.Interface, namespace string, fil
 	return diff, nil
 }
 
-func GetUnusedRoles(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedRoles(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceRoles(clientset, namespace, filterOpts)
diff --git a/pkg/kor/secrets.go b/pkg/kor/secrets.go
index 107ce98..270e7b9 100644
--- a/pkg/kor/secrets.go
+++ b/pkg/kor/secrets.go
@@ -13,6 +13,7 @@ import (
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 	"k8s.io/utils/strings/slices"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -195,7 +196,7 @@ func processNamespaceSecret(clientset kubernetes.Interface, namespace string, fi
 
 }
 
-func GetUnusedSecrets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedSecrets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceSecret(clientset, namespace, filterOpts)
diff --git a/pkg/kor/serviceaccounts.go b/pkg/kor/serviceaccounts.go
index 0ee2866..4ccb765 100644
--- a/pkg/kor/serviceaccounts.go
+++ b/pkg/kor/serviceaccounts.go
@@ -11,6 +11,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -163,7 +164,7 @@ func processNamespaceSA(clientset kubernetes.Interface, namespace string, filter
 	return unusedServiceAccounts, nil
 }
 
-func GetUnusedServiceAccounts(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedServiceAccounts(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceSA(clientset, namespace, filterOpts)
diff --git a/pkg/kor/services.go b/pkg/kor/services.go
index 13e0903..6b1128a 100644
--- a/pkg/kor/services.go
+++ b/pkg/kor/services.go
@@ -11,6 +11,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -59,7 +60,7 @@ func processNamespaceServices(clientset kubernetes.Interface, namespace string,
 	return endpointsWithoutSubsets, nil
 }
 
-func GetUnusedServices(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedServices(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 
 	for _, namespace := range filterOpts.Namespaces(clientset) {
diff --git a/pkg/kor/statefulsets.go b/pkg/kor/statefulsets.go
index 0bc8841..2398957 100644
--- a/pkg/kor/statefulsets.go
+++ b/pkg/kor/statefulsets.go
@@ -10,6 +10,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -43,7 +44,7 @@ func processNamespaceStatefulSets(clientset kubernetes.Interface, namespace stri
 	return statefulSetsWithoutReplicas, nil
 }
 
-func GetUnusedStatefulSets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedStatefulSets(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	for _, namespace := range filterOpts.Namespaces(clientset) {
 		diff, err := processNamespaceStatefulSets(clientset, namespace, filterOpts)
diff --git a/pkg/kor/storageclasses.go b/pkg/kor/storageclasses.go
index 8e3a330..43df4f8 100644
--- a/pkg/kor/storageclasses.go
+++ b/pkg/kor/storageclasses.go
@@ -12,6 +12,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -98,7 +99,7 @@ func processStorageClasses(clientset kubernetes.Interface, filterOpts *filters.O
 	return unusedStorageClasses, nil
 }
 
-func GetUnusedStorageClasses(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts Opts) (string, error) {
+func GetUnusedStorageClasses(filterOpts *filters.Options, clientset kubernetes.Interface, outputFormat string, opts common.Opts) (string, error) {
 	resources := make(map[string]map[string][]ResourceInfo)
 	diff, err := processStorageClasses(clientset, filterOpts)
 	if err != nil {
diff --git a/pkg/kor/slack.go b/pkg/utils/slack.go
similarity index 89%
rename from pkg/kor/slack.go
rename to pkg/utils/slack.go
index 8bb3cb6..9d582c5 100644
--- a/pkg/kor/slack.go
+++ b/pkg/utils/slack.go
@@ -1,4 +1,4 @@
-package kor
+package utils
 
 import (
 	"bytes"
@@ -9,20 +9,22 @@ import (
 	"net/http"
 	"os"
 	"path/filepath"
+
+	"github.com/yonahd/kor/pkg/common"
 )
 
 type SendMessageToSlack interface {
-	SendToSlack(opts Opts, outputBuffer string) error
+	SendToSlack(opts common.Opts, outputBuffer string) error
 }
 
 type SlackMessage struct {
 }
 
-func SendToSlack(sm SendMessageToSlack, opts Opts, outputBuffer string) error {
+func SendToSlack(sm SendMessageToSlack, opts common.Opts, outputBuffer string) error {
 	return sm.SendToSlack(opts, outputBuffer)
 }
 
-func (sm SlackMessage) SendToSlack(opts Opts, outputBuffer string) error {
+func (sm SlackMessage) SendToSlack(opts common.Opts, outputBuffer string) error {
 	if opts.WebhookURL != "" {
 		payload := []byte(`{"text": "` + outputBuffer + `"}`)
 		_, err := http.Post(opts.WebhookURL, "application/json", bytes.NewBuffer(payload))


Test patch:
diff --git a/pkg/kor/clusterroles_test.go b/pkg/kor/clusterroles_test.go
index 0a8adf5..6283488 100644
--- a/pkg/kor/clusterroles_test.go
+++ b/pkg/kor/clusterroles_test.go
@@ -14,6 +14,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -138,7 +139,7 @@ func TestProcessClusterRoles(t *testing.T) {
 func TestGetUnusedClusterRolesStructured(t *testing.T) {
 	clientset := createTestClusterRoles(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/configmaps_test.go b/pkg/kor/configmaps_test.go
index 0214088..a0d8f41 100644
--- a/pkg/kor/configmaps_test.go
+++ b/pkg/kor/configmaps_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -197,7 +198,7 @@ func TestRetrieveUsedCM(t *testing.T) {
 func TestGetUnusedConfigmapsStructured(t *testing.T) {
 	clientset := createTestConfigmaps(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/create_test_resources.go b/pkg/kor/create_test_resources.go
index 9781090..bfcd22f 100644
--- a/pkg/kor/create_test_resources.go
+++ b/pkg/kor/create_test_resources.go
@@ -399,7 +399,14 @@ func CreateTestUnstructered(kind, apiVersion, namespace, name string) *unstructu
 	}
 }
 
-func CreateTestNetworkPolicy(name, namespace string, podSelector v1.LabelSelector, labels map[string]string) *networkingv1.NetworkPolicy {
+func CreateTestNetworkPolicy(name, namespace string, labels map[string]string, podSelector v1.LabelSelector, ingress []networkingv1.NetworkPolicyIngressRule, egress []networkingv1.NetworkPolicyEgressRule) *networkingv1.NetworkPolicy {
+	policies := []networkingv1.PolicyType{
+		networkingv1.PolicyTypeIngress,
+	}
+	if len(egress) > 0 {
+		policies = append(policies, networkingv1.PolicyTypeEgress)
+	}
+
 	return &networkingv1.NetworkPolicy{
 		ObjectMeta: v1.ObjectMeta{
 			Name:      name,
@@ -408,6 +415,9 @@ func CreateTestNetworkPolicy(name, namespace string, podSelector v1.LabelSelecto
 		},
 		Spec: networkingv1.NetworkPolicySpec{
 			PodSelector: podSelector,
+			PolicyTypes: policies,
+			Ingress:     ingress,
+			Egress:      egress,
 		},
 	}
 }
diff --git a/pkg/kor/daemonsets_test.go b/pkg/kor/daemonsets_test.go
index 78bf326..a5fb2e3 100644
--- a/pkg/kor/daemonsets_test.go
+++ b/pkg/kor/daemonsets_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -82,7 +83,7 @@ func TestProcessNamespaceDaemonSets(t *testing.T) {
 func TestGetUnusedDaemonSetsStructured(t *testing.T) {
 	clientset := createTestDaemonSets(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/deployments_test.go b/pkg/kor/deployments_test.go
index f659d6f..ca4c3f8 100644
--- a/pkg/kor/deployments_test.go
+++ b/pkg/kor/deployments_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -74,7 +75,7 @@ func TestProcessNamespaceDeployments(t *testing.T) {
 func TestGetUnusedDeploymentsStructured(t *testing.T) {
 	clientset := createTestDeployments(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/hpas_test.go b/pkg/kor/hpas_test.go
index b566edf..786e19f 100644
--- a/pkg/kor/hpas_test.go
+++ b/pkg/kor/hpas_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -83,7 +84,7 @@ func TestExtractUnusedHpas(t *testing.T) {
 func TestGetUnusedHpasStructured(t *testing.T) {
 	clientset := createTestHpas(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/ingresses_test.go b/pkg/kor/ingresses_test.go
index 5398310..c173589 100644
--- a/pkg/kor/ingresses_test.go
+++ b/pkg/kor/ingresses_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -81,7 +82,7 @@ func TestRetrieveUsedIngress(t *testing.T) {
 func TestGetUnusedIngressesStructured(t *testing.T) {
 	clientset := createTestIngresses(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/jobs_test.go b/pkg/kor/jobs_test.go
index 5a89595..557f679 100644
--- a/pkg/kor/jobs_test.go
+++ b/pkg/kor/jobs_test.go
@@ -15,6 +15,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -112,7 +113,7 @@ func TestProcessNamespaceJobs(t *testing.T) {
 func TestGetUnusedJobsStructured(t *testing.T) {
 	clientset := createTestJobs(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/networkpolicies_test.go b/pkg/kor/networkpolicies_test.go
index 27ade65..3e0c39d 100644
--- a/pkg/kor/networkpolicies_test.go
+++ b/pkg/kor/networkpolicies_test.go
@@ -13,56 +13,107 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
 func createTestNetworkPolicies(t *testing.T) *fake.Clientset {
 	clientset := fake.NewSimpleClientset()
 
-	_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
-		ObjectMeta: v1.ObjectMeta{Name: testNamespace},
-	}, v1.CreateOptions{})
+	testNamespace2 := "another-namespace"
+	namespaces := []string{testNamespace, testNamespace2}
 
-	if err != nil {
-		t.Fatalf("Error creating namespace %s: %v", testNamespace, err)
+	for _, ns := range namespaces {
+		_, err := clientset.CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{
+			ObjectMeta: v1.ObjectMeta{Name: ns},
+		}, v1.CreateOptions{})
+
+		if err != nil {
+			t.Fatalf("Error creating namespace %s: %v", ns, err)
+		}
 	}
 
-	podLabels := map[string]string{
+	podLabels1 := map[string]string{
 		"app.kubernetes.io/name":    "my-app",
 		"app.kubernetes.io/version": "v1",
 		"product.my-org/name":       "my-app",
 	}
-	noMatchLabels := map[string]string{"app.kubernetes.io/version": "v2"}
+	podLabels2 := map[string]string{"app.kubernetes.io/version": "v2"}
 
 	pods := []*corev1.Pod{
-		CreateTestPod(testNamespace, "pod-1", "", nil, podLabels),
+		CreateTestPod(testNamespace, "pod-1", "", nil, podLabels1),
 		CreateTestPod(testNamespace, "pod-2", "", nil, AppLabels),
+		CreateTestPod(testNamespace2, "pod-1", "", nil, podLabels2),
+		CreateTestPod(testNamespace2, "pod-2", "", nil, AppLabels),
 	}
 
 	for _, pod := range pods {
-		_, err = clientset.CoreV1().Pods(testNamespace).Create(context.TODO(), pod, v1.CreateOptions{})
+		_, err := clientset.CoreV1().Pods(pod.Namespace).Create(context.TODO(), pod, v1.CreateOptions{})
 		if err != nil {
 			t.Fatalf("Error creating fake pod: %v", err)
 		}
 	}
 
 	netpols := []*networkingv1.NetworkPolicy{
-		// all pods are selected
-		CreateTestNetworkPolicy("netpol-1", testNamespace, v1.LabelSelector{}, AppLabels),
-		CreateTestNetworkPolicy("netpol-2", testNamespace, v1.LabelSelector{}, UsedLabels),
-		CreateTestNetworkPolicy("netpol-3", testNamespace, v1.LabelSelector{}, UnusedLabels),
-		// some pods are selected
-		CreateTestNetworkPolicy("netpol-4", testNamespace, *v1.SetAsLabelSelector(podLabels), AppLabels),
-		CreateTestNetworkPolicy("netpol-5", testNamespace, *v1.SetAsLabelSelector(podLabels), UnusedLabels),
-		CreateTestNetworkPolicy("netpol-6", testNamespace, *v1.SetAsLabelSelector(podLabels), UsedLabels),
+		// with kor labels
+		CreateTestNetworkPolicy("netpol-1", testNamespace, UsedLabels, v1.LabelSelector{}, nil, nil),
+		CreateTestNetworkPolicy("netpol-2", testNamespace, UnusedLabels, v1.LabelSelector{}, nil, nil),
+
+		// with pod selectors
 		// no pods are selected
-		CreateTestNetworkPolicy("netpol-7", testNamespace, *v1.SetAsLabelSelector(noMatchLabels), AppLabels),
-		CreateTestNetworkPolicy("netpol-8", testNamespace, *v1.SetAsLabelSelector(noMatchLabels), UnusedLabels),
-		CreateTestNetworkPolicy("netpol-9", testNamespace, *v1.SetAsLabelSelector(noMatchLabels), UsedLabels),
+		CreateTestNetworkPolicy("netpol-3", testNamespace, AppLabels, *v1.SetAsLabelSelector(podLabels2), nil, nil),
+
+		// with ingress/egress rules
+		// deny-all ingress
+		CreateTestNetworkPolicy("netpol-4", testNamespace, AppLabels, *v1.SetAsLabelSelector(podLabels1), nil, nil),
+		// allow-all ingress
+		CreateTestNetworkPolicy("netpol-5", testNamespace, AppLabels, *v1.SetAsLabelSelector(podLabels1), []networkingv1.NetworkPolicyIngressRule{{}}, nil),
+		// allow ingress to some pods
+		CreateTestNetworkPolicy("netpol-6", testNamespace, AppLabels, *v1.SetAsLabelSelector(podLabels1), []networkingv1.NetworkPolicyIngressRule{{
+			From: []networkingv1.NetworkPolicyPeer{
+				{
+					PodSelector: &v1.LabelSelector{
+						MatchLabels: podLabels2,
+					},
+				},
+			},
+		}}, nil),
+		// ingress matches 0 pods
+		CreateTestNetworkPolicy("netpol-7", testNamespace, AppLabels, *v1.SetAsLabelSelector(podLabels1), []networkingv1.NetworkPolicyIngressRule{{
+			From: []networkingv1.NetworkPolicyPeer{
+				{
+					PodSelector: &v1.LabelSelector{
+						MatchLabels: map[string]string{"product.my-org/name": "unknown"},
+					},
+				},
+			},
+		}}, nil),
+		// with ipBlock
+		CreateTestNetworkPolicy("netpol-8", testNamespace, AppLabels, *v1.SetAsLabelSelector(podLabels1), []networkingv1.NetworkPolicyIngressRule{{
+			From: []networkingv1.NetworkPolicyPeer{
+				{
+					IPBlock: &networkingv1.IPBlock{
+						CIDR: "172.17.0.0/16",
+					},
+				},
+			},
+		}}, nil),
 	}
 
+	netpol9 := CreateTestNetworkPolicy("netpol-9", testNamespace, AppLabels, *v1.SetAsLabelSelector(podLabels1), nil, []networkingv1.NetworkPolicyEgressRule{{
+		To: []networkingv1.NetworkPolicyPeer{
+			{
+				PodSelector: &v1.LabelSelector{
+					MatchLabels: map[string]string{"product.my-org/name": "unknown"},
+				},
+			},
+		},
+	}}) // egress only - matches 0 pods
+	netpol9.Spec.PolicyTypes = []networkingv1.PolicyType{networkingv1.PolicyTypeEgress}
+	netpols = append(netpols, netpol9)
+
 	for _, netpol := range netpols {
-		_, err = clientset.NetworkingV1().NetworkPolicies(netpol.Namespace).Create(context.TODO(), netpol, v1.CreateOptions{})
+		_, err := clientset.NetworkingV1().NetworkPolicies(netpol.Namespace).Create(context.TODO(), netpol, v1.CreateOptions{})
 		if err != nil {
 			t.Fatalf("Error creating fake networkpolicy: %v", err)
 		}
@@ -71,6 +122,87 @@ func createTestNetworkPolicies(t *testing.T) *fake.Clientset {
 	return clientset
 }
 
+func TestRetrievePodsForSelector(t *testing.T) {
+	clientset := createTestNetworkPolicies(t)
+
+	selector := &v1.LabelSelector{
+		MatchLabels: map[string]string{
+			"app.kubernetes.io/version": "v1",
+		},
+	}
+	pods, err := retrievePodsForSelector(clientset, testNamespace, selector)
+	if err != nil {
+		t.Errorf("Error retrieving pods for selector %v: %v", selector, err)
+	}
+
+	expectedPods := []string{
+		"pod-1",
+	}
+
+	if len(pods) != len(expectedPods) {
+		t.Errorf("Expected %d pods, got %d", len(expectedPods), len(pods))
+	}
+
+	for i, pod := range pods {
+		if pod.Name != expectedPods[i] {
+			t.Errorf("Expected pod %s, got %v", expectedPods[i], pod)
+		}
+	}
+}
+
+func TestIsAnyPodMatchedInSources(t *testing.T) {
+	clientset := createTestNetworkPolicies(t)
+
+	sources := []networkingv1.NetworkPolicyPeer{
+		{
+			PodSelector: &v1.LabelSelector{
+				MatchLabels: map[string]string{
+					"app.kubernetes.io/version": "v1",
+				},
+			},
+		},
+	}
+
+	matched, err := isAnyPodMatchedInSources(clientset, sources)
+	if err != nil {
+		t.Errorf("Error checking if sources match any pods: %v", err)
+	}
+
+	if !matched {
+		t.Error("Expected matching pods, got none")
+	}
+}
+
+func TestIsAnyIngressRuleUsed(t *testing.T) {
+	clientset := createTestNetworkPolicies(t)
+
+	netpol := CreateTestNetworkPolicy("netpol-0", testNamespace, AppLabels, v1.LabelSelector{}, nil, nil)
+
+	used, err := isAnyIngressRuleUsed(clientset, *netpol)
+	if err != nil {
+		t.Errorf("Error checking if any ingress rule is used: %v", err)
+	}
+
+	if !used {
+		t.Error("Expected ingress rules in use, got none")
+	}
+}
+
+func TestIsAnyEgressRuleUsed(t *testing.T) {
+	clientset := createTestNetworkPolicies(t)
+
+	netpol := CreateTestNetworkPolicy("netpol-0", testNamespace, AppLabels, v1.LabelSelector{}, nil, nil)
+
+	used, err := isAnyEgressRuleUsed(clientset, *netpol)
+	if err != nil {
+		t.Errorf("Error checking if any egress rule is used: %v", err)
+	}
+
+	if used {
+		t.Error("Expected ingress rules not in use, got used rules")
+	}
+}
+
 func TestProcessNamespaceNetworkPolicies(t *testing.T) {
 	clientset := createTestNetworkPolicies(t)
 
@@ -80,10 +212,10 @@ func TestProcessNamespaceNetworkPolicies(t *testing.T) {
 	}
 
 	expectedUnusedNetpols := []string{
+		"netpol-2",
 		"netpol-3",
-		"netpol-5",
 		"netpol-7",
-		"netpol-8",
+		"netpol-9",
 	}
 
 	if len(unusedNetpols) != len(expectedUnusedNetpols) {
@@ -100,7 +232,7 @@ func TestProcessNamespaceNetworkPolicies(t *testing.T) {
 func TestGetUnusedNetworkPolicies(t *testing.T) {
 	clientset := createTestNetworkPolicies(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
@@ -117,10 +249,10 @@ func TestGetUnusedNetworkPolicies(t *testing.T) {
 	expectedOutput := map[string]map[string][]string{
 		testNamespace: {
 			"NetworkPolicy": []string{
+				"netpol-2",
 				"netpol-3",
-				"netpol-5",
 				"netpol-7",
-				"netpol-8",
+				"netpol-9",
 			},
 		},
 	}
diff --git a/pkg/kor/pdbs_test.go b/pkg/kor/pdbs_test.go
index 8f2b6b8..d918365 100644
--- a/pkg/kor/pdbs_test.go
+++ b/pkg/kor/pdbs_test.go
@@ -10,6 +10,7 @@ import (
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/fake"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -93,7 +94,7 @@ func TestProcessNamespacePdbs(t *testing.T) {
 func TestGetUnusedPdbsStructured(t *testing.T) {
 	clientset := createTestPdbs(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/pods_test.go b/pkg/kor/pods_test.go
index 3cab146..a13ef96 100644
--- a/pkg/kor/pods_test.go
+++ b/pkg/kor/pods_test.go
@@ -12,6 +12,7 @@ import (
 	fake "k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -115,7 +116,7 @@ func TestProcessNamespacePods(t *testing.T) {
 func TestGetUnusedPodsStructured(t *testing.T) {
 	clientset := createTestPods(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/pv_test.go b/pkg/kor/pv_test.go
index d69e160..189d7c8 100644
--- a/pkg/kor/pv_test.go
+++ b/pkg/kor/pv_test.go
@@ -9,6 +9,7 @@ import (
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/fake"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -61,7 +62,7 @@ func TestProcessPvs(t *testing.T) {
 func TestGetUnusedPvs(t *testing.T) {
 	clientset := createTestPvs(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/pvc_test.go b/pkg/kor/pvc_test.go
index 6547a01..2abdcf7 100644
--- a/pkg/kor/pvc_test.go
+++ b/pkg/kor/pvc_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -99,7 +100,7 @@ func TestProcessNamespacePvcs(t *testing.T) {
 func TestGetUnusedPvcsStructured(t *testing.T) {
 	clientset := createTestPvcs(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/replicaset_test.go b/pkg/kor/replicaset_test.go
index 1f7c291..2c4ca9d 100644
--- a/pkg/kor/replicaset_test.go
+++ b/pkg/kor/replicaset_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -57,7 +58,7 @@ func createTestReplicaSets(t *testing.T) *fake.Clientset {
 func TestProcessNamespaceReplicaSets(t *testing.T) {
 	clientset := createTestReplicaSets(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/roles_test.go b/pkg/kor/roles_test.go
index 05143bf..f424d1b 100644
--- a/pkg/kor/roles_test.go
+++ b/pkg/kor/roles_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -109,7 +110,7 @@ func TestProcessNamespaceRoles(t *testing.T) {
 func TestGetUnusedRolesStructured(t *testing.T) {
 	clientset := createTestRoles(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/secrets_test.go b/pkg/kor/secrets_test.go
index cbe066b..7873b11 100644
--- a/pkg/kor/secrets_test.go
+++ b/pkg/kor/secrets_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -276,7 +277,7 @@ func TestProcessNamespaceSecret(t *testing.T) {
 func TestGetUnusedSecretsStructured(t *testing.T) {
 	clientset := createTestSecrets(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/serviceaccounts_test.go b/pkg/kor/serviceaccounts_test.go
index 3458fda..cf906c1 100644
--- a/pkg/kor/serviceaccounts_test.go
+++ b/pkg/kor/serviceaccounts_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -184,7 +185,7 @@ func TestGetUnusedServiceAccountsStructured(t *testing.T) {
 		t.Fatalf("Error creating fake %s: %v", "clusterRoleBinding", err)
 	}
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/services_test.go b/pkg/kor/services_test.go
index 9acf854..eb017f5 100644
--- a/pkg/kor/services_test.go
+++ b/pkg/kor/services_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -74,7 +75,7 @@ func TestGetEndpointsWithoutSubsets(t *testing.T) {
 func TestGetUnusedServicesStructured(t *testing.T) {
 	clientset := createTestServices(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/statefulsets_test.go b/pkg/kor/statefulsets_test.go
index 249821b..d2f5c2c 100644
--- a/pkg/kor/statefulsets_test.go
+++ b/pkg/kor/statefulsets_test.go
@@ -13,6 +13,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 	"k8s.io/client-go/kubernetes/scheme"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -74,7 +75,7 @@ func TestProcessNamespaceStatefulSets(t *testing.T) {
 func TestGetUnusedStatefulSetsStructured(t *testing.T) {
 	clientset := createTestStatefulSets(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/storageclasses_test.go b/pkg/kor/storageclasses_test.go
index 8df66ef..95eba16 100644
--- a/pkg/kor/storageclasses_test.go
+++ b/pkg/kor/storageclasses_test.go
@@ -9,6 +9,7 @@ import (
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/fake"
 
+	"github.com/yonahd/kor/pkg/common"
 	"github.com/yonahd/kor/pkg/filters"
 )
 
@@ -69,7 +70,7 @@ func TestProcessStorageClasses(t *testing.T) {
 func TestGetUnusedStorageClassesStructured(t *testing.T) {
 	clientset := createTestStorageClass(t)
 
-	opts := Opts{
+	opts := common.Opts{
 		WebhookURL:    "",
 		Channel:       "",
 		Token:         "",
diff --git a/pkg/kor/slack_test.go b/pkg/utils/slack_test.go
similarity index 91%
rename from pkg/kor/slack_test.go
rename to pkg/utils/slack_test.go
index f19b538..ff82ca4 100644
--- a/pkg/kor/slack_test.go
+++ b/pkg/utils/slack_test.go
@@ -1,4 +1,4 @@
-package kor
+package utils
 
 import (
 	"bytes"
@@ -6,25 +6,27 @@ import (
 	"net/http/httptest"
 	"os"
 	"testing"
+
+	"github.com/yonahd/kor/pkg/common"
 )
 
 type SendToSlackTestCase struct {
 	Name         string
-	Opts         Opts
+	Opts         common.Opts
 	OutputBuffer string
 }
 
 var testCases = []SendToSlackTestCase{
 	{
 		Name: "Test using WebhookURL",
-		Opts: Opts{
+		Opts: common.Opts{
 			WebhookURL: "slack.webhookurl.com",
 		},
 		OutputBuffer: "Test message",
 	},
 	{
 		Name: "Test using Channel and Token",
-		Opts: Opts{
+		Opts: common.Opts{
 			Channel: "your_channel",
 			Token:   "your_token",
 		},
@@ -32,7 +34,7 @@ var testCases = []SendToSlackTestCase{
 	},
 	{
 		Name:         "Test with empty Opts",
-		Opts:         Opts{},
+		Opts:         common.Opts{},
 		OutputBuffer: "Test message",
 	},
 }