Skip to content

Commit

Permalink
Change serde parsing logic to accomodate JS swagger, added permission…
Browse files Browse the repository at this point in the history
… resolver with unit tests
  • Loading branch information
dxu2atlassian committed Dec 23, 2024
1 parent 054198a commit e2fc593
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 7 deletions.
20 changes: 18 additions & 2 deletions crates/forge_analyzer/src/checkers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,15 @@ impl<'cx> Dataflow<'cx> for PermissionDataflow {
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
if intrinsic_func_type == IntrinsicName::RequestJiraSoftware {
let permissions = check_url_for_permissions(
interp.jira_software_permission_resolver,
interp.jira_software_regex_map,
translate_request_type(Some(second_arg)),
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type
== IntrinsicName::RequestJiraServiceManagement
{
let permissions = check_url_for_permissions(
Expand Down Expand Up @@ -1146,7 +1154,15 @@ impl<'cx> Dataflow<'cx> for PermissionDataflow {
} else {
first_arg_vec.iter().for_each(|first_arg| {
let first_arg = first_arg.replace(&['\"'][..], "");
if intrinsic_func_type
if intrinsic_func_type == IntrinsicName::RequestJiraSoftware {
let permissions = check_url_for_permissions(
interp.jira_software_permission_resolver,
interp.jira_software_regex_map,
RequestType::Get,
&first_arg,
);
permissions_within_call.extend_from_slice(&permissions)
} else if intrinsic_func_type
== IntrinsicName::RequestJiraServiceManagement
{
let permissions = check_url_for_permissions(
Expand Down
3 changes: 2 additions & 1 deletion 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 Expand Up @@ -995,7 +996,7 @@ impl FunctionAnalyzer<'_> {
[PropPath::Def(def), ref authn @ .., PropPath::Static(ref last)]
if (*last == *"requestJira"
|| *last == *"requestConfluence"
|| *last == *"requestBitbucket")
|| *last == *"requestBitbucket") // TODO: resolve Jira API requests to the correct permission map, here JSM (and likely JS) is bundled inside Jira
&& Some(&ImportKind::Default)
== self.res.is_imported_from(def, "@forge/api") =>
{
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
69 changes: 67 additions & 2 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 @@ -362,4 +390,41 @@ 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);

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")),
"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);

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

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 e2fc593

Please sign in to comment.