//! 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 { 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(), ); }