Skip to content

fix: improve fine-grained PAT guidance in preflight and setup#3383

Merged
waynesun09 merged 5 commits into
mainfrom
fix-preflight-fgpat-scopes
Jul 8, 2026
Merged

fix: improve fine-grained PAT guidance in preflight and setup#3383
waynesun09 merged 5 commits into
mainfrom
fix-preflight-fgpat-scopes

Conversation

@waynesun09

Copy link
Copy Markdown
Member

Summary

When a fine-grained token is used, the CLI preflight now lists the specific scopes
that could not be verified and their equivalent fine-grained permissions, instead of
a generic "preflight skipped" message. When an org blocks classic PATs, the CLI
detects the specific 403 and prints actionable token resolution guidance.

Related Issue

Closes #3368

Changes

  • Add SkipGuidance() method to PreflightResult that maps OAuth scopes to
    fine-grained equivalents and renders a guidance message
  • Update both preflight paths (runPreflight and checkTokenScopes) to print
    scope names and fine-grained equivalents when a fine-grained token is detected
  • Add IsPATForbiddenError() classifier in the GitHub forge to detect
    the specific 403 when an org blocks classic PATs
  • Add patForbiddenGuidance() helper that prints token resolution order,
    required fine-grained permissions, and the export command
  • Wrap GetRepo call sites in per-repo setup to detect the PAT-forbidden
    error and show actionable guidance
  • Add token resolution and fine-grained permission documentation to
    docs/guides/getting-started/configuring-github.md

Testing

  • Tests added for SkipGuidance() (3 subtests: per-repo scopes, install scopes, empty)
  • Tests added for IsPATForbiddenError() (5 subtests: match, wrapped, generic 403, non-API, nil)
  • Updated existing fine-grained token tests to verify new output includes scope names
  • All existing preflight tests continue to pass

Checklist

  • PR title follows Conventional Commits (correct type, ! for breaking changes)
  • Commits are signed off (DCO) — human and human-directed agent sessions only
  • I wrote this contribution myself and can explain all changes in it

When a fine-grained token is detected during preflight, the CLI now
lists the specific scopes that could not be verified along with their
equivalent fine-grained permissions, instead of a generic skip message.

When an org blocks classic PATs and the GetRepo call returns a 403,
the CLI now detects the specific error and prints actionable guidance:
token resolution order, required fine-grained permissions, and the
export command to use a fine-grained PAT.

Adds token resolution and fine-grained permission documentation to
docs/guides/getting-started/configuring-github.md.

Closes #3368

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@waynesun09 waynesun09 requested a review from a team as a code owner July 7, 2026 16:38
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Improve fine-grained PAT guidance in preflight and setup

🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Show required OAuth scopes and fine-grained permission equivalents when scope checks are skipped.
• Detect org-level classic PAT rejections and print actionable remediation guidance during setup.
• Document token resolution order and required fine-grained permissions in the GitHub setup guide.
Diagram

