diff --git a/changelog.md b/changelog.md index 2a5db55..b65db92 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2025-11-25 - 2.1.1 - fix(oci) +Preserve raw manifest bytes for digest calculation and handle string/JSON manifest bodies in OCI registry + +- Preserve the exact bytes of the manifest payload when computing the sha256 digest to comply with the OCI spec and avoid mismatches caused by re-serialization. +- Accept string request bodies (converted using UTF-8) and treat already-parsed JSON objects by re-serializing as a fallback. +- Keep existing content-type fallback logic while ensuring accurate digest calculation prior to storing manifests. + ## 2025-11-25 - 2.1.0 - feat(oci) Support configurable OCI token realm/service and centralize unauthorized responses diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 1095f69..8eaeef5 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smartregistry', - version: '2.1.0', + version: '2.1.1', description: 'A composable TypeScript library implementing OCI, NPM, Maven, Cargo, Composer, PyPI, and RubyGems registries for building unified container and package registries' } diff --git a/ts/oci/classes.ociregistry.ts b/ts/oci/classes.ociregistry.ts index e7d7e49..07241f4 100644 --- a/ts/oci/classes.ociregistry.ts +++ b/ts/oci/classes.ociregistry.ts @@ -379,7 +379,18 @@ export class OciRegistry extends BaseRegistry { }; } - const manifestData = Buffer.isBuffer(body) ? body : Buffer.from(JSON.stringify(body)); + // Preserve raw bytes for accurate digest calculation + // Per OCI spec, digest must match the exact bytes sent by client + let manifestData: Buffer; + if (Buffer.isBuffer(body)) { + manifestData = body; + } else if (typeof body === 'string') { + // String body - convert directly without JSON transformation + manifestData = Buffer.from(body, 'utf-8'); + } else { + // Body was already parsed as JSON object - re-serialize as fallback + manifestData = Buffer.from(JSON.stringify(body)); + } const contentType = headers?.['content-type'] || headers?.['Content-Type'] || 'application/vnd.oci.image.manifest.v1+json'; // Calculate manifest digest