Skip to content

Harden windowless kubectl exec authentication - #12950

Closed
brooke-hamilton wants to merge 4 commits into
mainfrom
brooke-hamilton-harden-windowless-kubectl-execution-and
Closed

Harden windowless kubectl exec authentication#12950
brooke-hamilton wants to merge 4 commits into
mainfrom
brooke-hamilton-harden-windowless-kubectl-execution-and

Conversation

@brooke-hamilton

@brooke-hamilton brooke-hamilton commented Sep 9, 2026

Copy link
Copy Markdown
Member

Summary

Guard every PostgreSQL pod lookup, readiness, backup, and restore kubectl launch with the shared process.IsWindowless() policy. In Windows no-console mode, inspect the selected kubeconfig exec-auth configuration without authenticating or invoking its plugin, and reject interactiveMode: Always with guidance to configure non-interactive Kubernetes credentials or use an attached console.

Use client-go's standard file-list merging, context selection, API defaults, and selected-config validation. Disable kubeconfig migration during this read-only check. Existing Radius config helpers load a single file, so they cannot supply kubectl's KUBECONFIG merge semantics here. Never, IfAvailable, and unused exec-auth configurations remain allowed; malformed selected configuration is not silently ignored. Explicit contexts remain usable when an unrelated current context is stale, and caller cancellation takes precedence over preflight errors.

Keep lookup/readiness/backup stdin at EOF and preserve restore's kubectl exec -i with every SQL byte followed by EOF. Preserve arguments, namespace, pod selection, caller cancellation, command error causes, diagnostics, and the existing --timeout=120s readiness limit. Readiness failures are no longer all described as timeouts. Attached-console and non-Windows authentication behavior remains unchanged.

Reason for change

Closes #12949.

Parent: #12887, section 3. PostgreSQL password flags and the other remaining parent tasks are not included.

This PR targets main. #12946 has merged as 25d92745e60973eedd04c337303477123cad922c. The branch has been rebased onto that current main commit, replaying only the four kubectl-specific commits after the old dependency head. The old dependency commits are no longer part of this PR, and pkg/process has no changes relative to main. The required process.IsWindowless() function now comes from main.

How to test

Run go test ./pkg/cli/pgbackup ./pkg/process -count=1 -timeout=2m. The fixtures use temporary kubeconfigs and fake executables; no cluster or real credentials are required. On Windows, the suite runs a no-console helper using FreeConsole and a real attached-console helper using CREATE_NEW_CONSOLE, and contains their descendants in a kill-on-close Job Object.

Coverage includes all four launch paths; actual EOF and large, exact SQL input; argument and output preservation; explicit/current context selection including stale current contexts; first-file-wins and split-file KUBECONFIG merging; default home loading; Always rejection before kubectl/plugin launch; rechecking backup/restore after lookup; Never/IfAvailable pass-through; API mode defaults/validation; broken config; no-backup no-op; ordinary exit errors; and caller cancellation before/during preflight and execution. Regression cases for stale current-context and canceled callers were reproduced against the original implementation before applying the review fixes.

After the rebase, the native Windows amd64 suites for pkg/cli/pgbackup and pkg/process passed on the updated dependencies from main. git range-diff confirms all four replayed patches are unchanged, and git diff --check passes. No conflict resolutions or new implementation changes were needed.

Earlier validation also covered Linux with -race, targeted golangci-lint (zero issues), Windows arm64 test-binary cross-compilation, the full CI spellcheck glob (573 files, zero issues), and Markdown checks for the updated contributor guide. Native arm64 execution is registered in the existing Windows CI matrix but was not run locally. Test-only safety bounds do not add production timeouts.

Markdown checks previously reported the same pre-existing table-format issues at docs/architecture/rad-cli.md lines 20, 27, and 35 on both the dependency baseline and this branch; unrelated tables are unchanged. No live-cluster or third-party authentication-plugin validation was performed. This guard does not guarantee completion for arbitrary plugins that ignore interaction modes or cancellation. Native arm64 execution remains a CI validation step.

