Skip to content

Commit ee4234f

Browse files
committed
Fix OPENCODE_CONFIG_CONTENT token substitution
- Route inline config through load() function to enable {env:} and {file:} token substitution - Make OPENCODE_CONFIG_CONTENT a dynamic getter for runtime env var access - Add tests for {env:} and {file:} token substitution in OPENCODE_CONFIG_CONTENT Fixes #13219
1 parent e2a33f7 commit ee4234f

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

packages/opencode/src/config/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export namespace Config {
176176

177177
// Inline config content overrides all non-managed config sources.
178178
if (Flag.OPENCODE_CONFIG_CONTENT) {
179-
result = mergeConfigConcatArrays(result, JSON.parse(Flag.OPENCODE_CONFIG_CONTENT))
179+
result = mergeConfigConcatArrays(result, await load(Flag.OPENCODE_CONFIG_CONTENT, path.join(Instance.directory, "<inline>")))
180180
log.debug("loaded custom config from OPENCODE_CONFIG_CONTENT")
181181
}
182182

packages/opencode/src/flag/flag.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export namespace Flag {
88
export const OPENCODE_GIT_BASH_PATH = process.env["OPENCODE_GIT_BASH_PATH"]
99
export const OPENCODE_CONFIG = process.env["OPENCODE_CONFIG"]
1010
export declare const OPENCODE_CONFIG_DIR: string | undefined
11-
export const OPENCODE_CONFIG_CONTENT = process.env["OPENCODE_CONFIG_CONTENT"]
11+
export declare const OPENCODE_CONFIG_CONTENT: string | undefined
1212
export const OPENCODE_DISABLE_AUTOUPDATE = truthy("OPENCODE_DISABLE_AUTOUPDATE")
1313
export const OPENCODE_DISABLE_PRUNE = truthy("OPENCODE_DISABLE_PRUNE")
1414
export const OPENCODE_DISABLE_TERMINAL_TITLE = truthy("OPENCODE_DISABLE_TERMINAL_TITLE")
@@ -91,3 +91,14 @@ Object.defineProperty(Flag, "OPENCODE_CLIENT", {
9191
enumerable: true,
9292
configurable: false,
9393
})
94+
95+
// Dynamic getter for OPENCODE_CONFIG_CONTENT
96+
// This must be evaluated at access time, not module load time,
97+
// because external tooling may set this env var at runtime
98+
Object.defineProperty(Flag, "OPENCODE_CONFIG_CONTENT", {
99+
get() {
100+
return process.env["OPENCODE_CONFIG_CONTENT"]
101+
},
102+
enumerable: true,
103+
configurable: false,
104+
})

packages/opencode/test/config/config.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,3 +1800,66 @@ describe("OPENCODE_DISABLE_PROJECT_CONFIG", () => {
18001800
}
18011801
})
18021802
})
1803+
1804+
describe("OPENCODE_CONFIG_CONTENT token substitution", () => {
1805+
test("substitutes {env:} tokens in OPENCODE_CONFIG_CONTENT", async () => {
1806+
const originalEnv = process.env["OPENCODE_CONFIG_CONTENT"]
1807+
const originalTestVar = process.env["TEST_CONFIG_VAR"]
1808+
process.env["TEST_CONFIG_VAR"] = "test_api_key_12345"
1809+
process.env["OPENCODE_CONFIG_CONTENT"] = JSON.stringify({
1810+
$schema: "https://opencode.ai/config.json",
1811+
theme: "{env:TEST_CONFIG_VAR}",
1812+
})
1813+
1814+
try {
1815+
await using tmp = await tmpdir()
1816+
await Instance.provide({
1817+
directory: tmp.path,
1818+
fn: async () => {
1819+
const config = await Config.get()
1820+
expect(config.theme).toBe("test_api_key_12345")
1821+
},
1822+
})
1823+
} finally {
1824+
if (originalEnv !== undefined) {
1825+
process.env["OPENCODE_CONFIG_CONTENT"] = originalEnv
1826+
} else {
1827+
delete process.env["OPENCODE_CONFIG_CONTENT"]
1828+
}
1829+
if (originalTestVar !== undefined) {
1830+
process.env["TEST_CONFIG_VAR"] = originalTestVar
1831+
} else {
1832+
delete process.env["TEST_CONFIG_VAR"]
1833+
}
1834+
}
1835+
})
1836+
1837+
test("substitutes {file:} tokens in OPENCODE_CONFIG_CONTENT", async () => {
1838+
const originalEnv = process.env["OPENCODE_CONFIG_CONTENT"]
1839+
1840+
try {
1841+
await using tmp = await tmpdir({
1842+
init: async (dir) => {
1843+
await Bun.write(path.join(dir, "api_key.txt"), "secret_key_from_file")
1844+
process.env["OPENCODE_CONFIG_CONTENT"] = JSON.stringify({
1845+
$schema: "https://opencode.ai/config.json",
1846+
theme: "{file:./api_key.txt}",
1847+
})
1848+
},
1849+
})
1850+
await Instance.provide({
1851+
directory: tmp.path,
1852+
fn: async () => {
1853+
const config = await Config.get()
1854+
expect(config.theme).toBe("secret_key_from_file")
1855+
},
1856+
})
1857+
} finally {
1858+
if (originalEnv !== undefined) {
1859+
process.env["OPENCODE_CONFIG_CONTENT"] = originalEnv
1860+
} else {
1861+
delete process.env["OPENCODE_CONFIG_CONTENT"]
1862+
}
1863+
}
1864+
})
1865+
})

0 commit comments

Comments
 (0)