Skip to content

Add OpenCRE as a map analysis resource for issue #469#5

Open
Bornunique911 wants to merge 14 commits into
mainfrom
feature/issue-469-opencre-mapanalysis
Open

Add OpenCRE as a map analysis resource for issue #469#5
Bornunique911 wants to merge 14 commits into
mainfrom
feature/issue-469-opencre-mapanalysis

Conversation

@Bornunique911

Copy link
Copy Markdown
Owner

Related Issue

This branch addresses:

Problem

OpenCRE already acts as the central requirement graph, but it is not currently exposed as a selectable resource in map_analysis.

That means users can compare external standards to each other, but they cannot directly compare a standard against OpenCRE itself. This limits a useful workflow described in the issue, such as understanding how a standard maps into OpenCRE coverage.

Solution

This branch adds OpenCRE itself as a supported map-analysis resource.

1. Add OpenCRE to the standards list

The /rest/v1/standards response now includes OpenCRE so it can be selected like other map-analysis resources.

2. Add direct map-analysis support for OpenCRE

When one side of /rest/v1/map_analysis is OpenCRE, the backend now builds the result directly from CRE-to-standard links instead of sending the request through the normal queued standard-to-standard flow.

This works by:

  • treating OpenCRE as the set of CRE documents in the local database
  • matching the other selected standard through its linked CREs
  • building a direct overlap result from those shared CRE relationships

3. Keep the implementation narrow

This branch only adds the minimal backend behavior needed for OpenCRE to behave as a map-analysis resource. It does not change the general gap-analysis queue model for other standard-to-standard requests.

Testing

Executed focused validation with:

./venv/bin/python -m pytest application/tests/web_main_test.py -k 'standards_from_db or supports_opencre_as_standard' -q

@Bornunique911 Bornunique911 force-pushed the feature/issue-469-opencre-mapanalysis branch 11 times, most recently from 2a51270 to 876f801 Compare March 27, 2026 08:35
@Bornunique911 Bornunique911 force-pushed the feature/issue-469-opencre-mapanalysis branch from b30d13c to f62149a Compare March 28, 2026 14:44
@Bornunique911 Bornunique911 force-pushed the feature/issue-469-opencre-mapanalysis branch from 88e25aa to 445cbbd Compare April 11, 2026 07:49
@Bornunique911 Bornunique911 force-pushed the feature/issue-469-opencre-mapanalysis branch from 410ffac to 445cbbd Compare April 21, 2026 19:51
@ghost

ghost commented Apr 21, 2026

Copy link
Copy Markdown

Rooviewer Clock   Follow task

The merge-from-main issue is now fixed -- the OpenCRE dispatch block has been restored. Two previously flagged issues remain open.

  • Merge dropped OpenCRE dispatch in map_analysis() -- fixed in ce3ce06; the if OPENCRE_STANDARD_NAME in standards: block is back
  • Cache bypass for OpenCRE requests -- the OpenCRE code path in map_analysis() writes results to the gap-analysis cache but never reads from it, so every request recomputes from scratch
  • N+1 queries in _get_opencre_documents -- one get_CREs call per CRE row in the database; should be batched into a single query
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

Comment on lines +417 to +423
if OPENCRE_STANDARD_NAME in standards:
direct_gap_analysis = _build_direct_cre_overlap_map_analysis(
standards, standards_hash, database
)
if direct_gap_analysis:
return jsonify(direct_gap_analysis)
abort(404, "No direct overlap found for requested standards")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OpenCRE branch bypasses the cache lookup that the normal flow performs. _build_direct_cre_overlap_map_analysis writes to the cache via add_gap_analysis_result (line 403), but this code path never reads from it -- gap_analysis_exists / get_gap_analysis_result are only reached when OPENCRE_STANDARD_NAME is not in standards. Every OpenCRE map-analysis request will recompute the full result from scratch, which is especially costly given that _get_opencre_documents issues one query per CRE row. Adding a cache check before calling _build_direct_cre_overlap_map_analysis would fix this.

Fix it with Roo Code or mention @roomote and request a fix.

