Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.

Commit

Permalink
fix(externals): use browser and node integrity values
Browse files Browse the repository at this point in the history
  • Loading branch information
JAdshead committed Nov 7, 2023
1 parent c02d065 commit eeec4f7
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 51 deletions.
78 changes: 41 additions & 37 deletions packages/holocron/__tests__/loadModule.node.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ describe('loadModule.node', () => {
beforeAll(() => {
jest.spyOn(console, 'log');
jest.spyOn(console, 'warn');
console.log.mockImplementation(() => { });
console.warn.mockImplementation(() => { });
console.log.mockImplementation(() => {});
console.warn.mockImplementation(() => {});
});

beforeEach(() => {
Expand Down Expand Up @@ -788,14 +788,13 @@ describe('loadModule.node', () => {
environmentVariables: [{ name: 'COOL_API_URL', validate: jest.fn() }],
};
const moduleString = { onModuleLoadConfig };

// mock fetching module-config.json
mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 200,
statusText: 'OK',
json: () => '{ "requiredExternals": [] }',
json: () => '{ "requiredExternals": {} }',
ok: true,
})
);
}));

mockFetch.mockImplementationOnce(
makeFetchMock({ fetchText: moduleString })
Expand Down Expand Up @@ -834,7 +833,7 @@ describe('loadModule.node', () => {
environmentVariables: [{ name: 'COOL_API_URL', validate: jest.fn() }],
};
const moduleString = { onModuleLoadConfig };

// mock fetching module-config.json
mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 200,
statusText: 'OK',
Expand All @@ -843,20 +842,21 @@ describe('loadModule.node', () => {
{
name: 'lodash',
version: '1.0.0',
browserIntegrity: '123-browser',
nodeIntegrity: '123-node',
},
],
}),
ok: true,
})
);
}));

mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 200,
statusText: 'OK',
text: () => 'external fallback code',
ok: true,
})
);
}));

mockFetch.mockImplementationOnce(
makeFetchMock({ fetchText: moduleString })
);
Expand Down Expand Up @@ -921,8 +921,7 @@ describe('loadModule.node', () => {
},
}),
ok: true,
})
);
}));
mockFetch.mockImplementationOnce(
makeFetchMock({ fetchText: moduleString })
);
Expand Down Expand Up @@ -972,8 +971,7 @@ describe('loadModule.node', () => {
},
}),
ok: true,
})
);
}));
mockFetch.mockImplementationOnce(
makeFetchMock({ fetchText: moduleString })
);
Expand Down Expand Up @@ -1028,8 +1026,7 @@ describe('loadModule.node', () => {
},
}),
ok: true,
})
);
}));
mockFetch.mockImplementationOnce(
makeFetchMock({ fetchText: moduleString })
);
Expand Down Expand Up @@ -1070,14 +1067,14 @@ describe('loadModule.node', () => {
requiredExternals: {
'my-dep': {
name: 'my-dep',
integrity: '1234',
browserIntegrity: '1234-browser',
nodeIntegrity: '1234-node',
version: '1.0.1',
semanticRange: '^1.0.0',
},
},
}),
})
);
}));

// load module
const loadModule = load({
Expand Down Expand Up @@ -1108,7 +1105,8 @@ describe('loadModule.node', () => {
'my-module': {
'my-dep': {
name: 'my-dep',
integrity: '1234',
browserIntegrity: '1234-browser',
nodeIntegrity: '1234-node',
version: '1.0.1',
semanticRange: '^1.0.0',
},
Expand All @@ -1125,22 +1123,21 @@ describe('loadModule.node', () => {
requiredExternals: {
myDep: {
name: 'my-dep',
integrity: '1234',
browserIntegrity: '1234-browser',
nodeIntegrity: '1234-node',
version: '1.0.1',
semanticRange: '^1.0.0',
},
},
}),
ok: true,
})
);
}));

