Skip to content

fix(cli): open correct uninstall URL and wait for user confirmation - #1573

Merged
rh-hemartin merged 7 commits into
mainfrom
fix/uninstall-installation-url
Jun 8, 2026
Merged

fix(cli): open correct uninstall URL and wait for user confirmation#1573
rh-hemartin merged 7 commits into
mainfrom
fix/uninstall-installation-url

Conversation

@rh-hemartin

@rh-hemartin rh-hemartin commented May 27, 2026

Copy link
Copy Markdown
Member

Summary

Relates to #1490
Closes #323

Test plan

  • Run fullsend admin uninstall <org> against an org with fullsend installed as a third-party app
  • Verify browser opens to /settings/installations/{id} (not /settings/apps/.../advanced)
  • Verify command pauses and waits for Enter after each app page is opened
  • Verify fallback to /settings/installations list when installation ID is unavailable

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Site preview

Preview: https://a30e3bb0-site.fullsend-ai.workers.dev

Commit: 07f902fab2a6086aca8c72a9055c573e4bcf56f1

@fullsend-ai-review

fullsend-ai-review Bot commented May 27, 2026

Copy link
Copy Markdown

Review

Findings

Low

  • [stale-reference] internal/cli/github.go:936 — The parallel runGitHubUninstall function (reachable via fullsend github uninstall) still uses the old /settings/apps/{slug}/advanced URL pattern and "App cleanup" header. This is the same bug this PR fixes in runUninstall, but in a separate code path. Consider updating github.go in a follow-up PR.

  • [missing-test] internal/cli/admin_test.go — No test covers the new post-uninstall verification logic (the second ListOrgInstallations call after user confirmation). Since FakeClient returns the same Installations slice on every call, all existing tests silently hit the "Some fullsend apps are still installed" warning path. A test that mutates client.Installations between calls (or injects an error) would verify both the success and warning paths.

Info

  • [test-integrity] internal/cli/admin_test.go:1680 — In TestRunUninstall_LegacySlugsIncludedWhenConfigUnavailable, the assertion assert.NotContains(t, output, "App fullsend-coder not found") is now vacuously true because the new code no longer emits that message. The test still validates its core intent via other assertions.
Previous run

Review

Findings

No findings.

Previous run (2)

Review

Findings

No findings.

Previous run (3)

Review

Findings

Low

  • [correctness] internal/cli/admin.go:1700 — Diagnostic messages removed when installation lookup fails. The old code warned "Could not verify which apps exist; opening all" when ListOrgInstallations returned an error, and printed "App {slug} not found, skipping" for individual misses. Both messages were removed, making the fallback behavior silent. Consider restoring a warning when listErr != nil so users understand why they are being directed to the generic installations list page instead of individual installation pages.

  • [correctness] internal/cli/admin_test.go:1561 — Post-uninstall verification logic is untested. The new code calls ListOrgInstallations a second time after user confirmation to check whether apps were actually removed, but no test exercises this path. With FakeClient, the Installations slice is immutable between calls, so the verification always reports "Some fullsend apps are still installed." Consider adding a test that either (a) asserts the warning message appears (documenting the FakeClient limitation), or (b) uses a FakeClient callback to simulate mutation so the success path ("Apps were uninstalled") is also covered.

Info

  • [docs-currency] docs/guides/admin/installation.md:286 — The uninstall section does not describe the new interactive confirmation behavior (press Enter after each app) or the post-uninstall verification step. The current wording is not misleading but could be expanded in a follow-up to set user expectations for the interactive flow.
Previous run (4)

Review

Findings

Low

  • [correctness] internal/cli/admin.go:1678 — "App uninstall" header is printed unconditionally before the if len(agentSlugs) > 0 check. Previously, "App cleanup" was only shown when existingSlugs > 0. When all apps are already removed, the header now appears with no corresponding action beneath it. Consider moving it back inside the if len(existingSlugs) > 0 block.

  • [correctness] internal/cli/admin.go:1717os.Stdin is hardcoded, making the new confirmation behavior untestable. Existing tests pass because os.Stdin returns EOF immediately in test environments (and EOF is correctly handled), but no test can verify the prompt-and-wait behavior. Consider accepting an io.Reader parameter to enable testing.

Comment thread internal/cli/admin.go
Comment thread internal/cli/admin.go
Comment thread internal/cli/admin.go
existingSlugs = agentSlugs
}

if len(existingSlugs) > 0 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] correctness

Diagnostic messages removed when installation lookup fails. The old code warned "Could not verify which apps exist; opening all" when ListOrgInstallations returned an error, and printed "App {slug} not found, skipping" for individual misses. Both were removed, making the fallback behavior silent.

