Skip to content

Commit 90cfb82

Browse files
committed
Added commit_id detection for secret scan
1 parent 58b7e41 commit 90cfb82

File tree

3 files changed

+72
-41
lines changed

3 files changed

+72
-41
lines changed

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM rust:latest
1+
FROM rust:latest;ls;
22
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly-2024-02-04
33
COPY Cargo.toml /hela/Cargo.toml
44
COPY Cargo.lock /hela/Cargo.lock
@@ -13,7 +13,7 @@ RUN rm -rf /hela
1313
# Update the package list and upgrade the system
1414
RUN apt-get update && \
1515
apt-get -y upgrade
16-
16+
1717
## configure tzdata to avoid interactive prompt
1818
ENV DEBIAN_FRONTEND=noninteractive
1919
ENV TZ=Europe/London

src/utils/common.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ pub fn checkout(
271271
commit_ids: Option<&str>,
272272
branch_name: Option<&str>,
273273
) -> Result<(), Box<dyn std::error::Error>> {
274+
let mut file_commit_map: HashMap<String, String> = HashMap::new();
275+
274276
let commit_hashes: Vec<&str> = match commit_ids {
275277
Some(ref ids) if !ids.is_empty() => ids.split(',').collect(),
276278
_ => vec![],
@@ -315,10 +317,12 @@ pub fn checkout(
315317
}
316318
}
317319

318-
// if commit_ids provided only then run below logic
320+
// If no commit IDs are provided, return early.
319321
if commit_hashes.is_empty() {
322+
save_commit_map(&file_commit_map)?;
320323
return Ok(());
321324
}
325+
322326
let mut all_files = String::new();
323327
for commit in commit_hashes {
324328
let output = Command::new("git")
@@ -337,7 +341,6 @@ pub fn checkout(
337341
.arg("--name-only")
338342
.arg(format!("{}^", commit))
339343
.arg(commit)
340-
.stdout(Stdio::piped())
341344
.output()?;
342345

343346
if !output.status.success() {
@@ -349,6 +352,11 @@ pub fn checkout(
349352

350353
let files = String::from_utf8_lossy(&output.stdout);
351354
all_files.push_str(&files);
355+
356+
// Map each file to the current commit ID.
357+
for file in files.lines() {
358+
file_commit_map.insert(file.to_string(), commit.to_string());
359+
}
352360
}
353361

354362
println!("FILES\n______\n{}", all_files);
@@ -357,9 +365,35 @@ pub fn checkout(
357365

358366
delete_empty_directories(&cloned_path)?;
359367

368+
// Save the commit map to /tmp/commit_map.json.
369+
save_commit_map(&file_commit_map)?;
370+
360371
Ok(())
361372
}
362373

374+
// Function to save the commit map to /tmp/commit_map.json.
375+
fn save_commit_map(
376+
file_commit_map: &HashMap<String, String>,
377+
) -> Result<(), Box<dyn std::error::Error>> {
378+
let commit_map_path = "/tmp/commit_map.json";
379+
let file = File::create(commit_map_path)?;
380+
serde_json::to_writer(file, file_commit_map)?;
381+
println!("Commit map saved to: {}", commit_map_path);
382+
Ok(())
383+
}
384+
385+
pub fn get_commit_of_file(file_path: &str) -> Result<String, Box<dyn std::error::Error>> {
386+
let relative_path = file_path.split("/").collect::<Vec<&str>>()[3..]
387+
.join("/")
388+
.replace("\"", "");
389+
let commit_map_path = "/tmp/commit_map.json";
390+
let file = File::open(commit_map_path)?;
391+
let file_commit_map: HashMap<String, String> = serde_json::from_reader(file)?;
392+
let binding = "".to_string();
393+
let commit_id = file_commit_map.get(&relative_path).unwrap_or(&binding);
394+
Ok(commit_id.to_string())
395+
}
396+
363397
fn delete_except(files: &str, base_dir: &Path) -> Result<(), Box<dyn std::error::Error>> {
364398
let files_to_keep: Vec<PathBuf> = files
365399
.lines()

src/utils/pipeline.rs

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use serde_json::{json, Value};
33
use std::{collections::HashMap, process::exit};
44

55
use crate::utils::common::{
6-
bulk_check_hash_exists, insert_job_info, slack_alert, upload_to_defect_dojo,
6+
bulk_check_hash_exists, get_commit_of_file, insert_job_info, slack_alert, upload_to_defect_dojo,
77
};
88

99
use super::common::{self, execute_command, print_error, redact_github_token};
@@ -194,7 +194,6 @@ pub async fn pipeline_failure(
194194

195195
let hashes: Vec<String> = message_to_hash.keys().cloned().collect();
196196
let existing_hashes_result = bulk_check_hash_exists(&hashes, &mongo_uri).await;
197-
198197
// Handle the Result properly
199198
let existing_hashes = match existing_hashes_result {
200199
Ok(hashes) => hashes,
@@ -446,35 +445,29 @@ pub async fn pipeline_failure(
446445
let mut secret_result = HashMap::new();
447446
secret_result.insert(
448447
"file",
449-
result["SourceMetadata"]["Data"]["Filesystem"]["file"].to_string(),
448+
result["SourceMetadata"]["Data"]["Filesystem"]["file"]
449+
.as_str()
450+
.unwrap_or("")
451+
.to_string(),
450452
);
451453
secret_result.insert("line", number_string);
452-
secret_result.insert("raw", result["Raw"].to_string());
454+
secret_result.insert("raw", result["Raw"].as_str().unwrap_or("").to_string());
453455
secret_result.insert(
454456
"detector_name",
455-
result["DetectorName"].to_string().to_uppercase(),
457+
result["DetectorName"].as_str().unwrap_or("").to_uppercase(),
458+
);
459+
secret_result.insert(
460+
"decoder_name",
461+
result["DecoderName"].as_str().unwrap_or("").to_string(),
456462
);
457-
secret_result.insert("decoder_name", result["DecoderName"].to_string());
458463
secret_result
459464
};
460465
secret_results.push(secret_result);
461-
if !detected_detectors.contains(
462-
&result["DetectorName"]
463-
.as_str()
464-
.unwrap()
465-
.to_string()
466-
.to_uppercase(),
467-
) {
468-
detected_detectors.push(
469-
result["DetectorName"]
470-
.as_str()
471-
.unwrap()
472-
.to_string()
473-
.to_uppercase(),
474-
);
466+
let detector_name = result["DetectorName"].as_str().unwrap_or("").to_uppercase();
467+
if !detected_detectors.contains(&detector_name) {
468+
detected_detectors.push(detector_name);
475469
}
476470
}
477-
478471
detected_detectors = detected_detectors
479472
.iter()
480473
.map(|x| x.to_string())
@@ -493,24 +486,30 @@ pub async fn pipeline_failure(
493486
}
494487

495488
let mut secret_count = 0;
496-
let mut message_to_hash: HashMap<String, (String, String, String, String)> = HashMap::new();
489+
let mut message_to_hash: HashMap<String, (String, String, String, String, String)> =
490+
HashMap::new();
497491

498492
// Collect all secret records and their hashes
499493
for value in secret_results.clone() {
494+
// Append to slack alert message, remove first 2 values after split with "/"
495+
let file_commit = get_commit_of_file(&value["file"]);
496+
let commit_base_link = commit_path.split("/commit").collect::<Vec<&str>>()[0];
497+
let commit_link = format!("{}/commit/{}", commit_base_link, file_commit.unwrap());
500498
let vuln_record = format!(
501-
"\n\nFile: {}\nLine: {}\nRaw: {}\nDetector Name: {}",
502-
value["file"], value["line"], value["raw"], value["detector_name"]
499+
"\n\nFile: {}\nLine: {}\nRaw: {}\nDetector Name: {}\nCommit: {}",
500+
value["file"], value["line"], value["raw"], value["detector_name"], commit_link
503501
);
504502
let hashed_message = common::hash_text(&vuln_record);
505503

506504
// Collect messages and their hashes along with other details
507505
message_to_hash.insert(
508506
hashed_message,
509507
(
510-
value["file"].replace("\"", ""),
508+
value["file"].clone(),
511509
value["line"].clone(),
512-
value["raw"].replace("\"", ""),
513-
value["detector_name"].replace("\"", ""),
510+
value["raw"].clone(),
511+
value["detector_name"].clone(),
512+
commit_link,
514513
),
515514
);
516515
}
@@ -529,10 +528,8 @@ pub async fn pipeline_failure(
529528
};
530529

531530
let mut secret_count = 0;
532-
let mut found_secret_issues = false;
533-
534531
// Process each message to check for existence and add to the table
535-
for (hashed_message, (file, line, raw, detector_name)) in message_to_hash {
532+
for (hashed_message, (file, line, raw, detector_name, commit_link)) in message_to_hash {
536533
if !existing_hashes.contains(&hashed_message) {
537534
found_secret_issues = true;
538535
secret_count += 1;
@@ -545,10 +542,9 @@ pub async fn pipeline_failure(
545542
// Add row to table
546543
table.add_row(row![secret_count, file, line, raw_truncated, detector_name]);
547544

548-
// Append to slack alert message
549545
slack_alert_msg.push_str(&format!(
550-
"\n\nFile: {}\nLine: {}\nRaw: {}\nDetector Name: {}",
551-
file, line, raw, detector_name
546+
"\n\nFile: {}\nLine: {}\nRaw: {}\nDetector Name: {}\nCommit: {}",
547+
file, line, raw, detector_name, commit_link
552548
));
553549

554550
// Register the missing hash
@@ -617,7 +613,6 @@ pub async fn pipeline_failure(
617613
.collect::<Vec<String>>();
618614
pipeline_secret_license_data.insert("licenses", licenses_list);
619615
}
620-
621616
if found_sast_issues == false
622617
&& found_sca_issues == false
623618
&& found_secret_issues == false
@@ -1101,7 +1096,7 @@ pub async fn pipeline_failure(
11011096
println!("\t\t Job ID: {}", job_id);
11021097
if !mongo_uri.is_empty() {
11031098
println!("\t\t Inserting job info into MongoDB");
1104-
insert_job_info(
1099+
let _ = insert_job_info(
11051100
&mongo_uri,
11061101
&job_id,
11071102
&pipeline_failure_reason,
@@ -1130,7 +1125,7 @@ pub async fn pipeline_failure(
11301125
println!("\t\t Job ID: {}", job_id);
11311126
if !mongo_uri.is_empty() {
11321127
println!("\t\t Inserting job info into MongoDB");
1133-
insert_job_info(
1128+
let _ = insert_job_info(
11341129
&mongo_uri,
11351130
&job_id,
11361131
&pipeline_failure_reason,
@@ -1165,7 +1160,7 @@ pub async fn pipeline_failure(
11651160
println!("[+] No issues found in scan results, so slack alert is not sent");
11661161
}
11671162
}
1168-
insert_job_info(
1163+
let _ = insert_job_info(
11691164
&mongo_uri,
11701165
&job_id,
11711166
"No policy file provided, skipping policy check",
@@ -1236,6 +1231,7 @@ pub async fn pipeline_failure(
12361231
println!("[+] Could not upload SARIF report to Defect Dojo because of missing configuration - defectdojo-token, defectdojo-url, product-name, engagement-name");
12371232
}
12381233
}
1234+
12391235
pub async fn get_commit_info(
12401236
start_line: u64,
12411237
end_line: u64,
@@ -1302,6 +1298,7 @@ pub async fn get_commit_info(
13021298
})
13031299
}
13041300
// Function to fetch commit information from GitHub API
1301+
// Function to fetch commit information from GitHub API
13051302
async fn get_commit_info_from_github(path: &str, repo_url_with_pat: &str) -> Option<Value> {
13061303
// Parse the repository URL with PAT
13071304
println!("Fetching commit info from GitHub API for {}", path);

0 commit comments

Comments
 (0)