diff --git a/src/main/java/land/oras/OCILayout.java b/src/main/java/land/oras/OCILayout.java index 51c8ee28..664f63a4 100644 --- a/src/main/java/land/oras/OCILayout.java +++ b/src/main/java/land/oras/OCILayout.java @@ -342,16 +342,22 @@ public Descriptor fetchBlobDescriptor(LayoutRef ref) { @Override public Layer pushBlob(LayoutRef ref, Path blob, Map annotations) { - ensureDigest(ref, blob); - Path blobPath = getBlobPath(ref); - String digest = ref.getAlgorithm().digest(blob); + if (ref.getTag() == null) { + throw new OrasException("Missing ref"); + } + if (!SupportedAlgorithm.isSupported(ref.getTag())) { + throw new OrasException("Unsupported digest: %s".formatted(ref.getTag())); + } + String digest = ref.getTag(); ensureAlgorithmPath(digest); + Path blobPath = getBlobPath(ref); LOG.trace("Digest: {}", digest); try { if (Files.exists(blobPath)) { LOG.info("Blob already exists: {}", digest); return Layer.fromFile(blobPath, ref.getAlgorithm()).withAnnotations(annotations); } + ensureDigest(ref, blob); Files.copy(blob, blobPath); Layer layer = Layer.fromFile(blobPath, ref.getAlgorithm()).withAnnotations(annotations); packToTar(); @@ -394,12 +400,26 @@ public Layer pushBlob(LayoutRef ref, long size, Supplier stream, Ma @Override public Layer pushBlob(LayoutRef ref, byte[] data) { try { - Path path = Files.createTempFile("oras", "blob"); - Files.write(path, data); - ensureDigest(ref, path); + if (ref.getTag() == null) { + throw new OrasException("Missing ref"); + } + if (!SupportedAlgorithm.isSupported(ref.getTag())) { + throw new OrasException("Unsupported digest: %s".formatted(ref.getTag())); + } String digest = ref.getAlgorithm().digest(data); + if (!ref.getTag().equals(digest)) { + throw new OrasException("Digest mismatch: %s != %s".formatted(ref.getTag(), digest)); + } ensureAlgorithmPath(digest); - return pushBlob(ref, path, Map.of()); + Path blobPath = getBlobAlgorithmPath(digest).resolve(SupportedAlgorithm.getDigest(digest)); + if (Files.exists(blobPath)) { + LOG.info("Blob already exists: {}", digest); + return Layer.fromFile(blobPath, ref.getAlgorithm()).withAnnotations(Map.of()); + } + Files.write(blobPath, data); + packToTar(); + LOG.debug("Blob pushed to OCI layout: {}", digest); + return Layer.fromFile(blobPath, ref.getAlgorithm()).withAnnotations(Map.of()); } catch (IOException e) { throw new OrasException("Failed to push blob to OCI layout", e); } diff --git a/src/test/java/land/oras/OCILayoutTest.java b/src/test/java/land/oras/OCILayoutTest.java index 8c67ac4a..a4106e4e 100644 --- a/src/test/java/land/oras/OCILayoutTest.java +++ b/src/test/java/land/oras/OCILayoutTest.java @@ -719,6 +719,24 @@ void cannotPushBlobWithoutTagOrDigest() throws IOException { }); } + @Test + void cannotPushBlobFromPathWithoutTagOrDigest() throws IOException { + Path invalidBlobPushDir = layoutPath.resolve("cannotPushBlobFromPathWithoutTagOrDigest"); + OCILayout ociLayout = + OCILayout.Builder.builder().defaults(invalidBlobPushDir).build(); + Path blobFile = blobDir.resolve("cannotPushBlobFromPathWithoutTagOrDigest.txt"); + Files.writeString(blobFile, "hello"); + + LayoutRef noTagLayout = LayoutRef.of(ociLayout); + OrasException e1 = assertThrows(OrasException.class, () -> ociLayout.pushBlob(noTagLayout, blobFile, Map.of())); + assertEquals("Missing ref", e1.getMessage()); + + LayoutRef noDigestLayout = LayoutRef.of(ociLayout, "latest"); + OrasException e2 = + assertThrows(OrasException.class, () -> ociLayout.pushBlob(noDigestLayout, blobFile, Map.of())); + assertEquals("Unsupported digest: latest", e2.getMessage()); + } + @Test void cannotPushWithInvalidDigest() { Path invalidBlobPushDir = layoutPath.resolve("cannotPushWithInvalidDigest"); diff --git a/src/test/resources/oci/artifact.tar b/src/test/resources/oci/artifact.tar index 230c5ec7..dff3d448 100644 Binary files a/src/test/resources/oci/artifact.tar and b/src/test/resources/oci/artifact.tar differ diff --git a/src/test/resources/oci/subject.tar b/src/test/resources/oci/subject.tar index 9aefb813..271e24e1 100644 Binary files a/src/test/resources/oci/subject.tar and b/src/test/resources/oci/subject.tar differ