fix(plugins): preserve install policy on retained reactivation

This commit is contained in:
Vincent Koc
2026-06-23 16:03:19 +08:00
parent cd731fb63e
commit 74ecbbbb98
2 changed files with 37 additions and 6 deletions

View File

@@ -2880,21 +2880,28 @@ describe("installPluginFromNpmSpec", () => {
expect(requests[0]?.request.kind).toBe("plugin-npm");
});
it("reports install mode to policy when update-mode reactivates retained-only generations", async () => {
it("reports install mode to policy when update-mode reactivates retained generations", async () => {
const root = suiteTempRootTracker.makeTempDir();
const npmDir = path.join(root, "npm");
const extensionsDir = path.join(root, "extensions");
const packageName = "@acme/policy-generation-plugin";
const legacyProjectRoot = resolvePluginNpmProjectDir({ npmDir, packageName });
const generationProjectRoot = resolvePluginNpmGenerationProjectDir({
npmDir,
packageName,
generationKey: [packageName, "1.2.3", `${packageName}@1.2.3`, "sha512-test", "abc123"].join(
"\n",
),
});
const activeGenerationProjectRoot = resolvePluginNpmGenerationProjectDir({
npmDir,
packageName,
generationKey: [
packageName,
"1.2.3",
`${packageName}@1.2.3`,
"sha512-plugin-test",
"pluginshasum",
"2.0.0",
`${packageName}@2.0.0`,
"sha512-active",
"active123",
].join("\n"),
});
const legacyPackageDir = path.join(
@@ -2907,6 +2914,11 @@ describe("installPluginFromNpmSpec", () => {
"node_modules",
...packageName.split("/"),
);
const activeGenerationPackageDir = path.join(
activeGenerationProjectRoot,
"node_modules",
...packageName.split("/"),
);
for (const packageDir of [legacyPackageDir, generationPackageDir]) {
fs.mkdirSync(packageDir, { recursive: true });
await markRetainedManagedNpmInstall({
@@ -2916,6 +2928,7 @@ describe("installPluginFromNpmSpec", () => {
reason: "test-retained-generation",
});
}
fs.mkdirSync(activeGenerationPackageDir, { recursive: true });
const { scriptPath, logPath } = writeInstallOnlyBlockingPolicyScript(root);
mockNpmViewMetadata({
name: packageName,

View File

@@ -1149,7 +1149,7 @@ function resolveManagedNpmInstallRoot(params: {
});
const npmRoot = resolveManagedNpmRootForInstall(params);
const installRoot = resolveManagedNpmRootPackageDir(npmRoot, params.packageName);
if (!params.useGeneration || !hasRetainedManagedNpmInstallMarker(installRoot)) {
if (!hasRetainedManagedNpmInstallMarker(installRoot)) {
return npmRoot;
}
// Never mutate a retained tree: an older process may still hold lazy imports
@@ -1206,6 +1206,7 @@ async function resolveManagedNpmGenerationUseForInstall(params: {
npmBaseDir: string;
packageName: string;
requestedMode: "install" | "update";
npmResolution?: NpmSpecResolution;
}): Promise<"none" | "update" | "retained-install"> {
const packageDirs = await listManagedNpmPackageDirsForPackage({
runtime: params.runtime,
@@ -1218,6 +1219,20 @@ async function resolveManagedNpmGenerationUseForInstall(params: {
if (packageDirs.length > 0 && !hasNonRetainedPackageDir) {
return "retained-install";
}
const generationUse =
params.requestedMode === "update" && hasNonRetainedPackageDir ? "update" : "none";
if (params.npmResolution) {
const candidateRoot = resolveManagedNpmRootForInstall({
npmBaseDir: params.npmBaseDir,
packageName: params.packageName,
npmResolution: params.npmResolution,
useGeneration: generationUse !== "none",
});
const candidatePackageDir = resolveManagedNpmRootPackageDir(candidateRoot, params.packageName);
if (hasRetainedManagedNpmInstallMarker(candidatePackageDir)) {
return "retained-install";
}
}
if (params.requestedMode === "update") {
return hasNonRetainedPackageDir ? "update" : "none";
}
@@ -1332,6 +1347,7 @@ async function installPluginFromManagedNpmRoot(
npmBaseDir,
packageName: params.packageName,
requestedMode: mode,
npmResolution: params.npmResolution,
});
const npmRoot = resolveManagedNpmInstallRoot({
npmBaseDir,
@@ -3093,6 +3109,7 @@ export async function installPluginFromNpmSpec(
npmBaseDir,
packageName: parsedSpec.name,
requestedMode: mode,
npmResolution,
});
const npmRoot = resolveManagedNpmRootForInstall({
npmBaseDir,
@@ -3243,6 +3260,7 @@ export async function installPluginFromNpmPackArchive(
npmBaseDir,
packageName,
requestedMode: mode,
npmResolution,
});
const npmProjectRoot = resolveManagedNpmRootForInstall({
npmBaseDir,