Comment on lines +298 to +302
def _get_opencre_documents(collection: db.Node_collection) -> list[defs.CRE]:
return [
collection.get_CREs(internal_id=cre.id)[0]
for cre in collection.session.query(db.CRE).all()
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issues one get_CREs(internal_id=...) query per CRE row in the database. If there are N CREs, that is N+1 total queries (one to list all rows, then one per row to hydrate links). On a production-sized dataset this will be slow and put unnecessary load on the database for every uncached OpenCRE map-analysis request. Consider fetching all CREs with their links in a single batch query instead.

Fix it with Roo Code or mention @roomote and request a fix.

Comment thread application/web/web_main.py Outdated
Comment on lines +420 to +427
cache_key = gap_analysis.make_resources_key(standards)
if database.gap_analysis_exists(cache_key):
cached = database.get_gap_analysis_result(cache_key=cache_key)
if cached:
parsed = json.loads(cached)
if "result" in parsed:
return jsonify({"result": parsed.get("result")})
if os.environ.get("HEROKU"):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The merge from main (3ca88b8) dropped the if OPENCRE_STANDARD_NAME in standards: dispatch block that was present in the pre-merge feature branch (445cbbd, line 417). Without it, _build_direct_cre_overlap_map_analysis and the other helper functions defined above are dead code -- requests with OpenCRE as a standard fall through to the normal RQ/Neo4j flow, which will fail because "OpenCRE" is not a real standard in the database. This effectively breaks the PR's core feature. The block needs to be re-added between the cache_key assignment and the HEROKU guard, e.g.:

Suggested change
cache_key = gap_analysis.make_resources_key(standards)
if database.gap_analysis_exists(cache_key):
cached = database.get_gap_analysis_result(cache_key=cache_key)
if cached:
parsed = json.loads(cached)
if "result" in parsed:
return jsonify({"result": parsed.get("result")})
if os.environ.get("HEROKU"):
cache_key = gap_analysis.make_resources_key(standards)
if database.gap_analysis_exists(cache_key):
cached = database.get_gap_analysis_result(cache_key=cache_key)
if cached:
parsed = json.loads(cached)
if "result" in parsed:
return jsonify({"result": parsed.get("result")})
if OPENCRE_STANDARD_NAME in standards:
direct_gap_analysis = _build_direct_cre_overlap_map_analysis(
standards, cache_key, database
)
if direct_gap_analysis:
return jsonify(direct_gap_analysis)
abort(404, "No direct overlap found for requested standards")
if os.environ.get("HEROKU"):

Fix it with Roo Code or mention @roomote and request a fix.

@Bornunique911 Bornunique911 force-pushed the feature/issue-469-opencre-mapanalysis branch 6 times, most recently from 7e9ac14 to 445cbbd Compare April 22, 2026 19:03
@Bornunique911 Bornunique911 force-pushed the feature/issue-469-opencre-mapanalysis branch 17 times, most recently from ea65804 to 445cbbd Compare April 26, 2026 18:51
@Bornunique911 Bornunique911 force-pushed the feature/issue-469-opencre-mapanalysis branch from f87c053 to e92b08a Compare April 28, 2026 14:50
Bornunique911 pushed a commit that referenced this pull request Jun 24, 2026
OWASP#928)

* feat(module-b): add Pydantic v2 schemas + hashing for Module A input contract

Establishes the data contract Module B consumes from Module A. ChangeRecord
is a Pydantic v2 model matching A's actual emission shape: nested source
(discriminated union on type for github/rss), span (chunk position +
heading_path + char/line offsets), and locator (addressing scheme). Internal
models ClassifyResult and QueuePayload prep for later stages.

hashing.py provides normalize_text + compute_content_hash since Module A
does not emit content_hash; B computes its own (SHA-256 of normalized text)
for use as the knowledge_queue dedup key.

22 unittest cases cover the round-trip, the discriminated union, hash
determinism, normalization rules, code-fence preservation, and idempotency.
Full make test: 271 passing, no regressions.

Part of GSoC 2026 OpenCRE Scraper & Indexer (Project OIE) Module B.

* feat(module-b): add Module A mock fixture + generated JSON Schema artifact

module_a_mock.jsonl: Module A's canonical 20-record mock shared 2026-05-29,
saved as JSONL (one record per line per the contract). Becomes a permanent
integration-test fixture for B's parser and a reference shape for the
Module A contributor.

module_a_contract.schema.json: JSON Schema generated from B's Pydantic
ChangeRecord model via model_json_schema(). 246 lines covering all four
nested types (ChangeRecord, GithubSource, RssSource, Span, Locator).
Source of truth for cross-module CI validation.

Part of GSoC 2026 OpenCRE Scraper & Indexer (Project OIE) Module B.

* feat(module-b): add OWASP harvester, labeling TUI, and labeled dataset

build_labeled_dataset.py: PyGithub-based harvester that acts as Module A's
stand-in for producing benchmark data. Fetches recent commits from 4 OWASP
repos (WSTG, ASVS, CheatSheetSeries, SAMM), applies the contract's
normalization rules, splits into chunks at markdown heading boundaries
with a fence-aware stack-based walker that tracks heading_path + char/line
offsets, and emits records in Module A's actual nested shape. Pluggable
via GITHUB_TOKEN env var. Reproducible: python scripts/build_labeled_dataset.py
regenerates the candidate set.

label_dataset.py: resumable interactive TUI for manual classification.
Atomic-writes labeled_data.json after every keystroke; lookup by chunk_id
for resume. Embeds the recall-first definition (agreed with maintainer
2026-06-01) so labelers see the rule front-of-mind: KNOWLEDGE for any
chunk with security signal, NOISE only for pure organizational content.

candidate_commits.json: 100 records, 25 per repo, all Pydantic-valid
against ChangeRecord. 90/100 have non-empty heading_path; 10 multi-chunk
artifacts captured.

labeled_data.json: 100/100 labeled by hand under the recall-first rule.
Distribution 55 KNOWLEDGE / 40 NOISE / 5 UNCERTAIN. Per-repo skew is
visible: CheatSheetSeries 92% K, SAMM 0% K (the SAMM commits sampled
landed entirely on Website/Sponsorship/meetings paths -- empirical input
for Week 2's noise_patterns.yaml).

Part of GSoC 2026 OpenCRE Scraper & Indexer (Project OIE) Module B.

* style(module-b): apply Black formatting to Week 1 files

Super-Linter (Black 24.4.2) flagged 4 files in the previous push.
Applied `black` (same pinned version) to bring them in line with the
repo's formatting standard. Cosmetic changes only: blank lines around
section-separator comments, one multi-line dict join. No behavior or
test changes -- `make test` remains 271 passing, 1 skip.

* chore(module-b): address CodeRabbit Week 1 review comments

- Sort __all__ lists in hashing.py and schemas.py to satisfy
  Ruff RUF022.
- Declare JSON Schema dialect ($schema = draft 2020-12, which is
  what Pydantic v2 model_json_schema() emits) on the contract artifact.
- Wrap load_labeled() in scripts/label_dataset.py with try/except so a
  corrupted labeled_data.json prints an actionable hint instead of a
  raw JSONDecodeError stack trace.

Deferred to Week 2 (will be addressed when we touch the harvester):
- chunker should also track <pre> open/close, not just ``` fences
- _split_chunk_by_size cursor arithmetic assumes \\n\\n separator even
  on hard-split sub-chunks

Tests: 271 passing, 1 skip (unchanged). Black: clean.

* feat(module-b): add Stage 1.5 sanitize.py vendored from TRACT

Defensive text cleanup (PDF ligatures, zero-width chars, HTML, hyphenation).
Vendored from rocklambros/TRACT under CC0; drops their whitespace-collapse
step so structure (newlines, paragraphs) is preserved for Module B's LLM.

26 unit tests, all passing.

* feat(module-b): add Stage 1 regex_filter + noise_patterns.yaml

Path-based filter with extension/filename/glob deny rules and allow_overrides.
Patterns are deliberately conservative under the recall-first labeling rule.

15 unit tests including >=90% rejection / 0% false-positive acceptance criteria.

* fix(module-b): chunker tracks <pre> blocks; correct hard-split cursor math

Addresses CodeRabbit comments #4 and #5 on the Week 1 PR.

* chore(module-b): address CodeRabbit Week 2 review comments

* chore(module-b): address Week 2 maintainer review on noise_patterns.yaml

---------

Signed-off-by: Manshu Saini <149303743+manshusainishab@users.noreply.github.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.

1 participant