[pitboss/grind] deferred session-0034 (20260517T044708Z-e058)

This commit is contained in:
pitboss 2026-05-17 12:13:48 -05:00
parent fbd5700578
commit f4ef3a8ffc
3 changed files with 642 additions and 2 deletions

View file

@ -555,8 +555,9 @@ pub fn emit(spec: &HarnessSpec) -> Result<HarnessSource, UnsupportedReason> {
let entry_source = read_entry_source(&spec.entry_file);
let shape = JavaShape::detect(spec, &entry_source);
let entry_class = derive_entry_class(&entry_source);
let source = generate_harness_java(spec, shape, &entry_class);
let extra_files = match shape {
let entry_qualifier = derive_entry_qualifier(&entry_source, &entry_class);
let source = generate_harness_java(spec, shape, &entry_qualifier);
let mut extra_files = match shape {
// Real-world servlet sources import `javax.servlet.*` or
// `jakarta.servlet.*`; without those symbols on the classpath
// `javac` reports `package javax.servlet does not exist` and the
@ -567,6 +568,15 @@ pub fn emit(spec: &HarnessSpec) -> Result<HarnessSource, UnsupportedReason> {
}
_ => vec![],
};
// OWASP Benchmark v1.2 fixtures and other Spring-flavoured Java
// entry sources reach for `org.owasp.benchmark.helpers.*`,
// `org.owasp.esapi.*`, and a small Spring surface (RowMapper,
// SqlRowSet, DataAccessException, HtmlUtils). Stage the matching
// stub bundle when the entry source signals one of those imports;
// non-OWASP harnesses pay zero workdir cost.
if crate::dynamic::lang::java_owasp_stubs::entry_needs_owasp_stubs(&entry_source) {
extra_files.extend(crate::dynamic::lang::java_owasp_stubs::owasp_stub_files());
}
Ok(HarnessSource {
source,
@ -623,6 +633,46 @@ fn derive_entry_class(source: &str) -> String {
parse_public_class_name(source).unwrap_or_else(|| "Entry".to_owned())
}
/// Resolve the entry class as a fully-qualified Java name when the
/// entry source declares a `package`. Falls back to the bare simple
/// name when the source has no package declaration (the legacy
/// default-package fixture path).
///
/// OWASP Benchmark testcases ship with `package
/// org.owasp.benchmark.testcode;` headers; javac compiles their
/// sources into `org/owasp/benchmark/testcode/<Class>.class` under
/// the workdir, so `NyxHarness` (which itself lives in the default
/// package) cannot resolve them via the simple name alone. Using
/// the FQN in the harness's `Class.forName` / `.class` references
/// keeps both default-package and packaged entries linkable.
fn derive_entry_qualifier(source: &str, simple_name: &str) -> String {
match parse_package_name(source) {
Some(pkg) => format!("{pkg}.{simple_name}"),
None => simple_name.to_owned(),
}
}
fn parse_package_name(source: &str) -> Option<String> {
for line in source.lines() {
let trimmed = line.trim_start();
let rest = match trimmed.strip_prefix("package ") {
Some(r) => r,
None => continue,
};
let end = rest.find(';')?;
let name = rest[..end].trim();
if !name.is_empty()
&& name
.chars()
.all(|c| c.is_alphanumeric() || c == '_' || c == '.')
{
return Some(name.to_owned());
}
return None;
}
None
}
fn parse_public_class_name(source: &str) -> Option<String> {
for line in source.lines() {
let l = line.trim_start();
@ -1195,6 +1245,133 @@ mod tests {
assert!(harness.extra_files.is_empty());
}
#[test]
fn emit_servlet_doget_bundles_owasp_stubs_when_source_imports_owasp() {
let tmp = tempfile::TempDir::new().unwrap();
let entry_file = stage_entry(
tmp.path(),
"BenchmarkTest00001.java",
"package org.owasp.benchmark.testcode;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpServlet;\nimport org.owasp.benchmark.helpers.Utils;\nimport org.owasp.esapi.ESAPI;\npublic class BenchmarkTest00001 extends HttpServlet {\n public void doGet(HttpServletRequest r, HttpServletResponse w) {}\n}\n",
);
let spec = make_spec_with(EntryKind::HttpRoute, "doGet", &entry_file);
let harness = emit(&spec).unwrap();
let paths: Vec<&str> = harness.extra_files.iter().map(|(p, _)| p.as_str()).collect();
// Servlet stubs are present (same as the non-OWASP servlet case).
assert!(paths.contains(&"javax/servlet/http/HttpServletRequest.java"));
// OWASP helpers + esapi + spring stubs are appended.
assert!(paths.contains(&"org/owasp/benchmark/helpers/Utils.java"));
assert!(paths.contains(&"org/owasp/esapi/ESAPI.java"));
assert!(paths.contains(&"org/owasp/benchmark/helpers/DatabaseHelper.java"));
assert!(paths.contains(&"org/springframework/jdbc/core/RowMapper.java"));
}
#[test]
fn emit_servlet_doget_skips_owasp_stubs_when_source_is_plain() {
// Servlet entry without OWASP / Spring imports must only carry
// the servlet stub bundle, not the OWASP add-on. Keeps workdir
// small for the existing servlet_doget fixture path.
let tmp = tempfile::TempDir::new().unwrap();
let entry_file = stage_entry(
tmp.path(),
"Vuln.java",
"import javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\npublic class Vuln {\n public void doGet(HttpServletRequest r, HttpServletResponse w) {}\n}\n",
);
let spec = make_spec_with(EntryKind::HttpRoute, "doGet", &entry_file);
let harness = emit(&spec).unwrap();
let paths: Vec<&str> = harness.extra_files.iter().map(|(p, _)| p.as_str()).collect();
assert!(
!paths.iter().any(|p| p.starts_with("org/owasp/")),
"plain servlet entry unexpectedly bundles OWASP stubs: {paths:?}"
);
assert!(
!paths.iter().any(|p| p.starts_with("org/springframework/")),
"plain servlet entry unexpectedly bundles Spring stubs: {paths:?}"
);
}
#[test]
fn emit_static_method_with_owasp_imports_bundles_helpers() {
// Non-servlet shapes still need the OWASP stub set when the
// entry source pulls in helpers (e.g. a plain @Test fixture
// calling `Utils.encodeForHTML`).
let tmp = tempfile::TempDir::new().unwrap();
let entry_file = stage_entry(
tmp.path(),
"Vuln.java",
"import org.owasp.benchmark.helpers.Utils;\npublic class Vuln {\n public static void run(String p) { Utils.encodeForHTML(p); }\n}\n",
);
let spec = make_spec_with(EntryKind::Function, "run", &entry_file);
let harness = emit(&spec).unwrap();
let paths: Vec<&str> = harness.extra_files.iter().map(|(p, _)| p.as_str()).collect();
assert!(paths.contains(&"org/owasp/benchmark/helpers/Utils.java"));
// No servlet stubs for a non-servlet shape.
assert!(!paths.iter().any(|p| p.starts_with("javax/servlet/")));
}
#[test]
fn parse_package_name_handles_packaged_source() {
assert_eq!(
parse_package_name("package org.owasp.benchmark.testcode;\nclass X {}\n"),
Some("org.owasp.benchmark.testcode".to_owned())
);
// Leading whitespace + extra spaces inside the line are tolerated.
assert_eq!(
parse_package_name(" package a.b.c ;\n"),
Some("a.b.c".to_owned())
);
// Leading comments / blank lines must not cause an early miss.
assert_eq!(
parse_package_name("// header comment\n/* block */\npackage com.example;\n"),
Some("com.example".to_owned())
);
}
#[test]
fn parse_package_name_returns_none_when_absent() {
assert_eq!(parse_package_name(""), None);
assert_eq!(parse_package_name("public class X {}\n"), None);
}
#[test]
fn derive_entry_qualifier_uses_package_when_present() {
let src = "package org.owasp.benchmark.testcode;\npublic class BenchmarkTest00001 {}\n";
assert_eq!(
derive_entry_qualifier(src, "BenchmarkTest00001"),
"org.owasp.benchmark.testcode.BenchmarkTest00001"
);
}
#[test]
fn derive_entry_qualifier_falls_back_to_simple_name() {
assert_eq!(derive_entry_qualifier("", "Vuln"), "Vuln");
assert_eq!(
derive_entry_qualifier("public class Vuln {}", "Vuln"),
"Vuln"
);
}
#[test]
fn emit_static_method_with_packaged_source_uses_fqn_in_harness() {
// Packaged entry sources must be addressed by FQN in the
// generated NyxHarness, otherwise javac fails with
// `cannot find symbol: class <simple_name>` because the
// packaged .class lives under `org/owasp/.../<simple>.class`
// and NyxHarness itself sits in the default package.
let tmp = tempfile::TempDir::new().unwrap();
let entry_file = stage_entry(
tmp.path(),
"Vuln.java",
"package org.example;\npublic class Vuln { public static void run(String p) {} }\n",
);
let spec = make_spec_with(EntryKind::Function, "run", &entry_file);
let harness = emit(&spec).unwrap();
assert!(
harness.source.contains("org.example.Vuln.run(payload)"),
"harness must address packaged entry via FQN; got source:\n{}",
harness.source
);
}
#[test]
fn emit_spring_controller_carries_no_servlet_stubs() {
// Spring controllers do not import `javax.servlet.*`; shipping

View file

@ -0,0 +1,462 @@
//! Minimal `org.owasp.benchmark.helpers`, `org.owasp.esapi`, and Spring
//! shim stubs for Java harnesses against OWASP Benchmark v1.2 fixtures.
//!
//! OWASP Benchmark testcases lean on a handful of helper classes that
//! ship with the upstream Maven project but are not on the harness
//! workdir classpath. Without them `javac` reports
//! `error: package org.owasp.benchmark.helpers does not exist` (and
//! the matching `esapi` / `springframework` variants) and the verifier
//! flips to `BuildFailed` before any sink probe runs.
//!
//! The bundle here covers the surface OWASP Benchmark v1.2 fixtures
//! actually reference (verified by walking
//! `~/.cache/nyx/eval_corpus/owasp_benchmark_v1.2/`):
//!
//! * `org.owasp.benchmark.helpers.Utils` — `testfileDir` field plus
//! the encode / OS-command helpers.
//! * `org.owasp.benchmark.helpers.DatabaseHelper` — `JDBCtemplate`
//! field of stub `BenchmarkJdbcTemplate` type, plus the
//! `getSqlConnection` / `getSqlStatement` / `printResults` family.
//! * `org.owasp.benchmark.helpers.LDAPManager` — directory-context
//! handle pair.
//! * `org.owasp.benchmark.helpers.SeparateClassRequest` — wraps a
//! `javax.servlet.http.HttpServletRequest` and exposes
//! `getTheParameter` / `getTheValue`.
//! * `org.owasp.benchmark.helpers.ThingFactory` / `ThingInterface` —
//! reflection-style indirection used by reflection-shape fixtures.
//! * `org.owasp.esapi.ESAPI` / `org.owasp.esapi.Encoder` — the
//! `ESAPI.encoder().encodeForHTML(...)` / `encodeForBase64(...)`
//! pair.
//! * `org.springframework.dao.DataAccessException` —
//! `RowMapper.mapRow` throws it.
//! * `org.springframework.jdbc.core.RowMapper` — anonymous-impl
//! target.
//! * `org.springframework.jdbc.support.rowset.SqlRowSet` — return
//! type of `JDBCtemplate.queryForRowSet`.
//! * `org.springframework.web.util.HtmlUtils` — `htmlEscape` static.
//!
//! Methods return null / empty defaults; runtime correctness past the
//! `javac` link step is the job of the spec-derivation fallback
//! paths, not the build-time stubs.
//!
//! Detection gate ([`entry_needs_owasp_stubs`]) checks the entry
//! source for substring hits on `org.owasp.benchmark` /
//! `org.owasp.esapi` / `org.springframework`. Non-OWASP harnesses
//! pay zero workdir cost.
/// Returns `(workdir_relative_path, file_content)` pairs ready to
/// drop into [`crate::dynamic::lang::HarnessSource::extra_files`].
/// Always returns the full bundle; callers gate on
/// [`entry_needs_owasp_stubs`] when scoping is desired.
pub fn owasp_stub_files() -> Vec<(String, String)> {
vec![
(
"org/owasp/benchmark/helpers/Utils.java".to_owned(),
utils_stub(),
),
(
"org/owasp/benchmark/helpers/DatabaseHelper.java".to_owned(),
database_helper_stub(),
),
(
"org/owasp/benchmark/helpers/BenchmarkJdbcTemplate.java".to_owned(),
benchmark_jdbc_template_stub(),
),
(
"org/owasp/benchmark/helpers/LDAPManager.java".to_owned(),
ldap_manager_stub(),
),
(
"org/owasp/benchmark/helpers/SeparateClassRequest.java".to_owned(),
separate_class_request_stub(),
),
(
"org/owasp/benchmark/helpers/ThingFactory.java".to_owned(),
thing_factory_stub(),
),
(
"org/owasp/benchmark/helpers/ThingInterface.java".to_owned(),
thing_interface_stub(),
),
(
"org/owasp/esapi/ESAPI.java".to_owned(),
esapi_stub(),
),
(
"org/owasp/esapi/Encoder.java".to_owned(),
encoder_stub(),
),
(
"org/springframework/dao/DataAccessException.java".to_owned(),
data_access_exception_stub(),
),
(
"org/springframework/jdbc/core/RowMapper.java".to_owned(),
row_mapper_stub(),
),
(
"org/springframework/jdbc/support/rowset/SqlRowSet.java".to_owned(),
sql_row_set_stub(),
),
(
"org/springframework/web/util/HtmlUtils.java".to_owned(),
html_utils_stub(),
),
]
}
/// Substring probe to decide whether an entry source pulls in the
/// OWASP Benchmark helper set. Matches `org.owasp.benchmark` /
/// `org.owasp.esapi` / `org.springframework` references, including
/// import statements and inline FQNs. Conservative on false
/// positives: a fixture that only mentions one of these in a comment
/// will still get the stubs staged, which is harmless javac work.
pub fn entry_needs_owasp_stubs(source: &str) -> bool {
source.contains("org.owasp.benchmark")
|| source.contains("org.owasp.esapi")
|| source.contains("org.springframework")
}
fn utils_stub() -> String {
r#"package org.owasp.benchmark.helpers;
import java.io.IOException;
import java.io.InputStream;
public class Utils {
public static String testfileDir = "/tmp/testfiles/";
public static String encodeForHTML(String s) { return s == null ? "" : s; }
public static String escapeHtml(String s) { return s == null ? "" : s; }
public static String htmlEscape(String s) { return s == null ? "" : s; }
public static String getFileFromClasspath(String name, ClassLoader cl) { return name; }
public static String getInsecureOSCommandString(ClassLoader cl) { return "/bin/sh"; }
public static String getOSCommandString(String cmd) { return cmd == null ? "/bin/sh" : cmd; }
public static void printOSCommandResults(Process p, Object response) {
try {
InputStream is = p.getInputStream();
if (is != null) { is.close(); }
} catch (IOException ignore) {}
}
}
"#
.to_owned()
}
fn database_helper_stub() -> String {
r#"package org.owasp.benchmark.helpers;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DatabaseHelper {
public static boolean hideSQLErrors = false;
public static BenchmarkJdbcTemplate JDBCtemplate = new BenchmarkJdbcTemplate();
public static Connection getSqlConnection() throws SQLException { return null; }
public static Statement getSqlStatement() throws SQLException { return null; }
public static void printResults(ResultSet rs, String sql, Object response) throws SQLException {}
public static void printResults(Statement statement, String sql, Object response) throws SQLException {}
public static void outputUpdateComplete(String sql, Object response) {}
}
"#
.to_owned()
}
fn benchmark_jdbc_template_stub() -> String {
// Names the small JdbcTemplate-shaped surface OWASP fixtures call
// off `DatabaseHelper.JDBCtemplate`. Real Spring JdbcTemplate
// ships in spring-jdbc; this stub keeps the link step succeeding
// without dragging that jar in.
r#"package org.owasp.benchmark.helpers;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.rowset.SqlRowSet;
public class BenchmarkJdbcTemplate {
public int queryForInt(String sql) { return 0; }
public Long queryForLong(String sql) { return 0L; }
public List<?> queryForList(String sql) { return Collections.emptyList(); }
public Map<String, Object> queryForMap(String sql) { return Collections.emptyMap(); }
public <T> T queryForObject(String sql, Object[] args, Class<T> requiredType) { return null; }
public SqlRowSet queryForRowSet(String sql) { return null; }
public <T> List<T> query(String sql, RowMapper<T> mapper) { return Collections.emptyList(); }
public int[] batchUpdate(String sql) { return new int[0]; }
public void execute(String sql) {}
}
"#
.to_owned()
}
fn ldap_manager_stub() -> String {
r#"package org.owasp.benchmark.helpers;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
public class LDAPManager {
public LDAPManager() {}
public DirContext getDirContext() throws NamingException { return null; }
public void closeDirContext() {}
}
"#
.to_owned()
}
fn separate_class_request_stub() -> String {
// Real SeparateClassRequest wraps a servlet request and delegates
// getTheParameter / getTheValue through to it; the stub keeps the
// public surface but discards the request reference.
r#"package org.owasp.benchmark.helpers;
import javax.servlet.http.HttpServletRequest;
public class SeparateClassRequest {
public SeparateClassRequest(HttpServletRequest request) {}
public String getTheParameter(String name) { return null; }
public String getTheValue(String name) { return null; }
}
"#
.to_owned()
}
fn thing_factory_stub() -> String {
r#"package org.owasp.benchmark.helpers;
public class ThingFactory {
public static ThingInterface createThing() {
return new ThingInterface() {
@Override public String doSomething(String input) { return input; }
};
}
}
"#
.to_owned()
}
fn thing_interface_stub() -> String {
r#"package org.owasp.benchmark.helpers;
public interface ThingInterface {
String doSomething(String input);
}
"#
.to_owned()
}
fn esapi_stub() -> String {
r#"package org.owasp.esapi;
public class ESAPI {
private static final Encoder ENCODER = new Encoder() {
@Override public String encodeForHTML(String s) { return s == null ? "" : s; }
@Override public String encodeForBase64(byte[] b, boolean wrap) {
return b == null ? "" : java.util.Base64.getEncoder().encodeToString(b);
}
};
public static Encoder encoder() { return ENCODER; }
}
"#
.to_owned()
}
fn encoder_stub() -> String {
r#"package org.owasp.esapi;
public interface Encoder {
String encodeForHTML(String s);
String encodeForBase64(byte[] b, boolean wrap);
}
"#
.to_owned()
}
fn data_access_exception_stub() -> String {
r#"package org.springframework.dao;
public class DataAccessException extends RuntimeException {
public DataAccessException(String msg) { super(msg); }
public DataAccessException(String msg, Throwable cause) { super(msg, cause); }
}
"#
.to_owned()
}
fn row_mapper_stub() -> String {
r#"package org.springframework.jdbc.core;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.dao.DataAccessException;
public interface RowMapper<T> {
T mapRow(ResultSet rs, int rowNum) throws SQLException, DataAccessException;
}
"#
.to_owned()
}
fn sql_row_set_stub() -> String {
r#"package org.springframework.jdbc.support.rowset;
public interface SqlRowSet {
boolean next();
String getString(int columnIndex);
String getString(String columnLabel);
int getInt(int columnIndex);
int getInt(String columnLabel);
Object getObject(int columnIndex);
Object getObject(String columnLabel);
}
"#
.to_owned()
}
fn html_utils_stub() -> String {
r#"package org.springframework.web.util;
public class HtmlUtils {
public static String htmlEscape(String s) { return s == null ? "" : s; }
public static String htmlUnescape(String s) { return s == null ? "" : s; }
}
"#
.to_owned()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn entry_needs_owasp_stubs_detects_helper_imports() {
let src = "package x;\nimport org.owasp.benchmark.helpers.Utils;\npublic class V {}\n";
assert!(entry_needs_owasp_stubs(src));
}
#[test]
fn entry_needs_owasp_stubs_detects_esapi_imports() {
let src = "import org.owasp.esapi.ESAPI;\npublic class V {}\n";
assert!(entry_needs_owasp_stubs(src));
}
#[test]
fn entry_needs_owasp_stubs_detects_spring_imports() {
let src = "import org.springframework.web.util.HtmlUtils;\n";
assert!(entry_needs_owasp_stubs(src));
}
#[test]
fn entry_needs_owasp_stubs_detects_inline_fqn() {
// OWASP fixtures often use inline FQNs without an import line.
let src = "public class V { void f() { org.owasp.esapi.ESAPI.encoder(); } }";
assert!(entry_needs_owasp_stubs(src));
}
#[test]
fn entry_needs_owasp_stubs_rejects_non_owasp_source() {
let src = "public class V { void f() { System.out.println(\"hi\"); } }";
assert!(!entry_needs_owasp_stubs(src));
}
#[test]
fn bundle_includes_owasp_helpers() {
let paths: Vec<String> = owasp_stub_files()
.into_iter()
.map(|(p, _)| p)
.collect();
for required in &[
"org/owasp/benchmark/helpers/Utils.java",
"org/owasp/benchmark/helpers/DatabaseHelper.java",
"org/owasp/benchmark/helpers/BenchmarkJdbcTemplate.java",
"org/owasp/benchmark/helpers/LDAPManager.java",
"org/owasp/benchmark/helpers/SeparateClassRequest.java",
"org/owasp/benchmark/helpers/ThingFactory.java",
"org/owasp/benchmark/helpers/ThingInterface.java",
"org/owasp/esapi/ESAPI.java",
"org/owasp/esapi/Encoder.java",
"org/springframework/dao/DataAccessException.java",
"org/springframework/jdbc/core/RowMapper.java",
"org/springframework/jdbc/support/rowset/SqlRowSet.java",
"org/springframework/web/util/HtmlUtils.java",
] {
assert!(
paths.iter().any(|p| p == required),
"owasp stub bundle missing {required}; got {paths:?}",
);
}
}
#[test]
fn utils_stub_carries_owasp_method_surface() {
let src = utils_stub();
for method in &[
"testfileDir",
"encodeForHTML",
"escapeHtml",
"htmlEscape",
"getFileFromClasspath",
"getInsecureOSCommandString",
"getOSCommandString",
"printOSCommandResults",
] {
assert!(
src.contains(method),
"Utils stub missing OWASP surface member `{method}`",
);
}
}
#[test]
fn database_helper_stub_carries_owasp_method_surface() {
let src = database_helper_stub();
for method in &[
"hideSQLErrors",
"JDBCtemplate",
"getSqlConnection",
"getSqlStatement",
"printResults",
"outputUpdateComplete",
] {
assert!(
src.contains(method),
"DatabaseHelper stub missing OWASP surface member `{method}`",
);
}
}
#[test]
fn benchmark_jdbc_template_carries_call_surface() {
let src = benchmark_jdbc_template_stub();
for method in &[
"queryForInt",
"queryForLong",
"queryForList",
"queryForMap",
"queryForObject",
"queryForRowSet",
"query",
"batchUpdate",
"execute",
] {
assert!(
src.contains(method),
"BenchmarkJdbcTemplate stub missing OWASP surface member `{method}`",
);
}
}
#[test]
fn encoder_stub_declares_two_encode_methods() {
let src = encoder_stub();
assert!(src.contains("encodeForHTML"));
assert!(src.contains("encodeForBase64"));
}
#[test]
fn esapi_stub_returns_anonymous_encoder() {
let src = esapi_stub();
assert!(src.contains("public static Encoder encoder()"));
assert!(src.contains("new Encoder()"));
}
#[test]
fn separate_class_request_takes_servlet_request() {
let src = separate_class_request_stub();
assert!(src.contains("javax.servlet.http.HttpServletRequest"));
assert!(src.contains("getTheParameter"));
assert!(src.contains("getTheValue"));
}
#[test]
fn bundle_has_thirteen_files() {
// Tripwire: 9 OWASP-namespace + 4 spring-namespace stubs. A
// count drift here usually means a stub was added without
// updating the assertion or a stub got accidentally dropped.
let files = owasp_stub_files();
assert_eq!(files.len(), 13, "expected 9 owasp + 4 springframework stubs");
}
}

View file

@ -16,6 +16,7 @@ pub mod c;
pub mod cpp;
pub mod go;
pub mod java;
pub mod java_owasp_stubs;
pub mod java_servlet_stubs;
pub mod javascript;
pub mod js_shared;