feat(compartment-mapper): parseArchive return hash
MODIFY
packages/compartment-mapper/NEWS.md
packages/compartment-mapper/NEWS.md
User-visible changes to the compartment mapper:
+# Next release
+
+- The `parseArchive` function returns a promise for an archive. If provided a
+ `computeSha512`, regardless of whether provided `expectedSha512`, the archive
+ will have a `sha512` property computed from the parsed archive, for
+ the purpose of verifying integrity.
+
# 0.5.3 (2021-12-08)
- The `node-powers.js` module now exports `makeReadPowers` and

MODIFY
packages/compartment-mapper/README.md
packages/compartment-mapper/README.md
@@ -116,6 +116,9 @@ Use `parseArchive` to construct a runner from the bytes of an archive.
The `loadArchive` and `parseArchive` functions return an `Application`
object with an `import({ globals?, modules? })` method.
+`loadArchive` and `parseArchive` do not run the archived program,
+so they can be used to check the hash of a program without running it.
+
# Package Descriptors
The compartment mapper uses [Compartments], one for each Node.js package your

MODIFY
packages/compartment-mapper/src/import-archive.js
packages/compartment-mapper/src/import-archive.js
@@ -150,13 +150,16 @@ export const parseArchive = async (
const archive = await readZip(archiveBytes, archiveLocation);
const compartmentMapBytes = await archive.read('compartment-map.json');
+ let sha512;
+ if (computeSha512 !== undefined) {
+ sha512 = computeSha512(compartmentMapBytes);
+ }
if (expectedSha512 !== undefined) {
- if (computeSha512 === undefined) {
+ if (sha512 === undefined) {
throw new Error(
`Cannot verify expectedSha512 without also providing computeSha512, for archive ${archiveLocation}`,
);
}
- const sha512 = computeSha512(compartmentMapBytes);
if (sha512 !== expectedSha512) {
throw new Error(
`Archive compartment map failed a SHA-512 integrity check, expected ${expectedSha512}, got ${sha512}, for archive ${archiveLocation}`,
@@ -205,7 +208,7 @@ export const parseArchive = async (
return compartment.import(moduleSpecifier);
};
- return { import: execute };
+ return { import: execute, sha512 };
};
/**

MODIFY
packages/compartment-mapper/test/scaffold.js
packages/compartment-mapper/test/scaffold.js
@@ -184,7 +184,7 @@ export function scaffold(
});
test(`${name} / makeArchive / parseArchive / hashArchive consistency`, async t => {
- t.plan(0);
+ t.plan(1);
await setup();
const expectedSha512 = await hashLocation(readPowers, fixture, {
@@ -198,12 +198,18 @@ export function scaffold(
});
const { computeSha512 } = readPowers;
- await parseArchive(archiveBytes, 'memory:app.agar', {
+ const { sha512: computedSha512 } = await parseArchive(
+ archiveBytes,
+ 'memory:app.agar',
+ {
modules,
dev: true,
computeSha512,
expectedSha512,
- });
+ },
+ );
+
+ t.is(computedSha512, expectedSha512);
});
test(`${name} / makeArchive / parseArchive, but with sha512 corruption of a compartment map`, async t => {

feat(compartment-mapper): parseArchive return hash