diff --git a/README.md b/README.md index d1bfbcb..dfe9849 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,25 @@ netscaler-triage .\logs.7z Installation may require internet access. Analysis runs offline. +### Update an existing installation + +Activate the same virtual environment used to run the tool, then run from the +repository directory: + +```sh +git pull +python -m pip install --upgrade . +netscaler-triage rules +``` + +For an environment managed by uv, use `uv sync --locked` after `git pull`. +Version 1.0.1 fixes installation failures reporting `invalid perl operator: (?=` +or `SigmaRegularExpressionError` when loading the bundled rules. pySigma 2 changed +its default validation engine to RE2, which rejects lookaheads. The package now +requires compatible pySigma 1.x; detection patterns and timed matching are +unchanged. Reinstalling with the command above also downgrades an incompatible +pySigma installation. Rerun any scan that stopped with this error. + ## Everyday use ```sh diff --git a/VALIDATION.txt b/VALIDATION.txt index 2b338e4..ee93058 100644 --- a/VALIDATION.txt +++ b/VALIDATION.txt @@ -162,3 +162,18 @@ source mapping and validation results remain outside the public release. A subsequent presentation correction exposes original-file SHA-256 matches in SUMMARY.txt even without an event match. Three focused presentation tests passed, including this separate hash-only case; Ruff, formatting and strict mypy passed. + +DEPENDENCY COMPATIBILITY FIX — 2026-10-05 + +Version 1.0.0 was installed in an isolated environment with pySigma 2.0.0. +The bundled-rule validation reproduced the reported RE2 rejection of lookahead +syntax. Version 1.0.1 constrains pySigma to >=1.5.1,<2, keeping the existing +detection patterns and timeout-protected matching unchanged. + +Reinstalling the corrected package in that same environment automatically +replaced pySigma 2.0.0 with 1.5.1. All 47 bundled Sigma rules validated, with +246 explicit active indicators. All 138 tests passed against the installed +package with Python warnings treated as errors. A new regression checks the +reported lookahead pattern against raw and decoded text, including negative +cases. Ruff lint, formatting and strict mypy across source and tests passed. +This verification did not rerun the complete private forensic datasets. diff --git a/pyproject.toml b/pyproject.toml index 773ef6a..a9ffef0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "netscaler-triage" -version = "1.0.0" +version = "1.0.1" description = "Offline NetScaler evidence analysis with inspectable decoding and provenance" readme = "README.md" license = "MIT" @@ -17,7 +17,8 @@ dependencies = [ "rich>=14.1", "rich-argparse>=1.7", "pyzipper>=0.3.6", - "pysigma>=1.5.1", + # pySigma 2 defaults to RE2, which rejects the supported lookahead rules. + "pysigma>=1.5.1,<2", ] [project.scripts] diff --git a/src/netscaler_triage/__init__.py b/src/netscaler_triage/__init__.py index 3c4785b..f1f3945 100644 --- a/src/netscaler_triage/__init__.py +++ b/src/netscaler_triage/__init__.py @@ -1,3 +1,3 @@ """Offline analysis; no discovered payload is ever executed.""" -__version__ = "1.0.0" +__version__ = "1.0.1" diff --git a/tests/test_sigma_rules.py b/tests/test_sigma_rules.py index 31e94b4..e897fe1 100644 --- a/tests/test_sigma_rules.py +++ b/tests/test_sigma_rules.py @@ -13,6 +13,22 @@ def rule(detection: str, service: str = "") -> str: class SigmaTests(unittest.TestCase): + def test_lookahead_rule_on_raw_and_decoded_text(self) -> None: + matcher = SigmaMatcher.from_yaml( + rule( + " s:\n" + " raw|re: '(?im)^(?=.*(?:pitboss|NSPPE))" + "(?=.*(?:base64|PD9))(?=.*(?:2N|httpaccess))'\n" + " condition: s\n" + ) + ) + sample = "pitboss NSPPE base64 httpaccess" + self.assertTrue(matcher.search({"raw": sample})) + hits = matcher.search_with_details({"raw": "encoded record"}, [sample]) + self.assertEqual(hits[0]["basis"], ["decoded:0"]) + for benign in ("pitboss NSPPE", "base64 httpaccess", "NSPPE base64"): + self.assertFalse(matcher.search({"raw": benign})) + def test_catalog_not_repeated_in_hit(self) -> None: text = rule(" s: [abc]\n condition: s\n") text += "indicators:\n - type: ipv4\n value: 192.0.2.1\n status: reference_only\n" diff --git a/uv.lock b/uv.lock index 7925509..92286e7 100644 --- a/uv.lock +++ b/uv.lock @@ -546,7 +546,7 @@ wheels = [ [[package]] name = "netscaler-triage" -version = "1.0.0" +version = "1.0.1" source = { editable = "." } dependencies = [ { name = "py7zr" }, @@ -569,7 +569,7 @@ dev = [ [package.metadata] requires-dist = [ { name = "py7zr", specifier = ">=1.0" }, - { name = "pysigma", specifier = ">=1.5.1" }, + { name = "pysigma", specifier = ">=1.5.1,<2" }, { name = "pyzipper", specifier = ">=0.3.6" }, { name = "regex", specifier = ">=2025.11" }, { name = "rich", specifier = ">=14.1" },