Skip to content
Merged
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
35 changes: 34 additions & 1 deletion crates/cli/src/commands/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ fn parse_event_list(values: &[String]) -> Vec<String> {
.flat_map(|value| value.split(','))
.map(str::trim)
.filter(|value| !value.is_empty())
.map(ToString::to_string)
.map(normalize_event_name)
.collect();

if events.is_empty() {
Expand All @@ -358,6 +358,17 @@ fn parse_event_list(values: &[String]) -> Vec<String> {
events
}

fn normalize_event_name(value: &str) -> String {
match value.to_ascii_lowercase().as_str() {
"put" => "s3:ObjectCreated:*".to_string(),
"get" => "s3:ObjectAccessed:*".to_string(),
"delete" => "s3:ObjectRemoved:*".to_string(),
"replica" => "s3:Replication:*".to_string(),
"ilm" => "s3:ObjectTransition:*".to_string(),
_ => value.to_string(),
Comment on lines +362 to +368
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalize_event_name allocates a new String for every event via to_ascii_lowercase(), even when the value is already a fully-qualified S3 event name. Consider using eq_ignore_ascii_case(...) checks (or matching on value with AsciiExt-style comparisons) to avoid the extra allocation in the hot path, especially when many events are provided.

Suggested change
match value.to_ascii_lowercase().as_str() {
"put" => "s3:ObjectCreated:*".to_string(),
"get" => "s3:ObjectAccessed:*".to_string(),
"delete" => "s3:ObjectRemoved:*".to_string(),
"replica" => "s3:Replication:*".to_string(),
"ilm" => "s3:ObjectTransition:*".to_string(),
_ => value.to_string(),
if value.eq_ignore_ascii_case("put") {
"s3:ObjectCreated:*".to_string()
} else if value.eq_ignore_ascii_case("get") {
"s3:ObjectAccessed:*".to_string()
} else if value.eq_ignore_ascii_case("delete") {
"s3:ObjectRemoved:*".to_string()
} else if value.eq_ignore_ascii_case("replica") {
"s3:Replication:*".to_string()
} else if value.eq_ignore_ascii_case("ilm") {
"s3:ObjectTransition:*".to_string()
} else {
value.to_string()

Copilot uses AI. Check for mistakes.
}
}

fn infer_target_from_arn(arn: &str) -> Result<NotificationTarget, String> {
if arn.contains(":sqs:") {
Ok(NotificationTarget::Queue)
Expand Down Expand Up @@ -441,6 +452,28 @@ mod tests {
);
}

#[test]
fn test_parse_event_list_normalizes_shorthand_names() {
let events = parse_event_list(&[
"put,get,delete".to_string(),
"replica".to_string(),
"ilm,s3:ObjectCreated:Post".to_string(),
"PUT".to_string(),
]);

assert_eq!(
events,
vec![
"s3:ObjectAccessed:*".to_string(),
"s3:ObjectCreated:*".to_string(),
"s3:ObjectCreated:Post".to_string(),
"s3:ObjectRemoved:*".to_string(),
"s3:ObjectTransition:*".to_string(),
"s3:Replication:*".to_string(),
]
);
}

#[test]
fn test_infer_target_from_arn() {
assert_eq!(
Expand Down
Loading