Skip to content

Commit

Permalink
Merge pull request #60 from dxu2atlassian/feat/EAS-2547-js-parsing
Browse files Browse the repository at this point in the history
Jira Software parsing and permission resolvers with unit tests
  • Loading branch information
jwong101 authored Jan 3, 2025
2 parents 054198a + 0ce2619 commit a7ad816
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 91 deletions.
126 changes: 42 additions & 84 deletions crates/forge_analyzer/src/checkers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1092,99 +1092,57 @@ impl<'cx> Dataflow<'cx> for PermissionDataflow {
let mut permissions_within_call: Vec<String> = vec![];
let intrinsic_func_type = intrinsic_argument.name.unwrap();

let (resolver, regex_map) = match intrinsic_func_type {
IntrinsicName::RequestJiraSoftware => (
interp.jira_software_permission_resolver,
interp.jira_software_regex_map,
),
IntrinsicName::RequestJiraServiceManagement => (
interp.jira_service_management_permission_resolver,
interp.jira_service_management_regex_map,
),
IntrinsicName::RequestConfluence => (
interp.confluence_permission_resolver,
interp.confluence_regex_map,
),
IntrinsicName::RequestJira => {
(interp.jira_permission_resolver, interp.jira_regex_map)
}
IntrinsicName::RequestBitbucket => (
interp.bitbucket_permission_resolver,
interp.bitbucket_regex_map,
),
_ => unreachable!("Invalid intrinsic function type"),
};

if intrinsic_argument.first_arg.is_none() {
interp.permissions.drain(..);
} else {
intrinsic_argument
.first_arg
.iter()
.for_each(|first_arg_vec| {
if let Some(second_arg_vec) = intrinsic_argument.second_arg.clone() {
first_arg_vec.iter().for_each(|first_arg| {
let first_arg = first_arg.replace(&['\"'][..], "");
second_arg_vec.iter().for_each(|second_arg| {
if intrinsic_func_type
== IntrinsicName::RequestJiraServiceManagement
{
let permissions = check_url_for_permissions(
interp.jira_service_management_permission_resolver,
interp.jira_service_management_regex_map,
translate_request_type(Some(second_arg)),
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type
== IntrinsicName::RequestConfluence
{
let permissions = check_url_for_permissions(
interp.confluence_permission_resolver,
interp.confluence_regex_map,
translate_request_type(Some(second_arg)),
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type == IntrinsicName::RequestJira {
let permissions = check_url_for_permissions(
interp.jira_permission_resolver,
interp.jira_regex_map,
translate_request_type(Some(second_arg)),
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type == IntrinsicName::RequestBitbucket
{
let permissions = check_url_for_permissions(
interp.bitbucket_permission_resolver,
interp.bitbucket_regex_map,
translate_request_type(Some(second_arg)),
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
}
first_arg_vec.iter().for_each(|first_arg| {
let first_arg = first_arg.replace(&['\"'][..], "");
let request_types = intrinsic_argument
.second_arg
.as_ref()
.map(|args| {
args.iter()
.map(|arg| translate_request_type(Some(arg)))
.collect::<Vec<_>>()
.into_iter()
})
})
} else {
first_arg_vec.iter().for_each(|first_arg| {
let first_arg = first_arg.replace(&['\"'][..], "");
if intrinsic_func_type
== IntrinsicName::RequestJiraServiceManagement
{
let permissions = check_url_for_permissions(
interp.jira_service_management_permission_resolver,
interp.jira_service_management_regex_map,
RequestType::Get,
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type == IntrinsicName::RequestConfluence {
let permissions = check_url_for_permissions(
interp.confluence_permission_resolver,
interp.confluence_regex_map,
RequestType::Get,
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type == IntrinsicName::RequestJira {
let permissions = check_url_for_permissions(
interp.jira_permission_resolver,
interp.jira_regex_map,
RequestType::Get,
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type == IntrinsicName::RequestBitbucket {
let permissions = check_url_for_permissions(
interp.bitbucket_permission_resolver,
interp.bitbucket_regex_map,
RequestType::Get,
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
}
})
}
});
.unwrap_or_else(|| vec![RequestType::Get].into_iter());

for req_type in request_types {
let permissions = check_url_for_permissions(
resolver, regex_map, req_type, &first_arg,
);
permissions_within_call.extend_from_slice(&permissions);
}
});
});
interp
.permissions
.retain(|permissions| !permissions_within_call.contains(permissions));
Expand Down
1 change: 1 addition & 0 deletions crates/forge_analyzer/src/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ enum LowerStage {

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IntrinsicName {
RequestJiraSoftware,
RequestJiraServiceManagement,
RequestConfluence,
RequestJira,
Expand Down
10 changes: 8 additions & 2 deletions crates/forge_analyzer/src/interp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,11 +390,13 @@ pub struct Interp<'cx, C: Runner<'cx>> {
pub callstack_arguments: Vec<Vec<Value>>,
pub value_manager: ValueManager,
pub permissions: Vec<String>,
pub jira_software_permission_resolver: &'cx PermissionHashMap,
pub jira_service_management_permission_resolver: &'cx PermissionHashMap,
pub jira_permission_resolver: &'cx PermissionHashMap,
pub confluence_permission_resolver: &'cx PermissionHashMap,
pub jira_service_management_regex_map: &'cx HashMap<String, Regex>,
pub bitbucket_permission_resolver: &'cx PermissionHashMap,
pub jira_software_regex_map: &'cx HashMap<String, Regex>,
pub jira_service_management_regex_map: &'cx HashMap<String, Regex>,
pub jira_regex_map: &'cx HashMap<String, Regex>,
pub confluence_regex_map: &'cx HashMap<String, Regex>,
pub bitbucket_regex_map: &'cx HashMap<String, Regex>,
Expand Down Expand Up @@ -510,6 +512,8 @@ impl<'cx, C: Runner<'cx>> Interp<'cx, C> {
call_all: bool,
call_uncalled: bool,
permissions: Vec<String>,
jira_software_permission_resolver: &'cx PermissionHashMap,
jira_software_regex_map: &'cx HashMap<String, Regex>,
jira_service_management_permission_resolver: &'cx PermissionHashMap,
jira_service_management_regex_map: &'cx HashMap<String, Regex>,
jira_permission_resolver: &'cx PermissionHashMap,
Expand Down Expand Up @@ -544,11 +548,13 @@ impl<'cx, C: Runner<'cx>> Interp<'cx, C> {
expecting_value: VecDeque::default(),
},
permissions,
jira_software_permission_resolver,
jira_service_management_permission_resolver,
jira_permission_resolver,
confluence_permission_resolver,
jira_service_management_regex_map,
bitbucket_permission_resolver,
jira_software_regex_map,
jira_service_management_regex_map,
jira_regex_map,
confluence_regex_map,
bitbucket_regex_map,
Expand Down
66 changes: 61 additions & 5 deletions crates/forge_permission_resolver/src/permissions_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ struct RequestDetails {
default
)]
permission: Vec<PermissionData>,

// For parsing Jira Software as that swagger doesn't follow "x-atlassian-oauth2-scopes" scope style
#[serde(default)]
security: Vec<SecurityData>,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Deserialize)]
Expand All @@ -44,6 +48,12 @@ struct PermissionData {
scopes: Vec<String>,
}

#[derive(Default, Debug, Clone, PartialEq, Eq, Deserialize)]
struct SecurityData {
#[serde(default, rename = "OAuth2")]
oauth2: Vec<String>,
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
pub enum RequestType {
Get,
Expand Down Expand Up @@ -85,6 +95,11 @@ pub fn check_url_for_permissions(
vec![]
}

pub fn get_permission_resolver_jira_software() -> (PermissionHashMap, HashMap<String, Regex>) {
let jira_software_url = "https://developer.atlassian.com/cloud/jira/software/swagger.v3.json";
get_permission_resolver(jira_software_url)
}

pub fn get_permission_resolver_jira_service_management(
) -> (PermissionHashMap, HashMap<String, Regex>) {
let jira_service_management_url =
Expand Down Expand Up @@ -199,12 +214,25 @@ fn get_request_type(
}

fn get_scopes(endpoint_data: &RequestDetails) -> Vec<String> {
endpoint_data
let mut scopes = endpoint_data
.permission
.iter()
.flat_map(|data| &*data.scopes)
.cloned()
.collect()
.collect::<Vec<_>>();

if scopes.is_empty() {
// For Jira Software if the initial scopes are empty, try the scopes from the security field
scopes.extend(
endpoint_data
.security
.iter()
.flat_map(|sec| &sec.oauth2)
.cloned(),
);
}

scopes
}

#[cfg(test)]
Expand Down Expand Up @@ -285,9 +313,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("manage:servicedesk-customer")),
Expand Down Expand Up @@ -362,4 +387,35 @@ mod test {
"Should require admin:repository:bitbucket permission"
);
}

#[test]
fn test_get_issues_for_epic() {
let (permission_map, regex_map) = get_permission_resolver_jira_software();
let url = "/rest/agile/1.0/sprint/23";
let request_type = RequestType::Get;
let result = check_url_for_permissions(&permission_map, &regex_map, request_type, url);

assert!(!result.is_empty(), "Should have parsed permissions");
assert!(
result.contains(&String::from("read:sprint:jira-software")),
"Should require read:sprint:jira-software permission"
);
}

#[test]
fn test_get_all_boards() {
let (permission_map, regex_map) = get_permission_resolver_jira_software();
let url = "/rest/agile/1.0/board";
let request_type = RequestType::Get;
let result = check_url_for_permissions(&permission_map, &regex_map, request_type, url);

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

let expected_permission: Vec<String> = vec![
String::from("read:board-scope:jira-software"),
String::from("read:project:jira"),
];

assert_eq!(result, expected_permission);
}
}
13 changes: 13 additions & 0 deletions crates/fsrt/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use clap::{Parser, ValueHint};
use forge_permission_resolver::permissions_resolver::{
get_permission_resolver_bitbucket, get_permission_resolver_confluence,
get_permission_resolver_jira, get_permission_resolver_jira_service_management,
get_permission_resolver_jira_software,
};

use std::{
Expand Down Expand Up @@ -275,6 +276,8 @@ pub(crate) fn scan_directory<'a>(

let permissions = permissions_declared.into_iter().collect::<Vec<_>>();

let (jira_software_permission_resolver, jira_software_regex_map) =
get_permission_resolver_jira_software();
let (jira_service_management_permission_resolver, jira_service_management_regex_map) =
get_permission_resolver_jira_service_management();
let (jira_permission_resolver, jira_regex_map) = get_permission_resolver_jira();
Expand All @@ -287,6 +290,8 @@ pub(crate) fn scan_directory<'a>(
false,
true,
permissions.clone(),
&jira_software_permission_resolver,
&jira_software_regex_map,
&jira_service_management_permission_resolver,
&jira_service_management_regex_map,
&jira_permission_resolver,
Expand All @@ -302,6 +307,8 @@ pub(crate) fn scan_directory<'a>(
false,
false,
permissions.clone(),
&jira_software_permission_resolver,
&jira_software_regex_map,
&jira_service_management_permission_resolver,
&jira_service_management_regex_map,
&jira_permission_resolver,
Expand All @@ -316,6 +323,8 @@ pub(crate) fn scan_directory<'a>(
false,
false,
permissions.clone(),
&jira_software_permission_resolver,
&jira_software_regex_map,
&jira_service_management_permission_resolver,
&jira_service_management_regex_map,
&jira_permission_resolver,
Expand All @@ -332,6 +341,8 @@ pub(crate) fn scan_directory<'a>(
false,
false,
permissions.clone(),
&jira_software_permission_resolver,
&jira_software_regex_map,
&jira_service_management_permission_resolver,
&jira_service_management_regex_map,
&jira_permission_resolver,
Expand All @@ -348,6 +359,8 @@ pub(crate) fn scan_directory<'a>(
false,
true,
permissions,
&jira_software_permission_resolver,
&jira_software_regex_map,
&jira_service_management_permission_resolver,
&jira_service_management_regex_map,
&jira_permission_resolver,
Expand Down

0 comments on commit a7ad816

Please sign in to comment.