Skip to content

Feat(RHOAIENG-56731): type guards strengthening #7204

Merged
openshift-merge-bot[bot] merged 4 commits intoopendatahub-io:mainfrom
claudialphonse78:feat/RHOAIENG-56731-type-guards
Apr 16, 2026
Merged

Feat(RHOAIENG-56731): type guards strengthening #7204
openshift-merge-bot[bot] merged 4 commits intoopendatahub-io:mainfrom
claudialphonse78:feat/RHOAIENG-56731-type-guards

Conversation

@claudialphonse78
Copy link
Copy Markdown
Contributor

@claudialphonse78 claudialphonse78 commented Apr 13, 2026

Closes RHOAIENG-56731

Description

Addresses UI-breaking bugs caused by null or missing array fields in API
responses, both from the upstream MaaS API and from K8s-backed resources.
Previously a single malformed item or unexpected null field was enough to crash an entire list page.

The fix is applied at two levels:
BFF — send clean data to the frontend

  • Normalize null array fields from the upstream MaaS API (model_refs,
    token_rate_limits, data) to empty arrays before forwarding to the frontend
  • Ensure K8s-converted resources (MaaSSubscription, MaaSAuthPolicy) always have
    initialized slices for owner.groups, modelRefs, and subjects.groups — never
    null
  • Remove omitempty from OwnerSpec.Groups and SubjectSpec.Groups so an empty
    group list always serializes as [] rather than being dropped from the JSON
  • Make ListPolicies skip a malformed policy and log a warning instead of returning
    a 500 for the entire list (same pattern already used for model refs)

Frontend — handle the unexpected gracefully

  • Replace the every() + throw pattern in subscription list fetching with .filter()
    so one bad item is dropped silently instead of taking down the whole page
  • Strengthen the isAPIKey guard to also validate status since it's shown in the
    table
  • Add null acceptance to a few guards (isGroupsSpec, isModelRefInfo) as a
    safety net in case the BFF ever sends unexpected data

How Has This Been Tested?

  • Added Go tests covering the null → empty array normalization in the MaaS client
  • Added Go regression tests to catch anyone accidentally re-adding omitempty to the
    group fields
  • Updated unit tests

Test Impact

  1. Updated spec and go test cases

Request review criteria:

Self checklist (all need to be checked):

  • The developer has manually tested the changes and verified that the changes work
  • Testing instructions have been added in the PR body (for PRs involving changes that are not immediately obvious).
  • The developer has added tests or explained why testing cannot be added (unit or cypress tests for related changes)
  • The code follows our Best Practices (React coding standards, PatternFly usage, performance considerations)

If you have UI changes:

  • Included any necessary screenshots or gifs if it was a UI change.
  • Included tags to the UX team if it was a UI/UX change.

After the PR is posted & before it merges:

  • The developer has tested their solution on a cluster by using the image produced by the PR to main

Summary by CodeRabbit

  • Bug Fixes

    • API responses now consistently return empty arrays instead of nulls for several list fields, and empty "groups" arrays are always emitted in JSON, reducing null-related errors.
    • Client and frontend now tolerate and filter out malformed or incomplete items instead of failing the entire response.
  • Tests

    • Added extensive tests covering response normalization, serialization of empty groups, and guarding/filtering behavior.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

📝 Walkthrough

Walkthrough

The PR adds defensive normalization and stricter serialization plus tests across backend and frontend. Backend: MaaS client and repositories ensure slices are non-nil and normalize nested nils; subscription model JSON tags now always emit groups; policy listing now logs and skips individual conversion failures. Frontend: runtime guards tightened for API keys, array-type guards replaced with Array.isArray + per-item filtering and normalization; multiple unit tests added/updated to exercise nil-handling and filtering behaviors.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Actionable Issues

CWE-391: Unchecked Error Condition — packages/maas/bff/internal/repositories/policies.go

  • Problem: On conversion failure per MaaSAuthPolicy item the code logs a warning and continues; callers receive a potentially incomplete policy list with no indication of skipped items.
  • Action: Decide intended behavior. Either (a) return partial results with explicit metadata listing conversion errors, or (b) fail the operation when any conversion fails. Add unit tests to assert chosen behavior and include structured logging with identifiers for skipped policies.

CWE-253: Incorrect Check for Missing Optional Data — packages/maas/bff/internal/integrations/maas/maas_client.go and frontend guards

  • Problem: Frontend replaced strict array validators with Array.isArray + per-item filtering; backend normalizes nils to empty slices. This combination can silently drop or alter upstream data shapes without observable signals.
  • Action: Add explicit telemetry/logging for filtered/dropped items (counts + example identifiers) or return an API-level structure {items, filteredCount, errors}. Add tests that assert telemetry/emission when items are filtered.

CWE-1025: Comparison Using Wrong Factors — packages/maas/frontend/src/app/api/api-keys.ts and subscriptions.ts

  • Problem: Tightening isAPIKey and relaxing top-level array checks risk rejecting valid but slightly different payload shapes or accepting malformed top-level payloads.
  • Action: Reintroduce a top-level shape guard for responses (explicit schema) and keep per-item guards; add regression tests for top-level shape mismatches and malformed elements.

CWE-772: Missing Release of Resource after Effective Lifetime — packages/maas/bff/internal/integrations/maas/maas_client_test.go

  • Problem: httptest servers are created in tests; if any test path returns early or blocks, servers may not be closed, causing CI flakiness.
  • Action: Ensure every httptest.Server is closed via defer ts.Close() immediately after creation and that handlers cannot block indefinitely (use timeouts or deterministic handlers). Add tests that run with race/timeout settings where applicable.

CWE-330: Use of Insufficiently Random Values — frontend tests/mocks

  • Problem: Tests and mocked API key values use deterministic/static key samples; risk of accidental exposure or misuse if mocks leak into non-test contexts.
  • Action: Clearly mark and locate mocks in test-only files, ensure build tags or test-only directories prevent inclusion in production builds, and avoid using realistic key patterns in tests. Add a CI check that test mocks are not imported from non-test code.
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'type guards strengthening' accurately captures the main focus of the PR—hardening type validation and null-safety in both backend and frontend code.
Description check ✅ Passed The PR description provides a clear structure addressing the issue (RHOAIENG-56731), the two-level fix strategy (BFF + frontend), testing approach, and completed self-checklist items. It covers the what, why, and testing details required by the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/maas/bff/internal/repositories/subscriptions.go (1)

362-373: ⚠️ Potential issue | 🟠 Major

Handle unstructured.NestedSlice errors instead of silently treating malformed specs as empty lists.

Both convertUnstructuredToSubscription and convertUnstructuredToAuthPolicy declare error return types but never propagate errors from unstructured.Nested* calls. When CR fields have wrong types, conversion silently degrades to empty groups/modelRefs, masking invalid data and returning misleading responses.

Proposed fix pattern
- ownerGroups, _, _ := unstructured.NestedSlice(content, "spec", "owner", "groups")
- for _, g := range ownerGroups {
+ ownerGroups, found, err := unstructured.NestedSlice(content, "spec", "owner", "groups")
+ if err != nil {
+   return nil, fmt.Errorf("invalid spec.owner.groups: %w", err)
+ }
+ if found {
+   for _, g := range ownerGroups {
      if gMap, ok := g.(map[string]interface{}); ok {
        if name, ok := gMap["name"].(string); ok {
          sub.Owner.Groups = append(sub.Owner.Groups, models.GroupReference{Name: name})
        }
      }
- }
+   }
+ }

Apply the same found/err handling to:

  • spec.modelRefs (line 373)
  • spec.modelRefs and spec.subjects.groups in convertUnstructuredToAuthPolicy (lines 456, 471)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/maas/bff/internal/repositories/subscriptions.go` around lines 362 -
373, convertUnstructuredToSubscription and convertUnstructuredToAuthPolicy
currently ignore errors from unstructured.NestedSlice, causing malformed CR
fields to be treated as empty slices; update each NestedSlice call (e.g., the
ownerGroups/modelRefs calls that populate sub.Owner.Groups and sub.ModelRefs,
and the subjects.groups calls used in convertUnstructuredToAuthPolicy) to
capture the returned found/err values, check err and return a descriptive error
from the conversion function if err != nil or if found is false but the field
exists with a wrong type, and only iterate the slice when no error occurred;
ensure you reference the same variable names (ownerGroups, modelRefs,
subjectsGroups, sub.Owner.Groups, sub.ModelRefs) so the added checks are placed
exactly around those conversions.
🧹 Nitpick comments (2)
packages/maas/bff/internal/models/subscription_test.go (1)

13-31: Add explicit zero-value (nil slice) serialization coverage for groups.

Current tests only assert behavior for explicitly initialized empty slices. Add assertions for OwnerSpec{} and SubjectSpec{} so null vs [] behavior is locked intentionally and future tag/normalization changes are caught early.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/maas/bff/internal/models/subscription_test.go` around lines 13 - 31,
Add tests to assert nil (zero-value) slice serialization for groups so it yields
"groups":[] rather than null: for OwnerSpec and SubjectSpec marshal the
zero-value structs (OwnerSpec{} and SubjectSpec{}) using json.Marshal and assert
the resulting JSON contains `"groups":[]` (mirror the existing
TestOwnerSpec_EmptyGroupsSerializesAsArray and
TestSubjectSpec_EmptyGroupsSerializesAsArray patterns). Name the new tests
clearly (e.g., TestOwnerSpec_NilGroupsSerializesAsArray and
TestSubjectSpec_NilGroupsSerializesAsArray) and reuse the same error handling
and strings.Contains checks to fail on unexpected marshal errors or wrong
output.
packages/maas/frontend/src/app/api/subscriptions.ts (1)

166-167: Add diagnostics when filtering invalid response items.

Both list endpoints now silently drop invalid entries. Add warning/metric emission with dropped-count so backend schema drift is visible instead of quietly degrading data.

As per coding guidelines, "REVIEW PRIORITIES: ... Bug-prone patterns and error handling gaps".

Also applies to: 288-289

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/maas/frontend/src/app/api/subscriptions.ts` around lines 166 - 167,
When filtering response.data in the isModArchResponse check, count how many
items are invalid (use Array.isArray(response.data), compute valid =
response.data.filter(isMaaSSubscription) and dropped = response.data.length -
valid.length), then return valid.map(normalizeSubscription) but first emit a
warning and a metric when dropped > 0 (e.g., logger.warn("Dropped %d
subscription items due to schema mismatch", dropped) and
metrics.increment("maas.subscriptions.dropped_items", dropped)); apply the same
change to the other occurrence that uses
isModArchResponse/isMaaSSubscription/normalizeSubscription so backend schema
drift is visible.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/maas/bff/internal/repositories/policies.go`:
- Around line 52-53: The current loop in the repository that logs conversion
failures (where you call r.logger.Warn("Failed to convert MaaSAuthPolicy",
slog.String("name", item.GetName()), slog.Any("error", err)) and continue) can
return an empty slice and nil error if every item fails; change the logic in the
policy conversion function (the method performing the loop that references
r.logger.Warn and item.GetName()) to track successful conversions (e.g., append
to a results slice or increment a success counter) and after the loop, if the
input list was non-empty but the results slice is empty, return a non-nil error
indicating all policy conversions failed so callers can surface schema/uptream
breakage; keep the current behavior of skipping individual bad items when at
least one conversion succeeds.

In `@packages/maas/frontend/src/app/api/api-keys.ts`:
- Around line 22-26: The type guard isAPIKey currently only checks id, name, and
status loosely; update it to validate all required APIKey fields (e.g., ensure
creationDate exists and is a string (and optionally a valid ISO date), ensure
status is one of the allowed enum values such as 'active'|'revoked'|'pending'),
and keep the isRecord(v) check; modify the predicate for isAPIKey to explicitly
verify these properties (id, name, creationDate, status) and their
types/accepted values so malformed API payloads are rejected before reaching UI
logic.

In `@packages/maas/frontend/src/app/api/subscriptions.ts`:
- Around line 50-51: isGroupsSpec currently allows v.groups == null which can
let null flow into consumers typed as OwnerSpec/SubjectSpec; update the
predicate to require an array (remove the v.groups == null branch) so it only
returns true when Array.isArray(v.groups) && v.groups.every(isGroupRef), thereby
guaranteeing callers receive a groups array, or alternatively, if you must
accept null here, add an explicit normalization step where the validated object
is converted into OwnerSpec/SubjectSpec (replace null/undefined groups with [])
before returning or casting to the typed object.

---

Outside diff comments:
In `@packages/maas/bff/internal/repositories/subscriptions.go`:
- Around line 362-373: convertUnstructuredToSubscription and
convertUnstructuredToAuthPolicy currently ignore errors from
unstructured.NestedSlice, causing malformed CR fields to be treated as empty
slices; update each NestedSlice call (e.g., the ownerGroups/modelRefs calls that
populate sub.Owner.Groups and sub.ModelRefs, and the subjects.groups calls used
in convertUnstructuredToAuthPolicy) to capture the returned found/err values,
check err and return a descriptive error from the conversion function if err !=
nil or if found is false but the field exists with a wrong type, and only
iterate the slice when no error occurred; ensure you reference the same variable
names (ownerGroups, modelRefs, subjectsGroups, sub.Owner.Groups, sub.ModelRefs)
so the added checks are placed exactly around those conversions.

---

Nitpick comments:
In `@packages/maas/bff/internal/models/subscription_test.go`:
- Around line 13-31: Add tests to assert nil (zero-value) slice serialization
for groups so it yields "groups":[] rather than null: for OwnerSpec and
SubjectSpec marshal the zero-value structs (OwnerSpec{} and SubjectSpec{}) using
json.Marshal and assert the resulting JSON contains `"groups":[]` (mirror the
existing TestOwnerSpec_EmptyGroupsSerializesAsArray and
TestSubjectSpec_EmptyGroupsSerializesAsArray patterns). Name the new tests
clearly (e.g., TestOwnerSpec_NilGroupsSerializesAsArray and
TestSubjectSpec_NilGroupsSerializesAsArray) and reuse the same error handling
and strings.Contains checks to fail on unexpected marshal errors or wrong
output.

In `@packages/maas/frontend/src/app/api/subscriptions.ts`:
- Around line 166-167: When filtering response.data in the isModArchResponse
check, count how many items are invalid (use Array.isArray(response.data),
compute valid = response.data.filter(isMaaSSubscription) and dropped =
response.data.length - valid.length), then return
valid.map(normalizeSubscription) but first emit a warning and a metric when
dropped > 0 (e.g., logger.warn("Dropped %d subscription items due to schema
mismatch", dropped) and metrics.increment("maas.subscriptions.dropped_items",
dropped)); apply the same change to the other occurrence that uses
isModArchResponse/isMaaSSubscription/normalizeSubscription so backend schema
drift is visible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 00d6d664-2a4a-421f-986f-ce440eff8d7b

📥 Commits

Reviewing files that changed from the base of the PR and between 1044662 and a45b8d5.

📒 Files selected for processing (11)
  • packages/maas/bff/internal/integrations/maas/maas_client.go
  • packages/maas/bff/internal/integrations/maas/maas_client_test.go
  • packages/maas/bff/internal/models/subscription.go
  • packages/maas/bff/internal/models/subscription_test.go
  • packages/maas/bff/internal/repositories/policies.go
  • packages/maas/bff/internal/repositories/subscriptions.go
  • packages/maas/bff/internal/repositories/subscriptions_mock.go
  • packages/maas/frontend/src/app/api/__tests__/api-keys.spec.ts
  • packages/maas/frontend/src/app/api/__tests__/subscriptions.spec.ts
  • packages/maas/frontend/src/app/api/api-keys.ts
  • packages/maas/frontend/src/app/api/subscriptions.ts

Comment thread packages/maas/bff/internal/repositories/policies.go
Comment thread packages/maas/frontend/src/app/api/api-keys.ts
Comment thread packages/maas/frontend/src/app/api/subscriptions.ts Outdated
@claudialphonse78 claudialphonse78 force-pushed the feat/RHOAIENG-56731-type-guards branch from 176a6cf to 04549a5 Compare April 13, 2026 13:59
@claudialphonse78 claudialphonse78 changed the title Feat/rhoaieng 56731 type guards Feat(RHOAIENG-56731): type guards strengthening Apr 13, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.88%. Comparing base (04e806c) to head (13cfd6a).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #7204      +/-   ##
==========================================
- Coverage   64.89%   64.88%   -0.02%     
==========================================
  Files        2442     2448       +6     
  Lines       76015    76069      +54     
  Branches    19171    19184      +13     
==========================================
+ Hits        49330    49355      +25     
- Misses      26685    26714      +29     
Files with missing lines Coverage Δ
packages/maas/frontend/src/app/api/api-keys.ts 93.10% <100.00%> (+0.37%) ⬆️
...ackages/maas/frontend/src/app/api/subscriptions.ts 94.66% <100.00%> (-0.14%) ⬇️

... and 16 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 04e806c...13cfd6a. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@emilys314
Copy link
Copy Markdown
Contributor

My subscription with null modelRefs is fixed with this PR
image

dpanshug

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@dpanshug dpanshug left a comment

Choose a reason for hiding this comment

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

/lgtm This fixes null field crash scenarios properly and tested well with the unit tests. Great work!

@openshift-ci openshift-ci Bot added the lgtm label Apr 15, 2026
@claudialphonse78 claudialphonse78 force-pushed the feat/RHOAIENG-56731-type-guards branch from e68dcb5 to 789d125 Compare April 15, 2026 18:38
@openshift-ci openshift-ci Bot removed the lgtm label Apr 15, 2026
@Griffin-Sullivan
Copy link
Copy Markdown
Contributor

/retest

@red-hat-konflux
Copy link
Copy Markdown
Contributor

All PipelineRuns for this commit have already succeeded. Use /retest <pipeline-name> to re-run a specific pipeline or /test to re-run all pipelines.

@Griffin-Sullivan
Copy link
Copy Markdown
Contributor

/retest

@Griffin-Sullivan
Copy link
Copy Markdown
Contributor

/approve
/lgtm

@claudialphonse78 claudialphonse78 force-pushed the feat/RHOAIENG-56731-type-guards branch from 789d125 to 13cfd6a Compare April 16, 2026 07:31
@openshift-ci openshift-ci Bot removed the lgtm label Apr 16, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/maas/frontend/src/app/api/subscriptions.ts (1)

166-167: Emit diagnostics when malformed entries are dropped.

Line 166-167 and Line 288-289 silently discard invalid items via .filter(...). Add a dropped-count warning/metric so backend contract regressions are visible during triage.

Also applies to: 288-289

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/maas/frontend/src/app/api/subscriptions.ts` around lines 166 - 167,
When filtering response.data you currently drop invalid items silently; compute
droppedCount as response.data.length minus filtered.length where you call
isMaaSSubscription, log or emit a metric (e.g., call a diagnostics/metrics
helper like metrics.increment or processLogger.warn) with context
(endpoint/response id and droppedCount) and then map normalizeSubscription over
the filtered items; apply the same change in the second occurrence that uses
isMaaSSubscription (lines ~288-289) so backend contract regressions are visible
during triage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/maas/bff/internal/integrations/maas/maas_client_test.go`:
- Line 21: The test currently ignores the error returned by url.Parse(ts.URL);
update the test setup to capture and handle the error (e.g., u, err :=
url.Parse(ts.URL) and if err != nil { t.Fatalf("parse test server URL: %v", err)
}) so errcheck passes; update the code around the url.Parse call in
maas_client_test.go (where variable u and ts are used) to fail the test on parse
failure.

In `@packages/maas/frontend/src/app/api/subscriptions.ts`:
- Around line 130-131: The validator currently allows
ModelRefInfo.token_rate_limits to be null (via the condition v.token_rate_limits
== null) which permits null to flow into typed UserSubscription payloads; change
the validation so token_rate_limits must be either undefined or an array of
valid items (use Array.isArray(v.token_rate_limits) &&
v.token_rate_limits.every(isTokenRateLimitInfo) and remove the acceptance of
null), and also normalize any outgoing payloads where UserSubscription objects
are constructed (the code that returns/filter objects around token_rate_limits)
to coerce null/undefined into an empty array and filter with
isTokenRateLimitInfo (e.g., set token_rate_limits = (Array.isArray(value) ?
value.filter(isTokenRateLimitInfo) : [])) so no null escapes.

---

Nitpick comments:
In `@packages/maas/frontend/src/app/api/subscriptions.ts`:
- Around line 166-167: When filtering response.data you currently drop invalid
items silently; compute droppedCount as response.data.length minus
filtered.length where you call isMaaSSubscription, log or emit a metric (e.g.,
call a diagnostics/metrics helper like metrics.increment or processLogger.warn)
with context (endpoint/response id and droppedCount) and then map
normalizeSubscription over the filtered items; apply the same change in the
second occurrence that uses isMaaSSubscription (lines ~288-289) so backend
contract regressions are visible during triage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: a4840ff9-e4b2-40d5-a16b-7a2ba4881492

📥 Commits

Reviewing files that changed from the base of the PR and between 789d125 and 13cfd6a.

📒 Files selected for processing (11)
  • packages/maas/bff/internal/integrations/maas/maas_client.go
  • packages/maas/bff/internal/integrations/maas/maas_client_test.go
  • packages/maas/bff/internal/models/subscription.go
  • packages/maas/bff/internal/models/subscription_test.go
  • packages/maas/bff/internal/repositories/policies.go
  • packages/maas/bff/internal/repositories/subscriptions.go
  • packages/maas/bff/internal/repositories/subscriptions_mock.go
  • packages/maas/frontend/src/app/api/__tests__/api-keys.spec.ts
  • packages/maas/frontend/src/app/api/__tests__/subscriptions.spec.ts
  • packages/maas/frontend/src/app/api/api-keys.ts
  • packages/maas/frontend/src/app/api/subscriptions.ts
✅ Files skipped from review due to trivial changes (4)
  • packages/maas/bff/internal/models/subscription_test.go
  • packages/maas/bff/internal/repositories/subscriptions_mock.go
  • packages/maas/frontend/src/app/api/tests/subscriptions.spec.ts
  • packages/maas/bff/internal/integrations/maas/maas_client.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/maas/bff/internal/repositories/policies.go
  • packages/maas/frontend/src/app/api/api-keys.ts
  • packages/maas/bff/internal/repositories/subscriptions.go
  • packages/maas/bff/internal/models/subscription.go
  • packages/maas/frontend/src/app/api/tests/api-keys.spec.ts

t.Helper()
ts := httptest.NewServer(handler)
t.Cleanup(ts.Close)
u, _ := url.Parse(ts.URL)
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.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate golangci config:"
fd -a '.golangci.yml' '.golangci.yaml' || true

echo
echo "Inspect ignored Parse errors in Go files:"
rg -nP --type go 'url\.Parse\(' -C2
rg -nP --type go ':\=\s*[^,\n]+,\s*_\s*:=?\s*url\.Parse\(' -C2 || true

Repository: opendatahub-io/odh-dashboard

Length of output: 9529


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for golangci config in maas package ==="
find packages/maas -name '.golangci.yaml' -o -name '.golangci.yml' 2>/dev/null | head -20

echo
echo "=== Check if there's a linter config at package root ==="
ls -la packages/maas/ | grep -i config || true

echo
echo "=== Read the test file to understand context ==="
head -50 packages/maas/bff/internal/integrations/maas/maas_client_test.go

echo
echo "=== Check if this test is actually running url.Parse and relying on success ==="
sed -n '15,35p' packages/maas/bff/internal/integrations/maas/maas_client_test.go

Repository: opendatahub-io/odh-dashboard

Length of output: 2529


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Read the .golangci.yaml in packages/maas/bff ==="
cat packages/maas/bff/.golangci.yaml

echo
echo "=== Check if errcheck is enabled ==="
grep -i "errcheck" packages/maas/bff/.golangci.yaml || echo "errcheck not found in config"

Repository: opendatahub-io/odh-dashboard

Length of output: 528


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check golangci-lint documentation for std-error-handling preset ==="
echo "The 'std-error-handling' preset in golangci-lint typically enables:"
echo "- errcheck (checks for unchecked errors)"
echo "- errchkjson (checks for json.Unmarshal unchecked errors)"
echo "- nilerr (checks for explicit nil returns)"

echo
echo "=== Verify the actual usage pattern - is ts.URL guaranteed valid? ==="
grep -n "httptest.NewServer" packages/maas/bff/internal/integrations/maas/maas_client_test.go

echo
echo "=== Check if NewMaasClient expects a non-nil *url.URL ==="
grep -A5 "func NewMaasClient" packages/maas/bff/internal/integrations/maas/maas_client.go | head -20

Repository: opendatahub-io/odh-dashboard

Length of output: 736


Handle url.Parse error in test setup to comply with errcheck linter.

Line 21 ignores the error return from url.Parse(). The std-error-handling preset is enabled in .golangci.yaml, which activates errcheck. Even though httptest.NewServer produces a valid URL, explicit error handling is required for linter compliance and consistency with the rest of the codebase.

Suggested fix
-	u, _ := url.Parse(ts.URL)
+	u, err := url.Parse(ts.URL)
+	if err != nil {
+		t.Fatalf("failed to parse test server URL: %v", err)
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
u, _ := url.Parse(ts.URL)
u, err := url.Parse(ts.URL)
if err != nil {
t.Fatalf("failed to parse test server URL: %v", err)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/maas/bff/internal/integrations/maas/maas_client_test.go` at line 21,
The test currently ignores the error returned by url.Parse(ts.URL); update the
test setup to capture and handle the error (e.g., u, err := url.Parse(ts.URL)
and if err != nil { t.Fatalf("parse test server URL: %v", err) }) so errcheck
passes; update the code around the url.Parse call in maas_client_test.go (where
variable u and ts are used) to fail the test on parse failure.

Comment on lines +130 to 131
(v.token_rate_limits == null ||
(Array.isArray(v.token_rate_limits) && v.token_rate_limits.every(isTokenRateLimitInfo)));
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.

⚠️ Potential issue | 🟠 Major

Prevent null from escaping as ModelRefInfo.token_rate_limits.

Line 130 accepts token_rate_limits == null, and Line 288-289 returns filtered objects without normalization. That allows null to flow in typed UserSubscription payloads and can still break array consumers.

Suggested fix
+const normalizeUserSubscription = (sub: UserSubscription): UserSubscription => ({
+  ...sub,
+  model_refs: sub.model_refs.map((ref) => ({
+    ...ref,
+    token_rate_limits: Array.isArray(ref.token_rate_limits) ? ref.token_rate_limits : [],
+  })),
+});
+
 export const listUserSubscriptions =
   (hostPath = '') =>
   (opts: APIOptions): Promise<UserSubscription[]> =>
     handleRestFailures(
       restGET(hostPath, `${URL_PREFIX}/api/${BFF_API_VERSION}/subscriptions`, {}, opts),
     ).then((response) => {
       if (isModArchResponse<unknown>(response) && Array.isArray(response.data)) {
-        return response.data.filter(isUserSubscription);
+        return response.data.filter(isUserSubscription).map(normalizeUserSubscription);
       }
       throw new Error('Invalid response format');
     });

As per coding guidelines, "Validate all API responses before rendering".

Also applies to: 288-289

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/maas/frontend/src/app/api/subscriptions.ts` around lines 130 - 131,
The validator currently allows ModelRefInfo.token_rate_limits to be null (via
the condition v.token_rate_limits == null) which permits null to flow into typed
UserSubscription payloads; change the validation so token_rate_limits must be
either undefined or an array of valid items (use
Array.isArray(v.token_rate_limits) &&
v.token_rate_limits.every(isTokenRateLimitInfo) and remove the acceptance of
null), and also normalize any outgoing payloads where UserSubscription objects
are constructed (the code that returns/filter objects around token_rate_limits)
to coerce null/undefined into an empty array and filter with
isTokenRateLimitInfo (e.g., set token_rate_limits = (Array.isArray(value) ?
value.filter(isTokenRateLimitInfo) : [])) so no null escapes.

Copy link
Copy Markdown
Contributor

@dpanshug dpanshug left a comment

Choose a reason for hiding this comment

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

/lgtm

@openshift-ci openshift-ci Bot added the lgtm label Apr 16, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 16, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: dpanshug, Griffin-Sullivan

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot openshift-merge-bot Bot merged commit 4fadc71 into opendatahub-io:main Apr 16, 2026
54 checks passed
katieperry4 pushed a commit to katieperry4/odh-dashboard that referenced this pull request Apr 17, 2026
* fix:added guards checks on the backend for subscriptions, policies and test cases

* fix:added guards checks on frontend and test case changes

* fix:added test case fixes

* review:code rabbit review changes
openshift-merge-bot Bot pushed a commit that referenced this pull request Apr 17, 2026
* fix:added guards checks on the backend for subscriptions, policies and test cases

* fix:added guards checks on frontend and test case changes

* fix:added test case fixes

* review:code rabbit review changes

Co-authored-by: Claudia Alphonse <claudialphonse@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants