Skip to content

Front the Agent Manager API with the API Platform Gateway (phase 1)#1307

Closed
RAVEENSR wants to merge 2 commits into
wso2:mainfrom
RAVEENSR:amp-api-gateway-scope-manifest
Closed

Front the Agent Manager API with the API Platform Gateway (phase 1)#1307
RAVEENSR wants to merge 2 commits into
wso2:mainfrom
RAVEENSR:amp-api-gateway-scope-manifest

Conversation

@RAVEENSR

@RAVEENSR RAVEENSR commented Jul 11, 2026

Copy link
Copy Markdown
Member

Purpose

Today all traffic to api.amp.localhost is routed by the control-plane kgateway straight to amp-api, and JWT validation plus scope checks happen only inside the service. There is no gateway-level enforcement point in front of the platform API, even though the platform already ships the WSO2 API Platform Gateway (deployed per-environment as the data-plane "AI Gateway").

This PR is phase 1 of putting the Agent Manager API behind that gateway so token validation and per-operation scope enforcement can happen at the edge. Everything is gated behind a feature flag that defaults off, so this is a no-op for existing installs.

Related to #1131

Goals

  • Enforce JWT validation and per-operation OAuth scopes at the gateway for the /api/v1 surface, without hand-maintaining a scope list that can drift from the service's route registrars.
  • Keep the change inert until explicitly enabled, and atomically reversible.
  • Preserve amp-api's own JWT + RBAC middleware as defense in depth — the gateway is an additional layer, never the sole authority.

Approach

