Skip to content

Commit fecbc4d

Browse files
Classify Jira API requests with url pattern matching
1 parent 33ab089 commit fecbc4d

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

crates/forge_analyzer/src/definitions.rs

+41-4
Original file line numberDiff line numberDiff line change
@@ -991,24 +991,61 @@ impl FunctionAnalyzer<'_> {
991991
*prop == *"get" || *prop == *"getSecret" || *prop == *"query"
992992
}
993993

994+
fn resolve_jira_api_type(url: &str) -> Option<IntrinsicName> {
995+
match url {
996+
url if url.starts_with("/rest/servicedeskapi/") => {
997+
Some(IntrinsicName::RequestJiraServiceManagement)
998+
}
999+
url if url.starts_with("/rest/agile/") => Some(IntrinsicName::RequestJiraSoftware),
1000+
// Accept Jira API v2.0 or v3.0
1001+
url if url.starts_with("/rest/api/3/") || url.starts_with("/rest/api/2/") => {
1002+
Some(IntrinsicName::RequestJira)
1003+
}
1004+
_ => {
1005+
warn!("Invalid Jira API URL format: {}", url);
1006+
None
1007+
}
1008+
}
1009+
}
1010+
9941011
match *callee {
9951012
[PropPath::Unknown((ref name, ..))] if *name == *"fetch" => Some(Intrinsic::Fetch),
9961013
[PropPath::Def(def), ref authn @ .., PropPath::Static(ref last)]
9971014
if (*last == *"requestJira"
9981015
|| *last == *"requestConfluence"
999-
|| *last == *"requestBitbucket") // TODO: resolve Jira API requests to the correct permission map, here JSM (and likely JS) is bundled inside Jira
1016+
|| *last == *"requestBitbucket")
10001017
&& Some(&ImportKind::Default)
10011018
== self.res.is_imported_from(def, "@forge/api") =>
10021019
{
1020+
let first_arg = first_arg?;
1021+
let is_as_app = authn.first() == Some(&PropPath::MemberCall("asApp".into()));
1022+
10031023
let function_name = if *last == "requestJira" {
1004-
IntrinsicName::RequestJira
1024+
// Resolve Jira API requests to either JSM/JS/Jira as all are bundled within requestJira()
1025+
match first_arg {
1026+
Expr::Tpl(template) => {
1027+
let url = template
1028+
.quasis
1029+
.iter()
1030+
.map(|quasi| quasi.raw.as_str())
1031+
.collect::<String>();
1032+
1033+
resolve_jira_api_type(&url).unwrap_or_else(|| {
1034+
warn!("Falling back to generic Jira request");
1035+
IntrinsicName::RequestJira // TODO: how should we handle this edge case?
1036+
})
1037+
}
1038+
_ => {
1039+
warn!("First parameter to requestJira() is invalid");
1040+
IntrinsicName::RequestJira // TODO: how should we handle this edge case?
1041+
}
1042+
}
10051043
} else if *last == "requestBitbucket" {
10061044
IntrinsicName::RequestBitbucket
10071045
} else {
10081046
IntrinsicName::RequestConfluence
10091047
};
1010-
let first_arg = first_arg?;
1011-
let is_as_app = authn.first() == Some(&PropPath::MemberCall("asApp".into()));
1048+
10121049
match classify_api_call(first_arg) {
10131050
ApiCallKind::Unknown => {
10141051
if is_as_app {

crates/forge_permission_resolver/src/permissions_resolver.rs

-6
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,6 @@ mod test {
395395
let request_type = RequestType::Get;
396396
let result = check_url_for_permissions(&permission_map, &regex_map, request_type, url);
397397

398-
println!("Permission Map: {:?}", permission_map);
399-
println!("Regex Map: {:?}", regex_map);
400-
401398
assert!(!result.is_empty(), "Should have parsed permissions");
402399
assert!(
403400
result.contains(&String::from("read:sprint:jira-software")),
@@ -412,9 +409,6 @@ mod test {
412409
let request_type = RequestType::Get;
413410
let result = check_url_for_permissions(&permission_map, &regex_map, request_type, url);
414411

415-
println!("Permission Map: {:?}", permission_map);
416-
println!("Regex Map: {:?}", regex_map);
417-
418412
assert!(!result.is_empty(), "Should have parsed permissions");
419413

420414
let expected_permission: Vec<String> = vec![

0 commit comments

Comments
 (0)