mockFetch.mockImplementation(() => Promise.resolve({
ok: true,
status: 200,
text: () => JSON.stringify({}),
})
);
}));

const loadModule = load({
fetch: mockFetch,
Expand Down Expand Up @@ -1197,7 +1194,8 @@ describe('loadModule.node', () => {
semanticRange: '^1.0.0',
name: 'lodash',
version: '1.2.3',
integrity: '12345',
browserIntegrity: '1234-browser',
nodeIntegrity: '1234-node',
},
},
}),
Expand All @@ -1209,8 +1207,7 @@ describe('loadModule.node', () => {
statusText: 'OK',
text: () => 'external fallback code',
ok: true,
})
);
}));

// mock fetch for module code
mockFetch.mockImplementationOnce(
Expand Down Expand Up @@ -1245,8 +1242,9 @@ describe('loadModule.node', () => {
Object {
"awesome": Object {
"lodash": Object {
"integrity": "12345",
"browserIntegrity": "1234-browser",
"name": "lodash",
"nodeIntegrity": "1234-node",
"semanticRange": "^1.0.0",
"version": "1.2.3",
},
Expand Down Expand Up @@ -1280,7 +1278,8 @@ describe('loadModule.node', () => {
mockFetch.mockImplementationOnce(
makeFetchMock({
fetchText: fakeModule,
}));
})
);

const loadModule = load({
fetch: mockFetch,
Expand All @@ -1294,7 +1293,7 @@ describe('loadModule.node', () => {
},
})
).rejects.toThrowErrorMatchingInlineSnapshot(
'"External \'example-dep\' is required by awesome, but is not provided by the root module"'
"\"External 'example-dep' is required by awesome, but is not provided by the root module\""
);
});

Expand All @@ -1305,7 +1304,8 @@ describe('loadModule.node', () => {
// does not have moduleConfig file.
mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 404,
}));
})
);

// mock fetch for module
mockFetch.mockImplementationOnce(
Expand Down Expand Up @@ -1343,7 +1343,8 @@ describe('loadModule.node', () => {
// does not have moduleConfig file.
mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 404,
}));
})
);

// mock fetch for module
mockFetch.mockImplementationOnce(
Expand Down Expand Up @@ -1388,7 +1389,8 @@ describe('loadModule.node', () => {
// does not have moduleConfig file.
mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 404,
}));
})
);

// mock fetch for module
mockFetch.mockImplementationOnce(
Expand Down Expand Up @@ -1435,7 +1437,8 @@ describe('loadModule.node', () => {
// does not have moduleConfig file.
mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 404,
}));
})
);

// mock fetch for module
mockFetch.mockImplementationOnce(
Expand Down Expand Up @@ -1476,7 +1479,8 @@ describe('loadModule.node', () => {
// does not have moduleConfig file.
mockFetch.mockImplementationOnce(() => Promise.resolve({
status: 404,
}));
})
);

// mock fetch for module
mockFetch.mockImplementationOnce(
Expand Down
15 changes: 11 additions & 4 deletions packages/holocron/src/externalRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,19 @@ let registeredExternals = iMap();
* name: {string}[name of external],
* version: {string}[version of external fallback],
* semanticRange: {string}[range of expected external],
* integrity: {string}[hash value of module code]
* browserIntegrity: {string}[hash value of external fallback browser code]
* nodeIntegrity: {string}[hash value of external fallback server code]
* }
* }
* }
* @type { Immutable.Map } registry
* @param {string} registry.[moduleName].[externalName].name external name
* @param {string} registry.[moduleName].[externalName].version external version
* @param {string} registry.[moduleName].[externalName].semanticRange accepted semantic range
* @param {string} registry.[moduleName].[externalName].integrity hash value of fallback external
* @param {string} registry.[moduleName].[externalName].browserIntegrity hash value of
* fallback external browser code
* @param {string} registry.[moduleName].[externalName].nodeIntegrity hash value of
* fallback external server code
*/
let requiredModuleExternals = iMap();

