mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 19:59:26 +00:00
Task 5.13, measured on ten real pmpro pairs at callDepth 1 with each join half switched separately and
the 54 s JVM fixed cost subtracted: both halves off 11.1 s/request, field half 10.9 s, hook half past
49 s (timeout). Stage timers put it in `hookSeedsIn("")`: every field access in all 7,061 methods put
through the field join before the first callback was answered. Seeds are now the callback's own body
and file, which is where WP Statistics's `set_current_page` and `$this->rest_hits = ...` both live.
Both halves on: 9.7 s/request. `sourceNodes` is also materialised once per request instead of once
per sink.
The WP Statistics re-verification then exposed the larger term. A `joern --script` run is two JVMs and
`-J-Xmx` sizes only the launcher, so the heap knob governed nothing; the backend now sets
JAVA_TOOL_OPTIONS too. And since PHP builds went through php2cpg directly (1ce7e9d, an hour after the
hook half was verified from a joern-parse build), every query batch has recomputed the dataflow overlay
at load -- 54 s on pmpro, and on WP Statistics an OutOfMemoryError inside OssDataFlow after 21 minutes
at 2 GB, no completion in 25 minutes at 4 GB, and no help from --max-num-def at 1000 or 200. Two
vendored browser-profile tables, one array literal each, were 60% of that graph.
Three changes, all named in the log: `queries/overlay.sc` applies the overlays once at build time and
the saved graph replaces the raw one (joern-parse --overlaysonly NPEs in 4.0.623); a source file over
1 MB is excluded as a data table and reported in `unparsed`; and the seed scoping above. After: the WP
Statistics graph reloads in 8 s, the `record` request that timed out at 520 s answers in 39 s including
the JVM, and CVE-2022-25148 is entailed again with `sourceKind = hook`. A raw-vs-saved payload diff on
pmpro shows identical evidence keys and fewer duplicate flow rows.
Also: the backend's own unit tests left fifteen ousast-cpg-* directories in /tmp per run; conftest now
keeps tempfile under the test's directory. The compile test covers overlay.sc.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
65 lines
2.7 KiB
Python
65 lines
2.7 KiB
Python
"""Shared test fixtures."""
|
|
|
|
import subprocess
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
_HARNESSX_GUARD = (
|
|
"\nimport sys as _sys\n"
|
|
"_leaked = sorted(m for m in _sys.modules if m == 'harnessx' or m.startswith('harnessx.'))\n"
|
|
"assert not _leaked, 'leaked harnessx modules: ' + repr(_leaked)\n"
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _pointer_pairs_offline(monkeypatch: pytest.MonkeyPatch, tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
"""Req 10.4: the default test run never touches the network for pointer pairs, whatever the operator's shell exports."""
|
|
monkeypatch.delenv("OPENULTRASAST_PAIRS_NETWORK", raising=False)
|
|
monkeypatch.setenv("OPENULTRASAST_PAIR_CACHE", str(tmp_path_factory.mktemp("pair-cache")))
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _repos_offline(monkeypatch: pytest.MonkeyPatch, tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
"""Req 4.1: pinned repository recipes never fetch during a test run, whatever the operator's shell exports.
|
|
|
|
The cache is redirected as well as the switch cleared, so a developer with warm checkouts and a test that
|
|
forgets to pass an explicit root still cannot read them by accident.
|
|
"""
|
|
monkeypatch.delenv("OPENULTRASAST_REPOS_NETWORK", raising=False)
|
|
monkeypatch.setenv("OPENULTRASAST_REPO_CACHE", str(tmp_path_factory.mktemp("repo-cache")))
|
|
|
|
|
|
@pytest.fixture
|
|
def assert_cold_of_harnessx(): # type: ignore[no-untyped-def]
|
|
"""Run ``code`` in a fresh interpreter and assert it imported no ``harnessx`` module.
|
|
|
|
Hermetic by construction: the lazy-import guarantee is verified the same way
|
|
whether or not the optional extra is installed in this environment (a global
|
|
``sys.modules`` check would be polluted by other tests once the extra is present).
|
|
"""
|
|
|
|
def _check(code: str) -> str:
|
|
proc = subprocess.run(
|
|
[sys.executable, "-c", code + _HARNESSX_GUARD],
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
assert proc.returncode == 0, f"exit={proc.returncode}\nstdout={proc.stdout}\nstderr={proc.stderr}"
|
|
return proc.stdout
|
|
|
|
return _check
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _scratch_under_tmp_path(monkeypatch: pytest.MonkeyPatch, tmp_path_factory: pytest.TempPathFactory) -> None:
|
|
"""Every CPG build makes an `ousast-cpg-*` scratch directory, and a test that feeds it a fake engine never
|
|
reaches the cleanup a real run does: one run of the backend tests left fifteen of them in the system
|
|
temp directory, and the product's stale sweep waits six hours. Pointing `tempfile` at the test's own
|
|
directory keeps them out of `/tmp` entirely, whatever the test forgets.
|
|
"""
|
|
import tempfile
|
|
|
|
scratch = tmp_path_factory.mktemp("scratch")
|
|
monkeypatch.setattr(tempfile, "tempdir", str(scratch))
|