Skip to content

Commit 775ae5f

Browse files
committed
apply review comments
1 parent 68b947c commit 775ae5f

File tree

7 files changed

+56
-18
lines changed

7 files changed

+56
-18
lines changed

bear/src/args.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,18 @@ impl TryFrom<&ArgMatches> for BuildCommand {
112112
type Error = ParseError;
113113

114114
fn try_from(matches: &ArgMatches) -> Result<Self, Self::Error> {
115-
let arguments = matches
115+
let arguments: Vec<_> = matches
116116
.get_many("COMMAND")
117117
.ok_or(ParseError::MissingBuildCommand)?
118118
.cloned()
119119
.collect();
120-
Ok(BuildCommand { arguments })
120+
121+
// TODO: write test to validate we need this check.
122+
if arguments.is_empty() {
123+
Err(ParseError::MissingBuildCommand)
124+
} else {
125+
Ok(BuildCommand { arguments })
126+
}
121127
}
122128
}
123129

bear/src/intercept/environment.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,15 @@ impl BuildEnvironment {
212212
///
213213
/// Panics if the build command has no arguments (empty arguments vector).
214214
fn as_command(&self, val: BuildCommand) -> std::process::Command {
215-
let mut command = std::process::Command::new(val.arguments.first().unwrap());
216-
command.args(val.arguments.iter().skip(1));
215+
let mut command = match val.arguments.as_slice() {
216+
[] => panic!("BuildCommand arguments cannot be empty"),
217+
[executable] => std::process::Command::new(executable),
218+
[executable, arguments @ ..] => {
219+
let mut cmd = std::process::Command::new(executable);
220+
cmd.args(arguments);
221+
cmd
222+
}
223+
};
217224
command.envs(self.environment.clone());
218225
command
219226
}

bear/src/intercept/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ use thiserror::Error;
2626
/// It does not contain information about the outcome of the execution,
2727
/// like the exit code or the duration of the execution. It only contains
2828
/// the information that is necessary to reproduce the execution.
29+
///
30+
/// # Fields
31+
/// - `executable`: The path to the executable that was run.
32+
/// - `arguments`: The command line arguments that were passed to the executable.
33+
/// Includes the executable itself as the first argument.
34+
/// - `working_dir`: The current working directory of the process.
35+
/// - `environment`: The environment variables that were set for the process.
2936
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3037
pub struct Execution {
3138
pub executable: PathBuf,
@@ -39,6 +46,10 @@ impl Execution {
3946
///
4047
/// This method retrieves the executable path, command-line arguments,
4148
/// current working directory, and environment variables of the process.
49+
///
50+
/// **Security Note**: This method captures ALL environment variables from
51+
/// the current process, which may include sensitive information. Consider
52+
/// using the `trim()` method to filter to only relevant environment variables.
4253
pub fn capture() -> Result<Self, CaptureError> {
4354
let executable = std::env::current_exe().map_err(CaptureError::CurrentExecutable)?;
4455
let arguments = std::env::args().collect();

bear/src/intercept/reporter.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,20 +60,26 @@ impl ReporterFactory {
6060
/// Creates a new reporter and returns it as an atomic pointer.
6161
///
6262
/// This is useful for static/global usage where a stable pointer is required
63-
/// for the program's lifetime. Caller is responsible for managing the memory.
63+
/// for the program's lifetime.
6464
///
65-
/// Logs errors if reporter creation fails and returns a null pointer in that case.
66-
/// Caller is responsible to check for null pointer before using it.
65+
/// # Safety
66+
///
67+
/// The caller is responsible for ensuring the returned pointer is not used after
68+
/// the program terminates. The memory will be leaked intentionally to provide a
69+
/// stable pointer for the lifetime of the program.
70+
///
71+
/// Returns a null pointer if reporter creation fails. Caller must check for null
72+
/// before dereferencing.
6773
pub fn create_as_ptr() -> AtomicPtr<tcp::ReporterOnTcp> {
6874
match Self::create() {
6975
Ok(reporter) => {
7076
log::debug!("Reporter created successfully");
7177

7278
// Leak the reporter to get a stable pointer for the lifetime of the program
7379
let boxed_reporter = Box::new(reporter);
74-
let prt = Box::into_raw(boxed_reporter);
80+
let ptr = Box::into_raw(boxed_reporter);
7581

76-
AtomicPtr::new(prt)
82+
AtomicPtr::new(ptr)
7783
}
7884
Err(err) => {
7985
log::error!("Failed to create reporter: {err}");

bear/src/intercept/supervise.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,16 @@ pub fn supervise_execution(execution: Execution) -> Result<ExitStatus, Supervise
5454

5555
impl From<Execution> for std::process::Command {
5656
fn from(val: Execution) -> Self {
57-
let mut command = std::process::Command::new(val.executable);
58-
command.args(val.arguments.iter().skip(1));
57+
let mut command = match val.arguments.as_slice() {
58+
[] => panic!("Execution arguments cannot be empty"),
59+
[_] => std::process::Command::new(val.executable),
60+
[_, arguments @ ..] => {
61+
let mut cmd = std::process::Command::new(val.executable);
62+
cmd.args(arguments);
63+
cmd
64+
}
65+
};
66+
5967
command.envs(val.environment);
6068
command.current_dir(val.working_dir);
6169
command

bear/src/intercept/tcp.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ use std::sync::Arc;
1111

1212
/// The serializer for events to transmit over the network.
1313
///
14-
/// The events are serialized using TLV (Type-Length-Value) format.
15-
/// The type is always 0, the length is a 4-byte big-endian integer,
16-
/// and the value is the JSON representation of the event.
14+
/// The events are serialized using LV (Length-Value) format.
15+
/// The length is a 4-byte big-endian integer, and the value is the JSON
16+
/// representation of the event.
1717
struct EventWireSerializer;
1818

1919
impl EventWireSerializer {
20-
/// Read an event from a reader using TLV format.
20+
/// Read an event from a reader using LV format.
2121
fn read(reader: &mut impl Read) -> Result<Event, ReporterError> {
2222
let mut length_bytes = [0; 4];
2323
reader.read_exact(&mut length_bytes)?;
@@ -30,7 +30,7 @@ impl EventWireSerializer {
3030
Ok(event)
3131
}
3232

33-
/// Write an event to a writer using TLV format.
33+
/// Write an event to a writer using LV format.
3434
fn write(writer: &mut impl Write, event: Event) -> Result<u32, ReporterError> {
3535
let serialized_event = serde_json::to_string(&event)?;
3636
let bytes = serialized_event.into_bytes();

bear/src/semantic/interpreters/combinators.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ mod test {
8787

8888
fn execution_fixture() -> Execution {
8989
Execution {
90-
executable: PathBuf::new(),
91-
arguments: vec![],
90+
executable: PathBuf::from("/usr/bin/ls"),
91+
arguments: vec!["ls".to_string()],
9292
working_dir: PathBuf::new(),
9393
environment: HashMap::new(),
9494
}

0 commit comments

Comments
 (0)