Skip to content

add type safety for rate limit namespace and scope identifiers#1943

Open
nXtCyberNet wants to merge 1 commit into
Kuadrant:mainfrom
nXtCyberNet:main
Open

add type safety for rate limit namespace and scope identifiers#1943
nXtCyberNet wants to merge 1 commit into
Kuadrant:mainfrom
nXtCyberNet:main

Conversation

@nXtCyberNet

@nXtCyberNet nXtCyberNet commented May 4, 2026

Copy link
Copy Markdown

feat: add type safety for rate limit namespace and scope identifiers

Define LimitNamespace and ActionScope as distinct named types wrapping
string to prevent accidental mixing of Limitador limit namespaces and
WASM action scopes.

Changes:

  • Add LimitNamespace and ActionScope types in ratelimit_workflow_helpers.go
  • Add ToActionScope() conversion method on LimitNamespace
  • Update LimitsNamespaceFromRoute() to return LimitNamespace
  • Update wasmActionFromLimit() to accept ActionScope parameter
  • Update wasmActionsFromTokenLimit() to accept ActionScope parameter
  • Update buildWasmActionsForAnyRateLimit() actionFunc signature
  • Update all call sites to use explicit type conversions
  • Add unit tests to verify type safety

Closes #1916

Summary by CodeRabbit

  • Bug Fixes

    • Resolved test suite cleanup to prevent potential errors during environment teardown.
  • Improvements

    • Enhanced internal type safety for rate limiting logic through improved type definitions.

Signed-off-by: nXtCyberNet <rohantech2005@gmail.com>
@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces type-safe wrappers (LimitNamespace and ActionScope) for rate limit identifiers, updates function signatures and implementations to use these new types, and ensures all call sites, tests, and assertions are updated to work with the typed values whilst maintaining backward compatibility through explicit string conversions.

Changes

Type Safety for Rate Limit Identifiers

Layer / File(s) Summary
Type Definitions
internal/controller/ratelimit_workflow_helpers.go
Introduces exported LimitNamespace and ActionScope string-based types to provide stronger typing for rate limit namespace and WASM action scope identifiers.
Function Signatures
internal/controller/ratelimit_workflow_helpers.go
LimitsNamespaceFromRoute() now returns LimitNamespace instead of string. wasmActionFromLimit() and wasmActionsFromTokenLimit() now accept ActionScope parameter instead of string.
Core Implementation
internal/controller/ratelimit_workflow_helpers.go, internal/controller/limitador_limits_reconciler.go
Updated WASM action construction to accept and convert ActionScope via string(scope). Updated Namespace field assignments in rate limit generation to explicitly convert to string using string(limitsNamespace). Generic action builder converts typed limitsNamespace to string before downstream propagation.
Call Sites & Wiring
internal/controller/ratelimit_workflow_helpers.go
Updated call sites to wrap scope arguments with ActionScope(...) and construct typed values at the point of use.
Unit Tests
internal/controller/ratelimit_workflow_helpers_test.go
New test file verifies type conversions, format preservation (namespace/name), and assignability for LimitNamespace and ActionScope; validates LimitsNamespaceFromRoute() returns correctly formatted and typed namespaced names.
Integration Tests
internal/controller/ratelimit_workflow_test.go, internal/controller/tokenratelimit_workflow_test.go, tests/common/ratelimitpolicy/*, tests/envoygateway/extension_reconciler_test.go, tests/istio/extension_reconciler_test.go
Updated test invocations and assertions to wrap scope values with ActionScope(...) and explicit string(...) conversions where needed; adjusted expected wasm.Action.Scope and RateLimit.Namespace field comparisons throughout.
Suite Teardown
tests/common/ratelimitpolicy/suite_test.go
Updated SynchronizedAfterSuite to conditionally clean up k8sClient and testEnv only when non-nil, preventing panics if setup did not fully initialise these variables.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • Add GRPCRoute support to RateLimitPolicy #1881: Both PRs modify LimitsNamespaceFromRoute() and related namespace handling in internal/controller/ratelimit_workflow_helpers.go and internal/controller/limitador_limits_reconciler.go; this PR adds type safety as a follow-up to that work.

Suggested labels

kind/enhancement

Suggested reviewers

  • guicassolato

Poem

🐰 String types wrapped in safety's embrace,
LimitNamespace now marks its place,
ActionScope dances, no mix-ups in sight,
Type-checked rate limits, forever right!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing type safety for rate limit namespace and scope identifiers through new LimitNamespace and ActionScope types.
Linked Issues check ✅ Passed All acceptance criteria from issue #1916 are met: LimitNamespace and ActionScope types defined, function signatures updated, call sites converted, and unit tests added.
Out of Scope Changes check ✅ Passed All changes directly support the type safety objectives. The suite_test.go teardown fix is a necessary prerequisite for tests to run properly with the new typed functions.

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

✨ 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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (1)
tests/istio/extension_reconciler_test.go (1)

462-462: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Six Equal assertions compare string against LimitNamespace — all will fail at runtime.

The Scope field on wasm.Action is type string. Now that LimitsNamespaceFromRoute returns LimitNamespace (a distinct named type), Gomega's Equal uses reflect.DeepEqual, which returns false whenever the types differ — even if the underlying values match.

Every struct-literal assignment was correctly updated with string(...), but these six Expect calls in the "Full featured RLP targeting HTTPRoute" test were missed.

🐛 Proposed fix (apply at all six sites)
- Expect(actionSet.Actions[1].Scope).To(Equal(controllers.LimitsNamespaceFromRoute(httpRoute)))
+ Expect(actionSet.Actions[1].Scope).To(Equal(string(controllers.LimitsNamespaceFromRoute(httpRoute))))

Also applies to: 520-520, 578-578, 635-635, 693-693, 751-751

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

In `@tests/istio/extension_reconciler_test.go` at line 462, The test is comparing
a string-typed Scope (actionSet.Actions[1].Scope) against a value of the named
type controllers.LimitNamespace, causing Gomega Equal to fail due to type
mismatch; update each failing Expect call in the "Full featured RLP targeting
HTTPRoute" test (and the five other sites listed) to convert the named type to
string by calling string(controllers.LimitsNamespaceFromRoute(httpRoute)) so the
assertion compares identical string types (i.e., change
Equal(controllers.LimitsNamespaceFromRoute(...)) to
Equal(string(controllers.LimitsNamespaceFromRoute(...))) for the Expect checks
referencing actionSet.Actions[n].Scope).
🧹 Nitpick comments (3)
internal/controller/ratelimit_workflow_helpers.go (2)

34-36: ⚡ Quick win

ToActionScope() conversion method stated in PR objectives is absent.

The PR description explicitly lists: "Provide a conversion method ToActionScope() on LimitNamespace for explicit conversion to ActionScope." The implementation instead uses ad-hoc direct casting (ActionScope(limitsNamespace)) at every call site. Adding the method would centralise the conversion, make the intent self-documenting, and match the documented API contract.

💡 Suggested addition
 type LimitNamespace string
 type ActionScope string
+
+// ToActionScope converts a LimitNamespace to an ActionScope for use in WASM action construction.
+func (n LimitNamespace) ToActionScope() ActionScope {
+	return ActionScope(n)
+}

Call sites in buildWasmActionsForRateLimit and buildWasmActionsForTokenRateLimit can then use limitsNamespace.ToActionScope() instead of ActionScope(limitsNamespace).

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

In `@internal/controller/ratelimit_workflow_helpers.go` around lines 34 - 36, Add
a conversion method on LimitNamespace named ToActionScope that returns
ActionScope; replace ad-hoc casts ActionScope(limitsNamespace) with
limitsNamespace.ToActionScope() in buildWasmActionsForRateLimit and
buildWasmActionsForTokenRateLimit so callers use the explicit conversion method
(declare func (n LimitNamespace) ToActionScope() ActionScope and update the two
buildWasm... functions to call it).

375-422: ⚡ Quick win

buildWasmActionsForAnyRateLimit silently erases the ActionScope type in its actionFunc signature.

Line 381 keeps the actionFunc scope parameter as a plain string:

actionFunc func(interface{}, string, string, string, kuadrantv1.WhenPredicates) wasm.Action,

Line 417 converts LimitNamespace → string before passing it in, and then the caller's closure at Line 320 immediately re-wraps it as ActionScope(scope). The LimitNamespace → string → ActionScope round-trip within the same logical call chain undermines the type safety this PR is intended to establish. Changing the actionFunc scope parameter to ActionScope would make the boundary explicit and eliminate the re-wrapping closure.

♻️ Proposed refactor
 func buildWasmActionsForAnyRateLimit(
 	path []machinery.Targetable,
 	rules map[string]kuadrantv1.MergeableRule,
 	topLevelPredicatesKey string,
 	policyPredicate func(machinery.Policy) bool,
 	identifierFunc func(k8stypes.NamespacedName, string) string,
-	actionFunc func(interface{}, string, string, string, kuadrantv1.WhenPredicates) wasm.Action,
+	actionFunc func(interface{}, string, ActionScope, string, kuadrantv1.WhenPredicates) wasm.Action,
 ) []wasm.Action {

And on line 417:

-		scope := string(limitsNamespace)
+		scope := ActionScope(limitsNamespace)

The buildWasmActionsForRateLimit closure can then remove the ActionScope(scope) re-wrap:

 func(spec interface{}, limitIdentifier string, scope, sourcePolicyLocator string, predicates kuadrantv1.WhenPredicates) wasm.Action {
     limit := spec.(*kuadrantv1.Limit)
-    return wasmActionFromLimit(limit, limitIdentifier, ActionScope(scope), sourcePolicyLocator, predicates)
+    return wasmActionFromLimit(limit, limitIdentifier, scope, sourcePolicyLocator, predicates)
 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/controller/ratelimit_workflow_helpers.go` around lines 375 - 422,
buildWasmActionsForAnyRateLimit is losing the ActionScope type by declaring
actionFunc's scope parameter as string and converting LimitsNamespace to string
before calling it; change the actionFunc signature to take
kuadrantv1.ActionScope (or the ActionScope type you introduced) instead of
string, keep limitsNamespace as an ActionScope (or cast it once from
LimitsNamespaceFromRoute(parsed.GetRoute()) to ActionScope), pass that
ActionScope directly into actionFunc when calling it, and update the caller
closures (the buildWasmActionsForRateLimit closure that currently re-wraps
ActionScope(scope)) to remove the redundant ActionScope(scope) re-wrap so the
scope type boundary is explicit and preserved.
internal/controller/ratelimit_workflow_helpers_test.go (1)

22-25: 💤 Low value

BeAssignableToTypeOf assertions are trivially true and add no safety signal.

A value already declared as LimitNamespace or ActionScope is always assignable to its own type. These tests will pass even if the type system is broken. They should either be removed or replaced with tests that actually exercise the conversion boundary — e.g., verifying ToActionScope() (the explicit conversion method described in the PR objectives) returns the correct type and value.

Also applies to: 31-34, 58-61

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

In `@internal/controller/ratelimit_workflow_helpers_test.go` around lines 22 - 25,
Replace the meaningless BeAssignableToTypeOf assertions in the tests (e.g., the
spec creating ns := LimitNamespace("mynamespace/myroute") and similar cases for
ActionScope) with real conversion/value checks: call the explicit conversion
method ToActionScope() or the relevant conversion function and Assert the
returned type/value equals the expected ActionScope string/struct (use
Expect(converted).To(Equal(expected)) or
Expect(converted).To(BeAssignableToTypeOf(ActionScope(""))) plus an equality
check); remove any redundant tests that only assert a value is assignable to its
own declared type and apply the same replacement to the other occurrences
referenced in the comment (the tests at the other two blocks).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@tests/istio/extension_reconciler_test.go`:
- Line 462: The test is comparing a string-typed Scope
(actionSet.Actions[1].Scope) against a value of the named type
controllers.LimitNamespace, causing Gomega Equal to fail due to type mismatch;
update each failing Expect call in the "Full featured RLP targeting HTTPRoute"
test (and the five other sites listed) to convert the named type to string by
calling string(controllers.LimitsNamespaceFromRoute(httpRoute)) so the assertion
compares identical string types (i.e., change
Equal(controllers.LimitsNamespaceFromRoute(...)) to
Equal(string(controllers.LimitsNamespaceFromRoute(...))) for the Expect checks
referencing actionSet.Actions[n].Scope).

---

Nitpick comments:
In `@internal/controller/ratelimit_workflow_helpers_test.go`:
- Around line 22-25: Replace the meaningless BeAssignableToTypeOf assertions in
the tests (e.g., the spec creating ns := LimitNamespace("mynamespace/myroute")
and similar cases for ActionScope) with real conversion/value checks: call the
explicit conversion method ToActionScope() or the relevant conversion function
and Assert the returned type/value equals the expected ActionScope string/struct
(use Expect(converted).To(Equal(expected)) or
Expect(converted).To(BeAssignableToTypeOf(ActionScope(""))) plus an equality
check); remove any redundant tests that only assert a value is assignable to its
own declared type and apply the same replacement to the other occurrences
referenced in the comment (the tests at the other two blocks).

In `@internal/controller/ratelimit_workflow_helpers.go`:
- Around line 34-36: Add a conversion method on LimitNamespace named
ToActionScope that returns ActionScope; replace ad-hoc casts
ActionScope(limitsNamespace) with limitsNamespace.ToActionScope() in
buildWasmActionsForRateLimit and buildWasmActionsForTokenRateLimit so callers
use the explicit conversion method (declare func (n LimitNamespace)
ToActionScope() ActionScope and update the two buildWasm... functions to call
it).
- Around line 375-422: buildWasmActionsForAnyRateLimit is losing the ActionScope
type by declaring actionFunc's scope parameter as string and converting
LimitsNamespace to string before calling it; change the actionFunc signature to
take kuadrantv1.ActionScope (or the ActionScope type you introduced) instead of
string, keep limitsNamespace as an ActionScope (or cast it once from
LimitsNamespaceFromRoute(parsed.GetRoute()) to ActionScope), pass that
ActionScope directly into actionFunc when calling it, and update the caller
closures (the buildWasmActionsForRateLimit closure that currently re-wraps
ActionScope(scope)) to remove the redundant ActionScope(scope) re-wrap so the
scope type boundary is explicit and preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1eb15134-0e05-4a74-9121-a6867de81c13

📥 Commits

Reviewing files that changed from the base of the PR and between ec89156 and 67edad9.

📒 Files selected for processing (9)
  • internal/controller/limitador_limits_reconciler.go
  • internal/controller/ratelimit_workflow_helpers.go
  • internal/controller/ratelimit_workflow_helpers_test.go
  • internal/controller/ratelimit_workflow_test.go
  • internal/controller/tokenratelimit_workflow_test.go
  • tests/common/ratelimitpolicy/ratelimitpolicy_controller_test.go
  • tests/common/ratelimitpolicy/suite_test.go
  • tests/envoygateway/extension_reconciler_test.go
  • tests/istio/extension_reconciler_test.go

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.

Add type safety for rate limit namespace and scope identifiers

1 participant