Skip to content

feat: add dry-run stale PR lifecycle workflow - #43

Open
xnoto wants to merge 5 commits into
mainfrom
feat/stale-pr-lifecycle
Open

feat: add dry-run stale PR lifecycle workflow#43
xnoto wants to merge 5 commits into
mainfrom
feat/stale-pr-lifecycle

Conversation

@xnoto

@xnoto xnoto commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

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 whose pullRequest.updated_at is 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

  • Bug fix
  • Feature / enhancement
  • Documentation
  • Infrastructure (OpenTofu root or module)
  • GitOps desired state (manifests, kustomize, charts, SOPS/KSOPS secrets)
  • Container image
  • CI / reusable workflow
  • Refactor / cleanup
  • Breaking change

Validation

  • Required pull-request checks pass — pending lint.
  • Generated or centrally distributed files were regenerated by their owning automation, not hand-edited — no generated consumer file is changed; this is the reusable-workflow producer.
  • Adversarial review found no remaining Critical or High findings after branch-closure and branch-deletion safeguards were corrected.
  • Infrastructure-security review found no Critical or High findings.
  • QA review confirms existing CI provides static workflow validation only; a reviewed dry-run: true consumer pilot remains required before live mode.
  • GitHub Advanced Security secret scanning is unavailable for this repository; reviewer inspection found no secrets.

Impact and rollout

Producer: shared-workflows owns the new _stale-pull-requests.yml reusable workflow and its GitHub Script action pin.

Consumer: no repository calls this workflow yet. A later tfroot-github change 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: write and pull-requests: write. dry-run defaults to true. Live mode excludes drafts, assigned and milestoned PRs, and PRs labeled do-not-close, blocked, or security. 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 lint is 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 any tfroot-github apply 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

  • Contains no plaintext secrets, decrypted SOPS values, state files, kubeconfigs, tokens, or private endpoints.
  • No local OpenTofu init/plan/apply/destroy/import/state operations were run or claimed — plans come from pull-request checks.
  • Breaking or irreversible effects are described above with rollback notes.

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.

@xnoto
xnoto requested a review from a team as a code owner September 9, 2026 06:40
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

Shared Workflows CI

Shared workflows CI passed.

View the workflow run.

View run output
[INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Initializing environment for https://github.com/gitleaks/gitleaks.
[INFO] Initializing environment for https://github.com/rhysd/actionlint.
[INFO] Installing environment for https://github.com/pre-commit/pre-commit-hooks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/gitleaks/gitleaks.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
[INFO] Installing environment for https://github.com/rhysd/actionlint.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
check for case conflicts.................................................Passed
check for merge conflicts................................................Passed
check for broken symlinks............................(no files to check)Skipped
check vcs permalinks.....................................................Passed
detect destroyed symlinks................................................Passed
detect private key.......................................................Passed
mixed line ending........................................................Passed
trim trailing whitespace.................................................Passed
Detect hardcoded secrets.................................................Passed
Lint GitHub Actions workflow files.......................................Passed

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.
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.

1 participant