Skip to content

Command cleanup#140

Open
Joeavaikath wants to merge 5 commits intomigtools:oadp-devfrom
Joeavaikath:command-cleanup
Open

Command cleanup#140
Joeavaikath wants to merge 5 commits intomigtools:oadp-devfrom
Joeavaikath:command-cleanup

Conversation

@Joeavaikath
Copy link
Contributor

@Joeavaikath Joeavaikath commented Feb 19, 2026

Why the changes were made

  • Removes the -n flag test, which is redundant: the flag will appear if BindFlags is called from the veleroClient
  • Add a check for GOOS before make install runs
  • Cleanup client.go
  • Fix NABSL commands not getting the right resource, NonAdminBackupStorageLocation Request

How to test the changes made

oc oadp nabsl-request describe should now work correctly

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced describe output with colorized phases and improved field alignment.
  • Bug Fixes

    • Added validation to prevent builds with undefined target binaries.
  • Changes

    • Removed bug, datamover, repo, and repomantenance CLI commands.
    • Simplified NABSL request lookup and validation flows.
    • Removed all-namespaces flag from get command.

Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
Signed-off-by: Joseph <jvaikath@redhat.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

This PR refactors NABSL request command handling by removing namespace flag support, eliminating validation hooks, repositioning UUID/name lookups to use direct admin namespace queries, improving output formatting with color and alignment, removing unused CLI commands, and pruning indirect dependencies.

Changes

Cohort / File(s) Summary
NABSL Request Command Simplification
cmd/nabsl-request/approve.go, cmd/nabsl-request/reject.go
Removed no-op Validate methods and their invocations from the Run paths, simplifying command execution to Complete → Run flow.
NABSL Request Describe Refactoring
cmd/nabsl-request/describe.go
Changed from listing NABSLs in current namespace to direct UUID/name lookup in admin namespace. Replaced field Name with UUID_Name. Added structured output formatting with alignment, color-coded phase, and utility-based labels/annotations printing.
NABSL Request Get Simplification
cmd/nabsl-request/get.go
Removed AllNamespaces flag and BindFlags method. Refactored to use FindNABSLRequestByNameOrUUID for name resolution and simplified List to always scope admin namespace. Removed Validate method.
Shared Utilities
cmd/shared/output.go
New file introducing three exported formatting utilities: Indent (prefix each line), ColorizePhase (ANSI color codes by phase), and PrintLabelsOrAnnotations (OC-style aligned output).
NABSL Request Lookup
cmd/shared/nabsl_requests.go
Updated FindNABSLRequestByNameOrUUID to explicitly try Get first, then fallback to List-and-match on SourceNonAdminBSL.Name with proper error handling.
Client Initialization
cmd/shared/client.go
Refactored NewClientWithScheme to create scheme and REST config upfront before timeout handling, eliminating duplicate code paths and improving clarity.
CLI Root Command
cmd/root.go
Removed command registrations for bug, datamover, repo, and repomaintenance subcommands.
Build & Testing
Makefile, cmd/namespace_flag_test.go
Added GOOS validation in Makefile install target; deleted namespace_flag_test.go test file.
Dependency Management
go.mod
Pruned large number of indirect dependencies, reducing transitive dependency footprint without adding new direct dependencies.

Sequence Diagram(s)

sequenceDiagram
    actor Client as CLI Client
    participant Find as FindNABSL<br/>RequestByNameOrUUID
    participant API as Admin Namespace<br/>API Server
    participant Desc as Describe Output
    
    Client->>Find: Resolve UUID_Name to request name
    Find->>API: Get request by UUID
    alt UUID found
        API-->>Find: Return request
    else UUID not found
        Find->>API: List all requests in namespace
        API-->>Find: Return request list
        Find->>Find: Match on SourceNonAdminBSL.Name
    end
    Find-->>Client: Return canonical request name
    
    Client->>API: Get full request details
    API-->>Client: Return request object
    
    Client->>Desc: Format and print with structure
    Desc->>Desc: Apply color to phase
    Desc->>Desc: Align labels/annotations
    Desc-->>Client: Output formatted description
