Skip to content

Fix scope selection misleading Launchpad users#232

Merged
jeremy merged 6 commits intomainfrom
worktree-scope-fix-220
Mar 10, 2026
Merged

Fix scope selection misleading Launchpad users#232
jeremy merged 6 commits intomainfrom
worktree-scope-fix-220

Conversation

@jeremy
Copy link
Copy Markdown
Member

@jeremy jeremy commented Mar 10, 2026

Summary

  • Launchpad OAuth doesn't support scopes, so selecting "read-only" still grants full read+write access — a false sense of security, especially for AI agents operators want to restrict
  • Makes scope a BC3-only concept: Login() now returns a LoginResult with the effective scope determined by the OAuth provider, not user input
  • Launchpad: scope is always cleared (with warning if --scope was passed); BC3: defaults to "read", respects explicit --scope
  • Removes the scope picker from the setup wizard and suppresses scope display everywhere for Launchpad sessions (auth status, doctor, profile show)

Fixes #220

Test plan

  • make check passes (fmt, vet, lint, unit tests, 263 e2e tests, surface snapshot)
  • basecamp auth login against Launchpad — no scope prompt, no scope in output, auth status shows no scope
  • basecamp auth login --scope read against Launchpad — warning logged, scope not stored
  • basecamp auth login --scope read against BC3 — scope sent, displayed, stored correctly
  • basecamp profile show <launchpad-profile> — no scope displayed even if legacy "read" stored
  • basecamp doctor --verbose — no scope for Launchpad credentials

Summary by cubic

