diff --git a/sdk/containerregistry/container-registry/review/container-registry.api.md b/sdk/containerregistry/container-registry/review/container-registry.api.md index 790ab7f1828a..4207713ea062 100644 --- a/sdk/containerregistry/container-registry/review/container-registry.api.md +++ b/sdk/containerregistry/container-registry/review/container-registry.api.md @@ -160,7 +160,7 @@ export interface DownloadManifestOptions extends OperationOptions { // @public export interface DownloadManifestResult { - content: NodeJS.ReadableStream; + content: Buffer; digest: string; mediaType: string; } diff --git a/sdk/containerregistry/container-registry/samples-dev/downloadImage.ts b/sdk/containerregistry/container-registry/samples-dev/downloadImage.ts index cda7b284d0f0..a80c6a731aa3 100644 --- a/sdk/containerregistry/container-registry/samples-dev/downloadImage.ts +++ b/sdk/containerregistry/container-registry/samples-dev/downloadImage.ts @@ -40,9 +40,8 @@ async function main() { } const manifest = result.manifest; - // Manifests of all media types can be written to a file using the `content` stream. - const manifestFile = fs.createWriteStream("manifest.json"); - result.content.pipe(manifestFile); + // Manifests of all media types have a buffer containing their content; this can be written to a file. + fs.writeFileSync("manifest.json", result.content); const configResult = await client.downloadBlob(manifest.config.digest); const configFile = fs.createWriteStream("config.json"); diff --git a/sdk/containerregistry/container-registry/samples/v1-beta/javascript/downloadImage.js b/sdk/containerregistry/container-registry/samples/v1-beta/javascript/downloadImage.js index 63ee6a4cca3b..87bfcd97cc21 100644 --- a/sdk/containerregistry/container-registry/samples/v1-beta/javascript/downloadImage.js +++ b/sdk/containerregistry/container-registry/samples/v1-beta/javascript/downloadImage.js @@ -39,9 +39,8 @@ async function main() { } const manifest = result.manifest; - // Manifests of all media types can be written to a file using the `content` stream. - const manifestFile = fs.createWriteStream("manifest.json"); - result.content.pipe(manifestFile); + // Manifests of all media types have a buffer containing their content; this can be written to a file. + fs.writeFileSync("manifest.json", result.content); const configResult = await client.downloadBlob(manifest.config.digest); const configFile = fs.createWriteStream("config.json"); diff --git a/sdk/containerregistry/container-registry/samples/v1-beta/typescript/src/downloadImage.ts b/sdk/containerregistry/container-registry/samples/v1-beta/typescript/src/downloadImage.ts index 3c9ac24df834..4c75fe3e6a44 100644 --- a/sdk/containerregistry/container-registry/samples/v1-beta/typescript/src/downloadImage.ts +++ b/sdk/containerregistry/container-registry/samples/v1-beta/typescript/src/downloadImage.ts @@ -39,9 +39,8 @@ async function main() { } const manifest = result.manifest; - // Manifests of all media types can be written to a file using the `content` stream. - const manifestFile = fs.createWriteStream("manifest.json"); - result.content.pipe(manifestFile); + // Manifests of all media types have a buffer containing their content; this can be written to a file. + fs.writeFileSync("manifest.json", result.content); const configResult = await client.downloadBlob(manifest.config.digest); const configFile = fs.createWriteStream("config.json"); diff --git a/sdk/containerregistry/container-registry/src/blob/containerRegistryBlobClient.ts b/sdk/containerregistry/container-registry/src/blob/containerRegistryBlobClient.ts index 8f39392aeb73..d4959d144c48 100644 --- a/sdk/containerregistry/container-registry/src/blob/containerRegistryBlobClient.ts +++ b/sdk/containerregistry/container-registry/src/blob/containerRegistryBlobClient.ts @@ -29,7 +29,7 @@ import { } from "./models"; import * as Mappers from "../generated/models/mappers"; import { CommonClientOptions, createSerializer } from "@azure/core-client"; -import { readChunksFromStream, readStreamToEnd } from "../utils/helpers"; +import { isDigest, readChunksFromStream, readStreamToEnd } from "../utils/helpers"; import { Readable } from "stream"; import { tracingClient } from "../tracing"; import crypto from "crypto"; @@ -205,7 +205,7 @@ export class ContainerRegistryBlobClient { /** * Upload a manifest for an OCI artifact. * - * @param manifest - the manifest to upload. If a resettable stream (a factory function that returns a stream) is provided, it may be called multiple times. Each time the function is called, a fresh stream should be returned. + * @param manifest - the manifest to upload. */ public async uploadManifest( manifest: Buffer | NodeJS.ReadableStream | OciImageManifest, @@ -277,22 +277,28 @@ export class ContainerRegistryBlobClient { assertHasProperty(response, "mediaType"); - const bodyData = response.readableStreamBody + const content = response.readableStreamBody ? await readStreamToEnd(response.readableStreamBody) : Buffer.alloc(0); - const expectedDigest = await calculateDigest(bodyData); + const expectedDigest = await calculateDigest(content); + + if (isDigest(tagOrDigest) && expectedDigest !== tagOrDigest) { + throw new DigestMismatchError( + "Digest of downloaded manifest does not match the input digest" + ); + } if (response.dockerContentDigest !== expectedDigest) { throw new DigestMismatchError( - "Digest of blob to upload does not match the digest from the server." + "Computed digest of downloaded manifest does not match the value of the Docker-Content-Digest header" ); } if (response.mediaType === KnownManifestMediaType.OciManifest) { const manifest = serializer.deserialize( Mappers.OCIManifest, - JSON.parse(bodyData.toString()), + JSON.parse(content.toString()), "OCIManifest" ); @@ -300,14 +306,14 @@ export class ContainerRegistryBlobClient { digest: response.dockerContentDigest, mediaType: response.mediaType, manifest, - content: Readable.from(bodyData), + content, }; } return { digest: response.dockerContentDigest, mediaType: response.mediaType, - content: Readable.from(bodyData), + content, }; } ); diff --git a/sdk/containerregistry/container-registry/src/blob/models.ts b/sdk/containerregistry/container-registry/src/blob/models.ts index d97a042c7f67..3148c4896558 100644 --- a/sdk/containerregistry/container-registry/src/blob/models.ts +++ b/sdk/containerregistry/container-registry/src/blob/models.ts @@ -48,9 +48,9 @@ export interface DownloadManifestResult { mediaType: string; /** - * The manifest stream that was downloaded. + * The raw content of the manifest that was downloaded. */ - content: NodeJS.ReadableStream; + content: Buffer; } /**