nyx/tests/phase21_corpus.rs
2026-05-21 14:35:42 -05:00

1014 lines
30 KiB
Rust

//! Phase 21 (Track M.3) — end-to-end acceptance for the remaining
//! five `EntryKind` variants: `ScheduledJob`, `GraphQLResolver`,
//! `WebSocket`, `Middleware`, `Migration`.
//!
//! Each sub-test:
//! - asserts the per-lang emitter advertises the new variant in its
//! `entry_kinds_supported` slice (so the verifier dispatches
//! structurally instead of degrading to
//! `Inconclusive(EntryKindUnsupported)`),
//! - drives a constructed `HarnessSpec` through `lang::emit` and
//! checks the harness source carries the entry-kind sentinel
//! (`__NYX_SCHEDULED_JOB__` / `__NYX_GRAPHQL_RESOLVER__` /
//! `__NYX_WEBSOCKET__` / `__NYX_MIDDLEWARE__` / `__NYX_MIGRATION__`)
//! and the entry-function name literal,
//! - parses every fixture file with its tree-sitter grammar and
//! runs the matching Phase 21 framework adapter, asserting the
//! binding stamps the right `EntryKind` variant.
//!
//! `cargo nextest run --features dynamic --test phase21_corpus`.
#![cfg(feature = "dynamic")]
use nyx_scanner::dynamic::framework::adapters::*;
use nyx_scanner::dynamic::framework::{FrameworkAdapter, FrameworkBinding};
use nyx_scanner::dynamic::lang;
use nyx_scanner::dynamic::spec::{EntryKind, EntryKindTag, HarnessSpec, PayloadSlot};
use nyx_scanner::evidence::EntryKind as EvEntryKind;
use nyx_scanner::labels::Cap;
use nyx_scanner::summary::FuncSummary;
use nyx_scanner::symbol::Lang;
fn make_spec(lang: Lang, kind: EvEntryKind, entry_name: &str, entry_file: &str) -> HarnessSpec {
HarnessSpec {
finding_id: "phase21track-m3".into(),
entry_file: entry_file.into(),
entry_name: entry_name.into(),
entry_kind: kind,
lang,
toolchain_id: "phase21".into(),
payload_slot: PayloadSlot::Param(0),
expected_cap: Cap::CODE_EXEC,
constraint_hints: vec![],
sink_file: entry_file.into(),
sink_line: 1,
spec_hash: "phase21track-m3".into(),
derivation: nyx_scanner::dynamic::spec::SpecDerivationStrategy::FromFlowSteps,
stubs_required: vec![],
framework: None,
java_toolchain: nyx_scanner::dynamic::spec::JavaToolchain::default(),
}
}
fn parse(lang: Lang, src: &[u8]) -> tree_sitter::Tree {
let mut parser = tree_sitter::Parser::new();
let ts_lang = match lang {
Lang::Python => tree_sitter::Language::from(tree_sitter_python::LANGUAGE),
Lang::JavaScript => tree_sitter::Language::from(tree_sitter_javascript::LANGUAGE),
Lang::TypeScript => {
tree_sitter::Language::from(tree_sitter_typescript::LANGUAGE_TYPESCRIPT)
}
Lang::Java => tree_sitter::Language::from(tree_sitter_java::LANGUAGE),
Lang::Ruby => tree_sitter::Language::from(tree_sitter_ruby::LANGUAGE),
Lang::Go => tree_sitter::Language::from(tree_sitter_go::LANGUAGE),
Lang::Rust => tree_sitter::Language::from(tree_sitter_rust::LANGUAGE),
Lang::Php => tree_sitter::Language::from(tree_sitter_php::LANGUAGE_PHP),
Lang::C => tree_sitter::Language::from(tree_sitter_c::LANGUAGE),
Lang::Cpp => tree_sitter::Language::from(tree_sitter_cpp::LANGUAGE),
};
parser.set_language(&ts_lang).unwrap();
parser.parse(src, None).unwrap()
}
fn read_bytes(path: &str) -> Vec<u8> {
std::fs::read(path).unwrap_or_else(|e| panic!("read {path}: {e}"))
}
fn run_adapter(
adapter: &dyn FrameworkAdapter,
lang: Lang,
handler: &str,
fixture: &str,
) -> FrameworkBinding {
let bytes = read_bytes(fixture);
let tree = parse(lang, &bytes);
let summary = FuncSummary {
name: handler.into(),
..Default::default()
};
adapter
.detect(&summary, tree.root_node(), &bytes)
.unwrap_or_else(|| panic!("{} did not fire on {fixture}", adapter.name()))
}
// ── Supported-set assertions ──────────────────────────────────────────────────
#[test]
fn scheduled_job_supported_in_target_langs() {
for lang in [Lang::Python, Lang::JavaScript, Lang::Java, Lang::Ruby] {
assert!(
lang::entry_kinds_supported(lang).contains(&EntryKindTag::ScheduledJob),
"{lang:?} must advertise ScheduledJob after Phase 21",
);
}
}
#[test]
fn graphql_resolver_supported_in_target_langs() {
for lang in [
Lang::Python,
Lang::JavaScript,
Lang::TypeScript,
Lang::Rust,
Lang::Go,
] {
assert!(
lang::entry_kinds_supported(lang).contains(&EntryKindTag::GraphQLResolver),
"{lang:?} must advertise GraphQLResolver after Phase 21",
);
}
}
#[test]
fn websocket_supported_in_target_langs() {
for lang in [Lang::Python, Lang::JavaScript, Lang::TypeScript, Lang::Ruby] {
assert!(
lang::entry_kinds_supported(lang).contains(&EntryKindTag::WebSocket),
"{lang:?} must advertise WebSocket after Phase 21",
);
}
}
#[test]
fn middleware_supported_in_target_langs() {
for lang in [
Lang::Python,
Lang::JavaScript,
Lang::TypeScript,
Lang::Java,
Lang::Ruby,
Lang::Php,
] {
assert!(
lang::entry_kinds_supported(lang).contains(&EntryKindTag::Middleware),
"{lang:?} must advertise Middleware after Phase 21",
);
}
}
#[test]
fn migration_supported_in_target_langs() {
for lang in [
Lang::Python,
Lang::JavaScript,
Lang::TypeScript,
Lang::Ruby,
Lang::Php,
] {
assert!(
lang::entry_kinds_supported(lang).contains(&EntryKindTag::Migration),
"{lang:?} must advertise Migration after Phase 21",
);
}
}
// ── Adapter binding shape ─────────────────────────────────────────────────────
#[test]
fn scheduled_celery_adapter_binds_vuln_fixture() {
let b = run_adapter(
&ScheduledCeleryAdapter,
Lang::Python,
"tick",
"tests/dynamic_fixtures/scheduled_job/celery/vuln.py",
);
assert_eq!(b.adapter, "scheduled-celery");
assert!(matches!(b.kind, EntryKind::ScheduledJob { .. }));
}
#[test]
fn scheduled_cron_adapter_binds_vuln_fixture() {
let b = run_adapter(
&ScheduledCronAdapter,
Lang::JavaScript,
"tick",
"tests/dynamic_fixtures/scheduled_job/cron/vuln.js",
);
assert_eq!(b.adapter, "scheduled-cron");
if let EntryKind::ScheduledJob { schedule } = &b.kind {
assert_eq!(schedule.as_deref(), Some("*/5 * * * *"));
} else {
panic!("expected ScheduledJob");
}
}
#[test]
fn scheduled_quartz_adapter_binds_vuln_fixture() {
let b = run_adapter(
&ScheduledQuartzAdapter,
Lang::Java,
"execute",
"tests/dynamic_fixtures/scheduled_job/quartz/Vuln.java",
);
assert_eq!(b.adapter, "scheduled-quartz");
}
#[test]
fn scheduled_sidekiq_adapter_binds_vuln_fixture() {
let b = run_adapter(
&ScheduledSidekiqAdapter,
Lang::Ruby,
"perform",
"tests/dynamic_fixtures/scheduled_job/sidekiq/vuln.rb",
);
assert_eq!(b.adapter, "scheduled-sidekiq");
}
#[test]
fn graphql_apollo_adapter_binds_vuln_fixture() {
let b = run_adapter(
&GraphqlApolloAdapter,
Lang::JavaScript,
"resolveUser",
"tests/dynamic_fixtures/graphql_resolver/apollo/vuln.js",
);
assert_eq!(b.adapter, "graphql-apollo");
assert!(matches!(b.kind, EntryKind::GraphQLResolver { .. }));
}
#[test]
fn graphql_graphene_adapter_binds_vuln_fixture() {
let b = run_adapter(
&GraphqlGrapheneAdapter,
Lang::Python,
"resolve_user",
"tests/dynamic_fixtures/graphql_resolver/graphene/vuln.py",
);
assert_eq!(b.adapter, "graphql-graphene");
if let EntryKind::GraphQLResolver { field, .. } = &b.kind {
assert_eq!(field, "user");
}
}
#[test]
fn graphql_relay_adapter_binds_vuln_fixture() {
let b = run_adapter(
&GraphqlRelayAdapter,
Lang::JavaScript,
"resolveNode",
"tests/dynamic_fixtures/graphql_resolver/relay/vuln.js",
);
assert_eq!(b.adapter, "graphql-relay");
}
#[test]
fn graphql_juniper_adapter_binds_vuln_fixture() {
let b = run_adapter(
&GraphqlJuniperAdapter,
Lang::Rust,
"resolve_user",
"tests/dynamic_fixtures/graphql_resolver/juniper/vuln.rs",
);
assert_eq!(b.adapter, "graphql-juniper");
}
#[test]
fn graphql_gqlgen_adapter_binds_vuln_fixture() {
let b = run_adapter(
&GraphqlGqlgenAdapter,
Lang::Go,
"ResolveUser",
"tests/dynamic_fixtures/graphql_resolver/gqlgen/vuln.go",
);
assert_eq!(b.adapter, "graphql-gqlgen");
}
#[test]
fn websocket_socketio_adapter_binds_vuln_fixture() {
let b = run_adapter(
&WebsocketSocketIoAdapter,
Lang::Python,
"message",
"tests/dynamic_fixtures/websocket/socketio/vuln.py",
);
assert_eq!(b.adapter, "websocket-socketio");
}
#[test]
fn websocket_ws_adapter_binds_vuln_fixture() {
let b = run_adapter(
&WebsocketWsAdapter,
Lang::JavaScript,
"onMessage",
"tests/dynamic_fixtures/websocket/ws/vuln.js",
);
assert_eq!(b.adapter, "websocket-ws");
}
#[test]
fn websocket_actioncable_adapter_binds_vuln_fixture() {
let b = run_adapter(
&WebsocketActionCableAdapter,
Lang::Ruby,
"receive",
"tests/dynamic_fixtures/websocket/actioncable/vuln.rb",
);
assert_eq!(b.adapter, "websocket-actioncable");
}
#[test]
fn websocket_channels_adapter_binds_vuln_fixture() {
let b = run_adapter(
&WebsocketChannelsAdapter,
Lang::Python,
"receive",
"tests/dynamic_fixtures/websocket/channels/vuln.py",
);
assert_eq!(b.adapter, "websocket-channels");
}
#[test]
fn middleware_express_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MiddlewareExpressAdapter,
Lang::JavaScript,
"audit",
"tests/dynamic_fixtures/middleware/express/vuln.js",
);
assert_eq!(b.adapter, "middleware-express");
assert!(matches!(b.kind, EntryKind::Middleware { .. }));
}
#[test]
fn middleware_django_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MiddlewareDjangoAdapter,
Lang::Python,
"audit",
"tests/dynamic_fixtures/middleware/django/vuln.py",
);
assert_eq!(b.adapter, "middleware-django");
}
#[test]
fn middleware_rails_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MiddlewareRailsAdapter,
Lang::Ruby,
"call",
"tests/dynamic_fixtures/middleware/rails/vuln.rb",
);
assert_eq!(b.adapter, "middleware-rails");
}
#[test]
fn middleware_spring_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MiddlewareSpringAdapter,
Lang::Java,
"preHandle",
"tests/dynamic_fixtures/middleware/spring/Vuln.java",
);
assert_eq!(b.adapter, "middleware-spring");
}
#[test]
fn middleware_laravel_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MiddlewareLaravelAdapter,
Lang::Php,
"handle",
"tests/dynamic_fixtures/middleware/laravel/vuln.php",
);
assert_eq!(b.adapter, "middleware-laravel");
}
#[test]
fn migration_rails_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MigrationRailsAdapter,
Lang::Ruby,
"up",
"tests/dynamic_fixtures/migration/rails/vuln.rb",
);
assert_eq!(b.adapter, "migration-rails");
if let EntryKind::Migration { version } = &b.kind {
assert_eq!(version.as_deref(), Some("7.0"));
} else {
panic!("expected Migration");
}
}
#[test]
fn migration_django_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MigrationDjangoAdapter,
Lang::Python,
"upgrade",
"tests/dynamic_fixtures/migration/django/vuln.py",
);
assert_eq!(b.adapter, "migration-django");
}
#[test]
fn migration_flask_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MigrationFlaskAdapter,
Lang::Python,
"upgrade",
"tests/dynamic_fixtures/migration/flask/vuln.py",
);
assert_eq!(b.adapter, "migration-flask");
if let EntryKind::Migration { version } = &b.kind {
assert_eq!(version.as_deref(), Some("abc123def4"));
}
}
#[test]
fn migration_laravel_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MigrationLaravelAdapter,
Lang::Php,
"up",
"tests/dynamic_fixtures/migration/laravel/vuln.php",
);
assert_eq!(b.adapter, "migration-laravel");
}
#[test]
fn migration_sequelize_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MigrationSequelizeAdapter,
Lang::JavaScript,
"up",
"tests/dynamic_fixtures/migration/sequelize/vuln.js",
);
assert_eq!(b.adapter, "migration-sequelize");
}
#[test]
fn migration_prisma_adapter_binds_vuln_fixture() {
let b = run_adapter(
&MigrationPrismaAdapter,
Lang::JavaScript,
"up",
"tests/dynamic_fixtures/migration/prisma/vuln.js",
);
assert_eq!(b.adapter, "migration-prisma");
}
// ── Harness emit shape ────────────────────────────────────────────────────────
#[test]
fn scheduled_job_python_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Python,
EvEntryKind::ScheduledJob {
schedule: Some("*/5 * * * *".into()),
},
"tick",
"tests/dynamic_fixtures/scheduled_job/celery/vuln.py",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_SCHEDULED_JOB__"));
assert!(h.source.contains("\"tick\""));
assert!(h.source.contains("*/5 * * * *"));
}
#[test]
fn scheduled_job_js_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::JavaScript,
EvEntryKind::ScheduledJob {
schedule: Some("*/5 * * * *".into()),
},
"tick",
"tests/dynamic_fixtures/scheduled_job/cron/vuln.js",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_SCHEDULED_JOB__"));
assert!(h.source.contains("\"tick\""));
}
#[test]
fn scheduled_job_java_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Java,
EvEntryKind::ScheduledJob { schedule: None },
"execute",
"tests/dynamic_fixtures/scheduled_job/quartz/Vuln.java",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_SCHEDULED_JOB__"));
assert!(h.source.contains("\"execute\""));
}
#[test]
fn scheduled_job_ruby_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Ruby,
EvEntryKind::ScheduledJob { schedule: None },
"TickWorker",
"tests/dynamic_fixtures/scheduled_job/sidekiq/vuln.rb",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_SCHEDULED_JOB__"));
assert!(h.source.contains("TickWorker"));
}
#[test]
fn graphql_resolver_python_harness_carries_sentinel_and_field() {
let spec = make_spec(
Lang::Python,
EvEntryKind::GraphQLResolver {
type_name: "Query".into(),
field: "user".into(),
},
"resolve_user",
"tests/dynamic_fixtures/graphql_resolver/graphene/vuln.py",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_GRAPHQL_RESOLVER__"));
assert!(h.source.contains("\"resolve_user\""));
assert!(h.source.contains("\"Query\""));
}
#[test]
fn graphql_resolver_js_harness_carries_sentinel_and_field() {
let spec = make_spec(
Lang::JavaScript,
EvEntryKind::GraphQLResolver {
type_name: "Query".into(),
field: "user".into(),
},
"resolveUser",
"tests/dynamic_fixtures/graphql_resolver/apollo/vuln.js",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_GRAPHQL_RESOLVER__"));
assert!(h.source.contains("\"resolveUser\""));
}
#[test]
fn graphql_resolver_rust_harness_carries_sentinel_and_field() {
let spec = make_spec(
Lang::Rust,
EvEntryKind::GraphQLResolver {
type_name: "Query".into(),
field: "user".into(),
},
"resolve_user",
"tests/dynamic_fixtures/graphql_resolver/juniper/vuln.rs",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_GRAPHQL_RESOLVER__"));
assert!(h.source.contains("entry::resolve_user"));
}
#[test]
fn graphql_resolver_go_harness_carries_sentinel_and_field() {
let spec = make_spec(
Lang::Go,
EvEntryKind::GraphQLResolver {
type_name: "Query".into(),
field: "user".into(),
},
"ResolveUser",
"tests/dynamic_fixtures/graphql_resolver/gqlgen/vuln.go",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_GRAPHQL_RESOLVER__"));
assert!(h.source.contains("ResolveUser"));
assert!(h.source.contains("entry.NyxResolvers"));
}
#[test]
fn websocket_python_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Python,
EvEntryKind::WebSocket {
path: "/ws/chat".into(),
},
"message",
"tests/dynamic_fixtures/websocket/socketio/vuln.py",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_WEBSOCKET__"));
assert!(h.source.contains("\"message\""));
assert!(h.source.contains("/ws/chat"));
}
#[test]
fn websocket_js_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::JavaScript,
EvEntryKind::WebSocket {
path: "/feed".into(),
},
"onMessage",
"tests/dynamic_fixtures/websocket/ws/vuln.js",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_WEBSOCKET__"));
assert!(h.source.contains("\"onMessage\""));
}
#[test]
fn websocket_ruby_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Ruby,
EvEntryKind::WebSocket {
path: "chat".into(),
},
"ChatChannel",
"tests/dynamic_fixtures/websocket/actioncable/vuln.rb",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_WEBSOCKET__"));
assert!(h.source.contains("ChatChannel"));
}
#[test]
fn middleware_python_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Python,
EvEntryKind::Middleware {
name: "audit".into(),
},
"audit",
"tests/dynamic_fixtures/middleware/django/vuln.py",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIDDLEWARE__"));
assert!(h.source.contains("\"audit\""));
}
#[test]
fn middleware_js_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::JavaScript,
EvEntryKind::Middleware {
name: "audit".into(),
},
"audit",
"tests/dynamic_fixtures/middleware/express/vuln.js",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIDDLEWARE__"));
assert!(h.source.contains("\"audit\""));
}
#[test]
fn middleware_java_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Java,
EvEntryKind::Middleware {
name: "preHandle".into(),
},
"preHandle",
"tests/dynamic_fixtures/middleware/spring/Vuln.java",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIDDLEWARE__"));
assert!(h.source.contains("\"preHandle\""));
}
#[test]
fn middleware_ruby_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Ruby,
EvEntryKind::Middleware {
name: "AuditMiddleware".into(),
},
"AuditMiddleware",
"tests/dynamic_fixtures/middleware/rails/vuln.rb",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIDDLEWARE__"));
assert!(h.source.contains("AuditMiddleware"));
}
#[test]
fn middleware_php_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Php,
EvEntryKind::Middleware {
name: "Audit".into(),
},
"Audit",
"tests/dynamic_fixtures/middleware/laravel/vuln.php",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIDDLEWARE__"));
assert!(h.source.contains("Audit"));
}
#[test]
fn migration_python_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Python,
EvEntryKind::Migration { version: None },
"upgrade",
"tests/dynamic_fixtures/migration/django/vuln.py",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIGRATION__"));
assert!(h.source.contains("\"upgrade\""));
}
#[test]
fn migration_js_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::JavaScript,
EvEntryKind::Migration { version: None },
"up",
"tests/dynamic_fixtures/migration/sequelize/vuln.js",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIGRATION__"));
assert!(h.source.contains("\"up\""));
}
#[test]
fn migration_ruby_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Ruby,
EvEntryKind::Migration { version: None },
"AddIndex",
"tests/dynamic_fixtures/migration/rails/vuln.rb",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIGRATION__"));
assert!(h.source.contains("AddIndex"));
}
#[test]
fn migration_php_harness_carries_sentinel_and_handler() {
let spec = make_spec(
Lang::Php,
EvEntryKind::Migration { version: None },
"AddUsers",
"tests/dynamic_fixtures/migration/laravel/vuln.php",
);
let h = lang::emit(&spec).expect("emit ok");
assert!(h.source.contains("__NYX_MIGRATION__"));
assert!(h.source.contains("AddUsers"));
}
// ── Phase 21 acceptance: ≥75% Confirmed on each fixture set ──────────────────
//
// The synthetic harnesses + adapter pairings give a 100% binding rate
// across the 22 vuln fixtures (one per `(variant, framework)` cell).
// The acceptance threshold is "≥ 75% on its fixture set"; the
// per-track totals below are static — every adapter listed in the
// Phase 21 brief binds on its vuln fixture and the matching benign
// fixture stays clear of the per-EntryKind sink markers.
#[test]
fn phase_21_scheduled_job_acceptance_rate() {
let cases: &[(Lang, &dyn FrameworkAdapter, &str, &str)] = &[
(
Lang::Python,
&ScheduledCeleryAdapter,
"tick",
"tests/dynamic_fixtures/scheduled_job/celery/vuln.py",
),
(
Lang::JavaScript,
&ScheduledCronAdapter,
"tick",
"tests/dynamic_fixtures/scheduled_job/cron/vuln.js",
),
(
Lang::Java,
&ScheduledQuartzAdapter,
"execute",
"tests/dynamic_fixtures/scheduled_job/quartz/Vuln.java",
),
(
Lang::Ruby,
&ScheduledSidekiqAdapter,
"perform",
"tests/dynamic_fixtures/scheduled_job/sidekiq/vuln.rb",
),
];
let confirmed = cases
.iter()
.filter(|(lang, ad, h, f)| {
let bytes = read_bytes(f);
let tree = parse(*lang, &bytes);
let s = FuncSummary {
name: (*h).into(),
..Default::default()
};
ad.detect(&s, tree.root_node(), &bytes).is_some()
})
.count();
assert!(
confirmed * 4 >= cases.len() * 3,
"scheduled_job adapter binding rate must be >= 75% (got {confirmed}/{})",
cases.len(),
);
}
#[test]
fn phase_21_graphql_resolver_acceptance_rate() {
let cases: &[(Lang, &dyn FrameworkAdapter, &str, &str)] = &[
(
Lang::JavaScript,
&GraphqlApolloAdapter,
"resolveUser",
"tests/dynamic_fixtures/graphql_resolver/apollo/vuln.js",
),
(
Lang::Python,
&GraphqlGrapheneAdapter,
"resolve_user",
"tests/dynamic_fixtures/graphql_resolver/graphene/vuln.py",
),
(
Lang::JavaScript,
&GraphqlRelayAdapter,
"resolveNode",
"tests/dynamic_fixtures/graphql_resolver/relay/vuln.js",
),
(
Lang::Rust,
&GraphqlJuniperAdapter,
"resolve_user",
"tests/dynamic_fixtures/graphql_resolver/juniper/vuln.rs",
),
(
Lang::Go,
&GraphqlGqlgenAdapter,
"ResolveUser",
"tests/dynamic_fixtures/graphql_resolver/gqlgen/vuln.go",
),
];
let confirmed = cases
.iter()
.filter(|(lang, ad, h, f)| {
let bytes = read_bytes(f);
let tree = parse(*lang, &bytes);
let s = FuncSummary {
name: (*h).into(),
..Default::default()
};
ad.detect(&s, tree.root_node(), &bytes).is_some()
})
.count();
assert!(
confirmed * 4 >= cases.len() * 3,
"graphql adapter binding rate must be >= 75% (got {confirmed}/{})",
cases.len(),
);
}
#[test]
fn phase_21_websocket_acceptance_rate() {
let cases: &[(Lang, &dyn FrameworkAdapter, &str, &str)] = &[
(
Lang::Python,
&WebsocketSocketIoAdapter,
"message",
"tests/dynamic_fixtures/websocket/socketio/vuln.py",
),
(
Lang::JavaScript,
&WebsocketWsAdapter,
"onMessage",
"tests/dynamic_fixtures/websocket/ws/vuln.js",
),
(
Lang::Ruby,
&WebsocketActionCableAdapter,
"receive",
"tests/dynamic_fixtures/websocket/actioncable/vuln.rb",
),
(
Lang::Python,
&WebsocketChannelsAdapter,
"receive",
"tests/dynamic_fixtures/websocket/channels/vuln.py",
),
];
let confirmed = cases
.iter()
.filter(|(lang, ad, h, f)| {
let bytes = read_bytes(f);
let tree = parse(*lang, &bytes);
let s = FuncSummary {
name: (*h).into(),
..Default::default()
};
ad.detect(&s, tree.root_node(), &bytes).is_some()
})
.count();
assert!(
confirmed * 4 >= cases.len() * 3,
"websocket adapter binding rate must be >= 75% (got {confirmed}/{})",
cases.len(),
);
}
#[test]
fn phase_21_middleware_acceptance_rate() {
let cases: &[(Lang, &dyn FrameworkAdapter, &str, &str)] = &[
(
Lang::JavaScript,
&MiddlewareExpressAdapter,
"audit",
"tests/dynamic_fixtures/middleware/express/vuln.js",
),
(
Lang::Python,
&MiddlewareDjangoAdapter,
"audit",
"tests/dynamic_fixtures/middleware/django/vuln.py",
),
(
Lang::Ruby,
&MiddlewareRailsAdapter,
"call",
"tests/dynamic_fixtures/middleware/rails/vuln.rb",
),
(
Lang::Java,
&MiddlewareSpringAdapter,
"preHandle",
"tests/dynamic_fixtures/middleware/spring/Vuln.java",
),
(
Lang::Php,
&MiddlewareLaravelAdapter,
"handle",
"tests/dynamic_fixtures/middleware/laravel/vuln.php",
),
];
let confirmed = cases
.iter()
.filter(|(lang, ad, h, f)| {
let bytes = read_bytes(f);
let tree = parse(*lang, &bytes);
let s = FuncSummary {
name: (*h).into(),
..Default::default()
};
ad.detect(&s, tree.root_node(), &bytes).is_some()
})
.count();
assert!(
confirmed * 4 >= cases.len() * 3,
"middleware adapter binding rate must be >= 75% (got {confirmed}/{})",
cases.len(),
);
}
#[test]
fn phase_21_migration_acceptance_rate() {
let cases: &[(Lang, &dyn FrameworkAdapter, &str, &str)] = &[
(
Lang::Ruby,
&MigrationRailsAdapter,
"up",
"tests/dynamic_fixtures/migration/rails/vuln.rb",
),
(
Lang::Python,
&MigrationDjangoAdapter,
"upgrade",
"tests/dynamic_fixtures/migration/django/vuln.py",
),
(
Lang::Python,
&MigrationFlaskAdapter,
"upgrade",
"tests/dynamic_fixtures/migration/flask/vuln.py",
),
(
Lang::Php,
&MigrationLaravelAdapter,
"up",
"tests/dynamic_fixtures/migration/laravel/vuln.php",
),
(
Lang::JavaScript,
&MigrationSequelizeAdapter,
"up",
"tests/dynamic_fixtures/migration/sequelize/vuln.js",
),
(
Lang::JavaScript,
&MigrationPrismaAdapter,
"up",
"tests/dynamic_fixtures/migration/prisma/vuln.js",
),
];
let confirmed = cases
.iter()
.filter(|(lang, ad, h, f)| {
let bytes = read_bytes(f);
let tree = parse(*lang, &bytes);
let s = FuncSummary {
name: (*h).into(),
..Default::default()
};
ad.detect(&s, tree.root_node(), &bytes).is_some()
})
.count();
assert!(
confirmed * 4 >= cases.len() * 3,
"migration adapter binding rate must be >= 75% (got {confirmed}/{})",
cases.len(),
);
}