Skip to content

feat(api): filter /rest/v1/standards by saved resource selection (#586) - #1001

Merged
Pa04rth merged 2 commits into
OWASP:mainfrom
skypank-coder:feat/586-standards-filter
Aug 3, 2026
Merged

feat(api): filter /rest/v1/standards by saved resource selection (#586)#1001
Pa04rth merged 2 commits into
OWASP:mainfrom
skypank-coder:feat/586-standards-filter

Conversation

@skypank-coder

Copy link
Copy Markdown
Contributor

What & why

Part of #586. This makes a user's saved resource selection (from PR #980 + #981)
actually take effect: a logged-in user with a non-empty selection now sees only
their selected standards when calling GET /rest/v1/standards. Builds directly
on the merged User persistence (#980) and resource-selection API (#981).

Behaviour

  • Logged-in + non-empty selection + MyOpenCRE enabled/rest/v1/standards
    returns only the selected standards. OPENCRE is always kept (it's the core
    graph, already special-cased).
  • Anonymous / empty selection / login disabled / MyOpenCRE disabled → full,
    unfiltered list (same no-op discipline as feat(api): per-user resource selection endpoint — Part of #586 #981 — never narrow results silently
    for users who didn't opt in).
  • ?all=true bypasses the filter for a single request, so a user can see
    everything without clearing their saved selection. Documented in OpenAPI.

Design

Scope (deliberately tight)

  • In scope: /rest/v1/standards only.
  • Deferred to a follow-up: /rest/v1/ga_standards (filtering it server-side
    without the paired frontend ?all=true wiring would silently narrow
    gap-analysis inputs), and graph-node/link pruning for root_cres /
    text_search / find_cre (a distinct semantic decision; the client
    applyFilters already handles link-level filtering). Single-resource lookups
    (/standard/<name>, map_analysis) are intentionally never filtered — the user
    asked for that resource explicitly.

Testing

  • New application/tests/resource_filter_test.py, verified on real Postgres:
    selection → {selected}+OPENCRE; empty/anonymous/login-off/myopencre-off → full;
    OPENCRE always kept; ?all=true bypass.
  • Mutation-checked: removing the filter call makes the "returns only selected"
    tests fail, so they genuinely detect an unapplied filter.
  • OpenAPI ?all param added + spec regenerated; guardrail green
    (documented-views / freshness / validity / route-coverage).
  • black clean; no new mypy errors.

…SP#586)

Part of OWASP#586. Logged-in users with a saved selection see only their selected
standards (OpenCRE always kept); ?all=true bypasses. No-op for anon / empty
selection / flags off. ga_standards and graph-node pruning deferred.
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • New Features

    • Standards results can now be personalized based on a logged-in user’s saved resource selections.
    • The OpenCRE standard is always included in filtered results.
    • Added an all=true option to return the complete standards list.
  • Documentation

    • Updated API documentation to describe standards filtering and the new query parameter.
  • Tests

    • Added coverage for authenticated, anonymous, feature-disabled, empty-selection, and full-list scenarios.

Walkthrough

Changes

Standards filtering

Layer / File(s) Summary
Filtering logic and coverage
application/web/web_main.py, application/tests/resource_filter_test.py
The standards endpoint filters results by saved user selections when the relevant features and user state permit it. OPENCRE remains included. Tests cover fallback cases and all=true.
OpenAPI parameter and contract wiring
application/web/openapi_registry.py, docs/api/openapi.yaml
PathSpec supports custom parameters. The standards endpoint documents the optional all boolean parameter and its filtering behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • OWASP/OpenCRE#981: Implements the per-user resource selections used by this filtering logic.

Suggested reviewers: pa04rth, northdpole

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes filtering the standards endpoint by saved resource selection.
Description check ✅ Passed The description accurately explains the endpoint behavior, feature flags, bypass parameter, scope, implementation, and tests.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
application/web/openapi_registry.py (1)

518-521: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Prevent duplicate query parameters.

path_names only contains path parameters. A custom query parameter can duplicate a parameter generated from query_schema. This can generate an invalid OpenAPI operation.

Track existing (name, in) pairs after adding query-schema parameters. Skip duplicate custom parameters. Add a generation test with the same query parameter from both sources.

Proposed fix
     if path_spec.parameters:
-        parameters.extend(
-            [param for param in path_spec.parameters if param["name"] not in path_names]
-        )
+        seen = {(param["name"], param["in"]) for param in parameters}
+        for param in path_spec.parameters:
+            key = (param["name"], param["in"])
+            if param["name"] not in path_names and key not in seen:
+                parameters.append(param)
+                seen.add(key)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@application/web/openapi_registry.py` around lines 518 - 521, Update the
parameter assembly logic around path_spec.parameters to track existing (name,
in) pairs after adding query-schema parameters, and filter custom parameters
against that set instead of path_names alone. Preserve distinct parameters with
different locations, and add a generation test covering the same query parameter
supplied by both query_schema and custom parameters.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@application/web/openapi_registry.py`:
- Around line 518-521: Update the parameter assembly logic around
path_spec.parameters to track existing (name, in) pairs after adding
query-schema parameters, and filter custom parameters against that set instead
of path_names alone. Preserve distinct parameters with different locations, and
add a generation test covering the same query parameter supplied by both
query_schema and custom parameters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9bfee594-fc9d-438b-acc4-94760673af46

📥 Commits

Reviewing files that changed from the base of the PR and between ef7810c and 8cc01be.

📒 Files selected for processing (4)
  • application/tests/resource_filter_test.py
  • application/web/openapi_registry.py
  • application/web/web_main.py
  • docs/api/openapi.yaml

@Pa04rth
Pa04rth merged commit 15f36f6 into OWASP:main Aug 3, 2026
6 checks 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