Expand Down Expand Up @@ -115,8 +119,11 @@ function clearModulesRequiredExternals(moduleName) {
* @param {string} externals.[externalName].name external name
* @param {string} externals.[externalName].version external version
* @param {string} externals.[externalName].semanticRange semantic range module will accept
* @param {string} externals.[externalName].integrity hash value of fallback external
*/
* @param {string} externals.[externalName].nodeIntegrity hash value of
* fallback external browser code
* @param {string} externals.[externalName].browserIntegrity hash value of
* fallback external server code
*/
function setModulesRequiredExternals({ moduleName, externals }) {
if (externals) {
requiredModuleExternals = requiredModuleExternals.set(moduleName, fromJS(externals));
Expand Down
17 changes: 9 additions & 8 deletions packages/holocron/src/loadModule.node.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const fetchNodeModule = async (url, integrity, context) => {
try {
const moduleString = await fetchAsset(url);

if (process.env.NODE_ENV === 'production') {
if (process.env.NODE_ENV !== 'development') {
const actualSRI = ssri.fromData(
moduleString,
{ algorithms: ['sha256', 'sha384'] }
Expand All @@ -125,16 +125,16 @@ const fetchNodeModule = async (url, integrity, context) => {
};

/**
* Loads Fallback Externals for a module
* Loads Fallback Externals server bundle for a module
* @param {string} baseUrl path to the assets
* @param {string} moduleName module name
*/
const loadModuleFallbackExternals = async (baseUrl, moduleName) => {
const fallbacks = getUnregisteredRequiredExternals(moduleName);

await Promise.all(
fallbacks.map(async ({ name, version, integrity }) => {
const fallbackDependency = await fetchNodeModule(`${baseUrl}${name}.node.js`, integrity, {
fallbacks.map(async ({ name, version, nodeIntegrity }) => {
const fallbackDependency = await fetchNodeModule(`${baseUrl}${name}.node.js`, nodeIntegrity, {
type: 'External Fallback',
name,
});
Expand Down Expand Up @@ -212,9 +212,9 @@ const validateRequiredExternals = ({
const providedExternal = providedExternals[externalName];
const requiredExternal = requiredExternals[externalName];
const {
version, name, integrity, semanticRange,
version, name, nodeIntegrity, browserIntegrity, semanticRange,
} = requiredExternal;
const fallbackExternalAvailable = !!name && !!version;
const fallbackExternalAvailable = !!name && !!version && !!nodeIntegrity && !!browserIntegrity;
const fallbackBlockedByRootModule = !!providedExternal && !providedExternal.fallbackEnabled;

if (!providedExternal) {
Expand Down Expand Up @@ -242,7 +242,8 @@ const validateRequiredExternals = ({
name,
version,
semanticRange,
integrity,
nodeIntegrity,
browserIntegrity,
};
}
});
Expand Down Expand Up @@ -296,7 +297,7 @@ const loadModule = async (
// root modules can be built without getTenantRootModule
const rootModule = global.getTenantRootModule ? global.getTenantRootModule() : null;

// if no root module, module being loaded should be root.
// if no root module, module being loaded should be rootModule
if (rootModule) {
const {
providedExternals: rootProvidedExternals,
Expand Down
4 changes: 2 additions & 2 deletions packages/holocron/src/loadModule.web.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ function loadModuleFallbackExternals(moduleName) {
const fallbacks = getUnregisteredRequiredExternals(moduleName);
const baseUrl = getModuleMap().getIn(['modules', moduleName, 'baseUrl']);

return Promise.all(fallbacks.map(({ name, integrity }) => createScript({
return Promise.all(fallbacks.map(({ name, browserIntegrity }) => createScript({
url: `${baseUrl}${name}.browser.js`,
integrity,
integrity: browserIntegrity,
})));
}

Expand Down

0 comments on commit eeec4f7

Please sign in to comment.