From 725178a64777650f1f846d8311f6e4729dff712d Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Wed, 13 Mar 2024 17:17:09 -0700 Subject: [PATCH 01/26] fix: initial panicRecovery --- cmd/start.go | 1 + cmd/utils.go | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/cmd/start.go b/cmd/start.go index 064fce3..c982a33 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -112,6 +112,7 @@ func start(ctx context.Context) { } } else if jobQueued.TryLock() { go func() { + defer panicRecovery() // seems like we should stop the program completely if we do defer jobQueued.Unlock() defer bheClient.CloseIdleConnections() defer azClient.CloseIdleConnections() diff --git a/cmd/utils.go b/cmd/utils.go index fd59f82..a6dd444 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -34,6 +34,7 @@ import ( "os" "path" "path/filepath" + "runtime/debug" "runtime/pprof" "time" @@ -85,6 +86,12 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { } } +func panicRecovery() { + if recovery := recover(); recovery != nil { + log.V(0).Error(fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()), "") + } +} + func gracefulShutdown(stop context.CancelFunc) { stop() fmt.Fprintln(os.Stderr, "\nshutting down gracefully, press ctrl+c again to force") From 835bb7f90b8bc05054656a2845c2579b0d722922 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 11:30:36 -0700 Subject: [PATCH 02/26] panic recovery via channels --- cmd/start.go | 1 - cmd/utils.go | 27 +++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/cmd/start.go b/cmd/start.go index c982a33..064fce3 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -112,7 +112,6 @@ func start(ctx context.Context) { } } else if jobQueued.TryLock() { go func() { - defer panicRecovery() // seems like we should stop the program completely if we do defer jobQueued.Unlock() defer bheClient.CloseIdleConnections() defer azClient.CloseIdleConnections() diff --git a/cmd/utils.go b/cmd/utils.go index a6dd444..c85965e 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -86,9 +86,32 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { } } -func panicRecovery() { +func bubblingPanic() chan error { + var bubblingPanic = make(chan error) + + return bubblingPanic +} + +func handleBubbledPanic(ctx context.Context, bubblingPanic chan error) { + go func() { + defer close(bubblingPanic) // how do we know when the channel is done?? + + for { + select { + case err := <-bubblingPanic: + log.V(0).Error(err, "") + // TODO: end the program please + case <-ctx.Done(): + return + } + } + }() +} + +// panicRecovery recovers from and sends that panic to bubblingPanic channel +func panicRecovery(bubblingPanic chan error) { if recovery := recover(); recovery != nil { - log.V(0).Error(fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()), "") + bubblingPanic <- fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()) } } From 523da7a7143c2739c3961be2c7ba59188c4cc791 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 14:29:59 -0700 Subject: [PATCH 03/26] stop context when panic happens --- cmd/utils.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/utils.go b/cmd/utils.go index c85965e..55bb855 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -92,7 +92,7 @@ func bubblingPanic() chan error { return bubblingPanic } -func handleBubbledPanic(ctx context.Context, bubblingPanic chan error) { +func handleBubbledPanic(ctx context.Context, bubblingPanic chan error, stop context.CancelFunc) { go func() { defer close(bubblingPanic) // how do we know when the channel is done?? @@ -100,7 +100,7 @@ func handleBubbledPanic(ctx context.Context, bubblingPanic chan error) { select { case err := <-bubblingPanic: log.V(0).Error(err, "") - // TODO: end the program please + stop() case <-ctx.Done(): return } From b4c163427c0615b9708cf2fef83259e75666aacc Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 14:45:44 -0700 Subject: [PATCH 04/26] initial channel panic recovery pattern --- cmd/list-app-owners.go | 6 ++++-- cmd/list-apps.go | 7 +++++-- cmd/list-azure-ad.go | 10 ++++++---- cmd/list-root.go | 9 ++++++++- cmd/utils.go | 18 +++++++++--------- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/cmd/list-app-owners.go b/cmd/list-app-owners.go index 869f03b..309b855 100644 --- a/cmd/list-app-owners.go +++ b/cmd/list-app-owners.go @@ -44,19 +44,20 @@ var listAppOwnersCmd = &cobra.Command{ func listAppOwnersCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) + panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") azClient := connectAndCreateClient() log.Info("collecting azure app owners...") start := time.Now() - stream := listAppOwners(ctx, azClient, listApps(ctx, azClient)) + stream := listAppOwners(ctx, azClient, panicChan, listApps(ctx, azClient, panicChan)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan azureWrapper[models.App]) <-chan azureWrapper[models.AppOwners] { +func listAppOwners(ctx context.Context, client client.AzureClient, panicChan chan error, apps <-chan azureWrapper[models.App]) <-chan azureWrapper[models.AppOwners] { var ( out = make(chan azureWrapper[models.AppOwners]) streams = pipeline.Demux(ctx.Done(), apps, 25) @@ -67,6 +68,7 @@ func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan a for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for app := range stream { var ( diff --git a/cmd/list-apps.go b/cmd/list-apps.go index 76f7e59..ecc1a6c 100644 --- a/cmd/list-apps.go +++ b/cmd/list-apps.go @@ -49,16 +49,19 @@ func listAppsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory applications...") start := time.Now() - stream := listApps(ctx, azClient) + panicChan := panicChan() + stream := listApps(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listApps(ctx context.Context, client client.AzureClient) <-chan azureWrapper[models.App] { +func listApps(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan azureWrapper[models.App] { out := make(chan azureWrapper[models.App]) go func() { + defer panicRecovery(panicChan) defer close(out) count := 0 for item := range client.ListAzureADApps(ctx, "", "", "", "", nil) { diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index c53fcaa..22e5067 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -42,6 +42,7 @@ var listAzureADCmd = &cobra.Command{ } func listAzureADCmdImpl(cmd *cobra.Command, args []string) { + var bubblingPanic = make(chan error) if len(args) > 0 { exit(fmt.Errorf("unsupported subcommand: %v", args)) } @@ -53,13 +54,14 @@ func listAzureADCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure ad objects...") start := time.Now() - stream := listAllAD(ctx, azClient) + stream := listAllAD(ctx, azClient, bubblingPanic) + handleBubbledPanic(ctx, bubblingPanic, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAllAD(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listAllAD(ctx context.Context, client client.AzureClient, bubblingPanic chan error) <-chan interface{} { var ( devices = make(chan interface{}) devices2 = make(chan interface{}) @@ -79,9 +81,9 @@ func listAllAD(ctx context.Context, client client.AzureClient) <-chan interface{ ) // Enumerate Apps, AppOwners and AppMembers - appChans := pipeline.TeeFixed(ctx.Done(), listApps(ctx, client), 2) + appChans := pipeline.TeeFixed(ctx.Done(), listApps(ctx, client, bubblingPanic), 2) apps := pipeline.ToAny(ctx.Done(), appChans[0]) - appOwners := pipeline.ToAny(ctx.Done(), listAppOwners(ctx, client, appChans[1])) + appOwners := pipeline.ToAny(ctx.Done(), listAppOwners(ctx, client, bubblingPanic, appChans[1])) // Enumerate Devices and DeviceOwners pipeline.Tee(ctx.Done(), listDevices(ctx, client), devices, devices2) diff --git a/cmd/list-root.go b/cmd/list-root.go index fb0d05d..649bf2e 100644 --- a/cmd/list-root.go +++ b/cmd/list-root.go @@ -62,9 +62,16 @@ func listCmdImpl(cmd *cobra.Command, args []string) { } func listAll(ctx context.Context, client client.AzureClient) <-chan interface{} { + ctx, stop := context.WithCancel(ctx) + var ( - azureAD = listAllAD(ctx, client) + panicChan = panicChan() + + azureAD = listAllAD(ctx, client, panicChan) azureRM = listAllRM(ctx, client) ) + + handleBubbledPanic(ctx, panicChan, stop) + return pipeline.Mux(ctx.Done(), azureAD, azureRM) } diff --git a/cmd/utils.go b/cmd/utils.go index 55bb855..9356407 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -86,19 +86,19 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { } } -func bubblingPanic() chan error { - var bubblingPanic = make(chan error) +func panicChan() chan error { + var panicChan = make(chan error) - return bubblingPanic + return panicChan } -func handleBubbledPanic(ctx context.Context, bubblingPanic chan error, stop context.CancelFunc) { +func handleBubbledPanic(ctx context.Context, panicChan chan error, stop context.CancelFunc) { go func() { - defer close(bubblingPanic) // how do we know when the channel is done?? + defer close(panicChan) for { select { - case err := <-bubblingPanic: + case err := <-panicChan: log.V(0).Error(err, "") stop() case <-ctx.Done(): @@ -108,10 +108,10 @@ func handleBubbledPanic(ctx context.Context, bubblingPanic chan error, stop cont }() } -// panicRecovery recovers from and sends that panic to bubblingPanic channel -func panicRecovery(bubblingPanic chan error) { +// panicRecovery recovers from and sends that to panicChan +func panicRecovery(panicChan chan error) { if recovery := recover(); recovery != nil { - bubblingPanic <- fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()) + panicChan <- fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()) } } From 716217c5799048543d6cddcdbe2c24b01077551c Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 14:49:42 -0700 Subject: [PATCH 05/26] list-devices --- cmd/list-azure-ad.go | 14 +++++++------- cmd/list-devices.go | 7 +++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index 22e5067..cb027cc 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -42,7 +42,6 @@ var listAzureADCmd = &cobra.Command{ } func listAzureADCmdImpl(cmd *cobra.Command, args []string) { - var bubblingPanic = make(chan error) if len(args) > 0 { exit(fmt.Errorf("unsupported subcommand: %v", args)) } @@ -54,14 +53,15 @@ func listAzureADCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure ad objects...") start := time.Now() - stream := listAllAD(ctx, azClient, bubblingPanic) - handleBubbledPanic(ctx, bubblingPanic, stop) + panicChan := panicChan() + stream := listAllAD(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAllAD(ctx context.Context, client client.AzureClient, bubblingPanic chan error) <-chan interface{} { +func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { var ( devices = make(chan interface{}) devices2 = make(chan interface{}) @@ -81,12 +81,12 @@ func listAllAD(ctx context.Context, client client.AzureClient, bubblingPanic cha ) // Enumerate Apps, AppOwners and AppMembers - appChans := pipeline.TeeFixed(ctx.Done(), listApps(ctx, client, bubblingPanic), 2) + appChans := pipeline.TeeFixed(ctx.Done(), listApps(ctx, client, panicChan), 2) apps := pipeline.ToAny(ctx.Done(), appChans[0]) - appOwners := pipeline.ToAny(ctx.Done(), listAppOwners(ctx, client, bubblingPanic, appChans[1])) + appOwners := pipeline.ToAny(ctx.Done(), listAppOwners(ctx, client, panicChan, appChans[1])) // Enumerate Devices and DeviceOwners - pipeline.Tee(ctx.Done(), listDevices(ctx, client), devices, devices2) + pipeline.Tee(ctx.Done(), listDevices(ctx, client, panicChan), devices, devices2) deviceOwners := listDeviceOwners(ctx, client, devices2) // Enumerate Groups, GroupOwners and GroupMembers diff --git a/cmd/list-devices.go b/cmd/list-devices.go index 37ccbb6..2c82b04 100644 --- a/cmd/list-devices.go +++ b/cmd/list-devices.go @@ -49,16 +49,19 @@ func listDevicesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory devices...") start := time.Now() - stream := listDevices(ctx, azClient) + panicChan := panicChan() + stream := listDevices(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listDevices(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listDevices(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) count := 0 for item := range client.ListAzureDevices(ctx, "", "", "", "", nil) { From 360c3554d84c70d3160106e410d4af8218529611 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 14:51:57 -0700 Subject: [PATCH 06/26] list-device-owners --- cmd/list-azure-ad.go | 2 +- cmd/list-device-owners.go | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index cb027cc..0f20aa3 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -87,7 +87,7 @@ func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan er // Enumerate Devices and DeviceOwners pipeline.Tee(ctx.Done(), listDevices(ctx, client, panicChan), devices, devices2) - deviceOwners := listDeviceOwners(ctx, client, devices2) + deviceOwners := listDeviceOwners(ctx, client, panicChan, devices2) // Enumerate Groups, GroupOwners and GroupMembers pipeline.Tee(ctx.Done(), listGroups(ctx, client), groups, groups2, groups3) diff --git a/cmd/list-device-owners.go b/cmd/list-device-owners.go index 124c646..5222dcc 100644 --- a/cmd/list-device-owners.go +++ b/cmd/list-device-owners.go @@ -51,13 +51,15 @@ func listDeviceOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure device owners...") start := time.Now() - stream := listDeviceOwners(ctx, azClient, listDevices(ctx, azClient)) + panicChan := panicChan() + stream := listDeviceOwners(ctx, azClient, panicChan, listDevices(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listDeviceOwners(ctx context.Context, client client.AzureClient, devices <-chan interface{}) <-chan interface{} { +func listDeviceOwners(ctx context.Context, client client.AzureClient, panicChan chan error, devices <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listDeviceOwners(ctx context.Context, client client.AzureClient, devices <- ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), devices) { @@ -83,6 +86,7 @@ func listDeviceOwners(ctx context.Context, client client.AzureClient, devices <- for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( From 517678202c00f2e6f94d6ce3f038d72bde6d4b10 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 15:01:06 -0700 Subject: [PATCH 07/26] list-group list-group-owners list-group-members --- cmd/list-azure-ad.go | 6 +++--- cmd/list-group-members.go | 7 +++++-- cmd/list-group-owners.go | 7 +++++-- cmd/list-groups.go | 7 +++++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index 0f20aa3..be4b056 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -90,9 +90,9 @@ func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan er deviceOwners := listDeviceOwners(ctx, client, panicChan, devices2) // Enumerate Groups, GroupOwners and GroupMembers - pipeline.Tee(ctx.Done(), listGroups(ctx, client), groups, groups2, groups3) - groupOwners := listGroupOwners(ctx, client, groups2) - groupMembers := listGroupMembers(ctx, client, groups3) + pipeline.Tee(ctx.Done(), listGroups(ctx, client, panicChan), groups, groups2, groups3) + groupOwners := listGroupOwners(ctx, client, panicChan, groups2) + groupMembers := listGroupMembers(ctx, client, panicChan, groups3) // Enumerate ServicePrincipals and ServicePrincipalOwners pipeline.Tee(ctx.Done(), listServicePrincipals(ctx, client), servicePrincipals, servicePrincipals2, servicePrincipals3) diff --git a/cmd/list-group-members.go b/cmd/list-group-members.go index cfdd203..af2d540 100644 --- a/cmd/list-group-members.go +++ b/cmd/list-group-members.go @@ -51,13 +51,14 @@ func listGroupMembersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure group members...") start := time.Now() - stream := listGroupMembers(ctx, azClient, listGroups(ctx, azClient)) + panicChan := panicChan() + stream := listGroupMembers(ctx, azClient, panicChan, listGroups(ctx, azClient, panicChan)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-chan interface{}) <-chan interface{} { +func listGroupMembers(ctx context.Context, client client.AzureClient, panicChan chan error, groups <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +67,7 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-c ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), groups) { @@ -84,6 +86,7 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-c for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-group-owners.go b/cmd/list-group-owners.go index 6bd171d..4dbed96 100644 --- a/cmd/list-group-owners.go +++ b/cmd/list-group-owners.go @@ -51,13 +51,14 @@ func listGroupOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure group owners...") start := time.Now() - stream := listGroupOwners(ctx, azClient, listGroups(ctx, azClient)) + panicChan := panicChan() + stream := listGroupOwners(ctx, azClient, panicChan, listGroups(ctx, azClient, panicChan)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-chan interface{}) <-chan interface{} { +func listGroupOwners(ctx context.Context, client client.AzureClient, panicChan chan error, groups <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +67,7 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-ch ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), groups) { @@ -84,6 +86,7 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-ch for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-groups.go b/cmd/list-groups.go index 21e321a..25544fc 100644 --- a/cmd/list-groups.go +++ b/cmd/list-groups.go @@ -49,16 +49,19 @@ func listGroupsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory groups...") start := time.Now() - stream := listGroups(ctx, azClient) + panicChan := panicChan() + stream := listGroups(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listGroups(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listGroups(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) count := 0 for item := range client.ListAzureADGroups(ctx, "securityEnabled eq true", "", "", "", nil) { From 647e887a1c39fcd7a142c5b7ae04f38c9137168c Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 15:19:41 -0700 Subject: [PATCH 08/26] list-service-principles list-service-principalOwners list-tenants list-app-role-assignments --- cmd/list-app-role-assignments.go | 10 +++++++--- cmd/list-azure-ad.go | 8 ++++---- cmd/list-service-principal-owners.go | 8 ++++++-- cmd/list-service-principals.go | 7 +++++-- cmd/list-tenants.go | 7 +++++-- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/cmd/list-app-role-assignments.go b/cmd/list-app-role-assignments.go index 0cb2a52..2f96c53 100644 --- a/cmd/list-app-role-assignments.go +++ b/cmd/list-app-role-assignments.go @@ -51,14 +51,16 @@ func listAppRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory app role assignments...") start := time.Now() - servicePrincipals := listServicePrincipals(ctx, azClient) - stream := listAppRoleAssignments(ctx, azClient, servicePrincipals) + panicChan := panicChan() + servicePrincipals := listServicePrincipals(ctx, azClient, panicChan) + stream := listAppRoleAssignments(ctx, azClient, panicChan, servicePrincipals) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAppRoleAssignments(ctx context.Context, client client.AzureClient, servicePrincipals <-chan interface{}) <-chan interface{} { +func listAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, servicePrincipals <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) filteredSPs = make(chan models.ServicePrincipal) @@ -67,6 +69,7 @@ func listAppRoleAssignments(ctx context.Context, client client.AzureClient, serv ) go func() { + defer panicRecovery(panicChan) defer close(filteredSPs) for result := range pipeline.OrDone(ctx.Done(), servicePrincipals) { @@ -87,6 +90,7 @@ func listAppRoleAssignments(ctx context.Context, client client.AzureClient, serv for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for servicePrincipal := range stream { var ( diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index be4b056..096849e 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -95,11 +95,11 @@ func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan er groupMembers := listGroupMembers(ctx, client, panicChan, groups3) // Enumerate ServicePrincipals and ServicePrincipalOwners - pipeline.Tee(ctx.Done(), listServicePrincipals(ctx, client), servicePrincipals, servicePrincipals2, servicePrincipals3) - servicePrincipalOwners := listServicePrincipalOwners(ctx, client, servicePrincipals2) + pipeline.Tee(ctx.Done(), listServicePrincipals(ctx, client, panicChan), servicePrincipals, servicePrincipals2, servicePrincipals3) + servicePrincipalOwners := listServicePrincipalOwners(ctx, client, panicChan, servicePrincipals2) // Enumerate Tenants - pipeline.Tee(ctx.Done(), listTenants(ctx, client), tenants) + pipeline.Tee(ctx.Done(), listTenants(ctx, client, panicChan), tenants) // Enumerate Users users := listUsers(ctx, client) @@ -109,7 +109,7 @@ func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan er roleAssignments := listRoleAssignments(ctx, client, roles2) // Enumerate AppRoleAssignments - appRoleAssignments := listAppRoleAssignments(ctx, client, servicePrincipals3) + appRoleAssignments := listAppRoleAssignments(ctx, client, panicChan, servicePrincipals3) return pipeline.Mux(ctx.Done(), appOwners, diff --git a/cmd/list-service-principal-owners.go b/cmd/list-service-principal-owners.go index 5e07aed..b67ed94 100644 --- a/cmd/list-service-principal-owners.go +++ b/cmd/list-service-principal-owners.go @@ -51,13 +51,15 @@ func listServicePrincipalOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure service principal owners...") start := time.Now() - stream := listServicePrincipalOwners(ctx, azClient, listServicePrincipals(ctx, azClient)) + panicChan := panicChan() + stream := listServicePrincipalOwners(ctx, azClient, panicChan, listServicePrincipals(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, servicePrincipals <-chan interface{}) <-chan interface{} { +func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, panicChan chan error, servicePrincipals <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), servicePrincipals) { @@ -84,6 +87,7 @@ func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-service-principals.go b/cmd/list-service-principals.go index 80500e9..1a3f549 100644 --- a/cmd/list-service-principals.go +++ b/cmd/list-service-principals.go @@ -49,16 +49,19 @@ func listServicePrincipalsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory service principals...") start := time.Now() - stream := listServicePrincipals(ctx, azClient) + panicChan := panicChan() + stream := listServicePrincipals(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listServicePrincipals(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listServicePrincipals(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) count := 0 for item := range client.ListAzureADServicePrincipals(ctx, "", "", "", "", nil) { diff --git a/cmd/list-tenants.go b/cmd/list-tenants.go index 438cb79..f150793 100644 --- a/cmd/list-tenants.go +++ b/cmd/list-tenants.go @@ -49,16 +49,19 @@ func listTenantsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory tenants...") start := time.Now() - stream := listTenants(ctx, azClient) + panicChan := panicChan() + stream := listTenants(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listTenants(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listTenants(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) // Send the fully hydrated tenant that is being collected From 3ca490fbf4819be92d6d19a5487ecfceab9fe87d Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 15:20:38 -0700 Subject: [PATCH 09/26] listUsers --- cmd/list-azure-ad.go | 2 +- cmd/list-users.go | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index 096849e..200a8ef 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -102,7 +102,7 @@ func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan er pipeline.Tee(ctx.Done(), listTenants(ctx, client, panicChan), tenants) // Enumerate Users - users := listUsers(ctx, client) + users := listUsers(ctx, client, panicChan) // Enumerate Roles and RoleAssignments pipeline.Tee(ctx.Done(), listRoles(ctx, client), roles, roles2) diff --git a/cmd/list-users.go b/cmd/list-users.go index e02e37a..9bc6410 100644 --- a/cmd/list-users.go +++ b/cmd/list-users.go @@ -49,16 +49,19 @@ func listUsersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory users...") start := time.Now() - stream := listUsers(ctx, azClient) + panicChan := panicChan() + stream := listUsers(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listUsers(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listUsers(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) count := 0 for item := range client.ListAzureADUsers(ctx, "", "", "", []string{ From 62d141d3014b9764a5fdeb7657b71b6fa9b59370 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 15:22:12 -0700 Subject: [PATCH 10/26] list-roles list-role-assignments --- cmd/list-azure-ad.go | 4 ++-- cmd/list-role-assignments.go | 10 +++++++--- cmd/list-roles.go | 7 +++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index 200a8ef..38c6f39 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -105,8 +105,8 @@ func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan er users := listUsers(ctx, client, panicChan) // Enumerate Roles and RoleAssignments - pipeline.Tee(ctx.Done(), listRoles(ctx, client), roles, roles2) - roleAssignments := listRoleAssignments(ctx, client, roles2) + pipeline.Tee(ctx.Done(), listRoles(ctx, client, panicChan), roles, roles2) + roleAssignments := listRoleAssignments(ctx, client, panicChan, roles2) // Enumerate AppRoleAssignments appRoleAssignments := listAppRoleAssignments(ctx, client, panicChan, servicePrincipals3) diff --git a/cmd/list-role-assignments.go b/cmd/list-role-assignments.go index 0289c9e..f1a7c9e 100644 --- a/cmd/list-role-assignments.go +++ b/cmd/list-role-assignments.go @@ -51,14 +51,16 @@ func listRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory role assignments...") start := time.Now() - roles := listRoles(ctx, azClient) - stream := listRoleAssignments(ctx, azClient, roles) + panicChan := panicChan() + roles := listRoles(ctx, azClient, panicChan) + stream := listRoleAssignments(ctx, azClient, panicChan, roles) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listRoleAssignments(ctx context.Context, client client.AzureClient, roles <-chan interface{}) <-chan interface{} { +func listRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, roles <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -67,6 +69,7 @@ func listRoleAssignments(ctx context.Context, client client.AzureClient, roles < ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), roles) { @@ -85,6 +88,7 @@ func listRoleAssignments(ctx context.Context, client client.AzureClient, roles < for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-roles.go b/cmd/list-roles.go index ab93352..a61773d 100644 --- a/cmd/list-roles.go +++ b/cmd/list-roles.go @@ -49,16 +49,19 @@ func listRolesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory roles...") start := time.Now() - stream := listRoles(ctx, azClient) + panicChan := panicChan() + stream := listRoles(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listRoles(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listRoles(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) count := 0 for item := range client.ListAzureADRoles(ctx, "", "") { From 8866740c94cb792aee70f37ca1d9fa322edcf694 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 15:47:04 -0700 Subject: [PATCH 11/26] listAzureRm --- cmd/list-automation-accounts.go | 8 +++- cmd/list-azure-rm.go | 40 ++++++++++--------- cmd/list-container-registries.go | 9 ++++- cmd/list-function-apps.go | 8 +++- cmd/list-key-vaults.go | 8 +++- cmd/list-logic-apps.go | 9 ++++- cmd/list-managed-clusters.go | 9 ++++- cmd/list-management-group-descendants.go | 8 +++- cmd/list-management-group-owners.go | 6 ++- cmd/list-management-group-role-assignments.go | 10 +++-- ...ist-management-group-user-access-admins.go | 6 ++- cmd/list-management-groups.go | 7 +++- cmd/list-resource-groups.go | 8 +++- cmd/list-root.go | 2 +- cmd/list-storage-accounts.go | 2 +- cmd/list-subscription-owners.go | 11 +++-- cmd/list-subscription-role-assignments.go | 10 +++-- cmd/list-subscription-user-access-admins.go | 11 +++-- cmd/list-subscriptions.go | 7 +++- cmd/list-virtual-machines.go | 8 +++- cmd/list-vm-scale-sets.go | 9 ++++- cmd/list-web-apps.go | 8 +++- 22 files changed, 139 insertions(+), 65 deletions(-) diff --git a/cmd/list-automation-accounts.go b/cmd/list-automation-accounts.go index cf38396..02d30f1 100644 --- a/cmd/list-automation-accounts.go +++ b/cmd/list-automation-accounts.go @@ -51,13 +51,15 @@ func listAutomationAccountsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure automation accounts...") start := time.Now() - stream := listAutomationAccounts(ctx, azClient, listSubscriptions(ctx, azClient)) + panicChan := panicChan() + stream := listAutomationAccounts(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAutomationAccounts(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listAutomationAccounts(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listAutomationAccounts(ctx context.Context, client client.AzureClient, subs ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -83,6 +86,7 @@ func listAutomationAccounts(ctx context.Context, client client.AzureClient, subs for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-azure-rm.go b/cmd/list-azure-rm.go index de4f186..778178f 100644 --- a/cmd/list-azure-rm.go +++ b/cmd/list-azure-rm.go @@ -55,13 +55,15 @@ func listAzureRMCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure resource management objects...") start := time.Now() - stream := listAllRM(ctx, azClient) + panicChan := panicChan() + stream := listAllRM(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAllRM(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { var ( functionApps = make(chan interface{}) functionApps2 = make(chan interface{}) @@ -128,8 +130,8 @@ func listAllRM(ctx context.Context, client client.AzureClient) <-chan interface{ ) // Enumerate entities - pipeline.Tee(ctx.Done(), listManagementGroups(ctx, client), mgmtGroups, mgmtGroups2, mgmtGroups3) - pipeline.Tee(ctx.Done(), listSubscriptions(ctx, client), + pipeline.Tee(ctx.Done(), listManagementGroups(ctx, client, panicChan), mgmtGroups, mgmtGroups2, mgmtGroups3) + pipeline.Tee(ctx.Done(), listSubscriptions(ctx, client, panicChan), subscriptions, subscriptions2, subscriptions3, @@ -143,28 +145,28 @@ func listAllRM(ctx context.Context, client client.AzureClient) <-chan interface{ subscriptions11, subscriptions12, ) - pipeline.Tee(ctx.Done(), listResourceGroups(ctx, client, subscriptions2), resourceGroups, resourceGroups2) - pipeline.Tee(ctx.Done(), listKeyVaults(ctx, client, subscriptions3), keyVaults, keyVaults2, keyVaults3) - pipeline.Tee(ctx.Done(), listVirtualMachines(ctx, client, subscriptions4), virtualMachines, virtualMachines2) - pipeline.Tee(ctx.Done(), listFunctionApps(ctx, client, subscriptions6), functionApps, functionApps2) - pipeline.Tee(ctx.Done(), listWebApps(ctx, client, subscriptions7), webApps, webApps2) - pipeline.Tee(ctx.Done(), listAutomationAccounts(ctx, client, subscriptions8), automationAccounts, automationAccounts2) - pipeline.Tee(ctx.Done(), listContainerRegistries(ctx, client, subscriptions9), containerRegistries, containerRegistries2) - pipeline.Tee(ctx.Done(), listLogicApps(ctx, client, subscriptions10), logicApps, logicApps2) - pipeline.Tee(ctx.Done(), listManagedClusters(ctx, client, subscriptions11), managedClusters, managedClusters2) - pipeline.Tee(ctx.Done(), listVMScaleSets(ctx, client, subscriptions12), vmScaleSets, vmScaleSets2) + pipeline.Tee(ctx.Done(), listResourceGroups(ctx, client, panicChan, subscriptions2), resourceGroups, resourceGroups2) + pipeline.Tee(ctx.Done(), listKeyVaults(ctx, client, panicChan, subscriptions3), keyVaults, keyVaults2, keyVaults3) + pipeline.Tee(ctx.Done(), listVirtualMachines(ctx, client, panicChan, subscriptions4), virtualMachines, virtualMachines2) + pipeline.Tee(ctx.Done(), listFunctionApps(ctx, client, panicChan, subscriptions6), functionApps, functionApps2) + pipeline.Tee(ctx.Done(), listWebApps(ctx, client, panicChan, subscriptions7), webApps, webApps2) + pipeline.Tee(ctx.Done(), listAutomationAccounts(ctx, client, panicChan, subscriptions8), automationAccounts, automationAccounts2) + pipeline.Tee(ctx.Done(), listContainerRegistries(ctx, client, panicChan, subscriptions9), containerRegistries, containerRegistries2) + pipeline.Tee(ctx.Done(), listLogicApps(ctx, client, panicChan, subscriptions10), logicApps, logicApps2) + pipeline.Tee(ctx.Done(), listManagedClusters(ctx, client, panicChan, subscriptions11), managedClusters, managedClusters2) + pipeline.Tee(ctx.Done(), listVMScaleSets(ctx, client, panicChan, subscriptions12), vmScaleSets, vmScaleSets2) // Enumerate Relationships // ManagementGroups: Descendants, Owners and UserAccessAdmins - mgmtGroupDescendants := listManagementGroupDescendants(ctx, client, mgmtGroups2) - pipeline.Tee(ctx.Done(), listManagementGroupRoleAssignments(ctx, client, mgmtGroups3), mgmtGroupRoleAssignments1, mgmtGroupRoleAssignments2) + mgmtGroupDescendants := listManagementGroupDescendants(ctx, client, panicChan, mgmtGroups2) + pipeline.Tee(ctx.Done(), listManagementGroupRoleAssignments(ctx, client, panicChan, mgmtGroups3), mgmtGroupRoleAssignments1, mgmtGroupRoleAssignments2) mgmtGroupOwners := listManagementGroupOwners(ctx, mgmtGroupRoleAssignments1) mgmtGroupUserAccessAdmins := listManagementGroupUserAccessAdmins(ctx, mgmtGroupRoleAssignments2) // Subscriptions: Owners and UserAccessAdmins - pipeline.Tee(ctx.Done(), listSubscriptionRoleAssignments(ctx, client, subscriptions5), subscriptionRoleAssignments1, subscriptionRoleAssignments2) - subscriptionOwners := listSubscriptionOwners(ctx, client, subscriptionRoleAssignments1) - subscriptionUserAccessAdmins := listSubscriptionUserAccessAdmins(ctx, client, subscriptionRoleAssignments2) + pipeline.Tee(ctx.Done(), listSubscriptionRoleAssignments(ctx, client, panicChan, subscriptions5), subscriptionRoleAssignments1, subscriptionRoleAssignments2) + subscriptionOwners := listSubscriptionOwners(ctx, client, panicChan, subscriptionRoleAssignments1) + subscriptionUserAccessAdmins := listSubscriptionUserAccessAdmins(ctx, client, panicChan, subscriptionRoleAssignments2) // ResourceGroups: Owners and UserAccessAdmins pipeline.Tee(ctx.Done(), listResourceGroupRoleAssignments(ctx, client, resourceGroups2), resourceGroupRoleAssignments1, resourceGroupRoleAssignments2) diff --git a/cmd/list-container-registries.go b/cmd/list-container-registries.go index 2ed3e4f..5556ba6 100644 --- a/cmd/list-container-registries.go +++ b/cmd/list-container-registries.go @@ -45,6 +45,7 @@ var listContainerRegistriesCmd = &cobra.Command{ func listContainerRegistriesCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) + panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -55,14 +56,16 @@ func listContainerRegistriesCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure container registries...") start := time.Now() - stream := listContainerRegistries(ctx, azClient, listSubscriptions(ctx, azClient)) + stream := listContainerRegistries(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } + + handleBubbledPanic(ctx, panicChan, stop) } -func listContainerRegistries(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listContainerRegistries(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -71,6 +74,7 @@ func listContainerRegistries(ctx context.Context, client client.AzureClient, sub ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -88,6 +92,7 @@ func listContainerRegistries(ctx context.Context, client client.AzureClient, sub for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-function-apps.go b/cmd/list-function-apps.go index a63e453..b2b7c80 100644 --- a/cmd/list-function-apps.go +++ b/cmd/list-function-apps.go @@ -51,13 +51,15 @@ func listFunctionAppsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure function apps...") start := time.Now() - stream := listFunctionApps(ctx, azClient, listSubscriptions(ctx, azClient)) + panicChan := panicChan() + stream := listFunctionApps(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listFunctionApps(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listFunctionApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listFunctionApps(ctx context.Context, client client.AzureClient, subscripti ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -83,6 +86,7 @@ func listFunctionApps(ctx context.Context, client client.AzureClient, subscripti for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-key-vaults.go b/cmd/list-key-vaults.go index dee1bcb..3326387 100644 --- a/cmd/list-key-vaults.go +++ b/cmd/list-key-vaults.go @@ -51,13 +51,15 @@ func listKeyVaultsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vaults...") start := time.Now() - stream := listKeyVaults(ctx, azClient, listSubscriptions(ctx, azClient)) + panicChan := panicChan() + stream := listKeyVaults(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listKeyVaults(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listKeyVaults(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listKeyVaults(ctx context.Context, client client.AzureClient, subscriptions ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { @@ -84,6 +87,7 @@ func listKeyVaults(ctx context.Context, client client.AzureClient, subscriptions for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-logic-apps.go b/cmd/list-logic-apps.go index a928634..e2a68ac 100644 --- a/cmd/list-logic-apps.go +++ b/cmd/list-logic-apps.go @@ -45,6 +45,7 @@ var listLogicAppsCmd = &cobra.Command{ func listLogicAppsCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) + panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -55,14 +56,16 @@ func listLogicAppsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure logic apps...") start := time.Now() - stream := listLogicApps(ctx, azClient, listSubscriptions(ctx, azClient)) + stream := listLogicApps(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } + + handleBubbledPanic(ctx, panicChan, stop) } -func listLogicApps(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listLogicApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -71,6 +74,7 @@ func listLogicApps(ctx context.Context, client client.AzureClient, subscriptions ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -88,6 +92,7 @@ func listLogicApps(ctx context.Context, client client.AzureClient, subscriptions for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-managed-clusters.go b/cmd/list-managed-clusters.go index 3384e61..6100f4b 100644 --- a/cmd/list-managed-clusters.go +++ b/cmd/list-managed-clusters.go @@ -45,6 +45,7 @@ var listManagedClustersCmd = &cobra.Command{ func listManagedClustersCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) + panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -55,14 +56,16 @@ func listManagedClustersCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure managed clusters...") start := time.Now() - stream := listManagedClusters(ctx, azClient, listSubscriptions(ctx, azClient)) + stream := listManagedClusters(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } + + handleBubbledPanic(ctx, panicChan, stop) } -func listManagedClusters(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listManagedClusters(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -71,6 +74,7 @@ func listManagedClusters(ctx context.Context, client client.AzureClient, subscri ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -88,6 +92,7 @@ func listManagedClusters(ctx context.Context, client client.AzureClient, subscri for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-management-group-descendants.go b/cmd/list-management-group-descendants.go index 904c11e..7b06389 100644 --- a/cmd/list-management-group-descendants.go +++ b/cmd/list-management-group-descendants.go @@ -51,13 +51,15 @@ func listManagementGroupDescendantsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure management group descendants...") start := time.Now() - stream := listManagementGroupDescendants(ctx, azClient, listManagementGroups(ctx, azClient)) + panicChan := panicChan() + stream := listManagementGroupDescendants(ctx, azClient, panicChan, listManagementGroups(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listManagementGroupDescendants(ctx context.Context, client client.AzureClient, managementGroups <-chan interface{}) <-chan interface{} { +func listManagementGroupDescendants(ctx context.Context, client client.AzureClient, panicChan chan error, managementGroups <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listManagementGroupDescendants(ctx context.Context, client client.AzureClie ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), managementGroups) { @@ -84,6 +87,7 @@ func listManagementGroupDescendants(ctx context.Context, client client.AzureClie for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-management-group-owners.go b/cmd/list-management-group-owners.go index c28cf6b..7d2417b 100644 --- a/cmd/list-management-group-owners.go +++ b/cmd/list-management-group-owners.go @@ -50,8 +50,10 @@ func listManagementGroupOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure management group owners...") start := time.Now() - managementGroups := listManagementGroups(ctx, azClient) - roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, managementGroups) + panicChan := panicChan() + managementGroups := listManagementGroups(ctx, azClient, panicChan) + roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, panicChan, managementGroups) + handleBubbledPanic(ctx, panicChan, stop) stream := listManagementGroupOwners(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-management-group-role-assignments.go b/cmd/list-management-group-role-assignments.go index 3d07121..9198e79 100644 --- a/cmd/list-management-group-role-assignments.go +++ b/cmd/list-management-group-role-assignments.go @@ -51,14 +51,16 @@ func listManagementGroupRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string azClient := connectAndCreateClient() log.Info("collecting azure management group role assignments...") start := time.Now() - managementGroups := listManagementGroups(ctx, azClient) - stream := listManagementGroupRoleAssignments(ctx, azClient, managementGroups) + panicChan := panicChan() + managementGroups := listManagementGroups(ctx, azClient, panicChan) + stream := listManagementGroupRoleAssignments(ctx, azClient, panicChan, managementGroups) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listManagementGroupRoleAssignments(ctx context.Context, client client.AzureClient, managementGroups <-chan interface{}) <-chan azureWrapper[models.ManagementGroupRoleAssignments] { +func listManagementGroupRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, managementGroups <-chan interface{}) <-chan azureWrapper[models.ManagementGroupRoleAssignments] { var ( out = make(chan azureWrapper[models.ManagementGroupRoleAssignments]) ids = make(chan string) @@ -67,6 +69,7 @@ func listManagementGroupRoleAssignments(ctx context.Context, client client.Azure ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), managementGroups) { @@ -85,6 +88,7 @@ func listManagementGroupRoleAssignments(ctx context.Context, client client.Azure for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-management-group-user-access-admins.go b/cmd/list-management-group-user-access-admins.go index 1235a51..96b2751 100644 --- a/cmd/list-management-group-user-access-admins.go +++ b/cmd/list-management-group-user-access-admins.go @@ -50,8 +50,10 @@ func listManagementGroupUserAccessAdminsCmdImpl(cmd *cobra.Command, args []strin azClient := connectAndCreateClient() log.Info("collecting azure management group user access admins...") start := time.Now() - managementGroups := listManagementGroups(ctx, azClient) - roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, managementGroups) + panicChan := panicChan() + managementGroups := listManagementGroups(ctx, azClient, panicChan) + roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, panicChan, managementGroups) + handleBubbledPanic(ctx, panicChan, stop) stream := listManagementGroupUserAccessAdmins(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-management-groups.go b/cmd/list-management-groups.go index 2d02e5f..54549f6 100644 --- a/cmd/list-management-groups.go +++ b/cmd/list-management-groups.go @@ -50,16 +50,19 @@ func listManagementGroupsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory management groups...") start := time.Now() - stream := listManagementGroups(ctx, azClient) + panicChan := panicChan() + stream := listManagementGroups(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listManagementGroups(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listManagementGroups(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) count := 0 for item := range client.ListAzureManagementGroups(ctx) { diff --git a/cmd/list-resource-groups.go b/cmd/list-resource-groups.go index 5f83d56..2e3ca66 100644 --- a/cmd/list-resource-groups.go +++ b/cmd/list-resource-groups.go @@ -51,13 +51,15 @@ func listResourceGroupsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure resource groups...") start := time.Now() - stream := listResourceGroups(ctx, azClient, listSubscriptions(ctx, azClient)) + panicChan := panicChan() + stream := listResourceGroups(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listResourceGroups(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listResourceGroups(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listResourceGroups(ctx context.Context, client client.AzureClient, subscrip ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { @@ -84,6 +87,7 @@ func listResourceGroups(ctx context.Context, client client.AzureClient, subscrip for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-root.go b/cmd/list-root.go index 649bf2e..1cf76ee 100644 --- a/cmd/list-root.go +++ b/cmd/list-root.go @@ -68,7 +68,7 @@ func listAll(ctx context.Context, client client.AzureClient) <-chan interface{} panicChan = panicChan() azureAD = listAllAD(ctx, client, panicChan) - azureRM = listAllRM(ctx, client) + azureRM = listAllRM(ctx, client, panicChan) ) handleBubbledPanic(ctx, panicChan, stop) diff --git a/cmd/list-storage-accounts.go b/cmd/list-storage-accounts.go index 143a645..35c65a2 100644 --- a/cmd/list-storage-accounts.go +++ b/cmd/list-storage-accounts.go @@ -57,7 +57,7 @@ func listStorageAccountsCmdImpl(cmd *cobra.Command, args []string) { log.Info("collection completed", "duration", duration.String()) } -func listStorageAccounts(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listStorageAccounts(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) diff --git a/cmd/list-subscription-owners.go b/cmd/list-subscription-owners.go index af7dd59..91d32df 100644 --- a/cmd/list-subscription-owners.go +++ b/cmd/list-subscription-owners.go @@ -52,18 +52,21 @@ func listSubscriptionOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure subscription owners...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, subscriptions) - stream := listSubscriptionOwners(ctx, azClient, roleAssignments) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, panicChan, subscriptions) + stream := listSubscriptionOwners(ctx, azClient, panicChan, roleAssignments) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptionOwners(ctx context.Context, client client.AzureClient, roleAssignments <-chan interface{}) <-chan interface{} { +func listSubscriptionOwners(ctx context.Context, client client.AzureClient, panicChan chan error, roleAssignments <-chan interface{}) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) for result := range pipeline.OrDone(ctx.Done(), roleAssignments) { diff --git a/cmd/list-subscription-role-assignments.go b/cmd/list-subscription-role-assignments.go index 3f23107..b41c371 100644 --- a/cmd/list-subscription-role-assignments.go +++ b/cmd/list-subscription-role-assignments.go @@ -51,14 +51,16 @@ func listSubscriptionRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure subscription role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listSubscriptionRoleAssignments(ctx, azClient, subscriptions) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listSubscriptionRoleAssignments(ctx, azClient, panicChan, subscriptions) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -67,6 +69,7 @@ func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureCli ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { @@ -85,6 +88,7 @@ func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureCli for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-subscription-user-access-admins.go b/cmd/list-subscription-user-access-admins.go index 9947836..39abb01 100644 --- a/cmd/list-subscription-user-access-admins.go +++ b/cmd/list-subscription-user-access-admins.go @@ -52,18 +52,21 @@ func listSubscriptionUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure subscription user access admins...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, subscriptions) - stream := listSubscriptionUserAccessAdmins(ctx, azClient, roleAssignments) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, panicChan, subscriptions) + stream := listSubscriptionUserAccessAdmins(ctx, azClient, panicChan, roleAssignments) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptionUserAccessAdmins(ctx context.Context, client client.AzureClient, vmRoleAssignments <-chan interface{}) <-chan interface{} { +func listSubscriptionUserAccessAdmins(ctx context.Context, client client.AzureClient, panicChan chan error, vmRoleAssignments <-chan interface{}) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) for result := range pipeline.OrDone(ctx.Done(), vmRoleAssignments) { diff --git a/cmd/list-subscriptions.go b/cmd/list-subscriptions.go index b2ee039..ccca449 100644 --- a/cmd/list-subscriptions.go +++ b/cmd/list-subscriptions.go @@ -53,16 +53,19 @@ func listSubscriptionsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory subscriptions...") start := time.Now() - stream := listSubscriptions(ctx, azClient) + panicChan := panicChan() + stream := listSubscriptions(ctx, azClient, panicChan) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptions(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listSubscriptions(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) var ( count = 0 diff --git a/cmd/list-virtual-machines.go b/cmd/list-virtual-machines.go index ad4b78e..9d0fa01 100644 --- a/cmd/list-virtual-machines.go +++ b/cmd/list-virtual-machines.go @@ -51,13 +51,15 @@ func listVirtualMachinesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machines...") start := time.Now() - stream := listVirtualMachines(ctx, azClient, listSubscriptions(ctx, azClient)) + panicChan := panicChan() + stream := listVirtualMachines(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listVirtualMachines(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listVirtualMachines(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -66,6 +68,7 @@ func listVirtualMachines(ctx context.Context, client client.AzureClient, subscri ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -83,6 +86,7 @@ func listVirtualMachines(ctx context.Context, client client.AzureClient, subscri for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-vm-scale-sets.go b/cmd/list-vm-scale-sets.go index 9623a54..a81d648 100644 --- a/cmd/list-vm-scale-sets.go +++ b/cmd/list-vm-scale-sets.go @@ -45,6 +45,7 @@ var listVMScaleSetsCmd = &cobra.Command{ func listVMScaleSetsCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) + panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -55,14 +56,16 @@ func listVMScaleSetsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure virtual machine scale sets...") start := time.Now() - stream := listVMScaleSets(ctx, azClient, listSubscriptions(ctx, azClient)) + stream := listVMScaleSets(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } + + handleBubbledPanic(ctx, panicChan, stop) } -func listVMScaleSets(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listVMScaleSets(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -71,6 +74,7 @@ func listVMScaleSets(ctx context.Context, client client.AzureClient, subscriptio ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -88,6 +92,7 @@ func listVMScaleSets(ctx context.Context, client client.AzureClient, subscriptio for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-web-apps.go b/cmd/list-web-apps.go index ac1bad7..726617e 100644 --- a/cmd/list-web-apps.go +++ b/cmd/list-web-apps.go @@ -55,14 +55,16 @@ func listWebAppsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure web apps...") start := time.Now() - stream := listWebApps(ctx, azClient, listSubscriptions(ctx, azClient)) + panicChan := panicChan() + stream := listWebApps(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listWebApps(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { +func listWebApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -71,6 +73,7 @@ func listWebApps(ctx context.Context, client client.AzureClient, subscriptions < ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -88,6 +91,7 @@ func listWebApps(ctx context.Context, client client.AzureClient, subscriptions < for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 From 96995de782d59fdee666df8fd88c30e084409ee3 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 16:12:56 -0700 Subject: [PATCH 12/26] listAzureRM group 2 --- cmd/list-azure-rm.go | 10 +++++----- cmd/list-function-app-role-assignments.go | 10 +++++++--- cmd/list-key-vault-access-policies.go | 9 ++++++--- cmd/list-key-vault-contributors.go | 8 +++++--- cmd/list-key-vault-kvcontributors.go | 8 +++++--- cmd/list-key-vault-owners.go | 8 +++++--- cmd/list-key-vault-role-assignments.go | 10 +++++++--- cmd/list-key-vault-user-access-admins.go | 8 +++++--- cmd/list-resource-group-owners.go | 8 +++++--- cmd/list-resource-group-role-assignments.go | 12 ++++++++---- cmd/list-resource-group-user-access-admins.go | 8 +++++--- cmd/list-subscriptions.go | 2 +- cmd/list-virtual-machine-avere-contributors.go | 8 +++++--- cmd/list-virtual-machine-contributors.go | 8 +++++--- cmd/list-virtual-machine-owners.go | 8 +++++--- cmd/list-virtual-machine-role-assignments.go | 10 +++++++--- cmd/list-virtual-machine-user-access-admins.go | 8 +++++--- 17 files changed, 91 insertions(+), 52 deletions(-) diff --git a/cmd/list-azure-rm.go b/cmd/list-azure-rm.go index 778178f..0e1b847 100644 --- a/cmd/list-azure-rm.go +++ b/cmd/list-azure-rm.go @@ -169,20 +169,20 @@ func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan er subscriptionUserAccessAdmins := listSubscriptionUserAccessAdmins(ctx, client, panicChan, subscriptionRoleAssignments2) // ResourceGroups: Owners and UserAccessAdmins - pipeline.Tee(ctx.Done(), listResourceGroupRoleAssignments(ctx, client, resourceGroups2), resourceGroupRoleAssignments1, resourceGroupRoleAssignments2) + pipeline.Tee(ctx.Done(), listResourceGroupRoleAssignments(ctx, client, panicChan, resourceGroups2), resourceGroupRoleAssignments1, resourceGroupRoleAssignments2) resourceGroupOwners := listResourceGroupOwners(ctx, resourceGroupRoleAssignments1) resourceGroupUserAccessAdmins := listResourceGroupUserAccessAdmins(ctx, resourceGroupRoleAssignments2) // KeyVaults: AccessPolicies, Owners, UserAccessAdmins, Contributors and KVContributors - pipeline.Tee(ctx.Done(), listKeyVaultRoleAssignments(ctx, client, keyVaults2), keyVaultRoleAssignments1, keyVaultRoleAssignments2, keyVaultRoleAssignments3, keyVaultRoleAssignments4) - keyVaultAccessPolicies := listKeyVaultAccessPolicies(ctx, client, keyVaults3, []enums.KeyVaultAccessType{enums.GetCerts, enums.GetKeys, enums.GetCerts}) + pipeline.Tee(ctx.Done(), listKeyVaultRoleAssignments(ctx, client, panicChan, keyVaults2), keyVaultRoleAssignments1, keyVaultRoleAssignments2, keyVaultRoleAssignments3, keyVaultRoleAssignments4) + keyVaultAccessPolicies := listKeyVaultAccessPolicies(ctx, client, panicChan, keyVaults3, []enums.KeyVaultAccessType{enums.GetCerts, enums.GetKeys, enums.GetCerts}) keyVaultOwners := listKeyVaultOwners(ctx, keyVaultRoleAssignments1) keyVaultUserAccessAdmins := listKeyVaultUserAccessAdmins(ctx, keyVaultRoleAssignments2) keyVaultContributors := listKeyVaultContributors(ctx, keyVaultRoleAssignments3) keyVaultKVContributors := listKeyVaultKVContributors(ctx, keyVaultRoleAssignments4) // VirtualMachines: Owners, AvereContributors, Contributors, AdminLogins and UserAccessAdmins - pipeline.Tee(ctx.Done(), listVirtualMachineRoleAssignments(ctx, client, virtualMachines2), virtualMachineRoleAssignments1, virtualMachineRoleAssignments2, virtualMachineRoleAssignments3, virtualMachineRoleAssignments4, virtualMachineRoleAssignments5) + pipeline.Tee(ctx.Done(), listVirtualMachineRoleAssignments(ctx, client, panicChan, virtualMachines2), virtualMachineRoleAssignments1, virtualMachineRoleAssignments2, virtualMachineRoleAssignments3, virtualMachineRoleAssignments4, virtualMachineRoleAssignments5) virtualMachineOwners := listVirtualMachineOwners(ctx, virtualMachineRoleAssignments1) virtualMachineAvereContributors := listVirtualMachineAvereContributors(ctx, virtualMachineRoleAssignments2) virtualMachineContributors := listVirtualMachineContributors(ctx, virtualMachineRoleAssignments3) @@ -190,7 +190,7 @@ func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan er virtualMachineUserAccessAdmins := listVirtualMachineUserAccessAdmins(ctx, virtualMachineRoleAssignments5) // Enumerate Function App Role Assignments - functionAppRoleAssignments := listFunctionAppRoleAssignments(ctx, client, functionApps2) + functionAppRoleAssignments := listFunctionAppRoleAssignments(ctx, client, panicChan, functionApps2) // Enumerate Web App Role Assignments webAppRoleAssignments := listWebAppRoleAssignments(ctx, client, webApps2) diff --git a/cmd/list-function-app-role-assignments.go b/cmd/list-function-app-role-assignments.go index 7433e75..0f05298 100644 --- a/cmd/list-function-app-role-assignments.go +++ b/cmd/list-function-app-role-assignments.go @@ -52,14 +52,16 @@ func listFunctionAppRoleAssignmentImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure function app role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listFunctionAppRoleAssignments(ctx, azClient, listFunctionApps(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listFunctionAppRoleAssignments(ctx, azClient, panicChan, listFunctionApps(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClient, functionApps <-chan interface{}) <-chan interface{} { +func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, functionApps <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,6 +70,7 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), functionApps) { @@ -86,6 +89,7 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-key-vault-access-policies.go b/cmd/list-key-vault-access-policies.go index a7438e1..2091a46 100644 --- a/cmd/list-key-vault-access-policies.go +++ b/cmd/list-key-vault-access-policies.go @@ -53,24 +53,27 @@ func listKeyVaultAccessPoliciesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault access policies...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) if filters, ok := config.KeyVaultAccessTypes.Value().([]enums.KeyVaultAccessType); !ok { exit(fmt.Errorf("filter failed type assertion")) } else { if len(filters) > 0 { log.Info("applying access type filters", "filters", filters) } - stream := listKeyVaultAccessPolicies(ctx, azClient, listKeyVaults(ctx, azClient, subscriptions), filters) + stream := listKeyVaultAccessPolicies(ctx, azClient, panicChan, listKeyVaults(ctx, azClient, panicChan, subscriptions), filters) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } + handleBubbledPanic(ctx, panicChan, stop) } -func listKeyVaultAccessPolicies(ctx context.Context, client client.AzureClient, keyVaults <-chan interface{}, filters []enums.KeyVaultAccessType) <-chan interface{} { +func listKeyVaultAccessPolicies(ctx context.Context, client client.AzureClient, panicChan chan error, keyVaults <-chan interface{}, filters []enums.KeyVaultAccessType) <-chan interface{} { out := make(chan interface{}) go func() { + defer panicRecovery(panicChan) defer close(out) for result := range pipeline.OrDone(ctx.Done(), keyVaults) { diff --git a/cmd/list-key-vault-contributors.go b/cmd/list-key-vault-contributors.go index 59bb49d..288a1c1 100644 --- a/cmd/list-key-vault-contributors.go +++ b/cmd/list-key-vault-contributors.go @@ -50,9 +50,11 @@ func listKeyVaultContributorsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault contributors...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - keyVaults := listKeyVaults(ctx, azClient, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) + handleBubbledPanic(ctx, panicChan, stop) stream := listKeyVaultContributors(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-key-vault-kvcontributors.go b/cmd/list-key-vault-kvcontributors.go index 46bfdc6..fc905b8 100644 --- a/cmd/list-key-vault-kvcontributors.go +++ b/cmd/list-key-vault-kvcontributors.go @@ -50,9 +50,11 @@ func listKeyVaultKVContributorsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault kvcontributors...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - keyVaults := listKeyVaults(ctx, azClient, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) + handleBubbledPanic(ctx, panicChan, stop) stream := listKeyVaultKVContributors(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-key-vault-owners.go b/cmd/list-key-vault-owners.go index 42ae7db..eafe697 100644 --- a/cmd/list-key-vault-owners.go +++ b/cmd/list-key-vault-owners.go @@ -50,9 +50,11 @@ func listKeyVaultOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault owners...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - keyVaults := listKeyVaults(ctx, azClient, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) + handleBubbledPanic(ctx, panicChan, stop) stream := listKeyVaultOwners(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-key-vault-role-assignments.go b/cmd/list-key-vault-role-assignments.go index ee14b05..3d1e572 100644 --- a/cmd/list-key-vault-role-assignments.go +++ b/cmd/list-key-vault-role-assignments.go @@ -51,14 +51,16 @@ func listKeyVaultRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listKeyVaultRoleAssignments(ctx, azClient, listKeyVaults(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listKeyVaultRoleAssignments(ctx, azClient, panicChan, listKeyVaults(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, keyVaults <-chan interface{}) <-chan azureWrapper[models.KeyVaultRoleAssignments] { +func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, keyVaults <-chan interface{}) <-chan azureWrapper[models.KeyVaultRoleAssignments] { var ( out = make(chan azureWrapper[models.KeyVaultRoleAssignments]) ids = make(chan string) @@ -67,6 +69,7 @@ func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), keyVaults) { @@ -85,6 +88,7 @@ func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-key-vault-user-access-admins.go b/cmd/list-key-vault-user-access-admins.go index b19fd2c..a55c865 100644 --- a/cmd/list-key-vault-user-access-admins.go +++ b/cmd/list-key-vault-user-access-admins.go @@ -50,9 +50,11 @@ func listKeyVaultUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault user access admins...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - keyVaults := listKeyVaults(ctx, azClient, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) + handleBubbledPanic(ctx, panicChan, stop) stream := listKeyVaultUserAccessAdmins(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-resource-group-owners.go b/cmd/list-resource-group-owners.go index 7a07ae0..5b82932 100644 --- a/cmd/list-resource-group-owners.go +++ b/cmd/list-resource-group-owners.go @@ -50,9 +50,11 @@ func listResourceGroupOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure resource group owners...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - resourceGroups := listResourceGroups(ctx, azClient, subscriptions) - roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, resourceGroups) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + resourceGroups := listResourceGroups(ctx, azClient, panicChan, subscriptions) + roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, panicChan, resourceGroups) + handleBubbledPanic(ctx, panicChan, stop) stream := listResourceGroupOwners(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-resource-group-role-assignments.go b/cmd/list-resource-group-role-assignments.go index 055d3e0..3138f5b 100644 --- a/cmd/list-resource-group-role-assignments.go +++ b/cmd/list-resource-group-role-assignments.go @@ -51,15 +51,17 @@ func listResourceGroupRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure resource group role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - resourceGroups := listResourceGroups(ctx, azClient, subscriptions) - stream := listResourceGroupRoleAssignments(ctx, azClient, resourceGroups) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + resourceGroups := listResourceGroups(ctx, azClient, panicChan, subscriptions) + stream := listResourceGroupRoleAssignments(ctx, azClient, panicChan, resourceGroups) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureClient, resourceGroups <-chan interface{}) <-chan azureWrapper[models.ResourceGroupRoleAssignments] { +func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, resourceGroups <-chan interface{}) <-chan azureWrapper[models.ResourceGroupRoleAssignments] { var ( out = make(chan azureWrapper[models.ResourceGroupRoleAssignments]) ids = make(chan string) @@ -68,6 +70,7 @@ func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureCl ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), resourceGroups) { @@ -86,6 +89,7 @@ func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureCl for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-resource-group-user-access-admins.go b/cmd/list-resource-group-user-access-admins.go index 01f3af1..0550829 100644 --- a/cmd/list-resource-group-user-access-admins.go +++ b/cmd/list-resource-group-user-access-admins.go @@ -50,9 +50,11 @@ func listResourceGroupUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure resource group user access admins...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - resourceGroups := listResourceGroups(ctx, azClient, subscriptions) - roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, resourceGroups) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + resourceGroups := listResourceGroups(ctx, azClient, panicChan, subscriptions) + roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, panicChan, resourceGroups) + handleBubbledPanic(ctx, panicChan, stop) stream := listResourceGroupUserAccessAdmins(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-subscriptions.go b/cmd/list-subscriptions.go index ccca449..0a409b7 100644 --- a/cmd/list-subscriptions.go +++ b/cmd/list-subscriptions.go @@ -75,7 +75,7 @@ func listSubscriptions(ctx context.Context, client client.AzureClient, panicChan ) if len(selectedMgmtGroupIds) != 0 { - descendantChannel := listManagementGroupDescendants(ctx, client, listManagementGroups(ctx, client)) + descendantChannel := listManagementGroupDescendants(ctx, client, panicChan, listManagementGroups(ctx, client, panicChan)) for i := range descendantChannel { if item, ok := i.(AzureWrapper).Data.(azure.DescendantInfo); !ok { log.Error(fmt.Errorf("failed type assertion"), "unable to continue evaluating management group descendants", "result", i) diff --git a/cmd/list-virtual-machine-avere-contributors.go b/cmd/list-virtual-machine-avere-contributors.go index 6ee9780..24c0d60 100644 --- a/cmd/list-virtual-machine-avere-contributors.go +++ b/cmd/list-virtual-machine-avere-contributors.go @@ -50,9 +50,11 @@ func listVirtualMachineAvereContributorsCmdImpl(cmd *cobra.Command, args []strin azClient := connectAndCreateClient() log.Info("collecting azure virtual machine averecontributors...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - vms := listVirtualMachines(ctx, azClient, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) + handleBubbledPanic(ctx, panicChan, stop) stream := listVirtualMachineAvereContributors(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-contributors.go b/cmd/list-virtual-machine-contributors.go index 5d58f3d..4dd2873 100644 --- a/cmd/list-virtual-machine-contributors.go +++ b/cmd/list-virtual-machine-contributors.go @@ -50,9 +50,11 @@ func listVirtualMachineContributorsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machine contributors...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - vms := listVirtualMachines(ctx, azClient, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) + handleBubbledPanic(ctx, panicChan, stop) stream := listVirtualMachineContributors(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-owners.go b/cmd/list-virtual-machine-owners.go index 2f5b99b..a6061ed 100644 --- a/cmd/list-virtual-machine-owners.go +++ b/cmd/list-virtual-machine-owners.go @@ -50,9 +50,11 @@ func listVirtualMachineOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machine owners...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - vms := listVirtualMachines(ctx, azClient, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) + handleBubbledPanic(ctx, panicChan, stop) stream := listVirtualMachineOwners(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-role-assignments.go b/cmd/list-virtual-machine-role-assignments.go index d826a3f..8febdc3 100644 --- a/cmd/list-virtual-machine-role-assignments.go +++ b/cmd/list-virtual-machine-role-assignments.go @@ -51,14 +51,16 @@ func listVirtualMachineRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure virtual machine role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listVirtualMachineRoleAssignments(ctx, azClient, listVirtualMachines(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, listVirtualMachines(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureClient, virtualMachines <-chan interface{}) <-chan azureWrapper[models.VirtualMachineRoleAssignments] { +func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, virtualMachines <-chan interface{}) <-chan azureWrapper[models.VirtualMachineRoleAssignments] { var ( out = make(chan azureWrapper[models.VirtualMachineRoleAssignments]) ids = make(chan string) @@ -67,6 +69,7 @@ func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureC ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), virtualMachines) { @@ -85,6 +88,7 @@ func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureC for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-virtual-machine-user-access-admins.go b/cmd/list-virtual-machine-user-access-admins.go index 0846c0f..d87ed1a 100644 --- a/cmd/list-virtual-machine-user-access-admins.go +++ b/cmd/list-virtual-machine-user-access-admins.go @@ -50,9 +50,11 @@ func listVirtualMachineUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string azClient := connectAndCreateClient() log.Info("collecting azure virtual machine user access admins...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - vms := listVirtualMachines(ctx, azClient, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) + handleBubbledPanic(ctx, panicChan, stop) stream := listVirtualMachineUserAccessAdmins(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) From edb629b4381f084254f0e6c0137aed547d509131 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Fri, 15 Mar 2024 16:18:42 -0700 Subject: [PATCH 13/26] listAzureRM group 3 --- cmd/list-automation-account-role-assignments.go | 10 +++++++--- cmd/list-azure-rm.go | 12 ++++++------ cmd/list-container-registry-role-assignments.go | 10 +++++++--- cmd/list-logic-app-role-assignments.go | 10 +++++++--- cmd/list-managed-cluster-role-assignments.go | 10 +++++++--- cmd/list-vm-scale-set-role-assignments.go | 10 +++++++--- cmd/list-web-app-role-assignments.go | 10 +++++++--- 7 files changed, 48 insertions(+), 24 deletions(-) diff --git a/cmd/list-automation-account-role-assignments.go b/cmd/list-automation-account-role-assignments.go index f0bbcff..a5634da 100644 --- a/cmd/list-automation-account-role-assignments.go +++ b/cmd/list-automation-account-role-assignments.go @@ -52,14 +52,16 @@ func listAutomationAccountRoleAssignmentImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure automation account role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listAutomationAccountRoleAssignments(ctx, azClient, listAutomationAccounts(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listAutomationAccountRoleAssignments(ctx, azClient, panicChan, listAutomationAccounts(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAutomationAccountRoleAssignments(ctx context.Context, client client.AzureClient, automationAccounts <-chan interface{}) <-chan interface{} { +func listAutomationAccountRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, automationAccounts <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,6 +70,7 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), automationAccounts) { @@ -86,6 +89,7 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-azure-rm.go b/cmd/list-azure-rm.go index 0e1b847..3491486 100644 --- a/cmd/list-azure-rm.go +++ b/cmd/list-azure-rm.go @@ -193,22 +193,22 @@ func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan er functionAppRoleAssignments := listFunctionAppRoleAssignments(ctx, client, panicChan, functionApps2) // Enumerate Web App Role Assignments - webAppRoleAssignments := listWebAppRoleAssignments(ctx, client, webApps2) + webAppRoleAssignments := listWebAppRoleAssignments(ctx, client, panicChan, webApps2) // Enumerate Automation Account Role Assignments - automationAccountRoleAssignments := listAutomationAccountRoleAssignments(ctx, client, automationAccounts2) + automationAccountRoleAssignments := listAutomationAccountRoleAssignments(ctx, client, panicChan, automationAccounts2) // Enumerate Container Registry Role Assignments - containerRegistryRoleAssignments := listContainerRegistryRoleAssignments(ctx, client, containerRegistries2) + containerRegistryRoleAssignments := listContainerRegistryRoleAssignments(ctx, client, panicChan, containerRegistries2) // Enumerate Logic Apps Role Assignments - logicAppRoleAssignments := listLogicAppRoleAssignments(ctx, client, logicApps2) + logicAppRoleAssignments := listLogicAppRoleAssignments(ctx, client, panicChan, logicApps2) // Enumerate Managed Cluster Role Assignments - managedClusterRoleAssignments := listManagedClusterRoleAssignments(ctx, client, managedClusters2) + managedClusterRoleAssignments := listManagedClusterRoleAssignments(ctx, client, panicChan, managedClusters2) // Enumerate VM Scale Set Role Assignments - vmScaleSetRoleAssignments := listVMScaleSetRoleAssignments(ctx, client, vmScaleSets2) + vmScaleSetRoleAssignments := listVMScaleSetRoleAssignments(ctx, client, panicChan, vmScaleSets2) return pipeline.Mux(ctx.Done(), automationAccounts, diff --git a/cmd/list-container-registry-role-assignments.go b/cmd/list-container-registry-role-assignments.go index 4cfdf12..6122e04 100644 --- a/cmd/list-container-registry-role-assignments.go +++ b/cmd/list-container-registry-role-assignments.go @@ -56,15 +56,17 @@ func listContainerRegistryRoleAssignmentImpl(cmd *cobra.Command, args []string) } else { log.Info("collecting azure container registry role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listContainerRegistryRoleAssignments(ctx, azClient, listContainerRegistries(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listContainerRegistryRoleAssignments(ctx, azClient, panicChan, listContainerRegistries(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listContainerRegistryRoleAssignments(ctx context.Context, client client.AzureClient, containerRegistries <-chan interface{}) <-chan interface{} { +func listContainerRegistryRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, containerRegistries <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,6 +75,7 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), containerRegistries) { @@ -91,6 +94,7 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-logic-app-role-assignments.go b/cmd/list-logic-app-role-assignments.go index ed73508..6fe164a 100644 --- a/cmd/list-logic-app-role-assignments.go +++ b/cmd/list-logic-app-role-assignments.go @@ -56,15 +56,17 @@ func listLogicAppRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure logic app role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listLogicAppRoleAssignments(ctx, azClient, listLogicApps(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listLogicAppRoleAssignments(ctx, azClient, panicChan, listLogicApps(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, logicapps <-chan interface{}) <-chan interface{} { +func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, logicapps <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,6 +75,7 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), logicapps) { @@ -91,6 +94,7 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-managed-cluster-role-assignments.go b/cmd/list-managed-cluster-role-assignments.go index 323df75..10c5f23 100644 --- a/cmd/list-managed-cluster-role-assignments.go +++ b/cmd/list-managed-cluster-role-assignments.go @@ -56,15 +56,17 @@ func listManagedClusterRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure managed cluster role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listManagedClusterRoleAssignments(ctx, azClient, listManagedClusters(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listManagedClusterRoleAssignments(ctx, azClient, panicChan, listManagedClusters(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureClient, managedClusters <-chan interface{}) <-chan interface{} { +func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, managedClusters <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,6 +75,7 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), managedClusters) { @@ -91,6 +94,7 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-vm-scale-set-role-assignments.go b/cmd/list-vm-scale-set-role-assignments.go index 80c5a52..c871b4d 100644 --- a/cmd/list-vm-scale-set-role-assignments.go +++ b/cmd/list-vm-scale-set-role-assignments.go @@ -56,15 +56,17 @@ func listVMScaleSetRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure vm scale set role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listVMScaleSetRoleAssignments(ctx, azClient, listVMScaleSets(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listVMScaleSetRoleAssignments(ctx, azClient, panicChan, listVMScaleSets(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClient, vmScaleSets <-chan interface{}) <-chan interface{} { +func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, vmScaleSets <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,6 +75,7 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), vmScaleSets) { @@ -91,6 +94,7 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-web-app-role-assignments.go b/cmd/list-web-app-role-assignments.go index 3b45efb..81f0ded 100644 --- a/cmd/list-web-app-role-assignments.go +++ b/cmd/list-web-app-role-assignments.go @@ -56,15 +56,17 @@ func listWebAppRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure web app role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listWebAppRoleAssignments(ctx, azClient, listWebApps(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listWebAppRoleAssignments(ctx, azClient, panicChan, listWebApps(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, webApps <-chan interface{}) <-chan interface{} { +func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, webApps <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,6 +75,7 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, w ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), webApps) { @@ -91,6 +94,7 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, w for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( From a2652c47a9312913790532e459ec0faa39dc5cab Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Mon, 18 Mar 2024 09:43:16 -0700 Subject: [PATCH 14/26] panicChan to a couple strays --- cmd/list-storage-account-role-assignments.go | 10 +++++++--- cmd/list-storage-accounts.go | 6 +++++- cmd/list-storage-containers.go | 12 ++++++++---- cmd/list-virtual-machine-admin-logins.go | 8 +++++--- cmd/list-virtual-machine-vmcontributors.go | 8 +++++--- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/cmd/list-storage-account-role-assignments.go b/cmd/list-storage-account-role-assignments.go index 4e5d0bc..566fb98 100644 --- a/cmd/list-storage-account-role-assignments.go +++ b/cmd/list-storage-account-role-assignments.go @@ -52,14 +52,16 @@ func listStorageAccountRoleAssignmentsImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure storage account role assignments...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - stream := listStorageAccountRoleAssignments(ctx, azClient, listStorageAccounts(ctx, azClient, subscriptions)) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + stream := listStorageAccountRoleAssignments(ctx, azClient, panicChan, listStorageAccounts(ctx, azClient, panicChan, subscriptions)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureClient, storageAccounts <-chan interface{}) <-chan interface{} { +func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, storageAccounts <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,6 +70,7 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), storageAccounts) { @@ -86,6 +89,7 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-storage-accounts.go b/cmd/list-storage-accounts.go index 35c65a2..5c5a0b5 100644 --- a/cmd/list-storage-accounts.go +++ b/cmd/list-storage-accounts.go @@ -51,7 +51,9 @@ func listStorageAccountsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure storage accounts...") start := time.Now() - stream := listStorageAccounts(ctx, azClient, listSubscriptions(ctx, azClient)) + panicChan := panicChan() + stream := listStorageAccounts(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) @@ -66,6 +68,7 @@ func listStorageAccounts(ctx context.Context, client client.AzureClient, panicCh ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -83,6 +86,7 @@ func listStorageAccounts(ctx context.Context, client client.AzureClient, panicCh for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-storage-containers.go b/cmd/list-storage-containers.go index 08b04d1..0d2cc59 100644 --- a/cmd/list-storage-containers.go +++ b/cmd/list-storage-containers.go @@ -51,15 +51,17 @@ func listStorageContainersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure storage containers...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - storageAccounts := listStorageAccounts(ctx, azClient, subscriptions) - stream := listStorageContainers(ctx, azClient, storageAccounts) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + storageAccounts := listStorageAccounts(ctx, azClient, panicChan, subscriptions) + stream := listStorageContainers(ctx, azClient, panicChan, storageAccounts) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listStorageContainers(ctx context.Context, client client.AzureClient, storageAccounts <-chan interface{}) <-chan interface{} { +func listStorageContainers(ctx context.Context, client client.AzureClient, panicChan chan error, storageAccounts <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan interface{}) @@ -73,6 +75,7 @@ func listStorageContainers(ctx context.Context, client client.AzureClient, stora ) go func() { + defer panicRecovery(panicChan) defer close(ids) for result := range pipeline.OrDone(ctx.Done(), storageAccounts) { if storageAccount, ok := result.(AzureWrapper).Data.(models.StorageAccount); !ok { @@ -90,6 +93,7 @@ func listStorageContainers(ctx context.Context, client client.AzureClient, stora for i := range streams { stream := streams[i] go func() { + defer panicRecovery(panicChan) defer wg.Done() for stAccount := range stream { count := 0 diff --git a/cmd/list-virtual-machine-admin-logins.go b/cmd/list-virtual-machine-admin-logins.go index 7223317..49e0cb2 100644 --- a/cmd/list-virtual-machine-admin-logins.go +++ b/cmd/list-virtual-machine-admin-logins.go @@ -50,9 +50,11 @@ func listVirtualMachineAdminLoginsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machine admin logins...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - vms := listVirtualMachines(ctx, azClient, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) + handleBubbledPanic(ctx, panicChan, stop) stream := listVirtualMachineAdminLogins(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-vmcontributors.go b/cmd/list-virtual-machine-vmcontributors.go index fda2b38..f3b0e5f 100644 --- a/cmd/list-virtual-machine-vmcontributors.go +++ b/cmd/list-virtual-machine-vmcontributors.go @@ -50,9 +50,11 @@ func listVirtualMachineVMContributorsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure virtual machine vmcontributors...") start := time.Now() - subscriptions := listSubscriptions(ctx, azClient) - vms := listVirtualMachines(ctx, azClient, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicChan := panicChan() + subscriptions := listSubscriptions(ctx, azClient, panicChan) + vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) + handleBubbledPanic(ctx, panicChan, stop) stream := listVirtualMachineVMContributors(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) From c0810747a889afbe38d8e322da1b69033b07c60b Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Mon, 18 Mar 2024 11:16:36 -0700 Subject: [PATCH 15/26] chore: add comments per util --- cmd/utils.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/utils.go b/cmd/utils.go index 9356407..c172ade 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -86,12 +86,14 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { } } +// panicChan creates an error channel to be used for communicating errors between goroutines. func panicChan() chan error { var panicChan = make(chan error) return panicChan } +// handleBubbledPanic receives errors from panicChan, then it will print them and stop() context. func handleBubbledPanic(ctx context.Context, panicChan chan error, stop context.CancelFunc) { go func() { defer close(panicChan) @@ -108,7 +110,7 @@ func handleBubbledPanic(ctx context.Context, panicChan chan error, stop context. }() } -// panicRecovery recovers from and sends that to panicChan +// panicRecovery recovers from panics and sends them to panicChan func panicRecovery(panicChan chan error) { if recovery := recover(); recovery != nil { panicChan <- fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()) From 79c0e8afa0dd1b628c51a8a078811504354f3b5d Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Mon, 18 Mar 2024 16:03:17 -0700 Subject: [PATCH 16/26] fix: handle loops of go routines --- cmd/list-root.go | 6 ++---- cmd/start.go | 3 ++- cmd/utils.go | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cmd/list-root.go b/cmd/list-root.go index 1cf76ee..c28856f 100644 --- a/cmd/list-root.go +++ b/cmd/list-root.go @@ -55,18 +55,16 @@ func listCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure objects...") start := time.Now() - stream := listAll(ctx, azClient) + stream := listAll(ctx, azClient, panicChan()) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAll(ctx context.Context, client client.AzureClient) <-chan interface{} { +func listAll(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { ctx, stop := context.WithCancel(ctx) var ( - panicChan = panicChan() - azureAD = listAllAD(ctx, client, panicChan) azureRM = listAllRM(ctx, client, panicChan) ) diff --git a/cmd/start.go b/cmd/start.go index 064fce3..e7852a6 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -96,6 +96,7 @@ func start(ctx context.Context) { log.Info("connected successfully! waiting for jobs...") ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() + panicChan := panicChan() var ( jobQueued sync.Mutex @@ -150,7 +151,7 @@ func start(ctx context.Context) { start := time.Now() // Batch data out for ingestion - stream := listAll(ctx, azClient) + stream := listAll(ctx, azClient, panicChan) batches := pipeline.Batch(ctx.Done(), stream, 256, 10*time.Second) hasIngestErr := ingest(ctx, *bheInstance, bheClient, batches) diff --git a/cmd/utils.go b/cmd/utils.go index c172ade..9867489 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -96,7 +96,6 @@ func panicChan() chan error { // handleBubbledPanic receives errors from panicChan, then it will print them and stop() context. func handleBubbledPanic(ctx context.Context, panicChan chan error, stop context.CancelFunc) { go func() { - defer close(panicChan) for { select { From 285841e36fc24890d5e91567c4f985c004fa5df7 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Mon, 18 Mar 2024 17:34:13 -0700 Subject: [PATCH 17/26] fix: move handleBubbledPanic and ctx to root --- cmd/list-root.go | 3 --- cmd/start.go | 3 +++ cmd/utils.go | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cmd/list-root.go b/cmd/list-root.go index c28856f..0686c01 100644 --- a/cmd/list-root.go +++ b/cmd/list-root.go @@ -62,14 +62,11 @@ func listCmdImpl(cmd *cobra.Command, args []string) { } func listAll(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { - ctx, stop := context.WithCancel(ctx) var ( azureAD = listAllAD(ctx, client, panicChan) azureRM = listAllRM(ctx, client, panicChan) ) - handleBubbledPanic(ctx, panicChan, stop) - return pipeline.Mux(ctx.Done(), azureAD, azureRM) } diff --git a/cmd/start.go b/cmd/start.go index e7852a6..685bcc9 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -150,6 +150,9 @@ func start(ctx context.Context) { start := time.Now() + ctx, stop := context.WithCancel(ctx) + handleBubbledPanic(ctx, panicChan, stop) + // Batch data out for ingestion stream := listAll(ctx, azClient, panicChan) batches := pipeline.Batch(ctx.Done(), stream, 256, 10*time.Second) diff --git a/cmd/utils.go b/cmd/utils.go index 9867489..2781903 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -96,7 +96,6 @@ func panicChan() chan error { // handleBubbledPanic receives errors from panicChan, then it will print them and stop() context. func handleBubbledPanic(ctx context.Context, panicChan chan error, stop context.CancelFunc) { go func() { - for { select { case err := <-panicChan: From 96518b3f0a1eef9f3da5e4cd6258fd41ee7ad479 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Tue, 19 Mar 2024 10:24:33 -0700 Subject: [PATCH 18/26] fix: add panicChan to tests --- cmd/list-app-owners_test.go | 2 +- cmd/list-apps_test.go | 2 +- cmd/list-device-owners_test.go | 2 +- cmd/list-devices_test.go | 2 +- cmd/list-group-members_test.go | 2 +- cmd/list-group-owners_test.go | 2 +- cmd/list-groups_test.go | 2 +- cmd/list-key-vault-access-policies_test.go | 2 +- cmd/list-key-vault-role-assignments_test.go | 2 +- cmd/list-key-vaults_test.go | 2 +- cmd/list-management-group-descendants_test.go | 2 +- cmd/list-management-group-role-assignments_test.go | 2 +- cmd/list-management-groups_test.go | 2 +- cmd/list-resource-group-role-assignments_test.go | 2 +- cmd/list-resource-groups_test.go | 2 +- cmd/list-roles_test.go | 2 +- cmd/list-service-principal-owners_test.go | 2 +- cmd/list-service-principals_test.go | 2 +- cmd/list-subscription-owners_test.go | 2 +- cmd/list-subscription-role-assignments_test.go | 2 +- cmd/list-subscription-user-access-admins_test.go | 2 +- cmd/list-subscriptions_test.go | 2 +- cmd/list-tenants_test.go | 2 +- cmd/list-users_test.go | 2 +- cmd/list-virtual-machine-role-assignments_test.go | 2 +- cmd/list-virtual-machines_test.go | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cmd/list-app-owners_test.go b/cmd/list-app-owners_test.go index 666d8f1..f4265b1 100644 --- a/cmd/list-app-owners_test.go +++ b/cmd/list-app-owners_test.go @@ -50,7 +50,7 @@ func TestListAppOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel).Times(1) mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel2).Times(1) - channel := listAppOwners(ctx, mockClient, mockAppsChannel) + channel := listAppOwners(ctx, mockClient, panicChan(), mockAppsChannel) go func() { defer close(mockAppsChannel) diff --git a/cmd/list-apps_test.go b/cmd/list-apps_test.go index 136656a..c95970d 100644 --- a/cmd/list-apps_test.go +++ b/cmd/list-apps_test.go @@ -56,7 +56,7 @@ func TestListApps(t *testing.T) { } }() - channel := listApps(ctx, mockClient) + channel := listApps(ctx, mockClient, panicChan()) <-channel if _, ok := <-channel; ok { t.Error("expected channel to close from an error result but it did not") diff --git a/cmd/list-device-owners_test.go b/cmd/list-device-owners_test.go index 5f0dc3e..6894f13 100644 --- a/cmd/list-device-owners_test.go +++ b/cmd/list-device-owners_test.go @@ -49,7 +49,7 @@ func TestListDeviceOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureDeviceRegisteredOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockDeviceOwnerChannel).Times(1) mockClient.EXPECT().ListAzureDeviceRegisteredOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockDeviceOwnerChannel2).Times(1) - channel := listDeviceOwners(ctx, mockClient, mockDevicesChannel) + channel := listDeviceOwners(ctx, mockClient, panicChan(), mockDevicesChannel) go func() { defer close(mockDevicesChannel) diff --git a/cmd/list-devices_test.go b/cmd/list-devices_test.go index 1bbf4bf..1e62816 100644 --- a/cmd/list-devices_test.go +++ b/cmd/list-devices_test.go @@ -56,7 +56,7 @@ func TestListDevices(t *testing.T) { } }() - channel := listDevices(ctx, mockClient) + channel := listDevices(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-group-members_test.go b/cmd/list-group-members_test.go index f3cf088..bd3c7ce 100644 --- a/cmd/list-group-members_test.go +++ b/cmd/list-group-members_test.go @@ -49,7 +49,7 @@ func TestListGroupMembers(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel).Times(1) mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel2).Times(1) - channel := listGroupMembers(ctx, mockClient, mockGroupsChannel) + channel := listGroupMembers(ctx, mockClient, panicChan(), mockGroupsChannel) go func() { defer close(mockGroupsChannel) diff --git a/cmd/list-group-owners_test.go b/cmd/list-group-owners_test.go index b1e7eea..da41727 100644 --- a/cmd/list-group-owners_test.go +++ b/cmd/list-group-owners_test.go @@ -49,7 +49,7 @@ func TestListGroupOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel).Times(1) mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel2).Times(1) - channel := listGroupOwners(ctx, mockClient, mockGroupsChannel) + channel := listGroupOwners(ctx, mockClient, panicChan(), mockGroupsChannel) go func() { defer close(mockGroupsChannel) diff --git a/cmd/list-groups_test.go b/cmd/list-groups_test.go index d931ff2..244452c 100644 --- a/cmd/list-groups_test.go +++ b/cmd/list-groups_test.go @@ -57,7 +57,7 @@ func TestListGroups(t *testing.T) { } }() - channel := listGroups(ctx, mockClient) + channel := listGroups(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-key-vault-access-policies_test.go b/cmd/list-key-vault-access-policies_test.go index 877fe1f..b14eb52 100644 --- a/cmd/list-key-vault-access-policies_test.go +++ b/cmd/list-key-vault-access-policies_test.go @@ -41,7 +41,7 @@ func TestListKeyVaultAccessPolicies(t *testing.T) { mockKeyVaultsChannel := make(chan interface{}) mockTenant := azure.Tenant{} mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() - channel := listKeyVaultAccessPolicies(ctx, mockClient, mockKeyVaultsChannel, nil) + channel := listKeyVaultAccessPolicies(ctx, mockClient, panicChan(), mockKeyVaultsChannel, nil) go func() { defer close(mockKeyVaultsChannel) diff --git a/cmd/list-key-vault-role-assignments_test.go b/cmd/list-key-vault-role-assignments_test.go index db7e4c3..292109f 100644 --- a/cmd/list-key-vault-role-assignments_test.go +++ b/cmd/list-key-vault-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListKeyVaultRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel2).Times(1) - channel := listKeyVaultRoleAssignments(ctx, mockClient, mockKeyVaultsChannel) + channel := listKeyVaultRoleAssignments(ctx, mockClient, panicChan(), mockKeyVaultsChannel) go func() { defer close(mockKeyVaultsChannel) diff --git a/cmd/list-key-vaults_test.go b/cmd/list-key-vaults_test.go index 269288a..d7c9877 100644 --- a/cmd/list-key-vaults_test.go +++ b/cmd/list-key-vaults_test.go @@ -48,7 +48,7 @@ func TestListKeyVaults(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureKeyVaults(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultChannel).Times(1) mockClient.EXPECT().ListAzureKeyVaults(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultChannel2).Times(1) - channel := listKeyVaults(ctx, mockClient, mockSubscriptionsChannel) + channel := listKeyVaults(ctx, mockClient, panicChan(), mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) diff --git a/cmd/list-management-group-descendants_test.go b/cmd/list-management-group-descendants_test.go index 01806b1..c4cd6a7 100644 --- a/cmd/list-management-group-descendants_test.go +++ b/cmd/list-management-group-descendants_test.go @@ -48,7 +48,7 @@ func TestListManagementGroupDescendants(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel).Times(1) mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel2).Times(1) - channel := listManagementGroupDescendants(ctx, mockClient, mockManagementGroupsChannel) + channel := listManagementGroupDescendants(ctx, mockClient, panicChan(), mockManagementGroupsChannel) go func() { defer close(mockManagementGroupsChannel) diff --git a/cmd/list-management-group-role-assignments_test.go b/cmd/list-management-group-role-assignments_test.go index eed6954..040ab6a 100644 --- a/cmd/list-management-group-role-assignments_test.go +++ b/cmd/list-management-group-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListResourceGroupRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel2).Times(1) - channel := listResourceGroupRoleAssignments(ctx, mockClient, mockResourceGroupsChannel) + channel := listResourceGroupRoleAssignments(ctx, mockClient, panicChan(), mockResourceGroupsChannel) go func() { defer close(mockResourceGroupsChannel) diff --git a/cmd/list-management-groups_test.go b/cmd/list-management-groups_test.go index 47efe17..3eba355 100644 --- a/cmd/list-management-groups_test.go +++ b/cmd/list-management-groups_test.go @@ -56,7 +56,7 @@ func TestListManagementGroups(t *testing.T) { } }() - channel := listManagementGroups(ctx, mockClient) + channel := listManagementGroups(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-resource-group-role-assignments_test.go b/cmd/list-resource-group-role-assignments_test.go index 5c8c8bb..cc5e204 100644 --- a/cmd/list-resource-group-role-assignments_test.go +++ b/cmd/list-resource-group-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListManagementGroupRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel2).Times(1) - channel := listManagementGroupRoleAssignments(ctx, mockClient, mockManagementGroupsChannel) + channel := listManagementGroupRoleAssignments(ctx, mockClient, panicChan(), mockManagementGroupsChannel) go func() { defer close(mockManagementGroupsChannel) diff --git a/cmd/list-resource-groups_test.go b/cmd/list-resource-groups_test.go index 78ac328..da3a307 100644 --- a/cmd/list-resource-groups_test.go +++ b/cmd/list-resource-groups_test.go @@ -48,7 +48,7 @@ func TestListResourceGroups(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureResourceGroups(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupChannel).Times(1) mockClient.EXPECT().ListAzureResourceGroups(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupChannel2).Times(1) - channel := listResourceGroups(ctx, mockClient, mockSubscriptionsChannel) + channel := listResourceGroups(ctx, mockClient, panicChan(), mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) diff --git a/cmd/list-roles_test.go b/cmd/list-roles_test.go index 0805f0a..469d231 100644 --- a/cmd/list-roles_test.go +++ b/cmd/list-roles_test.go @@ -56,7 +56,7 @@ func TestListRoles(t *testing.T) { } }() - channel := listRoles(ctx, mockClient) + channel := listRoles(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-service-principal-owners_test.go b/cmd/list-service-principal-owners_test.go index 1dff1d1..926a64c 100644 --- a/cmd/list-service-principal-owners_test.go +++ b/cmd/list-service-principal-owners_test.go @@ -49,7 +49,7 @@ func TestListServicePrincipalOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel).Times(1) mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel2).Times(1) - channel := listServicePrincipalOwners(ctx, mockClient, mockServicePrincipalsChannel) + channel := listServicePrincipalOwners(ctx, mockClient, panicChan(), mockServicePrincipalsChannel) go func() { defer close(mockServicePrincipalsChannel) diff --git a/cmd/list-service-principals_test.go b/cmd/list-service-principals_test.go index c62f028..db66e89 100644 --- a/cmd/list-service-principals_test.go +++ b/cmd/list-service-principals_test.go @@ -56,7 +56,7 @@ func TestListServicePrincipals(t *testing.T) { } }() - channel := listServicePrincipals(ctx, mockClient) + channel := listServicePrincipals(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-subscription-owners_test.go b/cmd/list-subscription-owners_test.go index 7850fef..d1642b4 100644 --- a/cmd/list-subscription-owners_test.go +++ b/cmd/list-subscription-owners_test.go @@ -42,7 +42,7 @@ func TestListSubscriptionOwners(t *testing.T) { mockRoleAssignmentsChannel := make(chan interface{}) mockTenant := azure.Tenant{} mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() - channel := listSubscriptionOwners(ctx, mockClient, mockRoleAssignmentsChannel) + channel := listSubscriptionOwners(ctx, mockClient, panicChan(), mockRoleAssignmentsChannel) go func() { defer close(mockRoleAssignmentsChannel) diff --git a/cmd/list-subscription-role-assignments_test.go b/cmd/list-subscription-role-assignments_test.go index 1902684..3d1db82 100644 --- a/cmd/list-subscription-role-assignments_test.go +++ b/cmd/list-subscription-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListSubscriptionRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel2).Times(1) - channel := listSubscriptionRoleAssignments(ctx, mockClient, mockSubscriptionsChannel) + channel := listSubscriptionRoleAssignments(ctx, mockClient, panicChan(), mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) diff --git a/cmd/list-subscription-user-access-admins_test.go b/cmd/list-subscription-user-access-admins_test.go index 1a6a8dc..34a956a 100644 --- a/cmd/list-subscription-user-access-admins_test.go +++ b/cmd/list-subscription-user-access-admins_test.go @@ -42,7 +42,7 @@ func TestListSubscriptionUserAccessAdmins(t *testing.T) { mockRoleAssignmentsChannel := make(chan interface{}) mockTenant := azure.Tenant{} mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() - channel := listSubscriptionUserAccessAdmins(ctx, mockClient, mockRoleAssignmentsChannel) + channel := listSubscriptionUserAccessAdmins(ctx, mockClient, panicChan(), mockRoleAssignmentsChannel) go func() { defer close(mockRoleAssignmentsChannel) diff --git a/cmd/list-subscriptions_test.go b/cmd/list-subscriptions_test.go index 51571c5..535e900 100644 --- a/cmd/list-subscriptions_test.go +++ b/cmd/list-subscriptions_test.go @@ -56,7 +56,7 @@ func TestListSubscriptions(t *testing.T) { } }() - channel := listSubscriptions(ctx, mockClient) + channel := listSubscriptions(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-tenants_test.go b/cmd/list-tenants_test.go index 5f22399..003eb32 100644 --- a/cmd/list-tenants_test.go +++ b/cmd/list-tenants_test.go @@ -56,7 +56,7 @@ func TestListTenants(t *testing.T) { } }() - channel := listTenants(ctx, mockClient) + channel := listTenants(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-users_test.go b/cmd/list-users_test.go index d7e6211..a4693c5 100644 --- a/cmd/list-users_test.go +++ b/cmd/list-users_test.go @@ -57,7 +57,7 @@ func TestListUsers(t *testing.T) { } }() - channel := listUsers(ctx, mockClient) + channel := listUsers(ctx, mockClient, panicChan()) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-virtual-machine-role-assignments_test.go b/cmd/list-virtual-machine-role-assignments_test.go index dffaf79..db4187e 100644 --- a/cmd/list-virtual-machine-role-assignments_test.go +++ b/cmd/list-virtual-machine-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListVirtualMachineRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel2).Times(1) - channel := listVirtualMachineRoleAssignments(ctx, mockClient, mockVirtualMachinesChannel) + channel := listVirtualMachineRoleAssignments(ctx, mockClient, panicChan(), mockVirtualMachinesChannel) go func() { defer close(mockVirtualMachinesChannel) diff --git a/cmd/list-virtual-machines_test.go b/cmd/list-virtual-machines_test.go index 58b9113..98dd14b 100644 --- a/cmd/list-virtual-machines_test.go +++ b/cmd/list-virtual-machines_test.go @@ -48,7 +48,7 @@ func TestListVirtualMachines(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureVirtualMachines(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineChannel).Times(1) mockClient.EXPECT().ListAzureVirtualMachines(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineChannel2).Times(1) - channel := listVirtualMachines(ctx, mockClient, mockSubscriptionsChannel) + channel := listVirtualMachines(ctx, mockClient, panicChan(), mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) From 02f40d4ee1d2de1ed77a660d74482e45823a5d8e Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Tue, 19 Mar 2024 11:41:42 -0700 Subject: [PATCH 19/26] chore: CmdImpl only open panicChan if its going to get used --- cmd/list-container-registries.go | 5 +++-- cmd/list-logic-apps.go | 5 +++-- cmd/list-managed-clusters.go | 4 ++-- cmd/list-vm-scale-sets.go | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cmd/list-container-registries.go b/cmd/list-container-registries.go index 5556ba6..695a7a6 100644 --- a/cmd/list-container-registries.go +++ b/cmd/list-container-registries.go @@ -45,7 +45,7 @@ var listContainerRegistriesCmd = &cobra.Command{ func listContainerRegistriesCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) - panicChan := panicChan() + defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -56,13 +56,14 @@ func listContainerRegistriesCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure container registries...") start := time.Now() + panicChan := panicChan() stream := listContainerRegistries(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - handleBubbledPanic(ctx, panicChan, stop) } func listContainerRegistries(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { diff --git a/cmd/list-logic-apps.go b/cmd/list-logic-apps.go index e2a68ac..9c87868 100644 --- a/cmd/list-logic-apps.go +++ b/cmd/list-logic-apps.go @@ -45,7 +45,7 @@ var listLogicAppsCmd = &cobra.Command{ func listLogicAppsCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) - panicChan := panicChan() + defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -56,13 +56,14 @@ func listLogicAppsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure logic apps...") start := time.Now() + panicChan := panicChan() stream := listLogicApps(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - handleBubbledPanic(ctx, panicChan, stop) } func listLogicApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { diff --git a/cmd/list-managed-clusters.go b/cmd/list-managed-clusters.go index 6100f4b..4da93f0 100644 --- a/cmd/list-managed-clusters.go +++ b/cmd/list-managed-clusters.go @@ -45,7 +45,6 @@ var listManagedClustersCmd = &cobra.Command{ func listManagedClustersCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) - panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -56,13 +55,14 @@ func listManagedClustersCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure managed clusters...") start := time.Now() + panicChan := panicChan() stream := listManagedClusters(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - handleBubbledPanic(ctx, panicChan, stop) } func listManagedClusters(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { diff --git a/cmd/list-vm-scale-sets.go b/cmd/list-vm-scale-sets.go index a81d648..7f9feaf 100644 --- a/cmd/list-vm-scale-sets.go +++ b/cmd/list-vm-scale-sets.go @@ -45,7 +45,6 @@ var listVMScaleSetsCmd = &cobra.Command{ func listVMScaleSetsCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) - panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -56,13 +55,14 @@ func listVMScaleSetsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure virtual machine scale sets...") start := time.Now() + panicChan := panicChan() stream := listVMScaleSets(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - handleBubbledPanic(ctx, panicChan, stop) } func listVMScaleSets(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { From 8151b0b4967aec50bb3d946a8494d965602f1f02 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Tue, 19 Mar 2024 13:08:26 -0700 Subject: [PATCH 20/26] fix: white-space formatting --- cmd/list-app-owners.go | 1 + cmd/list-container-registries.go | 2 -- cmd/list-logic-apps.go | 2 -- cmd/list-managed-clusters.go | 1 - cmd/list-root.go | 2 -- 5 files changed, 1 insertion(+), 7 deletions(-) diff --git a/cmd/list-app-owners.go b/cmd/list-app-owners.go index 309b855..c21a0ba 100644 --- a/cmd/list-app-owners.go +++ b/cmd/list-app-owners.go @@ -52,6 +52,7 @@ func listAppOwnersCmdImpl(cmd *cobra.Command, args []string) { log.Info("collecting azure app owners...") start := time.Now() stream := listAppOwners(ctx, azClient, panicChan, listApps(ctx, azClient, panicChan)) + handleBubbledPanic(ctx, panicChan, stop) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) diff --git a/cmd/list-container-registries.go b/cmd/list-container-registries.go index 695a7a6..977e718 100644 --- a/cmd/list-container-registries.go +++ b/cmd/list-container-registries.go @@ -45,7 +45,6 @@ var listContainerRegistriesCmd = &cobra.Command{ func listContainerRegistriesCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) - defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -63,7 +62,6 @@ func listContainerRegistriesCmdImpl(cmd *cobra.Command, args []string) { duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - } func listContainerRegistries(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { diff --git a/cmd/list-logic-apps.go b/cmd/list-logic-apps.go index 9c87868..6631cc5 100644 --- a/cmd/list-logic-apps.go +++ b/cmd/list-logic-apps.go @@ -45,7 +45,6 @@ var listLogicAppsCmd = &cobra.Command{ func listLogicAppsCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) - defer gracefulShutdown(stop) log.V(1).Info("testing connections") @@ -63,7 +62,6 @@ func listLogicAppsCmdImpl(cmd *cobra.Command, args []string) { duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - } func listLogicApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { diff --git a/cmd/list-managed-clusters.go b/cmd/list-managed-clusters.go index 4da93f0..4e2ec1e 100644 --- a/cmd/list-managed-clusters.go +++ b/cmd/list-managed-clusters.go @@ -62,7 +62,6 @@ func listManagedClustersCmdImpl(cmd *cobra.Command, args []string) { duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - } func listManagedClusters(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { diff --git a/cmd/list-root.go b/cmd/list-root.go index 0686c01..e143c74 100644 --- a/cmd/list-root.go +++ b/cmd/list-root.go @@ -62,11 +62,9 @@ func listCmdImpl(cmd *cobra.Command, args []string) { } func listAll(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { - var ( azureAD = listAllAD(ctx, client, panicChan) azureRM = listAllRM(ctx, client, panicChan) ) - return pipeline.Mux(ctx.Done(), azureAD, azureRM) } From b23eee567319e687f5226dbf308cca26b31181d6 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Wed, 20 Mar 2024 11:08:18 -0700 Subject: [PATCH 21/26] fix: panic recovery from top level goroutine --- cmd/start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/start.go b/cmd/start.go index 685bcc9..e05a1f6 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -113,6 +113,7 @@ func start(ctx context.Context) { } } else if jobQueued.TryLock() { go func() { + defer panicRecovery(panicChan) defer jobQueued.Unlock() defer bheClient.CloseIdleConnections() defer azClient.CloseIdleConnections() @@ -121,7 +122,6 @@ func start(ctx context.Context) { if jobs, err := getAvailableJobs(ctx, *bheInstance, bheClient); err != nil { log.Error(err, "unable to fetch available jobs for azurehound") } else { - // Get only the jobs that have reached their execution time executableJobs := []models.ClientJob{} now := time.Now() From c7bebc7a403acb15d40a5a91bc986edaa04feb1c Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Wed, 20 Mar 2024 13:47:03 -0700 Subject: [PATCH 22/26] feature: use panicrecovery package between channels --- cmd/list-app-owners.go | 10 +-- cmd/list-app-owners_test.go | 2 +- cmd/list-app-role-assignments.go | 14 ++-- cmd/list-apps.go | 10 +-- cmd/list-apps_test.go | 2 +- ...ist-automation-account-role-assignments.go | 14 ++-- cmd/list-automation-accounts.go | 12 ++-- cmd/list-azure-ad.go | 36 +++++------ cmd/list-azure-rm.go | 64 +++++++++---------- cmd/list-container-registries.go | 12 ++-- ...ist-container-registry-role-assignments.go | 14 ++-- cmd/list-device-owners.go | 12 ++-- cmd/list-device-owners_test.go | 2 +- cmd/list-devices.go | 10 +-- cmd/list-devices_test.go | 2 +- cmd/list-function-app-role-assignments.go | 14 ++-- cmd/list-function-apps.go | 12 ++-- cmd/list-group-members.go | 10 +-- cmd/list-group-members_test.go | 2 +- cmd/list-group-owners.go | 10 +-- cmd/list-group-owners_test.go | 2 +- cmd/list-groups.go | 10 +-- cmd/list-groups_test.go | 2 +- cmd/list-key-vault-access-policies.go | 12 ++-- cmd/list-key-vault-access-policies_test.go | 2 +- cmd/list-key-vault-contributors.go | 10 +-- cmd/list-key-vault-kvcontributors.go | 10 +-- cmd/list-key-vault-owners.go | 10 +-- cmd/list-key-vault-role-assignments.go | 14 ++-- cmd/list-key-vault-role-assignments_test.go | 2 +- cmd/list-key-vault-user-access-admins.go | 10 +-- cmd/list-key-vaults.go | 12 ++-- cmd/list-key-vaults_test.go | 2 +- cmd/list-logic-app-role-assignments.go | 14 ++-- cmd/list-logic-apps.go | 12 ++-- cmd/list-managed-cluster-role-assignments.go | 14 ++-- cmd/list-managed-clusters.go | 12 ++-- cmd/list-management-group-descendants.go | 12 ++-- cmd/list-management-group-descendants_test.go | 2 +- cmd/list-management-group-owners.go | 8 +-- cmd/list-management-group-role-assignments.go | 14 ++-- ...-management-group-role-assignments_test.go | 2 +- ...ist-management-group-user-access-admins.go | 8 +-- cmd/list-management-groups.go | 11 ++-- cmd/list-management-groups_test.go | 2 +- cmd/list-resource-group-owners.go | 10 +-- cmd/list-resource-group-role-assignments.go | 16 ++--- ...st-resource-group-role-assignments_test.go | 2 +- cmd/list-resource-group-user-access-admins.go | 10 +-- cmd/list-resource-groups.go | 12 ++-- cmd/list-resource-groups_test.go | 2 +- cmd/list-role-assignments.go | 14 ++-- cmd/list-roles.go | 10 +-- cmd/list-roles_test.go | 2 +- cmd/list-root.go | 8 +-- cmd/list-service-principal-owners.go | 12 ++-- cmd/list-service-principal-owners_test.go | 2 +- cmd/list-service-principals.go | 10 +-- cmd/list-service-principals_test.go | 2 +- cmd/list-storage-account-role-assignments.go | 14 ++-- cmd/list-storage-accounts.go | 12 ++-- cmd/list-storage-containers.go | 16 ++--- cmd/list-subscription-owners.go | 14 ++-- cmd/list-subscription-owners_test.go | 2 +- cmd/list-subscription-role-assignments.go | 14 ++-- ...list-subscription-role-assignments_test.go | 2 +- cmd/list-subscription-user-access-admins.go | 14 ++-- ...st-subscription-user-access-admins_test.go | 2 +- cmd/list-subscriptions.go | 12 ++-- cmd/list-subscriptions_test.go | 2 +- cmd/list-tenants.go | 10 +-- cmd/list-tenants_test.go | 2 +- cmd/list-users.go | 10 +-- cmd/list-users_test.go | 2 +- cmd/list-virtual-machine-admin-logins.go | 10 +-- ...list-virtual-machine-avere-contributors.go | 10 +-- cmd/list-virtual-machine-contributors.go | 10 +-- cmd/list-virtual-machine-owners.go | 10 +-- cmd/list-virtual-machine-role-assignments.go | 14 ++-- ...t-virtual-machine-role-assignments_test.go | 2 +- ...list-virtual-machine-user-access-admins.go | 10 +-- cmd/list-virtual-machine-vmcontributors.go | 10 +-- cmd/list-virtual-machines.go | 12 ++-- cmd/list-virtual-machines_test.go | 2 +- cmd/list-vm-scale-set-role-assignments.go | 14 ++-- cmd/list-vm-scale-sets.go | 12 ++-- cmd/list-web-app-role-assignments.go | 14 ++-- cmd/list-web-apps.go | 12 ++-- cmd/start.go | 8 +-- cmd/utils.go | 30 --------- panicrecovery/panic_recovery.go | 34 ++++++++++ 91 files changed, 466 insertions(+), 461 deletions(-) create mode 100644 panicrecovery/panic_recovery.go diff --git a/cmd/list-app-owners.go b/cmd/list-app-owners.go index c21a0ba..5fe7336 100644 --- a/cmd/list-app-owners.go +++ b/cmd/list-app-owners.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -44,21 +45,20 @@ var listAppOwnersCmd = &cobra.Command{ func listAppOwnersCmdImpl(cmd *cobra.Command, args []string) { ctx, stop := signal.NotifyContext(cmd.Context(), os.Interrupt, os.Kill) - panicChan := panicChan() defer gracefulShutdown(stop) log.V(1).Info("testing connections") azClient := connectAndCreateClient() log.Info("collecting azure app owners...") start := time.Now() - stream := listAppOwners(ctx, azClient, panicChan, listApps(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listAppOwners(ctx, azClient, listApps(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAppOwners(ctx context.Context, client client.AzureClient, panicChan chan error, apps <-chan azureWrapper[models.App]) <-chan azureWrapper[models.AppOwners] { +func listAppOwners(ctx context.Context, client client.AzureClient, apps <-chan azureWrapper[models.App]) <-chan azureWrapper[models.AppOwners] { var ( out = make(chan azureWrapper[models.AppOwners]) streams = pipeline.Demux(ctx.Done(), apps, 25) @@ -69,7 +69,7 @@ func listAppOwners(ctx context.Context, client client.AzureClient, panicChan cha for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for app := range stream { var ( diff --git a/cmd/list-app-owners_test.go b/cmd/list-app-owners_test.go index f4265b1..666d8f1 100644 --- a/cmd/list-app-owners_test.go +++ b/cmd/list-app-owners_test.go @@ -50,7 +50,7 @@ func TestListAppOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel).Times(1) mockClient.EXPECT().ListAzureADAppOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockAppOwnerChannel2).Times(1) - channel := listAppOwners(ctx, mockClient, panicChan(), mockAppsChannel) + channel := listAppOwners(ctx, mockClient, mockAppsChannel) go func() { defer close(mockAppsChannel) diff --git a/cmd/list-app-role-assignments.go b/cmd/list-app-role-assignments.go index 2f96c53..9e3aa4b 100644 --- a/cmd/list-app-role-assignments.go +++ b/cmd/list-app-role-assignments.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,16 +52,15 @@ func listAppRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory app role assignments...") start := time.Now() - panicChan := panicChan() - servicePrincipals := listServicePrincipals(ctx, azClient, panicChan) - stream := listAppRoleAssignments(ctx, azClient, panicChan, servicePrincipals) - handleBubbledPanic(ctx, panicChan, stop) + servicePrincipals := listServicePrincipals(ctx, azClient) + stream := listAppRoleAssignments(ctx, azClient, servicePrincipals) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, servicePrincipals <-chan interface{}) <-chan interface{} { +func listAppRoleAssignments(ctx context.Context, client client.AzureClient, servicePrincipals <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) filteredSPs = make(chan models.ServicePrincipal) @@ -69,7 +69,7 @@ func listAppRoleAssignments(ctx context.Context, client client.AzureClient, pani ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(filteredSPs) for result := range pipeline.OrDone(ctx.Done(), servicePrincipals) { @@ -90,7 +90,7 @@ func listAppRoleAssignments(ctx context.Context, client client.AzureClient, pani for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for servicePrincipal := range stream { var ( diff --git a/cmd/list-apps.go b/cmd/list-apps.go index ecc1a6c..8160eb6 100644 --- a/cmd/list-apps.go +++ b/cmd/list-apps.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -49,19 +50,18 @@ func listAppsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory applications...") start := time.Now() - panicChan := panicChan() - stream := listApps(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listApps(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listApps(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan azureWrapper[models.App] { +func listApps(ctx context.Context, client client.AzureClient) <-chan azureWrapper[models.App] { out := make(chan azureWrapper[models.App]) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) count := 0 for item := range client.ListAzureADApps(ctx, "", "", "", "", nil) { diff --git a/cmd/list-apps_test.go b/cmd/list-apps_test.go index c95970d..136656a 100644 --- a/cmd/list-apps_test.go +++ b/cmd/list-apps_test.go @@ -56,7 +56,7 @@ func TestListApps(t *testing.T) { } }() - channel := listApps(ctx, mockClient, panicChan()) + channel := listApps(ctx, mockClient) <-channel if _, ok := <-channel; ok { t.Error("expected channel to close from an error result but it did not") diff --git a/cmd/list-automation-account-role-assignments.go b/cmd/list-automation-account-role-assignments.go index a5634da..7b25179 100644 --- a/cmd/list-automation-account-role-assignments.go +++ b/cmd/list-automation-account-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -52,16 +53,15 @@ func listAutomationAccountRoleAssignmentImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure automation account role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listAutomationAccountRoleAssignments(ctx, azClient, panicChan, listAutomationAccounts(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listAutomationAccountRoleAssignments(ctx, azClient, listAutomationAccounts(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAutomationAccountRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, automationAccounts <-chan interface{}) <-chan interface{} { +func listAutomationAccountRoleAssignments(ctx context.Context, client client.AzureClient, automationAccounts <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -70,7 +70,7 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), automationAccounts) { @@ -89,7 +89,7 @@ func listAutomationAccountRoleAssignments(ctx context.Context, client client.Azu for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-automation-accounts.go b/cmd/list-automation-accounts.go index 02d30f1..bd51f48 100644 --- a/cmd/list-automation-accounts.go +++ b/cmd/list-automation-accounts.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listAutomationAccountsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure automation accounts...") start := time.Now() - panicChan := panicChan() - stream := listAutomationAccounts(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listAutomationAccounts(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAutomationAccounts(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listAutomationAccounts(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listAutomationAccounts(ctx context.Context, client client.AzureClient, pani ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -86,7 +86,7 @@ func listAutomationAccounts(ctx context.Context, client client.AzureClient, pani for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-azure-ad.go b/cmd/list-azure-ad.go index 38c6f39..bca217d 100644 --- a/cmd/list-azure-ad.go +++ b/cmd/list-azure-ad.go @@ -25,6 +25,7 @@ import ( "time" "github.com/bloodhoundad/azurehound/v2/client" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -53,15 +54,14 @@ func listAzureADCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure ad objects...") start := time.Now() - panicChan := panicChan() - stream := listAllAD(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listAllAD(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listAllAD(ctx context.Context, client client.AzureClient) <-chan interface{} { var ( devices = make(chan interface{}) devices2 = make(chan interface{}) @@ -81,35 +81,35 @@ func listAllAD(ctx context.Context, client client.AzureClient, panicChan chan er ) // Enumerate Apps, AppOwners and AppMembers - appChans := pipeline.TeeFixed(ctx.Done(), listApps(ctx, client, panicChan), 2) + appChans := pipeline.TeeFixed(ctx.Done(), listApps(ctx, client), 2) apps := pipeline.ToAny(ctx.Done(), appChans[0]) - appOwners := pipeline.ToAny(ctx.Done(), listAppOwners(ctx, client, panicChan, appChans[1])) + appOwners := pipeline.ToAny(ctx.Done(), listAppOwners(ctx, client, appChans[1])) // Enumerate Devices and DeviceOwners - pipeline.Tee(ctx.Done(), listDevices(ctx, client, panicChan), devices, devices2) - deviceOwners := listDeviceOwners(ctx, client, panicChan, devices2) + pipeline.Tee(ctx.Done(), listDevices(ctx, client), devices, devices2) + deviceOwners := listDeviceOwners(ctx, client, devices2) // Enumerate Groups, GroupOwners and GroupMembers - pipeline.Tee(ctx.Done(), listGroups(ctx, client, panicChan), groups, groups2, groups3) - groupOwners := listGroupOwners(ctx, client, panicChan, groups2) - groupMembers := listGroupMembers(ctx, client, panicChan, groups3) + pipeline.Tee(ctx.Done(), listGroups(ctx, client), groups, groups2, groups3) + groupOwners := listGroupOwners(ctx, client, groups2) + groupMembers := listGroupMembers(ctx, client, groups3) // Enumerate ServicePrincipals and ServicePrincipalOwners - pipeline.Tee(ctx.Done(), listServicePrincipals(ctx, client, panicChan), servicePrincipals, servicePrincipals2, servicePrincipals3) - servicePrincipalOwners := listServicePrincipalOwners(ctx, client, panicChan, servicePrincipals2) + pipeline.Tee(ctx.Done(), listServicePrincipals(ctx, client), servicePrincipals, servicePrincipals2, servicePrincipals3) + servicePrincipalOwners := listServicePrincipalOwners(ctx, client, servicePrincipals2) // Enumerate Tenants - pipeline.Tee(ctx.Done(), listTenants(ctx, client, panicChan), tenants) + pipeline.Tee(ctx.Done(), listTenants(ctx, client), tenants) // Enumerate Users - users := listUsers(ctx, client, panicChan) + users := listUsers(ctx, client) // Enumerate Roles and RoleAssignments - pipeline.Tee(ctx.Done(), listRoles(ctx, client, panicChan), roles, roles2) - roleAssignments := listRoleAssignments(ctx, client, panicChan, roles2) + pipeline.Tee(ctx.Done(), listRoles(ctx, client), roles, roles2) + roleAssignments := listRoleAssignments(ctx, client, roles2) // Enumerate AppRoleAssignments - appRoleAssignments := listAppRoleAssignments(ctx, client, panicChan, servicePrincipals3) + appRoleAssignments := listAppRoleAssignments(ctx, client, servicePrincipals3) return pipeline.Mux(ctx.Done(), appOwners, diff --git a/cmd/list-azure-rm.go b/cmd/list-azure-rm.go index 3491486..b377e58 100644 --- a/cmd/list-azure-rm.go +++ b/cmd/list-azure-rm.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -55,15 +56,14 @@ func listAzureRMCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure resource management objects...") start := time.Now() - panicChan := panicChan() - stream := listAllRM(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listAllRM(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listAllRM(ctx context.Context, client client.AzureClient) <-chan interface{} { var ( functionApps = make(chan interface{}) functionApps2 = make(chan interface{}) @@ -130,8 +130,8 @@ func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan er ) // Enumerate entities - pipeline.Tee(ctx.Done(), listManagementGroups(ctx, client, panicChan), mgmtGroups, mgmtGroups2, mgmtGroups3) - pipeline.Tee(ctx.Done(), listSubscriptions(ctx, client, panicChan), + pipeline.Tee(ctx.Done(), listManagementGroups(ctx, client), mgmtGroups, mgmtGroups2, mgmtGroups3) + pipeline.Tee(ctx.Done(), listSubscriptions(ctx, client), subscriptions, subscriptions2, subscriptions3, @@ -145,44 +145,44 @@ func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan er subscriptions11, subscriptions12, ) - pipeline.Tee(ctx.Done(), listResourceGroups(ctx, client, panicChan, subscriptions2), resourceGroups, resourceGroups2) - pipeline.Tee(ctx.Done(), listKeyVaults(ctx, client, panicChan, subscriptions3), keyVaults, keyVaults2, keyVaults3) - pipeline.Tee(ctx.Done(), listVirtualMachines(ctx, client, panicChan, subscriptions4), virtualMachines, virtualMachines2) - pipeline.Tee(ctx.Done(), listFunctionApps(ctx, client, panicChan, subscriptions6), functionApps, functionApps2) - pipeline.Tee(ctx.Done(), listWebApps(ctx, client, panicChan, subscriptions7), webApps, webApps2) - pipeline.Tee(ctx.Done(), listAutomationAccounts(ctx, client, panicChan, subscriptions8), automationAccounts, automationAccounts2) - pipeline.Tee(ctx.Done(), listContainerRegistries(ctx, client, panicChan, subscriptions9), containerRegistries, containerRegistries2) - pipeline.Tee(ctx.Done(), listLogicApps(ctx, client, panicChan, subscriptions10), logicApps, logicApps2) - pipeline.Tee(ctx.Done(), listManagedClusters(ctx, client, panicChan, subscriptions11), managedClusters, managedClusters2) - pipeline.Tee(ctx.Done(), listVMScaleSets(ctx, client, panicChan, subscriptions12), vmScaleSets, vmScaleSets2) + pipeline.Tee(ctx.Done(), listResourceGroups(ctx, client, subscriptions2), resourceGroups, resourceGroups2) + pipeline.Tee(ctx.Done(), listKeyVaults(ctx, client, subscriptions3), keyVaults, keyVaults2, keyVaults3) + pipeline.Tee(ctx.Done(), listVirtualMachines(ctx, client, subscriptions4), virtualMachines, virtualMachines2) + pipeline.Tee(ctx.Done(), listFunctionApps(ctx, client, subscriptions6), functionApps, functionApps2) + pipeline.Tee(ctx.Done(), listWebApps(ctx, client, subscriptions7), webApps, webApps2) + pipeline.Tee(ctx.Done(), listAutomationAccounts(ctx, client, subscriptions8), automationAccounts, automationAccounts2) + pipeline.Tee(ctx.Done(), listContainerRegistries(ctx, client, subscriptions9), containerRegistries, containerRegistries2) + pipeline.Tee(ctx.Done(), listLogicApps(ctx, client, subscriptions10), logicApps, logicApps2) + pipeline.Tee(ctx.Done(), listManagedClusters(ctx, client, subscriptions11), managedClusters, managedClusters2) + pipeline.Tee(ctx.Done(), listVMScaleSets(ctx, client, subscriptions12), vmScaleSets, vmScaleSets2) // Enumerate Relationships // ManagementGroups: Descendants, Owners and UserAccessAdmins - mgmtGroupDescendants := listManagementGroupDescendants(ctx, client, panicChan, mgmtGroups2) - pipeline.Tee(ctx.Done(), listManagementGroupRoleAssignments(ctx, client, panicChan, mgmtGroups3), mgmtGroupRoleAssignments1, mgmtGroupRoleAssignments2) + mgmtGroupDescendants := listManagementGroupDescendants(ctx, client, mgmtGroups2) + pipeline.Tee(ctx.Done(), listManagementGroupRoleAssignments(ctx, client, mgmtGroups3), mgmtGroupRoleAssignments1, mgmtGroupRoleAssignments2) mgmtGroupOwners := listManagementGroupOwners(ctx, mgmtGroupRoleAssignments1) mgmtGroupUserAccessAdmins := listManagementGroupUserAccessAdmins(ctx, mgmtGroupRoleAssignments2) // Subscriptions: Owners and UserAccessAdmins - pipeline.Tee(ctx.Done(), listSubscriptionRoleAssignments(ctx, client, panicChan, subscriptions5), subscriptionRoleAssignments1, subscriptionRoleAssignments2) - subscriptionOwners := listSubscriptionOwners(ctx, client, panicChan, subscriptionRoleAssignments1) - subscriptionUserAccessAdmins := listSubscriptionUserAccessAdmins(ctx, client, panicChan, subscriptionRoleAssignments2) + pipeline.Tee(ctx.Done(), listSubscriptionRoleAssignments(ctx, client, subscriptions5), subscriptionRoleAssignments1, subscriptionRoleAssignments2) + subscriptionOwners := listSubscriptionOwners(ctx, client, subscriptionRoleAssignments1) + subscriptionUserAccessAdmins := listSubscriptionUserAccessAdmins(ctx, client, subscriptionRoleAssignments2) // ResourceGroups: Owners and UserAccessAdmins - pipeline.Tee(ctx.Done(), listResourceGroupRoleAssignments(ctx, client, panicChan, resourceGroups2), resourceGroupRoleAssignments1, resourceGroupRoleAssignments2) + pipeline.Tee(ctx.Done(), listResourceGroupRoleAssignments(ctx, client, resourceGroups2), resourceGroupRoleAssignments1, resourceGroupRoleAssignments2) resourceGroupOwners := listResourceGroupOwners(ctx, resourceGroupRoleAssignments1) resourceGroupUserAccessAdmins := listResourceGroupUserAccessAdmins(ctx, resourceGroupRoleAssignments2) // KeyVaults: AccessPolicies, Owners, UserAccessAdmins, Contributors and KVContributors - pipeline.Tee(ctx.Done(), listKeyVaultRoleAssignments(ctx, client, panicChan, keyVaults2), keyVaultRoleAssignments1, keyVaultRoleAssignments2, keyVaultRoleAssignments3, keyVaultRoleAssignments4) - keyVaultAccessPolicies := listKeyVaultAccessPolicies(ctx, client, panicChan, keyVaults3, []enums.KeyVaultAccessType{enums.GetCerts, enums.GetKeys, enums.GetCerts}) + pipeline.Tee(ctx.Done(), listKeyVaultRoleAssignments(ctx, client, keyVaults2), keyVaultRoleAssignments1, keyVaultRoleAssignments2, keyVaultRoleAssignments3, keyVaultRoleAssignments4) + keyVaultAccessPolicies := listKeyVaultAccessPolicies(ctx, client, keyVaults3, []enums.KeyVaultAccessType{enums.GetCerts, enums.GetKeys, enums.GetCerts}) keyVaultOwners := listKeyVaultOwners(ctx, keyVaultRoleAssignments1) keyVaultUserAccessAdmins := listKeyVaultUserAccessAdmins(ctx, keyVaultRoleAssignments2) keyVaultContributors := listKeyVaultContributors(ctx, keyVaultRoleAssignments3) keyVaultKVContributors := listKeyVaultKVContributors(ctx, keyVaultRoleAssignments4) // VirtualMachines: Owners, AvereContributors, Contributors, AdminLogins and UserAccessAdmins - pipeline.Tee(ctx.Done(), listVirtualMachineRoleAssignments(ctx, client, panicChan, virtualMachines2), virtualMachineRoleAssignments1, virtualMachineRoleAssignments2, virtualMachineRoleAssignments3, virtualMachineRoleAssignments4, virtualMachineRoleAssignments5) + pipeline.Tee(ctx.Done(), listVirtualMachineRoleAssignments(ctx, client, virtualMachines2), virtualMachineRoleAssignments1, virtualMachineRoleAssignments2, virtualMachineRoleAssignments3, virtualMachineRoleAssignments4, virtualMachineRoleAssignments5) virtualMachineOwners := listVirtualMachineOwners(ctx, virtualMachineRoleAssignments1) virtualMachineAvereContributors := listVirtualMachineAvereContributors(ctx, virtualMachineRoleAssignments2) virtualMachineContributors := listVirtualMachineContributors(ctx, virtualMachineRoleAssignments3) @@ -190,25 +190,25 @@ func listAllRM(ctx context.Context, client client.AzureClient, panicChan chan er virtualMachineUserAccessAdmins := listVirtualMachineUserAccessAdmins(ctx, virtualMachineRoleAssignments5) // Enumerate Function App Role Assignments - functionAppRoleAssignments := listFunctionAppRoleAssignments(ctx, client, panicChan, functionApps2) + functionAppRoleAssignments := listFunctionAppRoleAssignments(ctx, client, functionApps2) // Enumerate Web App Role Assignments - webAppRoleAssignments := listWebAppRoleAssignments(ctx, client, panicChan, webApps2) + webAppRoleAssignments := listWebAppRoleAssignments(ctx, client, webApps2) // Enumerate Automation Account Role Assignments - automationAccountRoleAssignments := listAutomationAccountRoleAssignments(ctx, client, panicChan, automationAccounts2) + automationAccountRoleAssignments := listAutomationAccountRoleAssignments(ctx, client, automationAccounts2) // Enumerate Container Registry Role Assignments - containerRegistryRoleAssignments := listContainerRegistryRoleAssignments(ctx, client, panicChan, containerRegistries2) + containerRegistryRoleAssignments := listContainerRegistryRoleAssignments(ctx, client, containerRegistries2) // Enumerate Logic Apps Role Assignments - logicAppRoleAssignments := listLogicAppRoleAssignments(ctx, client, panicChan, logicApps2) + logicAppRoleAssignments := listLogicAppRoleAssignments(ctx, client, logicApps2) // Enumerate Managed Cluster Role Assignments - managedClusterRoleAssignments := listManagedClusterRoleAssignments(ctx, client, panicChan, managedClusters2) + managedClusterRoleAssignments := listManagedClusterRoleAssignments(ctx, client, managedClusters2) // Enumerate VM Scale Set Role Assignments - vmScaleSetRoleAssignments := listVMScaleSetRoleAssignments(ctx, client, panicChan, vmScaleSets2) + vmScaleSetRoleAssignments := listVMScaleSetRoleAssignments(ctx, client, vmScaleSets2) return pipeline.Mux(ctx.Done(), automationAccounts, diff --git a/cmd/list-container-registries.go b/cmd/list-container-registries.go index 977e718..93a0932 100644 --- a/cmd/list-container-registries.go +++ b/cmd/list-container-registries.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -55,16 +56,15 @@ func listContainerRegistriesCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure container registries...") start := time.Now() - panicChan := panicChan() - stream := listContainerRegistries(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listContainerRegistries(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listContainerRegistries(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listContainerRegistries(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,7 +73,7 @@ func listContainerRegistries(ctx context.Context, client client.AzureClient, pan ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -91,7 +91,7 @@ func listContainerRegistries(ctx context.Context, client client.AzureClient, pan for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-container-registry-role-assignments.go b/cmd/list-container-registry-role-assignments.go index 6122e04..31c3806 100644 --- a/cmd/list-container-registry-role-assignments.go +++ b/cmd/list-container-registry-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -56,17 +57,16 @@ func listContainerRegistryRoleAssignmentImpl(cmd *cobra.Command, args []string) } else { log.Info("collecting azure container registry role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listContainerRegistryRoleAssignments(ctx, azClient, panicChan, listContainerRegistries(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listContainerRegistryRoleAssignments(ctx, azClient, listContainerRegistries(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listContainerRegistryRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, containerRegistries <-chan interface{}) <-chan interface{} { +func listContainerRegistryRoleAssignments(ctx context.Context, client client.AzureClient, containerRegistries <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -75,7 +75,7 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), containerRegistries) { @@ -94,7 +94,7 @@ func listContainerRegistryRoleAssignments(ctx context.Context, client client.Azu for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-device-owners.go b/cmd/list-device-owners.go index 5222dcc..1d0c2e6 100644 --- a/cmd/list-device-owners.go +++ b/cmd/list-device-owners.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listDeviceOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure device owners...") start := time.Now() - panicChan := panicChan() - stream := listDeviceOwners(ctx, azClient, panicChan, listDevices(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listDeviceOwners(ctx, azClient, listDevices(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listDeviceOwners(ctx context.Context, client client.AzureClient, panicChan chan error, devices <-chan interface{}) <-chan interface{} { +func listDeviceOwners(ctx context.Context, client client.AzureClient, devices <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listDeviceOwners(ctx context.Context, client client.AzureClient, panicChan ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), devices) { @@ -86,7 +86,7 @@ func listDeviceOwners(ctx context.Context, client client.AzureClient, panicChan for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-device-owners_test.go b/cmd/list-device-owners_test.go index 6894f13..5f0dc3e 100644 --- a/cmd/list-device-owners_test.go +++ b/cmd/list-device-owners_test.go @@ -49,7 +49,7 @@ func TestListDeviceOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureDeviceRegisteredOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockDeviceOwnerChannel).Times(1) mockClient.EXPECT().ListAzureDeviceRegisteredOwners(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockDeviceOwnerChannel2).Times(1) - channel := listDeviceOwners(ctx, mockClient, panicChan(), mockDevicesChannel) + channel := listDeviceOwners(ctx, mockClient, mockDevicesChannel) go func() { defer close(mockDevicesChannel) diff --git a/cmd/list-devices.go b/cmd/list-devices.go index 2c82b04..5e68b8b 100644 --- a/cmd/list-devices.go +++ b/cmd/list-devices.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -49,19 +50,18 @@ func listDevicesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory devices...") start := time.Now() - panicChan := panicChan() - stream := listDevices(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listDevices(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listDevices(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listDevices(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) count := 0 for item := range client.ListAzureDevices(ctx, "", "", "", "", nil) { diff --git a/cmd/list-devices_test.go b/cmd/list-devices_test.go index 1e62816..1bbf4bf 100644 --- a/cmd/list-devices_test.go +++ b/cmd/list-devices_test.go @@ -56,7 +56,7 @@ func TestListDevices(t *testing.T) { } }() - channel := listDevices(ctx, mockClient, panicChan()) + channel := listDevices(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-function-app-role-assignments.go b/cmd/list-function-app-role-assignments.go index 0f05298..d881936 100644 --- a/cmd/list-function-app-role-assignments.go +++ b/cmd/list-function-app-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -52,16 +53,15 @@ func listFunctionAppRoleAssignmentImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure function app role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listFunctionAppRoleAssignments(ctx, azClient, panicChan, listFunctionApps(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listFunctionAppRoleAssignments(ctx, azClient, listFunctionApps(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, functionApps <-chan interface{}) <-chan interface{} { +func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClient, functionApps <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -70,7 +70,7 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), functionApps) { @@ -89,7 +89,7 @@ func listFunctionAppRoleAssignments(ctx context.Context, client client.AzureClie for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-function-apps.go b/cmd/list-function-apps.go index b2b7c80..d4e9b56 100644 --- a/cmd/list-function-apps.go +++ b/cmd/list-function-apps.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listFunctionAppsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure function apps...") start := time.Now() - panicChan := panicChan() - stream := listFunctionApps(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listFunctionApps(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listFunctionApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listFunctionApps(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listFunctionApps(ctx context.Context, client client.AzureClient, panicChan ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -86,7 +86,7 @@ func listFunctionApps(ctx context.Context, client client.AzureClient, panicChan for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-group-members.go b/cmd/list-group-members.go index af2d540..2f534a0 100644 --- a/cmd/list-group-members.go +++ b/cmd/list-group-members.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,14 +52,13 @@ func listGroupMembersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure group members...") start := time.Now() - panicChan := panicChan() - stream := listGroupMembers(ctx, azClient, panicChan, listGroups(ctx, azClient, panicChan)) + stream := listGroupMembers(ctx, azClient, listGroups(ctx, azClient)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listGroupMembers(ctx context.Context, client client.AzureClient, panicChan chan error, groups <-chan interface{}) <-chan interface{} { +func listGroupMembers(ctx context.Context, client client.AzureClient, groups <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -67,7 +67,7 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, panicChan ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), groups) { @@ -86,7 +86,7 @@ func listGroupMembers(ctx context.Context, client client.AzureClient, panicChan for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-group-members_test.go b/cmd/list-group-members_test.go index bd3c7ce..f3cf088 100644 --- a/cmd/list-group-members_test.go +++ b/cmd/list-group-members_test.go @@ -49,7 +49,7 @@ func TestListGroupMembers(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel).Times(1) mockClient.EXPECT().ListAzureADGroupMembers(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupMemberChannel2).Times(1) - channel := listGroupMembers(ctx, mockClient, panicChan(), mockGroupsChannel) + channel := listGroupMembers(ctx, mockClient, mockGroupsChannel) go func() { defer close(mockGroupsChannel) diff --git a/cmd/list-group-owners.go b/cmd/list-group-owners.go index 4dbed96..e24d13b 100644 --- a/cmd/list-group-owners.go +++ b/cmd/list-group-owners.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,14 +52,13 @@ func listGroupOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure group owners...") start := time.Now() - panicChan := panicChan() - stream := listGroupOwners(ctx, azClient, panicChan, listGroups(ctx, azClient, panicChan)) + stream := listGroupOwners(ctx, azClient, listGroups(ctx, azClient)) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listGroupOwners(ctx context.Context, client client.AzureClient, panicChan chan error, groups <-chan interface{}) <-chan interface{} { +func listGroupOwners(ctx context.Context, client client.AzureClient, groups <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -67,7 +67,7 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, panicChan c ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), groups) { @@ -86,7 +86,7 @@ func listGroupOwners(ctx context.Context, client client.AzureClient, panicChan c for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-group-owners_test.go b/cmd/list-group-owners_test.go index da41727..b1e7eea 100644 --- a/cmd/list-group-owners_test.go +++ b/cmd/list-group-owners_test.go @@ -49,7 +49,7 @@ func TestListGroupOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel).Times(1) mockClient.EXPECT().ListAzureADGroupOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockGroupOwnerChannel2).Times(1) - channel := listGroupOwners(ctx, mockClient, panicChan(), mockGroupsChannel) + channel := listGroupOwners(ctx, mockClient, mockGroupsChannel) go func() { defer close(mockGroupsChannel) diff --git a/cmd/list-groups.go b/cmd/list-groups.go index 25544fc..47b8dde 100644 --- a/cmd/list-groups.go +++ b/cmd/list-groups.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -49,19 +50,18 @@ func listGroupsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory groups...") start := time.Now() - panicChan := panicChan() - stream := listGroups(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listGroups(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listGroups(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listGroups(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) count := 0 for item := range client.ListAzureADGroups(ctx, "securityEnabled eq true", "", "", "", nil) { diff --git a/cmd/list-groups_test.go b/cmd/list-groups_test.go index 244452c..d931ff2 100644 --- a/cmd/list-groups_test.go +++ b/cmd/list-groups_test.go @@ -57,7 +57,7 @@ func TestListGroups(t *testing.T) { } }() - channel := listGroups(ctx, mockClient, panicChan()) + channel := listGroups(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-key-vault-access-policies.go b/cmd/list-key-vault-access-policies.go index 2091a46..31c8d79 100644 --- a/cmd/list-key-vault-access-policies.go +++ b/cmd/list-key-vault-access-policies.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" kinds "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -53,27 +54,26 @@ func listKeyVaultAccessPoliciesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault access policies...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) + subscriptions := listSubscriptions(ctx, azClient) if filters, ok := config.KeyVaultAccessTypes.Value().([]enums.KeyVaultAccessType); !ok { exit(fmt.Errorf("filter failed type assertion")) } else { if len(filters) > 0 { log.Info("applying access type filters", "filters", filters) } - stream := listKeyVaultAccessPolicies(ctx, azClient, panicChan, listKeyVaults(ctx, azClient, panicChan, subscriptions), filters) + stream := listKeyVaultAccessPolicies(ctx, azClient, listKeyVaults(ctx, azClient, subscriptions), filters) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } - handleBubbledPanic(ctx, panicChan, stop) + panicrecovery.HandleBubbledPanic(ctx, stop, log) } -func listKeyVaultAccessPolicies(ctx context.Context, client client.AzureClient, panicChan chan error, keyVaults <-chan interface{}, filters []enums.KeyVaultAccessType) <-chan interface{} { +func listKeyVaultAccessPolicies(ctx context.Context, client client.AzureClient, keyVaults <-chan interface{}, filters []enums.KeyVaultAccessType) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) for result := range pipeline.OrDone(ctx.Done(), keyVaults) { diff --git a/cmd/list-key-vault-access-policies_test.go b/cmd/list-key-vault-access-policies_test.go index b14eb52..877fe1f 100644 --- a/cmd/list-key-vault-access-policies_test.go +++ b/cmd/list-key-vault-access-policies_test.go @@ -41,7 +41,7 @@ func TestListKeyVaultAccessPolicies(t *testing.T) { mockKeyVaultsChannel := make(chan interface{}) mockTenant := azure.Tenant{} mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() - channel := listKeyVaultAccessPolicies(ctx, mockClient, panicChan(), mockKeyVaultsChannel, nil) + channel := listKeyVaultAccessPolicies(ctx, mockClient, mockKeyVaultsChannel, nil) go func() { defer close(mockKeyVaultsChannel) diff --git a/cmd/list-key-vault-contributors.go b/cmd/list-key-vault-contributors.go index 288a1c1..8bea518 100644 --- a/cmd/list-key-vault-contributors.go +++ b/cmd/list-key-vault-contributors.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listKeyVaultContributorsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault contributors...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + keyVaults := listKeyVaults(ctx, azClient, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listKeyVaultContributors(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-key-vault-kvcontributors.go b/cmd/list-key-vault-kvcontributors.go index fc905b8..1e8a864 100644 --- a/cmd/list-key-vault-kvcontributors.go +++ b/cmd/list-key-vault-kvcontributors.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listKeyVaultKVContributorsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault kvcontributors...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + keyVaults := listKeyVaults(ctx, azClient, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listKeyVaultKVContributors(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-key-vault-owners.go b/cmd/list-key-vault-owners.go index eafe697..3adb5d5 100644 --- a/cmd/list-key-vault-owners.go +++ b/cmd/list-key-vault-owners.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listKeyVaultOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault owners...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + keyVaults := listKeyVaults(ctx, azClient, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listKeyVaultOwners(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-key-vault-role-assignments.go b/cmd/list-key-vault-role-assignments.go index 3d1e572..05b67d2 100644 --- a/cmd/list-key-vault-role-assignments.go +++ b/cmd/list-key-vault-role-assignments.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,16 +52,15 @@ func listKeyVaultRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listKeyVaultRoleAssignments(ctx, azClient, panicChan, listKeyVaults(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listKeyVaultRoleAssignments(ctx, azClient, listKeyVaults(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, keyVaults <-chan interface{}) <-chan azureWrapper[models.KeyVaultRoleAssignments] { +func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, keyVaults <-chan interface{}) <-chan azureWrapper[models.KeyVaultRoleAssignments] { var ( out = make(chan azureWrapper[models.KeyVaultRoleAssignments]) ids = make(chan string) @@ -69,7 +69,7 @@ func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), keyVaults) { @@ -88,7 +88,7 @@ func listKeyVaultRoleAssignments(ctx context.Context, client client.AzureClient, for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-key-vault-role-assignments_test.go b/cmd/list-key-vault-role-assignments_test.go index 292109f..db7e4c3 100644 --- a/cmd/list-key-vault-role-assignments_test.go +++ b/cmd/list-key-vault-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListKeyVaultRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultRoleAssignmentChannel2).Times(1) - channel := listKeyVaultRoleAssignments(ctx, mockClient, panicChan(), mockKeyVaultsChannel) + channel := listKeyVaultRoleAssignments(ctx, mockClient, mockKeyVaultsChannel) go func() { defer close(mockKeyVaultsChannel) diff --git a/cmd/list-key-vault-user-access-admins.go b/cmd/list-key-vault-user-access-admins.go index a55c865..e0e2515 100644 --- a/cmd/list-key-vault-user-access-admins.go +++ b/cmd/list-key-vault-user-access-admins.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listKeyVaultUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vault user access admins...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - keyVaults := listKeyVaults(ctx, azClient, panicChan, subscriptions) - kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, panicChan, keyVaults) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + keyVaults := listKeyVaults(ctx, azClient, subscriptions) + kvRoleAssignments := listKeyVaultRoleAssignments(ctx, azClient, keyVaults) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listKeyVaultUserAccessAdmins(ctx, kvRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-key-vaults.go b/cmd/list-key-vaults.go index 3326387..66626d4 100644 --- a/cmd/list-key-vaults.go +++ b/cmd/list-key-vaults.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listKeyVaultsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure key vaults...") start := time.Now() - panicChan := panicChan() - stream := listKeyVaults(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listKeyVaults(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listKeyVaults(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listKeyVaults(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listKeyVaults(ctx context.Context, client client.AzureClient, panicChan cha ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { @@ -87,7 +87,7 @@ func listKeyVaults(ctx context.Context, client client.AzureClient, panicChan cha for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-key-vaults_test.go b/cmd/list-key-vaults_test.go index d7c9877..269288a 100644 --- a/cmd/list-key-vaults_test.go +++ b/cmd/list-key-vaults_test.go @@ -48,7 +48,7 @@ func TestListKeyVaults(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureKeyVaults(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultChannel).Times(1) mockClient.EXPECT().ListAzureKeyVaults(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockKeyVaultChannel2).Times(1) - channel := listKeyVaults(ctx, mockClient, panicChan(), mockSubscriptionsChannel) + channel := listKeyVaults(ctx, mockClient, mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) diff --git a/cmd/list-logic-app-role-assignments.go b/cmd/list-logic-app-role-assignments.go index 6fe164a..0dd33aa 100644 --- a/cmd/list-logic-app-role-assignments.go +++ b/cmd/list-logic-app-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -56,17 +57,16 @@ func listLogicAppRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure logic app role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listLogicAppRoleAssignments(ctx, azClient, panicChan, listLogicApps(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listLogicAppRoleAssignments(ctx, azClient, listLogicApps(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, logicapps <-chan interface{}) <-chan interface{} { +func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, logicapps <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -75,7 +75,7 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), logicapps) { @@ -94,7 +94,7 @@ func listLogicAppRoleAssignments(ctx context.Context, client client.AzureClient, for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-logic-apps.go b/cmd/list-logic-apps.go index 6631cc5..415168d 100644 --- a/cmd/list-logic-apps.go +++ b/cmd/list-logic-apps.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -55,16 +56,15 @@ func listLogicAppsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure logic apps...") start := time.Now() - panicChan := panicChan() - stream := listLogicApps(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listLogicApps(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listLogicApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listLogicApps(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,7 +73,7 @@ func listLogicApps(ctx context.Context, client client.AzureClient, panicChan cha ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -91,7 +91,7 @@ func listLogicApps(ctx context.Context, client client.AzureClient, panicChan cha for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-managed-cluster-role-assignments.go b/cmd/list-managed-cluster-role-assignments.go index 10c5f23..102db09 100644 --- a/cmd/list-managed-cluster-role-assignments.go +++ b/cmd/list-managed-cluster-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -56,17 +57,16 @@ func listManagedClusterRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure managed cluster role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listManagedClusterRoleAssignments(ctx, azClient, panicChan, listManagedClusters(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listManagedClusterRoleAssignments(ctx, azClient, listManagedClusters(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, managedClusters <-chan interface{}) <-chan interface{} { +func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureClient, managedClusters <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -75,7 +75,7 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), managedClusters) { @@ -94,7 +94,7 @@ func listManagedClusterRoleAssignments(ctx context.Context, client client.AzureC for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-managed-clusters.go b/cmd/list-managed-clusters.go index 4e2ec1e..d186666 100644 --- a/cmd/list-managed-clusters.go +++ b/cmd/list-managed-clusters.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -55,16 +56,15 @@ func listManagedClustersCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure managed clusters...") start := time.Now() - panicChan := panicChan() - stream := listManagedClusters(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listManagedClusters(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listManagedClusters(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listManagedClusters(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,7 +73,7 @@ func listManagedClusters(ctx context.Context, client client.AzureClient, panicCh ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -91,7 +91,7 @@ func listManagedClusters(ctx context.Context, client client.AzureClient, panicCh for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-management-group-descendants.go b/cmd/list-management-group-descendants.go index 7b06389..404c56e 100644 --- a/cmd/list-management-group-descendants.go +++ b/cmd/list-management-group-descendants.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listManagementGroupDescendantsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure management group descendants...") start := time.Now() - panicChan := panicChan() - stream := listManagementGroupDescendants(ctx, azClient, panicChan, listManagementGroups(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listManagementGroupDescendants(ctx, azClient, listManagementGroups(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listManagementGroupDescendants(ctx context.Context, client client.AzureClient, panicChan chan error, managementGroups <-chan interface{}) <-chan interface{} { +func listManagementGroupDescendants(ctx context.Context, client client.AzureClient, managementGroups <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listManagementGroupDescendants(ctx context.Context, client client.AzureClie ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), managementGroups) { @@ -87,7 +87,7 @@ func listManagementGroupDescendants(ctx context.Context, client client.AzureClie for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-management-group-descendants_test.go b/cmd/list-management-group-descendants_test.go index c4cd6a7..01806b1 100644 --- a/cmd/list-management-group-descendants_test.go +++ b/cmd/list-management-group-descendants_test.go @@ -48,7 +48,7 @@ func TestListManagementGroupDescendants(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel).Times(1) mockClient.EXPECT().ListAzureManagementGroupDescendants(gomock.Any(), gomock.Any()).Return(mockManagementGroupDescendantChannel2).Times(1) - channel := listManagementGroupDescendants(ctx, mockClient, panicChan(), mockManagementGroupsChannel) + channel := listManagementGroupDescendants(ctx, mockClient, mockManagementGroupsChannel) go func() { defer close(mockManagementGroupsChannel) diff --git a/cmd/list-management-group-owners.go b/cmd/list-management-group-owners.go index 7d2417b..b076ed6 100644 --- a/cmd/list-management-group-owners.go +++ b/cmd/list-management-group-owners.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,10 +51,9 @@ func listManagementGroupOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure management group owners...") start := time.Now() - panicChan := panicChan() - managementGroups := listManagementGroups(ctx, azClient, panicChan) - roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, panicChan, managementGroups) - handleBubbledPanic(ctx, panicChan, stop) + managementGroups := listManagementGroups(ctx, azClient) + roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, managementGroups) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listManagementGroupOwners(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-management-group-role-assignments.go b/cmd/list-management-group-role-assignments.go index 9198e79..6ef9a51 100644 --- a/cmd/list-management-group-role-assignments.go +++ b/cmd/list-management-group-role-assignments.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,16 +52,15 @@ func listManagementGroupRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string azClient := connectAndCreateClient() log.Info("collecting azure management group role assignments...") start := time.Now() - panicChan := panicChan() - managementGroups := listManagementGroups(ctx, azClient, panicChan) - stream := listManagementGroupRoleAssignments(ctx, azClient, panicChan, managementGroups) - handleBubbledPanic(ctx, panicChan, stop) + managementGroups := listManagementGroups(ctx, azClient) + stream := listManagementGroupRoleAssignments(ctx, azClient, managementGroups) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listManagementGroupRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, managementGroups <-chan interface{}) <-chan azureWrapper[models.ManagementGroupRoleAssignments] { +func listManagementGroupRoleAssignments(ctx context.Context, client client.AzureClient, managementGroups <-chan interface{}) <-chan azureWrapper[models.ManagementGroupRoleAssignments] { var ( out = make(chan azureWrapper[models.ManagementGroupRoleAssignments]) ids = make(chan string) @@ -69,7 +69,7 @@ func listManagementGroupRoleAssignments(ctx context.Context, client client.Azure ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), managementGroups) { @@ -88,7 +88,7 @@ func listManagementGroupRoleAssignments(ctx context.Context, client client.Azure for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-management-group-role-assignments_test.go b/cmd/list-management-group-role-assignments_test.go index 040ab6a..eed6954 100644 --- a/cmd/list-management-group-role-assignments_test.go +++ b/cmd/list-management-group-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListResourceGroupRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupRoleAssignmentChannel2).Times(1) - channel := listResourceGroupRoleAssignments(ctx, mockClient, panicChan(), mockResourceGroupsChannel) + channel := listResourceGroupRoleAssignments(ctx, mockClient, mockResourceGroupsChannel) go func() { defer close(mockResourceGroupsChannel) diff --git a/cmd/list-management-group-user-access-admins.go b/cmd/list-management-group-user-access-admins.go index 96b2751..ecb4be0 100644 --- a/cmd/list-management-group-user-access-admins.go +++ b/cmd/list-management-group-user-access-admins.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,10 +51,9 @@ func listManagementGroupUserAccessAdminsCmdImpl(cmd *cobra.Command, args []strin azClient := connectAndCreateClient() log.Info("collecting azure management group user access admins...") start := time.Now() - panicChan := panicChan() - managementGroups := listManagementGroups(ctx, azClient, panicChan) - roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, panicChan, managementGroups) - handleBubbledPanic(ctx, panicChan, stop) + managementGroups := listManagementGroups(ctx, azClient) + roleAssignments := listManagementGroupRoleAssignments(ctx, azClient, managementGroups) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listManagementGroupUserAccessAdmins(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-management-groups.go b/cmd/list-management-groups.go index 54549f6..87ddbe0 100644 --- a/cmd/list-management-groups.go +++ b/cmd/list-management-groups.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/config" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,19 +51,19 @@ func listManagementGroupsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory management groups...") start := time.Now() - panicChan := panicChan() - stream := listManagementGroups(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + + stream := listManagementGroups(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listManagementGroups(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listManagementGroups(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) count := 0 for item := range client.ListAzureManagementGroups(ctx) { diff --git a/cmd/list-management-groups_test.go b/cmd/list-management-groups_test.go index 3eba355..47efe17 100644 --- a/cmd/list-management-groups_test.go +++ b/cmd/list-management-groups_test.go @@ -56,7 +56,7 @@ func TestListManagementGroups(t *testing.T) { } }() - channel := listManagementGroups(ctx, mockClient, panicChan()) + channel := listManagementGroups(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-resource-group-owners.go b/cmd/list-resource-group-owners.go index 5b82932..e049501 100644 --- a/cmd/list-resource-group-owners.go +++ b/cmd/list-resource-group-owners.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listResourceGroupOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure resource group owners...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - resourceGroups := listResourceGroups(ctx, azClient, panicChan, subscriptions) - roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, panicChan, resourceGroups) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + resourceGroups := listResourceGroups(ctx, azClient, subscriptions) + roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, resourceGroups) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listResourceGroupOwners(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-resource-group-role-assignments.go b/cmd/list-resource-group-role-assignments.go index 3138f5b..a6d2fb7 100644 --- a/cmd/list-resource-group-role-assignments.go +++ b/cmd/list-resource-group-role-assignments.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,17 +52,16 @@ func listResourceGroupRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure resource group role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - resourceGroups := listResourceGroups(ctx, azClient, panicChan, subscriptions) - stream := listResourceGroupRoleAssignments(ctx, azClient, panicChan, resourceGroups) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + resourceGroups := listResourceGroups(ctx, azClient, subscriptions) + stream := listResourceGroupRoleAssignments(ctx, azClient, resourceGroups) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, resourceGroups <-chan interface{}) <-chan azureWrapper[models.ResourceGroupRoleAssignments] { +func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureClient, resourceGroups <-chan interface{}) <-chan azureWrapper[models.ResourceGroupRoleAssignments] { var ( out = make(chan azureWrapper[models.ResourceGroupRoleAssignments]) ids = make(chan string) @@ -70,7 +70,7 @@ func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureCl ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), resourceGroups) { @@ -89,7 +89,7 @@ func listResourceGroupRoleAssignments(ctx context.Context, client client.AzureCl for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-resource-group-role-assignments_test.go b/cmd/list-resource-group-role-assignments_test.go index cc5e204..5c8c8bb 100644 --- a/cmd/list-resource-group-role-assignments_test.go +++ b/cmd/list-resource-group-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListManagementGroupRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockManagementGroupRoleAssignmentChannel2).Times(1) - channel := listManagementGroupRoleAssignments(ctx, mockClient, panicChan(), mockManagementGroupsChannel) + channel := listManagementGroupRoleAssignments(ctx, mockClient, mockManagementGroupsChannel) go func() { defer close(mockManagementGroupsChannel) diff --git a/cmd/list-resource-group-user-access-admins.go b/cmd/list-resource-group-user-access-admins.go index 0550829..0762c77 100644 --- a/cmd/list-resource-group-user-access-admins.go +++ b/cmd/list-resource-group-user-access-admins.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listResourceGroupUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure resource group user access admins...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - resourceGroups := listResourceGroups(ctx, azClient, panicChan, subscriptions) - roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, panicChan, resourceGroups) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + resourceGroups := listResourceGroups(ctx, azClient, subscriptions) + roleAssignments := listResourceGroupRoleAssignments(ctx, azClient, resourceGroups) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listResourceGroupUserAccessAdmins(ctx, roleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-resource-groups.go b/cmd/list-resource-groups.go index 2e3ca66..c3ae948 100644 --- a/cmd/list-resource-groups.go +++ b/cmd/list-resource-groups.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listResourceGroupsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure resource groups...") start := time.Now() - panicChan := panicChan() - stream := listResourceGroups(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listResourceGroups(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listResourceGroups(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listResourceGroups(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listResourceGroups(ctx context.Context, client client.AzureClient, panicCha ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { @@ -87,7 +87,7 @@ func listResourceGroups(ctx context.Context, client client.AzureClient, panicCha for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-resource-groups_test.go b/cmd/list-resource-groups_test.go index da3a307..78ac328 100644 --- a/cmd/list-resource-groups_test.go +++ b/cmd/list-resource-groups_test.go @@ -48,7 +48,7 @@ func TestListResourceGroups(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureResourceGroups(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupChannel).Times(1) mockClient.EXPECT().ListAzureResourceGroups(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockResourceGroupChannel2).Times(1) - channel := listResourceGroups(ctx, mockClient, panicChan(), mockSubscriptionsChannel) + channel := listResourceGroups(ctx, mockClient, mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) diff --git a/cmd/list-role-assignments.go b/cmd/list-role-assignments.go index f1a7c9e..cde6422 100644 --- a/cmd/list-role-assignments.go +++ b/cmd/list-role-assignments.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,16 +52,15 @@ func listRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory role assignments...") start := time.Now() - panicChan := panicChan() - roles := listRoles(ctx, azClient, panicChan) - stream := listRoleAssignments(ctx, azClient, panicChan, roles) - handleBubbledPanic(ctx, panicChan, stop) + roles := listRoles(ctx, azClient) + stream := listRoleAssignments(ctx, azClient, roles) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, roles <-chan interface{}) <-chan interface{} { +func listRoleAssignments(ctx context.Context, client client.AzureClient, roles <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -69,7 +69,7 @@ func listRoleAssignments(ctx context.Context, client client.AzureClient, panicCh ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), roles) { @@ -88,7 +88,7 @@ func listRoleAssignments(ctx context.Context, client client.AzureClient, panicCh for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-roles.go b/cmd/list-roles.go index a61773d..836c9b5 100644 --- a/cmd/list-roles.go +++ b/cmd/list-roles.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -49,19 +50,18 @@ func listRolesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory roles...") start := time.Now() - panicChan := panicChan() - stream := listRoles(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listRoles(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listRoles(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listRoles(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) count := 0 for item := range client.ListAzureADRoles(ctx, "", "") { diff --git a/cmd/list-roles_test.go b/cmd/list-roles_test.go index 469d231..0805f0a 100644 --- a/cmd/list-roles_test.go +++ b/cmd/list-roles_test.go @@ -56,7 +56,7 @@ func TestListRoles(t *testing.T) { } }() - channel := listRoles(ctx, mockClient, panicChan()) + channel := listRoles(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-root.go b/cmd/list-root.go index e143c74..fb0d05d 100644 --- a/cmd/list-root.go +++ b/cmd/list-root.go @@ -55,16 +55,16 @@ func listCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure objects...") start := time.Now() - stream := listAll(ctx, azClient, panicChan()) + stream := listAll(ctx, azClient) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listAll(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listAll(ctx context.Context, client client.AzureClient) <-chan interface{} { var ( - azureAD = listAllAD(ctx, client, panicChan) - azureRM = listAllRM(ctx, client, panicChan) + azureAD = listAllAD(ctx, client) + azureRM = listAllRM(ctx, client) ) return pipeline.Mux(ctx.Done(), azureAD, azureRM) } diff --git a/cmd/list-service-principal-owners.go b/cmd/list-service-principal-owners.go index b67ed94..7fd4c56 100644 --- a/cmd/list-service-principal-owners.go +++ b/cmd/list-service-principal-owners.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listServicePrincipalOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure service principal owners...") start := time.Now() - panicChan := panicChan() - stream := listServicePrincipalOwners(ctx, azClient, panicChan, listServicePrincipals(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listServicePrincipalOwners(ctx, azClient, listServicePrincipals(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, panicChan chan error, servicePrincipals <-chan interface{}) <-chan interface{} { +func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, servicePrincipals <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), servicePrincipals) { @@ -87,7 +87,7 @@ func listServicePrincipalOwners(ctx context.Context, client client.AzureClient, for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-service-principal-owners_test.go b/cmd/list-service-principal-owners_test.go index 926a64c..1dff1d1 100644 --- a/cmd/list-service-principal-owners_test.go +++ b/cmd/list-service-principal-owners_test.go @@ -49,7 +49,7 @@ func TestListServicePrincipalOwners(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel).Times(1) mockClient.EXPECT().ListAzureADServicePrincipalOwners(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(mockServicePrincipalOwnerChannel2).Times(1) - channel := listServicePrincipalOwners(ctx, mockClient, panicChan(), mockServicePrincipalsChannel) + channel := listServicePrincipalOwners(ctx, mockClient, mockServicePrincipalsChannel) go func() { defer close(mockServicePrincipalsChannel) diff --git a/cmd/list-service-principals.go b/cmd/list-service-principals.go index 1a3f549..57399bd 100644 --- a/cmd/list-service-principals.go +++ b/cmd/list-service-principals.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -49,19 +50,18 @@ func listServicePrincipalsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory service principals...") start := time.Now() - panicChan := panicChan() - stream := listServicePrincipals(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listServicePrincipals(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listServicePrincipals(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listServicePrincipals(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) count := 0 for item := range client.ListAzureADServicePrincipals(ctx, "", "", "", "", nil) { diff --git a/cmd/list-service-principals_test.go b/cmd/list-service-principals_test.go index db66e89..c62f028 100644 --- a/cmd/list-service-principals_test.go +++ b/cmd/list-service-principals_test.go @@ -56,7 +56,7 @@ func TestListServicePrincipals(t *testing.T) { } }() - channel := listServicePrincipals(ctx, mockClient, panicChan()) + channel := listServicePrincipals(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-storage-account-role-assignments.go b/cmd/list-storage-account-role-assignments.go index 566fb98..71df35a 100644 --- a/cmd/list-storage-account-role-assignments.go +++ b/cmd/list-storage-account-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -52,16 +53,15 @@ func listStorageAccountRoleAssignmentsImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure storage account role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listStorageAccountRoleAssignments(ctx, azClient, panicChan, listStorageAccounts(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listStorageAccountRoleAssignments(ctx, azClient, listStorageAccounts(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, storageAccounts <-chan interface{}) <-chan interface{} { +func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureClient, storageAccounts <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -70,7 +70,7 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), storageAccounts) { @@ -89,7 +89,7 @@ func listStorageAccountRoleAssignments(ctx context.Context, client client.AzureC for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-storage-accounts.go b/cmd/list-storage-accounts.go index 5c5a0b5..8c91c71 100644 --- a/cmd/list-storage-accounts.go +++ b/cmd/list-storage-accounts.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listStorageAccountsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure storage accounts...") start := time.Now() - panicChan := panicChan() - stream := listStorageAccounts(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listStorageAccounts(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listStorageAccounts(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listStorageAccounts(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listStorageAccounts(ctx context.Context, client client.AzureClient, panicCh ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -86,7 +86,7 @@ func listStorageAccounts(ctx context.Context, client client.AzureClient, panicCh for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-storage-containers.go b/cmd/list-storage-containers.go index 0d2cc59..322f456 100644 --- a/cmd/list-storage-containers.go +++ b/cmd/list-storage-containers.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,17 +52,16 @@ func listStorageContainersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure storage containers...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - storageAccounts := listStorageAccounts(ctx, azClient, panicChan, subscriptions) - stream := listStorageContainers(ctx, azClient, panicChan, storageAccounts) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + storageAccounts := listStorageAccounts(ctx, azClient, subscriptions) + stream := listStorageContainers(ctx, azClient, storageAccounts) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listStorageContainers(ctx context.Context, client client.AzureClient, panicChan chan error, storageAccounts <-chan interface{}) <-chan interface{} { +func listStorageContainers(ctx context.Context, client client.AzureClient, storageAccounts <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan interface{}) @@ -75,7 +75,7 @@ func listStorageContainers(ctx context.Context, client client.AzureClient, panic ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), storageAccounts) { if storageAccount, ok := result.(AzureWrapper).Data.(models.StorageAccount); !ok { @@ -93,7 +93,7 @@ func listStorageContainers(ctx context.Context, client client.AzureClient, panic for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for stAccount := range stream { count := 0 diff --git a/cmd/list-subscription-owners.go b/cmd/list-subscription-owners.go index 91d32df..b351b8e 100644 --- a/cmd/list-subscription-owners.go +++ b/cmd/list-subscription-owners.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -52,21 +53,20 @@ func listSubscriptionOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure subscription owners...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, panicChan, subscriptions) - stream := listSubscriptionOwners(ctx, azClient, panicChan, roleAssignments) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, subscriptions) + stream := listSubscriptionOwners(ctx, azClient, roleAssignments) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptionOwners(ctx context.Context, client client.AzureClient, panicChan chan error, roleAssignments <-chan interface{}) <-chan interface{} { +func listSubscriptionOwners(ctx context.Context, client client.AzureClient, roleAssignments <-chan interface{}) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) for result := range pipeline.OrDone(ctx.Done(), roleAssignments) { diff --git a/cmd/list-subscription-owners_test.go b/cmd/list-subscription-owners_test.go index d1642b4..7850fef 100644 --- a/cmd/list-subscription-owners_test.go +++ b/cmd/list-subscription-owners_test.go @@ -42,7 +42,7 @@ func TestListSubscriptionOwners(t *testing.T) { mockRoleAssignmentsChannel := make(chan interface{}) mockTenant := azure.Tenant{} mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() - channel := listSubscriptionOwners(ctx, mockClient, panicChan(), mockRoleAssignmentsChannel) + channel := listSubscriptionOwners(ctx, mockClient, mockRoleAssignmentsChannel) go func() { defer close(mockRoleAssignmentsChannel) diff --git a/cmd/list-subscription-role-assignments.go b/cmd/list-subscription-role-assignments.go index b41c371..94279e3 100644 --- a/cmd/list-subscription-role-assignments.go +++ b/cmd/list-subscription-role-assignments.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,16 +52,15 @@ func listSubscriptionRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure subscription role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listSubscriptionRoleAssignments(ctx, azClient, panicChan, subscriptions) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listSubscriptionRoleAssignments(ctx, azClient, subscriptions) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -69,7 +69,7 @@ func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureCli ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { @@ -88,7 +88,7 @@ func listSubscriptionRoleAssignments(ctx context.Context, client client.AzureCli for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-subscription-role-assignments_test.go b/cmd/list-subscription-role-assignments_test.go index 3d1db82..1902684 100644 --- a/cmd/list-subscription-role-assignments_test.go +++ b/cmd/list-subscription-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListSubscriptionRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockSubscriptionRoleAssignmentChannel2).Times(1) - channel := listSubscriptionRoleAssignments(ctx, mockClient, panicChan(), mockSubscriptionsChannel) + channel := listSubscriptionRoleAssignments(ctx, mockClient, mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) diff --git a/cmd/list-subscription-user-access-admins.go b/cmd/list-subscription-user-access-admins.go index 39abb01..c3f78fa 100644 --- a/cmd/list-subscription-user-access-admins.go +++ b/cmd/list-subscription-user-access-admins.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -52,21 +53,20 @@ func listSubscriptionUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure subscription user access admins...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, panicChan, subscriptions) - stream := listSubscriptionUserAccessAdmins(ctx, azClient, panicChan, roleAssignments) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + roleAssignments := listSubscriptionRoleAssignments(ctx, azClient, subscriptions) + stream := listSubscriptionUserAccessAdmins(ctx, azClient, roleAssignments) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptionUserAccessAdmins(ctx context.Context, client client.AzureClient, panicChan chan error, vmRoleAssignments <-chan interface{}) <-chan interface{} { +func listSubscriptionUserAccessAdmins(ctx context.Context, client client.AzureClient, vmRoleAssignments <-chan interface{}) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) for result := range pipeline.OrDone(ctx.Done(), vmRoleAssignments) { diff --git a/cmd/list-subscription-user-access-admins_test.go b/cmd/list-subscription-user-access-admins_test.go index 34a956a..1a6a8dc 100644 --- a/cmd/list-subscription-user-access-admins_test.go +++ b/cmd/list-subscription-user-access-admins_test.go @@ -42,7 +42,7 @@ func TestListSubscriptionUserAccessAdmins(t *testing.T) { mockRoleAssignmentsChannel := make(chan interface{}) mockTenant := azure.Tenant{} mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() - channel := listSubscriptionUserAccessAdmins(ctx, mockClient, panicChan(), mockRoleAssignmentsChannel) + channel := listSubscriptionUserAccessAdmins(ctx, mockClient, mockRoleAssignmentsChannel) go func() { defer close(mockRoleAssignmentsChannel) diff --git a/cmd/list-subscriptions.go b/cmd/list-subscriptions.go index 0a409b7..c1a6f24 100644 --- a/cmd/list-subscriptions.go +++ b/cmd/list-subscriptions.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/models" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/bloodhoundad/azurehound/v2/client" @@ -53,19 +54,18 @@ func listSubscriptionsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory subscriptions...") start := time.Now() - panicChan := panicChan() - stream := listSubscriptions(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listSubscriptions(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listSubscriptions(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listSubscriptions(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) var ( count = 0 @@ -75,7 +75,7 @@ func listSubscriptions(ctx context.Context, client client.AzureClient, panicChan ) if len(selectedMgmtGroupIds) != 0 { - descendantChannel := listManagementGroupDescendants(ctx, client, panicChan, listManagementGroups(ctx, client, panicChan)) + descendantChannel := listManagementGroupDescendants(ctx, client, listManagementGroups(ctx, client)) for i := range descendantChannel { if item, ok := i.(AzureWrapper).Data.(azure.DescendantInfo); !ok { log.Error(fmt.Errorf("failed type assertion"), "unable to continue evaluating management group descendants", "result", i) diff --git a/cmd/list-subscriptions_test.go b/cmd/list-subscriptions_test.go index 535e900..51571c5 100644 --- a/cmd/list-subscriptions_test.go +++ b/cmd/list-subscriptions_test.go @@ -56,7 +56,7 @@ func TestListSubscriptions(t *testing.T) { } }() - channel := listSubscriptions(ctx, mockClient, panicChan()) + channel := listSubscriptions(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-tenants.go b/cmd/list-tenants.go index f150793..3e02caf 100644 --- a/cmd/list-tenants.go +++ b/cmd/list-tenants.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -49,19 +50,18 @@ func listTenantsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory tenants...") start := time.Now() - panicChan := panicChan() - stream := listTenants(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listTenants(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listTenants(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listTenants(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) // Send the fully hydrated tenant that is being collected diff --git a/cmd/list-tenants_test.go b/cmd/list-tenants_test.go index 003eb32..5f22399 100644 --- a/cmd/list-tenants_test.go +++ b/cmd/list-tenants_test.go @@ -56,7 +56,7 @@ func TestListTenants(t *testing.T) { } }() - channel := listTenants(ctx, mockClient, panicChan()) + channel := listTenants(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-users.go b/cmd/list-users.go index 9bc6410..531b7a3 100644 --- a/cmd/list-users.go +++ b/cmd/list-users.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -49,19 +50,18 @@ func listUsersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure active directory users...") start := time.Now() - panicChan := panicChan() - stream := listUsers(ctx, azClient, panicChan) - handleBubbledPanic(ctx, panicChan, stop) + stream := listUsers(ctx, azClient) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listUsers(ctx context.Context, client client.AzureClient, panicChan chan error) <-chan interface{} { +func listUsers(ctx context.Context, client client.AzureClient) <-chan interface{} { out := make(chan interface{}) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(out) count := 0 for item := range client.ListAzureADUsers(ctx, "", "", "", []string{ diff --git a/cmd/list-users_test.go b/cmd/list-users_test.go index a4693c5..d7e6211 100644 --- a/cmd/list-users_test.go +++ b/cmd/list-users_test.go @@ -57,7 +57,7 @@ func TestListUsers(t *testing.T) { } }() - channel := listUsers(ctx, mockClient, panicChan()) + channel := listUsers(ctx, mockClient) result := <-channel if _, ok := result.(AzureWrapper); !ok { t.Errorf("failed type assertion: got %T, want %T", result, AzureWrapper{}) diff --git a/cmd/list-virtual-machine-admin-logins.go b/cmd/list-virtual-machine-admin-logins.go index 49e0cb2..3bbcd30 100644 --- a/cmd/list-virtual-machine-admin-logins.go +++ b/cmd/list-virtual-machine-admin-logins.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listVirtualMachineAdminLoginsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machine admin logins...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + vms := listVirtualMachines(ctx, azClient, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listVirtualMachineAdminLogins(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-avere-contributors.go b/cmd/list-virtual-machine-avere-contributors.go index 24c0d60..577582d 100644 --- a/cmd/list-virtual-machine-avere-contributors.go +++ b/cmd/list-virtual-machine-avere-contributors.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listVirtualMachineAvereContributorsCmdImpl(cmd *cobra.Command, args []strin azClient := connectAndCreateClient() log.Info("collecting azure virtual machine averecontributors...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + vms := listVirtualMachines(ctx, azClient, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listVirtualMachineAvereContributors(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-contributors.go b/cmd/list-virtual-machine-contributors.go index 4dd2873..bcc6abf 100644 --- a/cmd/list-virtual-machine-contributors.go +++ b/cmd/list-virtual-machine-contributors.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listVirtualMachineContributorsCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machine contributors...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + vms := listVirtualMachines(ctx, azClient, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listVirtualMachineContributors(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-owners.go b/cmd/list-virtual-machine-owners.go index a6061ed..62edcf3 100644 --- a/cmd/list-virtual-machine-owners.go +++ b/cmd/list-virtual-machine-owners.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listVirtualMachineOwnersCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machine owners...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + vms := listVirtualMachines(ctx, azClient, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listVirtualMachineOwners(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-role-assignments.go b/cmd/list-virtual-machine-role-assignments.go index 8febdc3..097055e 100644 --- a/cmd/list-virtual-machine-role-assignments.go +++ b/cmd/list-virtual-machine-role-assignments.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,16 +52,15 @@ func listVirtualMachineRoleAssignmentsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure virtual machine role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, listVirtualMachines(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listVirtualMachineRoleAssignments(ctx, azClient, listVirtualMachines(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, virtualMachines <-chan interface{}) <-chan azureWrapper[models.VirtualMachineRoleAssignments] { +func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureClient, virtualMachines <-chan interface{}) <-chan azureWrapper[models.VirtualMachineRoleAssignments] { var ( out = make(chan azureWrapper[models.VirtualMachineRoleAssignments]) ids = make(chan string) @@ -69,7 +69,7 @@ func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureC ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), virtualMachines) { @@ -88,7 +88,7 @@ func listVirtualMachineRoleAssignments(ctx context.Context, client client.AzureC for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-virtual-machine-role-assignments_test.go b/cmd/list-virtual-machine-role-assignments_test.go index db4187e..dffaf79 100644 --- a/cmd/list-virtual-machine-role-assignments_test.go +++ b/cmd/list-virtual-machine-role-assignments_test.go @@ -49,7 +49,7 @@ func TestListVirtualMachineRoleAssignments(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel).Times(1) mockClient.EXPECT().ListRoleAssignmentsForResource(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineRoleAssignmentChannel2).Times(1) - channel := listVirtualMachineRoleAssignments(ctx, mockClient, panicChan(), mockVirtualMachinesChannel) + channel := listVirtualMachineRoleAssignments(ctx, mockClient, mockVirtualMachinesChannel) go func() { defer close(mockVirtualMachinesChannel) diff --git a/cmd/list-virtual-machine-user-access-admins.go b/cmd/list-virtual-machine-user-access-admins.go index d87ed1a..7b37c59 100644 --- a/cmd/list-virtual-machine-user-access-admins.go +++ b/cmd/list-virtual-machine-user-access-admins.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listVirtualMachineUserAccessAdminsCmdImpl(cmd *cobra.Command, args []string azClient := connectAndCreateClient() log.Info("collecting azure virtual machine user access admins...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + vms := listVirtualMachines(ctx, azClient, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listVirtualMachineUserAccessAdmins(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machine-vmcontributors.go b/cmd/list-virtual-machine-vmcontributors.go index f3b0e5f..b89e04f 100644 --- a/cmd/list-virtual-machine-vmcontributors.go +++ b/cmd/list-virtual-machine-vmcontributors.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/internal" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -50,11 +51,10 @@ func listVirtualMachineVMContributorsCmdImpl(cmd *cobra.Command, args []string) azClient := connectAndCreateClient() log.Info("collecting azure virtual machine vmcontributors...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - vms := listVirtualMachines(ctx, azClient, panicChan, subscriptions) - vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, panicChan, vms) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + vms := listVirtualMachines(ctx, azClient, subscriptions) + vmRoleAssignments := listVirtualMachineRoleAssignments(ctx, azClient, vms) + panicrecovery.HandleBubbledPanic(ctx, stop, log) stream := listVirtualMachineVMContributors(ctx, vmRoleAssignments) outputStream(ctx, stream) duration := time.Since(start) diff --git a/cmd/list-virtual-machines.go b/cmd/list-virtual-machines.go index 9d0fa01..d28d6e5 100644 --- a/cmd/list-virtual-machines.go +++ b/cmd/list-virtual-machines.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -51,15 +52,14 @@ func listVirtualMachinesCmdImpl(cmd *cobra.Command, args []string) { azClient := connectAndCreateClient() log.Info("collecting azure virtual machines...") start := time.Now() - panicChan := panicChan() - stream := listVirtualMachines(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listVirtualMachines(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } -func listVirtualMachines(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listVirtualMachines(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -68,7 +68,7 @@ func listVirtualMachines(ctx context.Context, client client.AzureClient, panicCh ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -86,7 +86,7 @@ func listVirtualMachines(ctx context.Context, client client.AzureClient, panicCh for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-virtual-machines_test.go b/cmd/list-virtual-machines_test.go index 98dd14b..58b9113 100644 --- a/cmd/list-virtual-machines_test.go +++ b/cmd/list-virtual-machines_test.go @@ -48,7 +48,7 @@ func TestListVirtualMachines(t *testing.T) { mockClient.EXPECT().TenantInfo().Return(mockTenant).AnyTimes() mockClient.EXPECT().ListAzureVirtualMachines(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineChannel).Times(1) mockClient.EXPECT().ListAzureVirtualMachines(gomock.Any(), gomock.Any(), gomock.Any()).Return(mockVirtualMachineChannel2).Times(1) - channel := listVirtualMachines(ctx, mockClient, panicChan(), mockSubscriptionsChannel) + channel := listVirtualMachines(ctx, mockClient, mockSubscriptionsChannel) go func() { defer close(mockSubscriptionsChannel) diff --git a/cmd/list-vm-scale-set-role-assignments.go b/cmd/list-vm-scale-set-role-assignments.go index c871b4d..4a82b2e 100644 --- a/cmd/list-vm-scale-set-role-assignments.go +++ b/cmd/list-vm-scale-set-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -56,17 +57,16 @@ func listVMScaleSetRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure vm scale set role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listVMScaleSetRoleAssignments(ctx, azClient, panicChan, listVMScaleSets(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listVMScaleSetRoleAssignments(ctx, azClient, listVMScaleSets(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, vmScaleSets <-chan interface{}) <-chan interface{} { +func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClient, vmScaleSets <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -75,7 +75,7 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), vmScaleSets) { @@ -94,7 +94,7 @@ func listVMScaleSetRoleAssignments(ctx context.Context, client client.AzureClien for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-vm-scale-sets.go b/cmd/list-vm-scale-sets.go index 7f9feaf..c55f4b2 100644 --- a/cmd/list-vm-scale-sets.go +++ b/cmd/list-vm-scale-sets.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -55,9 +56,8 @@ func listVMScaleSetsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure virtual machine scale sets...") start := time.Now() - panicChan := panicChan() - stream := listVMScaleSets(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listVMScaleSets(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) @@ -65,7 +65,7 @@ func listVMScaleSetsCmdImpl(cmd *cobra.Command, args []string) { } -func listVMScaleSets(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listVMScaleSets(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -74,7 +74,7 @@ func listVMScaleSets(ctx context.Context, client client.AzureClient, panicChan c ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -92,7 +92,7 @@ func listVMScaleSets(ctx context.Context, client client.AzureClient, panicChan c for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/list-web-app-role-assignments.go b/cmd/list-web-app-role-assignments.go index 81f0ded..90ce0ef 100644 --- a/cmd/list-web-app-role-assignments.go +++ b/cmd/list-web-app-role-assignments.go @@ -29,6 +29,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -56,17 +57,16 @@ func listWebAppRoleAssignmentImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure web app role assignments...") start := time.Now() - panicChan := panicChan() - subscriptions := listSubscriptions(ctx, azClient, panicChan) - stream := listWebAppRoleAssignments(ctx, azClient, panicChan, listWebApps(ctx, azClient, panicChan, subscriptions)) - handleBubbledPanic(ctx, panicChan, stop) + subscriptions := listSubscriptions(ctx, azClient) + stream := listWebAppRoleAssignments(ctx, azClient, listWebApps(ctx, azClient, subscriptions)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, panicChan chan error, webApps <-chan interface{}) <-chan interface{} { +func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, webApps <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -75,7 +75,7 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, p ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), webApps) { @@ -94,7 +94,7 @@ func listWebAppRoleAssignments(ctx context.Context, client client.AzureClient, p for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { var ( diff --git a/cmd/list-web-apps.go b/cmd/list-web-apps.go index 726617e..ac2aaec 100644 --- a/cmd/list-web-apps.go +++ b/cmd/list-web-apps.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" "github.com/spf13/cobra" ) @@ -55,16 +56,15 @@ func listWebAppsCmdImpl(cmd *cobra.Command, args []string) { } else { log.Info("collecting azure web apps...") start := time.Now() - panicChan := panicChan() - stream := listWebApps(ctx, azClient, panicChan, listSubscriptions(ctx, azClient, panicChan)) - handleBubbledPanic(ctx, panicChan, stop) + stream := listWebApps(ctx, azClient, listSubscriptions(ctx, azClient)) + panicrecovery.HandleBubbledPanic(ctx, stop, log) outputStream(ctx, stream) duration := time.Since(start) log.Info("collection completed", "duration", duration.String()) } } -func listWebApps(ctx context.Context, client client.AzureClient, panicChan chan error, subscriptions <-chan interface{}) <-chan interface{} { +func listWebApps(ctx context.Context, client client.AzureClient, subscriptions <-chan interface{}) <-chan interface{} { var ( out = make(chan interface{}) ids = make(chan string) @@ -73,7 +73,7 @@ func listWebApps(ctx context.Context, client client.AzureClient, panicChan chan ) go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer close(ids) for result := range pipeline.OrDone(ctx.Done(), subscriptions) { if subscription, ok := result.(AzureWrapper).Data.(models.Subscription); !ok { @@ -91,7 +91,7 @@ func listWebApps(ctx context.Context, client client.AzureClient, panicChan chan for i := range streams { stream := streams[i] go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer wg.Done() for id := range stream { count := 0 diff --git a/cmd/start.go b/cmd/start.go index e05a1f6..a112eef 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -42,6 +42,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/config" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -96,7 +97,6 @@ func start(ctx context.Context) { log.Info("connected successfully! waiting for jobs...") ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() - panicChan := panicChan() var ( jobQueued sync.Mutex @@ -113,7 +113,7 @@ func start(ctx context.Context) { } } else if jobQueued.TryLock() { go func() { - defer panicRecovery(panicChan) + defer panicrecovery.PanicRecovery() defer jobQueued.Unlock() defer bheClient.CloseIdleConnections() defer azClient.CloseIdleConnections() @@ -151,10 +151,10 @@ func start(ctx context.Context) { start := time.Now() ctx, stop := context.WithCancel(ctx) - handleBubbledPanic(ctx, panicChan, stop) + panicrecovery.HandleBubbledPanic(ctx, stop, log) // Batch data out for ingestion - stream := listAll(ctx, azClient, panicChan) + stream := listAll(ctx, azClient) batches := pipeline.Batch(ctx.Done(), stream, 256, 10*time.Second) hasIngestErr := ingest(ctx, *bheInstance, bheClient, batches) diff --git a/cmd/utils.go b/cmd/utils.go index 2781903..fd59f82 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -34,7 +34,6 @@ import ( "os" "path" "path/filepath" - "runtime/debug" "runtime/pprof" "time" @@ -86,35 +85,6 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { } } -// panicChan creates an error channel to be used for communicating errors between goroutines. -func panicChan() chan error { - var panicChan = make(chan error) - - return panicChan -} - -// handleBubbledPanic receives errors from panicChan, then it will print them and stop() context. -func handleBubbledPanic(ctx context.Context, panicChan chan error, stop context.CancelFunc) { - go func() { - for { - select { - case err := <-panicChan: - log.V(0).Error(err, "") - stop() - case <-ctx.Done(): - return - } - } - }() -} - -// panicRecovery recovers from panics and sends them to panicChan -func panicRecovery(panicChan chan error) { - if recovery := recover(); recovery != nil { - panicChan <- fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()) - } -} - func gracefulShutdown(stop context.CancelFunc) { stop() fmt.Fprintln(os.Stderr, "\nshutting down gracefully, press ctrl+c again to force") diff --git a/panicrecovery/panic_recovery.go b/panicrecovery/panic_recovery.go new file mode 100644 index 0000000..731dc78 --- /dev/null +++ b/panicrecovery/panic_recovery.go @@ -0,0 +1,34 @@ +package panicrecovery + +import ( + "context" + "fmt" + "runtime/debug" + + "github.com/go-logr/logr" +) + +var PanicChan = make(chan error) + +// handleBubbledPanic receives errors from panicChan, then it will print them and stop() context. +func HandleBubbledPanic(ctx context.Context, stop context.CancelFunc, log logr.Logger) { + go func() { + for { + select { + case err := <-PanicChan: + fmt.Println(" THAT IS WHAT IM TALKING ABOUT ✅✅✅✅") + log.V(0).Error(err, "") + stop() + case <-ctx.Done(): + return + } + } + }() +} + +// panicRecovery recovers from panics and sends them to panicChan +func PanicRecovery() { + if recovery := recover(); recovery != nil { + PanicChan <- fmt.Errorf("[panic recovery] %s - [stack trace] %s", recovery, debug.Stack()) + } +} From e1bc856e8ddb4083fab9df191fd3522efc70937d Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Wed, 20 Mar 2024 13:57:22 -0700 Subject: [PATCH 23/26] remove extra log --- panicrecovery/panic_recovery.go | 1 - 1 file changed, 1 deletion(-) diff --git a/panicrecovery/panic_recovery.go b/panicrecovery/panic_recovery.go index 731dc78..3cbd757 100644 --- a/panicrecovery/panic_recovery.go +++ b/panicrecovery/panic_recovery.go @@ -16,7 +16,6 @@ func HandleBubbledPanic(ctx context.Context, stop context.CancelFunc, log logr.L for { select { case err := <-PanicChan: - fmt.Println(" THAT IS WHAT IM TALKING ABOUT ✅✅✅✅") log.V(0).Error(err, "") stop() case <-ctx.Done(): From e2a6fda0d7db1d3e4d6fdd1bb3932491fc9c8b9e Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Wed, 20 Mar 2024 13:57:40 -0700 Subject: [PATCH 24/26] plumb into client package --- client/app_role_assignments.go | 2 ++ client/apps.go | 4 ++++ client/automation_accounts.go | 2 ++ client/container_registries.go | 2 ++ client/devices.go | 3 +++ client/function_apps.go | 2 ++ client/groups.go | 4 ++++ client/keyvaults.go | 2 ++ client/logic_apps.go | 2 ++ client/managed_clusters.go | 2 ++ client/management_groups.go | 3 +++ client/resource_groups.go | 2 ++ client/role_assignments.go | 4 ++++ client/roles.go | 2 ++ client/service_principals.go | 3 +++ client/storage_accounts.go | 3 +++ client/subscriptions.go | 2 ++ client/tenants.go | 2 ++ client/users.go | 2 ++ client/virtual_machines.go | 2 ++ client/vm_scale_sets.go | 2 ++ client/web_apps.go | 2 ++ 22 files changed, 54 insertions(+) diff --git a/client/app_role_assignments.go b/client/app_role_assignments.go index c2eac7a..09659f0 100644 --- a/client/app_role_assignments.go +++ b/client/app_role_assignments.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -56,6 +57,7 @@ func (s *azureClient) ListAzureADAppRoleAssignments(ctx context.Context, service out := make(chan azure.AppRoleAssignmentResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/apps.go b/client/apps.go index 1091a31..fb60ed5 100644 --- a/client/apps.go +++ b/client/apps.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -105,6 +106,7 @@ func (s *azureClient) ListAzureADApps(ctx context.Context, filter, search, order out := make(chan azure.ApplicationResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -169,6 +171,7 @@ func (s *azureClient) ListAzureADAppOwners(ctx context.Context, objectId string, out := make(chan azure.AppOwnerResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -239,6 +242,7 @@ func (s *azureClient) ListAzureADAppMemberObjects(ctx context.Context, objectId out := make(chan azure.MemberObjectResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/automation_accounts.go b/client/automation_accounts.go index 2131acf..512271b 100644 --- a/client/automation_accounts.go +++ b/client/automation_accounts.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureAutomationAccounts(ctx context.Context, subscript out := make(chan azure.AutomationAccountResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/container_registries.go b/client/container_registries.go index 8aeecdc..9e7eebb 100644 --- a/client/container_registries.go +++ b/client/container_registries.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureContainerRegistries(ctx context.Context, subscrip out := make(chan azure.ContainerRegistryResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/devices.go b/client/devices.go index 8b811a2..823ab71 100644 --- a/client/devices.go +++ b/client/devices.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -86,6 +87,7 @@ func (s *azureClient) ListAzureDevices(ctx context.Context, filter, search, orde out := make(chan azure.DeviceResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -150,6 +152,7 @@ func (s *azureClient) ListAzureDeviceRegisteredOwners(ctx context.Context, objec out := make(chan azure.DeviceRegisteredOwnerResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/function_apps.go b/client/function_apps.go index 640acce..3e2e113 100644 --- a/client/function_apps.go +++ b/client/function_apps.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureFunctionApps(ctx context.Context, subscriptionId out := make(chan azure.FunctionAppResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/groups.go b/client/groups.go index 4e205f8..5db0474 100644 --- a/client/groups.go +++ b/client/groups.go @@ -28,6 +28,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/enums" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -102,6 +103,7 @@ func (s *azureClient) ListAzureADGroups(ctx context.Context, filter, search, ord out := make(chan azure.GroupResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -166,6 +168,7 @@ func (s *azureClient) ListAzureADGroupOwners(ctx context.Context, objectId strin out := make(chan azure.GroupOwnerResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -236,6 +239,7 @@ func (s *azureClient) ListAzureADGroupMembers(ctx context.Context, objectId stri out := make(chan azure.MemberObjectResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/keyvaults.go b/client/keyvaults.go index 991cd6c..56e33f7 100644 --- a/client/keyvaults.go +++ b/client/keyvaults.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureKeyVaults(ctx context.Context, subscriptionId str out := make(chan azure.KeyVaultResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/logic_apps.go b/client/logic_apps.go index 70d1257..54006a5 100644 --- a/client/logic_apps.go +++ b/client/logic_apps.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureLogicApps(ctx context.Context, subscriptionId str out := make(chan azure.LogicAppResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/managed_clusters.go b/client/managed_clusters.go index 13168ac..b1db393 100644 --- a/client/managed_clusters.go +++ b/client/managed_clusters.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureManagedClusters(ctx context.Context, subscription out := make(chan azure.ManagedClusterResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/management_groups.go b/client/management_groups.go index 673c9b0..f68d866 100644 --- a/client/management_groups.go +++ b/client/management_groups.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -82,6 +83,7 @@ func (s *azureClient) ListAzureManagementGroups(ctx context.Context) <-chan azur out := make(chan azure.ManagementGroupResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -146,6 +148,7 @@ func (s *azureClient) ListAzureManagementGroupDescendants(ctx context.Context, g out := make(chan azure.DescendantInfoResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/resource_groups.go b/client/resource_groups.go index 3164c0f..c693fc4 100644 --- a/client/resource_groups.go +++ b/client/resource_groups.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureResourceGroups(ctx context.Context, subscriptionI out := make(chan azure.ResourceGroupResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/role_assignments.go b/client/role_assignments.go index fd94cd4..34f7da1 100644 --- a/client/role_assignments.go +++ b/client/role_assignments.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -71,6 +72,7 @@ func (s *azureClient) ListAzureADRoleAssignments(ctx context.Context, filter, se out := make(chan azure.UnifiedRoleAssignmentResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -153,6 +155,7 @@ func (s *azureClient) ListRoleAssignmentsForResource(ctx context.Context, resour out := make(chan azure.RoleAssignmentResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -240,6 +243,7 @@ func (s *azureClient) ListResourceRoleAssignments(ctx context.Context, subscript out := make(chan azure.RoleAssignmentResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/roles.go b/client/roles.go index 006c003..1f6fd5a 100644 --- a/client/roles.go +++ b/client/roles.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureADRoles(ctx context.Context, filter, expand strin out := make(chan azure.RoleResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/service_principals.go b/client/service_principals.go index 9c1d39b..9f8642e 100644 --- a/client/service_principals.go +++ b/client/service_principals.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -86,6 +87,7 @@ func (s *azureClient) ListAzureADServicePrincipals(ctx context.Context, filter, out := make(chan azure.ServicePrincipalResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -150,6 +152,7 @@ func (s *azureClient) ListAzureADServicePrincipalOwners(ctx context.Context, obj out := make(chan azure.ServicePrincipalOwnerResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/storage_accounts.go b/client/storage_accounts.go index 50f40c9..920deb1 100644 --- a/client/storage_accounts.go +++ b/client/storage_accounts.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -64,6 +65,7 @@ func (s *azureClient) ListAzureStorageAccounts(ctx context.Context, subscription out := make(chan azure.StorageAccountResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( @@ -169,6 +171,7 @@ func (s *azureClient) ListAzureStorageContainers(ctx context.Context, subscripti out := make(chan azure.StorageContainerResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/subscriptions.go b/client/subscriptions.go index c44c17f..877d18b 100644 --- a/client/subscriptions.go +++ b/client/subscriptions.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureSubscriptions(ctx context.Context) <-chan azure.S out := make(chan azure.SubscriptionResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/tenants.go b/client/tenants.go index bd3314e..1584190 100644 --- a/client/tenants.go +++ b/client/tenants.go @@ -26,6 +26,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureADTenants(ctx context.Context, includeAllTenantCa out := make(chan azure.TenantResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/users.go b/client/users.go index 98cec6c..cea543d 100644 --- a/client/users.go +++ b/client/users.go @@ -27,6 +27,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/constants" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -71,6 +72,7 @@ func (s *azureClient) ListAzureADUsers(ctx context.Context, filter string, searc out := make(chan azure.UserResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/virtual_machines.go b/client/virtual_machines.go index ccb810c..1934974 100644 --- a/client/virtual_machines.go +++ b/client/virtual_machines.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureVirtualMachines(ctx context.Context, subscription out := make(chan azure.VirtualMachineResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/vm_scale_sets.go b/client/vm_scale_sets.go index 4158553..94879ad 100644 --- a/client/vm_scale_sets.go +++ b/client/vm_scale_sets.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureVMScaleSets(ctx context.Context, subscriptionId s out := make(chan azure.VMScaleSetResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( diff --git a/client/web_apps.go b/client/web_apps.go index 7560d23..d25fdfc 100644 --- a/client/web_apps.go +++ b/client/web_apps.go @@ -25,6 +25,7 @@ import ( "github.com/bloodhoundad/azurehound/v2/client/query" "github.com/bloodhoundad/azurehound/v2/client/rest" "github.com/bloodhoundad/azurehound/v2/models/azure" + "github.com/bloodhoundad/azurehound/v2/panicrecovery" "github.com/bloodhoundad/azurehound/v2/pipeline" ) @@ -65,6 +66,7 @@ func (s *azureClient) ListAzureWebApps(ctx context.Context, subscriptionId strin out := make(chan azure.WebAppResult) go func() { + defer panicrecovery.PanicRecovery() defer close(out) var ( From 232bf8399c9c3f1a5c8104180475815b84bf767c Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Wed, 20 Mar 2024 14:02:57 -0700 Subject: [PATCH 25/26] move up panic recovery to handle root panics --- cmd/start.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmd/start.go b/cmd/start.go index a112eef..2f649b9 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -118,6 +118,9 @@ func start(ctx context.Context) { defer bheClient.CloseIdleConnections() defer azClient.CloseIdleConnections() + ctx, stop := context.WithCancel(ctx) + panicrecovery.HandleBubbledPanic(ctx, stop, log) + log.V(2).Info("checking for available collection jobs") if jobs, err := getAvailableJobs(ctx, *bheInstance, bheClient); err != nil { log.Error(err, "unable to fetch available jobs for azurehound") @@ -150,9 +153,6 @@ func start(ctx context.Context) { start := time.Now() - ctx, stop := context.WithCancel(ctx) - panicrecovery.HandleBubbledPanic(ctx, stop, log) - // Batch data out for ingestion stream := listAll(ctx, azClient) batches := pipeline.Batch(ctx.Done(), stream, 256, 10*time.Second) @@ -280,7 +280,7 @@ func getAvailableJobs(ctx context.Context, bheUrl url.URL, bheClient *http.Clien endpoint = bheUrl.ResolveReference(&url.URL{Path: "/api/v2/jobs/available"}) response basicResponse[[]models.ClientJob] ) - + panic(" ANOTHER WAY OF PANIC ✅✅✅✅") if req, err := rest.NewRequest(ctx, "GET", endpoint, nil, nil, nil); err != nil { return nil, err } else if res, err := do(bheClient, req); err != nil { From 6c5e7457397c33ae414da1a49b72a96df4eafe72 Mon Sep 17 00:00:00 2001 From: Ben Waples Date: Wed, 20 Mar 2024 14:06:01 -0700 Subject: [PATCH 26/26] remove hardcoded panic --- cmd/start.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/start.go b/cmd/start.go index 2f649b9..3ea2afd 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -280,7 +280,7 @@ func getAvailableJobs(ctx context.Context, bheUrl url.URL, bheClient *http.Clien endpoint = bheUrl.ResolveReference(&url.URL{Path: "/api/v2/jobs/available"}) response basicResponse[[]models.ClientJob] ) - panic(" ANOTHER WAY OF PANIC ✅✅✅✅") + if req, err := rest.NewRequest(ctx, "GET", endpoint, nil, nil, nil); err != nil { return nil, err } else if res, err := do(bheClient, req); err != nil {