diff --git a/scripts/patch-linux-window-ui.test.js b/scripts/patch-linux-window-ui.test.js index d475e80f..a6dae374 100644 --- a/scripts/patch-linux-window-ui.test.js +++ b/scripts/patch-linux-window-ui.test.js @@ -6888,7 +6888,7 @@ test("auto-installs the current Chrome plugin gate shape", () => { assert.equal((patched.match(/installWhenMissing:!0,name:o\.s/g) || []).length, 0); }); -test("makes Linux bundled plugin staging writable after copying read-only resources", async () => { +test("makes Linux bundled plugin staging owner-writable without cooperative write bits", async () => { const patched = applyPatchTwice( applyLinuxBundledPluginCopyPermissionsPatch, currentBundledPluginCopyBundleFixture(), @@ -6897,21 +6897,29 @@ test("makes Linux bundled plugin staging writable after copying read-only resour const sourcePlugin = path.join(root, "source-plugin"); const sourceManifestDir = path.join(sourcePlugin, ".codex-plugin"); const sourceManifest = path.join(sourceManifestDir, "plugin.json"); + const sourceCooperativeFile = path.join(sourceManifestDir, "cooperative.txt"); const externalFile = path.join(root, "external-read-only-file"); const sourceLink = path.join(sourcePlugin, "external-link"); const targetPlugin = path.join(root, "target-plugin"); const targetManifest = path.join(targetPlugin, ".codex-plugin", "plugin.json"); + const targetCooperativeFile = path.join( + targetPlugin, + ".codex-plugin", + "cooperative.txt", + ); const targetLink = path.join(targetPlugin, "external-link"); try { fs.mkdirSync(sourceManifestDir, { recursive: true }); fs.writeFileSync(sourceManifest, '{"name":"computer-use"}\n'); + fs.writeFileSync(sourceCooperativeFile, "cooperative\n"); fs.writeFileSync(externalFile, "external\n"); fs.chmodSync(externalFile, 0o444); fs.symlinkSync(externalFile, sourceLink); fs.chmodSync(sourceManifest, 0o444); - fs.chmodSync(sourceManifestDir, 0o555); - fs.chmodSync(sourcePlugin, 0o555); + fs.chmodSync(sourceCooperativeFile, 0o664); + fs.chmodSync(sourceManifestDir, 0o775); + fs.chmodSync(sourcePlugin, 0o775); const copyPlugin = new Function("process", "require", `${patched};return fl;`)( { platform: "linux" }, @@ -6923,6 +6931,9 @@ test("makes Linux bundled plugin staging writable after copying read-only resour assert.match(patched, /async function codexLinuxMakeBundledPluginTreeWritable/); assert.equal(fs.statSync(targetPlugin).mode & 0o200, 0o200); assert.equal(fs.statSync(targetManifest).mode & 0o200, 0o200); + assert.equal(fs.statSync(targetPlugin).mode & 0o022, 0); + assert.equal(fs.statSync(targetManifest).mode & 0o022, 0); + assert.equal(fs.statSync(targetCooperativeFile).mode & 0o022, 0); assert.equal(fs.lstatSync(targetLink).isSymbolicLink(), true); assert.equal(fs.statSync(externalFile).mode & 0o200, 0); } finally { diff --git a/scripts/patches/impl/main-process/browser.js b/scripts/patches/impl/main-process/browser.js index 0225173a..52d35a30 100644 --- a/scripts/patches/impl/main-process/browser.js +++ b/scripts/patches/impl/main-process/browser.js @@ -44,7 +44,7 @@ function applyLinuxBundledPluginCopyPermissionsPatch(currentSource) { } const helper = - `async function ${helperName}(e,t){let n=await t.lstat(e);if(n.isSymbolicLink())return;await t.chmod(e,n.mode|128);if(n.isDirectory())for(let n of await t.readdir(e))await ${helperName}((0,${pathVar}.join)(e,n),t)}`; + `async function ${helperName}(e,t){let n=await t.lstat(e);if(n.isSymbolicLink())return;await t.chmod(e,(n.mode|128)&~18);if(n.isDirectory())for(let n of await t.readdir(e))await ${helperName}((0,${pathVar}.join)(e,n),t)}`; const strictDirective = '"use strict";'; const helperInsertionIndex = currentSource.startsWith(strictDirective) ? strictDirective.length