fix failing tests and rules

This commit is contained in:
elipeter 2026-06-03 16:24:11 -05:00
parent ddf9ff13e2
commit 7fe1abda8b
4 changed files with 57 additions and 22 deletions

View file

@ -135,7 +135,7 @@ The tables below are generated from `src/patterns/<lang>.rs` by [`tools/docgen`]
| `java.sqli.execute_concat` | Medium | B | Medium | | `java.sqli.execute_concat` | Medium | B | Medium |
| `java.crypto.insecure_random` | Low | A | Medium | | `java.crypto.insecure_random` | Low | A | Medium |
### JavaScript: 22 patterns ### JavaScript: 23 patterns
| Rule ID | Severity | Tier | Confidence | | Rule ID | Severity | Tier | Confidence |
|---|---|---|---| |---|---|---|---|
@ -157,6 +157,7 @@ The tables below are generated from `src/patterns/<lang>.rs` by [`tools/docgen`]
| `js.xss.outer_html` | Medium | A | High | | `js.xss.outer_html` | Medium | A | High |
| `js.config.insecure_session_samesite` | Low | A | High | | `js.config.insecure_session_samesite` | Low | A | High |
| `js.config.insecure_session_secure` | Low | A | Medium | | `js.config.insecure_session_secure` | Low | A | Medium |
| `js.crypto.hardcoded_key` | Low | A | Medium |
| `js.crypto.math_random` | Low | A | Medium | | `js.crypto.math_random` | Low | A | Medium |
| `js.crypto.weak_hash` | Low | A | Medium | | `js.crypto.weak_hash` | Low | A | Medium |
| `js.secrets.hardcoded_secret` | Low | A | Medium | | `js.secrets.hardcoded_secret` | Low | A | Medium |
@ -234,7 +235,7 @@ The tables below are generated from `src/patterns/<lang>.rs` by [`tools/docgen`]
| `rs.quality.todo` | Low | A | High | | `rs.quality.todo` | Low | A | High |
| `rs.quality.unwrap` | Low | A | High | | `rs.quality.unwrap` | Low | A | High |
### TypeScript: 22 patterns ### TypeScript: 23 patterns
| Rule ID | Severity | Tier | Confidence | | Rule ID | Severity | Tier | Confidence |
|---|---|---|---| |---|---|---|---|
@ -254,6 +255,7 @@ The tables below are generated from `src/patterns/<lang>.rs` by [`tools/docgen`]
| `ts.xss.outer_html` | Medium | A | High | | `ts.xss.outer_html` | Medium | A | High |
| `ts.config.insecure_session_samesite` | Low | A | High | | `ts.config.insecure_session_samesite` | Low | A | High |
| `ts.config.insecure_session_secure` | Low | A | Medium | | `ts.config.insecure_session_secure` | Low | A | Medium |
| `ts.crypto.hardcoded_key` | Low | A | Medium |
| `ts.crypto.math_random` | Low | A | Medium | | `ts.crypto.math_random` | Low | A | Medium |
| `ts.crypto.weak_hash` | Low | A | Medium | | `ts.crypto.weak_hash` | Low | A | Medium |
| `ts.quality.any_annotation` | Low | A | Medium | | `ts.quality.any_annotation` | Low | A | Medium |

View file

