Skip to content

fix(cloud): request required organization scopes#164

Open
flemzord wants to merge 1 commit into
mainfrom
fix/cloud-required-scopes
Open

fix(cloud): request required organization scopes#164
flemzord wants to merge 1 commit into
mainfrom
fix/cloud-required-scopes

Conversation

@flemzord

Copy link
Copy Markdown
Member

Summary

  • request command-specific organization scopes before membership API calls
  • refresh root token access after stack creation before creating the stack client
  • sort stack versions semantically when presenting create/upgrade choices

Tests

  • go test ./cmd/stack ./cmd/cloud/regions ./pkg
  • go test ./...

@flemzord flemzord requested a review from a team as a code owner June 11, 2026 09:52
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR introduces OAuth scope-based access control to organization membership API operations. It adds version sorting utilities, token refresh and scope validation helpers, refactors client construction to require scopes, and integrates scope enforcement into stack and region commands.

Changes

OAuth Scope-Based Access Control

Layer / File(s) Summary
Version sorting utilities
cmd/stack/version_sort.go, cmd/stack/version_sort_test.go
Stable sorters for component versions and version strings using semver-aware normalization, with support for prerelease and short formats. Includes full unit test coverage for sorting order and edge cases.
Token refresh and scope validation
pkg/authentication.go, pkg/authentication_test.go
RefreshRootTokens refreshes tokens with conditional ID token override. AccessToken methods compute missing scopes and validate scope presence.
Scope-aware client construction
pkg/clients.go
EnsureOrganizationAccessWithScopes validates required scopes and re-authenticates if missing. New NewMembershipClientForOrganizationWithScopes and flag-based helper enforce scopes during client creation.
Command integrations with scope requirements
cmd/cloud/regions/list.go, cmd/stack/create.go, cmd/stack/upgrade.go
Stack create uses dynamic scopes based on flags, applies version sorting to region versions, and validates stack access. Stack upgrade uses version sorting for target versions. Region list requests organization:ListRegions scope.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Scopes now guide the auth dance,
From tokens fresh to client stance,
Versions sort by semver's grace,
Stack and regions find their place! 🎯

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: requesting required organization scopes before making membership API calls, which is the primary refactoring across multiple files.
Description check ✅ Passed The description is clearly related to the changeset, summarizing the three main objectives: requesting organization scopes, refreshing root tokens, and sorting stack versions semantically.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cloud-required-scopes

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/stack/version_sort_test.go (1)

52-56: 💤 Low value

Consider adding test cases for invalid version inputs.

The test only covers valid semver cases. Given the behavior in isVersionNewerThanCurrent for invalid inputs (always returns true), adding test cases for edge scenarios would help document and verify intended behavior:

  • Invalid candidate vs valid current
  • Valid candidate vs invalid current
  • Both invalid
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/stack/version_sort_test.go` around lines 52 - 56, Add tests to cover
invalid-version edge cases for isVersionNewerThanCurrent: assert that when the
candidate is invalid and current is valid the function returns true, when the
candidate is valid and current is invalid it returns true, and when both
candidate and current are invalid it returns true; place these new assertions
alongside the existing cases in TestIsVersionNewerThanCurrent so the intended
"invalid inputs => true" behavior is documented and verified.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/stack/version_sort.go`:
- Around line 41-48: The function isVersionNewerThanCurrent currently treats any
non-parseable candidate as newer; change it so that if normalizeSemver reports
the candidate is invalid you return false (do not treat invalid candidates as
upgrades). Keep the existing behavior of comparing normalizedCandidate and
normalizedCurrent when both valid, and if candidate is valid but current is not
you may still return true; update the logic in isVersionNewerThanCurrent (which
calls normalizeSemver and semver.Compare) so invalid candidate -> false,
validCandidate && validCurrent -> use semver.Compare, otherwise (validCandidate
&& !validCurrent) -> true.

---

Nitpick comments:
In `@cmd/stack/version_sort_test.go`:
- Around line 52-56: Add tests to cover invalid-version edge cases for
isVersionNewerThanCurrent: assert that when the candidate is invalid and current
is valid the function returns true, when the candidate is valid and current is
invalid it returns true, and when both candidate and current are invalid it
returns true; place these new assertions alongside the existing cases in
TestIsVersionNewerThanCurrent so the intended "invalid inputs => true" behavior
is documented and verified.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f9ac3bf7-3778-43bc-9ba2-de3d526cf53d

📥 Commits

Reviewing files that changed from the base of the PR and between bfe70b0 and 895cc64.

📒 Files selected for processing (8)
  • cmd/cloud/regions/list.go
  • cmd/stack/create.go
  • cmd/stack/upgrade.go
  • cmd/stack/version_sort.go
  • cmd/stack/version_sort_test.go
  • pkg/authentication.go
  • pkg/authentication_test.go
  • pkg/clients.go

Comment thread cmd/stack/version_sort.go
Comment on lines +41 to +48
func isVersionNewerThanCurrent(candidate, current string) bool {
normalizedCandidate, validCandidate := normalizeSemver(candidate)
normalizedCurrent, validCurrent := normalizeSemver(current)
if validCandidate && validCurrent {
return semver.Compare(normalizedCandidate, normalizedCurrent) > 0
}
return true
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Invalid candidate versions are always treated as newer.

When candidate is not semver-parseable but current is valid, the function returns true, incorrectly presenting invalid versions as upgrade candidates. This could lead to users selecting non-semver versions (e.g., typos, placeholder strings) as upgrade targets.

Consider returning false when the candidate is invalid:

🐛 Proposed fix
 func isVersionNewerThanCurrent(candidate, current string) bool {
 	normalizedCandidate, validCandidate := normalizeSemver(candidate)
 	normalizedCurrent, validCurrent := normalizeSemver(current)
 	if validCandidate && validCurrent {
 		return semver.Compare(normalizedCandidate, normalizedCurrent) > 0
 	}
-	return true
+	// If candidate is not parseable, don't treat it as newer
+	// If current is not parseable, any valid candidate is acceptable
+	return validCandidate
 }
📝 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
func isVersionNewerThanCurrent(candidate, current string) bool {
normalizedCandidate, validCandidate := normalizeSemver(candidate)
normalizedCurrent, validCurrent := normalizeSemver(current)
if validCandidate && validCurrent {
return semver.Compare(normalizedCandidate, normalizedCurrent) > 0
}
return true
}
func isVersionNewerThanCurrent(candidate, current string) bool {
normalizedCandidate, validCandidate := normalizeSemver(candidate)
normalizedCurrent, validCurrent := normalizeSemver(current)
if validCandidate && validCurrent {
return semver.Compare(normalizedCandidate, normalizedCurrent) > 0
}
// If candidate is not parseable, don't treat it as newer
// If current is not parseable, any valid candidate is acceptable
return validCandidate
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmd/stack/version_sort.go` around lines 41 - 48, The function
isVersionNewerThanCurrent currently treats any non-parseable candidate as newer;
change it so that if normalizeSemver reports the candidate is invalid you return
false (do not treat invalid candidates as upgrades). Keep the existing behavior
of comparing normalizedCandidate and normalizedCurrent when both valid, and if
candidate is valid but current is not you may still return true; update the
logic in isVersionNewerThanCurrent (which calls normalizeSemver and
semver.Compare) so invalid candidate -> false, validCandidate && validCurrent ->
use semver.Compare, otherwise (validCandidate && !validCurrent) -> true.

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