feat: add dry-run stale PR lifecycle workflow - #43
Open
xnoto wants to merge 5 commits into
Open
Conversation
Shared Workflows CIShared workflows CI passed. View run output |
14 tasks
xnoto
added a commit
that referenced
this pull request
Sep 9, 2026
## Summary Supersedes #43, whose branch could not be updated because of a README conflict after `main` advanced. Adds `_stale-pull-requests.yml`, a dry-run-first reusable workflow for the approved 30-day inactive-PR policy. Fixes # None. ## Type of change - [ ] Bug fix - [x] Feature / enhancement - [x] Documentation - [ ] Infrastructure (OpenTofu root or module) - [ ] GitOps desired state (manifests, kustomize, charts, SOPS/KSOPS secrets) - [ ] Container image - [x] CI / reusable workflow - [ ] Refactor / cleanup - [ ] Breaking change ## Validation - [ ] Required pull-request checks pass — pending `lint` on this rebased PR. - [x] Generated or centrally distributed files were regenerated by their owning automation, not hand-edited — this is the reusable-workflow producer; no consumer file changes. - The final implementation was adversarially and infrastructure-security reviewed with no Critical or High findings. The rebased branch retains the reviewed workflow logic and incorporates current `main` README guidance. - QA confirmed static CI does not execute destructive behavior; a reviewed `dry-run: true` consumer pilot remains mandatory before live mode. ## Impact and rollout **Producer:** `shared-workflows` owns `_stale-pull-requests.yml`. It uses only a full-SHA-pinned GitHub Script action. **Consumer:** none yet. A later `tfroot-github`-owned caller and repository-local bootstrap PRs are required. This merge makes the producer callable but does not schedule, close, or delete anything. **Behavior:** `dry-run` defaults to true. Live mode closes non-draft, unassigned, unmilestoned PRs with `pullRequest.updated_at` at least 30 days old, excluding `do-not-close`, `blocked`, and `security`. It deletes only eligible, same-repository, unprotected non-default branches after verified closure and head/base reference checks; fork heads are skipped. **Delivery stages:** authored and submitted. `lint` is pending. Merge is confirmation-gated. Consumer selection, dry-run pilot, live-mode enablement, PR closure, branch deletion, and any OpenTofu apply are all separate gates. **Rollback:** do not add a caller, or remove/disable it before live mode. A mistakenly closed PR can be reopened and GitHub's Restore branch path is the intended branch recovery method. ## Safety and secrets - [x] Contains no plaintext secrets, decrypted SOPS values, state files, kubeconfigs, tokens, or private endpoints. - [x] No local OpenTofu init/plan/apply/destroy/import/state operations were run or claimed — plans come from pull-request checks. - [x] Breaking or irreversible effects are described above with rollback notes. AI-assisted change: owner-approved implementation, dry-run by default. No consumer is activated by this PR.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
_stale-pull-requests.yml, a reusable, dry-run-first workflow for the approved PR lifecycle policy. In live mode it closes eligible PRs whosepullRequest.updated_atis at least 30 days old, then deletes only an eligible same-repository head branch that GitHub can restore from the closed PR.Fixes #
None.
Type of change
Validation
lint.dry-run: trueconsumer pilot remains required before live mode.Impact and rollout
Producer:
shared-workflowsowns the new_stale-pull-requests.ymlreusable workflow and its GitHub Script action pin.Consumer: no repository calls this workflow yet. A later
tfroot-githubchange must own the scheduled caller at.github/workflows/stale-pull-requests.yml; existing protected repositories require their own bootstrap PRs.Behavior: the caller receives no secrets and must grant
contents: writeandpull-requests: write.dry-rundefaults totrue. Live mode excludes drafts, assigned and milestoned PRs, and PRs labeleddo-not-close,blocked, orsecurity. It checks head/base references, default-branch status, protection, and same-repository ownership before deletion. Fork head branches are not deleted.Delivery stages: authored and submitted. PR
lintis pending. Merge is a separate confirmation gate. After merge, the producer is callable but inert until a reviewed consumer dry-run caller is merged. Enabling live mode, closing PRs, deleting branches, and anytfroot-githubapply remain separate confirmation-gated operations.Rollback: do not add a caller, or remove/disable its caller before live mode. A mistakenly closed PR can be reopened; GitHub's closed-PR Restore branch path is the intended branch recovery mechanism.
Safety and secrets
AI-assisted change: an OpenCode agent authored the reusable workflow after the owner approved the 30-day policy. It is dry-run-first and does not activate any consumer repository.