diff --git a/__tests__/ghcr-client.test.ts b/__tests__/ghcr-client.test.ts
index 2ae5adb..01fb2ee 100644
--- a/__tests__/ghcr-client.test.ts
+++ b/__tests__/ghcr-client.test.ts
@@ -1,5 +1,6 @@
import {
- uploadOCIImageManifest
+ uploadOCIImageManifest,
+ uploadOCIIndexManifest
// uploadOCIIndexManifest
} from '../src/ghcr-client'
import * as ociContainer from '../src/oci-container'
@@ -178,6 +179,63 @@ function configureFetchMock(
)
}
+describe('uploadOCIIndexManifest', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ fetchMock = jest.spyOn(global, 'fetch').mockImplementation()
+ })
+
+ it('uploads the tagged manifest with the appropriate tag', async () => {
+ const { manifest, sha } = testIndexManifest()
+ const tag = 'sha-1234'
+
+ configureFetchMock(fetchMock, {
+ putManifestMock: putManifestSuccessful(sha, tag)
+ })
+
+ await uploadOCIIndexManifest(token, registry, repository, manifest, tag)
+
+ expect(fetchMock).toHaveBeenCalledTimes(1)
+ expect(
+ fetchMock.mock.calls.filter(call => call[1].method === 'PUT')
+ ).toHaveLength(1)
+ })
+
+ it('throws an error if a manifest upload fails', async () => {
+ const { manifest, blobs } = testImageManifest()
+
+ configureFetchMock(fetchMock, {
+ checkBlobMock: checkBlobAllExistingBlobs,
+ initiateBlobUploadMock: initiateBlobUploadSuccessForAllBlobs,
+ putBlobMock: putBlobSuccess,
+ putManifestMock: putManifestFailure
+ })
+
+ await expect(
+ uploadOCIImageManifest(token, registry, repository, manifest, blobs)
+ ).rejects.toThrow(
+ 'Unexpected 400 Bad Request response from manifest upload. Errors: BAD_REQUEST - tag already exists.'
+ )
+ })
+
+ it('throws an error if the returned digest does not match the precalculated one', async () => {
+ const { manifest, sha, blobs } = testImageManifest()
+
+ configureFetchMock(fetchMock, {
+ checkBlobMock: checkBlobAllExistingBlobs,
+ initiateBlobUploadMock: initiateBlobUploadSuccessForAllBlobs,
+ putBlobMock: putBlobSuccess,
+ putManifestMock: putManifestSuccessful('some-garbage-digest', sha)
+ })
+
+ await expect(
+ uploadOCIImageManifest(token, registry, repository, manifest, blobs)
+ ).rejects.toThrow(
+ `Digest mismatch. Expected ${sha}, got some-garbage-digest.`
+ )
+ })
+})
+
describe('uploadOCIImageManifest', () => {
beforeEach(() => {
jest.clearAllMocks()
@@ -196,7 +254,6 @@ describe('uploadOCIImageManifest', () => {
await uploadOCIImageManifest(token, registry, repository, manifest, blobs)
- // TODO: See what calls there are
expect(fetchMock).toHaveBeenCalledTimes(10)
expect(
fetchMock.mock.calls.filter(call => call[1].method === 'HEAD')
@@ -228,7 +285,6 @@ describe('uploadOCIImageManifest', () => {
semver
)
- // TODO: See what calls there are
expect(fetchMock).toHaveBeenCalledTimes(10)
expect(
fetchMock.mock.calls.filter(call => call[1].method === 'HEAD')
@@ -388,19 +444,6 @@ describe('uploadOCIImageManifest', () => {
})
})
-describe('uploadOCIIndexManifest', () => {
- beforeEach(() => {
- jest.clearAllMocks()
- fetchMock = jest.spyOn(global, 'fetch').mockImplementation()
- })
-
- it('uploads the tagged manifest with the appropriate tag', async () => {})
-
- it('throws an error if a manifest upload fails', async () => {})
-
- it('throws an error if the returned digest does not match the precalculated one', async () => {})
-})
-
function testImageManifest(): {
manifest: ociContainer.OCIImageManifest
sha: string
@@ -452,6 +495,20 @@ function testImageManifest(): {
return { manifest, sha, blobs }
}
+function testIndexManifest(): {
+ manifest: ociContainer.OCIIndexManifest
+ sha: string
+} {
+ const manifest = ociContainer.createReferrerTagManifest(
+ 'attestation-digest',
+ 1234,
+ new Date(),
+ new Date()
+ )
+ const sha = ociContainer.sha256Digest(manifest)
+ return { manifest, sha }
+}
+
// We expect all fetch calls to have auth headers set
// This function verifies that given an request config.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
diff --git a/badges/coverage.svg b/badges/coverage.svg
index 6b04204..a4f5396 100644
--- a/badges/coverage.svg
+++ b/badges/coverage.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file