Route → scope manifest generator. A new AST-based tool (agent-manager-service/scripts/gen_gateway_route_manifest) reads the HTTP route registrars in api/*.go and the rbac permission constants, and emits a deterministic manifest (deployments/helm-charts/wso2-agent-manager/files/amp-api-route-scopes.yaml). It folds string literals, local variables, concatenation and the route() helper, resolves rbac.<Perm> selectors, and hard-fails on anything it cannot resolve statically so drift becomes a build error. make gen-gateway-scopes regenerates it; make gen-gateway-scopes-check runs in the existing codegen-format CI job. Routes that are dynamic, root-OU, or validation-only are classified jwt-only (authenticated but not scope-enforced at the gateway).

Chart templates (flag-gated, default off). Under templates/api-gateway/:

  • A standalone APIGateway CR (no control-plane registration/token) reconciled by the cluster-wide gateway-operator.
  • A configRef ConfigMap for the gateway stack, cloned from the per-env extension with the control-plane block dropped and the jwt-auth keymanager derived from the same Thunder issuer/JWKS amp-api validates against, so both hops accept identical tokens. The instance-global upstream route timeout is raised (gateway 1.1.0 has no per-route knob and its 60s default is too tight for slow build-log/metric calls).
  • A RestApi CR whose operations are generated from the manifest. Scoped routes carry requiredScopes only when enforcement is on; OPTIONS /* and GET /config carry no policy so CORS preflight and pre-login discovery pass through.

oc-ingress repoints /api/v1 to the gateway runtime (with a ReferenceGrant entry); /mcp, /auth/*, /.well-known/* and /healthz stay direct on amp-api. Scope enforcement follows agentManagerService.config.rbacEnabled unless apiGateway.enforceScopes overrides it, so the gateway never enforces scopes the service is configured to skip.

User stories

As a platform operator, I can enforce OAuth scopes for the Agent Manager API at the gateway edge, keeping in-service checks as a second layer, and turn the whole thing on or off with a single flag.

Release note

Added an opt-in API Platform Gateway in front of the Agent Manager API for gateway-level JWT validation and per-operation scope enforcement (disabled by default).

Documentation

N/A for this phase — the feature is disabled by default and not yet documented in the install guides. Documentation and enablement follow once the standalone gateway is validated on a real cluster.

Training

N/A — no training-content impact.

Certification

N/A — no certification-exam impact; this is an internal deployment/enforcement change with no new end-user concepts.

Marketing

N/A — no marketing content for an internal, default-off infrastructure change.

Automation tests

  • Unit tests

    New table/AST tests for the generator (scripts/gen_gateway_route_manifest): permission parsing, all five registrar variants, local/concat/route() folding, hard-fails on unresolvable patterns / unknown permissions / greedy wildcards, and deterministic sorted rendering. An integration test runs the generator against the live api/ package and asserts all 229 routes resolve (221 scoped / 6 any-scopes / 2 jwt-only).

  • Integration tests

    Chart rendering verified with helm template and helm lint in both states: disabled renders zero gateway resources and leaves /api/v1 on amp-api; enabled renders the APIGateway CR, configRef ConfigMap and RestApi, repoints /api/v1, and emits per-operation requiredScopes (dropped when enforcement is off). Standalone-operator behavior on a real cluster is the phase-2 rollout gate before the flag is enabled anywhere.

Security checks

Samples

N/A

Related PRs

N/A — first PR in the phased rollout.

Migrations (if applicable)

N/A — feature flag defaults off; enabling and disabling are both handled by Helm with no data migration or state change.

Test environment

  • Go 1.26 (go test for the generator)
  • Helm v4 (helm template / helm lint) for chart rendering

Learning

Design was grounded in the WSO2 API Platform Gateway 1.1.0 sources (gateway-controller, gateway-runtime, gateway-controllers jwt-auth policy) and the published gateway Helm chart, confirming standalone APIGateway support, {param} path-template matching, the requiredScopes semantics, and the instance-global timeout model.

https://claude.ai/code/session_013NPK1n7XSXtedczmv2pXx7

Summary by CodeRabbit

  • New Features

    • Added optional API Gateway deployment for the Agent Manager API, configurable through Helm values.
    • Added gateway routing, TLS, runtime, policy, replica, and timeout configuration options.
    • Added automatic route-level JWT authentication and OAuth scope enforcement.
    • Added generated coverage for API routes and required authorization scopes.
  • Bug Fixes

    • Added validation to detect outdated gateway route and scope definitions during pull request checks.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a99af6f4-6809-4032-b03d-89a22315ab6f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds AST-based gateway route manifest generation with CI drift checks, then introduces optional API Platform Gateway Helm resources, scope-aware RestApi operations, configurable gateway settings, and /api/v1 ingress routing.

Changes

Gateway integration

Layer / File(s) Summary
Static route extraction
agent-manager-service/scripts/gen_gateway_route_manifest/generate.go
Extracts registrar routes and RBAC scopes from Go ASTs, validates patterns, and renders deterministic YAML.
Generator CLI and validation
agent-manager-service/scripts/gen_gateway_route_manifest/main.go, agent-manager-service/scripts/gen_gateway_route_manifest/*_test.go
Adds CLI file loading and tests for extraction, expression folding, failure cases, rendering, and real API route counts.
Committed manifest and drift checks
deployments/helm-charts/wso2-agent-manager/files/amp-api-route-scopes.yaml, agent-manager-service/Makefile, .github/workflows/*, agent-manager-service/AGENTS.md
Commits the generated route manifest and adds regeneration, verification, CI, and development-instruction updates.
Gateway resources and route policies
deployments/helm-charts/wso2-agent-manager/templates/_helpers.tpl, deployments/helm-charts/wso2-agent-manager/templates/api-gateway/*
Adds gateway naming, configuration, APIGateway and RestApi resources, and manifest-driven JWT scope policies.
Ingress routing and gateway values
deployments/helm-charts/wso2-agent-manager/values.yaml, deployments/helm-charts/wso2-agent-manager/templates/oc-ingress.yaml
Adds API Gateway configuration and conditionally routes /api/v1 traffic to the gateway runtime service.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant HTTPRoute
  participant GatewayRuntime
  participant RestApi
  participant AgentManager
  Client->>HTTPRoute: request /api/v1
  HTTPRoute->>GatewayRuntime: forward to port 22893
  GatewayRuntime->>RestApi: apply route and JWT policy
  RestApi->>AgentManager: proxy authorized request
Loading

Possibly related PRs

Suggested reviewers: hanzjk, rasika2012, jhivandb

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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
Title check ✅ Passed The title clearly summarizes the main change: fronting the Agent Manager API with the API Platform Gateway.
Description check ✅ Passed The description follows the repository template and includes all required sections with substantive details or N/A notes.
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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
agent-manager-service/scripts/gen_gateway_route_manifest/generate.go (1)

44-45: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

resourceServerPrefix is hardcoded; consider parsing it from the rbac source.

The generator already parses rbac/permissions.go via parsePermissions but skips the ResourceServer constant, hardcoding "amp" instead. If rbac.ResourceServer ever changes, the generator will silently emit incorrect scope strings. Extracting the prefix from the same AST walk is straightforward and eliminates the drift risk.

♻️ Proposed refactor: parse ResourceServer alongside permissions
 const resourceServerPrefix = "amp"
+// or make it a var populated during parsePermissions
 
 // parsePermissions reads an rbac permissions source file and returns a map from
 // the Go constant name (e.g. "MonitorScoreRead") to its full scope string
 // (e.g. "amp:monitor:score-read"), matching rbac.Permission.Scope().
-func parsePermissions(file *ast.File) (map[string]string, error) {
+func parsePermissions(file *ast.File) (string, map[string]string, error) {
+	prefix := "amp" // fallback
 	perms := map[string]string{}
 	for _, decl := range file.Decls {
 		gen, ok := decl.(*ast.GenDecl)
 		if !ok {
 			continue
 		}
 		for _, spec := range gen.Specs {
 			vs, ok := spec.(*ast.ValueSpec)
 			if !ok {
 				continue
 			}
+			// Extract ResourceServer constant
+			if len(vs.Names) == 1 && vs.Names[0].Name == "ResourceServer" && len(vs.Values) == 1 {
+				if lit, ok := vs.Values[0].(*ast.BasicLit); ok {
+					if p, err := strconv.Unquote(lit.Value); err == nil {
+						prefix = p
+					}
+				}
+				continue
+			}
 			typeName, ok := vs.Type.(*ast.Ident)
 			if !ok || typeName.Name != "Permission" || len(vs.Names) != 1 || len(vs.Values) != 1 {
 				continue
 			}
 			lit, ok := vs.Values[0].(*ast.BasicLit)
 			if !ok {
 				continue
 			}
 			value, err := strconv.Unquote(lit.Value)
 			if err != nil {
-				return nil, fmt.Errorf("permission %s: %w", vs.Names[0].Name, err)
+				return "", nil, fmt.Errorf("permission %s: %w", vs.Names[0].Name, err)
 			}
-			perms[vs.Names[0].Name] = resourceServerPrefix + ":" + value
+			perms[vs.Names[0].Name] = prefix + ":" + value
 		}
 	}
-	return perms, nil
+	return prefix, perms, nil
 }

Then update callers (main.go, generate_test.go, integration_test.go) to use the returned prefix instead of the hardcoded constant.

🤖 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 `@agent-manager-service/scripts/gen_gateway_route_manifest/generate.go` around
lines 44 - 45, Update parsePermissions to extract the rbac.ResourceServer
constant from the same AST traversal and return it alongside the parsed
permissions. Remove the hardcoded resourceServerPrefix usage, and update callers
in main.go, generate_test.go, and integration_test.go to consume the parsed
prefix when generating scope strings.
🤖 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.

Inline comments:
In
`@deployments/helm-charts/wso2-agent-manager/templates/api-gateway/config.yaml`:
- Around line 100-106: Update the ThunderKeyManager JWKS remote configuration in
the Helm template so skipTlsVerify is controlled by a chart value, defaulting to
false when unset; preserve operator override support for deployments that
explicitly require TLS verification to be skipped.

---

Nitpick comments:
In `@agent-manager-service/scripts/gen_gateway_route_manifest/generate.go`:
- Around line 44-45: Update parsePermissions to extract the rbac.ResourceServer
constant from the same AST traversal and return it alongside the parsed
permissions. Remove the hardcoded resourceServerPrefix usage, and update callers
in main.go, generate_test.go, and integration_test.go to consume the parsed
prefix when generating scope strings.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aa1cd000-57ce-4926-bd09-a9fef07e0831

📥 Commits

Reviewing files that changed from the base of the PR and between 949344d and ed5120f.

📒 Files selected for processing (14)
  • .github/workflows/agent-manager-service-pr-checks.yaml
  • agent-manager-service/AGENTS.md
  • agent-manager-service/Makefile
  • agent-manager-service/scripts/gen_gateway_route_manifest/generate.go
  • agent-manager-service/scripts/gen_gateway_route_manifest/generate_test.go
  • agent-manager-service/scripts/gen_gateway_route_manifest/integration_test.go
  • agent-manager-service/scripts/gen_gateway_route_manifest/main.go
  • deployments/helm-charts/wso2-agent-manager/files/amp-api-route-scopes.yaml
  • deployments/helm-charts/wso2-agent-manager/templates/_helpers.tpl
  • deployments/helm-charts/wso2-agent-manager/templates/api-gateway/apigateway.yaml
  • deployments/helm-charts/wso2-agent-manager/templates/api-gateway/config.yaml
  • deployments/helm-charts/wso2-agent-manager/templates/api-gateway/restapi.yaml
  • deployments/helm-charts/wso2-agent-manager/templates/oc-ingress.yaml
  • deployments/helm-charts/wso2-agent-manager/values.yaml

Comment on lines +100 to +106
- name: ThunderKeyManager
issuer: {{ .Values.agentManagerService.config.keyManager.issuer | quote }}
jwks:
remote:
uri: {{ .Values.agentManagerService.config.keyManager.jwksUrl | quote }}
skipTlsVerify: true
{{- end }}

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.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

skipTlsVerify: true is hardcoded for the default JWKS remote.

The default JWKS URL uses plain HTTP so this is currently harmless, but if an operator configures an HTTPS JWKS endpoint, TLS verification will be silently skipped. Consider making this configurable via values or defaulting to false so HTTPS JWKS endpoints are verified by default.

🔒 Suggested fix: make skipTlsVerify configurable
               - name: ThunderKeyManager
                 issuer: {{ .Values.agentManagerService.config.keyManager.issuer | quote }}
                 jwks:
                   remote:
                     uri: {{ .Values.agentManagerService.config.keyManager.jwksUrl | quote }}
-                    skipTlsVerify: true
+                    skipTlsVerify: {{ .Values.apiGateway.jwksSkipTlsVerify | default false }}
📝 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
- name: ThunderKeyManager
issuer: {{ .Values.agentManagerService.config.keyManager.issuer | quote }}
jwks:
remote:
uri: {{ .Values.agentManagerService.config.keyManager.jwksUrl | quote }}
skipTlsVerify: true
{{- end }}
- name: ThunderKeyManager
issuer: {{ .Values.agentManagerService.config.keyManager.issuer | quote }}
jwks:
remote:
uri: {{ .Values.agentManagerService.config.keyManager.jwksUrl | quote }}
skipTlsVerify: {{ .Values.apiGateway.jwksSkipTlsVerify | default false }}
{{- end }}
🤖 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 `@deployments/helm-charts/wso2-agent-manager/templates/api-gateway/config.yaml`
around lines 100 - 106, Update the ThunderKeyManager JWKS remote configuration
in the Helm template so skipTlsVerify is controlled by a chart value, defaulting
to false when unset; preserve operator override support for deployments that
explicitly require TLS verification to be skipped.

@RAVEENSR RAVEENSR marked this pull request as draft July 13, 2026 12:51
RAVEENSR added 2 commits July 13, 2026 18:41
The Agent Manager API is being fronted by the API Platform Gateway so
that JWT validation and scope enforcement happen at the gateway, not
only inside the service. The gateway needs a per-operation list of
required scopes, and that mapping already lives in the Go route
registrars (api/*.go declare an rbac permission per route). Maintaining
a second hand-written copy for the gateway would drift.

Add an AST-based generator (scripts/gen_gateway_route_manifest) that
reads the RouteRegistrar calls and rbac permission constants and emits a
deterministic manifest (amp-api-route-scopes.yaml) the Helm chart will
render into the RestApi CR's jwt-auth policies. It folds string
literals, local variables, concatenation, and the route() helper, and
hard-fails on any pattern or permission it cannot resolve statically so
drift becomes a build error rather than a silent gap.

Wire make gen-gateway-scopes / gen-gateway-scopes-check and run the
drift check in the existing codegen-format CI job. Routes classified as
dynamic, root-OU, or validation-only are emitted as jwt-only; amp-api
remains the authority for those.

Related to wso2#1131
Render a standalone API Platform Gateway in front of the Agent Manager
API so JWT validation and per-operation scope enforcement can happen at
the gateway (issue wso2#1131). This is phase 1: everything is gated behind
apiGateway.enabled and defaults off, so existing installs are unchanged.

New templates under templates/api-gateway/:
  * APIGateway CR — standalone (no controlPlane, no registration token);
    the cluster-wide gateway-operator reconciles it into the runtime.
  * configRef ConfigMap — the gateway stack values, cloned from the
    per-env extension with the controlPlane block dropped and the
    jwt-auth keymanager derived from the same Thunder issuer/JWKS amp-api
    validates against, so both hops accept identical tokens. The instance
    route timeout is raised (timeouts are instance-global in gateway
    1.1.0 and 60s is too tight for slow build-log/metric calls).
  * RestApi CR — context /api/v1, operations generated from the checked-in
    route-scope manifest. Scoped routes carry requiredScopes only when
    enforcement is on; OPTIONS /* and GET /config carry no policy so CORS
    preflight and pre-login discovery pass through.

The jwt-auth policy sets forwardedTokenHeader: Authorization so the
original bearer reaches amp-api under Authorization (the policy default,
x-forwarded-authorization, would strip it) — amp-api keeps validating the
token and enforcing org/tenant isolation as defense in depth.

oc-ingress repoints /api/v1 to the gateway runtime (with a ReferenceGrant
entry); /mcp, /auth/*, /.well-known/* and /healthz stay direct on amp-api.
Scope enforcement follows agentManagerService.config.rbacEnabled unless
apiGateway.enforceScopes overrides it, so the gateway never enforces
scopes the service is configured to skip.

Related to wso2#1131
@RAVEENSR RAVEENSR force-pushed the amp-api-gateway-scope-manifest branch from fddea0e to 5c159ba Compare July 13, 2026 13:12
@RAVEENSR

Copy link
Copy Markdown
Member Author

We decided not to introduce the API Platform API Gateway between the controlplane amp-api and the edg cp kagateway.

@RAVEENSR RAVEENSR closed this Jul 15, 2026
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