diff --git a/.github/workflows/check_approved_limit.yml b/.github/workflows/check_approved_limit.yml
deleted file mode 100644
index b6aed9af..00000000
--- a/.github/workflows/check_approved_limit.yml
+++ /dev/null
@@ -1,54 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-name: Check Approved Actions Limit
-
-on:
- push:
- branches:
- - main
- paths:
- - approved_patterns.yml
- pull_request:
- paths:
- - approved_patterns.yml
- - .github/workflows/check_approved_limit.yml
-
-permissions:
- contents: read
-
-jobs:
- check-limit:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: false
-
- - name: Check approved actions count
- run: |
- # The org-wide approved_patterns list has a hard limit of 1000 entries.
- # We fail at 800 to give ourselves room to act before hitting the wall.
- # See https://github.com/apache/infrastructure-actions/issues/602
- LIMIT=800
- COUNT=$(grep -c '^- ' approved_patterns.yml)
- echo "Approved actions count: $COUNT / 1000 (warning threshold: $LIMIT)"
- if [ "$COUNT" -ge "$LIMIT" ]; then
- echo "::error::Approved actions count ($COUNT) has reached the warning threshold of $LIMIT. The org-wide limit is 1000. Time to clean up unused actions or explore workarounds. See https://github.com/apache/infrastructure-actions/issues/602"
- exit 1
- fi
diff --git a/.github/workflows/update_actions.yml b/.github/workflows/update_actions.yml
deleted file mode 100644
index 54baa5d0..00000000
--- a/.github/workflows/update_actions.yml
+++ /dev/null
@@ -1,91 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-name: Handle Dependabot update
-on:
- workflow_dispatch:
- push:
- branches:
- - main
- paths:
- - ".github/actions/for-dependabot-triggered-reviews/action.yml"
- pull_request:
- paths:
- - ".github/workflows/update_actions.yml"
- - ".github/actions/for-dependabot-triggered-reviews/action.yml"
- - gateway/*
-
-permissions:
- contents: read
-
-# We want workflows on main to run in order to avoid losing data through race conditions
-concurrency: "${{ github.ref }}-${{ github.workflow }}"
-
-jobs:
- update_actions:
- runs-on: ubuntu-latest
- permissions:
- contents: write
- steps:
-
- - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: true
- token: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN || github.token }} # zizmor: ignore[secrets-outside-env]
-
- - name: Print token details
- if: ${{ github.event_name != 'pull_request' }}
- env:
- GH_TOKEN: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN }} # zizmor: ignore[secrets-outside-env]
- run: |
- echo "::group::Token details"
- echo "Token user and permissions:"
- gh api /user --jq '"Login: \(.login)\nName: \(.name)\nEmail: \(.email)"'
- echo ""
- echo "Token expiration:"
- gh api /installation/token --jq '.expires_at' 2>/dev/null || echo "Token expiration not available (likely a PAT, not an installation token)"
- echo ""
- echo "Token scopes:"
- curl -sS -H "Authorization: token ${GH_TOKEN}" -I https://api.github.com/ 2>/dev/null | grep -i 'x-oauth-scopes' || echo "No OAuth scopes header (fine-grained or app token)"
- echo "::endgroup::"
-
- - run: pipx install uv
-
- - name: Update actions.yml
- run: |
- uv run python << 'PYEOF'
- import sys
- sys.path.append("./gateway/")
-
- import gateway as g
- g.update_actions(".github/actions/for-dependabot-triggered-reviews/action.yml", "actions.yml")
- g.update_patterns("approved_patterns.yml", "actions.yml")
- PYEOF
-
- - name: Commit and push changes
- if: ${{ github.event_name != 'pull_request' }}
- env:
- GH_TOKEN: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN || github.token }} # zizmor: ignore[secrets-outside-env]
- run: |
- AUTHOR_NAME=$(gh api /user --jq '.login' 2>/dev/null || echo "asfgit")
- AUTHOR_EMAIL=$(gh api /user --jq '.email // "\(.login)@users.noreply.github.com"' 2>/dev/null || echo "asfgit@users.noreply.github.com")
- git config --local user.name "${AUTHOR_NAME}"
- git config --local user.email "${AUTHOR_EMAIL}"
- git add -f actions.yml approved_patterns.yml
- git commit -m "Update actions.yml and approved_patterns.yml based on .github/actions/for-dependabot-triggered-reviews/action.yml" -m "Generated by .github/workflows/update_actions.yml" || echo "No changes"
- git push origin
diff --git a/.github/workflows/update_allowlist.yml b/.github/workflows/update_allowlist.yml
new file mode 100644
index 00000000..70121163
--- /dev/null
+++ b/.github/workflows/update_allowlist.yml
@@ -0,0 +1,172 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# Replaces the former pair `update_actions.yml` (composite -> actions.yml)
+# and `update_composite_action.yml` (actions.yml -> composite). Those ran
+# in separate concurrency groups and could race when both files changed in
+# overlapping pushes, silently overwriting one direction's edit. This
+# single workflow always runs both directions in order, so neither edit
+# is lost regardless of which file triggered the run. See #866.
+#
+# Also subsumes the former `check_approved_limit.yml`: the 800/1000-entry
+# cap on approved_patterns.yml is now enforced inline (see the "Check
+# approved actions count" step). Folding it in here means no downstream
+# push-triggered workflow needs to fire after this workflow commits, so
+# the workflow can authenticate with the default GITHUB_TOKEN — no PAT.
+name: Update Allowlist
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - main
+ paths:
+ - "actions.yml"
+ - ".github/actions/for-dependabot-triggered-reviews/action.yml"
+ pull_request:
+ paths:
+ - ".github/workflows/update_allowlist.yml"
+ - ".github/actions/for-dependabot-triggered-reviews/action.yml"
+ - "actions.yml"
+ - "gateway/*"
+
+permissions:
+ contents: read
+
+# Single group across both inputs so no two updates touch the allowlist
+# files in parallel. Don't cancel — every queued run must finish so we
+# don't drop a dependabot bump or a manual actions.yml edit.
+concurrency:
+ group: "${{ github.ref }}-update-allowlist"
+ cancel-in-progress: false
+
+jobs:
+ update:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ steps:
+
+ - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: true
+ # On push/dispatch, check out the current tip of main rather
+ # than the trigger SHA. A queued run that started on an older
+ # SHA would otherwise regenerate from stale inputs and either
+ # undo the prior run's commit or fail to push.
+ ref: ${{ (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && 'main' || '' }}
+
+ - run: pipx install uv
+
+ - name: Sync composite action, actions.yml, and approved_patterns.yml
+ run: |
+ uv run python << 'PYEOF'
+ import sys
+ sys.path.append("./gateway/")
+
+ import gateway as g
+
+ composite = ".github/actions/for-dependabot-triggered-reviews/action.yml"
+ actions = "actions.yml"
+ patterns = "approved_patterns.yml"
+
+ # Always run both directions. The previous two-workflow split
+ # raced on overlapping pushes; running both here means the
+ # outcome is the same regardless of which file triggered us.
+ #
+ # 1. Pull any new refs from the composite (e.g. dependabot
+ # bumps) into actions.yml. Additive: existing entries stay
+ # and get their expiry refreshed.
+ g.update_actions(composite, actions)
+
+ # 2. Regenerate the composite from the (now-merged)
+ # actions.yml so a manual actions.yml edit is reflected.
+ g.update_workflow(composite, actions)
+
+ # 3. Regenerate the approved patterns from actions.yml.
+ g.update_patterns(patterns, actions)
+ PYEOF
+
+ - name: Check approved actions count
+ # Inlined from the former check_approved_limit.yml. The org-wide
+ # approved_patterns list has a hard limit of 1000 entries; we
+ # fail at 800 to give maintainers room to act before hitting the
+ # wall. Runs after regeneration and before commit/push, so an
+ # over-cap state never lands on main. See
+ # https://github.com/apache/infrastructure-actions/issues/602
+ run: |
+ LIMIT=800
+ COUNT=$(grep -c '^- ' approved_patterns.yml)
+ echo "Approved actions count: $COUNT / 1000 (warning threshold: $LIMIT)"
+ if [ "$COUNT" -ge "$LIMIT" ]; then
+ echo "::error::Approved actions count ($COUNT) has reached the warning threshold of $LIMIT. The org-wide limit is 1000. Time to clean up unused actions or explore workarounds. See https://github.com/apache/infrastructure-actions/issues/602"
+ exit 1
+ fi
+
+ - name: Commit and push changes
+ if: ${{ github.event_name != 'pull_request' }}
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ AUTHOR_NAME=$(gh api /user --jq '.login' 2>/dev/null || echo "asfgit")
+ AUTHOR_EMAIL=$(gh api /user --jq '.email // "\(.login)@users.noreply.github.com"' 2>/dev/null || echo "asfgit@users.noreply.github.com")
+ git config --local user.name "${AUTHOR_NAME}"
+ git config --local user.email "${AUTHOR_EMAIL}"
+
+ composite=".github/actions/for-dependabot-triggered-reviews/action.yml"
+ if git diff --quiet -- actions.yml approved_patterns.yml "${composite}"; then
+ echo "No changes"
+ exit 0
+ fi
+
+ git add -f actions.yml approved_patterns.yml "${composite}"
+ git commit \
+ -m "Sync actions.yml, composite action, and approved_patterns.yml" \
+ -m "Generated by .github/workflows/update_allowlist.yml"
+
+ # If a concurrent push (e.g. remove_expired.yml) advanced main
+ # while we were computing, rebase and retry. The sync script is
+ # idempotent so re-running on the rebased tree is safe.
+ for attempt in 1 2 3; do
+ if git push origin HEAD:main; then
+ exit 0
+ fi
+ echo "Push rejected on attempt ${attempt}; rebasing and re-running sync"
+ git fetch origin main
+ git reset --hard origin/main
+ uv run python << 'PYEOF'
+ import sys
+ sys.path.append("./gateway/")
+ import gateway as g
+ composite = ".github/actions/for-dependabot-triggered-reviews/action.yml"
+ actions = "actions.yml"
+ patterns = "approved_patterns.yml"
+ g.update_actions(composite, actions)
+ g.update_workflow(composite, actions)
+ g.update_patterns(patterns, actions)
+ PYEOF
+ if git diff --quiet -- actions.yml approved_patterns.yml "${composite}"; then
+ echo "Already in sync after rebase; nothing to push"
+ exit 0
+ fi
+ git add -f actions.yml approved_patterns.yml "${composite}"
+ git commit \
+ -m "Sync actions.yml, composite action, and approved_patterns.yml" \
+ -m "Generated by .github/workflows/update_allowlist.yml"
+ done
+ echo "Failed to push after 3 attempts"
+ exit 1
diff --git a/.github/workflows/update_composite_action.yml b/.github/workflows/update_composite_action.yml
deleted file mode 100644
index 2b3d58d2..00000000
--- a/.github/workflows/update_composite_action.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-name: Update Approved Patterns and Composite Action
-on:
- workflow_dispatch:
- push:
- branches:
- - main
- paths:
- - "actions.yml"
- pull_request:
- paths:
- - ".github/workflows/update_composite_action.yml"
- - "actions.yml"
- - gateway/*
-
-permissions: {}
-
-# We want workflows on main to run in order to avoid losing data through race conditions
-concurrency: "${{ github.ref }}-${{ github.workflow }}"
-
-jobs:
- update:
- name: Update Workflow
- runs-on: ubuntu-latest
- steps:
-
- - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: true
- # We have to use a PAT to commit the workflow file
- token: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN || github.token }} # zizmor: ignore[secrets-outside-env]
-
- - name: Print token details
- if: ${{ github.event_name != 'pull_request' }}
- env:
- GH_TOKEN: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN }} # zizmor: ignore[secrets-outside-env]
- run: |
- echo "::group::Token details"
- echo "Token user and permissions:"
- gh api /user --jq '"Login: \(.login)\nName: \(.name)\nEmail: \(.email)"'
- echo ""
- echo "Token expiration:"
- gh api /installation/token --jq '.expires_at' 2>/dev/null || echo "Token expiration not available (likely a PAT, not an installation token)"
- echo ""
- echo "Token scopes:"
- curl -sS -H "Authorization: token ${GH_TOKEN}" -I https://api.github.com/ 2>/dev/null | grep -i 'x-oauth-scopes' || echo "No OAuth scopes header (fine-grained or app token)"
- echo "::endgroup::"
-
- - run: pipx install uv
-
- - name: Update Workflow
- run: |
- uv run python << 'PYEOF'
- import sys
- sys.path.append("./gateway/")
-
- import gateway as g
- g.update_workflow(".github/actions/for-dependabot-triggered-reviews/action.yml", "actions.yml")
- g.update_patterns("approved_patterns.yml", "actions.yml")
- PYEOF
-
- - name: Commit and push changes
- if: ${{ github.event_name != 'pull_request' }}
- env:
- GH_TOKEN: ${{ secrets.ALLOWLIST_WORKFLOW_TOKEN || github.token }} # zizmor: ignore[secrets-outside-env]
- run: |
- AUTHOR_NAME=$(gh api /user --jq '.login' 2>/dev/null || echo "asfgit")
- AUTHOR_EMAIL=$(gh api /user --jq '.email // "\(.login)@users.noreply.github.com"' 2>/dev/null || echo "asfgit@users.noreply.github.com")
- git config --local user.name "${AUTHOR_NAME}"
- git config --local user.email "${AUTHOR_EMAIL}"
- git add -f .github/actions/for-dependabot-triggered-reviews/action.yml approved_patterns.yml
- git commit -m "Update approved_patterns.yml and .github/actions/for-dependabot-triggered-reviews/action.yml based on actions.yml" -m "Generated by .github/workflows/update_composite_action.yml" || echo "No changes"
- git push origin
diff --git a/README.md b/README.md
index 27e74991..9cf5c050 100644
--- a/README.md
+++ b/README.md
@@ -119,41 +119,39 @@ graph LR
human-->actions
dependabot-->composite
- dependabot-.verified by.-verify["verify_dependabot_action.yml
(rebuild & diff)"]
+ dependabot-.verified by.-verify["verify job
(rebuild & diff)"]
- composite=="update_actions.yml
(on merge)"==>actions
- cron=="remove_expired.yml"==>actions
+ composite=="update job
(on merge)"==>actions
+ cron=="clean_up job"==>actions
- actions=="update_composite_action.yml"==>composite
- actions=="update_composite_action.yml"==>approved
-
- guard["check_approved_limit.yml
(fails at 800 / 1000)"]-.monitors.-approved
+ actions=="update job"==>composite
+ actions=="update job
(cap check + regen)"==>approved
classDef source fill:#fff3b0,stroke:#8a6d0b,color:#333
classDef generated fill:#e0f0ff,stroke:#2563a6,color:#333
classDef trigger fill:#f3e0ff,stroke:#6a1b9a,color:#333
- classDef workflow fill:#e6ffe6,stroke:#1b5e20,color:#333
+ classDef job fill:#e6ffe6,stroke:#1b5e20,color:#333
class actions source
class composite,approved generated
class human,dependabot,cron trigger
- class verify,guard workflow
+ class verify job
```
-Solid arrows (`==>`) are workflow regeneration edges — the "source → generated" flows that keep `actions.yml`, `approved_patterns.yml` and the dependabot composite in sync. Thin arrows feed the pipeline with new content (human or Dependabot PRs, cron), and dotted arrows are observer workflows that verify or guard rather than mutate.
+Solid arrows (`==>`) are regeneration edges — the "source → generated" flows that keep `actions.yml`, `approved_patterns.yml` and the dependabot composite in sync. Thin arrows feed the pipeline with new content (human or Dependabot PRs, cron), and dotted arrows are observer jobs that verify rather than mutate. Bold labels are job names (rather than workflow filenames) — `update` lives in `update_allowlist.yml`, `verify` in `verify_dependabot_action.yml` / `verify_manual_action.yml`, `clean_up` in `remove_expired.yml`.
> [!NOTE]
-> `check_approved_limit.yml` guards the whole pipeline: the org-wide allow list has a hard cap of 1000 entries, and this workflow fails at 800 to give maintainers room to clean up before hitting the wall.
+> The 800/1000-entry cap on `approved_patterns.yml` is enforced as a step inside the `update` job (formerly the separate `check_approved_limit.yml`). It runs after regeneration and before commit/push, so an over-cap state never lands on `main`. Folding the check in here also lets the workflow push with the default `GITHUB_TOKEN` — no PAT, no downstream-trigger requirement.
### Adding a New Action to the Allow List
```mermaid
graph TD;
manual["manual PR"]--new entry-->actions.yml
- actions.yml--"update_composite_action.yml"-->composite[".github/actions/for-dependabot-triggered-reviews/action.yml"]
- actions.yml--"update_composite_action.yml"-->approved["approved_patterns.yml"]
+ actions.yml--"update job"-->composite[".github/actions/for-dependabot-triggered-reviews/action.yml"]
+ actions.yml--"update job"-->approved["approved_patterns.yml"]
```
-A human-authored PR edits `actions.yml` directly. Once it merges to `main`, the **`update_composite_action.yml`** workflow regenerates both `.github/actions/for-dependabot-triggered-reviews/action.yml` and `approved_patterns.yml` from the new entries, so contributors never have to hand-edit the generated files.
+A human-authored PR edits `actions.yml` directly. Once it merges to `main`, the **`update`** job (in `update_allowlist.yml`) regenerates both `.github/actions/for-dependabot-triggered-reviews/action.yml` and `approved_patterns.yml` from the new entries, so contributors never have to hand-edit the generated files.
To request addition of an action to the allow list:
@@ -184,15 +182,15 @@ The infrastructure team will review your request and either approve, request cha
```mermaid
graph TD;
dependabot--"PR updates"-->composite[".github/actions/for-dependabot-triggered-reviews/action.yml"]
- dependabot-.verified by.-verify["verify_dependabot_action.yml"]
- composite--"update_actions.yml (on merge)"-->actions.yml
- actions.yml--"update_actions.yml"-->approved["approved_patterns.yml"]
+ dependabot-.verified by.-verify["verify job"]
+ composite--"update job (on merge)"-->actions.yml
+ actions.yml--"update job"-->approved["approved_patterns.yml"]
```
In most cases, new versions are automatically added through Dependabot:
- Dependabot opens PRs against `.github/actions/for-dependabot-triggered-reviews/action.yml` to update actions to the newest releases
-- **`verify_dependabot_action.yml`** runs on each such PR, rebuilds the action's compiled JavaScript in Docker, and diffs it against the published version (see [Automated Verification in CI](#automated-verification-in-ci))
-- Once a reviewer merges the PR, **`update_actions.yml`** reflects the new commit SHAs back into `actions.yml` and regenerates `approved_patterns.yml`
+- The **`verify`** job (in `verify_dependabot_action.yml`) runs on each such PR, rebuilds the action's compiled JavaScript in Docker, and diffs it against the published version (see [Automated Verification in CI](#automated-verification-in-ci))
+- Once a reviewer merges the PR, the **`update`** job (in `update_allowlist.yml`) reflects the new commit SHAs back into `actions.yml`, regenerates `approved_patterns.yml`, and enforces the 800/1000-entry cap inline before pushing
- The previously approved version is marked with an `expires_at` date 3 months out, giving projects a grace period to update their workflows; see [Automatic Expiration of Old Versions](#automatic-expiration-of-old-versions) for how the cleanup runs
Projects are encouraged to help review updates to actions they use. Please have a look at the diff and mention in your approval what you have checked and why you think the action is safe.
@@ -273,8 +271,8 @@ The `--no-gh` mode supports all the same features as the default `gh`-based mode
Two workflows in `.github/workflows/` run `verify-action-build` on PRs that touch the allow list, so the verification status is visible on every PR as a required-candidate status check:
-- **`verify_dependabot_action.yml`** — triggers on Dependabot PRs that modify `.github/actions/for-dependabot-triggered-reviews/action.yml`. Extracts the action reference from the PR, rebuilds the compiled JavaScript in Docker, and compares it against the published version.
-- **`verify_manual_action.yml`** — triggers on human-authored PRs that modify `actions.yml` or `approved_patterns.yml` (i.e. manual allow-list additions / version bumps). Dependabot-authored PRs are skipped, since they are already covered by the workflow above.
+- **`verify` job in `verify_dependabot_action.yml`** — triggers on Dependabot PRs that modify `.github/actions/for-dependabot-triggered-reviews/action.yml`. Extracts the action reference from the PR, rebuilds the compiled JavaScript in Docker, and compares it against the published version.
+- **`verify` job in `verify_manual_action.yml`** — triggers on human-authored PRs that modify `actions.yml` or `approved_patterns.yml` (i.e. manual allow-list additions / version bumps). Dependabot-authored PRs are skipped, since they are already covered by the workflow above.
Both workflows use a regular `pull_request` trigger with read-only permissions and no PR comments — pass/fail is surfaced through the status check. Neither workflow auto-approves or merges; a human reviewer must still approve.
@@ -355,23 +353,23 @@ If you add older version of the action and want to set an expiration date for it
```mermaid
graph TD;
- entry["actions.yml entry
with expires_at"]--"remove_expired.yml (daily, 02:04 UTC)"-->actions.yml
- actions.yml--"update_composite_action.yml"-->composite[".github/actions/for-dependabot-triggered-reviews/action.yml"]
- actions.yml--"update_composite_action.yml"-->approved["approved_patterns.yml"]
+ entry["actions.yml entry
with expires_at"]--"clean_up job (daily, 02:04 UTC)"-->actions.yml
+ actions.yml--"update job"-->composite[".github/actions/for-dependabot-triggered-reviews/action.yml"]
+ actions.yml--"update job"-->approved["approved_patterns.yml"]
```
Routine cleanup of superseded versions is automated:
- Any entry in `actions.yml` with an `expires_at: YYYY-MM-DD` field is a candidate for removal.
- Dependabot-driven updates (see [Updating Version of Already Approved Action](#updating-version-of-already-approved-action)) set `expires_at` to **3 months out** on the previously approved version. For manually added older versions, set `expires_at` explicitly (see [Manual Addition of Specific Versions](#manual-addition-of-specific-versions)).
-- The **`remove_expired.yml`** workflow runs daily at **02:04 UTC**. Every entry whose `expires_at` date has passed is deleted from `actions.yml`; the workflow then commits the change and lets `update_composite_action.yml` regenerate `approved_patterns.yml` and the dependabot composite.
+- The **`clean_up`** job (in `remove_expired.yml`) runs daily at **02:04 UTC**. Every entry whose `expires_at` date has passed is deleted from `actions.yml`; the job then commits the change and lets the `update` job in `update_allowlist.yml` regenerate `approved_patterns.yml` and the dependabot composite.
- Entries without `expires_at` (for example, `keep: true` wildcards and the current approved version) are never auto-removed — removal of those requires a manual PR.
No human action is required for the routine case: projects get a 3-month grace window after a version bump, and the old entry disappears on its own afterwards.
### Removing a version manually
-Routine removal is already automated: set `expires_at` on the entry and the daily `remove_expired.yml` workflow will delete it once the date passes. Use the manual process below only when you need an immediate removal that can't wait for the entry to expire.
+Routine removal is already automated: set `expires_at` on the entry and the daily `clean_up` job (in `remove_expired.yml`) will delete it once the date passes. Use the manual process below only when you need an immediate removal that can't wait for the entry to expire.
> [!IMPORTANT]
> If a version or entire action needs to be removed immediately due to a security vulnerability: