feat(compartment-mapper): Add makeAndHashArchive
MODIFY
packages/compartment-mapper/NEWS.md
packages/compartment-mapper/NEWS.md
User-visible changes to the compartment mapper:
+# Next release
+
+- Adds a `makeAndHashArchive` function that returns both the generated bytes
+ and the SHA-512 of an archive as its created.
+ `makeArchive` just returns the bytes.
+
# 0.6.7 (2022-02-21)
- *BREAKING:* The `loadArchive` and `parseArchive` functions, when given a

MODIFY
packages/compartment-mapper/archive.js
packages/compartment-mapper/archive.js
export {
makeArchive,
+ makeAndHashArchive,
writeArchive,
mapLocation,
hashLocation,

MODIFY
packages/compartment-mapper/index.d.ts
packages/compartment-mapper/index.d.ts
export { loadLocation, importLocation } from './src/import.js';
-export { makeArchive, writeArchive } from './src/archive.js';
+export {
+ makeArchive,
+ makeAndHashArchive,
+ writeArchive,
+ mapLocation,
+ hashLocation,
+} from './src/archive.js';
export {
parseArchive,
loadArchive,

MODIFY
packages/compartment-mapper/index.js
packages/compartment-mapper/index.js
export { loadLocation, importLocation } from './src/import.js';
export {
makeArchive,
+ makeAndHashArchive,
writeArchive,
mapLocation,
hashLocation,

MODIFY
packages/compartment-mapper/src/archive.js
packages/compartment-mapper/src/archive.js
@@ -173,11 +173,12 @@ const captureSourceLocations = async (sources, captureSourceLocation) => {
}
}
};
+
/**
* @param {ReadFn | ReadPowers} powers
* @param {string} moduleLocation
* @param {ArchiveOptions} [options]
- * @returns {Promise<{archiveSources: Sources, archiveCompartmentMapBytes: Uint8Array}>}
+ * @returns {Promise<{sources: Sources, compartmentMapBytes: Uint8Array, sha512?: string}>}
*/
const digestLocation = async (powers, moduleLocation, options) => {
const {
@@ -274,9 +275,15 @@ const digestLocation = async (powers, moduleLocation, options) => {
captureSourceLocations(archiveSources, captureSourceLocation);
}
+ let archiveSha512;
+ if (computeSha512 !== undefined) {
+ archiveSha512 = computeSha512(archiveCompartmentMapBytes);
+ }
+
return {
- archiveCompartmentMapBytes,
- archiveSources,
+ compartmentMapBytes: archiveCompartmentMapBytes,
+ sources: archiveSources,
+ sha512: archiveSha512,
};
};
@@ -284,20 +291,32 @@ const digestLocation = async (powers, moduleLocation, options) => {
* @param {ReadFn | ReadPowers} powers
* @param {string} moduleLocation
* @param {ArchiveOptions} [options]
- * @returns {Promise<Uint8Array>}
+ * @returns {Promise<{bytes: Uint8Array, sha512?: string}>}
*/
-export const makeArchive = async (powers, moduleLocation, options) => {
- const { archiveCompartmentMapBytes, archiveSources } = await digestLocation(
+export const makeAndHashArchive = async (powers, moduleLocation, options) => {
+ const { compartmentMapBytes, sources, sha512 } = await digestLocation(
powers,
moduleLocation,
options,
);
const archive = writeZip();
- await archive.write('compartment-map.json', archiveCompartmentMapBytes);
- await addSourcesToArchive(archive, archiveSources);
+ await archive.write('compartment-map.json', compartmentMapBytes);
+ await addSourcesToArchive(archive, sources);
+ const bytes = await archive.snapshot();
+
+ return { bytes, sha512 };
+};
- return archive.snapshot();
+/**
+ * @param {ReadFn | ReadPowers} powers
+ * @param {string} moduleLocation
+ * @param {ArchiveOptions} [options]
+ * @returns {Promise<Uint8Array>}
+ */
+export const makeArchive = async (powers, moduleLocation, options) => {
+ const { bytes } = await makeAndHashArchive(powers, moduleLocation, options);
+ return bytes;
};
/**
@@ -307,12 +326,12 @@ export const makeArchive = async (powers, moduleLocation, options) => {
* @returns {Promise<Uint8Array>}
*/
export const mapLocation = async (powers, moduleLocation, options) => {
- const { archiveCompartmentMapBytes } = await digestLocation(
+ const { compartmentMapBytes } = await digestLocation(
powers,
moduleLocation,
options,
);
- return archiveCompartmentMapBytes;
+ return compartmentMapBytes;
};
/**
@@ -322,13 +341,13 @@ export const mapLocation = async (powers, moduleLocation, options) => {
* @returns {Promise<string>}
*/
export const hashLocation = async (powers, moduleLocation, options) => {
- const { archiveCompartmentMapBytes } = await digestLocation(
+ const { compartmentMapBytes } = await digestLocation(
powers,
moduleLocation,
options,
);
const { computeSha512 } = powers;
- return computeSha512(archiveCompartmentMapBytes);
+ return computeSha512(compartmentMapBytes);
};
/**

MODIFY
packages/compartment-mapper/test/test-integrity.js
packages/compartment-mapper/test/test-integrity.js
import 'ses';
import test from 'ava';
import { ZipReader, ZipWriter } from '@endo/zip';
-import { makeArchive, parseArchive } from '../index.js';
+import { makeArchive, makeAndHashArchive, parseArchive } from '../index.js';
import { readPowers } from './scaffold.js';
const fixture = new URL(
@@ -109,14 +109,17 @@ test('extracting an archive with an inconsistent hash', async t => {
});
test('extracting an archive with an inconsistent compartment map hash', async t => {
- const validBytes = await makeArchive(readPowers, fixture, {
+ const {
+ bytes: validBytes,
+ sha512: expectedSha512,
+ } = await makeAndHashArchive(readPowers, fixture, {
modules: {
builtin: null,
},
dev: true,
});
- const { sha512: expectedSha512 } = await parseArchive(
+ const { sha512: verifiedSha512 } = await parseArchive(
validBytes,
'valid.zip',
{
@@ -125,6 +128,8 @@ test('extracting an archive with an inconsistent compartment map hash', async t
},
);
+ t.is(expectedSha512, verifiedSha512);
+
const reader = new ZipReader(validBytes);
const writer = new ZipWriter();
writer.files = reader.files;

feat(compartment-mapper): Add makeAndHashArchive