From ddf4c62fe1ce32c860aa804f78fcc5257b40c0e8 Mon Sep 17 00:00:00 2001 From: Exploit Intel Date: Fri, 25 Sep 2026 21:13:14 +0300 Subject: [PATCH] Keep live checks aligned with corpus and output bounds --- CONTRIBUTING.md | 6 ++++++ tests/test_live.py | 9 +++++++++ tests/test_live_parameter_effects.py | 12 +++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21ddcda..c46ce7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,6 +49,12 @@ EIP_MCP_TEST_API_BASE_URL=https://exploit-intel.com \ They must verify the meaning of returned parameters and fields, not merely a successful HTTP status. +An upstream Git revision can remove a named live test file. The wide-fence +file-read case skips only after a successful complete API file inventory proves +that its named file is absent; the independent oversized ExploitDB file case +still runs. Catalog-filter checks compare returned identities with the API's +bounded page and distinguish explicitly truncated fields from incorrect values. + ## Pull requests - Preserve API ordering, identifiers, attribution, and opaque cursors. diff --git a/tests/test_live.py b/tests/test_live.py index 5bb5533..1f1da3e 100644 --- a/tests/test_live.py +++ b/tests/test_live.py @@ -950,6 +950,15 @@ async def test_oversized_file_read_is_capped_with_the_fence_reclosed(tools, arti as a system message. The text and structured source payload share one complete serialized-result budget, so neither channel alone is required to fill it. """ + if (artifact_id, path) == CAPPED_WIDE_FENCE: + # This Git file may disappear as its repository advances. Prove absence + # from the complete current API inventory before declaring this live + # case unavailable; a failed request or incomplete listing must fail. + listing = await tools._post_for_artifact("/api/v1/poc-files", artifact_id) + detail = await tools._api.get(f"/api/v1/pocs/{artifact_id}") + assert len(listing["items"]) == detail["file_count"] + if path not in {item["path"] for item in listing["items"]}: + pytest.skip("current repository snapshot no longer contains the wide-fence test file") out = await tools.read_exploit_file(artifact_id, path=path) wire = call_tool_result("read_exploit_file", out).model_dump_json() assert len(wire) <= 40_000 diff --git a/tests/test_live_parameter_effects.py b/tests/test_live_parameter_effects.py index ec32d68..0f2597a 100644 --- a/tests/test_live_parameter_effects.py +++ b/tests/test_live_parameter_effects.py @@ -1221,7 +1221,17 @@ async def test_catalog_kind_holds_on_every_row(tools, kind): result = await tools.search_exploits(catalog_kind=kind, limit=10) rows = result.structured.data["items"] assert rows, f"catalog_kind={kind} returned nothing" - off = {r.get("catalog_kind") for r in rows if r.get("catalog_kind") != kind} + # The shared wire budget may stop within the final structured row. Compare + # the returned identities to the API's complete bounded page, and only + # permit absent fields when the envelope explicitly discloses truncation. + expected = await tools._api.get("/api/v1/pocs", {"catalog_kind": kind, "limit": 10}) + assert all(row["catalog_kind"] == kind for row in expected["items"]) + assert [row["artifact_id"] for row in rows] == [ + row["artifact_id"] for row in expected["items"][: len(rows)] + ] + assert any("catalog_kind" in row for row in rows) + assert result.structured.truncated or all("catalog_kind" in row for row in rows) + off = {r["catalog_kind"] for r in rows if "catalog_kind" in r and r["catalog_kind"] != kind} assert not off, f"catalog_kind={kind} returned {off}"