File change summary

File Summary of change
pkg/cli/pgbackup/kubectl.go Shared kubectl constructor and read-only selected exec-auth guard, preserving explicit context selection and cancellation.
pkg/cli/pgbackup/pgbackup.go Route four command paths through the guard and preserve readiness diagnostics without a false timeout label.
pkg/cli/pgbackup/kubectl_test.go Fake executable fixtures and command/input/error/cancellation regressions.
pkg/cli/pgbackup/kubectl_config_test.go Context, merging, API defaults/validation, and default-home fixtures.
pkg/cli/pgbackup/kubectl_windows_test.go Native no-console/attached-console regression orchestration and owned-process cleanup.
pkg/cli/pgbackup/kubectl_other_test.go Non-Windows execution of the shared regression cases.
.github/workflows/unit-tests.yaml Add the package to the existing Windows amd64/arm64 job.
.cspellignore Recognize the Go package name used in the workflow.
docs/architecture/rad-cli.md Description of the guard, SQL input preservation, and limitations.
docs/contributing/contributing-code/contributing-code-cli/README.md Align the documented Windows command and coverage with CI.

@brooke-hamilton
brooke-hamilton changed the base branch from main to brooke-hamilton-windowless-process-policy September 9, 2026 23:24
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Kubeconfig context selection and preflight cancellation handling have unresolved moderate issues.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Hardens windowless Windows kubectl authentication for PostgreSQL operations.

Changes:

  • Adds kubeconfig exec-auth validation and shared kubectl construction.
  • Preserves stdin, cancellation, arguments, and readiness diagnostics.
  • Adds cross-platform and Windows regression coverage.
  • Updates CI, documentation, and spellcheck configuration.
File summaries
File Summary
pkg/cli/pgbackup/pgbackup.go Routes PostgreSQL operations through the guarded command helper.
pkg/cli/pgbackup/kubectl.go Adds command construction and exec-auth preflight validation.
pkg/cli/pgbackup/kubectl_windows_test.go Tests Windows console behavior and process cleanup.
pkg/cli/pgbackup/kubectl_test.go Covers command, input, error, and cancellation behavior.
pkg/cli/pgbackup/kubectl_other_test.go Enables shared regression tests on non-Windows systems.
pkg/cli/pgbackup/kubectl_config_test.go Tests kubeconfig selection, merging, defaults, and validation.
docs/architecture/rad-cli.md Documents the guard and its limitations.
.github/workflows/unit-tests.yaml Adds pgbackup to Windows CI tests.
.cspellignore Allows the pgbackup term in spellcheck.
Review details

Suppressed comments (2)

pkg/cli/pgbackup/kubectl.go:56

  • Passing an empty contextName makes client-go's ConfirmUsable validate config.CurrentContext for the existence check, even when overrides.CurrentContext selects an explicit context. If the current context is stale or missing but kubeContext is valid, this preflight rejects a command that kubectl would run with the explicit context. Pass kubeContext as the constructor's context name (leaving it empty only for current-context fallback), and add a regression case with a missing current context.
	selected, err := clientcmd.NewNonInteractiveClientConfig(*config, "", overrides, rules).MergedRawConfig()

pkg/cli/pgbackup/kubectl_windows_test.go:41

  • The attached-console filter does not match the actual subtest name broken config is inspected only without a console because it uses broken_config. Consequently this helper only exercises Always under an attached console and never verifies that malformed configuration remains pass-through there; match the real subtest name or add a dedicated attached-case filter.
		{name: "attached", flags: windows.CREATE_NEW_CONSOLE, tests: "^TestKubectlHelper$/^(Always|broken_config)"},
  • Files reviewed: 9/9 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pkg/cli/pgbackup/kubectl.go
Comment thread .github/workflows/unit-tests.yaml
@brooke-hamilton
brooke-hamilton marked this pull request as ready for review September 9, 2026 23:56
@brooke-hamilton
brooke-hamilton requested review from a team as code owners September 9, 2026 23:56
@brooke-hamilton
brooke-hamilton changed the base branch from brooke-hamilton-windowless-process-policy to main September 10, 2026 02:31
@brooke-hamilton
brooke-hamilton marked this pull request as draft September 10, 2026 02:37
brooke-hamilton and others added 4 commits September 11, 2026 09:46
Reject selected kubeconfig exec-auth requiring interaction before pgbackup kubectl launches, while preserving finite restore stdin and command diagnostics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com>
Honor explicit contexts even when current-context is stale, prefer caller cancellation over preflight errors, and align the documented Windows regression command with CI.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com>
@brooke-hamilton
brooke-hamilton force-pushed the brooke-hamilton-harden-windowless-kubectl-execution-and branch from b815a2f to da8010a Compare September 11, 2026 13:47
@radius-functional-tests

radius-functional-tests Bot commented Sep 11, 2026

Copy link
Copy Markdown

Radius functional test overview

🔍 Go to test action run

Click here to see the test run details
Name Value
Repository radius-project/radius
Commit ref da8010a
Unique ID func14b2cfb3b5
Image tag pr-func14b2cfb3b5
  • Dapr: 1.14.4
  • Azure KeyVault CSI driver: 1.4.2
  • Azure Workload identity webhook: 1.3.0
  • Bicep recipe location ghcr.io/radius-project/dev/test/testrecipes/test-bicep-recipes/<name>:pr-func14b2cfb3b5
  • Terraform recipe location http://tf-module-server.radius-test-tf-module-server.svc.cluster.local/<name>.zip (in cluster)
  • applications-rp test image location: ghcr.io/radius-project/dev/applications-rp:pr-func14b2cfb3b5
  • dynamic-rp test image location: ghcr.io/radius-project/dev/dynamic-rp:pr-func14b2cfb3b5
  • controller test image location: ghcr.io/radius-project/dev/controller:pr-func14b2cfb3b5
  • ucp test image location: ghcr.io/radius-project/dev/ucpd:pr-func14b2cfb3b5
  • deployment-engine test image location: ghcr.io/radius-project/deployment-engine:latest

Test Status

⌛ Building Radius and pushing container images for functional tests...
✅ Container images build succeeded
⌛ Publishing Bicep Recipes for functional tests...
✅ Recipe publishing succeeded
⌛ Starting corerp-cloud functional tests...
⌛ Starting ucp-cloud functional tests...
✅ ucp-cloud functional tests succeeded
✅ corerp-cloud functional tests succeeded

@github-actions

Copy link
Copy Markdown

Unit Tests

    2 files  ± 0    460 suites  ±0   11m 29s ⏱️ + 2m 15s
6 656 tests +73  6 653 ✅ +72  3 💤 +1  0 ❌ ±0 
7 957 runs  +73  7 954 ✅ +72  3 💤 +1  0 ❌ ±0 

Results for commit da8010a. ± Comparison against base commit 25d9274.

@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 71.79487% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.96%. Comparing base (25d9274) to head (da8010a).

Files with missing lines Patch % Lines
pkg/cli/pgbackup/kubectl.go 73.07% 7 Missing ⚠️
pkg/cli/pgbackup/pgbackup.go 69.23% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12950      +/-   ##
==========================================
+ Coverage   59.78%   59.96%   +0.17%     
==========================================
  Files         778      779       +1     
  Lines       45918    45944      +26     
==========================================
+ Hits        27454    27551      +97     
+ Misses      18464    18393      -71     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@brooke-hamilton

Copy link
Copy Markdown
Member Author

Closing for now because this is not a priority. We can revisit the scope of this work later.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Harden windowless kubectl execution and Kubernetes authentication

2 participants