rust-programming-expert — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited rust-programming-expert (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Production Rust patterns: memory safety, async-first, web backends, CLI, and performance.
# New project
cargo new my-app --bin
cargo new my-lib --lib
# Essential Cargo.toml
[package]
name = "my-app"
version = "0.1.0"
edition = "2024"
[dependencies]
tokio = { version = "1", features = ["full"] }
axum = "0.8"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
sqlx = { version = "0.8", features = ["postgres", "runtime-tokio", "uuid", "chrono"] }
anyhow = "1"
thiserror = "2"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
uuid = { version = "1", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }
[dev-dependencies]
tokio-test = "0.4"// Clone when you need owned data in multiple places
fn process(data: Vec<String>) -> Vec<String> {
let upper: Vec<String> = data.iter().map(|s| s.to_uppercase()).collect();
upper // data dropped here
}
// Borrow when you only need to read
fn count_long(items: &[String], min_len: usize) -> usize {
items.iter().filter(|s| s.len() >= min_len).count()
}
// Cow<str> for "borrow or own" flexibility
use std::borrow::Cow;
fn sanitize(input: &str) -> Cow<str> {
if input.contains('<') {
Cow::Owned(input.replace('<', "<"))
} else {
Cow::Borrowed(input) // zero allocation when no change needed
}
}// Named lifetime: output lives as long as input
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// Struct holding a reference
struct Parser<'a> {
input: &'a str,
pos: usize,
}
impl<'a> Parser<'a> {
fn new(input: &'a str) -> Self {
Self { input, pos: 0 }
}
fn remaining(&self) -> &'a str {
&self.input[self.pos..]
}
}thiserror for Library Errorsuse thiserror::Error;
#[derive(Error, Debug)]
pub enum AppError {
#[error("Not found: {0}")]
NotFound(String),
#[error("Unauthorized")]
Unauthorized,
#[error("Validation failed: {field} — {message}")]
Validation { field: String, message: String },
#[error("Database error")]
Database(#[from] sqlx::Error),
#[error("IO error")]
Io(#[from] std::io::Error),
}
// Result alias
pub type Result<T> = std::result::Result<T, AppError>;anyhow for Application Codeuse anyhow::{Context, Result, bail, ensure};
async fn load_config(path: &str) -> Result<Config> {
let content = tokio::fs::read_to_string(path)
.await
.with_context(|| format!("Failed to read config file: {path}"))?;
let config: Config = serde_json::from_str(&content)
.context("Config file is not valid JSON")?;
ensure!(config.port > 1024, "Port must be > 1024, got {}", config.port);
Ok(config)
}use axum::{http::StatusCode, response::{IntoResponse, Response}, Json};
use serde_json::json;
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match &self {
AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
AppError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized".into()),
AppError::Validation { field, message } => (
StatusCode::UNPROCESSABLE_ENTITY,
format!("{field}: {message}"),
),
AppError::Database(_) | AppError::Io(_) => {
tracing::error!(error = ?self, "Internal error");
(StatusCode::INTERNAL_SERVER_ERROR, "Internal server error".into())
}
};
(status, Json(json!({ "error": message }))).into_response()
}
}#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.init();
let config = load_config("config.json").await?;
let app = build_app(config).await?;
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
tracing::info!("Listening on {}", listener.local_addr()?);
axum::serve(listener, app).await?;
Ok(())
}use tokio::task::JoinSet;
async fn fetch_all(ids: Vec<String>) -> Vec<Result<Data>> {
let mut set = JoinSet::new();
for id in ids {
set.spawn(async move { fetch_one(&id).await });
}
let mut results = Vec::new();
while let Some(res) = set.join_next().await {
results.push(res.expect("task panicked"));
}
results
}
// Or use join! for fixed set of futures
async fn fetch_dashboard(user_id: &str) -> Result<Dashboard> {
let (user, posts, stats) = tokio::try_join!(
fetch_user(user_id),
fetch_posts(user_id),
fetch_stats(user_id),
)?;
Ok(Dashboard { user, posts, stats })
}use axum::{Router, extract::State, routing::{get, post}};
use std::sync::Arc;
#[derive(Clone)]
pub struct AppState {
pub db: sqlx::PgPool,
pub config: Arc<Config>,
}
pub fn build_router(state: AppState) -> Router {
Router::new()
.route("/health", get(health_check))
.nest("/api/v1", api_routes())
.with_state(state)
.layer(
tower::ServiceBuilder::new()
.layer(tower_http::trace::TraceLayer::new_for_http())
.layer(tower_http::cors::CorsLayer::permissive())
)
}
fn api_routes() -> Router<AppState> {
Router::new()
.route("/posts", get(list_posts).post(create_post))
.route("/posts/:id", get(get_post).delete(delete_post))
}use axum::{
extract::{Path, Query, State, Json},
http::StatusCode,
};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Deserialize)]
pub struct ListQuery {
page: Option<u32>,
limit: Option<u32>,
}
#[derive(Serialize)]
pub struct PostResponse {
id: Uuid,
title: String,
content: Option<String>,
}
pub async fn list_posts(
State(state): State<AppState>,
Query(query): Query<ListQuery>,
) -> Result<Json<Vec<PostResponse>>, AppError> {
let page = query.page.unwrap_or(1).max(1);
let limit = query.limit.unwrap_or(10).min(100);
let offset = (page - 1) * limit;
let posts = sqlx::query_as!(
PostResponse,
"SELECT id, title, content FROM posts WHERE published = true
ORDER BY created_at DESC LIMIT $1 OFFSET $2",
limit as i64,
offset as i64,
)
.fetch_all(&state.db)
.await?;
Ok(Json(posts))
}
#[derive(Deserialize)]
pub struct CreatePost {
title: String,
content: Option<String>,
}
pub async fn create_post(
State(state): State<AppState>,
Json(body): Json<CreatePost>,
) -> Result<(StatusCode, Json<PostResponse>), AppError> {
if body.title.trim().is_empty() {
return Err(AppError::Validation {
field: "title".into(),
message: "must not be empty".into(),
});
}
let post = sqlx::query_as!(
PostResponse,
"INSERT INTO posts (title, content) VALUES ($1, $2) RETURNING id, title, content",
body.title,
body.content,
)
.fetch_one(&state.db)
.await?;
Ok((StatusCode::CREATED, Json(post)))
}use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(name = "myapp", about = "My CLI tool", version)]
pub struct Cli {
#[arg(short, long, default_value = "info")]
pub log_level: String,
#[command(subcommand)]
pub command: Command,
}
#[derive(Subcommand)]
pub enum Command {
/// Start the server
Serve {
#[arg(short, long, default_value = "3000")]
port: u16,
},
/// Run database migrations
Migrate,
/// Generate a secret key
GenKey,
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let cli = Cli::parse();
match cli.command {
Command::Serve { port } => serve(port).await?,
Command::Migrate => migrate().await?,
Command::GenKey => println!("{}", generate_key()),
}
Ok(())
}// Pre-allocate when size is known
let mut vec = Vec::with_capacity(items.len());
// Use &str instead of String in hot paths
fn is_valid(s: &str) -> bool { /* no allocation */ }
// Avoid unnecessary clones — use references
fn process(items: &[Item]) -> usize { items.len() }
// Use rayon for CPU-bound parallelism
use rayon::prelude::*;
let sum: u64 = big_vec.par_iter().map(|x| expensive(x)).sum();
// Use bytes::Bytes for zero-copy HTTP bodies
use bytes::Bytes;
async fn handler() -> Bytes {
Bytes::from_static(b"hello")
}
// Profile with cargo-flamegraph
// cargo install flamegraph
// cargo flamegraph --bin my-appunwrap() in tests or truly infallibletokio::task::spawn_blocking for CPU workcargo clippy -- -D warnings in CIClone on shared stateCargo.toml — use latest language features~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.