Merge pull request 'fix(security): bump @react-navigation/core to 7.22.1 via override' (#119) from issue-117-react-navigation-core-7.22.1 into master
This commit is contained in:
commit
53c33e73a4
3 changed files with 105 additions and 9 deletions
15
package-lock.json
generated
15
package-lock.json
generated
|
|
@ -3468,16 +3468,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/core": {
|
||||
"version": "7.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.14.0.tgz",
|
||||
"integrity": "sha512-tMpzskBzVp0E7CRNdNtJIdXjk54Kwe/TF9ViXAef+YFM1kSfGv4e/B2ozfXE+YyYgmh4WavTv8fkdJz1CNyu+g==",
|
||||
"version": "7.22.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.22.1.tgz",
|
||||
"integrity": "sha512-6JAaYM4u6RPtVMUjN5ovX5DNBdBZtDqebk7kEwlncUP6fP4P94+qEYv1bRmtxSFs7UxiZwQQs+jzTsBaW2WeyA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^7.5.3",
|
||||
"@react-navigation/routers": "^7.6.4",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"nanoid": "^3.3.11",
|
||||
"query-string": "^7.1.3",
|
||||
"react-is": "^19.1.0",
|
||||
"use-latest-callback": "^0.2.4",
|
||||
"use-sync-external-store": "^1.5.0"
|
||||
|
|
@ -3546,9 +3545,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@react-navigation/routers": {
|
||||
"version": "7.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz",
|
||||
"integrity": "sha512-1tJHg4KKRJuQ1/EvJxatrMef3NZXEPzwUIUZ3n1yJ2t7Q97siwRtbynRpQG9/69ebbtiZ8W3ScOZF/OmhvM4Rg==",
|
||||
"version": "7.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.6.4.tgz",
|
||||
"integrity": "sha512-GI7eJm8/KsZUQaYcXvEExikKurRZRgEsSzyZ7faENfi65yqJBCXjDMwyN1pF6pNW1MoLH1ErDwDivFxY6BzD3w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11"
|
||||
|
|
|
|||
|
|
@ -109,7 +109,8 @@
|
|||
"metro-source-map": "^0.83.8",
|
||||
"metro-symbolicate": "^0.83.8",
|
||||
"metro-transform-plugins": "^0.83.8",
|
||||
"metro-transform-worker": "^0.83.8"
|
||||
"metro-transform-worker": "^0.83.8",
|
||||
"@react-navigation/core": "^7.22.1"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,6 +168,102 @@ check('feedback.ts stays import-free (protects type-stripping test path)', () =>
|
|||
);
|
||||
});
|
||||
|
||||
// --- Build toolchain guards ---
|
||||
// A blanket `npm audit fix` (PR #118) once rewrote hundreds of lock entries:
|
||||
// babel-preset-expo and @expo/metro-config lost their root hoisting and a
|
||||
// second Expo SDK was nested inside Expo 54. The tests stayed green while the
|
||||
// first Metro bundle failed. These checks lock the layout the build relies on.
|
||||
|
||||
const ROOT = path.resolve(__dirname, '..');
|
||||
const ROOT_NODE_MODULES = path.join(ROOT, 'node_modules');
|
||||
|
||||
function majorOf(version) {
|
||||
return version.split('.')[0];
|
||||
}
|
||||
|
||||
// Every installed copy of `name`, at the root and nested under other packages.
|
||||
function installedCopies(name, dir = ROOT_NODE_MODULES, found = []) {
|
||||
const pkgJson = path.join(dir, name, 'package.json');
|
||||
if (fs.existsSync(pkgJson)) {
|
||||
found.push({ dir: path.dirname(pkgJson), version: require(pkgJson).version });
|
||||
}
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
|
||||
const pkgDirs = entry.name.startsWith('@')
|
||||
? fs.readdirSync(path.join(dir, entry.name)).map((n) => path.join(dir, entry.name, n))
|
||||
: [path.join(dir, entry.name)];
|
||||
for (const pkgDir of pkgDirs) {
|
||||
const nested = path.join(pkgDir, 'node_modules');
|
||||
if (fs.existsSync(nested)) installedCopies(name, nested, found);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
// babel.config.js and sql-transformer.js require these from the repo root.
|
||||
for (const request of ['babel-preset-expo', '@expo/metro-config/babel-transformer']) {
|
||||
check(`${request} resolves from the repo root node_modules`, () => {
|
||||
const resolved = require.resolve(request, { paths: [ROOT] });
|
||||
const pkgName = request.startsWith('@')
|
||||
? request.split('/').slice(0, 2).join('/')
|
||||
: request.split('/')[0];
|
||||
const expectedDir = path.join(ROOT_NODE_MODULES, pkgName) + path.sep;
|
||||
assert.ok(
|
||||
resolved.startsWith(expectedDir),
|
||||
`${request} resolved to ${resolved}, expected under ${expectedDir}`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
check('a single Expo SDK major is installed (matches package.json)', () => {
|
||||
const pkg = require('../package.json');
|
||||
const expected = majorOf(pkg.dependencies.expo.replace(/^[~^]/, ''));
|
||||
const copies = installedCopies('expo');
|
||||
assert.ok(copies.length > 0, 'expo is not installed');
|
||||
const strays = copies.filter((c) => majorOf(c.version) !== expected);
|
||||
assert.deepEqual(
|
||||
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
|
||||
[],
|
||||
`expected only expo ${expected}.x`
|
||||
);
|
||||
});
|
||||
|
||||
check('every installed metro copy honors the 0.83.x override pin', () => {
|
||||
const copies = installedCopies('metro');
|
||||
assert.ok(copies.length > 0, 'metro is not installed');
|
||||
const strays = copies.filter((c) => !/^0\.83\./.test(c.version));
|
||||
assert.deepEqual(
|
||||
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
|
||||
[],
|
||||
'metro must stay on 0.83.x'
|
||||
);
|
||||
});
|
||||
|
||||
// @react-navigation/core <= 7.22.0 pulls query-string -> decode-uri-component
|
||||
// <= 0.4.2 (GHSA-vcc3-ghjq-m6fr). 7.22.1 parses queries itself, so the deep
|
||||
// link round trip must still carry query params through.
|
||||
// Scope: this covers @react-navigation/core's own linking helpers only. The
|
||||
// app's deep links (simplliste://task/<id>) are resolved by expo-router's fork
|
||||
// (expo-router/build/fork/getStateFromPath*.js), which still uses
|
||||
// query-string@7 (see #120) and is not exercised here.
|
||||
check('@react-navigation/core is >= 7.22.1 and drops query-string', () => {
|
||||
const core = require('@react-navigation/core/package.json');
|
||||
const [major, minor, patch] = core.version.split('.').map(Number);
|
||||
assert.ok(
|
||||
major > 7 || (major === 7 && (minor > 22 || (minor === 22 && patch >= 1))),
|
||||
`@react-navigation/core ${core.version} is vulnerable`
|
||||
);
|
||||
assert.ok(!('query-string' in (core.dependencies || {})), 'core still depends on query-string');
|
||||
});
|
||||
|
||||
check('@react-navigation/core deep link round trip keeps query params', () => {
|
||||
const { getStateFromPath, getPathFromState } = require('@react-navigation/core');
|
||||
const config = { screens: { Task: 'task/:id' } };
|
||||
const state = getStateFromPath('/task/abc?x=1&y=a%20b', config);
|
||||
assert.deepEqual(state.routes[0].params, { id: 'abc', x: '1', y: 'a b' });
|
||||
assert.equal(getPathFromState(state, config), '/task/abc?x=1&y=a%20b');
|
||||
});
|
||||
|
||||
if (failed === 0) {
|
||||
console.log('\nsmoke OK');
|
||||
process.exit(0);
|
||||
|
|
|
|||
Loading…
Reference in a new issue