Skip to content

Address pre-publication review findings - #137

Merged
jdaigneau5 merged 2 commits into
devfrom
af/v1.0.0-prep
Aug 24, 2026
Merged

jdaigneau5 merged 2 commits into
devfrom
af/v1.0.0-prep

Conversation

@afoote-mitre

@afoote-mitre afoote-mitre commented Aug 21, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR addresses the actionable findings from the August 20 pre-publication review. Each remediation below explains the defect or drift that prompted the work, the resulting behavior, and the primary files that implement and verify the change.

Changes

1. Fail Closed for Invalid /webSearch Responses and Restore Its Supported Contract (M3)

Why this was needed: The controller previously returned HTTP 200 with zero results when BasicSearchManager reported success but omitted the expected hit structure. The endpoint was also still marked as deprecated in public documentation even though it remains supported for the near term.

What changed:

  • Validate successful BasicSearchManager responses for status metadata, notes and errors arrays, a nonnegative integer total, and a hit array.
  • Return a sanitized HTTP 502 response when the dependency reports success with an invalid response shape.
  • Remove /webSearch deprecation wording while preserving the operator-controlled feature flag and HTTP 410 behavior when disabled.
  • Document the inherited cve-core behavior that changes size to from + 1 when size < from. The application cannot correct this after BasicSearchManager constructs and executes the request.

Primary files: controllers/searchController.js, controllers/searchController.test.js, routes/index.js, routes/index.test.js, utils/errors.js, utils/errors.test.js, routes/swagger.js, api-docs/openapi.json, api-docs/openapi.test.js, README.md

2. Match Complete CVSS Vector Tokens (M1)

Why this was needed: Substring matching allowed a requested base metric such as AV:N to match an unrelated modified metric such as MAV:N, producing false-positive CVSS vector results.

What changed:

  • Normalize vectors into slash-delimited token sets and compare complete tokens during semantic post-filtering.
  • Replace broad wildcard candidate clauses with case-insensitive, token-boundary-aware regular expressions.
  • Retain support for vectors supplied with or without a CVSS version header.

Primary files: utils/cvss.js, utils/cvss.test.js, utils/searchQueryBuilder.js, utils/searchQueryBuilder.test.js, controllers/searchController.test.js

3. Make /search Ordering and Pagination Metadata Deterministic (M2)

Why this was needed: OpenSearch from/size pagination without an explicit immutable sort could return duplicates or omit records as shard ordering changed. The response also reported the requested page size instead of the number of records actually returned, including on out-of-range pages.

What changed:

  • Sort standard, semantic-candidate, and follow-up CVE ID searches by cveMetadata.cveId.keyword in ascending order.
  • Calculate response pageSize from the returned hit array.
  • Preserve semantic follow-up ordering by reordering fetched records to the selected CVE ID page.

Primary files: utils/searchQueryBuilder.js, utils/searchQueryBuilder.test.js, controllers/searchController.js, controllers/searchController.test.js, routes/search.integration.test.js, README.md

4. Validate Search Mappings During Readiness Checks (M6)

Why this was needed: A minimal match_all readiness query could succeed even when the index lacked keyword, text, numeric, boolean, or date mappings required by supported /search filters. Such a task could receive traffic and then fail real searches.

What changed:

  • Define the field capabilities required by the current search contract across base, CNA, and ADP fields.
  • Call OpenSearch field_caps before the existing minimal readiness search.
  • Fail readiness when a required field is missing, unsearchable, incorrectly typed, or non-aggregatable where sorting requires aggregation support.
  • Preserve request timeout and cancellation behavior for both readiness operations.

Primary files: utils/searchReadiness.js, utils/searchReadiness.test.js, utils/searchProvider.js, utils/searchProvider.test.js, routes/index.js, README.md

5. Complete the OpenAPI Response Contract (L1)

Why this was needed: OpenAPI described request fields but did not define reusable success or error response bodies, omitted HTTP 502 outcomes, and represented several boolean inputs more narrowly than the runtime validator.

What changed:

  • Add reusable schemas for API errors, search hits, /search responses, and /webSearch responses.
  • Associate response schemas with documented HTTP status codes, including HTTP 502.
  • Document accepted JSON booleans and lowercase string booleans for keywordExactMatch, noRejected, and isVulnerable.
  • Regenerate the committed OpenAPI artifact and expand its contract assertions.

Primary files: routes/swagger.js, routes/index.js, api-docs/openapi.json, api-docs/openapi.test.js

6. Remove Confirmed Stale and Unused Code (L2)

Why this was needed: Dead dependencies, configuration, middleware, branches, coverage exclusions, and mocks increased the apparent attack surface and made automated and human review more difficult without providing runtime behavior.

What changed:

  • Remove unused direct debug and http-errors dependencies and their unneeded lockfile entries.
  • Remove static-file middleware for the nonexistent public/ directory.
  • Remove the unreachable non-keyword query_string construction branch.
  • Remove unused minServer configuration and update its stale runtime assertion.
  • Remove the stale wrapper coverage exclusion and removed-performance mock.

Primary files: package.json, package-lock.json, server.js, utils/searchQueryBuilder.js, config/default.jsonc, config/devel.jsonc, config/prod.jsonc, config/runtime-config.test.js, jest.config.js, routes/search.integration.test.js

7. Synchronize Public and Generated Documentation

Why this was needed: Runtime behavior, feature status, response shapes, and readiness semantics must remain consistent across source annotations, generated API specifications, manual-test artifacts, and operator guidance.

What changed:

  • Update README guidance for readiness mapping checks, /webSearch support, invalid upstream responses, CVSS token boundaries, deterministic sorting, and actual pageSize semantics.
  • Regenerate the committed OpenAPI artifact from route annotations and schema definitions.
  • Update and regenerate Postman collection descriptions so /webSearch is described as a separate supported contract rather than a deprecated endpoint.

Primary files: README.md, routes/index.js, routes/swagger.js, api-docs/openapi.json, api-docs/openapi.test.js, test/postman/README.md, test/postman/buildCollection.js, test/postman/CVE-Search-API.postman_collection.json

Tracked Items Requiring Separate Decisions

  • H1 - Raw /webSearch query complexity: Query policy, complexity controls, and request-lifecycle cancellation remain under team discussion because the endpoint must remain supported in the near term.
  • H2 - Bounded semantic candidate retrieval: Semantic searches still evaluate at most 10,000 candidates. Complete and snapshot-consistent pagination requires an approved PIT and search_after design.
  • M3 dependency behavior: The controller-side fail-open behavior is fixed, but BasicSearchManager still expands size when size < from before executing OpenSearch. Resolving that requires a cve-core change or replacing that dependency path.
  • M4 - cve-core integration stability: Immutable dependency pinning, Node engine alignment, and replacement of private adapter contracts require coordination with the dependency owner.
  • M5 - Expensive public query shapes: Reference URL substrings, broad CVSS matching, and large response pages require representative infrastructure benchmarks before selecting stricter public limits.
  • M7 - Public repository controls: Licensing, vulnerability disclosure, package metadata, and repository-level security scanning ownership remain team and GitHub-organization decisions.

@afoote-mitre afoote-mitre self-assigned this Aug 21, 2026
@jdaigneau5
jdaigneau5 merged commit 7e0a85f into dev Aug 24, 2026
1 check passed
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