Scope is now a BC3-only concept. Launchpad logins no longer show or store scope; --scope is ignored with a warning, and profile create defers config writes and restores in-memory config on login failure to prevent dangling profiles (fixes #220).

  • Bug Fixes

    • auth.Login() validates scope (single source of truth) and returns *LoginResult with effective Scope and OAuthType.
    • Launchpad: scope cleared and hidden in auth status, doctor, and profile; --scope ignored with warning.
    • BC3: defaults to read when no scope is provided; scope is stored and displayed.
    • Profile create: persist profile only after successful Login() and fully restore in-memory state on failure.
    • Setup wizard removes scope picker; login and wizard show “Access: …” only when scope applies.
    • Docs and defaults updated: config default scope set to empty; README/install/skill clarify --scope is BC3-only, add --scope full example, and note BC3 vs Launchpad expected output.
    • Tests: provider-aware scope coverage (auth status, doctor --verbose, profile show); fix data race in TestLoginLaunchpadClearsScope using atomic.Bool.
  • Migration

    • Update call sites to handle (*LoginResult, error) from auth.Login() and read result.Scope for messages/persistence.
    • Do not pre-set scope in profile config; use the effective scope from LoginResult (BC3 only).
    • No action needed for existing Launchpad profiles; scope will be ignored and hidden.

Written for commit 3f551e4. Summary will update on new commits.

@jeremy jeremy requested a review from a team as a code owner March 10, 2026 10:51
Copilot AI review requested due to automatic review settings March 10, 2026 10:51
@github-actions github-actions bot added commands CLI command implementations tests Tests (unit and e2e) skills Agent skills auth OAuth authentication docs bug Something isn't working breaking Breaking change labels Mar 10, 2026
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 10, 2026

⚠️ Potential breaking changes detected:

  • The --scope flag behavior has changed in buildLoginCmd, where default behavior when no scope is provided is no longer set to 'read'. Scripts relying on the default 'read' scope may break.
  • The output of the auth status command has been modified to suppress the scope field for 'launchpad' OAuth type, which could break scripts parsing this field.
  • For the profile show command, the scope field is now omitted in the output for 'launchpad' OAuth type, which may break scripts expecting it.

Review carefully before merging. Consider a major version bump.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 12 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/commands/profile.go">

<violation number="1" location="internal/commands/profile.go:303">
P2: Silently discarding the `atomicWriteJSON` error here means a config-write failure goes unnoticed — the user sees the scope in the success output, but it won't survive a restart. Every other `atomicWriteJSON` call site in this file returns the error. At minimum, log a warning or return an error to stay consistent.</violation>
</file>

<file name="internal/auth/auth_test.go">

<violation number="1" location="internal/auth/auth_test.go:1180">
P2: Data race on `tokenCalled`: written in the `httptest` handler goroutine and read on the main goroutine without synchronization. Use `atomic.Bool` (or protect with a mutex) to avoid a `-race` failure.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82e8d9866d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR makes OAuth scope handling provider-aware so Launchpad logins no longer present or persist misleading “read-only” scope information (since Launchpad doesn’t support scopes), while keeping BC3 scope support with a BC3 default of "read".

Changes:

  • Updated auth login flow to return a LoginResult containing the effective scope determined by the OAuth provider (BC3 vs Launchpad), and to clear/ignore scope for Launchpad.
  • Removed scope selection from the setup wizard and suppressed scope display in user-facing outputs for Launchpad credentials (status/doctor/profile show).
  • Updated defaults, tests, and docs to reflect provider-specific scope behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
skills/basecamp/SKILL.md Updates troubleshooting guidance to reflect BC3-only --scope behavior.
internal/config/config.go Removes default pre-login scope from config defaults.
internal/config/config_test.go Adjusts config default scope expectation to empty.
internal/commands/wizard.go Removes scope picker and displays effective access only when applicable.
internal/commands/profile.go Stops pre-setting scope; patches profile scope post-login based on effective provider scope.
internal/commands/profile_test.go Updates profile defaults expectation; removes scope validation test in favor of auth-layer validation.
internal/commands/doctor.go Hides scope in verbose doctor output for Launchpad credentials.
internal/commands/auth.go Suppresses Launchpad scope in status output; prints effective access after login when available.
internal/auth/auth.go Introduces LoginResult; implements provider-aware scope rules (Launchpad clears, BC3 defaults to read).
internal/auth/auth_test.go Updates tests for new Login() return type; adds coverage for Launchpad clearing scope and BC3 defaulting to read.
install.md Updates install verification output expectations.
README.md Updates quick-start auth examples to avoid implying Launchpad supports read-only scoping.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="internal/commands/profile.go">

<violation number="1" location="internal/commands/profile.go:252">
P2: Incomplete in-memory cleanup on login failure: `app.Config.BaseURL` is not restored to its previous value, while the other two modified fields (`Profiles`, `ActiveProfile`) are cleaned up. If the caller continues after this error (e.g. a TUI wizard retrying with a different profile), `BaseURL` will still point at the failed profile's URL.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copilot AI review requested due to automatic review settings March 10, 2026 11:06
@github-actions github-actions bot removed the breaking Breaking change label Mar 10, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 10, 2026 11:26
@jeremy jeremy force-pushed the worktree-scope-fix-220 branch from 64429a2 to cbfd640 Compare March 10, 2026 11:26
@github-actions github-actions bot added the breaking Breaking change label Mar 10, 2026
@jeremy jeremy enabled auto-merge (squash) March 10, 2026 11:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

jeremy added 5 commits March 10, 2026 04:33
Launchpad OAuth doesn't support scopes, so exposing scope selection to
all users creates a false sense of security — selecting "read-only"
still grants a full read+write token. This makes scope provider-aware:

- Add LoginResult return type carrying effective scope and OAuth type
- Validate scope in Login() (single source of truth)
- Clear scope for Launchpad; default to "read" for BC3
- Remove scope picker from setup wizard
- Suppress scope display for Launchpad in auth status, doctor, profile
- Remove misleading "read" default from config

Fixes #220
- Update 5 Login() callers for new (*LoginResult, error) return type
- Add TestLoginLaunchpadClearsScope: scope cleared for Launchpad
- Add TestLoginBC3DefaultsToRead: BC3 defaults to "read" scope
- Add TestLoginRejectsInvalidScope: validation without network calls
- Update TestProfileCreateDefaultValues: no scope in default profile
- Remove TestProfileCreateRejectsInvalidScope: validation moved to Login()
- Update config default assertion from "read" to ""
- Note --scope flag is BC3 OAuth only
- Remove implied read-only default from auth examples
- Update troubleshooting to clarify --scope full requires BC3
Profile create wrote the profile to config.json before calling Login(),
so --scope admin would fail validation but leave a dangling profile
entry (and potentially set it as default). Move config persistence after
Login() succeeds.

Also add command-level tests for display-side scope sanitization:
auth status, doctor --verbose, and profile show all suppress scope
for Launchpad credentials.
- Use atomic.Bool for tokenCalled in TestLoginLaunchpadClearsScope
  to avoid race between httptest handler and test goroutine
- Add --scope full example to README auth section
- Clarify install.md expected output for BC3 vs Launchpad
Snapshot ActiveProfile and BaseURL before mutation so all three fields
are restored if Login() fails, not just Profiles and ActiveProfile.
@jeremy jeremy force-pushed the worktree-scope-fix-220 branch from cbfd640 to 3f551e4 Compare March 10, 2026 11:33
@jeremy jeremy merged commit af13eee into main Mar 10, 2026
24 checks passed
@jeremy jeremy deleted the worktree-scope-fix-220 branch March 10, 2026 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auth OAuth authentication breaking Breaking change bug Something isn't working commands CLI command implementations docs skills Agent skills tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Read-only OAuth scope does not prevent write operations

2 participants