Skip to content

Refactor bootstrap profile runner into focused modules#46855

Merged
pelikhan merged 8 commits into
mainfrom
copilot/file-diet-refactor-bootstrap-profile-runner-again
Jul 20, 2026
Merged

Refactor bootstrap profile runner into focused modules#46855
pelikhan merged 8 commits into
mainfrom
copilot/file-diet-refactor-bootstrap-profile-runner-again

Conversation

Copilot AI commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

pkg/cli/bootstrap_profile_runner.go had grown past the healthy size threshold and mixed orchestration, repo mutation, GitHub App setup, git operations, and shared parsing/UI helpers in one file. This change separates those concerns into focused modules while preserving the existing bootstrap flow and CLI surface.

  • Top-level runner

    • Kept bootstrap_profile_runner.go focused on orchestration only:
      • executeBootstrapProfile
      • applyBootstrapAction
      • bootstrapProfileState
      • bootstrapActionNeedsMutation
    • Left shared bootstrap types and injection points with the runner so the external behavior remains stable.
  • Repository actions

    • Added bootstrap_profile_actions_repo.go for repository variable/secret and Copilot auth paths:
      • runBootstrapRepoVariableAction
      • runBootstrapRepoSecretAction
      • runBootstrapCopilotAuthAction
      • repo variable/secret listing and write helpers
  • GitHub App flow

    • Added bootstrap_profile_github_app.go for the manifest registration flow, installation polling, and credential handling.
    • Moved the browser callback server and installation lookup/polling logic out of the main runner.
  • Git operations

    • Added bootstrap_profile_git.go for the commit/push bootstrap action and git command helpers.
  • Shared helpers

    • Added bootstrap_profile_helpers.go for parsing, prompt/env resolution, naming, HTML/browser/network helpers, and Copilot permission detection.
    • Kept manifest-construction helpers close to the bootstrap domain rather than leaving them embedded in the runner.
  • Tests

    • Split the previous monolithic runner test file into focused test files alongside the new modules.
    • Added coverage for extracted control-flow/helpers so the new file boundaries are exercised directly.

Example of the new separation:

switch action.Type {
case "repo-variable":
	return runBootstrapRepoVariableAction(ctx, config.Repo, action, state)
case "github-app":
	_, err := runBootstrapGitHubAppAction(ctx, config.Repo, action, state)
	return err
case "commit-and-push":
	return runBootstrapCommitAndPushAction(ctx, config.RepoDir, action)
}

pr-sous-chef run https://github.com/github/gh-aw/actions/runs/29761732160

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · 31.2 AIC · ⌖ 6.13 AIC · ⊞ 6.9K ·
Comment /souschef to run again

Copilot AI and others added 3 commits July 20, 2026 15:07
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor pkg/cli/bootstrap_profile_runner.go to reduce file size Refactor bootstrap profile runner into focused modules Jul 20, 2026
Copilot AI requested a review from pelikhan July 20, 2026 15:21
@pelikhan
pelikhan marked this pull request as ready for review July 20, 2026 16:40
Copilot AI review requested due to automatic review settings July 20, 2026 16:40

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.

Pull request overview

Refactors bootstrap profile execution into focused modules while preserving the CLI flow.

Changes:

  • Separates repository, GitHub App, git, and helper logic.
  • Splits and expands corresponding unit tests.
  • Adds injection support for testing GitHub App code exchange.
Show a summary per file
File Description
pkg/cli/bootstrap_profile_runner.go Retains orchestration and shared types.
pkg/cli/bootstrap_profile_runner_test.go Focuses orchestration tests.
pkg/cli/bootstrap_profile_actions_repo.go Handles repository variables, secrets, and Copilot auth.
pkg/cli/bootstrap_profile_actions_repo_test.go Tests repository actions.
pkg/cli/bootstrap_profile_github_app.go Contains GitHub App setup and installation flow.
pkg/cli/bootstrap_profile_github_app_test.go Tests GitHub App flows; exceeds the 500-line acceptance criterion.
pkg/cli/bootstrap_profile_git.go Contains commit-and-push operations.
pkg/cli/bootstrap_profile_git_test.go Tests git operations.
pkg/cli/bootstrap_profile_helpers.go Contains shared parsing, UI, and manifest helpers.
pkg/cli/bootstrap_profile_helpers_test.go Tests shared helpers.

Review details

Tip

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

  • Files reviewed: 10/10 changed files
  • Comments generated: 1
  • Review effort level: Medium

})
}

func TestBuildBootstrapGitHubAppMux(t *testing.T) {
@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 89/100 — Excellent

Analyzed 36 test(s): 34 design, 2 implementation, 0 violation(s).

📊 Metrics (36 tests)
Metric Value
Analyzed 36 (Go: 36, JS: 0)
✅ Design 34 (94%)
⚠️ Implementation 2 (6%)
Edge/error coverage 26 (72%)
Duplicate clusters 0
Inflation No
🚨 Violations 0
Test File Classification Issues
TestListBootstrapRepoNamesPaginate bootstrap_profile_actions_repo_test.go design_test
TestRunBootstrapRepoVariableAction bootstrap_profile_actions_repo_test.go design_test happy-path only
TestRunBootstrapRepoSecretAction bootstrap_profile_actions_repo_test.go design_test happy-path only
TestRunBootstrapCopilotAuthAction bootstrap_profile_actions_repo_test.go design_test edge covered (actions-token skip)
TestBootstrapRepoMutationHelpers_RejectInvalidRepo bootstrap_profile_actions_repo_test.go design_test error covered
TestRunBootstrapCommitAndPushAction_CommitsAndPushesChanges bootstrap_profile_git_test.go design_test
TestRunBootstrapCommitAndPushAction_RequiresRepoDir bootstrap_profile_git_test.go design_test error covered
TestRunBootstrapCommitAndPushAction_SkipsCleanCheckout bootstrap_profile_git_test.go design_test edge covered
TestLoadBootstrapGitHubAppOverrides bootstrap_profile_github_app_test.go design_test
TestLoadBootstrapGitHubAppOverrides_RejectsInvalidMode bootstrap_profile_github_app_test.go design_test error covered
TestRunBootstrapGitHubAppAction_NonInteractiveCreateRequiresExplicitOverride bootstrap_profile_github_app_test.go design_test error covered
TestRunBootstrapGitHubAppAction_RepairsExistingCredentialPairAtomically bootstrap_profile_github_app_test.go design_test behavioral contract
TestRunBootstrapGitHubAppAction_CreateOverwritesPartialCredentialPair bootstrap_profile_github_app_test.go design_test partial-state edge
TestIsRetryableBootstrapGitHubAppInstallationError bootstrap_profile_github_app_test.go design_test error classification
TestBootstrapGitHubAppInstalled_UsesUserInstallationsForAllRepositories bootstrap_profile_github_app_test.go design_test
TestBootstrapGitHubAppInstalled_SelectedInstallationChecksRepositoryMembership bootstrap_profile_github_app_test.go design_test
TestHandleBootstrapGitHubAppExistingFlow bootstrap_profile_github_app_test.go design_test edge covered (no creds)
TestHandleBootstrapGitHubAppCreateOrExistingChoice_UsesExistingOverride bootstrap_profile_github_app_test.go design_test
TestChooseBootstrapGitHubAppMode_NonInteractiveError bootstrap_profile_github_app_test.go design_test error covered
TestCompleteExistingGitHubAppCredentials_UsesProvidedValues bootstrap_profile_github_app_test.go design_test
TestSetupBootstrapGitHubAppDetails bootstrap_profile_github_app_test.go design_test
TestBuildBootstrapGitHubAppMux bootstrap_profile_github_app_test.go design_test error covered (missing code, state mismatch)
TestCreateBootstrapGitHubApp_CanceledContext bootstrap_profile_github_app_test.go design_test error covered
TestWaitForBootstrapGitHubAppInstallation bootstrap_profile_github_app_test.go design_test nil + cancel edge
TestBootstrapGitHubAppInstallationMatches bootstrap_profile_github_app_test.go design_test mismatch covered
TestParseBootstrapBool bootstrap_profile_helpers_test.go design_test truthy/falsy/invalid table
TestWorkflowGrantsCopilotRequestsWrite_UsesFrontmatterPermissions bootstrap_profile_helpers_test.go design_test false-positive covered
TestBootstrapRepositoryInputEnvNames bootstrap_profile_helpers_test.go design_test
TestProfileSourcesUseActionsTokenCopilotAuth bootstrap_profile_helpers_test.go design_test false-positive covered
TestRunBootstrapRequireOwnerType bootstrap_profile_helpers_test.go design_test mismatch error
TestResolveBootstrapTextValue_NonInteractivePaths bootstrap_profile_helpers_test.go design_test required-missing error
TestResolveBootstrapSecretValue_NonInteractivePaths bootstrap_profile_helpers_test.go design_test required-missing error
TestBootstrapHelperUtilities bootstrap_profile_helpers_test.go implementation_test omnibus utility test — mixes many contracts in one function
TestBootstrapGitHubAppManifestHelpers bootstrap_profile_helpers_test.go implementation_test manifest internals, no behavioral invariant
TestBootstrapActionNeedsMutation bootstrap_profile_runner_test.go design_test table-driven, covers all action types
TestBootstrapProfileState bootstrap_profile_runner_test.go design_test
⚠️ Flagged Tests (2)

TestBootstrapHelperUtilities (bootstrap_profile_helpers_test.go:188) — implementation_test. This test asserts on 10+ internal utility functions in a single function body with no single clear behavioral invariant. Each function would be better represented as a named subtest; however, no assertions are missing and the coverage is real.

TestBootstrapGitHubAppManifestHelpers (bootstrap_profile_helpers_test.go:229) — implementation_test. Tests manifest map contents (internal implementation detail of buildBootstrapGitHubAppManifest) and checks for a CSS class name in the rendered HTML. Low risk of missing a real regression.

Verdict

Passed. 6% implementation tests (threshold: 30%). No guideline violations. The test suite is well-structured with strong behavioral contract coverage, real git integration in _git_test.go, and comprehensive error/edge-case coverage across the GitHub App flow.

References:

🧪 Test quality analysis by Test Quality Sentinel · 50.9 AIC · ⌖ 7.15 AIC · ⊞ 7K ·
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (2,177 new lines in pkg/cli/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/46855-refactor-bootstrap-profile-runner-into-focused-modules.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list any additional alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-46855: Refactor Bootstrap Profile Runner into Focused Modules

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 46855-refactor-bootstrap-profile-runner-into-focused-modules.md for PR #46855).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 57.6 AIC · ⌖ 10.2 AIC · ⊞ 8.5K ·
Comment /review to run again

@github-actions github-actions 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.

✅ Test Quality Sentinel: 89/100. 6% implementation tests (threshold: 30%).

@github-actions github-actions 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.

Review: Refactor bootstrap profile runner into focused modules

The refactor is well-structured — concerns are cleanly separated, the new modules are appropriately sized, and the injectable function variables preserve testability. Two non-blocking issues worth addressing:

  1. Unused ctx in concrete implementationsupsertBootstrapRepoVariable and setBootstrapRepoSecret accept ctx context.Context to match the injectable var signature but never use it; name it _ to make the intent explicit.

  2. Partial credential write (pre-existing, now more visible) — If writing AppIDVariable succeeds but PrivateKeySecret fails, the repo is left in an inconsistent state that silently prevents recovery on re-run. Worth reversing the variable on secret failure, or at minimum documenting the operator recovery step.

The 539-line test file size issue is already covered by an existing review comment.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 50.8 AIC · ⌖ 4.52 AIC · ⊞ 5K

Comments that could not be inline-anchored

pkg/cli/bootstrap_profile_actions_repo.go:97

Both upsertBootstrapRepoVariable and setBootstrapRepoSecret accept a ctx context.Context parameter that is never used in the function body. Since these are the concrete implementations assigned to the injectable bootstrapUpsertVariable/bootstrapSetSecret function variables, the parameter must match the type signature — but the unused parameter should use _ naming (e.g. _ context.Context) to make the intent explicit and avoid confusing future readers.

@copilot please address this.

pkg/cli/bootstrap_profile_github_app.go:546

Partial credential write on error: if bootstrapUpsertVariable for AppIDVariable succeeds but the subsequent bootstrapSetSecret for PrivateKeySecret fails, the repo ends up with the variable set but no private-key secret. The next run will skip the action entirely (hasVar &amp;&amp; hasSecret check at the top is false because the secret is still missing, but hasVar is now true), so re-running won't re-attempt the variable write and won't prompt for the private key via the normal path…

@github-actions github-actions 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.

Skills-Based Review 🧠

Applied /codebase-design — requesting changes on interface honesty, stdlib usage, and a potential hang.

📋 Key Themes & Highlights

Issues Found

  1. Unused ctx parametersupsertBootstrapRepoVariable and setBootstrapRepoSecret accept ctx but neither underlying function (upsertDefaultsVariable, setRepoSecret) takes a context. Cancellation and deadlines are silently lost; callers deserve an honest interface.

  2. Unbounded server shutdownserver.Shutdown(context.Background()) in the defer can hang indefinitely if an in-flight callback request is slow. A 5-second deadline is sufficient here.

  3. htmlEscape reinvents html.EscapeString — the standard library covers all HTML entities including '; a hand-rolled replacer will miss them over time.

  4. firstNonEmpty trims for emptiness but returns untrimmed — callers compensate with repeated strings.TrimSpace calls. The function should trim on return or not trim at all.

Positive Highlights

  • ✅ Clean split into focused modules — the separation of git, GitHub App, repo actions, and helpers is well-judged and makes the code significantly more navigable.
  • ✅ Good test coverage across all new modules, including non-interactive paths and edge cases.
  • ✅ The polling loop in waitForBootstrapGitHubAppInstallation correctly handles retryable errors vs. hard failures.
  • ✅ Idempotency guards (state.variables, state.secrets) are preserved in every action function.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 83.4 AIC · ⌖ 4.91 AIC · ⊞ 6.7K
Comment /matt to run again

if err != nil {
return err
}
target.scope = defaultsScopeRepo

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.

[/codebase-design] upsertBootstrapRepoVariable accepts ctx but silently discards it — upsertDefaultsVariable does not take a context, so cancellation and deadlines are lost. The same applies to setBootstrapRepoSecret (line 109).

💡 Options

Either propagate context into the underlying functions (preferred for long-term correctness), or drop the unused ctx parameter from both wrappers to keep the interface honest:

func upsertBootstrapRepoVariable(repo, name, value string) error { ... }
func setBootstrapRepoSecret(repo, name, value string) error { ... }

Callers already have ctx in scope, so this is a mechanical change.

@copilot please address this.

return "https://github.com/settings/apps/new?state=" + state
}

func renderBootstrapGitHubAppRegistrationPage(registrationURL string, manifest map[string]any) (string, error) {

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.

[/codebase-design] htmlEscape reimplements html.EscapeString from the standard library — using a hand-rolled replacer risks missing edge cases and adds maintenance surface.

💡 Suggested fix
import "html"

func htmlEscape(value string) string {
    return html.EscapeString(value)
}

Or inline html.EscapeString directly at the two call sites in renderBootstrapGitHubAppRegistrationPage.

@copilot please address this.

return hex.EncodeToString(buf), nil
}

func htmlEscape(value string) string {

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.

[/codebase-design] htmlEscape reimplements html.EscapeString from the standard library — a hand-rolled replacer risks missing future escape cases (e.g., single-quote) and adds maintenance surface.

💡 Suggested fix
import "html"

func htmlEscape(value string) string {
    return html.EscapeString(value)
}

Or inline html.EscapeString at the two call sites in renderBootstrapGitHubAppRegistrationPage and remove the helper entirely.

@copilot please address this.

return net.Listen("tcp", "127.0.0.1:0")
}

func firstNonEmpty(values ...string) string {

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.

[/codebase-design] firstNonEmpty checks strings.TrimSpace(value) != "" but returns the original untrimmed value — callers then call strings.TrimSpace again on the result (e.g., lines 732–737 in bootstrap_profile_github_app.go). Either trim before returning or document that callers are expected to trim.

💡 Option A – trim on return (consistent)
func firstNonEmpty(values ...string) string {
    for _, value := range values {
        if trimmed := strings.TrimSpace(value); trimmed != "" {
            return trimmed
        }
    }
    return ""
}

This eliminates the redundant strings.TrimSpace at every call site.

@copilot please address this.

Comment thread pkg/cli/bootstrap_profile_github_app.go Outdated
_ = server.Serve(listener)
}()
defer func() {
_ = server.Shutdown(context.Background())

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.

[/codebase-design] server.Shutdown(context.Background()) uses an unbounded context — if the server is slow to shut down (e.g., an in-flight callback request), this defer will block indefinitely with no timeout.

💡 Suggested fix

Use a short deadline so the deferred cleanup is bounded:

defer func() {
    shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    _ = server.Shutdown(shutdownCtx)
}()

@copilot please address this.

@github-actions github-actions 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.

REQUEST_CHANGES — 5 issues must be fixed before merge

This refactor is structurally sound but the extraction surfaced several correctness and security-adjacent bugs.

SecuritybootstrapExchangeGitHubAppCodeImpl: the OAuth code from the browser callback is interpolated directly into a gh api URL path without sanitisation. See inline comment.

CorrectnessresolveBootstrapSecretValue: interactive empty input returns ("", true, nil), causing callers to silently store a blank secret.

CorrectnesscompleteExistingGitHubAppCredentials: PEM private key trimmed with TrimSpace instead of TrimRight(..., "\r\n"), inconsistent with every other callsite and capable of corrupting PEM content.

Context propagationupsertBootstrapRepoVariable and setBootstrapRepoSecret accept ctx but never forward it; cancellation is silently dropped for network operations.

Resource leakopenBootstrapBrowser calls cmd.Start() without cmd.Wait(), leaving zombie processes on Unix.

🔎 Code quality review by PR Code Quality Reviewer · 121.8 AIC · ⌖ 4.95 AIC · ⊞ 5.6K
Comment /review to run again

func bootstrapExchangeGitHubAppCodeImpl(ctx context.Context, code, owner, ownerType, appName, description string) (*bootstrapCreatedGitHubApp, error) {
output, err := workflow.RunGHContext(ctx, "Exchanging GitHub App manifest code...", "api", "-X", "POST", "-H", "Accept: application/vnd.github+json", "/app-manifests/"+code+"/conversions")
if err != nil {
return nil, err

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.

Unvalidated OAuth code interpolated into API URL path: code from the browser callback is embedded directly into /app-manifests/"+code+"/conversions with no sanitisation.

💡 Suggested fix

The code parameter comes from r.URL.Query().Get("code") and is never validated before use. A path segment containing ../../ or percent-encoded characters could trigger unintended API endpoints. Validate the code before passing it downstream:

// in the /callback handler, before calling bootstrapExchangeGitHubAppCode:
if !isSimpleToken(code) {
    http.Error(w, "Invalid manifest code format.", http.StatusBadRequest)
    select { case flowCh.errCh <- errors.New("invalid manifest code format"): default: }
    return
}

func isSimpleToken(s string) bool {
    for _, c := range s {
        if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_') {
            return false
        }
    }
    return len(s) > 0
}

GitHub manifest codes are short alphanumeric strings; anything else should be rejected at the callback boundary.

if trimmed == "" {
return nil
}
lines := strings.Split(trimmed, "\n")

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.

Empty secret silently stored as ok=true: in the non-optional interactive path, if the user submits an empty string, resolveBootstrapSecretValue returns ("", true, nil) — a blank secret with no error.

💡 Suggested fix

After the console.PromptSecretInput call:

value = strings.TrimRight(value, "\r\n")
if value == "" {
    if optional {
        return "", false, nil
    }
    return "", false, errors.New("secret value cannot be empty")
}
return value, true, nil

Without this guard, runBootstrapRepoSecretAction and runBootstrapCopilotAuthAction will call bootstrapSetSecret with an empty string, silently overwriting a valid existing secret with a blank value in the repository.

}
if handled {
return nil, nil
}

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.

PEM key trimmed inconsistently: runBootstrapGitHubAppAction uses strings.TrimRight(key, "\r\n") to preserve leading whitespace in PEM blocks, but completeExistingGitHubAppCredentials uses strings.TrimSpace on the same value — stripping leading whitespace and potentially corrupting the key.

💡 Suggested fix

In completeExistingGitHubAppCredentials:

// was: privateKey := strings.TrimSpace(existingPrivateKey)
privateKey := strings.TrimRight(existingPrivateKey, "\r\n")

This aligns with how the env-var path handles the same field in runBootstrapGitHubAppAction (line ~522). PEM keys begin with -----BEGIN and must not have leading whitespace stripped.

if err != nil {
return err
}
target.scope = defaultsScopeRepo

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.

Context parameter ignored in upsertBootstrapRepoVariable: ctx is accepted but never forwarded, so cancellation and deadlines are silently dropped for the underlying network call.

💡 Details

upsertDefaultsVariable currently takes a defaultsTarget and name/value, with no context parameter. If it makes network calls (REST or git), the caller's context timeout won't propagate and the operation can hang after cancellation.

Same issue exists in setBootstrapRepoSecretapi.NewRESTClient and setRepoSecret don't receive ctx.

If these functions cannot accept a context today, the ctx parameter should either be removed from the exported signature to avoid the false safety signal, or the downstream functions should be updated to accept one.

return true, nil
case "0", "false", "no", "off":
return false, nil
default:

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.

openBootstrapBrowser leaks zombie processes: cmd.Start() is called without a corresponding cmd.Wait(), leaving zombie entries in the process table for every successful browser launch.

💡 Suggested fix
if err := cmd.Start(); err == nil {
    go func() { _ = cmd.Wait() }()
    return true
}

On Unix, a child process that has exited but whose parent hasn't called wait stays in the zombie state. For a short-lived CLI invocation this is usually harmless, but it's a correctness issue and a bad pattern to establish.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any remaining review feedback, and rerun checks once the branch is up to date.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pi.dev

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · 31.2 AIC · ⌖ 6.13 AIC · ⊞ 6.9K ·
Comment /souschef to run again

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the refactor! 🎯 This PR looks great — it tackles the oversized bootstrap_profile_runner.go file by cleanly separating concerns into five focused modules while preserving behavior and external API.

What stands out:

The separation into bootstrap_profile_actions_repo.go, bootstrap_profile_github_app.go, bootstrap_profile_git.go, and bootstrap_profile_helpers.go makes the codebase significantly easier to navigate and test independently.

This PR is ready for review and merge. 🚀

Generated by ✅ Contribution Check · 51.3 AIC · ⌖ 17.6 AIC · ⊞ 6.2K ·

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any remaining review feedback, and rerun checks once the branch is up to date.

...

Addressed the remaining bootstrap-profile review feedback in 4f04aaf. I reran make fmt, make lint, make test-unit, make test, make recompile, and make agent-report-progress locally; GitHub Actions on this new head will still need a maintainer-triggered rerun.

@pelikhan
pelikhan merged commit e330649 into main Jul 20, 2026
23 checks passed
@pelikhan
pelikhan deleted the copilot/file-diet-refactor-bootstrap-profile-runner-again branch July 20, 2026 18:29
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.15

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.

[file-diet] Refactor: pkg/cli/bootstrap_profile_runner.go exceeds healthy size threshold (1259 lines)

4 participants