Skip to content

Commit

Permalink
Classify Jira API requests with url pattern matching
Browse files Browse the repository at this point in the history
  • Loading branch information
dxu2atlassian committed Jan 3, 2025
1 parent 33ab089 commit fecbc4d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 10 deletions.
45 changes: 41 additions & 4 deletions crates/forge_analyzer/src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -991,24 +991,61 @@ impl FunctionAnalyzer<'_> {
*prop == *"get" || *prop == *"getSecret" || *prop == *"query"
}

fn resolve_jira_api_type(url: &str) -> Option<IntrinsicName> {
match url {
url if url.starts_with("/rest/servicedeskapi/") => {
Some(IntrinsicName::RequestJiraServiceManagement)
}
url if url.starts_with("/rest/agile/") => Some(IntrinsicName::RequestJiraSoftware),
// Accept Jira API v2.0 or v3.0
url if url.starts_with("/rest/api/3/") || url.starts_with("/rest/api/2/") => {
Some(IntrinsicName::RequestJira)
}
_ => {
warn!("Invalid Jira API URL format: {}", url);
None
}
}
}

match *callee {
[PropPath::Unknown((ref name, ..))] if *name == *"fetch" => Some(Intrinsic::Fetch),
[PropPath::Def(def), ref authn @ .., PropPath::Static(ref last)]
if (*last == *"requestJira"
|| *last == *"requestConfluence"
|| *last == *"requestBitbucket") // TODO: resolve Jira API requests to the correct permission map, here JSM (and likely JS) is bundled inside Jira
|| *last == *"requestBitbucket")
&& Some(&ImportKind::Default)
== self.res.is_imported_from(def, "@forge/api") =>
{
let first_arg = first_arg?;
let is_as_app = authn.first() == Some(&PropPath::MemberCall("asApp".into()));

let function_name = if *last == "requestJira" {
IntrinsicName::RequestJira
// Resolve Jira API requests to either JSM/JS/Jira as all are bundled within requestJira()
match first_arg {
Expr::Tpl(template) => {
let url = template
.quasis
.iter()
.map(|quasi| quasi.raw.as_str())
.collect::<String>();

resolve_jira_api_type(&url).unwrap_or_else(|| {
warn!("Falling back to generic Jira request");
IntrinsicName::RequestJira // TODO: how should we handle this edge case?
})
}
_ => {
warn!("First parameter to requestJira() is invalid");
IntrinsicName::RequestJira // TODO: how should we handle this edge case?
}
}
} else if *last == "requestBitbucket" {
IntrinsicName::RequestBitbucket
} else {
IntrinsicName::RequestConfluence
};
let first_arg = first_arg?;
let is_as_app = authn.first() == Some(&PropPath::MemberCall("asApp".into()));

match classify_api_call(first_arg) {
ApiCallKind::Unknown => {
if is_as_app {
Expand Down
6 changes: 0 additions & 6 deletions crates/forge_permission_resolver/src/permissions_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,9 +395,6 @@ mod test {
let request_type = RequestType::Get;
let result = check_url_for_permissions(&permission_map, &regex_map, request_type, url);

println!("Permission Map: {:?}", permission_map);
println!("Regex Map: {:?}", regex_map);

assert!(!result.is_empty(), "Should have parsed permissions");
assert!(
result.contains(&String::from("read:sprint:jira-software")),
Expand All @@ -412,9 +409,6 @@ mod test {
let request_type = RequestType::Get;
let result = check_url_for_permissions(&permission_map, &regex_map, request_type, url);

println!("Permission Map: {:?}", permission_map);
println!("Regex Map: {:?}", regex_map);

assert!(!result.is_empty(), "Should have parsed permissions");

let expected_permission: Vec<String> = vec![
Expand Down

0 comments on commit fecbc4d

Please sign in to comment.