Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support sigstore attachments for v2s2 #2734

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

alex-berger
Copy link

Currently we support sigstore attachments for OCI. This PR adds support for sigstore attachments for v2s2 (Docker Registry HTTP API V2 Schema 2 Manifest).

fixes #2058

Copy link
Collaborator

@mtrmac mtrmac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

How did you test this? AFAICS this simply cannot work, when the schema2 definitions (as they exist in c/image) simply don’t have the “annotations” field which actually stores the signature.

Also, I think we’d need to build some amount of transport-agnostic manifest/image infrastructure to support this.

logrus.Debugf("Found a sigstore attachment manifest with %d layers", len(ociManifest.Layers))
for layerIndex, layer := range ociManifest.Layers {
layers := genManifest.LayerInfos()
numLayers := len(layers)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you look at the compiler outputs, adding a variable to avoid a len() does not speed things up — the slice itself is a local variable and this is a direct member access, quite likely to a value already in a register.

// We don’t benefit from a real BlobInfoCache here because we never try to reuse/mount attachment payloads.
// That might eventually need to change if payloads grow to be not just signatures, but something
// significantly large.
payload, err := s.c.getOCIDescriptorContents(ctx, s.physicalRef, layer, iolimits.MaxSignatureBodySize,
descriptor := imgspecv1.Descriptor{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a generic types.BlobInfo; getOCIDescriptorContents used a raw OCI type just because that was convenient for this caller, but now that we need to make things generic, turning getOCIDescriptorContents into something generic would be simpler.

// We don’t benefit from a real BlobInfoCache here because we never try to reuse/mount configs.
configBlob, err := d.c.getOCIDescriptorContents(ctx, d.ref, ociManifest.Config, iolimits.MaxConfigBodySize,
configBlob, err := d.c.getOCIDescriptorContents(ctx, d.ref, descriptor, iolimits.MaxConfigBodySize,
none.NoCache)
if err != nil {
return err
}
if err := json.Unmarshal(configBlob, &ociConfig); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unmarshaling v2s2 into OCI is not semantically correct (loses data).

// To make sure we can safely append to the slices of ociManifest, without adding a remote dependency on the code that creates it.
ociManifest.Layers = slices.Clone(ociManifest.Layers)
// To make sure we can safely append to the slices of Manifest, without adding a remote dependency on the code that creates it.
switch v := genManifest.(type) {
Copy link
Collaborator

@mtrmac mtrmac Feb 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No; hard-coding implementation types is an invisible dependency, and a trap for long-term maintenance.

At the very least, this package can build a private interface. More likely, we would need an (internal-only, because we can’t add methods to a public interface without breaking API) extension of the manifest.Manifest interface which adds an “add a layer” operation. (Compare internal/manifest.List{,Public}).

Size: layer.Size,
Annotations: layer.Annotations,
}
if layerMatchesSigstoreSignature(descriptor, mimeType, payloadBlob, annotations) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn’t work because schema2 manifests don’t have annotations at all.

case *manifest.OCI1:
v.Layers = append(v.Layers, sigDesc)
case *manifest.Schema2:
v.LayersDescriptors = append(v.LayersDescriptors, manifest.Schema2Descriptor{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This discards annotations (schema2 manifests don’t have annotations at all), and as a result, the signature is unusable.

case *manifest.OCI1:
v.Config = configDesc
case *manifest.Schema2:
v.ConfigDescriptor = manifest.Schema2Descriptor{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The config was uploaded above with a hard-coded MIME type
  • Structurally, assuming that OCI and schema2 configs are completely substitutable is not something the transport should assume; such a no-op conversion belongs into the image/ conversion code.

@alex-berger alex-berger marked this pull request as draft February 25, 2025 17:53
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.

Support v2s2 manifests in sigstore attachments (for cosign compatibility)
2 participants