8000 Support for index subject by jonesbusy · Pull Request #220 · oras-project/oras-java · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Support for index subject #220

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

Merged
Merged
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
8000
1 change: 1 addition & 0 deletions src/main/java/land/oras/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ private Config(String mediaType, String digest, long size, @Nullable String data
size,
mediaType,
!annotations.configAnnotations().isEmpty() ? Map.copyOf(annotations.configAnnotations()) : null,
null,
null);
this.data = data;
}
Expand Down
48 changes: 44 additions & 4 deletions src/main/java/land/oras/Descriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import land.oras.utils.Const;
import land.oras.utils.JsonUtils;
import org.jspecify.annotations.Nullable;
Expand All @@ -45,13 +46,32 @@ public sealed class Descriptor permits Config, Manifest, Layer, Index {
protected final @Nullable Long size;
protected final @Nullable String artifactType;

/**
* Original json
*/
protected transient String json;

protected Descriptor(
String digest, Long size, String mediaType, Map<String, String> annotations, String artifactType) {
String digest,
Long size,
String mediaType,
Map<String, String> annotations,
String artifactType,
String json) {
this.digest = digest;
this.size = size;
this.mediaType = mediaType;
this.annotations = annotations;
this.artifactType = artifactType;
this.json = json;
}

/**
* Return the original JSON
* @return The original JSON
*/
public String getJson() {
return json;
}

/**
Expand Down Expand Up @@ -108,6 +128,26 @@ public final String toJson() {
return JsonUtils.toJson(this);
}

/**
* Return same instance but with original JSON
* @param json The original JSON
* @return The index
*/
protected Descriptor withJson(String json) {
this.json = json;
return this;
}

/**
* Return this manifest descriptor as a subject
* @return The subject
*/
public Subject toSubject() {
Objects.requireNonNull(digest);
Objects.requireNonNull(size);
return Subject.of(mediaType, digest, size);
}

/**
* Create a new descriptor
* @param digest The digest
Expand All @@ -119,7 +159,7 @@ public final String toJson() {
*/
public static Descriptor of(
String digest, Long size, String mediaType, Map<String, String> annotations, String artifactType) {
return new Descriptor(digest, size, mediaType, annotations, artifactType);
return new Descriptor(digest, size, mediaType, annotations, artifactType, null);
}

/**
Expand All @@ -130,7 +170,7 @@ public static Descriptor of(
* @return The descriptor
*/
public static Descriptor of(String digest, Long size, String mediaType) {
return new Descriptor(digest, size, mediaType, null, null);
return new Descriptor(digest, size, mediaType, null, null, null);
}

/**
Expand All @@ -140,6 +180,6 @@ public static Descriptor of(String digest, Long size, String mediaType) {
* @return The descriptor
*/
public static Descriptor of(String digest, Long size) {
return new Descriptor(digest, size, Const.DEFAULT_DESCRIPTOR_MEDIA_TYPE, null, null);
return new Descriptor(digest, size, Const.DEFAULT_DESCRIPTOR_MEDIA_TYPE, null, null, null);
}
}
36 changes: 21 additions & 15 deletions src/main/java/land/oras/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ public final class Index extends Descriptor {

private final int schemaVersion;
private final List<ManifestDescriptor> manifests;

/**
* Original json
*/
private transient String json;
private final Subject subject;

8000 /**
* The manifest descriptor
Expand All @@ -53,13 +49,14 @@ private Index(
String artifactType,
List<ManifestDescriptor> manifests,
Map<String, String> annotations,
Subject subject,
ManifestDescriptor descriptor,
String json) {
super(null, null, mediaType, annotations, artifactType);
super(null, null, mediaType, annotations, artifactType, json);
this.schemaVersion = schemaVersion;
this.descriptor = descriptor;
this.subject = subject;
this.manifests = manifests;
this.json = json;
}

/**
Expand Down Expand Up @@ -113,7 +110,7 @@ public Index withNewManifests(ManifestDescriptor manifest) {
newManifests.add(ManifestDescriptor.fromJson(descriptor.toJson()));
}
newManifests.add(manifest);
return new Index(schemaVersion, mediaType, artifactType, newManifests, annotations, descriptor, json);
return new Index(schemaVersion, mediaType, artifactType, newManifests, annotations, subject, descriptor, json);
}

/**
Expand Down Expand Up @@ -142,25 +139,34 @@ public ManifestDescriptor getDescriptor() {
* @return The manifest
*/
public Index withDescriptor(ManifestDescriptor descriptor) {
return new Index(schemaVersion, mediaType, artifactType, manifests, annotations, descriptor, json);
return new Index(schemaVersion, mediaType, artifactType, manifests, annotations, subject, descriptor, json);
}

/**
* Return same instance but with original JSON
* @param json The original JSON
* @return The index
*/
private Index withJson(String json) {
protected Index withJson(String json) {
this.json = json;
return this;
}

/**
* Return the original JSON
* @return The original JSON
* Get the subject
* @return The subject
*/
public Subject getSubject() {
return subject;
}

/**
* Return a new index with the given subject
* @param subject The subject
* @return The index
*/
public String getJson() {
return json;
public Index withSubject(Subject subject) {
return new Index(schemaVersion, mediaType, artifactType, manifests, annotations, subject, descriptor, json);
}

/**
Expand All @@ -187,6 +193,6 @@ public static Index fromPath(Path path) {
* @return The index
*/
public static Index fromManifests(List<ManifestDescriptor> descriptors) {
return new Index(2, Const.DEFAULT_INDEX_MEDIA_TYPE, null, descriptors, null, null, null);
return new Index(2, Const.DEFAULT_INDEX_MEDIA_TYPE, null, descriptors, null, null, null, null);
}
}
4 changes: 2 additions & 2 deletions src/main/java/land/oras/Layer.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private Layer(
long size,
@Nullable String data,
@Nullable Map<String, String> annotations) {
super(digest, size, mediaType, annotations, null);
super(digest, size, mediaType, annotations, null, null);
this.data = data;
this.blobPath = null;
}
Expand All @@ -74,7 +74,7 @@ private Layer(
* @param blobPath The path to the blob
*/
private Layer(String mediaType, String digest, long size, Path blobPath, Map<String, String> annotations) {
super(digest, size, mediaType, annotations, null);
super(digest, size, mediaType, annotations, null, null);
this.data = null;
this.blobPath = blobPath;
}
Expand Down
19 changes: 3 additions & 16 deletions src/main/java/land/oras/Manifest.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,6 @@ public final class Manifest extends Descriptor {
*/
private final transient ManifestDescriptor descriptor;

/**
* Original json
*/
private transient String json;

private Manifest(
int schemaVersion,
String mediaType,
Expand All @@ -66,13 +61,13 @@ private Manifest(
null,
mediaType,
Map.copyOf(annotations.manifestAnnotations()),
artifactType != null ? artifactType.getMediaType() : null);
artifactType != null ? artifactType.getMediaType() : null,
json);
this.schemaVersion = schemaVersion;
this.descriptor = descriptor;
this.config = config;
this.subject = subject;
this.layers = layers;
this.json = json;
}

/**
Expand Down Expand Up @@ -240,7 +235,7 @@ public Manifest withDescriptor(ManifestDescriptor descriptor) {
* @param json The original JSON
* @return The index
*/
private Manifest withJson(String json) {
protected Manifest withJson(String json) {
this.json = json;
return this;
}
Expand All @@ -263,14 +258,6 @@ public static Manifest fromPath(Path path) {
return fromJson(JsonUtils.readFile(path));
}

/**
* Return the original JSON
* @return The original JSON
*/
public String getJson() {
return json;
}

private @Nullable ArtifactType getTopLevelArtifactType() {
if (artifactType != null) {
return ArtifactType.from(artifactType);
Expand Down
20 changes: 20 additions & 0 deletions src/main/java/land/oras/ManifestDescriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package land.oras;

import java.util.Map;
import java.util.Objects;
import land.oras.utils.JsonUtils;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
Expand Down Expand Up @@ -173,4 +174,23 @@
public static ManifestDescriptor of(String mediaType, String digest, long size) {
return new ManifestDescriptor(null, mediaType, digest, size, null, null);
}

/**
* Create a manifest descriptor
* @param descriptor The descriptor
* @return The subject
*/
public static ManifestDescriptor of(Descriptor descriptor) {
Objects.requireNonNull(descriptor.getDigest());
Objects.requireNonNull(descriptor.getSize());
return new ManifestDescriptor(
descriptor.getArtifactType() != null
? descriptor.getArtifactType().getMediaType()

Check warning on line 188 in src/main/java/land/oras/ManifestDescriptor.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/land/oras/ManifestDescriptor.java#L188

Added line #L188 was not covered by tests
: null,
descriptor.getMediaType(),
descriptor.getDigest(),
descriptor.getSize(),
null,
descriptor.getAnnotations());
}
}
39 changes: 20 additions & 19 deletions src/main/java/land/oras/Registry.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ public Manifest pushManifest(ContainerRef containerRef, Manifest manifest) {
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#pushing-manifests-with-subject
if (!response.headers().containsKey(Const.OCI_SUBJECT_HEADER.toLowerCase())) {
throw new OrasException(
"Subject was set on manifest but not OCI subject header was returned. Legecy flow not implemented");
"Subject was set on manifest but not OCI subject header was returned. Legacy flow not implemented");
}
}
return getManifest(containerRef);
Expand Down Expand Up @@ -362,8 +362,9 @@ public Manifest attachArtifact(
// Push layers
List<Layer> layers = pushLayers(containerRef, false, paths);

// Get the subject from the manifest
Subject subject = getManifest(containerRef).getDescriptor().toSubject();
// Get the subject from the descriptor
Descriptor descriptor = getDescriptor(containerRef);
Subject subject = descriptor.toSubject();

// Add created annotation if not present since we push with digest
Map<String, String> manifestAnnotations = annotations.manifestAnnotations();
Expand Down Expand Up @@ -559,36 +560,36 @@ public Descriptor fetchBlobDescriptor(ContainerRef containerRef) {
return Descriptor.of(digest, Long.parseLong(size), Const.DEFAULT_DESCRIPTOR_MEDIA_TYPE);
}

@Override
public Manifest getManifest(ContainerRef containerRef) {
OrasHttpClient.ResponseWrapper<String> response = getManifestResponse(containerRef);
logResponse(response);
handleError(response);
String contentType = response.headers().get(Const.CONTENT_TYPE_HEADER.toLowerCase());
Descriptor descriptor = getDescriptor(containerRef);
String contentType = descriptor.getMediaType();
if (!isManifestMediaType(contentType)) {
throw new OrasException(
"Expected manifest but got index. Probably a multi-platform image instead of artifact");
}
String size = response.headers().get(Const.CONTENT_LENGTH_HEADER.toLowerCase());
String digest = response.headers().get(Const.DOCKER_CONTENT_DIGEST_HEADER.toLowerCase());
ManifestDescriptor descriptor =
ManifestDescriptor.of(contentType, digest, size == null ? 0 : Long.parseLong(size));
return Manifest.fromJson(response.response()).withDescriptor(descriptor);
ManifestDescriptor manifestDescriptor = ManifestDescriptor.of(descriptor);
return Manifest.fromJson(descriptor.getJson()).withDescriptor(manifestDescriptor);
}

@Override
public Index getIndex(ContainerRef containerRef) {
OrasHttpClient.ResponseWrapper<String> response = getManifestResponse(containerRef);
logResponse(response);
handleError(response);
String contentType = response.headers().get(Const.CONTENT_TYPE_HEADER.toLowerCase());
Descriptor descriptor = getDescriptor(containerRef);
String contentType = descriptor.getMediaType();
if (!isIndexMediaType(contentType)) {
throw new OrasException("Expected index but got %s".formatted(contentType));
}
ManifestDescriptor manifestDescriptor = ManifestDescriptor.of(descriptor);
return Index.fromJson(descriptor.getJson()).withDescriptor(manifestDescriptor);
}

private Descriptor getDescriptor(ContainerRef containerRef) {
OrasHttpClient.ResponseWrapper<String> response = getManifestResponse(containerRef);
handleError(response);
String size = response.headers().get(Const.CONTENT_LENGTH_HEADER.toLowerCase());
String digest = response.headers().get(Const.DOCKER_CONTENT_DIGEST_HEADER.toLowerCase());
ManifestDescriptor descriptor =
ManifestDescriptor.of(contentType, digest, size == null ? 0 : Long.parseLong(size));
return Index.fromJson(response.response()).withDescriptor(descriptor);
String contentType = response.headers().get(Const.CONTENT_TYPE_HEADER.toLowerCase());
return Descriptor.of(digest, Long.parseLong(size), contentType).withJson(response.response());
}

/**
Expand Down
14 changes: 14 additions & 0 deletions src/test/java/land/oras/IndexTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ void shouldAddManifest() {
assertEquals(1, index.getManifests().get(1).getAnnotations().size());
}

@Test
void shouldAddSubject() {
Index index = Index.fromManifests(List.of());
index = index.withSubject(Subject.of(Const.DEFAULT_MANIFEST_MEDIA_TYPE, "sha256:123", 123));
Subject subject = index.getSubject();
assertNotNull(subject);
assertEquals(Const.DEFAULT_MANIFEST_MEDIA_TYPE, subject.getMediaType());
assertEquals("sha256:123", subject.getDigest());
assertEquals(123, subject.getSize());
assertEquals(
"{\"schemaVersion\":2,\"manifests\":[],\"subject\":{\"mediaType\":\"application/vnd.oci.image.manifest.v1+json\",\"digest\":\"sha256:123\",\"size\":123},\"mediaType\":\"application/vnd.oci.image.index.v1+json\"}",
index.toJson());
}

@Test
void shouldNotAddIfSameDigest() {
Index index = Index.fromManifests(List.of());
Expand Down
Loading
0