From fc75574a790357abdec48f85ee5382926da9405d Mon Sep 17 00:00:00 2001 From: Tom Hale Date: Sun, 5 Apr 2026 14:17:35 +0700 Subject: [PATCH 1/3] test(write): set umask to 0o022 for deterministic file permissions --- packages/opencode/test/tool/write.test.ts | 43 +++++++++++++---------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/packages/opencode/test/tool/write.test.ts b/packages/opencode/test/tool/write.test.ts index 97939c10519e..304ec6c9756b 100644 --- a/packages/opencode/test/tool/write.test.ts +++ b/packages/opencode/test/tool/write.test.ts @@ -156,25 +156,30 @@ describe("tool.write", () => { await using tmp = await tmpdir() const filepath = path.join(tmp.path, "sensitive.json") - await Instance.provide({ - directory: tmp.path, - fn: async () => { - const write = await WriteTool.init() - await write.execute( - { - filePath: filepath, - content: JSON.stringify({ secret: "data" }), - }, - ctx, - ) - - // On Unix systems, check permissions - if (process.platform !== "win32") { - const stats = await fs.stat(filepath) - expect(stats.mode & 0o777).toBe(0o644) - } - }, - }) + const prevUmask = process.umask(0o022) + try { + await Instance.provide({ + directory: tmp.path, + fn: async () => { + const write = await WriteTool.init() + await write.execute( + { + filePath: filepath, + content: JSON.stringify({ secret: "data" }), + }, + ctx, + ) + + // On Unix systems, check permissions + if (process.platform !== "win32") { + const stats = await fs.stat(filepath) + expect(stats.mode & 0o777).toBe(0o644) + } + }, + }) + } finally { + process.umask(prevUmask) + } }) }) From 90f7ec22f6bb369d9035af63b78b44d076c7c3f0 Mon Sep 17 00:00:00 2001 From: Tom Hale Date: Wed, 8 Apr 2026 23:48:14 +0700 Subject: [PATCH 2/3] test(write): cover base mode and masked file permissions --- packages/opencode/test/tool/write.test.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/opencode/test/tool/write.test.ts b/packages/opencode/test/tool/write.test.ts index 304ec6c9756b..66ccb483ed43 100644 --- a/packages/opencode/test/tool/write.test.ts +++ b/packages/opencode/test/tool/write.test.ts @@ -152,11 +152,10 @@ describe("tool.write", () => { }) describe("file permissions", () => { - test("sets file permissions when writing sensitive data", async () => { + async function writeAndCheckMode(umask: number, expected: number) { await using tmp = await tmpdir() const filepath = path.join(tmp.path, "sensitive.json") - - const prevUmask = process.umask(0o022) + const prev = process.umask(umask) try { await Instance.provide({ directory: tmp.path, @@ -170,17 +169,20 @@ describe("tool.write", () => { ctx, ) - // On Unix systems, check permissions if (process.platform !== "win32") { const stats = await fs.stat(filepath) - expect(stats.mode & 0o777).toBe(0o644) + expect(stats.mode & 0o777).toBe(expected) } }, }) } finally { - process.umask(prevUmask) + process.umask(prev) } - }) + } + + test("base mode is 0o644 before umask masking", () => writeAndCheckMode(0o000, 0o644)) + test("respects umask 0o022 → 0o644", () => writeAndCheckMode(0o022, 0o644)) + test("respects umask 0o077 → 0o600", () => writeAndCheckMode(0o077, 0o600)) }) describe("content types", () => { From 5c035c1d39eba32377f41d030b734accb517cf97 Mon Sep 17 00:00:00 2001 From: Tom Hale Date: Sat, 11 Apr 2026 00:41:47 +0700 Subject: [PATCH 3/3] test(write): align umask coverage with actual file modes Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- packages/opencode/test/tool/write.test.ts | 51 +++++++++++++---------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/opencode/test/tool/write.test.ts b/packages/opencode/test/tool/write.test.ts index 66ccb483ed43..8e42b15e72ca 100644 --- a/packages/opencode/test/tool/write.test.ts +++ b/packages/opencode/test/tool/write.test.ts @@ -152,37 +152,46 @@ describe("tool.write", () => { }) describe("file permissions", () => { + const base = 0o666 + + async function put(dir: string, filepath: string, content: string) { + await Instance.provide({ + directory: dir, + fn: async () => { + const write = await WriteTool.init() + await write.execute( + { + filePath: filepath, + content, + }, + ctx, + ) + }, + }) + } + async function writeAndCheckMode(umask: number, expected: number) { + if (process.platform === "win32") return await using tmp = await tmpdir() const filepath = path.join(tmp.path, "sensitive.json") const prev = process.umask(umask) try { - await Instance.provide({ - directory: tmp.path, - fn: async () => { - const write = await WriteTool.init() - await write.execute( - { - filePath: filepath, - content: JSON.stringify({ secret: "data" }), - }, - ctx, - ) - - if (process.platform !== "win32") { - const stats = await fs.stat(filepath) - expect(stats.mode & 0o777).toBe(expected) - } - }, - }) + await put(tmp.path, filepath, JSON.stringify({ secret: "data" })) + + const stats = await fs.stat(filepath) + expect(stats.mode & 0o777).toBe(expected) } finally { process.umask(prev) } } - test("base mode is 0o644 before umask masking", () => writeAndCheckMode(0o000, 0o644)) - test("respects umask 0o022 → 0o644", () => writeAndCheckMode(0o022, 0o644)) - test("respects umask 0o077 → 0o600", () => writeAndCheckMode(0o077, 0o600)) + test("base mode is 0o666 before umask masking", () => writeAndCheckMode(0o000, base)) + test("respects umask 0o022 → 0o644", () => writeAndCheckMode(0o022, base & ~0o022)) + test("respects corner umask 0o027 → 0o640", () => writeAndCheckMode(0o027, base & ~0o027)) + test("respects umask 0o077 → 0o600", () => writeAndCheckMode(0o077, base & ~0o077)) + test("0o777 fully masks the 0o666 base mode", () => { + expect(base & ~0o777).toBe(0o000) + }) }) describe("content types", () => {