codex: fix CI failure on PR #122

This commit is contained in:
Winston Howes
2026-08-13 15:19:36 -04:00
committed by William Woodruff
parent 284765110d
commit 55a97c67e7
2 changed files with 18 additions and 3 deletions
+1 -1
View File
@@ -58,7 +58,7 @@ If you have effectively opened up your use of `openai/codex-action` to the world
## Protecting your `OPENAI_API_KEY`
No doubt your `OPENAI_API_KEY` is an important secret that you do not want to share with the world. Use either `drop-sudo` or `unprivileged-user` for Codex launched by the action. Direct Codex commands in later steps do not pass through the action's reduced Linux process identity.
No doubt your `OPENAI_API_KEY` is an important secret that you do not want to share with the world. **Be sure to use either `drop-sudo` or `unprivileged-user` to ensure it stays secret!** On Linux, the reduced process identity applies to Codex launched by the action; direct Codex commands in later steps do not pass through it.
To underscore the importance of specifying either `drop-sudo` or `unprivileged-user` as the `safety-strategy` for `openai/codex-action`, we provide [an example](../examples/test-sandbox-protections.yml) of how **the combination of read-only access to the filesystem and `sudo` can be used to expose your `OPENAI_API_KEY`**. This often surprises developers, as many expect the combination of "read-only access" and no network to be a sufficient safeguard, but this is not the case in the presence of passwordless `sudo` (which is the default on GitHub-hosted runners). Notably, Linux's [procfs](https://en.wikipedia.org/wiki/Procfs) makes a considerable amount of information available via file-read operations to a user with appropriate privileges.
+17 -2
View File
@@ -1,6 +1,7 @@
import assert from "node:assert/strict";
import {
chmodSync,
copyFileSync,
existsSync,
mkdirSync,
mkdtempSync,
@@ -50,6 +51,7 @@ function spawnCodexAs({
user,
home,
binDir,
actionPath,
workspace,
outputPath,
prompt,
@@ -72,7 +74,7 @@ function spawnCodexAs({
`PATH=${binDir}:${process.env.PATH ?? ""}`,
...Object.entries(extraEnv).map(([key, value]) => `${key}=${value}`),
process.execPath,
mainPath,
actionPath,
"run-codex-exec",
"--prompt", prompt,
"--prompt-file", "",
@@ -141,6 +143,7 @@ test(
const tempDir = mkdtempSync(path.join(tmpdir(), "codex-drop-sudo-"));
const home = path.join(tempDir, "home");
const binDir = path.join(tempDir, "bin");
const actionPath = path.join(tempDir, "main.js");
const workspace = path.join(tempDir, "workspace");
const capturePath = path.join(tempDir, "capture.json");
const outputPath = path.join(tempDir, "output.md");
@@ -149,6 +152,7 @@ test(
const sudoersPath = `/etc/sudoers.d/${user}`;
mkdirSync(binDir);
mkdirSync(workspace);
copyFileSync(mainPath, actionPath);
registerCleanup(t, {
user,
@@ -183,13 +187,19 @@ test(
sudoersPath,
]);
const launcher = path.join(binDir, "codex");
const fakeCodexCopyPath = path.join(
binDir,
"fakeCodexLinuxIdentity.mjs"
);
copyFileSync(fakeCodexPath, fakeCodexCopyPath);
writeFileSync(
launcher,
`#!/bin/sh\nexec "${process.execPath}" "${fakeCodexPath}" "$@"\n`
`#!/bin/sh\nexec "${process.execPath}" "${fakeCodexCopyPath}" "$@"\n`
);
chmodSync(launcher, 0o755);
writeFileSync(groupFile, "group-only\n");
runSudo(["/usr/bin/chown", "-R", `${user}:${primaryGroup}`, tempDir]);
runSudo(["/usr/bin/chmod", "0711", tempDir]);
runSudo(["/usr/bin/chown", `root:${supplementaryGroup}`, groupFile]);
runSudo(["/usr/bin/chmod", "0640", groupFile]);
@@ -216,6 +226,7 @@ test(
user,
home,
binDir,
actionPath,
workspace,
outputPath,
prompt,
@@ -275,6 +286,7 @@ test(
const tempDir = mkdtempSync(path.join(tmpdir(), "codex-drop-sudo-fail-"));
const home = path.join(tempDir, "home");
const binDir = path.join(tempDir, "bin");
const actionPath = path.join(tempDir, "main.js");
const workspace = path.join(tempDir, "workspace");
const outputPath = path.join(tempDir, "output.md");
const startedPath = path.join(tempDir, "codex-started");
@@ -282,6 +294,7 @@ test(
const sudoersPath = `/etc/sudoers.d/${user}`;
mkdirSync(binDir);
mkdirSync(workspace);
copyFileSync(mainPath, actionPath);
registerCleanup(t, {
user,
groups: [sudoGroup, primaryGroup],
@@ -317,6 +330,7 @@ test(
writeFileSync(launcher, `#!/bin/sh\n: > "$CODEX_STARTED"\n`);
chmodSync(launcher, 0o755);
runSudo(["/usr/bin/chown", "-R", `${user}:${primaryGroup}`, tempDir]);
runSudo(["/usr/bin/chmod", "0711", tempDir]);
const uid = run("/usr/bin/id", ["-u", user]).stdout.trim();
const gid = run("/usr/bin/id", ["-g", user]).stdout.trim();
@@ -330,6 +344,7 @@ test(
user,
home,
binDir,
actionPath,
workspace,
outputPath,
prompt: "must remain gated",