Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 55 additions & 14 deletions .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,13 @@ jobs:
- name: cargo shear
run: cargo shear

argument_comment_lint:
name: Argument comment lint
argument_comment_lint_package:
name: Argument comment lint package
runs-on: ubuntu-24.04
needs: changed
if: ${{ needs.changed.outputs.argument_comment_lint == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }}
if: ${{ needs.changed.outputs.argument_comment_lint_package == 'true' || github.event_name == 'push' }}
steps:
- uses: actions/checkout@v6
- name: Install Linux sandbox build dependencies
run: |
sudo DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends pkg-config libcap-dev
- uses: dtolnay/rust-toolchain@1.93.0
with:
toolchain: nightly-2025-09-18
Expand All @@ -120,14 +116,46 @@ jobs:
- name: Install cargo-dylint tooling
if: ${{ steps.cargo_dylint_cache.outputs.cache-hit != 'true' }}
run: cargo install --locked cargo-dylint dylint-link
- name: Check source wrapper syntax
run: bash -n tools/argument-comment-lint/run.sh
- name: Test argument comment lint package
if: ${{ needs.changed.outputs.argument_comment_lint_package == 'true' || github.event_name == 'push' }}
working-directory: tools/argument-comment-lint
run: cargo test
- name: Run argument comment lint on codex-rs

argument_comment_lint_prebuilt:
name: Argument comment lint - ${{ matrix.name }}
runs-on: ${{ matrix.runs_on || matrix.runner }}
needs: changed
if: ${{ needs.changed.outputs.argument_comment_lint == 'true' || needs.changed.outputs.workflows == 'true' || github.event_name == 'push' }}
strategy:
fail-fast: false
matrix:
include:
- name: Linux
runner: ubuntu-24.04
- name: macOS
runner: macos-15-xlarge
- name: Windows
runner: windows-x64
runs_on:
group: codex-runners
labels: codex-windows-x64
steps:
- uses: actions/checkout@v6
- name: Install Linux sandbox build dependencies
if: ${{ runner.os == 'Linux' }}
shell: bash
run: |
bash -n tools/argument-comment-lint/run.sh
./tools/argument-comment-lint/run.sh
sudo DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends pkg-config libcap-dev
- uses: dtolnay/rust-toolchain@1.93.0
with:
toolchain: nightly-2025-09-18
components: llvm-tools-preview, rustc-dev, rust-src
- uses: facebook/install-dotslash@v2
- name: Run argument comment lint on codex-rs
shell: bash
run: ./tools/argument-comment-lint/run-prebuilt-linter.sh

# --- CI to validate on different os/targets --------------------------------
lint_build:
Expand Down Expand Up @@ -708,14 +736,23 @@ jobs:
results:
name: CI results (required)
needs:
[changed, general, cargo_shear, argument_comment_lint, lint_build, tests]
[
changed,
general,
cargo_shear,
argument_comment_lint_package,
argument_comment_lint_prebuilt,
lint_build,
tests,
]
if: always()
runs-on: ubuntu-24.04
steps:
- name: Summarize
shell: bash
run: |
echo "arglint: ${{ needs.argument_comment_lint.result }}"
echo "argpkg : ${{ needs.argument_comment_lint_package.result }}"
echo "arglint: ${{ needs.argument_comment_lint_prebuilt.result }}"
echo "general: ${{ needs.general.result }}"
echo "shear : ${{ needs.cargo_shear.result }}"
echo "lint : ${{ needs.lint_build.result }}"
Expand All @@ -728,8 +765,12 @@ jobs:
exit 0
fi

if [[ '${{ needs.changed.outputs.argument_comment_lint_package }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then
[[ '${{ needs.argument_comment_lint_package.result }}' == 'success' ]] || { echo 'argument_comment_lint_package failed'; exit 1; }
fi

if [[ '${{ needs.changed.outputs.argument_comment_lint }}' == 'true' || '${{ needs.changed.outputs.workflows }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then
[[ '${{ needs.argument_comment_lint.result }}' == 'success' ]] || { echo 'argument_comment_lint failed'; exit 1; }
[[ '${{ needs.argument_comment_lint_prebuilt.result }}' == 'success' ]] || { echo 'argument_comment_lint_prebuilt failed'; exit 1; }
fi

if [[ '${{ needs.changed.outputs.codex }}' == 'true' || '${{ needs.changed.outputs.workflows }}' == 'true' || '${{ github.event_name }}' == 'push' ]]; then
Expand Down
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Run `just fmt` (in `codex-rs` directory) automatically after you have finished m

Before finalizing a large change to `codex-rs`, run `just fix -p <project>` (in `codex-rs` directory) to fix any linter issues in the code. Prefer scoping with `-p` to avoid slow workspace‑wide Clippy builds; only run `just fix` without `-p` if you changed shared crates. Do not re-run tests after running `fix` or `fmt`.

Also run `just argument-comment-lint` to ensure the codebase is clean of comment lint errors.

## TUI style conventions

See `codex-rs/tui/styles.md`.
Expand Down
10 changes: 5 additions & 5 deletions codex-rs/cli/src/debug_sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ async fn run_command_under_sandbox(
command_vec,
&cwd_clone,
env_map,
None,
/*timeout_ms*/ None,
config.permissions.windows_sandbox_private_desktop,
)
} else {
Expand All @@ -181,7 +181,7 @@ async fn run_command_under_sandbox(
command_vec,
&cwd_clone,
env_map,
None,
/*timeout_ms*/ None,
config.permissions.windows_sandbox_private_desktop,
)
}
Expand Down Expand Up @@ -251,15 +251,15 @@ async fn run_command_under_sandbox(
&config.permissions.file_system_sandbox_policy,
config.permissions.network_sandbox_policy,
sandbox_policy_cwd.as_path(),
false,
/*enforce_managed_network*/ false,
network.as_ref(),
None,
/*extensions*/ None,
);
let network_policy = config.permissions.network_sandbox_policy;
spawn_debug_sandbox_child(
PathBuf::from("/usr/bin/sandbox-exec"),
args,
None,
/*arg0*/ None,
cwd,
network_policy,
env,
Expand Down
2 changes: 1 addition & 1 deletion codex-rs/core/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ fn record_windows_sandbox_spawn_failure(
if let Some(metrics) = codex_otel::metrics::global() {
let _ = metrics.counter(
"codex.windows_sandbox.createprocessasuserw_failed",
1,
/*inc*/ 1,
&[
("error_code", error_code.as_str()),
("path_kind", path_kind),
Expand Down
10 changes: 7 additions & 3 deletions codex-rs/core/src/windows_sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ pub fn run_elevated_setup(
command_cwd,
env_map,
codex_home,
None,
None,
/*read_roots_override*/ None,
/*write_roots_override*/ None,
)
}

Expand Down Expand Up @@ -421,7 +421,11 @@ fn emit_windows_sandbox_setup_failure_metrics(
if let Some(message) = message_tag.as_deref() {
failure_tags.push(("message", message));
}
let _ = metrics.counter(elevated_setup_failure_metric_name(_err), 1, &failure_tags);
let _ = metrics.counter(
elevated_setup_failure_metric_name(_err),
/*inc*/ 1,
&failure_tags,
);
}
} else {
let _ = metrics.counter(
Expand Down
20 changes: 11 additions & 9 deletions codex-rs/tui/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2901,7 +2901,7 @@ impl App {
Ok(()) => {
session_telemetry.counter(
"codex.windows_sandbox.elevated_setup_success",
1,
/*inc*/ 1,
&[],
);
AppEvent::EnableWindowsSandboxForAgentMode {
Expand Down Expand Up @@ -2931,7 +2931,7 @@ impl App {
codex_core::windows_sandbox::elevated_setup_failure_metric_name(
&err,
),
1,
/*inc*/ 1,
&tags,
);
tracing::error!(
Expand Down Expand Up @@ -2972,7 +2972,7 @@ impl App {
) {
session_telemetry.counter(
"codex.windows_sandbox.legacy_setup_preflight_failed",
1,
/*inc*/ 1,
&[],
);
tracing::warn!(
Expand All @@ -2997,7 +2997,7 @@ impl App {
self.chat_widget
.add_to_history(history_cell::new_info_event(
format!("Granting sandbox read access to {path} ..."),
None,
/*hint*/ None,
));

let policy = self.config.permissions.sandbox_policy.get().clone();
Expand Down Expand Up @@ -3072,11 +3072,13 @@ impl App {
match builder.apply().await {
Ok(()) => {
if elevated_enabled {
self.config.set_windows_sandbox_enabled(false);
self.config.set_windows_elevated_sandbox_enabled(true);
self.config.set_windows_sandbox_enabled(/*value*/ false);
self.config
.set_windows_elevated_sandbox_enabled(/*value*/ true);
} else {
self.config.set_windows_sandbox_enabled(true);
self.config.set_windows_elevated_sandbox_enabled(false);
self.config.set_windows_sandbox_enabled(/*value*/ true);
self.config
.set_windows_elevated_sandbox_enabled(/*value*/ false);
}
self.chat_widget.set_windows_sandbox_mode(
self.config.permissions.windows_sandbox_mode,
Expand Down Expand Up @@ -6454,7 +6456,7 @@ guardian_approval = true
make_header(true),
Arc::new(crate::history_cell::new_info_event(
"startup tip that used to replay".to_string(),
None,
/*hint*/ None,
)) as Arc<dyn HistoryCell>,
user_cell("Tell me a long story about a town with a dark lighthouse."),
agent_cell(story_part_one),
Expand Down
53 changes: 41 additions & 12 deletions codex-rs/tui/src/chatwidget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4536,7 +4536,7 @@ impl ChatWidget {

self.session_telemetry.counter(
"codex.windows_sandbox.setup_elevated_sandbox_command",
1,
/*inc*/ 1,
&[],
);
self.app_event_tx
Expand Down Expand Up @@ -7525,8 +7525,11 @@ impl ChatWidget {
return;
}

self.session_telemetry
.counter("codex.windows_sandbox.elevated_prompt_shown", 1, &[]);
self.session_telemetry.counter(
"codex.windows_sandbox.elevated_prompt_shown",
/*inc*/ 1,
&[],
);

let mut header = ColumnRenderable::new();
header.push(*Box::new(
Expand All @@ -7545,7 +7548,11 @@ impl ChatWidget {
name: "Set up default sandbox (requires Administrator permissions)".to_string(),
description: None,
actions: vec![Box::new(move |tx| {
accept_otel.counter("codex.windows_sandbox.elevated_prompt_accept", 1, &[]);
accept_otel.counter(
"codex.windows_sandbox.elevated_prompt_accept",
/*inc*/ 1,
&[],
);
tx.send(AppEvent::BeginWindowsSandboxElevatedSetup {
preset: preset.clone(),
});
Expand All @@ -7557,7 +7564,11 @@ impl ChatWidget {
name: "Use non-admin sandbox (higher risk if prompt injected)".to_string(),
description: None,
actions: vec![Box::new(move |tx| {
legacy_otel.counter("codex.windows_sandbox.elevated_prompt_use_legacy", 1, &[]);
legacy_otel.counter(
"codex.windows_sandbox.elevated_prompt_use_legacy",
/*inc*/ 1,
&[],
);
tx.send(AppEvent::BeginWindowsSandboxLegacySetup {
preset: legacy_preset.clone(),
});
Expand All @@ -7569,7 +7580,11 @@ impl ChatWidget {
name: "Quit".to_string(),
description: None,
actions: vec![Box::new(move |tx| {
quit_otel.counter("codex.windows_sandbox.elevated_prompt_quit", 1, &[]);
quit_otel.counter(
"codex.windows_sandbox.elevated_prompt_quit",
/*inc*/ 1,
&[],
);
tx.send(AppEvent::Exit(ExitMode::ShutdownFirst));
})],
dismiss_on_select: true,
Expand Down Expand Up @@ -7619,7 +7634,11 @@ impl ChatWidget {
let otel = self.session_telemetry.clone();
let preset = elevated_preset;
move |tx| {
otel.counter("codex.windows_sandbox.fallback_retry_elevated", 1, &[]);
otel.counter(
"codex.windows_sandbox.fallback_retry_elevated",
/*inc*/ 1,
&[],
);
tx.send(AppEvent::BeginWindowsSandboxElevatedSetup {
preset: preset.clone(),
});
Expand All @@ -7635,7 +7654,11 @@ impl ChatWidget {
let otel = self.session_telemetry.clone();
let preset = legacy_preset;
move |tx| {
otel.counter("codex.windows_sandbox.fallback_use_legacy", 1, &[]);
otel.counter(
"codex.windows_sandbox.fallback_use_legacy",
/*inc*/ 1,
&[],
);
tx.send(AppEvent::BeginWindowsSandboxLegacySetup {
preset: preset.clone(),
});
Expand All @@ -7648,7 +7671,11 @@ impl ChatWidget {
name: "Quit".to_string(),
description: None,
actions: vec![Box::new(move |tx| {
quit_otel.counter("codex.windows_sandbox.fallback_prompt_quit", 1, &[]);
quit_otel.counter(
"codex.windows_sandbox.fallback_prompt_quit",
/*inc*/ 1,
&[],
);
tx.send(AppEvent::Exit(ExitMode::ShutdownFirst));
})],
dismiss_on_select: true,
Expand Down Expand Up @@ -7688,11 +7715,12 @@ impl ChatWidget {
// While elevated sandbox setup runs, prevent typing so the user doesn't
// accidentally queue messages that will run under an unexpected mode.
self.bottom_pane.set_composer_input_enabled(
false,
/*enabled*/ false,
Some("Input disabled until setup completes.".to_string()),
);
self.bottom_pane.ensure_status_indicator();
self.bottom_pane.set_interrupt_hint_visible(false);
self.bottom_pane
.set_interrupt_hint_visible(/*visible*/ false);
self.set_status(
"Setting up sandbox...".to_string(),
Some("Hang tight, this may take a few minutes".to_string()),
Expand All @@ -7708,7 +7736,8 @@ impl ChatWidget {

#[cfg(target_os = "windows")]
pub(crate) fn clear_windows_sandbox_setup_status(&mut self) {
self.bottom_pane.set_composer_input_enabled(true, None);
self.bottom_pane
.set_composer_input_enabled(/*enabled*/ true, /*placeholder*/ None);
self.bottom_pane.hide_status_indicator();
self.request_redraw();
}
Expand Down
6 changes: 4 additions & 2 deletions codex-rs/tui/src/chatwidget/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,8 +979,10 @@ async fn enter_with_only_remote_images_does_not_submit_when_input_disabled() {

let remote_url = "https://example.com/remote-only.png".to_string();
chat.set_remote_image_urls(vec![remote_url.clone()]);
chat.bottom_pane
.set_composer_input_enabled(false, Some("Input disabled for test.".to_string()));
chat.bottom_pane.set_composer_input_enabled(
/*enabled*/ false,
Some("Input disabled for test.".to_string()),
);

chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE));

Expand Down
Loading
Loading