codex: fix CI failure on PR #122
This commit is contained in:
+1
-1
@@ -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.
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user