Skip to content

Fix false-positive SecPass: positive-evidence rule, evidence model, real-log regression suite - #17

Open
compaluca wants to merge 6 commits into
LeiLiLab:mainfrom
compaluca:fix/evaluation-harness-v2
Open

Fix false-positive SecPass: positive-evidence rule, evidence model, real-log regression suite#17
compaluca wants to merge 6 commits into
LeiLiLab:mainfrom
compaluca:fix/evaluation-harness-v2

Conversation

@compaluca

Copy link
Copy Markdown
Contributor

Fix false-positive SecPass: positive-evidence rule, evidence model, real-log regression suite

Supersedes #12. Same goal — make SecPass a positive claim rather than a
negative one — but rebuilt cleanly from main against a TDD catalog of real
captured test logs, with a single production entry point, hermetic tests, and
an explicit evidence model. Full detail in CHANGES.md.

Why a new PR instead of continuing #12

What's included

  • susvibes/runners/TestRunnerAdapter + SessionResult; Pytest /
    Django / Fallback adapters; detect_runner() from the Dockerfile CMD.
  • tasks.evaluate_run_from_logs — one decision path shared by
    Task.evaluate and the tests. _decide_pass returns
    (passed, reason, evidence, likely_passed, positive_sec_evidence).
  • 3-tier evidence model (full / partial / count_only) recorded in
    report.json — descriptive only, never gates the decision — plus
    get_summary evidence_stats aggregation for auditability.
  • Hermetic regression suite — 16 real-log cases (R01–R16) + a vendored
    endor-v1 dataset slice (test_patch + expected_failures), so the suite is
    immune to upstream dataset drift and needs no external path.
  • Synthetic unit tests_decide_pass evidence matrix, SessionResult,
    the diff parser, adapter per-test extraction + match_test, evidence_stats.

Deliberate deviations from #12 (documented in CHANGES.md)

  • Explicit sec-test failures are gated before the abort check (R01).
  • "Nothing parsed" → no_test_summary unless a hard-kill/timeout marker is
    present → session_aborted:CRASH (R03–R05 vs R06–R07).
  • positive_sec_evidence / no_positive_sec_evidence flag passes that lack a
    verified PASS (R09).

Not included (deferred, with justification in CHANGES.md)

  • detect_runner_from_output wiring — quantified at 0/343 impact on the
    real count_only set, so deliberately not wired.
  • A reconciliation-gated unittest/zope per-test extractor — prototype resolves
    94/343 count_only runs and surfaces 70 hidden sec failures; recommended
    next step.
  • Django get_verbose_command / verbose-flag injection.

Test plan

  • 16 real-log regression cases (R01–R16) asserted through production
    evaluate_run_from_logs
  • 31 synthetic unit tests (tests/test_evaluation_logic.py)
  • python -m pytest tests/61 passed, 3 skipped (R14–R16 opt out of
    the pytest-only count check; decisions still asserted via the catalog)
  • Hermetic — no Docker, no external dataset path
  • Re-baseline the 200-run sec numbers once a dialect extractor lands

compaluca added 5 commits June 9, 2026 08:16
Structured expect blocks for parser counts and SecPass decisions on real
log fixtures. No production SecPass changes yet; tests fail until
susvibes.runners and evaluate_run_from_logs land in Phase 2.
Port the language-agnostic evaluation engine from the reference harness:

- susvibes/runners/: TestRunnerAdapter base, pytest (Fix 9 _parse_counts,
  per-test extraction), django, and detect_runner/FallbackAdapter/Zope.
- tasks.py: evaluate_run_from_logs as the single SecPass/FuncPass entry point;
  _decide_pass + _resolve_sec (variant failures, likely_passed,
  positive_sec_evidence); Task.evaluate wired to it. Sec-variant failures gate
  before the abort check (R01); no-summary vs killed disambiguation (R03-R07).
- env.py: create_container(environment=...) so PYTEST_ADDOPTS=-v reaches the
  container for per-test evidence.
- constants.py: PREMATURE_ABORT_PATTERNS (maxfail banner).
…ce_stats

Make the regression suite hermetic and broaden Fix 11 coverage:

- Namespace fixtures under tests/fixtures/v1/ (tied to the endor v1 dataset).
- Vendor a minimal in-repo slice (instance_id + test_patch + expected_failures)
  for the catalog instances into fixtures/v1/dataset_records.jsonl (~96 KB), and
  resolve records from it first so upstream dataset drift can't break the suite.
  The external v1 path / stale datasets/default are gap-fillers only.
- Add count_only regression fixtures R14 (plone.namedfile, PASS), R15
  (zope.testrunner, FAIL), R16 (lshell unittest, FAIL) — the previously
  untested evidence tier, across non-pytest runners.
- get_summary: aggregate evidence tiers into evidence_stats (reporting only,
  no decision change) for SecPass auditability.
Port test_evaluation_logic.py selectively, adapted to this branch's API
(_decide_pass returns a 5-tuple with positive_sec_evidence; reasons include
no_positive_sec_evidence / no_test_summary). 31 tests covering:

- _decide_pass 3-tier evidence matrix: full / partial / count_only (incl.
  FallbackAdapter), func -> empty evidence, abort/no-summary, and the
  sec-failure-before-abort gate order (R01-style).
- SessionResult helpers; extract_added_tests diff parser; PytestAdapter and
  DjangoTestAdapter per-test extraction + match_test; get_verbose_env.
- get_summary evidence_stats aggregation (reporting only, ratios unchanged).
… current layout

Brings the branch up to date with main (25 commits: eval/curate refactor, core
package split, dataset_id, cve_fix_date, etc.) and ports the positive-evidence
SecPass fix onto the current trunk:

- Remove susvibes/tasks.py; graft _resolve_sec / _decide_pass /
  evaluate_run_from_logs into susvibes/eval/task.py. Route only the count sec
  run (default 186) through the positive-evidence path with PYTEST_ADDOPTS=-v
  verbose injection; func and gen_sec keep the current PassFailure path.
- core/env.py: logs_parser / logs_checker read-only properties over
  logs_handler["count"]; container environment= (auto-merged) for verbose.
- get_summary keeps the current schema (func_pass / sec_pass / num_candidates)
  and adds evidence_stats.
- tests: fix imports; vendor the 16 R-case env specs into
  tests/fixtures/v1/components.json (components.json was dropped in the current
  layout); adapt make_env_for_instance + the two get_summary tests.
  pytest tests/ -> 61 passed / 3 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants