Nil pointer dereference in plugin version check closes #4747 (#4897)

* Unskip test demonstrating bug #4747: Nil pointer dereference in plugin version check

Removed the GlobalConfig initialization workaround from setupTestEnvironment()
and added TestPluginVersionCheckWithNilGlobalConfig to demonstrate the bug.

The test will panic at runner.go:106 when attempting to access
steampipeconfig.GlobalConfig.PluginVersions without a nil check.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix #4747: Add nil check for GlobalConfig in version checks

Wraps both CLI and plugin version checks with a nil check for
steampipeconfig.GlobalConfig. This prevents panics when the runner
is invoked before full configuration initialization, such as in
test environments or unusual startup scenarios.

The previous fix only addressed the plugin version check at line 109,
but the CLI version check at line 104 also triggers a panic through
fetchAvailableCLIVersion -> BuildRequestPayload which accesses
GlobalConfig internally.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Nathan Wallace
2025-11-16 16:22:46 -05:00
committed by GitHub
parent f15764e506
commit ea6a7a09cc
2 changed files with 49 additions and 16 deletions

View File

@@ -96,15 +96,19 @@ func (r *Runner) run(ctx context.Context) {
waitGroup := sync.WaitGroup{}
if r.options.runUpdateCheck {
// check whether an updated version is available
r.runJobAsync(ctx, func(c context.Context) {
availableCliVersion, _ = fetchAvailableCLIVersion(ctx, r.currentState.InstallationID)
}, &waitGroup)
// Only perform version checks if GlobalConfig is initialized
// This can be nil during tests or unusual startup scenarios
if steampipeconfig.GlobalConfig != nil {
// check whether an updated version is available
r.runJobAsync(ctx, func(c context.Context) {
availableCliVersion, _ = fetchAvailableCLIVersion(ctx, r.currentState.InstallationID)
}, &waitGroup)
// check whether an updated version is available
r.runJobAsync(ctx, func(ctx context.Context) {
availablePluginVersions = plugin.GetAllUpdateReport(ctx, r.currentState.InstallationID, steampipeconfig.GlobalConfig.PluginVersions)
}, &waitGroup)
// check whether an updated version is available
r.runJobAsync(ctx, func(ctx context.Context) {
availablePluginVersions = plugin.GetAllUpdateReport(ctx, r.currentState.InstallationID, steampipeconfig.GlobalConfig.PluginVersions)
}, &waitGroup)
}
}
// remove log files older than 7 days

View File

@@ -12,7 +12,6 @@ import (
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/turbot/pipe-fittings/v2/app_specific"
"github.com/turbot/steampipe/v2/pkg/steampipeconfig"
)
// setupTestEnvironment sets up the necessary environment for tests
@@ -28,13 +27,6 @@ func setupTestEnvironment(t *testing.T) {
// Set the install directory to the temp directory
app_specific.InstallDir = filepath.Join(tempDir, ".steampipe")
// Initialize GlobalConfig to prevent nil pointer dereference
// BUG FOUND: runner.go:106 accesses steampipeconfig.GlobalConfig.PluginVersions
// without checking if GlobalConfig is nil, causing a panic
if steampipeconfig.GlobalConfig == nil {
steampipeconfig.GlobalConfig = &steampipeconfig.SteampipeConfig{}
}
}
// TestRunTasksGoroutineCleanup tests that goroutines are properly cleaned up
@@ -367,3 +359,40 @@ func TestPreHooksExecution(t *testing.T) {
// This test documents the expected behavior
t.Log("Pre-hook execution depends on shouldRun() returning true")
}
// TestPluginVersionCheckWithNilGlobalConfig tests that the plugin version check
// handles nil GlobalConfig gracefully. This is a regression test for bug #4747.
func TestPluginVersionCheckWithNilGlobalConfig(t *testing.T) {
// DO NOT call setupTestEnvironment here - we want GlobalConfig to be nil
// to reproduce the bug from issue #4747
// Create a temporary directory for test state
tempDir, err := os.MkdirTemp("", "steampipe-task-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
t.Cleanup(func() {
os.RemoveAll(tempDir)
})
// Set the install directory to the temp directory
app_specific.InstallDir = filepath.Join(tempDir, ".steampipe")
// Create a runner with update checks enabled
config := newRunConfig()
config.runUpdateCheck = true
runner := newRunner(config)
// Create a context with immediate cancellation to avoid network operations
// and race conditions with the CLI version check goroutine
ctx, cancel := context.WithCancel(context.Background())
cancel()
// Before the fix, this would panic at runner.go:106 when trying to access
// steampipeconfig.GlobalConfig.PluginVersions
// After the fix, it should handle nil GlobalConfig gracefully
runner.run(ctx)
// If we got here without panic, the fix is working
t.Log("runner.run() completed without panic when GlobalConfig is nil and update checks are enabled")
}