From a601e8ea44c83601816b7065df71d404e836cde7 Mon Sep 17 00:00:00 2001 From: dxu2atlassian <136645827+dxu2atlassian@users.noreply.github.com> Date: Sun, 12 Jan 2025 15:57:15 -0800 Subject: [PATCH] E2E bitbucket test with possible bug fix --- crates/forge_analyzer/src/checkers.rs | 37 +++++++-------- crates/forge_analyzer/src/reporter.rs | 4 ++ crates/fsrt/src/main.rs | 2 + crates/fsrt/src/test.rs | 67 +++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 19 deletions(-) diff --git a/crates/forge_analyzer/src/checkers.rs b/crates/forge_analyzer/src/checkers.rs index 185b9bd..87fdb18 100644 --- a/crates/forge_analyzer/src/checkers.rs +++ b/crates/forge_analyzer/src/checkers.rs @@ -1,22 +1,3 @@ -use core::fmt; -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; use crate::utils::projvec_from_str; use crate::{ @@ -36,6 +17,24 @@ use crate::{ }, worklist::WorkList, }; +use core::fmt; +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}; #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Default)] pub enum Taint { diff --git a/crates/forge_analyzer/src/reporter.rs b/crates/forge_analyzer/src/reporter.rs index 1be3e22..ea27393 100644 --- a/crates/forge_analyzer/src/reporter.rs +++ b/crates/forge_analyzer/src/reporter.rs @@ -26,6 +26,10 @@ impl Vulnerability { pub fn check_name(&self) -> &str { &self.check_name } + + pub fn description(&self) -> &str { + &self.description + } } pub trait IntoVuln { diff --git a/crates/fsrt/src/main.rs b/crates/fsrt/src/main.rs index 717551e..6ff0023 100644 --- a/crates/fsrt/src/main.rs +++ b/crates/fsrt/src/main.rs @@ -671,6 +671,7 @@ pub(crate) fn scan_directory<'a>( .collect::>() .join("\n"); + // let mut final_perms = perm_interp.permissions.clone(); let ast = parse_schema::<&str>(&joined_schema); if let std::result::Result::Ok(doc) = ast { @@ -716,6 +717,7 @@ pub(crate) fn scan_directory<'a>( .filter(|f| !oauth_scopes.contains(f.as_str())) .collect(); + // TODO: this has been corrected already to final_perms, however the indentation may still be wrong if run_permission_checker && !final_perms.is_empty() { reporter.add_vulnerabilities([PermissionVuln::new(final_perms)]); } diff --git a/crates/fsrt/src/test.rs b/crates/fsrt/src/test.rs index a9cf7fc..ac3adb5 100644 --- a/crates/fsrt/src/test.rs +++ b/crates/fsrt/src/test.rs @@ -20,6 +20,8 @@ trait ReportExt { #[cfg(feature = "graphql_schema")] fn contains_perm_vuln(&self, expected_len: usize) -> bool; + fn vuln_description_contains(&self, check_name: &str, description_snippet: &str) -> bool; + fn contains_vulns(&self, expected_len: i32) -> bool; fn contains_authz_vuln(&self, expected_len: usize) -> bool; @@ -59,6 +61,17 @@ impl ReportExt for Report { == expected_len } + #[inline] + fn vuln_description_contains(&self, check_name: &str, description_snippet: &str) -> bool { + self.into_vulns() + .iter() + .filter(|vuln| { + vuln.check_name() == check_name && vuln.description().contains(&description_snippet) + }) + .count() + == 1 + } + #[inline] fn contains_vulns(&self, expected_len: i32) -> bool { self.into_vulns().len() == expected_len as usize @@ -887,3 +900,57 @@ fn authz_function_called_in_object_bitbucket() { let scan_result = scan_directory_test(test_forge_project); assert!(scan_result.contains_vulns(1)) } + +#[test] +fn extra_permission_bitbucket() { + let test_forge_project = MockForgeProject::files_from_string( + "// src/index.tsx + import ForgeUI, { render, Fragment, Macro, Text } from '@forge/ui'; + import api, { route, fetch } from '@forge/api'; + const App = () => { + let testObject = { + someFunction() { + const res = api.asUser().requestBitbucket(route`/repositories/mockworkspace/mockreposlug/default-reviewers/jcg`, { + method: 'PUT', + body: {} + }); + return res; + } + } + testObject.someFunction() + return ( + + Hello world! + + ); + }; + export const run = render(} />); + + // manifest.yaml + modules: + macro: + - key: basic-hello-world + function: main + title: basic + handler: nothing + description: Inserts Hello world! + function: + - key: main + handler: index.run + app: + id: ari:cloud:ecosystem::app/07b89c0f-949a-4905-9de9-6c9521035986 + permissions: + scopes: + - 'admin:repository:bitbucket' + - 'unused:permission:defined'" + ); + + let scan_result = scan_directory_test(test_forge_project); + println!("scan_result {:#?}", scan_result); + assert!( + scan_result.contains_perm_vuln(1) + && scan_result.contains_vulns(1) + && scan_result + .vuln_description_contains("Least-Privilege", "unused:permission:defined") + ); +}