dataaxiom / ghcr-cleanup-action

GitHub Container Registry Cleanup Action
BSD 3-Clause "New" or "Revised" License
22 stars 5 forks source link

operating on attestation bundles not supported #13

Closed fmoessbauer closed 5 months ago

fmoessbauer commented 5 months ago

The github provenance attestations (e.g. from the attest-build-provenance action) are uploaded to the container registry as well (following the Cosign bundle specification). The attestation manifests are tagged as sha256-<digest>, whereby the digest refers to the container the attestation belongs to.

These attestation manifests have no platform set, which makes the cleanup action fail.

 in dry run mode - no packages will be deleted
deleting images by tags sha256-*
 deleting package id: 220688938 digest:sha256:060981ae539b31b773484a3b4030c9805b2d82899a5395517d884475372727ca tag:sha256-84d0ca4f9a5975c7fe229bb08c2340be1a4f8a1b7fcd65b0a43f3ea93589942f
Error: Cannot read properties of undefined (reading 'architecture')

Inspect this tag:

regctl manifest get --format raw-body ghcr.io/siemens/kas/kas:sha256-84d0ca4f9a5975c7fe229bb08c2340be1a4f8a1b7fcd65b0a43f3ea93589942f | jq
{
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "schemaVersion": 2,
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:7520ac63a6f1545cddcf33bb243980e15cc1e0ec3a6ff935f99f0aac90cda3e9",
      "size": 812,
      "artifactType": "application/vnd.dev.sigstore.bundle.v0.3+json",
      "annotations": {
        "org.opencontainers.image.created": "2024-05-24T14:58:36.963Z",
        "dev.sigstore.bundle.content": "dsse-envelope",
        "dev.sigstore.bundle.predicateType": "https://slsa.dev/provenance/v1"
      }
    }
  ]
}
rohanmars commented 5 months ago

Let me make a fix for that. Attestation support is needed.

rohanmars commented 5 months ago

Are you trying to delete the image by "tag" and then the associated attestation? I think the action should check for attestation tags and delete these as if they are part of image being deleted if they are present.

Your sample shows deleting the attestation directly by tag. Was that just a test? Or are you wanting to cleanup the full image with the attestation also?

fmoessbauer commented 5 months ago

Are you trying to delete the image by "tag" and then the associated attestation? I think the action should check for attestation tags and delete these as if they are part of image being deleted if they are present.

Well... ideally the action does not even care about the type of artifact it is operating on. The attestations are somehow special, as there are two "options" regarding how they are made discoverable in the OCI registry(legacy, OCI v2). At least for the OCI v2 version, no special handling should be required.

OCI registry v2 For registries supporting the OCI registry v2 spec, the attestations are uploaded as blobs. Then, a manifest is created that associates the bundle blob with the image it describes. This manifest contains the "subject" node, which points to the digest the manifest belongs to (the container that is attested). For v2 registries, the registry provides the referrers API, which makes the attestation discoverable when listing the container artifact. Example:

$ regctl artifact tree ghcr.io/siemens/kas/kas:next
Ref: ghcr.io/siemens/kas/kas:next
Digest: sha256:84d0ca4f9a5975c7fe229bb08c2340be1a4f8a1b7fcd65b0a43f3ea93589942f
Children:
  - sha256:01e1575a2f400f95be4049f5ab877336a4849fcf13e09be79304a1575ed543f3 [linux/amd64]
  - sha256:3992633a8839abb0444968441f01d0cb8f4248e3debed1173edbfb276af049eb [linux/arm64]
Referrers:
  - sha256:7520ac63a6f1545cddcf33bb243980e15cc1e0ec3a6ff935f99f0aac90cda3e9: application/vnd.dev.sigstore.bundle.v0.3+json

OCI registry v1 This registry does not support the referrers API, hence the association needs to be implemented using tags. In this case, the cosign bundle spec specifies well-known tag names (as stated above). These are named sha256-<digest>, whereby the digest is the digest of the container the attestation is for.

Unfortunately, the github attest-build-provenance action also creates the v1 tags, even if the registry supports the referrers API. This is problematic, as the cleanup action then needs to have explicit support for the cosign bundles. Otherwise, for each untagged image, the action could check if it refers to anything and if that artifact still exists. If not, the the artifact can be deleted.

Your sample shows deleting the attestation directly by tag. Was that just a test? Or are you wanting to cleanup the full image with the attestation also?

This was just a test to see if the action can operate on non-container artifacts.

rohanmars commented 5 months ago

I've added initial support for referrers/attestation 4cc714f on main.

I've added two attestation tests, it likely needs a few more. Additionally, in the validate mode, i search for orphaned referrer tags. The cleanup action should probably treat them as "untagged" and delete them in the "untagged" cleanup modes.

Strangely, ghcr.io returned a 404 for the referrers API for the digest, so I'm not sure it's implementing that api yet, I couldn't find any docs. So currently it looks for a v1 tag approach. Not sure if it makes sense to call the api for a 404 and then fall back to the tag approach (which the spec defines).

fmoessbauer commented 5 months ago

I've added initial support for referrers/attestation https://github.com/dataaxiom/ghcr-cleanup-action/commit/4cc714f4c8d594e6eaa93ce37d94e7b1963dd5aa on main.

Many thanks. I re-tested it here and it works like charms.

Strangely, ghcr.io returned a 404 for the referrers API for the digest,

That's indeed strange, as the regctl tool can definitely find the referrers (see above). When running the tool in debug mode, you can also see the exact http requests.

rohanmars commented 5 months ago

That's great news. Let me review the regctl debug output, it would be much better to work of the referrers API. I think the tag would then automatically get cleanup up via the way the GitHub packages api works.

rohanmars commented 5 months ago

The output of your jobs also appears it treated some of the referrer tags as "untagged". Im not sure that is correct.

rohanmars commented 5 months ago

Actually I think the code is finding orphaned referrer tags automatically!!!! Treating them as untagged as they aren't "in use". I should probably print out info message also in that case.

rohanmars commented 5 months ago

I verified the regctl also get's 404 on the referrers api, it's using the tag approach to find the referrers manifest on ghcr.io

fmoessbauer commented 5 months ago

I verified the regctl also get's 404 on the referrers api, it's using the tag approach to find the referrers manifest on ghcr.io

You're right. The same was just confirmed on https://github.com/actions/attest-build-provenance/issues/91 as well:

Unfortunately, GHCR does NOT yet support the referrers API (and doesn't set the OCI-Subject header) so that's why you're seeing the sha256-digest tag in that registry.

Anyways, many thanks for the investigation and this action in general!

rohanmars commented 5 months ago

thanks for your feature request and testing! released/fixed in v1.0.4 d0d9b2d