diff --git a/crates/forge_analyzer/src/checkers.rs b/crates/forge_analyzer/src/checkers.rs index abb896a..185b9bd 100644 --- a/crates/forge_analyzer/src/checkers.rs +++ b/crates/forge_analyzer/src/checkers.rs @@ -1,17 +1,20 @@ use core::fmt; -use forge_permission_resolver::permissions_resolver::{check_url_for_permissions, RequestType}; +use forge_permission_resolver::permissions_resolver::{ + check_url_for_permissions, PermissionHashMap, RequestType, +}; use forge_utils::FxHashMap; use itertools::Itertools; +use regex::Regex; use smallvec::SmallVec; use std::{ cmp::max, + collections::HashMap, collections::HashSet, iter::{self, zip}, mem, ops::ControlFlow, path::PathBuf, }; - use tracing::{debug, info, warn}; use crate::interp::ProjectionVec; @@ -1117,7 +1120,9 @@ impl<'cx> Dataflow<'cx> for PermissionDataflow { interp.bitbucket_permission_resolver, interp.bitbucket_regex_map, ), - _ => unreachable!("Invalid intrinsic function type"), + IntrinsicName::Other => { + (&PermissionHashMap::new(), &HashMap::::new()) + } }; if intrinsic_argument.first_arg.is_none() { diff --git a/crates/forge_analyzer/src/definitions.rs b/crates/forge_analyzer/src/definitions.rs index 8a22e4b..b83750a 100644 --- a/crates/forge_analyzer/src/definitions.rs +++ b/crates/forge_analyzer/src/definitions.rs @@ -1001,18 +1001,28 @@ impl FunctionAnalyzer<'_> { fn resolve_jira_api_type(url: &str) -> Option { // Pattern matching to classify, eg: api.[asApp | asUser]().requestJira(route`/rest/api/3/myself`); match url { + // JSM requests 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 + // Jira Software requests from https://developer.atlassian.com/cloud/jira/software/rest/intro/#introduction + url if url.starts_with("/rest/agile/") + || url.starts_with("/rest/devinfo/") + || url.starts_with("/rest/featureflags/") + || url.starts_with("/rest/deployments/") + || url.starts_with("/rest/builds") + || url.starts_with("/rest/remotelinks/") + || url.starts_with("/rest/security/") + || url.starts_with("/rest/operations/") + || url.starts_with("/rest/devopscomponents/") => + { + Some(IntrinsicName::RequestJiraSoftware) + } + // Jira requests, accept Jira API v2.0 or v3.0 url if url.starts_with("/rest/api/2/") || url.starts_with("/rest/api/3/") => { Some(IntrinsicName::RequestJira) } - _ => { - warn!("Provided Jira API URL: {:?} is neither Jira, JS, JSM!", url); - None - } + _ => None, } } @@ -1032,21 +1042,16 @@ impl FunctionAnalyzer<'_> { // Resolve Jira API requests to either JSM/JS/Jira as all are bundled within requestJira() match first_arg { Expr::TaggedTpl(TaggedTpl { tpl, .. }) => { - if let Some(TplElement { raw, .. }) = tpl.quasis.first() { - resolve_jira_api_type(raw).unwrap_or_else(|| { - // Conservatively assume any of Jira APIs may be used if we can't statically determine which one - warn!("Falling back to any Jira request"); - IntrinsicName::RequestJiraAny - }) - } else { - panic!("No url identifiable to classify requestJira() type"); - } - } - _ => { - warn!("Unable to classify requestJira() type"); - IntrinsicName::RequestJiraAny + tpl.quasis.first().map(|elem| &elem.raw) } + Expr::Lit(Lit::Str(str_lit)) => Some(&str_lit.value), + _ => None, } + .and_then(|atom| resolve_jira_api_type(atom.as_ref())) + .unwrap_or_else(|| { + warn!("Could not resolve Jira API type, falling back to any Jira request"); + IntrinsicName::RequestJiraAny + }) } else if *last == "requestBitbucket" { IntrinsicName::RequestBitbucket } else {