Loading
sequenceDiagram
    actor Client as CLI Client
    participant Find as FindNABSL<br/>RequestByNameOrUUID
    participant API as Admin Namespace<br/>API Server
    participant Output as Output Formatter
    
    Client->>Find: Resolve name or UUID
    Find->>API: Attempt Get by UUID
    alt Found by UUID
        API-->>Find: Return single request
        Find-->>Client: Return request name
    else Not found
        Find->>API: List all requests in admin namespace
        API-->>Find: Return filtered list
        Find-->>Client: Return matching request name
    end
    
    Client->>API: Get or List requests
    API-->>Client: Return result
    
    Client->>Output: Format for display
    Output-->>Client: Rendered output
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Bugfixes #138: Directly related refactoring of nabsl-request retrieval logic, modifying cmd/nabsl-request/get.go behavior and FindNABSLRequestByNameOrUUID lookup flow.

Suggested labels

ai-generated-test

Suggested reviewers

  • kaovilai
  • mpryc
  • stillalearner

Poem

🐰 A hop through the NABSL requests, now fleet,
UUID lookups direct—no listing to greet,
Colors bloom on the phases, aligned and so neat,
Commands streamlined away, the refactor's complete! 🎨✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Command cleanup' is partially related to the changeset but fails to capture the main changes: fixing NABSL commands, adding GOOS validation, and removing subcommands. Consider using a more specific title like 'Fix NABSL describe and remove subcommands' to better convey the primary changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description addresses most required sections with explanations of changes and testing instructions, but lacks detail on the impact and rationale for some significant changes like removing subcommands.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: Joseph <jvaikath@redhat.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/shared/nabsl_requests.go (1)

36-50: ⚠️ Potential issue | 🟠 Major

Return non-NotFound errors from the UUID lookup instead of silently falling back.

Currently, any Get error triggers a list fallback, which masks auth, network, and permission failures—allowing the function to surface a misleading "request not found" error at the end when the real problem was elsewhere.

Only proceed to the fallback when the error is explicitly a NotFound error. For all other errors, return immediately with proper context.

🔧 Suggested fix
 import (
 	"context"
 	"fmt"
 
 	kbclient "sigs.k8s.io/controller-runtime/pkg/client"
+	"k8s.io/apimachinery/pkg/api/errors"
 
 	nacv1alpha1 "github.com/migtools/oadp-non-admin/api/v1alpha1"
 )
@@
 	err := client.Get(ctx, kbclient.ObjectKey{
 		Name:      nameOrUUID,
 		Namespace: adminNamespace,
 	}, &testRequest)
 	if err == nil {
 		return nameOrUUID, nil
 	}