Suggested fix: Consider restoring a warning when listErr != nil so users understand why they are directed to the generic installations list page.

@@ -1561,7 +1561,7 @@ func TestRunUninstall_LegacySlugsIncludedWhenConfigUnavailable(t *testing.T) {
var buf strings.Builder

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[low] correctness

Post-uninstall verification logic is untested. The new code calls ListOrgInstallations a second time to check whether apps were removed, but no test covers this path. With FakeClient, installations are immutable, so verification always reports still-installed.

Suggested fix: Add a test that asserts the warning message appears, or use a FakeClient callback to simulate mutation so the success path is also covered.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels May 27, 2026
@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels May 27, 2026
@rh-hemartin rh-hemartin self-assigned this May 28, 2026
@rh-hemartin
rh-hemartin force-pushed the fix/uninstall-installation-url branch from 9c7ca05 to 62cbcc7 Compare May 28, 2026 07:53
@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels May 28, 2026

@ralphbean ralphbean left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. One non-blocking note inline about the rebase.

Comment thread internal/cli/admin.go Outdated

// runUninstall tears down the fullsend installation.
func runUninstall(ctx context.Context, client forge.Client, printer *ui.Printer, org, appSet string) error {
func runUninstall(ctx context.Context, client forge.Client, printer *ui.Printer, org, appSet string, stdin io.Reader) error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[non-blocking] Heads up — this branch is behind main and GitHub shows it as conflicting. During the rebase you'll run into the BrowserOpener injection that landed on main recently (plus slug dedup logic and two new tests). I think the cleanest path is to keep both browser and stdin as parameters so tests can still use NopBrowser and CI doesn't try to open a real browser.

rh-hemartin and others added 7 commits June 8, 2026 08:13
Opens /organizations/{org}/settings/installations/{id} instead of
/organizations/{org}/settings/apps/{slug}/advanced. The /advanced page
requires app owner access; org admins installing a third-party app need
the installation settings page to uninstall.

Falls back to /settings/installations list when the installation ID is
unavailable (e.g. ListOrgInstallations failed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
After opening the browser for each app's installation settings page,
prompt the user to press Enter before continuing to the next app.
Prevents the command from exiting immediately and making the manual
uninstall step appear optional.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hector Martinez <hemartin@redhat.com>
@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge and removed ready-for-merge All reviewers approved — ready to merge labels Jun 8, 2026
@rh-hemartin
rh-hemartin enabled auto-merge June 8, 2026 09:14
@rh-hemartin
rh-hemartin added this pull request to the merge queue Jun 8, 2026
Merged via the queue into main with commit be348d5 Jun 8, 2026
12 of 13 checks passed
@rh-hemartin
rh-hemartin deleted the fix/uninstall-installation-url branch June 8, 2026 09:28
@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #1573 — fix(cli): open correct uninstall URL and wait for user confirmation

Workflow outcome: Good. Human-authored PR with useful review agent findings that drove iterative improvements before merge.

Timeline

  1. May 27 08:18 — Human (rh-hemartin) opens PR fixing uninstall URL and adding user confirmation (3 files, +102/−75). Closes admin uninstall exits immediately after opening browser for app deletion #323, relates to Uninstall doesn't clean everything up (part 2) #1490.
  2. May 27 08:24 — Review run 1 (single-agent, ~2M tokens, 6 min) → APPROVE with 2 low findings: header printed unconditionally, os.Stdin hardcoded.
  3. May 27 08:46–08:58 — Human pushes 4 fix commits addressing review findings (stdin injection, post-uninstall verification, diagnostic warnings).
  4. May 27 08:49–09:04 — Review runs 2–3 triggered by rapid pushes → both APPROVE. Run 2 found 2 more low findings (removed diagnostics, untested verification).
  5. May 28 07:54 — Review run 4 after another push → APPROVE.
  6. Jun 6 19:13 — Human reviewer (ralphbean) approves with non-blocking rebase note.
  7. Jun 8 06:26 — Review run 5 (multi-agent architecture, ~7.8M tokens, 11 min) → APPROVE. Found stale github.go reference using old URL pattern.
  8. Jun 8 09:28 — PR merged.

What went well

  • Review agent caught real correctness issues (testability, unconditional header, removed diagnostics, stale cross-file reference) that improved code quality.
  • Human responded to review findings promptly, addressing 4 of them within 12 minutes.
  • The multi-agent review run (run 5) found a cross-file stale reference in github.go that the simpler single-agent runs missed — demonstrating the value of broader coverage.

Cost concerns (already tracked)

No new proposals

All identified improvement opportunities are already covered by existing open issues. No new proposals warranted.

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

Labels

ready-for-merge All reviewers approved — ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

admin uninstall exits immediately after opening browser for app deletion

2 participants