收口原生壳锁文件版本
移动壳配置检查锁定package-lock实际解析版本 桌面壳配置检查锁定package-lock与Cargo.lock解析版本 宿主壳方案文档补充锁文件版本门禁 共享决策日志记录原生壳锁文件依赖边界
This commit is contained in:
@@ -6,6 +6,8 @@ const packagePath = new URL('../package.json', import.meta.url);
|
||||
const packageConfig = JSON.parse(fs.readFileSync(packagePath, 'utf8'));
|
||||
const rootPackagePath = new URL('../../../package.json', import.meta.url);
|
||||
const rootPackageConfig = JSON.parse(fs.readFileSync(rootPackagePath, 'utf8'));
|
||||
const rootPackageLockPath = new URL('../../../package-lock.json', import.meta.url);
|
||||
const rootPackageLock = JSON.parse(fs.readFileSync(rootPackageLockPath, 'utf8'));
|
||||
const capabilityPath = new URL(
|
||||
'../src-tauri/capabilities/main.json',
|
||||
import.meta.url,
|
||||
@@ -15,6 +17,8 @@ const buildScriptPath = new URL('../src-tauri/build.rs', import.meta.url);
|
||||
const buildScript = fs.readFileSync(buildScriptPath, 'utf8');
|
||||
const cargoManifestPath = new URL('../src-tauri/Cargo.toml', import.meta.url);
|
||||
const cargoManifest = fs.readFileSync(cargoManifestPath, 'utf8');
|
||||
const cargoLockPath = new URL('../src-tauri/Cargo.lock', import.meta.url);
|
||||
const cargoLock = fs.readFileSync(cargoLockPath, 'utf8');
|
||||
const iconDirPath = new URL('../src-tauri/icons/', import.meta.url);
|
||||
const generatedPermissionDir = new URL(
|
||||
'../src-tauri/permissions/autogenerated/',
|
||||
@@ -140,6 +144,22 @@ function extractCargoDependencyLine(source, sectionName, dependencyName) {
|
||||
throw new Error(`Cargo ${sectionName}.${dependencyName} is missing`);
|
||||
}
|
||||
|
||||
function extractCargoLockPackages(source) {
|
||||
return source
|
||||
.split('\n[[package]]\n')
|
||||
.map((block) => block.trim())
|
||||
.filter((block) => block.includes('name = '))
|
||||
.map((block) => {
|
||||
const name = block.match(/^name = "([^"]+)"/m)?.[1];
|
||||
const version = block.match(/^version = "([^"]+)"/m)?.[1];
|
||||
const dependenciesMatch = block.match(/^dependencies = \[\n([\s\S]*?)\n\]/m);
|
||||
const dependencies = dependenciesMatch
|
||||
? [...dependenciesMatch[1].matchAll(/ "([^"]+)"/g)].map((entry) => entry[1])
|
||||
: [];
|
||||
return { block, dependencies, name, version };
|
||||
});
|
||||
}
|
||||
|
||||
function escapeRegExp(value) {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
@@ -242,6 +262,15 @@ function assertPackageDependencyVersion(
|
||||
}
|
||||
}
|
||||
|
||||
function assertPackageLockVersion(dependency, expected) {
|
||||
const actual = rootPackageLock.packages?.[`node_modules/${dependency}`]?.version;
|
||||
if (actual !== expected) {
|
||||
throw new Error(
|
||||
`root package-lock ${dependency} resolved version drifted: expected ${expected} but got ${actual}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function assertCargoDependencyLine(sectionName, dependencyName, expectedLine) {
|
||||
const actualLine = extractCargoDependencyLine(
|
||||
cargoManifest,
|
||||
@@ -255,6 +284,52 @@ function assertCargoDependencyLine(sectionName, dependencyName, expectedLine) {
|
||||
}
|
||||
}
|
||||
|
||||
const cargoLockPackages = extractCargoLockPackages(cargoLock);
|
||||
|
||||
function findCargoLockPackage(packageName, expectedVersion) {
|
||||
return cargoLockPackages.find(
|
||||
(entry) => entry.name === packageName && entry.version === expectedVersion,
|
||||
);
|
||||
}
|
||||
|
||||
function assertCargoLockPackageVersion(packageName, expectedVersion) {
|
||||
if (!findCargoLockPackage(packageName, expectedVersion)) {
|
||||
const actualVersions = cargoLockPackages
|
||||
.filter((entry) => entry.name === packageName)
|
||||
.map((entry) => entry.version)
|
||||
.join(', ');
|
||||
throw new Error(
|
||||
`Cargo.lock ${packageName} resolved version drifted: expected ${expectedVersion} but got ${actualVersions || 'missing'}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function assertCargoLockDirectDependency(
|
||||
parentPackageName,
|
||||
parentVersion,
|
||||
dependencyName,
|
||||
expectedVersion,
|
||||
) {
|
||||
const parentPackage = findCargoLockPackage(parentPackageName, parentVersion);
|
||||
if (!parentPackage) {
|
||||
throw new Error(
|
||||
`Cargo.lock ${parentPackageName} ${parentVersion} is missing`,
|
||||
);
|
||||
}
|
||||
|
||||
const dependencyToken = parentPackage.dependencies.find((dependency) => {
|
||||
const [name, version] = dependency.split(' ');
|
||||
return name === dependencyName && (!version || version === expectedVersion);
|
||||
});
|
||||
if (!dependencyToken) {
|
||||
throw new Error(
|
||||
`Cargo.lock ${parentPackageName} ${parentVersion} dependency ${dependencyName} drifted: expected ${expectedVersion}`,
|
||||
);
|
||||
}
|
||||
|
||||
assertCargoLockPackageVersion(dependencyName, expectedVersion);
|
||||
}
|
||||
|
||||
function collectProductionSourceFiles(entry) {
|
||||
const stats = fs.statSync(entry);
|
||||
if (stats.isDirectory()) {
|
||||
@@ -349,6 +424,13 @@ for (const [dependency, expected] of Object.entries({
|
||||
);
|
||||
}
|
||||
|
||||
for (const [dependency, expected] of Object.entries({
|
||||
'@tauri-apps/cli': '2.11.2',
|
||||
typescript: '5.8.3',
|
||||
})) {
|
||||
assertPackageLockVersion(dependency, expected);
|
||||
}
|
||||
|
||||
for (const [sectionName, dependencyName, expectedLine] of [
|
||||
['build-dependencies', 'tauri-build', 'tauri-build = { version = "2.6.2", features = [] }'],
|
||||
['dependencies', 'base64', 'base64 = "0.22"'],
|
||||
@@ -384,6 +466,41 @@ for (const [sectionName, dependencyName, expectedLine] of [
|
||||
assertCargoDependencyLine(sectionName, dependencyName, expectedLine);
|
||||
}
|
||||
|
||||
for (const [packageName, expectedVersion] of [
|
||||
['tauri-build', '2.6.2'],
|
||||
['base64', '0.22.1'],
|
||||
['serde', '1.0.228'],
|
||||
['serde_json', '1.0.150'],
|
||||
['tauri', '2.11.2'],
|
||||
['tauri-plugin-clipboard-manager', '2.3.2'],
|
||||
['tauri-plugin-dialog', '2.7.1'],
|
||||
['tauri-plugin-notification', '2.3.3'],
|
||||
['tauri-plugin-opener', '2.5.4'],
|
||||
['tauri-plugin-single-instance', '2.4.2'],
|
||||
]) {
|
||||
assertCargoLockPackageVersion(packageName, expectedVersion);
|
||||
}
|
||||
|
||||
for (const [dependencyName, expectedVersion] of [
|
||||
['tauri-build', '2.6.2'],
|
||||
['base64', '0.22.1'],
|
||||
['serde', '1.0.228'],
|
||||
['serde_json', '1.0.150'],
|
||||
['tauri', '2.11.2'],
|
||||
['tauri-plugin-clipboard-manager', '2.3.2'],
|
||||
['tauri-plugin-dialog', '2.7.1'],
|
||||
['tauri-plugin-notification', '2.3.3'],
|
||||
['tauri-plugin-opener', '2.5.4'],
|
||||
['tauri-plugin-single-instance', '2.4.2'],
|
||||
]) {
|
||||
assertCargoLockDirectDependency(
|
||||
'genarrative-desktop-shell',
|
||||
config.version,
|
||||
dependencyName,
|
||||
expectedVersion,
|
||||
);
|
||||
}
|
||||
|
||||
function readPngSize(file) {
|
||||
const buffer = fs.readFileSync(file);
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user