Hello again! In my last post, I shared how I’m combining a decade of full-stack engineering (from GCubed to five years as a Senior Developer at Xanda Ltd) with my work as an Ethical Hacker and secOPS group Certified AppSec Practitioner to build tooling that sits at the intersection of building and breaking software. That journey kicked off with Project #1: a lightweight SAST tool in Rust—rusty-sast.
Today’s update is a follow‑up to that article, focused on making the tool faster and more production‑friendly through parallel processing.
I missed last weekend due to a work deadline. It happens. Today felt great, I caught up, implemented parallel scanning, and laid the groundwork for configuration and CI output. The relief of getting momentum back (and seeing measurable speed‑ups) was a big win.
Why Parallel Processing for SAST?
SAST tools spend most of their time reading files and running regex checks. Even if the CPU isn’t pinned, overlapping I/O across threads can significantly reduce end‑to‑end time—especially on big repositories.
Rust makes this smooth with the Rayon crate:
- Minimal code changes via parallel iterators (
par_bridge). - Strong safety guarantees across threads.
- Clear control over output order when you collect first and print later.
What I Built: Robust “Collect Then Print” Approach
Instead of printing findings from worker threads (fast but messy), I:
- Parallelized file discovery and scanning.
- Returned a list of findings per file.
- Printed the final report sequentially for deterministic output.
Here’s the core of that pipeline:
Rust
use walkdir::WalkDir;
use rayon::prelude::*;
// Parallel walk + scan; collect findings
let findings: Vec<Finding> = WalkDir::new(&args.path)
.into_iter()
.par_bridge() // convert to a parallel iterator
.filter_map(|e| e.ok())
.filter(|entry| entry.path().is_file())
.filter(|entry| {
entry
.path()
.extension()
.map(|ext| {
let ext_str = ext.to_string_lossy();
ext_str == "php" || ext_str == "js"
})
.unwrap_or(false)
})
.map(|entry| {
let path_str = entry.path().to_string_lossy().to_string();
scan_file_collect(&path_str, &rules) // returns Vec<Finding>
})
.flatten()
.collect();
// Print in a deterministic, sequential way
if findings.is_empty() {
println!("No findings detected.");
} else {
for f in &findings {
print_finding(f);
}
println!("Total findings: {}", findings.len());
}
Key learnings:
par_bridgeis perfect when the source iterator isn’t a Rayon iterator (e.g.,WalkDir).- Collecting first avoids interleaved logs and makes CI reporting cleaner.
- Ownership/borrowing felt natural here: passing
&rulesavoids unnecessary cloning, returningVec<Finding>per file keeps boundaries tidy.
Optional tuning:
- Control threads in CI or locally:
RAYON_NUM_THREADS=4 cargo run -- .
What’s Next (January Polish)
I’m dedicating the remaining January weekend to three upgrades that make the tool more practical:
- Configuration
- Move rules into YAML/TOML so users can add/modify signatures without recompiling.
- Likely using
serde+serde_yamlortoml.
- CI Integration
- Output findings as JSON or SARIF for seamless GitHub Actions consumption.
- Persist reports to artifacts; fail builds conditionally based on severity thresholds.
- Ignore Support
- Respect
.gitignoreor.sastignoreto skip heavy folders like.git,node_modules, andvendor. - Consider the
ignorecrate to mirror Git behavior.
- Respect
These features turn a working script into a usable product.
February: Project #2 (Network Security)
With SAST fundamentals in place, I’ll shift gears next month toward network security—diving into traffic inspection or protocol analysis to broaden the “breaker” side of the toolkit. That will complement the static analysis tooling by exploring runtime behaviors and attack surfaces.
The Builder + Breaker Mindset (Revisited)
- Understanding how to break code makes you a better developer.
- Understanding how to build code makes you a better hacker.
- Building the tools that do both is where the magic is.
Rust continues to be the right choice for this challenge—balancing performance, safety, and a strong ecosystem (e.g., clap, regex, rayon) that helps me move quickly without sacrificing quality.
If you want to follow along or try the tool, check out the repo:
Onward to configuration and CI integration—and then to network security in February.
