fix: code quality hardening — unwrap removal, unsafe forbid, Go/Raw tests (#72)

* fix: remove unwrap() from production code, improve error handling

- Replace unwrap() with proper error handling in npm, mirror, validation
- Add input validation to cargo registry (crate name + version)
- Improve expect() messages with descriptive context in metrics, rate_limit
- Remove unnecessary clone() in error.rs, docker.rs, npm.rs, dashboard_metrics
- Add #![deny(clippy::unwrap_used)] to prevent future unwrap in prod code
- Add let-else pattern for safer null checks in validation.rs

* docs: update SECURITY.md — add 0.3.x to supported versions

* security: forbid unsafe code at crate level

Add #![forbid(unsafe_code)] to both lib.rs and main.rs.
NORA has zero unsafe blocks — this prevents future additions
without removing the forbid attribute (stronger than deny).

* build: add rust-toolchain.toml, Dockerfile HEALTHCHECK

- Pin toolchain to stable with clippy + rustfmt components
- Add Docker HEALTHCHECK for standalone deployments (wget /health)

* test: add Go proxy and Raw registry integration tests

Go proxy tests: list, .info, .mod, @latest, path traversal, 404
Raw registry tests: upload/download, HEAD, 404, path traversal,
overwrite, delete, binary data (10KB)
This commit is contained in:
2026-03-31 21:15:59 +03:00
committed by GitHub
parent 9ec5fe526b
commit bb125db074
16 changed files with 186 additions and 26 deletions

View File

@@ -64,7 +64,7 @@ pub fn create_progress_bar(total: u64) -> ProgressBar {
.template(
"{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta}) {msg}",
)
.unwrap()
.expect("static progress bar template is valid")
.progress_chars("=>-"),
);
pb
@@ -220,7 +220,7 @@ fn parse_requirements_txt(content: &str) -> Vec<MirrorTarget> {
.lines()
.filter(|l| !l.trim().is_empty() && !l.starts_with('#') && !l.starts_with('-'))
.filter_map(|line| {
let line = line.split('#').next().unwrap().trim();
let line = line.split('#').next().unwrap_or(line).trim();
if let Some((name, version)) = line.split_once("==") {
Some(MirrorTarget {
name: name.trim().to_string(),

View File

@@ -200,7 +200,11 @@ async fn mirror_npm_packages(
let mut handles = Vec::new();
for target in targets {
let permit = sem.clone().acquire_owned().await.unwrap();
let permit = sem
.clone()
.acquire_owned()
.await
.expect("semaphore closed unexpectedly");
let client = client.clone();
let pb = pb.clone();
let fetched = fetched.clone();