Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
395 changes: 390 additions & 5 deletions drift v3/crates/drift-engine/src/check_command.rs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions drift v3/crates/drift-engine/src/facts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ pub enum FactKind {
RouteDeclared,
FileRoleDetected,
TestDeclared,
AuthGuardCalled,
RouteReturnsResponse,
CallbackBoundaryDetected,
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down
27 changes: 27 additions & 0 deletions drift v3/crates/drift-engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ pub const DRIFT_ENGINE_VERSION: &str = "0.1.0";
mod diff;
mod facts;
mod rules;
mod security_capabilities;
mod security_control_flow;
mod security_facts;
mod security_patterns;
mod security_proof;
mod security_rules;

use std::{
fs::File,
Expand All @@ -23,6 +29,27 @@ pub use rules::{
Severity, classify_findings_against_baseline, detect_direct_data_access_imports,
materialize_direct_data_access_findings,
};
pub use security_capabilities::{
SecurityCapabilityStatus, SecurityScanCapability, security_capabilities,
};
pub use security_control_flow::{
MatchedMiddleware, MiddlewareMismatch, static_middleware_coverage,
};
pub use security_facts::extract_security_facts;
pub use security_patterns::{
AcceptedAuthHelper, AuthGuardBehavior, dynamic_middleware_matcher_line,
};
pub use security_proof::{
AuthBoundaryProof, MiddlewareBoundaryProof, RouteSecurityBoundaryProof, SecurityBoundaryProof,
SecurityParserGap, SecurityProofResult, SecurityProofStatus, TrustedGuardCallProof,
UndominatedSinkProof, build_auth_boundary_proof, build_auth_boundary_proofs_for_file,
build_middleware_coverage_proof,
};
pub use security_rules::{
SecurityAuthContract, SecurityContractCapability, SecurityEnforcementMode, SecurityFinding,
SecurityFindingResult, SecurityMiddlewareContract, evaluate_api_route_requires_auth_helper,
evaluate_api_route_requires_auth_helper_with_middleware, evaluate_middleware_must_cover_routes,
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FileFingerprint {
Expand Down
14 changes: 9 additions & 5 deletions drift v3/crates/drift-engine/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ mod protocol;

use candidate_command::infer_candidates;
use check_command::check_repo;
use drift_engine::{Fact, FactKind, extract_typescript_facts, should_index_path};
use drift_engine::{
Fact, FactKind, extract_security_facts, extract_typescript_facts, should_index_path,
};
use protocol::*;
use serde_json::json;
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -406,10 +408,9 @@ fn scan_file_with_reuse(
return Ok(Some((file, reused_facts, true)));
}
let source = fs::read_to_string(&absolute_path)?;
let facts = extract_typescript_facts(file_path, &source)?
.into_iter()
.map(engine_fact)
.collect();
let mut facts = extract_typescript_facts(file_path, &source)?;
facts.extend(extract_security_facts(file_path, &source, &[])?);
let facts = facts.into_iter().map(engine_fact).collect();
Ok(Some((file, facts, false)))
}

Expand Down Expand Up @@ -618,6 +619,9 @@ fn fact_kind(kind: FactKind) -> &'static str {
FactKind::RouteDeclared => "route_declared",
FactKind::FileRoleDetected => "file_role_detected",
FactKind::TestDeclared => "test_declared",
FactKind::AuthGuardCalled => "auth_guard_called",
FactKind::RouteReturnsResponse => "route_returns_response",
FactKind::CallbackBoundaryDetected => "callback_boundary_detected",
}
}

Expand Down
25 changes: 25 additions & 0 deletions drift v3/crates/drift-engine/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ pub struct CheckGraphData {
#[derive(Debug, Deserialize)]
pub struct CheckRepoContext {
pub repo_id: String,
#[serde(default)]
pub repo_root: Option<String>,
}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -308,14 +310,30 @@ pub struct EngineCandidateEvidenceRef {

#[derive(Debug, Deserialize)]
pub struct CheckContract {
#[serde(default)]
pub contract_id: Option<String>,
#[serde(default)]
pub contract_schema_version: Option<usize>,
pub conventions: Vec<CheckConvention>,
#[serde(default)]
pub waivers: Vec<Value>,
#[serde(default)]
pub exceptions: Vec<Value>,
}

#[derive(Debug, Deserialize)]
pub struct CheckConvention {
pub id: String,
pub kind: String,
pub matcher: CheckMatcher,
#[serde(default)]
pub requires: Option<Value>,
#[serde(default)]
pub scope: Option<Value>,
#[serde(default)]
pub exceptions: Vec<Value>,
#[serde(default)]
pub governance: Option<Value>,
pub severity: String,
pub enforcement_mode: String,
pub enforcement_capability: String,
Expand All @@ -325,6 +343,8 @@ pub struct CheckConvention {
pub struct CheckMatcher {
pub forbidden_imports: Option<Vec<String>>,
pub allowed_delegate_imports: Option<Vec<String>>,
pub required_calls: Option<Vec<String>>,
pub applies_to_file_roles: Option<Vec<String>>,
}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -356,6 +376,8 @@ pub struct CheckResult {
pub adapter_versions: BTreeMap<String, String>,
pub diff_mode: String,
pub findings: Vec<CheckFinding>,
#[serde(default)]
pub security_boundary_proofs: Vec<Value>,
pub diagnostics: Vec<EngineDiagnostic>,
pub stats: EngineStats,
pub completeness: Vec<EngineCompleteness>,
Expand Down Expand Up @@ -499,12 +521,15 @@ pub fn capability_stats(required: &[&str], missing: &[&str]) -> EngineCapability
pub fn certified_capabilities() -> Vec<String> {
[
"candidate_inference",
"auth_boundary_facts",
"control_flow_guard_dominance",
"data_operation_detection",
"direct_data_access_check",
"file_discovery",
"graph_stream",
"import_resolution",
"route_detection",
"security_facts",
"symbol_linking",
"syntax_facts",
]
Expand Down
42 changes: 42 additions & 0 deletions drift v3/crates/drift-engine/src/security_capabilities.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SecurityCapabilityStatus {
Complete,
Partial,
Unsupported,
Failed,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SecurityScanCapability {
pub name: String,
pub capability: String,
pub status: SecurityCapabilityStatus,
pub can_block: bool,
pub block_requires_accepted_convention: bool,
}

pub fn security_capabilities() -> Vec<SecurityScanCapability> {
vec![
SecurityScanCapability {
name: "security_facts".to_string(),
capability: "deterministic_check".to_string(),
status: SecurityCapabilityStatus::Partial,
can_block: false,
block_requires_accepted_convention: true,
},
SecurityScanCapability {
name: "auth_boundary_facts".to_string(),
capability: "deterministic_check".to_string(),
status: SecurityCapabilityStatus::Partial,
can_block: true,
block_requires_accepted_convention: true,
},
SecurityScanCapability {
name: "control_flow_guard_dominance".to_string(),
capability: "deterministic_check".to_string(),
status: SecurityCapabilityStatus::Partial,
can_block: true,
block_requires_accepted_convention: true,
},
]
}
Loading
Loading