+	if !errors.IsNotFound(err) {
+		return "", fmt.Errorf("failed to get request %q: %w", nameOrUUID, err)
+	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/shared/nabsl_requests.go` around lines 36 - 50, The UUID lookup currently
treats any error from client.Get(ctx, kbclient.ObjectKey{Name: nameOrUUID,
Namespace: adminNamespace}, &testRequest) as a signal to fallback to listing;
change this so only a NotFound error falls through to the list path—if
client.Get returns a non-NotFound error (e.g. network/auth/permission error)
return that error immediately with context (wrap/format it) instead of
proceeding; keep the fallback behavior when the error is explicitly a NotFound
(use the appropriate IsNotFound helper for your imports) and then continue with
the existing client.List logic using requestList and adminNamespace.
🧹 Nitpick comments (1)
cmd/nabsl-request/approve.go (1)

87-89: Minor: Remove leftover empty line.

Line 88 appears to be a leftover from removing the Validate() call. Consider removing the empty line to keep the function body clean.

🔧 Suggested cleanup
 func (o *ApproveOptions) Run(c *cobra.Command, f client.Factory) error {
-
 	adminNS := f.Namespace()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/nabsl-request/approve.go` around lines 87 - 89, The function
ApproveOptions.Run contains an extra blank line between the variable assignment
adminNS := f.Namespace() and surrounding code; remove that leftover empty line
so the function body is compact and the adminNS assignment is directly adjacent
to the next statement.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/nabsl-request/describe.go`:
- Around line 108-184: The code dereferences spec.ObjectStorage without checking
for nil (when reading spec.ObjectStorage.Bucket and spec.ObjectStorage.Prefix),
which can panic for partial/invalid requests; update the block that handles
source.RequestedSpec (the Requested BackupStorageLocation Spec logic for
variable spec := source.RequestedSpec) to first check if spec.ObjectStorage !=
nil before accessing its fields and only print "Object Storage Bucket" and
"Prefix" when ObjectStorage is non-nil; retain printing other spec fields as-is
and ensure the nil check guards both Bucket and Prefix accesses.

---

Outside diff comments:
In `@cmd/shared/nabsl_requests.go`:
- Around line 36-50: The UUID lookup currently treats any error from
client.Get(ctx, kbclient.ObjectKey{Name: nameOrUUID, Namespace: adminNamespace},
&testRequest) as a signal to fallback to listing; change this so only a NotFound
error falls through to the list path—if client.Get returns a non-NotFound error
(e.g. network/auth/permission error) return that error immediately with context
(wrap/format it) instead of proceeding; keep the fallback behavior when the
error is explicitly a NotFound (use the appropriate IsNotFound helper for your
imports) and then continue with the existing client.List logic using requestList
and adminNamespace.

---

Nitpick comments:
In `@cmd/nabsl-request/approve.go`:
- Around line 87-89: The function ApproveOptions.Run contains an extra blank
line between the variable assignment adminNS := f.Namespace() and surrounding
code; remove that leftover empty line so the function body is compact and the
adminNS assignment is directly adjacent to the next statement.

Comment on lines +108 to +184
// Name and Namespace
fmt.Printf("Name: %s\n", request.Name)
fmt.Printf("Namespace: %s\n", request.Namespace)

// Labels
shared.PrintLabelsOrAnnotations(os.Stdout, "Labels: ", request.Labels)

fmt.Printf("Labels:\t%s\n", formatLabels(request.Labels))
fmt.Printf("Annotations:\t%s\n", formatLabels(request.Annotations))
// Annotations
shared.PrintLabelsOrAnnotations(os.Stdout, "Annotations: ", request.Annotations)

fmt.Printf("Phase:\t%s\n", request.Status.Phase)
fmt.Printf("\n")

// Phase (with color)
fmt.Printf("Phase: %s\n", shared.ColorizePhase(string(request.Status.Phase)))

fmt.Printf("\n")

// Approval Decision
if request.Spec.ApprovalDecision != "" {
fmt.Printf("Approval Decision:\t%s\n", request.Spec.ApprovalDecision)
fmt.Printf("Approval Decision: %s\n", request.Spec.ApprovalDecision)
fmt.Printf("\n")
}

// Requested NonAdminBackupStorageLocation
if request.Status.SourceNonAdminBSL != nil {
source := request.Status.SourceNonAdminBSL
fmt.Printf("Requested NonAdminBackupStorageLocation:\n")
fmt.Printf(" Name:\t%s\n", source.Name)
fmt.Printf(" Namespace:\t%s\n", source.Namespace)
fmt.Printf(" Name: %s\n", source.Name)
fmt.Printf(" Namespace: %s\n", source.Namespace)

if source.NACUUID != "" {
fmt.Printf(" NACUUID:\t%s\n", source.NACUUID)
fmt.Printf(" NACUUID: %s\n", source.NACUUID)
}

fmt.Printf("\n")

// Requested BackupStorageLocation Spec
if source.RequestedSpec != nil {
spec := source.RequestedSpec
fmt.Printf("Requested BackupStorageLocation Spec:\n")
fmt.Printf(" Provider:\t%s\n", spec.Provider)
fmt.Printf(" Object Storage Bucket:\t%s\n", spec.ObjectStorage.Bucket)
fmt.Printf(" Provider: %s\n", spec.Provider)
fmt.Printf(" Object Storage Bucket: %s\n", spec.ObjectStorage.Bucket)

if spec.ObjectStorage.Prefix != "" {
fmt.Printf(" Prefix:\t%s\n", spec.ObjectStorage.Prefix)
fmt.Printf(" Prefix: %s\n", spec.ObjectStorage.Prefix)
}

if len(spec.Config) > 0 {
fmt.Printf(" Config:\t%s\n", formatLabels(spec.Config))
fmt.Printf(" Config:\n")
configKeys := make([]string, 0, len(spec.Config))
for k := range spec.Config {
configKeys = append(configKeys, k)
}
sort.Strings(configKeys)
for _, k := range configKeys {
fmt.Printf(" %s: %s\n", k, spec.Config[k])
}
}

if spec.AccessMode != "" {
fmt.Printf(" Access Mode:\t%s\n", spec.AccessMode)
fmt.Printf(" Access Mode: %s\n", spec.AccessMode)
}

if spec.BackupSyncPeriod != nil {
fmt.Printf(" Backup Sync Period:\t%s\n", spec.BackupSyncPeriod.String())
fmt.Printf(" Backup Sync Period: %s\n", spec.BackupSyncPeriod.String())
}

if spec.ValidationFrequency != nil {
fmt.Printf(" Validation Frequency:\t%s\n", spec.ValidationFrequency.String())
fmt.Printf(" Validation Frequency: %s\n", spec.ValidationFrequency.String())
}

fmt.Printf("\n")
}
}

fmt.Printf("Creation Timestamp:\t%s\n", request.CreationTimestamp.String())
// Creation Timestamp
fmt.Printf("Creation Timestamp: %s\n", request.CreationTimestamp.Time.Format("2006-01-02 15:04:05 -0700 MST"))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n "type BackupStorageLocationSpec" -A 20 -B 2 -g '*.go'

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

rg -n "ObjectStorage" -B 2 -A 2 -g '*.go' | head -100

Repository: migtools/oadp-cli

Length of output: 1589


🏁 Script executed:

fd -e go -type f | xargs grep -l "BackupStorageLocationSpec" | head -10

Repository: migtools/oadp-cli

Length of output: 231


🏁 Script executed:

rg -n "ObjectStorage.*\*" -B 1 -A 1 -g '*.go'

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

rg -n "struct {" -A 30 | grep -A 30 "BackupStorageLocationSpec"

Repository: migtools/oadp-cli

Length of output: 140


🏁 Script executed:

find . -name "*.go" -type f -exec grep -l "BackupStorageLocationSpec" {} \; | head -5

Repository: migtools/oadp-cli

Length of output: 117


🏁 Script executed:

rg "BackupStorageLocationSpec\|ObjectStorage" ./cmd/nabsl-request/describe.go -B 2 -A 2

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

cat ./cmd/nabsl-request/describe.go | head -50

Repository: migtools/oadp-cli

Length of output: 1579


🏁 Script executed:

rg "import" ./cmd/nabsl-request/describe.go -A 20

Repository: migtools/oadp-cli

Length of output: 579


🏁 Script executed:

cat -n ./cmd/nabsl-request/describe.go | sed -n '130,160p'

Repository: migtools/oadp-cli

Length of output: 1307


🏁 Script executed:

rg -n "spec.ObjectStorage" ./cmd/nabsl-request/describe.go

Repository: migtools/oadp-cli

Length of output: 269


🏁 Script executed:

rg -n "RequestedSpec.*BackupStorageLocationSpec" . -B 2 -A 2 --type go

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

rg -n "type.*BackupStorageLocationSpec" . --type go -A 25

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

rg -n "ObjectStorage.*\*ObjectStorageLocation" . --type go

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

grep -r "ObjectStorage" ./cmd/non-admin/bsl/get.go -B 3 -A 3 | head -20

Repository: migtools/oadp-cli

Length of output: 465


🏁 Script executed:

grep -r "ObjectStorage" . --include="*.go" | grep "type\|struct" | head -20

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

rg -n "\.ObjectStorage\s*\*" . --type go -B 2 -A 2

Repository: migtools/oadp-cli

Length of output: 43


🏁 Script executed:

web_search
Velero BackupStorageLocationSpec ObjectStorage pointer

Repository: migtools/oadp-cli

Length of output: 156


🌐 Web query:

Velero BackupStorageLocationSpec ObjectStorage field type

💡 Result:

In Velero’s Go API, .spec.objectStorage is a pointer to ObjectStorageLocation:

  • type StorageType struct { ObjectStorage *ObjectStorageLocation \json:"objectStorage"` }(andBackupStorageLocationSpecinlinesStorageType`). [1]

In the CRD/OpenAPI schema, .spec.objectStorage is an object of kind ObjectStorageLocation. [2][3]

Sources: [1] [2] [3]


🏁 Script executed:

rg -n "BackupStorageLocationSpec" . --type go -B 3 -A 15 | grep -A 15 "ObjectStorage"

Repository: migtools/oadp-cli

Length of output: 2148


🏁 Script executed:

grep -n "source.RequestedSpec" ./cmd/nabsl-request/describe.go -B 5 -A 20

Repository: migtools/oadp-cli

Length of output: 948


Guard against nil ObjectStorage in the requested spec.

spec.ObjectStorage is a pointer in the Velero BSL spec; if it's nil (invalid/partial request), dereferencing it at lines 149 and 151 will panic. Add a nil check before accessing its fields.

🛡️ Suggested fix
-			fmt.Printf("  Provider:                  %s\n", spec.Provider)
-			fmt.Printf("  Object Storage Bucket:     %s\n", spec.ObjectStorage.Bucket)
-
-			if spec.ObjectStorage.Prefix != "" {
-				fmt.Printf("  Prefix:                    %s\n", spec.ObjectStorage.Prefix)
-			}
+			fmt.Printf("  Provider:                  %s\n", spec.Provider)
+			if spec.ObjectStorage != nil {
+				fmt.Printf("  Object Storage Bucket:     %s\n", spec.ObjectStorage.Bucket)
+				if spec.ObjectStorage.Prefix != "" {
+					fmt.Printf("  Prefix:                    %s\n", spec.ObjectStorage.Prefix)
+				}
+			} else {
+				fmt.Printf("  Object Storage Bucket:     <none>\n")
+			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Name and Namespace
fmt.Printf("Name: %s\n", request.Name)
fmt.Printf("Namespace: %s\n", request.Namespace)
// Labels
shared.PrintLabelsOrAnnotations(os.Stdout, "Labels: ", request.Labels)
fmt.Printf("Labels:\t%s\n", formatLabels(request.Labels))
fmt.Printf("Annotations:\t%s\n", formatLabels(request.Annotations))
// Annotations
shared.PrintLabelsOrAnnotations(os.Stdout, "Annotations: ", request.Annotations)
fmt.Printf("Phase:\t%s\n", request.Status.Phase)
fmt.Printf("\n")
// Phase (with color)
fmt.Printf("Phase: %s\n", shared.ColorizePhase(string(request.Status.Phase)))
fmt.Printf("\n")
// Approval Decision
if request.Spec.ApprovalDecision != "" {
fmt.Printf("Approval Decision:\t%s\n", request.Spec.ApprovalDecision)
fmt.Printf("Approval Decision: %s\n", request.Spec.ApprovalDecision)
fmt.Printf("\n")
}
// Requested NonAdminBackupStorageLocation
if request.Status.SourceNonAdminBSL != nil {
source := request.Status.SourceNonAdminBSL
fmt.Printf("Requested NonAdminBackupStorageLocation:\n")
fmt.Printf(" Name:\t%s\n", source.Name)
fmt.Printf(" Namespace:\t%s\n", source.Namespace)
fmt.Printf(" Name: %s\n", source.Name)
fmt.Printf(" Namespace: %s\n", source.Namespace)
if source.NACUUID != "" {
fmt.Printf(" NACUUID:\t%s\n", source.NACUUID)
fmt.Printf(" NACUUID: %s\n", source.NACUUID)
}
fmt.Printf("\n")
// Requested BackupStorageLocation Spec
if source.RequestedSpec != nil {
spec := source.RequestedSpec
fmt.Printf("Requested BackupStorageLocation Spec:\n")
fmt.Printf(" Provider:\t%s\n", spec.Provider)
fmt.Printf(" Object Storage Bucket:\t%s\n", spec.ObjectStorage.Bucket)
fmt.Printf(" Provider: %s\n", spec.Provider)
fmt.Printf(" Object Storage Bucket: %s\n", spec.ObjectStorage.Bucket)
if spec.ObjectStorage.Prefix != "" {
fmt.Printf(" Prefix:\t%s\n", spec.ObjectStorage.Prefix)
fmt.Printf(" Prefix: %s\n", spec.ObjectStorage.Prefix)
}
if len(spec.Config) > 0 {
fmt.Printf(" Config:\t%s\n", formatLabels(spec.Config))
fmt.Printf(" Config:\n")
configKeys := make([]string, 0, len(spec.Config))
for k := range spec.Config {
configKeys = append(configKeys, k)
}
sort.Strings(configKeys)
for _, k := range configKeys {
fmt.Printf(" %s: %s\n", k, spec.Config[k])
}
}
if spec.AccessMode != "" {
fmt.Printf(" Access Mode:\t%s\n", spec.AccessMode)
fmt.Printf(" Access Mode: %s\n", spec.AccessMode)
}
if spec.BackupSyncPeriod != nil {
fmt.Printf(" Backup Sync Period:\t%s\n", spec.BackupSyncPeriod.String())
fmt.Printf(" Backup Sync Period: %s\n", spec.BackupSyncPeriod.String())
}
if spec.ValidationFrequency != nil {
fmt.Printf(" Validation Frequency:\t%s\n", spec.ValidationFrequency.String())
fmt.Printf(" Validation Frequency: %s\n", spec.ValidationFrequency.String())
}
fmt.Printf("\n")
}
}
fmt.Printf("Creation Timestamp:\t%s\n", request.CreationTimestamp.String())
// Creation Timestamp
fmt.Printf("Creation Timestamp: %s\n", request.CreationTimestamp.Time.Format("2006-01-02 15:04:05 -0700 MST"))
// Name and Namespace
fmt.Printf("Name: %s\n", request.Name)
fmt.Printf("Namespace: %s\n", request.Namespace)
// Labels
shared.PrintLabelsOrAnnotations(os.Stdout, "Labels: ", request.Labels)
// Annotations
shared.PrintLabelsOrAnnotations(os.Stdout, "Annotations: ", request.Annotations)
fmt.Printf("\n")
// Phase (with color)
fmt.Printf("Phase: %s\n", shared.ColorizePhase(string(request.Status.Phase)))
fmt.Printf("\n")
// Approval Decision
if request.Spec.ApprovalDecision != "" {
fmt.Printf("Approval Decision: %s\n", request.Spec.ApprovalDecision)
fmt.Printf("\n")
}
// Requested NonAdminBackupStorageLocation
if request.Status.SourceNonAdminBSL != nil {
source := request.Status.SourceNonAdminBSL
fmt.Printf("Requested NonAdminBackupStorageLocation:\n")
fmt.Printf(" Name: %s\n", source.Name)
fmt.Printf(" Namespace: %s\n", source.Namespace)
if source.NACUUID != "" {
fmt.Printf(" NACUUID: %s\n", source.NACUUID)
}
fmt.Printf("\n")
// Requested BackupStorageLocation Spec
if source.RequestedSpec != nil {
spec := source.RequestedSpec
fmt.Printf("Requested BackupStorageLocation Spec:\n")
fmt.Printf(" Provider: %s\n", spec.Provider)
if spec.ObjectStorage != nil {
fmt.Printf(" Object Storage Bucket: %s\n", spec.ObjectStorage.Bucket)
if spec.ObjectStorage.Prefix != "" {
fmt.Printf(" Prefix: %s\n", spec.ObjectStorage.Prefix)
}
} else {
fmt.Printf(" Object Storage Bucket: <none>\n")
}
if len(spec.Config) > 0 {
fmt.Printf(" Config:\n")
configKeys := make([]string, 0, len(spec.Config))
for k := range spec.Config {
configKeys = append(configKeys, k)
}
sort.Strings(configKeys)
for _, k := range configKeys {
fmt.Printf(" %s: %s\n", k, spec.Config[k])
}
}
if spec.AccessMode != "" {
fmt.Printf(" Access Mode: %s\n", spec.AccessMode)
}
if spec.BackupSyncPeriod != nil {
fmt.Printf(" Backup Sync Period: %s\n", spec.BackupSyncPeriod.String())
}
if spec.ValidationFrequency != nil {
fmt.Printf(" Validation Frequency: %s\n", spec.ValidationFrequency.String())
}
fmt.Printf("\n")
}
}
// Creation Timestamp
fmt.Printf("Creation Timestamp: %s\n", request.CreationTimestamp.Time.Format("2006-01-02 15:04:05 -0700 MST"))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/nabsl-request/describe.go` around lines 108 - 184, The code dereferences
spec.ObjectStorage without checking for nil (when reading
spec.ObjectStorage.Bucket and spec.ObjectStorage.Prefix), which can panic for
partial/invalid requests; update the block that handles source.RequestedSpec
(the Requested BackupStorageLocation Spec logic for variable spec :=
source.RequestedSpec) to first check if spec.ObjectStorage != nil before
accessing its fields and only print "Object Storage Bucket" and "Prefix" when
ObjectStorage is non-nil; retain printing other spec fields as-is and ensure the
nil check guards both Bucket and Prefix accesses.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments