Skip to content

Commit 7e9390d

Browse files
authored
Merge branch 'main' into main
2 parents 4e0d785 + a4b51f6 commit 7e9390d

File tree

9 files changed

+317
-29
lines changed

9 files changed

+317
-29
lines changed

.github/workflows/ci.yml

+6
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ jobs:
6868
- name: Build
6969
run: pnpm run build
7070

71+
- name: Ensure staging a release works.
72+
working-directory: codex-cli
73+
env:
74+
GH_TOKEN: ${{ github.token }}
75+
run: pnpm stage-release
76+
7177
- name: Ensure README.md contains only ASCII and certain Unicode code points
7278
run: ./scripts/asciicheck.py README.md
7379
- name: Check README ToC

README.md

+21-11
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ corepack enable
308308
pnpm install
309309
pnpm build
310310
311+
# Linux-only: download prebuilt sandboxing binaries (requires gh and zstd).
312+
./scripts/install_native_deps.sh
313+
311314
# Get the usage and the options
312315
node ./dist/cli.js --help
313316
@@ -633,18 +636,25 @@ The **DCO check** blocks merges until every commit in the PR carries the footer
633636

634637
### Releasing `codex`
635638

636-
To publish a new version of the CLI, run the release scripts defined in `codex-cli/package.json`:
639+
To publish a new version of the CLI, run the following in the `codex-cli` folder to stage the release in a temporary directory:
637640

638-
1. Open the `codex-cli` directory
639-
2. Make sure you're on a branch like `git checkout -b bump-version`
640-
3. Bump the version and `CLI_VERSION` to current datetime: `pnpm release:version`
641-
4. Commit the version bump (with DCO sign-off):
642-
```bash
643-
git add codex-cli/package.json
644-
git commit -s -m "chore(release): codex-cli v$(node -p \"require('./codex-cli/package.json').version\")"
645-
```
646-
5. Copy README, build, and publish to npm: `pnpm release`
647-
6. Push to branch: `git push origin HEAD`
641+
```
642+
pnpm stage-release
643+
```
644+
645+
Note you can specify the folder for the staged release:
646+
647+
```
648+
RELEASE_DIR=$(mktemp -d)
649+
pnpm stage-release "$RELEASE_DIR"
650+
```
651+
652+
Go to the folder where the release is staged and verify that it works as intended. If so, run the following from the temp folder:
653+
654+
```
655+
cd "$RELEASE_DIR"
656+
npm publish
657+
```
648658

649659
### Alternative Build Options
650660

codex-cli/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Added by ./scripts/install_native_deps.sh
2+
/bin/codex-linux-sandbox-arm64
3+
/bin/codex-linux-sandbox-x64

codex-cli/package.json

+1-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@
2020
"typecheck": "tsc --noEmit",
2121
"build": "node build.mjs",
2222
"build:dev": "NODE_ENV=development node build.mjs --dev && NODE_OPTIONS=--enable-source-maps node dist/cli-dev.js",
23-
"release:readme": "cp ../README.md ./README.md",
24-
"release:version": "TS=$(date +%y%m%d%H%M) && sed -E -i'' -e \"s/\\\"0\\.1\\.[0-9]{10}\\\"/\\\"0.1.${TS}\\\"/g\" package.json",
25-
"release:build-and-publish": "pnpm run build && npm publish",
26-
"release": "pnpm run release:readme && pnpm run release:version && pnpm install && pnpm run release:build-and-publish"
23+
"stage-release": "./scripts/stage_release.sh"
2724
},
2825
"files": [
2926
"dist"
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/bin/bash
2+
3+
# Copy the Linux sandbox native binaries into the bin/ subfolder of codex-cli/.
4+
#
5+
# Usage:
6+
# ./scripts/install_native_deps.sh [CODEX_CLI_ROOT]
7+
#
8+
# Arguments
9+
# [CODEX_CLI_ROOT] – Optional. If supplied, it should be the codex-cli
10+
# folder that contains the package.json for @openai/codex.
11+
#
12+
# When no argument is given we assume the script is being run directly from a
13+
# development checkout. In that case we install the binaries into the
14+
# repository’s own `bin/` directory so that the CLI can run locally.
15+
16+
set -euo pipefail
17+
18+
# ----------------------------------------------------------------------------
19+
# Determine where the binaries should be installed.
20+
# ----------------------------------------------------------------------------
21+
22+
if [[ $# -gt 0 ]]; then
23+
# The caller supplied a release root directory.
24+
CODEX_CLI_ROOT="$1"
25+
BIN_DIR="$CODEX_CLI_ROOT/bin"
26+
else
27+
# No argument; fall back to the repo’s own bin directory.
28+
# Resolve the path of this script, then walk up to the repo root.
29+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
30+
CODEX_CLI_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
31+
BIN_DIR="$CODEX_CLI_ROOT/bin"
32+
fi
33+
34+
# Make sure the destination directory exists.
35+
mkdir -p "$BIN_DIR"
36+
37+
# ----------------------------------------------------------------------------
38+
# Download and decompress the artifacts from the GitHub Actions workflow.
39+
# ----------------------------------------------------------------------------
40+
41+
# Until we start publishing stable GitHub releases, we have to grab the binaries
42+
# from the GitHub Action that created them. Update the URL below to point to the
43+
# appropriate workflow run:
44+
WORKFLOW_URL="https://github.com/openai/codex/actions/runs/14763725716"
45+
WORKFLOW_ID="${WORKFLOW_URL##*/}"
46+
47+
ARTIFACTS_DIR="$(mktemp -d)"
48+
trap 'rm -rf "$ARTIFACTS_DIR"' EXIT
49+
50+
# NB: The GitHub CLI `gh` must be installed and authenticated.
51+
gh run download --dir "$ARTIFACTS_DIR" --repo openai/codex "$WORKFLOW_ID"
52+
53+
# Decompress the two target architectures.
54+
zstd -d "$ARTIFACTS_DIR/x86_64-unknown-linux-musl/codex-linux-sandbox-x86_64-unknown-linux-musl.zst" \
55+
-o "$BIN_DIR/codex-linux-sandbox-x64"
56+
57+
zstd -d "$ARTIFACTS_DIR/aarch64-unknown-linux-gnu/codex-linux-sandbox-aarch64-unknown-linux-gnu.zst" \
58+
-o "$BIN_DIR/codex-linux-sandbox-arm64"
59+
60+
echo "Installed native dependencies into $BIN_DIR"
61+

codex-cli/scripts/stage_release.sh

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
# Change to the codex-cli directory.
6+
cd "$(dirname "${BASH_SOURCE[0]}")/.."
7+
8+
# First argument is where to stage the release. Creates a temporary directory
9+
# if not provided.
10+
RELEASE_DIR="${1:-$(mktemp -d)}"
11+
[ -n "${1-}" ] && shift
12+
13+
# Compile the JavaScript.
14+
pnpm install
15+
pnpm build
16+
mkdir "$RELEASE_DIR/bin"
17+
cp -r bin/codex.js "$RELEASE_DIR/bin/codex.js"
18+
cp -r dist "$RELEASE_DIR/dist"
19+
cp -r src "$RELEASE_DIR/src" # important if we want sourcemaps to continue to work
20+
cp ../README.md "$RELEASE_DIR"
21+
# TODO: Derive version from Git tag.
22+
VERSION=$(printf '0.1.%d' "$(date +%y%m%d%H%M)")
23+
jq --arg version "$VERSION" '.version = $version' package.json > "$RELEASE_DIR/package.json"
24+
25+
# Copy the native dependencies.
26+
./scripts/install_native_deps.sh "$RELEASE_DIR"
27+
28+
echo "Staged version $VERSION for release in $RELEASE_DIR"

codex-cli/src/utils/agent/exec.ts

+19-14
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { ParseEntry } from "shell-quote";
44

55
import { process_patch } from "./apply-patch.js";
66
import { SandboxType } from "./sandbox/interface.js";
7+
import { execWithLandlock } from "./sandbox/landlock.js";
78
import { execWithSeatbelt } from "./sandbox/macos-seatbelt.js";
89
import { exec as rawExec } from "./sandbox/raw-exec.js";
910
import { formatCommandForDisplay } from "../../format-command.js";
@@ -42,26 +43,30 @@ export function exec(
4243
sandbox: SandboxType,
4344
abortSignal?: AbortSignal,
4445
): Promise<ExecResult> {
45-
// This is a temporary measure to understand what are the common base commands
46-
// until we start persisting and uploading rollouts
47-
4846
const opts: SpawnOptions = {
4947
timeout: timeoutInMillis || DEFAULT_TIMEOUT_MS,
5048
...(requiresShell(cmd) ? { shell: true } : {}),
5149
...(workdir ? { cwd: workdir } : {}),
5250
};
53-
// Merge default writable roots with any user-specified ones.
54-
const writableRoots = [
55-
process.cwd(),
56-
os.tmpdir(),
57-
...additionalWritableRoots,
58-
];
59-
if (sandbox === SandboxType.MACOS_SEATBELT) {
60-
return execWithSeatbelt(cmd, opts, writableRoots, abortSignal);
61-
}
6251

63-
// SandboxType.NONE (or any other) falls back to the raw exec implementation
64-
return rawExec(cmd, opts, abortSignal);
52+
switch (sandbox) {
53+
case SandboxType.NONE: {
54+
// SandboxType.NONE uses the raw exec implementation.
55+
return rawExec(cmd, opts, abortSignal);
56+
}
57+
case SandboxType.MACOS_SEATBELT: {
58+
// Merge default writable roots with any user-specified ones.
59+
const writableRoots = [
60+
process.cwd(),
61+
os.tmpdir(),
62+
...additionalWritableRoots,
63+
];
64+
return execWithSeatbelt(cmd, opts, writableRoots, abortSignal);
65+
}
66+
case SandboxType.LINUX_LANDLOCK: {
67+
return execWithLandlock(cmd, opts, additionalWritableRoots, abortSignal);
68+
}
69+
}
6570
}
6671

6772
export function execApplyPatch(

codex-cli/src/utils/agent/handle-exec-command.ts

+5
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,11 @@ async function getSandbox(runInSandbox: boolean): Promise<SandboxType> {
303303
"Sandbox was mandated, but 'sandbox-exec' was not found in PATH!",
304304
);
305305
}
306+
} else if (process.platform === "linux") {
307+
// TODO: Need to verify that the Landlock sandbox is working. For example,
308+
// using Landlock in a Linux Docker container from a macOS host may not
309+
// work.
310+
return SandboxType.LINUX_LANDLOCK;
306311
} else if (CODEX_UNSAFE_ALLOW_NO_SANDBOX) {
307312
// Allow running without a sandbox if the user has explicitly marked the
308313
// environment as already being sufficiently locked-down.

0 commit comments

Comments
 (0)