Skip to content

Commit 622fcb1

Browse files
authored
fix: classify ALB events as load_balancer, not API Gateway (#63)
1 parent 537b00c commit 622fcb1

1 file changed

Lines changed: 101 additions & 0 deletions

File tree

src/otlp/trigger_chain.rs

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ pub fn extract_trigger_chain_from_json(json_val: &serde_json::Value) -> TriggerC
9292
return extract_kafka_chain(&json_val);
9393
}
9494

95+
// ALB / ELB: target-group events also carry "requestContext", but with an
96+
// "elb" sub-key. Must be checked before the API Gateway branch, which keys
97+
// off "requestContext" alone and would otherwise misclassify ALB as API GW.
98+
if let Some(elb) = json_val
99+
.get("requestContext")
100+
.and_then(|rc| rc.get("elb"))
101+
.filter(|elb| elb.is_object())
102+
{
103+
return extract_alb_chain(elb);
104+
}
105+
95106
// API Gateway: has "requestContext"
96107
if json_val.get("requestContext").is_some() {
97108
return extract_api_gateway_chain(&json_val);
@@ -412,6 +423,45 @@ fn extract_kafka_chain(json_val: &serde_json::Value) -> TriggerChainResult {
412423
}
413424
}
414425

426+
// ── ALB / ELB ─────────────────────────────────────────────────────────
427+
428+
/// Extracts the target group name from an ALB target-group ARN.
429+
///
430+
/// `arn:aws:elasticloadbalancing:us-east-2:123:targetgroup/my-tg/abc123` -> `my-tg`
431+
///
432+
/// `extract_name_from_arn` would return the trailing random id, so target groups
433+
/// need their own parse: the name is the segment after `targetgroup/`.
434+
fn extract_target_group_name(arn: &str) -> Option<String> {
435+
let parts: Vec<&str> = arn.splitn(6, ':').collect();
436+
if parts.len() < 6 {
437+
return None;
438+
}
439+
let segments: Vec<&str> = parts[5].split('/').collect();
440+
if segments.len() >= 2 && segments[0] == "targetgroup" {
441+
Some(segments[1].to_string())
442+
} else {
443+
None
444+
}
445+
}
446+
447+
fn extract_alb_chain(elb: &serde_json::Value) -> TriggerChainResult {
448+
let arn = elb
449+
.get("targetGroupArn")
450+
.and_then(|v| v.as_str())
451+
.map(|s| s.to_string());
452+
let name = arn.as_deref().and_then(extract_target_group_name);
453+
454+
TriggerChainResult {
455+
hops: vec![TriggerHop {
456+
trigger_type: "aws:load_balancer".to_string(),
457+
arn,
458+
name,
459+
timestamp: None,
460+
}],
461+
truncated: false,
462+
}
463+
}
464+
415465
// ── API Gateway ──────────────────────────────────────────────────────
416466

417467
fn extract_api_gateway_chain(json_val: &serde_json::Value) -> TriggerChainResult {
@@ -810,6 +860,57 @@ mod tests {
810860
assert!(result.hops[0].arn.is_none());
811861
}
812862

863+
// ── ALB / ELB ─────────────────────────────────────────────────────
864+
865+
#[test]
866+
fn alb_event_classified_as_load_balancer() {
867+
let payload = r#"{
868+
"requestContext": {
869+
"elb": {
870+
"targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-target/abcdef0123456789"
871+
}
872+
},
873+
"httpMethod": "GET", "path": "/lambda",
874+
"headers": {"host": "my-alb-1234567890.us-east-2.elb.amazonaws.com"},
875+
"body": ""
876+
}"#;
877+
878+
let result = extract_trigger_chain(payload);
879+
assert_eq!(result.hops.len(), 1);
880+
assert_eq!(result.hops[0].trigger_type, "aws:load_balancer");
881+
assert_eq!(
882+
result.hops[0].arn.as_deref(),
883+
Some("arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/lambda-target/abcdef0123456789")
884+
);
885+
assert_eq!(result.hops[0].name.as_deref(), Some("lambda-target"));
886+
}
887+
888+
#[test]
889+
fn alb_event_not_misclassified_as_api_gateway() {
890+
let payload = r#"{
891+
"requestContext": {"elb": {"targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:123:targetgroup/tg/abc"}},
892+
"httpMethod": "POST", "path": "/orders"
893+
}"#;
894+
895+
let result = extract_trigger_chain(payload);
896+
assert_eq!(result.hops.len(), 1);
897+
assert_eq!(result.hops[0].trigger_type, "aws:load_balancer");
898+
}
899+
900+
#[test]
901+
fn alb_event_without_target_group_arn_still_load_balancer() {
902+
let payload = r#"{
903+
"requestContext": {"elb": {}},
904+
"httpMethod": "GET", "path": "/lambda"
905+
}"#;
906+
907+
let result = extract_trigger_chain(payload);
908+
assert_eq!(result.hops.len(), 1);
909+
assert_eq!(result.hops[0].trigger_type, "aws:load_balancer");
910+
assert!(result.hops[0].arn.is_none());
911+
assert!(result.hops[0].name.is_none());
912+
}
913+
813914
// ── Edge cases ───────────────────────────────────────────────────
814915

815916
#[test]

0 commit comments

Comments
 (0)