fix(compartment-mapper): Deterministic archives
MODIFY
packages/compartment-mapper/NEWS.md
packages/compartment-mapper/NEWS.md
@@ -20,6 +20,7 @@ User-visible changes to the compartment mapper:
removal of the `ses/lockdown` light layering (there is no heavy layer to
distinguish as the weight has shifted to the `@endo/static-module-record`
package).
+* Archives are now deterministic.
## 0.2.4 (2021-03-30)

MODIFY
packages/compartment-mapper/src/archive.js
packages/compartment-mapper/src/archive.js
@@ -28,7 +28,7 @@ const parserForLanguage = {
*/
const resolveLocation = (rel, abs) => new URL(rel, abs).toString();
-const { entries, fromEntries, values } = Object;
+const { keys, entries, fromEntries } = Object;
/**
* @param {Record<string, CompartmentDescriptor>} compartments
@@ -53,13 +53,17 @@ const renameCompartments = compartments => {
*/
const translateCompartmentMap = (compartments, sources, renames) => {
const result = {};
- for (const [name, compartment] of entries(compartments)) {
+ for (const name of keys(compartments).sort()) {
+ const compartment = compartments[name];
const { label } = compartment;
// rename module compartments
/** @type {Record<string, ModuleDescriptor>} */
const modules = {};
- for (const [name, module] of entries(compartment.modules || {})) {
+ const compartmentModules = compartment.modules;
+ if (compartment.modules) {
+ for (const name of keys(compartmentModules).sort()) {
+ const module = compartmentModules[name];
const compartment = module.compartment
? renames[module.compartment]
: undefined;
@@ -68,10 +72,13 @@ const translateCompartmentMap = (compartments, sources, renames) => {
compartment,
};
}
+ }
// integrate sources into modules
const compartmentSources = sources[name];
- for (const [name, source] of entries(compartmentSources || {})) {
+ if (compartmentSources) {
+ for (const name of keys(compartmentSources).sort()) {
+ const source = compartmentSources[name];
const { location, parser, exit } = source;
modules[name] = {
location,
@@ -79,6 +86,7 @@ const translateCompartmentMap = (compartments, sources, renames) => {
exit,
};
}
+ }
result[renames[name]] = {
label,
@@ -111,9 +119,11 @@ const renameSources = (sources, renames) => {
* @param {Sources} sources
*/
const addSourcesToArchive = async (archive, sources) => {
- for (const [compartment, modules] of entries(sources)) {
+ for (const compartment of keys(sources).sort()) {
+ const modules = sources[compartment];
const compartmentLocation = resolveLocation(`${compartment}/`, 'file:///');
- for (const { location, bytes } of values(modules)) {
+ for (const specifier of keys(modules).sort()) {
+ const { bytes, location } = modules[specifier];
if (location !== undefined) {
const moduleLocation = resolveLocation(location, compartmentLocation);
const path = new URL(moduleLocation).pathname.slice(1); // elide initial "/"

MODIFY
packages/compartment-mapper/src/node-modules.js
packages/compartment-mapper/src/node-modules.js
import { inferExports } from './infer-exports.js';
import { parseLocatedJson } from './json.js';
-const { create, entries, keys, values } = Object;
+const { create, keys, values } = Object;
const decoder = new TextDecoder();
@@ -222,7 +222,7 @@ const graphPackage = async (
/** @type {Record<string, string>} */
const dependencies = {};
const children = [];
- for (const name of keys(packageDescriptor.dependencies || {})) {
+ for (const name of keys(packageDescriptor.dependencies || {}).sort()) {
children.push(
// Mutual recursion ahead:
// eslint-disable-next-line no-use-before-define
@@ -364,17 +364,17 @@ const translateGraph = (
// The full map includes every exported module from every dependencey
// package and is a complete list of every external module that the
// corresponding compartment can import.
- for (const [
- packageLocation,
- { label, dependencies, parsers, types },
- ] of entries(graph)) {
+ for (const packageLocation of keys(graph).sort()) {
+ const { label, dependencies, parsers, types } = graph[packageLocation];
/** @type {Record<string, ModuleDescriptor>} */
const modules = {};
/** @type {Record<string, ScopeDescriptor>} */
const scopes = {};
- for (const [dependencyName, packageLocation] of entries(dependencies)) {
+ for (const dependencyName of keys(dependencies).sort()) {
+ const packageLocation = dependencies[dependencyName];
const { exports, explicit } = graph[packageLocation];
- for (const [exportName, module] of entries(exports)) {
+ for (const exportName of keys(exports).sort()) {
+ const module = exports[exportName];
modules[exportName] = {
compartment: packageLocation,
module,

fix(compartment-mapper): Deterministic archives