@ -1156,7 +1156,7 @@ func nyxFollowLocation(location string) {{
fn generate_main_go(spec: &HarnessSpec, shape: GoShape) -> String { fn generate_main_go(spec: &HarnessSpec, shape: GoShape) -> String {
let entry_fn = capitalize_first(&spec.entry_name); let entry_fn = capitalize_first(&spec.entry_name);
let pre_call = pre_call_setup(spec); let pre_call = pre_call_setup(spec);
let imports = imports_for_shape(shape); let imports = imports_for_shape(shape, spec);
let invocation = invoke_for_shape(spec, shape, &entry_fn); let invocation = invoke_for_shape(spec, shape, &entry_fn);
let shim = probe_shim(); let shim = probe_shim();
@ -1200,17 +1200,36 @@ func nyxPayload() string {{
/// against per-shape additions in [`imports_for_shape`]. /// against per-shape additions in [`imports_for_shape`].
const SHIM_IMPORTS: &[&str] = &["encoding/json", "os/signal", "strings", "syscall", "time"]; const SHIM_IMPORTS: &[&str] = &["encoding/json", "os/signal", "strings", "syscall", "time"];
fn imports_for_shape(shape: GoShape) -> String { fn imports_for_shape(shape: GoShape, spec: &HarnessSpec) -> String {
let stdlib_base: &[&str] = &["encoding/base64", "os"]; let stdlib_base: &[&str] = &["encoding/base64", "os"];
let shape_extras: &[&str] = match shape { let use_body = matches!(&spec.payload_slot, PayloadSlot::HttpBody);
GoShape::Generic | GoShape::FlagParseCli | GoShape::FuzzVariadic => &[], let mut shape_extras: Vec<&str> = match shape {
GoShape::HttpHandlerFunc => &["net/http", "net/http/httptest"], GoShape::Generic | GoShape::FlagParseCli | GoShape::FuzzVariadic => vec![],
GoShape::GinHandler => &["net/http", "net/http/httptest"], GoShape::HttpHandlerFunc | GoShape::GinHandler => vec!["net/http", "net/http/httptest"],
GoShape::GinRoute | GoShape::EchoRoute | GoShape::ChiRoute => { GoShape::GinRoute | GoShape::EchoRoute | GoShape::ChiRoute => {
&["fmt", "net/http", "net/http/httptest", "net/url"] vec!["fmt", "net/http", "net/http/httptest"]
}
GoShape::FiberRoute => {
if use_body {
vec!["fmt", "net/http", "net/http/httptest"]
} else {
vec!["fmt", "net/http"]
}
} }
GoShape::FiberRoute => &["fmt", "net/http", "net/url"],
}; };
if !use_body
&& matches!(
shape,
GoShape::HttpHandlerFunc
| GoShape::GinHandler
| GoShape::GinRoute
| GoShape::EchoRoute
| GoShape::FiberRoute
| GoShape::ChiRoute
)
{
shape_extras.push("net/url");
}
let local_pkgs: &[&str] = match shape { let local_pkgs: &[&str] = match shape {
GoShape::GinHandler => &["nyx-harness/entry", "nyx-harness/entry/gin"], GoShape::GinHandler => &["nyx-harness/entry", "nyx-harness/entry/gin"],
GoShape::GinRoute => &["github.com/gin-gonic/gin", "nyx-harness/entry"], GoShape::GinRoute => &["github.com/gin-gonic/gin", "nyx-harness/entry"],
@ -1283,8 +1302,8 @@ fn invoke_for_shape(spec: &HarnessSpec, shape: GoShape, entry_fn: &str) -> Strin
String::new() String::new()
} else { } else {
format!( format!(
"\treq := httptest.NewRequest(\"GET\", \"/?{q}=\"+payload, strings.NewReader(\"\"))\n", "\treq := httptest.NewRequest(\"GET\", \"/?\"+url.QueryEscape({q})+\"=\"+url.QueryEscape(payload), strings.NewReader(\"\"))\n",
q = query_param q = go_string_literal(&query_param)
) )
}; };
format!( format!(
@ -1294,8 +1313,12 @@ fn invoke_for_shape(spec: &HarnessSpec, shape: GoShape, entry_fn: &str) -> Strin
GoShape::GinHandler => { GoShape::GinHandler => {
let setup = if use_body { let setup = if use_body {
"\treq := httptest.NewRequest(\"POST\", \"/\", strings.NewReader(payload))\n" "\treq := httptest.NewRequest(\"POST\", \"/\", strings.NewReader(payload))\n"
.to_owned()
} else { } else {
"\treq := httptest.NewRequest(\"GET\", \"/?payload=\"+payload, strings.NewReader(\"\"))\n" format!(
"\treq := httptest.NewRequest(\"GET\", \"/?\"+url.QueryEscape({q})+\"=\"+url.QueryEscape(payload), strings.NewReader(\"\"))\n",
q = go_string_literal(&query_param)
)
}; };
format!( format!(
"{setup}\trw := httptest.NewRecorder()\n\tctx := gin.NewContext(rw, req)\n\tentry.{entry_fn}(ctx)\n\t_ = http.StatusOK\n", "{setup}\trw := httptest.NewRecorder()\n\tctx := gin.NewContext(rw, req)\n\tentry.{entry_fn}(ctx)\n\t_ = http.StatusOK\n",

View file

@ -56,8 +56,8 @@ pub enum CopyStrategy {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[allow(dead_code)] #[allow(dead_code)]
pub enum Prerequisite { pub enum Prerequisite {
/// A binary must resolve on `PATH` and respond to `--version` with /// A binary must resolve on `PATH` and respond to its version probe with
/// exit code 0 (e.g. `python3`, `node`, `go`, `cargo`). /// exit code 0 (usually `--version`; Go uses `go version`).
CommandAvailable(&'static str), CommandAvailable(&'static str),
/// A specific env var must be set (used to gate feature-flagged /// A specific env var must be set (used to gate feature-flagged
/// suites — e.g. `NYX_ENABLE_FLAKY_FIXTURES=1`). /// suites — e.g. `NYX_ENABLE_FLAKY_FIXTURES=1`).
@ -78,7 +78,7 @@ pub enum Prerequisite {
/// framework-bound shape suites so hosts without preinstalled gems can /// framework-bound shape suites so hosts without preinstalled gems can
/// skip instead of depending on network access during tests. /// skip instead of depending on network access during tests.
RubyRequireAvailable(&'static str), RubyRequireAvailable(&'static str),
/// A binary must resolve on `PATH` and respond to `--version` with /// A binary must resolve on `PATH` and respond to its version probe with
/// exit code 0, but the binary name can be overridden via an env /// exit code 0, but the binary name can be overridden via an env
/// var. Used by the C / C++ fixture suites where `cc` / `c++` can /// var. Used by the C / C++ fixture suites where `cc` / `c++` can
/// be swapped in for `clang` / `gcc` via `NYX_CC_BIN` / `NYX_CXX_BIN`. /// be swapped in for `clang` / `gcc` via `NYX_CC_BIN` / `NYX_CXX_BIN`.
@ -128,7 +128,7 @@ pub fn check_prerequisites(reqs: &[Prerequisite]) -> Result<(), SkipReason> {
match req { match req {
Prerequisite::CommandAvailable(cmd) => { Prerequisite::CommandAvailable(cmd) => {
let ok = std::process::Command::new(cmd) let ok = std::process::Command::new(cmd)
.arg("--version") .arg(version_probe_arg(cmd))
.output() .output()
.map(|o| o.status.success()) .map(|o| o.status.success())
.unwrap_or(false); .unwrap_or(false);
@ -149,7 +149,7 @@ pub fn check_prerequisites(reqs: &[Prerequisite]) -> Result<(), SkipReason> {
_ => default, _ => default,
}; };
let ok = std::process::Command::new(bin) let ok = std::process::Command::new(bin)
.arg("--version") .arg(version_probe_arg(bin))
.output() .output()
.map(|o| o.status.success()) .map(|o| o.status.success())
.unwrap_or(false); .unwrap_or(false);
@ -244,6 +244,18 @@ pub fn check_prerequisites(reqs: &[Prerequisite]) -> Result<(), SkipReason> {
Ok(()) Ok(())
} }
fn version_probe_arg(bin: &str) -> &'static str {
if Path::new(bin)
.file_name()
.and_then(|name| name.to_str())
.is_some_and(|name| name == "go")
{
"version"
} else {
"--version"
}
}
/// Per-fixture specification. /// Per-fixture specification.
pub struct FixtureSpec<'a> { pub struct FixtureSpec<'a> {
/// Subdirectory under `tests/dynamic_fixtures/` (e.g. `"python"`, `"rust"`). /// Subdirectory under `tests/dynamic_fixtures/` (e.g. `"python"`, `"rust"`).

View file

@ -13,6 +13,7 @@ mod common;
#[cfg(feature = "dynamic")] #[cfg(feature = "dynamic")]
mod go_fixture_tests { mod go_fixture_tests {
use crate::common::fixture_harness::FIXTURE_LOCK;
use nyx_scanner::commands::scan::Diag; use nyx_scanner::commands::scan::Diag;
use nyx_scanner::dynamic::verify::{VerifyOptions, verify_finding}; use nyx_scanner::dynamic::verify::{VerifyOptions, verify_finding};
use nyx_scanner::evidence::{ use nyx_scanner::evidence::{
@ -22,11 +23,8 @@ mod go_fixture_tests {
use nyx_scanner::labels::Cap; use nyx_scanner::labels::Cap;
use nyx_scanner::patterns::{FindingCategory, Severity}; use nyx_scanner::patterns::{FindingCategory, Severity};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Mutex;
use tempfile::TempDir; use tempfile::TempDir;
static FIXTURE_LOCK: Mutex<()> = Mutex::new(());
fn go_available() -> bool { fn go_available() -> bool {
std::process::Command::new("go") std::process::Command::new("go")
.arg("version") .arg("version")
@ -66,7 +64,7 @@ mod go_fixture_tests {
} }
let path = fixture_path(fixture); let path = fixture_path(fixture);
let tmp = TempDir::new_in("/private/tmp").unwrap(); let tmp = TempDir::new().unwrap();
unsafe { unsafe {
std::env::set_var("NYX_REPRO_BASE", tmp.path().join("repro").to_str().unwrap()); std::env::set_var("NYX_REPRO_BASE", tmp.path().join("repro").to_str().unwrap());