graph TD
  CLI(["fullsend CLI"]) --> Preflight["Preflight / scope checks"] --> Printer["UI output"]
  Preflight --> Layers["PreflightResult.SkipGuidance"]
  CLI --> Setup["GitHub setup (per-repo)"] --> Forge["forge/github client"] --> GitHubAPI{{"GitHub API"}}
  Forge --> Classifier["IsPATForbiddenError"] --> Setup
  Docs["configuring-github.md"] --> CLI
  subgraph Legend
    direction LR
    _svc(["CLI/Command"]) ~~~ _mod["Module/Helper"] ~~~ _ext{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Match PAT-blocked condition using a structured error field/code
  • ➕ More robust than substring matching if GitHub changes wording/localization
  • ➕ Reduces false positives/negatives across other 403 conditions
  • ➖ May require additional plumbing if the API response does not expose a stable code today
  • ➖ Could be blocked by upstream GitHub API limitations
2. Centralize token resolution + permission guidance as a reusable CLI help module
  • ➕ Avoids duplicating token resolution order and permission lists across CLI + docs
  • ➕ Easier to keep guidance consistent as requirements evolve
  • ➖ Slightly more refactor now; may be overkill for this change size
  • ➖ Requires deciding ownership boundaries between cli/admin and layers/docs

Recommendation: The PR’s approach is solid for immediate UX improvement: it keeps guidance close to the failure points and adds focused tests. If GitHub exposes a stable machine-readable error code for the classic-PAT-blocked case, prefer switching the classifier from message substring matching to that structured signal; otherwise, the current implementation is acceptable and well-covered by tests.

Files changed (7) +217 / -2

Enhancement (1) +29 / -0
preflight.goGenerate skip guidance mapping OAuth scopes to fine-grained permissions +29/-0

Generate skip guidance mapping OAuth scopes to fine-grained permissions

• Adds a fine-grained permission equivalence map and a PreflightResult.SkipGuidance() helper. When scopes can’t be verified (fine-grained token), it emits a human-readable list of required scopes and corresponding fine-grained permissions plus a metadata baseline reminder.

internal/layers/preflight.go

Bug fix (2) +65 / -0
admin.goImprove preflight skip output and guide users when classic PATs are blocked +52/-0

Improve preflight skip output and guide users when classic PATs are blocked

• Enhances preflight output for fine-grained tokens by printing required scope names and mapped fine-grained permission equivalents via SkipGuidance(). Wraps GetRepo call sites in per-repo setup to detect the PAT-forbidden 403 and prints actionable remediation guidance (token resolution order, required permissions, export command).

internal/cli/admin.go

github.goAdd classifier for orgs that forbid classic PAT access +13/-0

Add classifier for orgs that forbid classic PAT access

• Introduces IsPATForbiddenError() to detect the specific GitHub API 403 message indicating classic PATs are blocked by organization policy. Uses errors.As on APIError and checks status + message content.

internal/forge/github/github.go

Tests (3) +90 / -2
admin_test.goAssert fine-grained token preflight output includes required scopes +14/-2

Assert fine-grained token preflight output includes required scopes

• Updates fine-grained token tests to capture printer output and verify it includes scope names (repo/workflow) and install-only scope (admin:org) where applicable. Ensures the new SkipGuidance-driven messaging is exercised in existing preflight paths.

internal/cli/admin_test.go

github_test.goTest PAT-forbidden error classification across common variants +46/-0

Test PAT-forbidden error classification across common variants

• Adds table-driven tests covering direct and wrapped APIError matches, generic 403s, non-API errors, and nil. Validates IsPATForbiddenError() behavior is precise and resilient to wrapping.

internal/forge/github/github_test.go

preflight_test.goAdd SkipGuidance tests for required scope sets and empty behavior +30/-0

Add SkipGuidance tests for required scope sets and empty behavior

• Adds subtests verifying SkipGuidance() includes scope names, fine-grained equivalents, and the metadata baseline. Covers per-repo scopes, install scopes including admin:org, and the empty-required case returning no guidance.

internal/layers/preflight_test.go

Documentation (1) +33 / -0
configuring-github.mdDocument token resolution order and fine-grained PAT permissions +33/-0

Document token resolution order and fine-grained PAT permissions

• Adds a new section describing how the CLI resolves GitHub tokens (GH_TOKEN/GITHUB_TOKEN/gh auth token). Documents the scenario where orgs block classic PATs and provides required fine-grained permissions plus an export example.

docs/guides/getting-started/configuring-github.md

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 4:39 PM UTC · Ended 4:46 PM UTC
Commit: e8381e3 · View workflow run →

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Site preview

Preview: https://95e39e11-site.fullsend-ai.workers.dev

Commit: 45ff7fecc660234ccc73ce8276b965919bbf3d70

@codecov

codecov Bot commented Jul 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.07018% with 25 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/cli/admin.go 69.76% 11 Missing and 2 partials ⚠️
internal/layers/commit.go 80.00% 5 Missing and 5 partials ⚠️
internal/layers/preflight.go 86.66% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@qodo-code-review

qodo-code-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (2)

Context used
✅ Compliance rules (platform): 54 rules

Grey Divider


Remediation recommended

1. Unnumbered procedural token step 📜 Skill insight ✧ Quality
Description
The added procedural instruction Export it before running setup... is not expressed as a numbered
step, despite being a procedure. This violates the requirement that procedures be written as
numbered steps instead of prose paragraphs.
Code

docs/guides/getting-started/configuring-github.md[R42-47]

+Export it before running setup so it takes priority:
+
+```bash
+export GH_TOKEN=github_pat_...
+fullsend github setup <org>/<repo> ...
+```
Relevance

⭐⭐⭐ High

Docs style “procedures as numbered steps” enforced historically; similar suggestions accepted in
#2663 and #2277.

PR-#2663
PR-#2277

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The rule requires procedural content to use numbered steps. The added text introduces a user action
(exporting GH_TOKEN before running setup) but presents it as a prose sentence plus a code block
rather than as an ordered step.

docs/guides/getting-started/configuring-github.md[42-47]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Procedural guidance is introduced in prose (`Export it before running setup...`) without using a numbered list.

## Issue Context
Documentation procedures must be written as numbered steps.

## Fix Focus Areas
- docs/guides/getting-started/configuring-github.md[42-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Skipped preflight misclassified ✓ Resolved 🐞 Bug ≡ Correctness
Description
runPreflight treats any PreflightResult.Skipped as a fine-grained token and prints SkipGuidance, but
Stack.Preflight also sets Skipped=true for GitHub App installation tokens. This will emit misleading
“fine-grained token”/fine-grained-permissions guidance when the resolved token is actually an
installation token (e.g., GITHUB_TOKEN in GitHub Actions).
Code

internal/cli/admin.go[R2082-2090]

	if result.Skipped {
		printer.StepWarn("Preflight skipped: fine-grained token detected (scopes cannot be verified)")
+		if guidance := result.SkipGuidance(); guidance != "" {
+			for _, line := range strings.Split(guidance, "\n") {
+				if line != "" {
+					printer.StepInfo(line)
+				}
+			}
+		}
Relevance

⭐⭐⭐ High

Team recently separated skipped-preflight reasons (installation vs fine-grained) in #2277;
misleading guidance likely fixed.

PR-#2277
PR-#760

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The preflight layer explicitly sets Skipped: true for installation tokens, but runPreflight
treats any skipped result as a fine-grained token and now prints fine-grained permission guidance in
that branch.

internal/layers/preflight.go[107-124]
internal/cli/admin.go[2066-2094]
internal/cli/admin.go[2880-2891]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`runPreflight` assumes `result.Skipped` implies a fine-grained PAT, but `Stack.Preflight` sets `Skipped=true` for *both* installation tokens and fine-grained tokens (scopes unavailable). With this PR, `runPreflight` now prints `SkipGuidance()` for all skipped cases, which is incorrect/misleading for installation tokens.

### Issue Context
- `Stack.Preflight` sets `Skipped=true` for installation tokens.
- `runPreflight` prints `"fine-grained token detected"` and `SkipGuidance()` whenever `Skipped` is true.
- `checkTokenScopes` already distinguishes installation tokens vs fine-grained tokens; `runPreflight` should align.

### Fix Focus Areas
- internal/layers/preflight.go[107-124]
- internal/cli/admin.go[2066-2094]

### Implementation direction
- Extend `layers.PreflightResult` with a field that disambiguates skip cause (e.g. `SkipReason string` or `InstallationToken bool`).
- Set that field inside `Stack.Preflight` when `isInstallation` is true vs when `granted == nil`.
- Update `runPreflight` to:
 - print an installation-token-specific skip message when the token is an installation token, and **do not** print `SkipGuidance()` in that case.
 - print fine-grained-token guidance (`SkipGuidance()`) only when the skip reason is “fine-grained scopes unavailable”.
- Optionally add/adjust tests to cover `runPreflight` output for installation tokens.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Guide not in admin/user 📜 Skill insight ⌂ Architecture
Description
docs/guides/getting-started/configuring-github.md is a guide file but it is not placed under
docs/guides/admin/ or docs/guides/user/ as required. This breaks the documentation structure and
makes it unclear which audience the guide targets.
Code

docs/guides/getting-started/configuring-github.md[R16-47]

+### Token resolution
+
+The `fullsend` CLI resolves a GitHub token in this order:
+
+1. `GH_TOKEN` environment variable
+2. `GITHUB_TOKEN` environment variable
+3. `gh auth token` (GitHub CLI)
+
+For most organizations, the token from `gh auth login` works. However, if
+your organization restricts personal access token types (Settings → Personal
+access tokens → Restrict access via PAT type), `gh auth login` may produce a
+token that GitHub rejects with a 403 error.
+
+In that case, create a **fine-grained personal access token** at
+<https://github.com/settings/personal-access-tokens/new> scoped to the
+target repository with these permissions:
+
+| Permission | Level | Why |
+|---|---|---|
+| Contents | Read and write | Commits `.fullsend/config.yaml` and scaffold files |
+| Workflows | Read and write | Writes/updates files under `.github/workflows/` |
+| Secrets | Read and write | Sets `FULLSEND_GCP_PROJECT_ID` / `FULLSEND_GCP_WIF_PROVIDER` |
+| Variables | Read and write | Sets `FULLSEND_MINT_URL` / `FULLSEND_GCP_REGION` |
+| Metadata | Read-only | GitHub-required baseline |
+| Pull requests | Read and write | Only needed without `--direct` |
+
+Export it before running setup so it takes priority:
+
+```bash
+export GH_TOKEN=github_pat_...
+fullsend github setup <org>/<repo> ...
+```
Relevance

⭐ Low

Repo uses docs/guides/getting-started/ (added #2124, updated #2666); not enforcing admin/user-only
placement.

PR-#2124
PR-#2666

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The compliance rule requires guide files under docs/guides/ to live under either
docs/guides/admin/ or docs/guides/user/. The modified file is
docs/guides/getting-started/configuring-github.md, which violates the required directory
structure.

docs/guides/getting-started/configuring-github.md[16-47]
Skill: writing-user-docs

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A guide under `docs/guides/` is located in `docs/guides/getting-started/` instead of the required `docs/guides/admin/` or `docs/guides/user/` directory.

## Issue Context
Compliance requires each guide file under `docs/guides/` to be placed in either `admin/` or `user/`.

## Fix Focus Areas
- docs/guides/getting-started/configuring-github.md[16-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +42 to +47
Export it before running setup so it takes priority:

```bash
export GH_TOKEN=github_pat_...
fullsend github setup <org>/<repo> ...
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. Unnumbered procedural token step 📜 Skill insight ✧ Quality

The added procedural instruction Export it before running setup... is not expressed as a numbered
step, despite being a procedure. This violates the requirement that procedures be written as
numbered steps instead of prose paragraphs.
Agent Prompt
## Issue description
Procedural guidance is introduced in prose (`Export it before running setup...`) without using a numbered list.

## Issue Context
Documentation procedures must be written as numbered steps.

## Fix Focus Areas
- docs/guides/getting-started/configuring-github.md[42-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread internal/cli/admin.go
- Add SkippedReason to PreflightResult to distinguish installation
  tokens from fine-grained PATs; runPreflight now shows the correct
  message for each token type instead of always saying "fine-grained"
- Extract printSkipGuidance helper to deduplicate the guidance-printing
  loop that appeared in both runPreflight and checkTokenScopes
- Add Pull requests (read/write) to fineGrainedEquivalents so
  SkipGuidance output is consistent with patForbiddenGuidance and docs
- Add test for patForbiddenGuidance verifying owner/repo, all
  permission bullets, token resolution order, and export command

Assisted-by: Claude (review, fix), Gemini (review)
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 4:47 PM UTC · Completed 5:01 PM UTC
Commit: bf0b3c4 · View workflow run →

@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review

Findings

Low

  • [edge-case] internal/cli/admin.go:2083 — The switch on result.SkippedReason uses a default case that prints a generic message without calling printSkipGuidance. If a new SkipReason variant is added in the future and is semantically similar to fine-grained (scopes cannot be verified), the guidance would not be printed. Consider adding a code comment noting that new skip reasons should get explicit case handling.
  • [code-duplication] internal/cli/admin.go — Classic PAT rejection handling appears identically at two call sites (~998 and ~1172). Both check gh.IsPATForbiddenError, call handlePATForbidden, and return the result. Consider extracting a shared helper that encapsulates the check-and-handle pattern.
  • [error-wrapping] internal/cli/admin.go — The error message "organization forbids classic PATs" in handlePATForbidden is somewhat redundant with the underlying error's own message from IsPATForbiddenError which contains "forbids access via a personal access token".
  • [naming-convention] internal/cli/admin.gopatForbiddenGuidance returns a string but lacks a verb prefix (e.g., buildPATForbiddenGuidance) to distinguish it from side-effect functions like printSkipGuidance.
  • [authorization] internal/layers/commit.goisFineGrainedToken uses a heuristic (scopes == nil after ruling out installation tokens) to detect fine-grained PATs. This matches the existing pattern in Preflight and is based on documented GitHub API behavior (fine-grained tokens do not populate X-OAuth-Scopes). The consequence (bypassing fork path) is fail-closed — a 403 will surface if the token lacks write access. No immediate risk, but worth noting for future-proofing.
  • [scope-boundary] internal/layers/preflight.go — The fineGrainedEquivalents map provides OAuth-to-fine-grained permission mapping guidance. This is useful UX but extends slightly beyond issue CLI and docs give no actionable guidance when a GitHub org rejects classic PATs #3368's core scope (detecting org-blocked classic PATs). Consider whether this mapping would be better maintained in documentation.
  • [missing-behavioral-documentation] docs/cli/github.md:56 — The "Required OAuth scopes" section documents classic PAT scopes but does not mention fine-grained PATs as an alternative or note that scope verification is skipped for these tokens.
Previous run

Looks good to me

Previous run (2)

Review

Findings

Low

  • [edge-case] internal/cli/admin.go:2083 — The switch on result.SkippedReason uses a default case for fine-grained token guidance. If a new SkipReason variant is added, it will silently fall into the default branch and print fine-grained PAT guidance, which may be incorrect. Consider explicitly matching SkipFineGrained with a generic default fallback.
  • [code-duplication] internal/cli/admin.go:998 — Classic PAT rejection handling appears identically at two call sites (~998 and ~1174). Both check gh.IsPATForbiddenError, print the same UI messages, and return the same error. Consider extracting a shared helper.
  • [error-wrapping] internal/cli/admin.go:1002 — The error message "organization forbids classic PATs" is somewhat redundant with the underlying error's own message from IsPATForbiddenError.
  • [naming-convention] internal/cli/admin.go:2943patForbiddenGuidance returns a string but lacks a verb prefix (e.g., buildPATForbiddenGuidance) to distinguish it from side-effect functions like printSkipGuidance.

Labels: PR modifies CLI install/setup flow and getting-started documentation

fullsend-ai-review[bot]

This comment was marked as outdated.

@fullsend-ai-review fullsend-ai-review Bot added ready-for-merge All reviewers approved — ready to merge component/install CLI install and app setup component/docs User-facing documentation labels Jul 7, 2026
The token resolution details are not a prerequisite for most users.
Collapse the section into a compact note so it does not dominate the
prerequisites list.

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 5:06 PM UTC · Ended 5:16 PM UTC
Commit: e8381e3 · View workflow run →

- Explicitly match SkipFineGrained in switch instead of using default,
  preventing future SkipReason variants from getting wrong guidance
- Guard SkipGuidance() to only generate output for fine-grained tokens,
  making it safe to call unconditionally
- Extract handlePATForbidden helper to deduplicate PAT rejection handling
  at two GetRepo call sites
- Set SkippedReason in checkTokenScopes when constructing PreflightResult
- Add test for SkipGuidance returning empty for installation tokens

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 5:16 PM UTC · Completed 5:31 PM UTC
Commit: aa5d6f8 · View workflow run →

fullsend-ai-review[bot]

This comment was marked as outdated.

@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 Jul 7, 2026
Fine-grained PATs are scoped to a single GitHub org and cannot create
cross-org forks. When the CLI detects a fine-grained token (nil scopes
from GetTokenScopes), it now hides the [f] fork option and presents
only the upstream [u] path with a confirmation prompt explaining that
a PR with scaffolding files will be created.

- Add isFineGrainedToken() to detect token type via scope introspection
- Add promptUpstreamOnly() for fine-grained-specific confirmation UX
- Update commitScaffoldViaPR to route fine-grained tokens to upstream
- Add fork limitation note to configuring-github.md
- Add tests for fine-grained interactive/non-interactive/decline paths

Relates-to: #3368

Assisted-by: Claude
Signed-off-by: Wayne Sun <gsun@redhat.com>
@fullsend-ai-review

fullsend-ai-review Bot commented Jul 7, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 9:00 PM UTC · Completed 9:17 PM UTC
Commit: 45ff7fe · View workflow run →

Comment thread internal/cli/admin.go
case layers.SkipFineGrained:
printer.StepWarn("Preflight skipped: fine-grained token detected (scopes cannot be verified)")
printSkipGuidance(printer, result)
default:

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] edge-case

The switch on result.SkippedReason uses a default case that prints a generic message without calling printSkipGuidance. If a new SkipReason variant is added and is semantically similar to fine-grained, the guidance would not be printed. Consider adding a code comment noting that new skip reasons should get explicit case handling.

Comment thread internal/cli/admin.go
scaffoldCommitFn := func(ctx context.Context, owner, repo string, files []forge.TreeFile, direct bool) error {
targetRepo, repoErr := client.GetRepo(ctx, owner, repo)
if repoErr != nil {
if gh.IsPATForbiddenError(repoErr) {

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] code-duplication

Classic PAT rejection handling appears identically at two call sites (~998 and ~1172). Both check gh.IsPATForbiddenError, call handlePATForbidden, and return the result. Consider extracting a shared helper that encapsulates the check-and-handle pattern.

Comment thread internal/cli/admin.go
}
}

func handlePATForbidden(printer *ui.Printer, owner, repo string, err error) error {

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] error-wrapping

The error message 'organization forbids classic PATs' in handlePATForbidden is somewhat redundant with the underlying error's own message from IsPATForbiddenError which contains 'forbids access via a personal access token'.

Comment thread internal/cli/admin.go
}

func patForbiddenGuidance(owner, repo string) string {
var b 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] naming-convention

patForbiddenGuidance returns a string but lacks a verb prefix (e.g., buildPATForbiddenGuidance) to distinguish it from side-effect functions like printSkipGuidance.

@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 Jul 7, 2026
@waynesun09 waynesun09 added this pull request to the merge queue Jul 8, 2026
Merged via the queue into main with commit 3ae65db Jul 8, 2026
23 checks passed
@waynesun09 waynesun09 deleted the fix-preflight-fgpat-scopes branch July 8, 2026 17:15
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jul 8, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 5:17 PM UTC · Completed 5:27 PM UTC
Commit: 45ff7fe · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

PR #3383 improved fine-grained PAT guidance in the CLI preflight and setup flow, closing issue #3368. The workflow involved 5 commits over ~4.5 hours by a human author (waynesun09, assisted by Claude), 5 review agent dispatches (2 cancelled, 3 completed), Qodo code review, and a human reviewer who approved with no comments. The multi-agent review system worked well: Qodo caught a real bug (installation token misclassification) within minutes, the author fixed it before the fullsend review agent's first successful run, and the fullsend agent provided valuable code quality feedback that the author addressed in targeted follow-up commits. The main waste was: (1) 2/5 review runs cancelled due to rapid pushes (existing issue #1355), and (2) all 4 inline findings in the final review run were repeats of Run 2 findings (existing issue #1013). The human reviewer approved with no comments ~17 hours after the last push, adding latency but no substantive feedback. Three proposals filed: evidence for #1013 (repeated findings), evidence for #1355 (cancelled reviews from rapid pushes), and a new proposal about tracking out-of-diff documentation findings that are lost after approval.

Proposals filed

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

Labels

component/docs User-facing documentation component/install CLI install and app setup ready-for-merge All reviewers approved — ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI and docs give no actionable guidance when a GitHub org rejects classic PATs

2 participants