Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions .github/workflows/image-cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,43 @@ on:
permissions: {}

jobs:
collect-digests:
name: 📦 Collect Digests (${{ matrix.package }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [amp-devcontainer-base, amp-devcontainer-cpp, amp-devcontainer-rust]
permissions:
packages: read # is needed to list package versions
steps:
- uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
with:
disable-sudo-and-containers: true
egress-policy: audit
allowed-endpoints: api.github.com:443
- name: Collect package digests
run: |
set -Eeuo pipefail
ORG="${GH_REPO%%/*}"
gh api "/orgs/${ORG}/packages/container/${GH_PACKAGE}/versions" \
--paginate \
--jq '.[].name' 2>/dev/null > digests.txt || touch digests.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
GH_PACKAGE: ${{ matrix.package }}
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: digests-before-cleanup-${{ matrix.package }}
path: digests.txt
if-no-files-found: warn
retention-days: 1

cleanup-images:
name: 🧹 Clean Images
if: always()
needs: collect-digests
runs-on: ubuntu-latest
permissions:
packages: write # is needed by dataaxiom/ghcr-cleanup-action to delete untagged and orphaned images
Expand All @@ -26,3 +61,51 @@ jobs:
delete-orphaned-images: true
delete-untagged: true
packages: amp-devcontainer,amp-devcontainer-cpp,amp-devcontainer-rust

cleanup-attestations:
name: 🔏 Cleanup Orphaned Attestations (${{ matrix.package }})
needs: cleanup-images
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [amp-devcontainer-base, amp-devcontainer-cpp, amp-devcontainer-rust]
permissions:
attestations: write # is needed to delete attestations
packages: read # is needed to list remaining package versions after cleanup
steps:
- uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
with:
disable-sudo-and-containers: true
egress-policy: audit
allowed-endpoints: api.github.com:443
- uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
id: download-digests
continue-on-error: true
with:
name: digests-before-cleanup-${{ matrix.package }}
- name: Delete orphaned attestations
if: steps.download-digests.outcome == 'success'
run: |
set -Eeuo pipefail
ORG="${GH_REPO%%/*}"

# Get remaining digests after image cleanup
current_digests=$(gh api "/orgs/${ORG}/packages/container/${GH_PACKAGE}/versions" \
--paginate \
--jq '.[].name' 2>/dev/null || echo "")

# Delete attestations for digests that no longer have a package version
while read -r digest; do
[[ -z "$digest" ]] && continue
if ! echo "$current_digests" | grep -qx "$digest"; then
echo "Deleting attestations for removed digest: ${digest}"
encoded_digest="${digest//:/%3A}"
gh api --method DELETE "/orgs/${ORG}/attestations/digest/${encoded_digest}" \
2>/dev/null && echo "Deleted" || echo "No attestations found (already cleaned up)"
fi
done < digests.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
GH_PACKAGE: ${{ matrix.package }}
80 changes: 80 additions & 0 deletions .github/workflows/pr-image-cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,47 @@ on:
permissions: {}

jobs:
collect-pr-digests:
name: 📦 Collect PR Digests (${{ matrix.package }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [amp-devcontainer-base, amp-devcontainer-cpp, amp-devcontainer-rust]
permissions:
packages: read # is needed to find the digest for the PR tag
steps:
- uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
with:
disable-sudo-and-containers: true
egress-policy: audit
allowed-endpoints: api.github.com:443
- name: Find PR image digest
run: |
set -Eeuo pipefail
ORG="${GH_REPO%%/*}"
PR_TAG="pr-${PR_NUMBER}"
digest=$(gh api "/orgs/${ORG}/packages/container/${GH_PACKAGE}/versions" \
--paginate \
--jq ".[] | select((.metadata.container.tags // []) | contains([\"${PR_TAG}\"]) ) | .name" \
2>/dev/null | head -1 || echo "")
echo "${digest:-}" > digest.txt
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
GH_PACKAGE: ${{ matrix.package }}
PR_NUMBER: ${{ github.event.pull_request.number }}
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: pr-digest-${{ matrix.package }}
path: digest.txt
if-no-files-found: warn
retention-days: 1

delete-images:
name: 🗑️ Delete PR Images
if: always()
needs: collect-pr-digests
runs-on: ubuntu-latest
permissions:
packages: write # is needed by dataaxiom/ghcr-cleanup-action to delete images
Expand All @@ -23,6 +62,47 @@ jobs:
delete-tags: pr-${{ github.event.pull_request.number }}
packages: amp-devcontainer,amp-devcontainer-cpp,amp-devcontainer-rust

delete-attestations:
name: 🔏 Delete PR Attestations (${{ matrix.package }})
needs: [collect-pr-digests, delete-images]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
package: [amp-devcontainer-base, amp-devcontainer-cpp, amp-devcontainer-rust]
permissions:
attestations: write # is needed to delete attestations
steps:
- uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1
with:
disable-sudo-and-containers: true
egress-policy: audit
allowed-endpoints: api.github.com:443
- uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
id: download-digest
continue-on-error: true
with:
name: pr-digest-${{ matrix.package }}
- name: Delete attestations for PR ${{ github.event.pull_request.number }}
if: steps.download-digest.outcome == 'success'
run: |
set -Eeuo pipefail
ORG="${GH_REPO%%/*}"
digest=$(cat digest.txt)
if [[ -z "$digest" ]]; then
echo "No digest found for pr-${PR_NUMBER} in ${GH_PACKAGE}, skipping"
exit 0
fi
echo "Deleting attestations for ${GH_PACKAGE}@${digest}"
encoded_digest="${digest//:/%3A}"
gh api --method DELETE "/orgs/${ORG}/attestations/digest/${encoded_digest}" \
2>/dev/null && echo "Deleted" || echo "No attestations found (already cleaned up)"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
GH_PACKAGE: ${{ matrix.package }}
PR_NUMBER: ${{ github.event.pull_request.number }}

cleanup-cache:
name: 🧹 Cleanup Cache
runs-on: ubuntu-latest
Expand Down
Loading