mirror of
https://github.com/openai/codex.git
synced 2026-11-05 08:28:29 +00:00
## Why Once the repo-local lint exists, `codex-rs` needs to follow the checked-in convention and CI needs to keep it from drifting. This commit applies the fallback `/*param*/` style consistently across existing positional literal call sites without changing those APIs. The longer-term preference is still to avoid APIs that require comments by choosing clearer parameter types and call shapes. This PR is intentionally the mechanical follow-through for the places where the existing signatures stay in place. After rebasing onto newer `main`, the rollout also had to cover newly introduced `tui_app_server` call sites. That made it clear the first cut of the CI job was too expensive for the common path: it was spending almost as much time installing `cargo-dylint` and re-testing the lint crate as a representative test job spends running product tests. The CI update keeps the full workspace enforcement but trims that extra overhead from ordinary `codex-rs` PRs. ## What changed - keep a dedicated `argument_comment_lint` job in `rust-ci` - mechanically annotate remaining opaque positional literals across `codex-rs` with exact `/*param*/` comments, including the rebased `tui_app_server` call sites that now fall under the lint - keep the checked-in style aligned with the lint policy by using `/*param*/` and leaving string and char literals uncommented - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo registry/git metadata in the lint job - split changed-path detection so the lint crate's own `cargo test` step runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes - continue to run the repo wrapper over the `codex-rs` workspace, so product-code enforcement is unchanged Most of the code changes in this commit are intentionally mechanical comment rewrites or insertions driven by the lint itself. ## Verification - `./tools/argument-comment-lint/run.sh --workspace` - `cargo test -p codex-tui-app-server -p codex-tui` - parsed `.github/workflows/rust-ci.yml` locally with PyYAML --- * -> #14652 * #14651
225 lines
7.1 KiB
Rust
225 lines
7.1 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use codex_core::config::set_project_trust_level;
|
|
use codex_core::git_info::resolve_root_git_project_for_trust;
|
|
use codex_protocol::config_types::TrustLevel;
|
|
use crossterm::event::KeyCode;
|
|
use crossterm::event::KeyEvent;
|
|
use crossterm::event::KeyEventKind;
|
|
use ratatui::buffer::Buffer;
|
|
use ratatui::layout::Rect;
|
|
use ratatui::style::Stylize;
|
|
use ratatui::text::Line;
|
|
use ratatui::widgets::Paragraph;
|
|
use ratatui::widgets::WidgetRef;
|
|
use ratatui::widgets::Wrap;
|
|
|
|
use crate::key_hint;
|
|
use crate::onboarding::onboarding_screen::KeyboardHandler;
|
|
use crate::onboarding::onboarding_screen::StepStateProvider;
|
|
use crate::render::Insets;
|
|
use crate::render::renderable::ColumnRenderable;
|
|
use crate::render::renderable::Renderable;
|
|
use crate::render::renderable::RenderableExt as _;
|
|
use crate::selection_list::selection_option_row;
|
|
|
|
use super::onboarding_screen::StepState;
|
|
pub(crate) struct TrustDirectoryWidget {
|
|
pub codex_home: PathBuf,
|
|
pub cwd: PathBuf,
|
|
pub show_windows_create_sandbox_hint: bool,
|
|
pub should_quit: bool,
|
|
pub selection: Option<TrustDirectorySelection>,
|
|
pub highlighted: TrustDirectorySelection,
|
|
pub error: Option<String>,
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
|
pub enum TrustDirectorySelection {
|
|
Trust,
|
|
Quit,
|
|
}
|
|
|
|
impl WidgetRef for &TrustDirectoryWidget {
|
|
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
|
|
let mut column = ColumnRenderable::new();
|
|
|
|
column.push(Line::from(vec![
|
|
"> ".into(),
|
|
"You are in ".bold(),
|
|
self.cwd.to_string_lossy().to_string().into(),
|
|
]));
|
|
column.push("");
|
|
|
|
column.push(
|
|
Paragraph::new(
|
|
"Do you trust the contents of this directory? Working with untrusted contents comes with higher risk of prompt injection.".to_string(),
|
|
)
|
|
.wrap(Wrap { trim: true })
|
|
.inset(Insets::tlbr(/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0)),
|
|
);
|
|
column.push("");
|
|
|
|
let options: Vec<(&str, TrustDirectorySelection)> = vec![
|
|
("Yes, continue", TrustDirectorySelection::Trust),
|
|
("No, quit", TrustDirectorySelection::Quit),
|
|
];
|
|
|
|
for (idx, (text, selection)) in options.iter().enumerate() {
|
|
column.push(selection_option_row(
|
|
idx,
|
|
text.to_string(),
|
|
self.highlighted == *selection,
|
|
));
|
|
}
|
|
|
|
column.push("");
|
|
|
|
if let Some(error) = &self.error {
|
|
column.push(
|
|
Paragraph::new(error.to_string())
|
|
.red()
|
|
.wrap(Wrap { trim: true })
|
|
.inset(Insets::tlbr(
|
|
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
|
|
)),
|
|
);
|
|
column.push("");
|
|
}
|
|
|
|
column.push(
|
|
Line::from(vec![
|
|
"Press ".dim(),
|
|
key_hint::plain(KeyCode::Enter).into(),
|
|
if self.show_windows_create_sandbox_hint {
|
|
" to continue and create a sandbox...".dim()
|
|
} else {
|
|
" to continue".dim()
|
|
},
|
|
])
|
|
.inset(Insets::tlbr(
|
|
/*top*/ 0, /*left*/ 2, /*bottom*/ 0, /*right*/ 0,
|
|
)),
|
|
);
|
|
|
|
column.render(area, buf);
|
|
}
|
|
}
|
|
|
|
impl KeyboardHandler for TrustDirectoryWidget {
|
|
fn handle_key_event(&mut self, key_event: KeyEvent) {
|
|
if key_event.kind == KeyEventKind::Release {
|
|
return;
|
|
}
|
|
|
|
match key_event.code {
|
|
KeyCode::Up | KeyCode::Char('k') => {
|
|
self.highlighted = TrustDirectorySelection::Trust;
|
|
}
|
|
KeyCode::Down | KeyCode::Char('j') => {
|
|
self.highlighted = TrustDirectorySelection::Quit;
|
|
}
|
|
KeyCode::Char('1') | KeyCode::Char('y') => self.handle_trust(),
|
|
KeyCode::Char('2') | KeyCode::Char('n') => self.handle_quit(),
|
|
KeyCode::Enter => match self.highlighted {
|
|
TrustDirectorySelection::Trust => self.handle_trust(),
|
|
TrustDirectorySelection::Quit => self.handle_quit(),
|
|
},
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl StepStateProvider for TrustDirectoryWidget {
|
|
fn get_step_state(&self) -> StepState {
|
|
if self.selection.is_some() || self.should_quit {
|
|
StepState::Complete
|
|
} else {
|
|
StepState::InProgress
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TrustDirectoryWidget {
|
|
fn handle_trust(&mut self) {
|
|
let target =
|
|
resolve_root_git_project_for_trust(&self.cwd).unwrap_or_else(|| self.cwd.clone());
|
|
if let Err(e) = set_project_trust_level(&self.codex_home, &target, TrustLevel::Trusted) {
|
|
tracing::error!("Failed to set project trusted: {e:?}");
|
|
self.error = Some(format!("Failed to set trust for {}: {e}", target.display()));
|
|
}
|
|
|
|
self.selection = Some(TrustDirectorySelection::Trust);
|
|
}
|
|
|
|
fn handle_quit(&mut self) {
|
|
self.highlighted = TrustDirectorySelection::Quit;
|
|
self.should_quit = true;
|
|
}
|
|
|
|
pub fn should_quit(&self) -> bool {
|
|
self.should_quit
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::test_backend::VT100Backend;
|
|
|
|
use super::*;
|
|
use crossterm::event::KeyCode;
|
|
use crossterm::event::KeyEvent;
|
|
use crossterm::event::KeyEventKind;
|
|
use crossterm::event::KeyModifiers;
|
|
use pretty_assertions::assert_eq;
|
|
use ratatui::Terminal;
|
|
use std::path::PathBuf;
|
|
use tempfile::TempDir;
|
|
|
|
#[test]
|
|
fn release_event_does_not_change_selection() {
|
|
let codex_home = TempDir::new().expect("temp home");
|
|
let mut widget = TrustDirectoryWidget {
|
|
codex_home: codex_home.path().to_path_buf(),
|
|
cwd: PathBuf::from("."),
|
|
show_windows_create_sandbox_hint: false,
|
|
should_quit: false,
|
|
selection: None,
|
|
highlighted: TrustDirectorySelection::Quit,
|
|
error: None,
|
|
};
|
|
|
|
let release = KeyEvent {
|
|
kind: KeyEventKind::Release,
|
|
..KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)
|
|
};
|
|
widget.handle_key_event(release);
|
|
assert_eq!(widget.selection, None);
|
|
|
|
let press = KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE);
|
|
widget.handle_key_event(press);
|
|
assert!(widget.should_quit);
|
|
}
|
|
|
|
#[test]
|
|
fn renders_snapshot_for_git_repo() {
|
|
let codex_home = TempDir::new().expect("temp home");
|
|
let widget = TrustDirectoryWidget {
|
|
codex_home: codex_home.path().to_path_buf(),
|
|
cwd: PathBuf::from("/workspace/project"),
|
|
show_windows_create_sandbox_hint: false,
|
|
should_quit: false,
|
|
selection: None,
|
|
highlighted: TrustDirectorySelection::Trust,
|
|
error: None,
|
|
};
|
|
|
|
let mut terminal = Terminal::new(VT100Backend::new(70, 14)).expect("terminal");
|
|
terminal
|
|
.draw(|f| (&widget).render_ref(f.area(), f.buffer_mut()))
|
|
.expect("draw");
|
|
|
|
insta::assert_snapshot!(terminal.backend());
|
|
}
|
|
}
|