Skip to content

cleanup-pr-artifacts: 403 on per-package/version lookups still hard-fails the job #153

Closed

Description

@cratis-direct

What's wrong

cleanup-pr-artifacts.yml's InventoryNotAuthorized handling only treats a 401/403
as a soft failure when it happens on the top-level org package listing call:

if (method == "GET" and endpoint.split("?", 1)[0] == "orgs/Cratis/packages"
        and status in (401, 403)):
    raise InventoryNotAuthorized("Package inventory not authorized")

Every other GET in inventory() — fetching a specific package
(orgs/Cratis/packages/{type}/{name}) or its versions
(orgs/Cratis/packages/{type}/{name}/versions?state=active) — falls through to the
generic require(status in allowed, ...) check and raises a hard CleanupError on the
same class of authorization failure, failing the job with exit code 1 and no actionable
message beyond API GET failed (HTTP 403).

Where this was observed

Cratis/cratis.studio's "Cleanup PR Artifacts" workflow (which calls this reusable
workflow with secrets: inherit) has been hard-failing on every PR close since
2026-09-10, consistently with API GET failed (HTTP 403):
https://github.com/Cratis/cratis.studio/actions/runs/36643627101

The top-level orgs/Cratis/packages?package_type=... listing succeeds (it enumerates
packages and finds ones associated with the calling repository), so the failure happens
on one of the narrower per-package/per-version lookups once a candidate package is
found — the same authorization gap the InventoryNotAuthorized fix (5435636, 193b80c,
c64bc9b) was meant to close for the listing call, just one level deeper.

(Note: cratis.studio itself never publishes GitHub Packages — no Dockerfile,
.csproj, or .nuspec — so for that repository the workflow is inert; we removed the
caller workflow there rather than carry a permanently-failing check with nothing to
clean up. This issue is about the reusable workflow itself, since any repository that
does publish packages but hits a 403 on a per-package/version lookup would hit the
exact same unhandled hard failure.)

Suggested fix

Extend the InventoryNotAuthorized check to cover the per-package and per-version
endpoints the same way it covers the top-level listing (e.g. match on
orgs/Cratis/packages/ as a prefix rather than only the exact top-level path), so an
authorization gap discovered partway through inventory degrades to the same warning
and No versions deleted outcome instead of a hard failure.

Status

State: Done — Merged in #210, bootstrap rollout succeeded; post-rollout spot-check watch j510 running
Branch: stage-422-atomic-execution (#209, #210)
Scope: 403 on per-package/version lookups -> logged skip; shipped with #138 in one patch PR
Delivered: Nothing yet.
Remaining: To be confirmed.
Follow-ups: None.

Activity

  1. added theissue type on Oct 9, 2026
  2. cratis-direct commented on Oct 9, 2026

    @cratis-direct
    Author

    Confirming a second affected repository: Cratis/Architecture has been hitting this same hard failure.

    Architecture publishes a real NuGet package (Cratis.Architecture.CodeAnalysis, built from Source/CodeAnalysis/Cratis.Architecture.CodeAnalysis.csproj) with PR-tagged prerelease versions, so its "Cleanup PR Artifacts" caller workflow (secrets: inherit) exercises the per-package/version lookups in inventory(), not just the top-level org listing.

    Its workflow run history shows the same pattern described here: every run from 2026-09-10 onward (right after the fail-closed rewrite in c46f3bc) failed at the "Inventory, approve, delete, and verify PR versions" step within a few seconds, e.g. https://github.com/Cratis/Architecture/actions/runs/36643495642 and https://github.com/Cratis/Architecture/actions/runs/36629207860. I couldn't pull the exact HTTP 403 text for those specific runs — GitHub had already expired/purged the logs (410 Gone) by the time I looked — but the timing, the step name, and the fast (~2-4s) failure duration line up exactly with the per-package/version gap this issue describes, and Architecture is a repository that genuinely has packages to inventory, unlike cratis.studio.

    No code change needed in Architecture's own workflow file — it's a correct, minimal reusable-workflow caller. It'll pick up the fix automatically via @main once this is resolved here.

  3. cratis-direct commented on Oct 9, 2026

    @cratis-direct
    Author

    Confirming this same failure mode on another repository: Cratis/Chronicle.Kotlin's "Cleanup PR Artifacts" workflow (which also calls this reusable workflow with secrets: inherit) hard-failed on PR #119's close with the identical API GET failed (HTTP 403) — https://github.com/Cratis/Chronicle.Kotlin/actions/runs/36843442560.

    Like cratis.studio, Chronicle.Kotlin never publishes GitHub Packages either (it publishes exclusively to Maven Central via com.vanniktech.maven.publish), so a package must have been associated with it from an earlier iteration of its CI for the per-package/version lookup to even be reached. We removed Chronicle.Kotlin's caller workflow for the same reason cratis.studio's was removed — it has nothing to ever clean up, and this issue plus #103 are the tracked path to a real fix upstream.

  4. self-assigned this
    on Oct 24, 2026
  5. woksin commented on Oct 25, 2026

    @woksin
    Contributor

    Delivered in #210: a 403 on one package's version inventory is now a warned skip; manual apply and other errors still fail. Rolled out by Bootstrap Common Workflows run 40145560859.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions