fix(#1960): include disabled repos in repo-maintenance token scope - #1962
Conversation
Site previewPreview: https://61d05b7a-site.fullsend-ai.workers.dev Commit: |
ReviewFindingsLow
Info
Previous runReviewFindingsLow
Previous run (2)ReviewFindingsLow
Info
|
| // Find the most recent repo-maintenance run so we can capture debug info | ||
| // if it failed. The CLI already watched it to completion, so it should | ||
| // exist and be completed. | ||
| var repoMaintRun *forge.WorkflowRun |
There was a problem hiding this comment.
[low] edge-case
The unenrollment debug-info capture takes runs[0] from ListWorkflowRuns without timestamp filtering, unlike the triage test which filters by CreatedAt. Since the CLI already watches the workflow to completion and each e2e org is isolated, runs[0] is reliable in practice, but adding a timestamp filter would improve robustness.
Suggested fix: Capture time.Now() before runCLI and filter ListWorkflowRuns results by CreatedAt, matching the pattern used in the triage test.
| @@ -584,6 +593,20 @@ func runUnenrollmentTest(t *testing.T, env *e2eEnv) { | |||
| "admin", "disable", "repos", env.org, testRepo, "--yolo") | |||
| t.Logf("Disable repos output:\n%s", output) | |||
|
|
|||
There was a problem hiding this comment.
[low] edge-case
The unenrollment debug-info capture takes runs[0] from ListWorkflowRuns without timestamp filtering, unlike the triage test (line 314) which filters by CreatedAt. Since the CLI disable repos command already watches the repo-maintenance workflow to completion before returning, and each e2e org is isolated, runs[0] is reliably the correct run in practice. Adding a timestamp filter would improve robustness if the test structure changes in the future.
| _ = os.MkdirAll(debugDir, 0o755) | ||
|
|
||
| logs, logErr := env.client.GetWorkflowRunLogs(ctx, env.org, forge.ConfigRepoName, run.ID) | ||
| if logErr != nil { |
There was a problem hiding this comment.
[low] annotation-format
saveWorkflowRunDebugInfo produces malformed GitHub Actions annotations for file-specific log lines. The annotation variable ends with :: (e.g. ::notice::), so the format string "%sfile=%s::..." produces ::notice::file=path::message instead of the correct ::notice file=path::message. The file= parameter will not be parsed by GitHub Actions.
Suggested fix: Split the annotation prefix so the file-parameter variant uses the bare command (e.g. ::notice / ::warning) rather than reusing the ::notice:: form.
| REPOS=$(yq '[.repos | to_entries[] | select(.value.enabled == true) | .key] | join(",")' config.yaml) | ||
| if [[ -z "$REPOS" ]]; then | ||
| echo "::notice::No enabled repos found in config.yaml — nothing to do" | ||
| # Collect ALL repos (enabled + disabled) so the minted token has |
There was a problem hiding this comment.
[low] edge-case
The yq filter select(.value.enabled == true or .value.enabled == false) excludes repos where .enabled is missing, null, or a non-boolean value. This matches the reconcile script behavior so there is no mismatch, but is worth noting for future config.yaml schema changes.
Extract saveWorkflowRunDebugInfo from the triage phase so both triage and unenrollment use the same code to fetch workflow logs, download artifacts, and emit GitHub Actions annotations on failure. In the unenrollment phase, find the most recent repo-maintenance run after the CLI returns and capture its logs if it failed. This gives us visibility into why the removal PR never appears. Closes #1960 Signed-off-by: Ralph Bean <rbean@redhat.com> Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
The minted token only covered enabled repos, so the reconcile script couldn't access disabled repos during unenrollment. API calls failed silently (2>/dev/null), causing the script to treat them as "already unenrolled" and skip removal PR creation. Also capture repo-maintenance workflow logs unconditionally in the e2e test so silent-skip problems leave a debug trail even when the workflow reports success. Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
- Replace two yq queries + bash concatenation with a single query that selects both enabled and disabled repos - Return debugDir from saveWorkflowRunDebugInfo so callers can reference it in failure messages - Consolidate the two removal-PR failure paths into one with conditional repo-maintenance run context - Update test assertion to match the simplified yq query Assisted-by: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
…eters Split annotation prefix into annotationMsg (::notice::) for plain messages and annotationFile (::notice ) for file-parameter annotations. The previous code reused ::notice:: for both, producing malformed annotations like ::notice::file=path::message instead of the correct ::notice file=path::message. Assisted-by: Claude claude-opus-4-6 <noreply@anthropic.com> Signed-off-by: Ralph Bean <rbean@redhat.com>
055b969 to
e9ec1f2
Compare
|
Review skipped — this PR is already merged. The Posted by fullsend post-review check |
Retro: PR #1962 — include disabled repos in repo-maintenance token scopeWorkflow quality: Good. This was a human-authored PR by Timeline: Issue filed → triage bot summary (6 min) → PR opened (35 min) → 3 review iterations over 2 days → human approval → merged. Total: ~43 hours. No new proposals. The main inefficiency observed — the review bot re-posting the same |
Summary
2>/dev/null), and the script treated them as "already unenrolled" — skipping removal PR creation entirely while reporting success.saveWorkflowRunDebugInfoso triage and unenrollment share the same log/artifact capture code::warning::annotations for failed runs,::notice::for successful onesTestRepoMaintenanceTokenCoversAllReposto prevent regressionRoot cause
repo-maintenance.ymlstep "Extract enrolled repo names from config" only selectedenabled == truerepos:REPOS=$(yq '[... | select(.value.enabled == true) | .key] | join(",")' config.yaml)This meant the minted token had no permissions for disabled repos. The reconcile script's Phase 2 unenrollment tried
gh api repos/$ORG/$REPO/contents/...on disabled repos, which returned 403 (swallowed by2>/dev/null), causing line 530-533 to conclude "no shim on default branch" and skip the repo.Fix
The step now collects both enabled and disabled repos for token minting:
Test plan
TestRepoMaintenanceTokenCoversAllRepos— asserts disabled repos are includedgo vet -tags e2e ./e2e/admin/passesmake lintpassesCloses #1960