```
├── .cargo/
├── config.toml (100 tokens)
├── .devcontainer.json
├── .dockerignore
├── .gitattributes (omitted)
├── .githooks/
├── prepare-commit-msg (100 tokens)
├── .github/
├── dependabot.yml (500 tokens)
├── vex/
├── openvex.json (400 tokens)
├── workflows/
├── cache-e2e
├── cache-lint
├── cache-test
├── debug_cache.yml (300 tokens)
├── nightly.yml (1100 tokens)
├── pull_request.yml (1900 tokens)
├── release.yml (4.6k tokens)
├── .gitignore
├── CHARTER.md (2.2k tokens)
├── CODEOWNERS
├── CODE_OF_CONDUCT.md (300 tokens)
├── CONTRIBUTION.md (700 tokens)
├── Cargo.lock (omitted)
├── Cargo.toml (1700 tokens)
├── DEVELOPMENT.md (100 tokens)
├── Dockerfile (600 tokens)
├── Dockerfile.windows (400 tokens)
├── LICENSE (omitted)
├── Makefile (600 tokens)
├── README.md (1400 tokens)
├── SECURITY.md (100 tokens)
├── Tiltfile (1200 tokens)
├── api/
├── go.mod
├── go.sum (100 tokens)
├── resource.pb.go (100.7k tokens)
├── resource_json.gen.go (12.3k tokens)
├── architecture/
├── README.md
├── cel.md (600 tokens)
├── configuration.md (800 tokens)
├── buf.gen.yaml
├── buf.yaml
├── common/
├── scripts/
├── get-agentgateway (1800 tokens)
├── controller/
├── .custom-gcl.yml (100 tokens)
├── .golangci.yaml (1200 tokens)
├── Makefile (6.7k tokens)
├── api/
├── README.md (1100 tokens)
├── annotations/
├── agentgateway.go (100 tokens)
├── settings/
├── settings.go (2k tokens)
├── settings_test.go (2.7k tokens)
├── tests/
├── agentgateway_policy_test.go (600 tokens)
├── cel_test.go (400 tokens)
├── testdata/
├── agentgateway_backend_invalid.yaml (600 tokens)
├── agentgateway_backend_valid.yaml (700 tokens)
├── agentgateway_parameters_invalid.yaml (200 tokens)
├── agentgateway_parameters_valid.yaml
├── agentgateway_policy_invalid.yaml (3.7k tokens)
├── agentgateway_policy_valid.yaml (3.7k tokens)
├── validator.go (300 tokens)
├── v1alpha1/
├── agentgateway/
├── agentgateway_backend_types.go (4.3k tokens)
├── agentgateway_parameters_types.go (1900 tokens)
├── agentgateway_policy_types.go (18.3k tokens)
├── ai_policy.go (2.9k tokens)
├── doc.go
├── zz_generated.deepcopy.go (19.5k tokens)
├── zz_generated.register.go (400 tokens)
├── shared/
├── doc.go
├── overlay_types.go (1100 tokens)
├── policy_types.go (400 tokens)
├── rbac.go (500 tokens)
├── shared_types.go (1300 tokens)
├── timeouts.go (200 tokens)
├── zz_generated.deepcopy.go (2.1k tokens)
├── cmd/
├── agctl/
├── main.go
├── agentgateway/
├── Dockerfile.agentgateway
├── main.go (200 tokens)
├── dependencies_test.go (800 tokens)
├── hack/
├── bump_deps.sh (100 tokens)
├── ci/
├── get-recent-flakes.sh (1400 tokens)
├── crdgen/
├── main.go (5.3k tokens)
├── main_test.go (1500 tokens)
├── testdata/
├── embedded/
├── types.go
├── ifthenembedded/
├── api/
├── v1/
├── doc.go
├── types.go (100 tokens)
├── embedded/
├── types.go
├── root/
├── types.go (100 tokens)
├── generate-release-notes.sh (2.1k tokens)
├── generate.go
├── generate.sh (600 tokens)
├── helm/
├── dev-pdb.yaml
├── dev.yaml (100 tokens)
├── run-e2e-test.sh (6.3k tokens)
├── testbox/
├── Dockerfile
├── README.md (100 tokens)
├── a2a.go (500 tokens)
├── app_echo.go (200 tokens)
├── dummy-idp.cert (400 tokens)
├── dummy-idp.key
├── dummy_idp.go (2.3k tokens)
├── extauth.go (800 tokens)
├── extproc.go (1700 tokens)
├── main.go (200 tokens)
├── mcp.go (400 tokens)
├── runtime.go (200 tokens)
├── utils/
├── jwt/
├── jwt-generator.go (400 tokens)
├── oss_compliance/
├── osa_included.md
├── osa_provided.md (1100 tokens)
├── install/
├── dashboards/
├── README.md (100 tokens)
├── agentgateway-dashboard.py (3k tokens)
├── helm/
├── agentgateway-crds/
├── Chart.yaml (100 tokens)
├── templates/
├── NOTES.txt (100 tokens)
├── agentgateway.dev_agentgatewaybackends.yaml (160.2k tokens)
├── agentgateway.dev_agentgatewayparameters.yaml (10.7k tokens)
├── agentgateway.dev_agentgatewaypolicies.yaml (117.1k tokens)
├── values.yaml
├── agentgateway/
├── Chart.yaml
├── files/
├── agentgateway-dashboard.json (7.4k tokens)
├── templates/
├── NOTES.txt (200 tokens)
├── _helpers.tpl (600 tokens)
├── deployment.yaml (1500 tokens)
├── horizontalpodautoscaler.yaml (100 tokens)
├── monitoring.yaml (400 tokens)
├── poddisruptionbudget.yaml (100 tokens)
├── role.yaml (600 tokens)
├── service.yaml (600 tokens)
├── serviceaccount.yaml (200 tokens)
├── verticalpodautoscaler.yaml (100 tokens)
├── values.yaml (1900 tokens)
├── pkg/
├── admin/
├── krt_snapshot.go (100 tokens)
├── logging.go (800 tokens)
├── pprof.go (100 tokens)
├── response.go (400 tokens)
├── response_test.go (400 tokens)
├── server.go (900 tokens)
├── agentgateway/
├── ir/
├── ir.go (300 tokens)
├── jwks/
├── cache.go (400 tokens)
├── collections.go (700 tokens)
├── collections_test.go (400 tokens)
├── configmap_controller.go (1500 tokens)
├── configmap_controller_test.go (1000 tokens)
├── fetcher.go (2.9k tokens)
├── fetcher_test.go (3.8k tokens)
├── lookup.go (200 tokens)
├── lookup_test.go (1000 tokens)
├── mocks/
├── mock_jwks_http_client.go (300 tokens)
├── owner.go (800 tokens)
├── owner_test.go (400 tokens)
├── persistence.go (1900 tokens)
├── persistence_test.go (1400 tokens)
├── request.go (200 tokens)
├── request_test.go (2000 tokens)
├── resolver.go (200 tokens)
├── store.go (800 tokens)
├── store_test.go (4.2k tokens)
├── types.go (400 tokens)
├── jwks_url/
├── testdata/
├── gw-with-backend-all-configurable-fields.yaml (600 tokens)
├── gw-with-backend-clear-text.yaml (100 tokens)
├── gw-with-backend-default-tls.yaml (100 tokens)
├── gw-with-backend-insecure-skip-verify.yaml (200 tokens)
├── gw-with-backend-tunnel-proxy.yaml (300 tokens)
├── gw-with-backend-with-policy-ref-with-all-configurable-fields.yaml (700 tokens)
├── gw-with-backend-with-policy-ref-with-default-tls.yaml (200 tokens)
├── gw-with-backend-with-policy-ref-with-insecure-skip-verify.yaml (200 tokens)
├── gw-with-missing-backend.yaml (100 tokens)
├── gw-with-non-static-backend.yaml (200 tokens)
├── jwkspath-starts-with-slash.yaml (100 tokens)
├── svc-clear-text.yaml (100 tokens)
├── svc-insecure-skip-verify.yaml (200 tokens)
├── svc-with-all-configurable-fields.yaml (600 tokens)
├── svc-with-default-tls.yaml (200 tokens)
├── plugins/
├── a2a_plugin.go (600 tokens)
├── ai_policies.go (1700 tokens)
├── backend_policies.go (6.6k tokens)
├── backend_tls_plugin.go (2.6k tokens)
├── collection.go (2.2k tokens)
├── frontend_policies.go (3.7k tokens)
├── inference_plugin.go (2.2k tokens)
├── interfaces.go (1000 tokens)
├── jwks_lookup.go (100 tokens)
├── jwks_lookup_test.go (100 tokens)
├── jwks_translation_test.go (600 tokens)
├── reference_indexes.go (4.2k tokens)
├── registry.go (300 tokens)
├── registry_test.go (100 tokens)
├── status.go (1200 tokens)
├── status_test.go (600 tokens)
├── testdata/
├── backendpolicy/
├── _defaults.yaml (200 tokens)
├── ai.yaml (1200 tokens)
├── awsauth.yaml (300 tokens)
├── azureauth.yaml (300 tokens)
├── backend-ancestor-backend.yaml (300 tokens)
├── backend-auth-custom-header.yaml (300 tokens)
├── backend-chain-ancestor-backend.yaml (300 tokens)
├── backend-missing-not-attached.yaml (200 tokens)
├── eviction-invalid-cel.yaml (300 tokens)
├── eviction.yaml (300 tokens)
├── extauthz.yaml (400 tokens)
├── gcpauth.yaml (1000 tokens)
├── httproute-missing-not-attached.yaml (200 tokens)
├── mcp-auth-missing-persisted-keyset.yaml (500 tokens)
├── mcp-auth-resolver-backend-missing.yaml (400 tokens)
├── mcp-authz-gateway.yaml (400 tokens)
├── mcp-authz-invalid-cel.yaml (300 tokens)
├── mcp-authz-require-invalid-cel.yaml (300 tokens)
├── mcp-authz-require.yaml (400 tokens)
├── mcp-authz-route.yaml (400 tokens)
├── multi-target-ref-backend-policy.yaml (2k tokens)
├── policy-chain-existing-intermediate-target.yaml (700 tokens)
├── policy-chain-missing-intermediate-target.yaml (500 tokens)
├── policy-targets-missing-backend.yaml (200 tokens)
├── selector-backend.yaml (500 tokens)
├── selector-service.yaml (400 tokens)
├── service-port-chain-different-section.yaml (700 tokens)
├── simple.yaml (2.4k tokens)
├── transformation.yaml (300 tokens)
├── tunnel.yaml (300 tokens)
├── frontendpolicy/
├── _defaults.yaml (100 tokens)
├── accesslog-invalid-filter.yaml (300 tokens)
├── accesslog-otlp.yaml (400 tokens)
├── accesslog.yaml (300 tokens)
├── full.yaml (1000 tokens)
├── http.yaml (300 tokens)
├── metrics-invalid-expression.yaml (300 tokens)
├── metrics.yaml (300 tokens)
├── network-authz-require.yaml (300 tokens)
├── proxy.yaml (300 tokens)
├── tcp-keepalive.yaml (300 tokens)
├── tls-listener-no-gw.yaml (300 tokens)
├── tls.yaml (400 tokens)
├── tracing-invalid-attribute.yaml (400 tokens)
├── tracing.yaml (300 tokens)
├── trafficpolicy/
├── _defaults.yaml (200 tokens)
├── apikey-pre-routing.yaml (400 tokens)
├── authorization-invalid-cel.yaml (300 tokens)
├── authorization-require-invalid-cel.yaml (300 tokens)
├── basic-auth-pre-routing.yaml (300 tokens)
├── cel-invalid.yaml (300 tokens)
├── cel.yaml (500 tokens)
├── conditional.yaml (1600 tokens)
├── cors.yaml (400 tokens)
├── csrf.yaml (300 tokens)
├── extauthz-grpc-invalid-metadata.yaml (300 tokens)
├── extauthz-grpc.yaml (400 tokens)
├── extauthz-http-invalid-path.yaml (300 tokens)
├── extauthz-http.yaml (500 tokens)
├── extauthz-missing-backend.yaml (300 tokens)
├── extproc.yaml (300 tokens)
├── gateway-missing-not-attached.yaml (200 tokens)
├── global-rl-invalid-cel.yaml (400 tokens)
├── global-rl.yaml (400 tokens)
├── header-modifier.yaml (500 tokens)
├── http-route-ancestor-gateway.yaml (300 tokens)
├── http-route-ancestor-listenerset.yaml (500 tokens)
├── http-route-missing-not-attached.yaml (200 tokens)
├── inferencepool-policy-selector.yaml (700 tokens)
├── jwt-mcp.yaml (500 tokens)
├── jwt-pre-routing.yaml (500 tokens)
├── jwt-remote-missing-persisted-keyset.yaml (400 tokens)
├── jwt-remote-resolver-backend-missing.yaml (300 tokens)
├── listenerset-sectionname.yaml (400 tokens)
├── listenerset-selector.yaml (400 tokens)
├── listenerset-targetref.yaml (400 tokens)
├── mcp-auth-multi-target.yaml (4.4k tokens)
├── mcp-auth.yaml (1900 tokens)
├── multi-target-missing.yaml (500 tokens)
├── retry-invalid-attempts-exceeds-i32.yaml (300 tokens)
├── retry-invalid-attempts-negative.yaml (200 tokens)
├── retry.yaml (300 tokens)
├── selector-cross-namespace.yaml (200 tokens)
├── selector-gateway.yaml (500 tokens)
├── selector-grpcroute.yaml (300 tokens)
├── selector-httproute.yaml (300 tokens)
├── selector-no-match.yaml (200 tokens)
├── status-update.yaml (600 tokens)
├── timeout.yaml (300 tokens)
├── tls.go (600 tokens)
├── traffic_plugin.go (12.2k tokens)
├── traffic_plugin_test.go (200 tokens)
├── policyselection/
├── selector.go (1400 tokens)
├── selector_test.go (800 tokens)
├── remotehttp/
├── ca_bundle.go (400 tokens)
├── connection_resolver.go (1300 tokens)
├── endpoint.go (100 tokens)
├── fetch_key.go (300 tokens)
├── fetch_key_test.go (700 tokens)
├── resolver.go (600 tokens)
├── resolver_test.go (3.7k tokens)
├── service_matcher.go (400 tokens)
├── tls_resolver.go (900 tokens)
├── transport_fingerprint.go (100 tokens)
├── testutils/
├── status.go (400 tokens)
├── util.go (1900 tokens)
├── util_test.go (100 tokens)
├── translator/
├── agw.go (3.5k tokens)
├── ancestors_test.go (2.6k tokens)
├── builtin_helpers.go (700 tokens)
├── conditions.go (1300 tokens)
├── conversion.go (11.5k tokens)
├── gateway_collection.go (4.7k tokens)
├── gatewayclass_collection.go (200 tokens)
├── golden_test.go (1100 tokens)
├── model.go (1400 tokens)
├── network_gateway.go (200 tokens)
├── option.go (200 tokens)
├── option_test.go (400 tokens)
├── references_collection.go (1100 tokens)
├── route_collections.go (7.9k tokens)
├── testdata/
├── backends/
├── _defaults.yaml (100 tokens)
├── a2a.yaml (200 tokens)
├── ai-auth-passthrough.yaml (200 tokens)
├── ai-auth-secret-missing-authorization.yaml (200 tokens)
├── ai-auth-secret-ref-not-found.yaml (100 tokens)
├── ai-auth-secret-ref.yaml (200 tokens)
├── ai-priority-groups-secret-ref-invalid.yaml (200 tokens)
├── ai-priority-groups-secret-ref.yaml (300 tokens)
├── ai-priority-groups.yaml (300 tokens)
├── ai-webhook-backend-ref-not-found.yaml (200 tokens)
├── backendtlspolicy.yaml (800 tokens)
├── dynamic-forward-proxy-with-auth.yaml (200 tokens)
├── dynamic-forward-proxy.yaml (100 tokens)
├── inferencepool-multiport.yaml (800 tokens)
├── inferencepool-policy.yaml (700 tokens)
├── inferencepool.yaml (800 tokens)
├── llm-bedrock.yaml (300 tokens)
├── llm-host-path-prefix.yaml (200 tokens)
├── llm-multi-priority.yaml (500 tokens)
├── llm-multi-secret.yaml (400 tokens)
├── llm-multi.yaml (300 tokens)
├── llm-openai.yaml (200 tokens)
├── mcp-authentication-jwks-missing-persisted-keyset.yaml (200 tokens)
├── mcp-authentication-jwks-resolver-backend-missing.yaml (200 tokens)
├── mcp-selector.yaml (300 tokens)
├── mcp-service-backendref.yaml (300 tokens)
├── mcp-service-selector-sse.yaml (300 tokens)
├── mcp-service-selector-streamable.yaml (300 tokens)
├── mcp-static-multiple-targets.yaml (400 tokens)
├── mcp-static-no-protocol.yaml (300 tokens)
├── mcp-static-policy-error.yaml (200 tokens)
├── mcp-static-sse-protocol.yaml (200 tokens)
├── mcp-static-streamable.yaml (300 tokens)
├── mcp-static-with-policies.yaml (300 tokens)
├── mcp-static.yaml (300 tokens)
├── service.yaml (100 tokens)
├── serviceentry-with-network.yaml (800 tokens)
├── serviceentry.yaml (300 tokens)
├── simple.yaml (100 tokens)
├── static-auth-passthrough.yaml (200 tokens)
├── static-secrets-not-found.yaml (100 tokens)
├── static-tls-ca-bundle-not-found.yaml (100 tokens)
├── tls.yaml (3.5k tokens)
├── delegation/
├── _defaults.yaml (100 tokens)
├── route-delegation-all-references.yaml (1400 tokens)
├── route-delegation-backend-references.yaml (900 tokens)
├── route-delegation-child-filter.yaml (1100 tokens)
├── route-delegation-labels.yaml (600 tokens)
├── route-delegation-multiple-parents.yaml (1000 tokens)
├── route-delegation-policy-references.yaml (800 tokens)
├── route-delegation-precise.yaml (600 tokens)
├── route-delegation-scopes-gateway.yaml (800 tokens)
├── route-delegation.yaml (800 tokens)
├── gateways/
├── _defaults.yaml
├── hbone-listener.yaml (400 tokens)
├── invalid-tls.yaml (400 tokens)
├── listenerset-hostnameconflict.yaml (4.4k tokens)
├── listenerset-refgrant.yaml (2.6k tokens)
├── listenerset.yaml (1000 tokens)
├── reference-grant-multiple-to.yaml (1200 tokens)
├── simple-http.yaml (400 tokens)
├── tls-backend-client-cert.yaml (500 tokens)
├── tls-istio-workload.yaml (700 tokens)
├── tls-listeners-cross-ns.yaml (1500 tokens)
├── tls-listeners.yaml (900 tokens)
├── tls-passthrough-listeners.yaml (400 tokens)
├── references/
├── _defaults.yaml (200 tokens)
├── backend-policy-to-backend-ref-cyclic.yaml (300 tokens)
├── backend-policy-to-backend-ref-transitive.yaml (300 tokens)
├── backend-policy-to-backend-ref.yaml (200 tokens)
├── policy-to-backend-ref.yaml (300 tokens)
├── service-targeted-backend-policy-via-traffic-policy.yaml (900 tokens)
├── routes/
├── _defaults.yaml (200 tokens)
├── basic-http.yaml (300 tokens)
├── basic-tcp.yaml (600 tokens)
├── basic-tls.yaml (400 tokens)
├── grpc-header-route.yaml (400 tokens)
├── grpc-invalid.yaml (300 tokens)
├── grpc-missing-backend.yaml (300 tokens)
├── grpc-multi.yaml (400 tokens)
├── httproute-filters.yaml (1900 tokens)
├── httproute-missing-dest.yaml (400 tokens)
├── httproute-path-prefix-regex.yaml (300 tokens)
├── httproute-timeout-retry.yaml (700 tokens)
├── inferencepool-invalid-endpoint-picker-ref-fail-open.yaml (600 tokens)
├── inferencepool-invalid-endpoint-picker-ref.yaml (600 tokens)
├── inferencepool-multiport.yaml (700 tokens)
├── inferencepool.yaml (700 tokens)
├── listenerset-shared-listener-route-key.yaml (800 tokens)
├── matchers.yaml (500 tokens)
├── multi-delegation.yaml (900 tokens)
├── multi-match.yaml (300 tokens)
├── multi-rule-grpc-route.yaml (500 tokens)
├── simple-grpc-route.yaml (300 tokens)
├── to-backend-cross-ns.yaml (300 tokens)
├── to-backend.yaml (300 tokens)
├── two-routes-same-gateway.yaml (600 tokens)
├── weighted-backends.yaml (400 tokens)
├── utils/
├── inferencepool.go (100 tokens)
├── utils.go (1500 tokens)
├── apiclient/
├── client.go (200 tokens)
├── fake/
├── fake.go (900 tokens)
├── filters.go (200 tokens)
├── types.go (600 tokens)
├── cli/
├── config/
├── all.go (100 tokens)
├── backends.go (1400 tokens)
├── backends_test.go (1400 tokens)
├── cmd.go (700 tokens)
├── configdump.go (100 tokens)
├── table.go (100 tokens)
├── flag/
├── cmd.go (200 tokens)
├── generic.go (200 tokens)
├── globals.go (100 tokens)
├── kubeutil/
├── kube.go (600 tokens)
├── root.go (100 tokens)
├── trace/
├── cmd.go (700 tokens)
├── trace.go (6.1k tokens)
├── trace_test.go (700 tokens)
├── client/
├── clientset/
├── versioned/
├── clientset.go (700 tokens)
├── fake/
├── clientset_generated.go (600 tokens)
├── doc.go
├── register.go (300 tokens)
├── scheme/
├── doc.go
├── register.go (300 tokens)
├── typed/
├── v1alpha1/
├── agentgateway/
├── agentgatewaybackend.go (600 tokens)
├── agentgatewayparameters.go (600 tokens)
├── agentgatewaypolicy.go (600 tokens)
├── doc.go
├── fake/
├── doc.go
├── fake_agentgatewaybackend.go (300 tokens)
├── fake_agentgatewayparameters.go (300 tokens)
├── fake_agentgatewaypolicy.go (300 tokens)
├── fake_v1alpha1_client.go (200 tokens)
├── generated_expansion.go
├── v1alpha1_client.go (600 tokens)
├── common/
├── named_runnable.go
├── controller/
├── controller.go (800 tokens)
├── gatewayclass.go (1700 tokens)
├── gw_controller.go (4.2k tokens)
├── metrics.go (600 tokens)
├── start.go (2.2k tokens)
├── start_internal_test.go (100 tokens)
├── start_test.go (500 tokens)
├── deployer/
├── agentgateway_parameters.go (3.7k tokens)
├── agentgateway_parameters_test.go (2.9k tokens)
├── charts.go (300 tokens)
├── deployer.go (3.6k tokens)
├── deployer_factory.go (100 tokens)
├── deployer_test.go (3.6k tokens)
├── gateway_parameters.go (1800 tokens)
├── gatewayclass.go (500 tokens)
├── helm_values_generator.go (300 tokens)
├── strategicpatch/
├── strategicpatch.go (2.6k tokens)
├── strategicpatch_test.go (2.6k tokens)
├── tls.go (200 tokens)
├── tls_test.go (400 tokens)
├── values.go (400 tokens)
├── values_helpers.go (1000 tokens)
├── helm/
├── agentgateway/
├── .helmignore (100 tokens)
├── Chart.yaml
├── templates/
├── _helpers.tpl (500 tokens)
├── configmap.yaml (200 tokens)
├── deployment.yaml (1900 tokens)
├── service.yaml (200 tokens)
├── serviceaccount.yaml (100 tokens)
├── xds-ca-configmap.yaml (100 tokens)
├── values.yaml
├── embed.go
├── logging/
├── level.go (1400 tokens)
├── level_test.go (1200 tokens)
├── logger.go (800 tokens)
├── logger_test.go (400 tokens)
├── options.go (400 tokens)
├── options_test.go (400 tokens)
├── metrics/
├── cmd/
├── findmetrics/
├── main.go (1300 tokens)
├── metrics.go (1800 tokens)
├── metrics_test.go (2.5k tokens)
├── metricstest/
├── metricstest.go (3k tokens)
├── pluginsdk/
├── collections/
├── deployer.go (800 tokens)
├── discovery.go (1600 tokens)
├── krtutil/
├── index.go (100 tokens)
├── options.go (200 tokens)
├── reporter/
├── types.go (300 tokens)
├── types.go (200 tokens)
├── reports/
├── reporter.go (1700 tokens)
├── reporter_test.go (4.7k tokens)
├── status.go (3.7k tokens)
├── schemes/
├── scheme.go (500 tokens)
├── setup/
├── authn.go (800 tokens)
├── controlplane.go (800 tokens)
├── setup.go (3.1k tokens)
├── xds_tls.go (2.3k tokens)
├── xds_tls_test.go (2.1k tokens)
├── syncer/
├── README.md (11.2k tokens)
├── backend/
├── backend_plugin.go (3.6k tokens)
├── backend_plugin_test.go (5.7k tokens)
├── mcp.go (900 tokens)
├── testdata/
├── Bedrock_backend_with_new_route_types_(responses_and_anthropic_token_count).yaml (100 tokens)
├── MultiPool_backend_-_translates_all_providers_for_failover.yaml (100 tokens)
├── MultiPool_backend_with_multiple_priority_levels_-_creates_separate_provider_groups.yaml (100 tokens)
├── Namespace_selector_MCPBackend_backend.yaml (100 tokens)
├── OpenAI_backend_with_routes_configuration.yaml (100 tokens)
├── OpenAI_backend_with_secret_reference_auth.yaml (100 tokens)
├── Service_backendRef_MCPBackend_backend_-_same_namespace.yaml (100 tokens)
├── Service_selector_MCPBackend_backend_-_agentgateway.dev_appProtocol.yaml (100 tokens)
├── Service_selector_MCPBackend_backend_-_legacy_annotation_path.yaml (100 tokens)
├── Service_selector_MCPBackend_backend_-_new_annotation_takes_precedence.yaml (100 tokens)
├── Service_selector_MCPBackend_backend_-_same_namespace.yaml (100 tokens)
├── Static_MCPBackend_target_backend.yaml (100 tokens)
├── Valid_AWS_AgentCore_backend.yaml
├── Valid_Anthropic_backend_with_model.yaml
├── Valid_Azure_Foundry_backend.yaml (100 tokens)
├── Valid_Azure_OpenAI_backend.yaml (100 tokens)
├── Valid_Bedrock_backend_with_custom_region_and_guardrail.yaml (100 tokens)
├── Valid_Gemini_backend.yaml
├── Valid_OpenAI_backend_with_inline_auth.yaml
├── Valid_VertexAI_backend.yaml
├── backend_collections.go (400 tokens)
├── krtxds/
├── pushqueue.go (700 tokens)
├── pushqueue_test.go (1500 tokens)
├── xds.go (9.3k tokens)
├── xds_internal_test.go (200 tokens)
├── xds_test.go (1500 tokens)
├── mesh_config.go (200 tokens)
├── mesh_config_test.go (400 tokens)
├── nack/
├── publisher.go (700 tokens)
├── publisher_test.go (300 tokens)
├── option.go (400 tokens)
├── policy_collections.go (500 tokens)
├── service.go (4.8k tokens)
├── status/
├── collection.go (1100 tokens)
├── workerpool.go (1000 tokens)
├── status_syncer.go (4.1k tokens)
├── status_syncer_test.go (700 tokens)
├── syncer.go (6.8k tokens)
├── testdata/
├── outputs/
├── backend/
├── no-idp-mcp-authn.status.yaml (100 tokens)
├── no-idp-mcp-authn.yaml (400 tokens)
├── workloads.go (200 tokens)
├── utils/
├── cmdutils/
├── cmd.go (200 tokens)
├── local.go (800 tokens)
├── print_guard_default.go
├── print_guard_e2e.go
├── run_error.go (400 tokens)
├── envutils/
├── env.go (300 tokens)
├── fsutils/
├── fsutils.go (200 tokens)
├── fsutils_test.go (200 tokens)
├── helmutils/
├── client.go (700 tokens)
├── constants.go
├── install.go (300 tokens)
├── uninstall.go (200 tokens)
├── krtutil/
├── index.go (100 tokens)
├── kubeutils/
├── dns.go (100 tokens)
├── domain.go (400 tokens)
├── domain_test.go (400 tokens)
├── kubectl/
├── cli.go (3.1k tokens)
├── logs_options.go (400 tokens)
├── logs_options_test.go (500 tokens)
├── pods.go (400 tokens)
├── port.go (100 tokens)
├── portforward/
├── cli_portforwarder.go (800 tokens)
├── options.go (600 tokens)
├── portforwarder.go (200 tokens)
├── print_guard_default.go
├── print_guard_e2e.go
├── resource.go (200 tokens)
├── rest_config.go (300 tokens)
├── secrets.go (300 tokens)
├── namespaces/
├── namespaces.go (100 tokens)
├── requestutils/
├── curl/
├── native_request.go (1200 tokens)
├── option.go (900 tokens)
├── request.go (1100 tokens)
├── request_test.go (200 tokens)
├── stopwatch/
├── stopwatch.go (400 tokens)
├── threadsafe/
├── buffer.go (300 tokens)
├── writer.go (100 tokens)
├── version/
├── version.go (300 tokens)
├── wellknown/
├── agw.go (300 tokens)
├── constants.go (200 tokens)
├── controller.go (200 tokens)
├── gwapi.go (900 tokens)
├── istio.go (100 tokens)
├── kube.go (200 tokens)
├── ports.go
├── translator.go
├── test/
├── README.md (100 tokens)
├── conformance/
├── conformance_test.go (1900 tokens)
├── deployer/
├── deployer_helm.go (2.4k tokens)
├── internal_helm_test.go (4k tokens)
├── testdata/
├── agentgateway-agwp-pod-scheduling-out.yaml (1300 tokens)
├── agentgateway-agwp-pod-scheduling.yaml (400 tokens)
├── agentgateway-aws-annotations-out.yaml (1200 tokens)
├── agentgateway-aws-annotations.yaml (200 tokens)
├── agentgateway-aws-nlb-dummy-port-out.yaml (1200 tokens)
├── agentgateway-aws-nlb-dummy-port.yaml (200 tokens)
├── agentgateway-azure-annotations-out.yaml (1200 tokens)
├── agentgateway-azure-annotations.yaml (200 tokens)
├── agentgateway-both-gwc-and-gw-have-params-out.yaml (1200 tokens)
├── agentgateway-both-gwc-and-gw-have-params.yaml (400 tokens)
├── agentgateway-controller-but-custom-gatewayclass-out.yaml (1200 tokens)
├── agentgateway-controller-but-custom-gatewayclass.yaml (100 tokens)
├── agentgateway-custom-configmap-out.yaml (1200 tokens)
├── agentgateway-custom-configmap.yaml (200 tokens)
├── agentgateway-deep-merging-out.yaml (1300 tokens)
├── agentgateway-deep-merging.yaml (400 tokens)
├── agentgateway-env-out.yaml (1200 tokens)
├── agentgateway-env.yaml (200 tokens)
├── agentgateway-gateway-addresses-out.yaml (1100 tokens)
├── agentgateway-gateway-addresses.yaml (100 tokens)
├── agentgateway-gke-subsetting-static-ip-out.yaml (1200 tokens)
├── agentgateway-gke-subsetting-static-ip.yaml (200 tokens)
├── agentgateway-hpa-overlay-out.yaml (1300 tokens)
├── agentgateway-hpa-overlay.yaml (200 tokens)
├── agentgateway-image-override-out.yaml (1200 tokens)
├── agentgateway-image-override.yaml (200 tokens)
├── agentgateway-image-pull-secrets-out.yaml (1200 tokens)
├── agentgateway-image-pull-secrets.yaml (200 tokens)
├── agentgateway-image-repo-only-out.yaml (1100 tokens)
├── agentgateway-image-repo-only.yaml (200 tokens)
├── agentgateway-infrastructure-out.yaml (1300 tokens)
├── agentgateway-infrastructure.yaml (400 tokens)
├── agentgateway-init-containers-out.yaml (1200 tokens)
├── agentgateway-init-containers.yaml (200 tokens)
├── agentgateway-istio-additional-trust-domains-out.yaml (1300 tokens)
├── agentgateway-istio-additional-trust-domains.yaml (200 tokens)
├── agentgateway-istio-out.yaml (1300 tokens)
├── agentgateway-istio.yaml (200 tokens)
├── agentgateway-loadbalancer-static-ip-out.yaml (1100 tokens)
├── agentgateway-loadbalancer-static-ip.yaml (200 tokens)
├── agentgateway-logging-format-out.yaml (1100 tokens)
├── agentgateway-logging-format.yaml (100 tokens)
├── agentgateway-long-gateway-name-exactly-63-chars-out.yaml (1500 tokens)
├── agentgateway-long-gateway-name-exactly-63-chars.yaml (100 tokens)
├── agentgateway-long-gateway-name-over-63-chars-out.yaml (1500 tokens)
├── agentgateway-long-gateway-name-over-63-chars.yaml (100 tokens)
├── agentgateway-omitdefaultsecuritycontext-out.yaml (1100 tokens)
├── agentgateway-omitdefaultsecuritycontext-ref-gwp-on-gw-out.yaml (1100 tokens)
├── agentgateway-omitdefaultsecuritycontext-ref-gwp-on-gw.yaml (200 tokens)
├── agentgateway-omitdefaultsecuritycontext.yaml (200 tokens)
├── agentgateway-out.yaml (1100 tokens)
├── agentgateway-params-primary-out.yaml (1200 tokens)
├── agentgateway-params-primary.yaml (500 tokens)
├── agentgateway-pdb-overlay-out.yaml (1300 tokens)
├── agentgateway-pdb-overlay.yaml (200 tokens)
├── agentgateway-rawconfig-binds-out.yaml (1200 tokens)
├── agentgateway-rawconfig-binds.yaml (200 tokens)
├── agentgateway-rawconfig-typed-conflict-out.yaml (1200 tokens)
├── agentgateway-rawconfig-typed-conflict.yaml (200 tokens)
├── agentgateway-replicas-out.yaml (1100 tokens)
├── agentgateway-replicas.yaml (200 tokens)
├── agentgateway-resource-requests-overlay-out.yaml (1100 tokens)
├── agentgateway-resource-requests-overlay.yaml (200 tokens)
├── agentgateway-sa-iam-annotations-out.yaml (1200 tokens)
├── agentgateway-sa-iam-annotations.yaml (200 tokens)
├── agentgateway-security-context-out.yaml (1200 tokens)
├── agentgateway-security-context.yaml (200 tokens)
├── agentgateway-shutdown-out.yaml (1100 tokens)
├── agentgateway-shutdown.yaml (100 tokens)
├── agentgateway-sidecar-containers-out.yaml (1200 tokens)
├── agentgateway-sidecar-containers.yaml (200 tokens)
├── agentgateway-strategic-merge-patch-out.yaml (1200 tokens)
├── agentgateway-strategic-merge-patch.yaml (500 tokens)
├── agentgateway-tls-out.yaml (1500 tokens)
├── agentgateway-tls.yaml (100 tokens)
├── agentgateway-yaml-injection-out.yaml (1200 tokens)
├── agentgateway-yaml-injection.yaml (200 tokens)
├── agentgateway.yaml (100 tokens)
├── testutils.go (200 tokens)
├── e2e/
├── README-e2e-framework.md (2.2k tokens)
├── README.md (700 tokens)
├── common/
├── base.go (1600 tokens)
├── debugging.md (3k tokens)
├── defaults/
├── defaults.go (100 tokens)
├── testdata/
├── ai_guardrails_webhook.yaml (200 tokens)
├── features/
├── agentgateway/
├── README.md (500 tokens)
├── a2a/
├── example/
├── .gitignore (100 tokens)
├── README.md (500 tokens)
├── http_server_only.rs (500 tokens)
├── helpers.go (400 tokens)
├── suite.go (700 tokens)
├── testdata/
├── common.yaml
├── types.go (600 tokens)
├── aibackend/
├── suite.go (2.5k tokens)
├── testdata/
├── failover_eviction.yaml (500 tokens)
├── setup.yaml (600 tokens)
├── apikeyauth/
├── suite.go (700 tokens)
├── testdata/
├── insecure-route.yaml (100 tokens)
├── secured-gateway-policy.yaml (200 tokens)
├── secured-route.yaml (200 tokens)
├── backendtls/
├── suite.go (1000 tokens)
├── testdata/
├── base.yaml (300 tokens)
├── configmap.yaml (200 tokens)
├── basicauth/
├── suite.go (1000 tokens)
├── testdata/
├── insecure-route.yaml (100 tokens)
├── secured-gateway-policy.yaml (100 tokens)
├── secured-route.yaml (300 tokens)
├── csrf/
├── suite.go (500 tokens)
├── testdata/
├── csrf-gw.yaml (100 tokens)
├── routes.yaml (100 tokens)
├── types.go (100 tokens)
├── delegation/
├── suite.go (1400 tokens)
├── testdata/
├── basic-delegation.yaml (300 tokens)
├── cyclic-delegation.yaml (400 tokens)
├── delegation-headers-query.yaml (500 tokens)
├── multiple-parents.yaml (300 tokens)
├── recursive-delegation.yaml (400 tokens)
├── setup.yaml (600 tokens)
├── unresolved-child.yaml (100 tokens)
├── types.go (300 tokens)
├── discoverynsfilter/
├── suite.go (500 tokens)
├── testdata/
├── route-selected.yaml (100 tokens)
├── route-unselected.yaml (100 tokens)
├── setup.yaml (200 tokens)
├── types.go (200 tokens)
├── extauth/
├── suite.go (2000 tokens)
├── testdata/
├── backend-targeted-route.yaml (200 tokens)
├── conditional-route.yaml (200 tokens)
├── insecure-route.yaml (100 tokens)
├── secure-and-disable-all.yaml (200 tokens)
├── secured-gateway-policy.yaml (100 tokens)
├── secured-route-missing-ref.yaml (100 tokens)
├── secured-route.yaml (100 tokens)
├── service.yaml (100 tokens)
├── types.go (200 tokens)
├── extproc/
├── resources.go (100 tokens)
├── suite.go (1000 tokens)
├── testdata/
├── gateway-targetref.yaml (200 tokens)
├── httproute-targetref.yaml (200 tokens)
├── jwtauth/
├── suite.go (1700 tokens)
├── testdata/
├── insecure-route.yaml (100 tokens)
├── secured-gateway-policy-with-rbac.yaml (400 tokens)
├── secured-gateway-policy.yaml (1000 tokens)
├── secured-route-with-rbac.yaml (500 tokens)
├── secured-route.yaml (1000 tokens)
├── locality/
├── suite.go (1600 tokens)
├── testdata/
├── backends.yaml (400 tokens)
├── gateway.yaml (100 tokens)
├── service-route.yaml (100 tokens)
├── types.go (300 tokens)
├── mcp/
├── README.md (1800 tokens)
├── helpers.go (3k tokens)
├── suite.go (2.6k tokens)
├── testdata/
├── dynamic.yaml (200 tokens)
├── remote-authn-auth0.yaml (700 tokens)
├── remote-route-authn-auth0.yaml (700 tokens)
├── static.yaml (100 tokens)
├── types.go (600 tokens)
├── otel/
├── suite.go (1100 tokens)
├── testdata/
├── accesslog-otlp.yaml (200 tokens)
├── setup.yaml (400 tokens)
├── tracing.yaml (300 tokens)
├── policystatus/
├── suite.go (900 tokens)
├── testdata/
├── policy-with-gw.yaml (100 tokens)
├── policy-with-missing-gw.yaml (100 tokens)
├── types.go (100 tokens)
├── rate_limit/
├── global/
├── suite.go (1000 tokens)
├── testdata/
├── combined-rate-limit.yaml (100 tokens)
├── ip-rate-limit.yaml (100 tokens)
├── path-rate-limit.yaml (100 tokens)
├── rate-limit-server.yaml (600 tokens)
├── routes.yaml (100 tokens)
├── user-rate-limit.yaml (100 tokens)
├── types.go (100 tokens)
├── local/
├── suite.go (900 tokens)
├── testdata/
├── extensionref-rl.yaml (200 tokens)
├── gw-local-rate-limit.yaml (100 tokens)
├── httproutes.yaml (100 tokens)
├── route-local-rate-limit-disabled.yaml (100 tokens)
├── route-local-rate-limit.yaml (100 tokens)
├── types.go (300 tokens)
├── rbac/
├── suite.go (400 tokens)
├── testdata/
├── cel-rbac.yaml (200 tokens)
├── types.go (200 tokens)
├── remotejwtauth/
├── suite.go (1800 tokens)
├── testdata/
├── common.yaml (900 tokens)
├── insecure-route.yaml (100 tokens)
├── secured-gateway-policy-with-backend-and-ref.yaml (300 tokens)
├── secured-gateway-policy-with-backend.yaml (300 tokens)
├── secured-gateway-policy-with-rbac.yaml (300 tokens)
├── secured-gateway-policy-with-svc-ca-cert.yaml (200 tokens)
├── secured-gateway-policy-with-svc.yaml (200 tokens)
├── secured-route-with-backend-and-ref.yaml (300 tokens)
├── secured-route-with-backend.yaml (300 tokens)
├── secured-route-with-rbac.yaml (300 tokens)
├── secured-route-with-svc-ca-cert.yaml (200 tokens)
├── secured-route-with-svc.yaml (200 tokens)
├── suite.go (700 tokens)
├── testdata/
├── agw-http-route.yaml (100 tokens)
├── agw-tcp-route.yaml (100 tokens)
├── transformation/
├── suite.go (1700 tokens)
├── testdata/
├── gateway-attached-transform.yaml (200 tokens)
├── grpc-transformation.yaml (200 tokens)
├── transform-for-body.yaml (300 tokens)
├── transform-for-headers.yaml (200 tokens)
├── types.go (200 tokens)
├── types.go (200 tokens)
├── tls/
├── certgen.go (600 tokens)
├── suite.go (800 tokens)
├── testdata/
├── gw.yaml (100 tokens)
├── types.go (100 tokens)
├── tlsplaintext/
├── suite.go (400 tokens)
├── testdata/
├── gw.yaml (100 tokens)
├── zero_downtime_rollout/
├── suite.go (700 tokens)
├── testdata/
├── agentgateway.yaml (100 tokens)
├── file.go (200 tokens)
├── load_balancing_tests.md (500 tokens)
├── suite.go (500 tokens)
├── test.go (2.8k tokens)
├── tests/
├── agent_gateway_test.go (400 tokens)
├── agent_gateway_tests.go (700 tokens)
├── base/
├── base_suite.go (4.9k tokens)
├── discovery_ns_filter_test.go (600 tokens)
├── discovery_ns_filter_tests.go (100 tokens)
├── manifests/
├── agent-gateway-base.yaml (1500 tokens)
├── agent-gateway-integration.yaml
├── controlplane-plaintext-helm.yaml
├── controlplane-tls-helm.yaml
├── custom-gwp-2.yaml
├── custom-gwp.yaml
├── discovery-ns-filter-helm.yaml
├── empty-values.yaml
├── inference-extension-helm.yaml (100 tokens)
├── tls_plaintext_test.go (300 tokens)
├── tls_test.go (600 tokens)
├── tls_tests.go (100 tokens)
├── zero_downtime_test.go (300 tokens)
├── zero_downtime_tests.go (100 tokens)
├── testutils/
├── actions/
├── README.md (100 tokens)
├── provider.go (300 tokens)
├── assertions/
├── README.md (100 tokens)
├── curl.go (2.3k tokens)
├── deployments.go (500 tokens)
├── gateway_install_assertions.go (100 tokens)
├── objects.go (800 tokens)
├── pods.go (1200 tokens)
├── provider.go (400 tokens)
├── status.go (4k tokens)
├── cluster/
├── context.go (200 tokens)
├── kind.go (400 tokens)
├── install/
├── context.go (500 tokens)
├── runtime/
├── context.go (200 tokens)
├── env.go
├── output.go (100 tokens)
├── run_source.go (100 tokens)
├── gomega/
├── matchers/
├── contain_substrings.go (200 tokens)
├── contain_substrings_test.go (300 tokens)
├── have_condition.go (1500 tokens)
├── have_condition_test.go (900 tokens)
├── have_http_response.go (1300 tokens)
├── have_kubegateway_status.go (600 tokens)
├── pod.go (700 tokens)
├── transforms/
├── curl.go (500 tokens)
├── curl_test.go (400 tokens)
├── transforms.go (200 tokens)
├── helm/
├── helm_version_test.go (2.3k tokens)
├── testdata/
├── agentgateway/
├── additional-labels.golden (1500 tokens)
├── default.golden (1500 tokens)
├── extra-env.golden (1600 tokens)
├── extra-volumes.golden (1500 tokens)
├── hpa-and-vpa.golden (1700 tokens)
├── monitoring-custom-proxy-namespace-selector.golden (1700 tokens)
├── monitoring-enabled-no-dashboard.golden (1700 tokens)
├── monitoring-enabled-no-service-monitor.golden (1500 tokens)
├── monitoring-enabled.golden (1700 tokens)
├── pdb-max-unavailable.golden (1600 tokens)
├── pdb-min-available.golden (1600 tokens)
├── priority-class-name.golden (1500 tokens)
├── service-full-config.golden (1600 tokens)
├── xds-tls-enabled.golden (1500 tokens)
├── helm-version-output.golden (100 tokens)
├── helpers/
├── kube_dump.go (1300 tokens)
├── names.go
├── timeouts.go (500 tokens)
├── setup/
├── metallb.yaml (13.2k tokens)
├── setup-kind-ci.sh (2k tokens)
├── testutils/
├── crd.go (1200 tokens)
├── env.go (1300 tokens)
├── file_loader.go (900 tokens)
├── project.go (200 tokens)
├── testjwt/
├── remote.go (700 tokens)
├── crates/
├── agentgateway-app/
├── Cargo.toml (300 tokens)
├── src/
├── commands/
├── migrate.rs (100 tokens)
├── mod.rs
├── oneshot.rs (800 tokens)
├── run.rs (800 tokens)
├── lib.rs (1100 tokens)
├── main.rs
├── tests/
├── app.rs
├── agentgateway/
├── Cargo.toml (1300 tokens)
├── benches/
├── bench_tests.rs (200 tokens)
├── src/
├── a2a/
├── mod.rs (700 tokens)
├── tests.rs (1100 tokens)
├── agentcore.rs (600 tokens)
├── app.rs (1500 tokens)
├── assets/
├── dashboard.html (200 tokens)
├── aws.rs (300 tokens)
├── cel/
├── benches.rs (1700 tokens)
├── helpers.rs (100 tokens)
├── mod.rs (2.2k tokens)
├── properties.rs (400 tokens)
├── query.rs (1600 tokens)
├── tests.rs (2.6k tokens)
├── types.rs (10.7k tokens)
├── types_test.rs (1600 tokens)
├── client/
├── azure.rs (800 tokens)
├── connect_tunnel.rs (300 tokens)
├── dns.rs (1200 tokens)
├── dns_tests.rs (1000 tokens)
├── hbone_tunnel.rs (1600 tokens)
├── mod.rs (4k tokens)
├── tls.rs (300 tokens)
├── config.rs (7.5k tokens)
├── control/
├── caclient.rs (3.7k tokens)
├── mod.rs (2.3k tokens)
├── http/
├── apikey.rs (1000 tokens)
├── apikey_tests.rs (300 tokens)
├── auth/
├── aws.rs (900 tokens)
├── azure.rs (3.4k tokens)
├── copilot.rs (900 tokens)
├── gcp.rs (2.7k tokens)
├── mod.rs (1900 tokens)
├── tests.rs (2.2k tokens)
├── authorization.rs (1600 tokens)
├── authorization_tests.rs (2.6k tokens)
├── backendtls.rs (1400 tokens)
├── basicauth.rs (1100 tokens)
├── basicauth_tests.rs (600 tokens)
├── buflist.rs (500 tokens)
├── compression/
├── mod.rs (2.5k tokens)
├── cors.rs (3.1k tokens)
├── csrf.rs (900 tokens)
├── envoy_proto_common.rs (3.6k tokens)
├── ext_authz.rs (5.4k tokens)
├── ext_authz_tests.rs (4.7k tokens)
├── ext_proc.rs (6.4k tokens)
├── ext_proc_tests.rs (7k tokens)
├── filters.rs (2.4k tokens)
├── filters_test.rs (4.6k tokens)
├── health.rs (3.5k tokens)
├── jwt.rs (2.9k tokens)
├── jwt_tests.rs (5.9k tokens)
├── localratelimit.rs (4.5k tokens)
├── mod.rs (5.7k tokens)
├── oauth.rs (600 tokens)
├── oidc/
├── callback.rs (1200 tokens)
├── local.rs (2k tokens)
├── mod.rs (1900 tokens)
├── provider.rs (800 tokens)
├── redirect.rs (800 tokens)
├── session.rs (1700 tokens)
├── tests.rs (6k tokens)
├── outlierdetction_tests.rs (700 tokens)
├── outlierdetection.rs (600 tokens)
├── peekbody.rs (1300 tokens)
├── recordbody.rs (1400 tokens)
├── remoteratelimit.rs (3.4k tokens)
├── remoteratelimit_tests.rs (5.1k tokens)
├── retry/
├── body.rs (2.7k tokens)
├── body_tests.rs (1500 tokens)
├── mod.rs (200 tokens)
├── route.rs (1700 tokens)
├── route_test.rs (7.1k tokens)
├── sessionpersistence.rs (1200 tokens)
├── tests_common.rs (400 tokens)
├── timeout.rs (600 tokens)
├── transformation_cel.rs (2000 tokens)
├── transformation_cel_tests.rs (2.1k tokens)
├── json.rs (500 tokens)
├── lib.rs (4.2k tokens)
├── llm/
├── README.md (200 tokens)
├── anthropic.rs (200 tokens)
├── anthropic_tests.rs (1100 tokens)
├── azure.rs (600 tokens)
├── bedrock.rs (400 tokens)
├── conversion/
├── bedrock.rs (19.8k tokens)
├── bedrock_tests.rs (7.4k tokens)
├── completions.rs (6.1k tokens)
├── gemini.rs
├── messages.rs (5k tokens)
├── mod.rs
├── openai_compat.rs (5.5k tokens)
├── responses.rs (500 tokens)
├── vertex.rs (600 tokens)
├── vertex_tests.rs (700 tokens)
├── copilot.rs (100 tokens)
├── gemini.rs (200 tokens)
├── mod.rs (10.5k tokens)
├── openai.rs (200 tokens)
├── policy/
├── azure_content_safety.rs (2.1k tokens)
├── bedrock_guardrails.rs (1500 tokens)
├── google_model_armor.rs (2.1k tokens)
├── mod.rs (9.2k tokens)
├── moderation.rs (300 tokens)
├── pii/
├── ca_sin_recognizer.rs (200 tokens)
├── credit_card_recognizer.rs (300 tokens)
├── email_recognizer.rs (200 tokens)
├── mod.rs (300 tokens)
├── pattern_recognizer.rs (400 tokens)
├── phone_recognizer.rs (600 tokens)
├── recognizer.rs
├── recognizer_result.rs
├── tests.rs (1600 tokens)
├── url_recognizer.rs (1500 tokens)
├── us_ssn_recognizer.rs (200 tokens)
├── tests.rs (6.8k tokens)
├── webhook.rs (1300 tokens)
├── tests.rs (8.8k tokens)
├── tests/
├── requests/
├── completions/
├── basic.anthropic.snap
├── basic.bedrock.snap
├── basic.json
├── full.anthropic.snap
├── full.bedrock.snap
├── full.get-messages-completions.snap
├── full.get-messages-messages.snap
├── full.json (500 tokens)
├── parallel-tool-call.bedrock.snap
├── parallel-tool-call.json (200 tokens)
├── reasoning.anthropic.snap
├── reasoning.bedrock.snap
├── reasoning.json
├── reasoning_max.anthropic.snap
├── reasoning_max.json
├── tool-call.anthropic.snap
├── tool-call.bedrock.snap
├── tool-call.json (100 tokens)
├── count-tokens/
├── basic.anthropic.snap
├── basic.bedrock.snap
├── basic.json
├── basic.vertex.snap
├── with_system.anthropic.snap
├── with_system.bedrock.snap
├── with_system.json
├── with_system.vertex.snap
├── embeddings/
├── array.bedrock-cohere.snap
├── array.json
├── array.openai.snap
├── array.vertex.snap
├── basic.bedrock-cohere.snap
├── basic.bedrock-titan.snap
├── basic.json
├── basic.openai.snap
├── basic.vertex.snap
├── messages/
├── basic.anthropic.snap
├── basic.bedrock.snap
├── basic.completions.snap
├── basic.json
├── basic.vertex.snap
├── reasoning.anthropic.snap
├── reasoning.bedrock.snap
├── reasoning.completions.snap
├── reasoning.json (100 tokens)
├── reasoning.vertex.snap
├── tools.anthropic.snap
├── tools.bedrock.snap
├── tools.completions.snap
├── tools.json (100 tokens)
├── tools.vertex.snap
├── policies/
├── anthropic_with_system.anthropic.snap
├── anthropic_with_system.json
├── openai_with_inputs.json
├── openai_with_inputs.openai.snap
├── openai_with_messages.json
├── openai_with_messages.openai.snap
├── openai_with_text_input.json
├── openai_with_text_input.openai.snap
├── responses/
├── assistant-history.get-messages-responses.snap
├── assistant-history.json (100 tokens)
├── assistant-history.openai.snap
├── basic.bedrock.snap
├── basic.gemini.snap
├── basic.json
├── input-list.bedrock.snap
├── input-list.gemini.snap
├── input-list.json
├── instructions.bedrock.snap
├── instructions.gemini.snap
├── instructions.json
├── parallel-tool-call.bedrock.snap
├── parallel-tool-call.gemini.snap
├── parallel-tool-call.json (200 tokens)
├── response/
├── anthropic/
├── basic.json (100 tokens)
├── basic.messages-completions.snap
├── basic.messages-detect.snap
├── basic.messages-messages.snap
├── count_tokens.anthropic.snap
├── count_tokens.json
├── stream_basic.json (300 tokens)
├── stream_basic.messages-completions-streaming.snap
├── stream_basic.messages-detect-streaming.snap
├── stream_basic.messages-messages-streaming.snap
├── stream_thinking.json (600 tokens)
├── stream_thinking.messages-completions-streaming.snap
├── stream_thinking.messages-detect-streaming.snap
├── stream_thinking.messages-messages-streaming.snap
├── thinking.json (100 tokens)
├── thinking.messages-completions.snap
├── thinking.messages-detect.snap
├── thinking.messages-messages.snap
├── tool.json (100 tokens)
├── tool.messages-completions.snap
├── tool.messages-detect.snap
├── tool.messages-messages.snap
├── bedrock-cohere/
├── embeddings.bedrock-cohere.snap
├── embeddings.json
├── bedrock-titan/
├── embeddings.bedrock-titan.snap
├── embeddings.json
├── bedrock/
├── basic.bedrock-completions-streaming.snap
├── basic.bedrock-completions.snap
├── basic.bedrock-messages-streaming.snap
├── basic.bedrock-messages.snap
├── basic.bedrock-responses-streaming.snap
├── basic.bedrock-responses.snap
├── basic.bin
├── basic.json (100 tokens)
├── tool.bedrock-completions-streaming.snap
├── tool.bedrock-completions.snap
├── tool.bedrock-messages-streaming.snap
├── tool.bedrock-messages.snap
├── tool.bedrock-responses-streaming.snap
├── tool.bedrock-responses.snap
├── tool.bin
├── tool.json (100 tokens)
├── completions/
├── audio.completions-completions.snap
├── audio.completions-detect.snap
├── audio.completions-messages.snap
├── audio.json (200 tokens)
├── basic.completions-completions.snap
├── basic.completions-detect.snap
├── basic.completions-messages.snap
├── basic.json (200 tokens)
├── gemini_with_completion_tokens.completions-completions.snap
├── gemini_with_completion_tokens.completions-detect.snap
├── gemini_with_completion_tokens.completions-messages.snap
├── gemini_with_completion_tokens.json (100 tokens)
├── gemini_zero_completion_tokens.completions-completions.snap
├── gemini_zero_completion_tokens.completions-detect.snap
├── gemini_zero_completion_tokens.completions-messages.snap
├── gemini_zero_completion_tokens.json (100 tokens)
├── openrouter_reasoning.completions-completions.snap
├── openrouter_reasoning.completions-detect.snap
├── openrouter_reasoning.completions-messages.snap
├── openrouter_reasoning.json (200 tokens)
├── stream.completions-completions-streaming.snap
├── stream.completions-detect-streaming.snap
├── stream.completions-messages-streaming.snap
├── stream.json (5.3k tokens)
├── detect/
├── broken-sse
├── broken-sse.completions-detect-streaming.snap
├── broken-sse.completions-detect.snap
├── non-json
├── non-json.completions-detect-streaming.snap
├── non-json.completions-detect.snap
├── stream-image-generation (100 tokens)
├── stream-image-generation.completions-detect-streaming.snap
├── stream-image-generation.completions-detect.snap
├── openai/
├── embeddings.json (100 tokens)
├── embeddings.openai.snap
├── responses/
├── basic.json (300 tokens)
├── basic.responses-detect.snap
├── basic.responses-responses.snap
├── stream-image.json (1800 tokens)
├── stream-image.responses-detect-streaming.snap
├── stream-image.responses-responses-streaming.snap
├── stream.json (500 tokens)
├── stream.responses-detect-streaming.snap
├── stream.responses-responses-streaming.snap
├── vertex/
├── embeddings.json (100 tokens)
├── embeddings.vertex.snap
├── types/
├── bedrock.rs (4.1k tokens)
├── completions.rs (7.9k tokens)
├── count_tokens.rs (500 tokens)
├── detect.rs (2.5k tokens)
├── embeddings.rs (1200 tokens)
├── messages.rs (6.5k tokens)
├── mod.rs (600 tokens)
├── responses.rs (3.6k tokens)
├── vertex.rs (200 tokens)
├── vertex.rs (2.3k tokens)
├── management/
├── admin.rs (2.8k tokens)
├── hyper_helpers.rs (1100 tokens)
├── metrics_server.rs (800 tokens)
├── mod.rs
├── readiness_server.rs (500 tokens)
├── mcp/
├── auth.rs (2k tokens)
├── handler.rs (4.6k tokens)
├── mcp_tests.rs (14.4k tokens)
├── mergestream.rs (1200 tokens)
├── mod.rs (1700 tokens)
├── rbac.rs (900 tokens)
├── router.rs (1200 tokens)
├── session.rs (5.4k tokens)
├── sse.rs (900 tokens)
├── streamablehttp.rs (1300 tokens)
├── upstream/
├── client.rs (600 tokens)
├── mod.rs (2.2k tokens)
├── openapi/
├── mod.rs (6.1k tokens)
├── tests.rs (8.8k tokens)
├── sse.rs (1600 tokens)
├── stdio.rs (1800 tokens)
├── streamablehttp.rs (1400 tokens)
├── parse/
├── aws_sse.rs (1000 tokens)
├── mod.rs (100 tokens)
├── parse_tests.rs (1700 tokens)
├── passthrough.rs (1000 tokens)
├── sse.rs (700 tokens)
├── transform.rs (900 tokens)
├── websocket.rs (900 tokens)
├── proxy/
├── dtrace.rs (2.6k tokens)
├── gateway.rs (8.7k tokens)
├── gateway_test.rs (18.2k tokens)
├── httpproxy.rs (17.4k tokens)
├── locality_test.rs (4.8k tokens)
├── mod.rs (3.4k tokens)
├── proxy_protocol.rs (3.3k tokens)
├── request_builder.rs (2.3k tokens)
├── tcpproxy.rs (5.5k tokens)
├── serdes.rs (2.8k tokens)
├── state_manager.rs (2.9k tokens)
├── store/
├── binds.rs (15.2k tokens)
├── discovery.rs (4.6k tokens)
├── mod.rs (500 tokens)
├── policy.rs (2.3k tokens)
├── telemetry/
├── log.rs (9.1k tokens)
├── metrics.rs (2.6k tokens)
├── mod.rs
├── trc.rs (4.6k tokens)
├── test_helpers/
├── extauthmock.rs (500 tokens)
├── extprocmock.rs (1400 tokens)
├── hyper_tower.rs (400 tokens)
├── mod.rs (1000 tokens)
├── oteltracemock.rs (400 tokens)
├── policy.rs (300 tokens)
├── proxymock.rs (6.3k tokens)
├── ratelimitmock.rs (500 tokens)
├── transport/
├── hbone.rs (200 tokens)
├── mod.rs
├── rewind.rs (700 tokens)
├── rewind_tests.rs (400 tokens)
├── stream.rs (3.4k tokens)
├── tls.rs (6.7k tokens)
├── types/
├── agent.rs (18.3k tokens)
├── agent_xds.rs (22.8k tokens)
├── backend.rs (600 tokens)
├── discovery.rs (5.6k tokens)
├── frontend.rs (1400 tokens)
├── loadbalancer.rs (10.1k tokens)
├── local.rs (18.2k tokens)
├── local_tests.rs (4.6k tokens)
├── local_tests/
├── aws_config.yaml
├── aws_normalized.snap
├── basic_config.yaml (100 tokens)
├── basic_normalized.snap
├── health_config.yaml (100 tokens)
├── health_normalized.snap
├── llm_config.yaml (100 tokens)
├── llm_normalized.snap
├── llm_simple_config.yaml (300 tokens)
├── llm_simple_normalized.snap
├── mcp_config.yaml (200 tokens)
├── mcp_normalized.snap
├── mcp_simple_config.yaml
├── mcp_simple_normalized.snap
├── mcp_to_aws_backend_config.yaml (100 tokens)
├── mcp_to_aws_backend_normalized.snap
├── named_mcp_backend_config.yaml (100 tokens)
├── named_mcp_backend_normalized.snap
├── mod.rs
├── proto.rs (300 tokens)
├── ui.rs (1200 tokens)
├── util.rs
├── tests/
├── common/
├── compare.rs (1900 tokens)
├── gateway.rs (1100 tokens)
├── hbone_server.rs (1700 tokens)
├── mock_ca_server.rs (400 tokens)
├── mod.rs
├── shared_ca.rs (200 tokens)
├── testdata/
├── README.md (200 tokens)
├── ca-key.pem (300 tokens)
├── gen_certs.sh (400 tokens)
├── key.pem
├── root-cert.pem (200 tokens)
├── integration.rs
├── tests/
├── envoycompare.rs (200 tokens)
├── hbone.rs (3.8k tokens)
├── llm.rs (7.9k tokens)
├── mod.rs
├── smoke.rs (200 tokens)
├── validate_examples.rs (1100 tokens)
├── cel-fork/
├── cel-derive/
├── Cargo.toml (100 tokens)
├── README.md (1100 tokens)
├── src/
├── lib.rs (6k tokens)
├── tests/
├── expand.rs (100 tokens)
├── expand/
├── comprehensive.expanded.rs (5k tokens)
├── comprehensive.rs (600 tokens)
├── edge_cases.expanded.rs (400 tokens)
├── edge_cases.rs (100 tokens)
├── cel/
├── CHANGELOG.md (1800 tokens)
├── Cargo.toml (300 tokens)
├── README.md
├── benches/
├── runtime.rs (1100 tokens)
├── src/
├── common/
├── ast/
├── mod.rs (900 tokens)
├── operators.rs (300 tokens)
├── mod.rs
├── traits.rs (400 tokens)
├── types/
├── bool.rs (200 tokens)
├── bytes.rs (100 tokens)
├── double.rs (100 tokens)
├── duration.rs (100 tokens)
├── int.rs (100 tokens)
├── mod.rs (1100 tokens)
├── null.rs
├── optional.rs (100 tokens)
├── string.rs (100 tokens)
├── timestamp.rs (100 tokens)
├── uint.rs (100 tokens)
├── value.rs (400 tokens)
├── context.rs (1300 tokens)
├── duration.rs (1100 tokens)
├── functions.rs (6.7k tokens)
├── json.rs (700 tokens)
├── lib.rs (2.4k tokens)
├── macros.rs (700 tokens)
├── magic.rs (1000 tokens)
├── objects.rs (13.4k tokens)
├── optimize.rs (1700 tokens)
├── parser/
├── gen/
├── CEL.g4 (1000 tokens)
├── CEL.interp (1800 tokens)
├── CEL.tokens (100 tokens)
├── CELLexer.interp (3.2k tokens)
├── CELLexer.tokens (100 tokens)
├── cellexer.rs (4.6k tokens)
├── cellistener.rs (2.9k tokens)
├── celparser.rs (40.5k tokens)
├── celvisitor.rs (4.9k tokens)
├── mod.rs (100 tokens)
├── macros.rs (1800 tokens)
├── mod.rs (100 tokens)
├── parse.rs (2.9k tokens)
├── parser.rs (12.2k tokens)
├── references.rs (1000 tokens)
├── ser.rs (6.6k tokens)
├── test.rs (2.8k tokens)
├── types/
├── bytes.rs (100 tokens)
├── dynamic.rs (2.1k tokens)
├── list.rs (300 tokens)
├── map.rs (1600 tokens)
├── mod.rs
├── opaque.rs (900 tokens)
├── optional.rs (400 tokens)
├── string.rs (300 tokens)
├── time.rs (400 tokens)
├── celx/
├── Cargo.toml (200 tokens)
├── benches/
├── cel_bench.rs
├── src/
├── benches.rs (400 tokens)
├── cidr.rs (1000 tokens)
├── flatten.rs (600 tokens)
├── function_tests.rs (3.4k tokens)
├── general.rs (2.8k tokens)
├── lib.rs (700 tokens)
├── math.rs (1700 tokens)
├── optimize.rs (800 tokens)
├── strings.rs (2.6k tokens)
├── core/
├── Cargo.toml (200 tokens)
├── build.rs (300 tokens)
├── src/
├── arc.rs
├── bow.rs (100 tokens)
├── copy.rs (3k tokens)
├── drain.rs (2.8k tokens)
├── durfmt.rs (500 tokens)
├── env.rs (200 tokens)
├── lib.rs (100 tokens)
├── metrics.rs (1500 tokens)
├── prelude.rs (100 tokens)
├── readiness.rs (400 tokens)
├── responsechannel.rs (300 tokens)
├── signal.rs (500 tokens)
├── strng.rs (500 tokens)
├── telemetry.rs (4.2k tokens)
├── telemetry/
├── date.rs (500 tokens)
├── msg.rs
├── nonblocking.rs (2.6k tokens)
├── worker.rs (900 tokens)
├── test_helpers.rs (200 tokens)
├── timestamp.rs (200 tokens)
├── tokio_metrics.rs (300 tokens)
├── version.rs (200 tokens)
├── hbone/
├── Cargo.toml (100 tokens)
├── src/
├── client.rs (1100 tokens)
├── lib.rs (2k tokens)
├── pool.rs (4k tokens)
├── server.rs (1000 tokens)
├── htpasswd-verify-fork/
├── Cargo.toml (100 tokens)
├── README.md (100 tokens)
├── src/
├── lib.rs (1100 tokens)
├── md5.rs (800 tokens)
├── pool/
├── .gitignore (100 tokens)
├── CHANGELOG.md (800 tokens)
├── Cargo.toml (100 tokens)
├── LICENSE (200 tokens)
├── README.md (900 tokens)
├── src/
├── blackbox_tests.rs (2.3k tokens)
├── client.rs (8k tokens)
├── common/
├── exec.rs (200 tokens)
├── mod.rs
├── sync.rs (400 tokens)
├── timer.rs (200 tokens)
├── connect/
├── http.rs (400 tokens)
├── mod.rs (2k tokens)
├── lib.rs (100 tokens)
├── pool.rs (15.5k tokens)
├── rt/
├── mod.rs
├── tokio.rs (1900 tokens)
├── tokio/
├── with_hyper_io.rs (800 tokens)
├── with_tokio_io.rs (800 tokens)
├── service/
├── mod.rs (200 tokens)
├── oneshot.rs (300 tokens)
├── protos/
├── Cargo.toml (100 tokens)
├── build.rs (300 tokens)
├── proto/
├── citadel.proto (300 tokens)
├── ext_authz.proto (3.5k tokens)
├── ext_proc.proto (5.3k tokens)
├── google/
├── protobuf/
├── any.proto (1200 tokens)
├── duration.proto (1000 tokens)
├── empty.proto (500 tokens)
├── struct.proto (800 tokens)
├── timestamp.proto (1300 tokens)
├── wrappers.proto (1100 tokens)
├── resource.proto (7.9k tokens)
├── rls.proto (2.3k tokens)
├── shared_envoy.proto (1100 tokens)
├── workload.proto (3.2k tokens)
├── xds.proto (2.6k tokens)
├── src/
├── lib.rs (300 tokens)
├── xds/
├── Cargo.toml (100 tokens)
├── src/
├── client.rs (4.2k tokens)
├── lib.rs (300 tokens)
├── metrics.rs (500 tokens)
├── types.rs
├── xtask/
├── Cargo.toml (100 tokens)
├── src/
├── cel.rs (200 tokens)
├── main.rs (100 tokens)
├── schema.rs (500 tokens)
├── deny.toml (300 tokens)
├── examples/
├── README.md (400 tokens)
├── a2a/
├── README.md (400 tokens)
├── config.yaml (100 tokens)
├── strands-agents/
├── .gitignore
├── README.md (800 tokens)
├── __init__.py
├── __main__.py (200 tokens)
├── pyproject.toml (100 tokens)
├── uv.lock (omitted)
├── ai-prompt-guard/
├── README.md (800 tokens)
├── azure-content-safety-config.yaml (100 tokens)
├── bedrock-config.yaml (200 tokens)
├── config.yaml (300 tokens)
├── model-armor-config.yaml (100 tokens)
├── authorization/
├── README.md (600 tokens)
├── config.yaml (200 tokens)
├── img/
├── connect.png
├── key1.png
├── key2.png
├── aws-agentcore/
├── config.yaml (100 tokens)
├── basic/
├── README.md (400 tokens)
├── config.yaml (100 tokens)
├── img/
├── connect.png
├── echo.png
├── tools.png
├── delegation/
├── README.md (600 tokens)
├── config.yaml (300 tokens)
├── http/
├── README.md (400 tokens)
├── config.yaml (400 tokens)
├── mcp-authentication/
├── README.md (1600 tokens)
├── auth_server.py (4.3k tokens)
├── config.yaml (1300 tokens)
├── keycloak/
├── docker-compose.yml (100 tokens)
├── mcp-realm.json (1500 tokens)
├── multiplex/
├── README.md (200 tokens)
├── config.yaml (100 tokens)
├── img/
├── call_0.png
├── call_1.png
├── connect.png
├── list.png
├── oauth2-proxy/
├── README.md (600 tokens)
├── config.yaml (500 tokens)
├── docker-compose.yaml (100 tokens)
├── oidc/
├── README.md (300 tokens)
├── agentgateway-realm.json (300 tokens)
├── config.yaml (100 tokens)
├── docker-compose.yaml (200 tokens)
├── openapi/
├── README.md (300 tokens)
├── config.yaml (100 tokens)
├── docker-compose.yaml
├── img/
├── call.png
├── connect.png
├── tools.png
├── openapi.json (6.6k tokens)
├── prompt-enrichment/
├── README.md (200 tokens)
├── config.yaml (100 tokens)
├── ratelimiting/
├── global/
├── README.md (900 tokens)
├── config.yaml (300 tokens)
├── img/
├── global-route-limits-429.png
├── ratelimit-config.yaml (100 tokens)
├── local/
├── README.md (300 tokens)
├── config.yaml (300 tokens)
├── standalone-epp/
├── README.md (400 tokens)
├── config.yaml (100 tokens)
├── tailscale-auth/
├── README.md (200 tokens)
├── config.yaml (200 tokens)
├── telemetry/
├── README.md (400 tokens)
├── config.yaml (100 tokens)
├── docker-compose.yaml (100 tokens)
├── img/
├── gemini-tracing.png
├── jaeger.png
├── logging/
├── otel.yaml (100 tokens)
├── otel-collector-config.yaml (100 tokens)
├── tracing/
├── README.md (200 tokens)
├── langfuse.yaml (400 tokens)
├── openllmetry.yaml (400 tokens)
├── otel.yaml (100 tokens)
├── phoenix.yaml (200 tokens)
├── tls/
├── README.md (200 tokens)
├── certs/
├── ca-cert.pem (100 tokens)
├── ca-key.pem
├── cert.pem (100 tokens)
├── gen.sh (100 tokens)
├── key.pem
├── config.yaml (100 tokens)
├── go.mod (2.6k tokens)
├── go.sum (15.6k tokens)
├── img/
├── UI-homepage.png
├── architecture.svg (84.4k tokens)
├── banner-dark.svg (2.4k tokens)
├── banner-light.svg (2.4k tokens)
├── blacksmith-light.svg (2k tokens)
├── blacksmith.svg (2k tokens)
├── lf-stacked-color.png
├── manifests/
├── grafana.json (1500 tokens)
├── jwt/
├── README.md (100 tokens)
├── example1.key
├── example2.key
├── priv-key (100 tokens)
├── pub-key (100 tokens)
├── localhost-config.json (100 tokens)
├── rust-toolchain.toml
├── rustfmt.toml
├── schema/
├── README.md (100 tokens)
├── cel-functions.md (2.6k tokens)
├── cel.json (4.3k tokens)
├── cel.md (1800 tokens)
├── config.json (38.3k tokens)
├── config.md (510.1k tokens)
├── tools/
├── actionlint
├── applyconfiguration-gen
├── buf
├── check_clean_repo.sh (100 tokens)
├── client-gen
├── cmd/
├── oss_compliance/
├── main.go (100 tokens)
├── controller-gen
├── crane
├── exec-go-tool
├── get-agentgateway (1900 tokens)
├── ginkgo
├── go-compile-without-link (100 tokens)
├── go.mod (4.3k tokens)
├── go.sum (30.7k tokens)
├── golangci-lint
├── gotestsum
├── helm
├── kind
├── manage-validation-deps.sh (400 tokens)
├── mockgen
├── openapi-gen
├── oss_compliance
├── protoc-gen-go
├── protoc-gen-golang-jsonshim
├── proxy-dev-build (200 tokens)
├── register-gen
├── report_build_info.ps1 (300 tokens)
├── report_build_info.sh (200 tokens)
├── schema-to-md.sh
├── schema_paths.jq (1500 tokens)
├── tilt/
├── .gitignore
├── restart.sh (100 tokens)
├── start.sh (200 tokens)
├── validate-configs.sh (200 tokens)
├── ui/
├── .eslintrc.json (100 tokens)
├── .gitignore (100 tokens)
├── .prettierrc
├── README.md
├── components.json (100 tokens)
├── next.config.ts
├── package-lock.json (60.4k tokens)
├── package.json (400 tokens)
├── postcss.config.mjs
├── public/
├── favicon.svg (500 tokens)
├── src/
├── app/
├── backends/
├── page.tsx (1000 tokens)
├── cel/
├── page.tsx (2.1k tokens)
├── globals.css (1000 tokens)
├── layout.tsx (400 tokens)
├── listeners/
├── page.tsx (500 tokens)
├── page.tsx (4k tokens)
├── playground/
├── page.tsx (12.5k tokens)
├── policies/
├── page.tsx (1800 tokens)
├── routes/
├── page.tsx (1100 tokens)
├── components/
├── agentgateway-logo.tsx (600 tokens)
├── app-sidebar.tsx (1600 tokens)
├── backend-config.tsx (800 tokens)
├── backend/
├── backend-components.tsx (7.8k tokens)
├── config-error-wrapper.tsx (100 tokens)
├── config-error.tsx (700 tokens)
├── forms/
├── index.ts
├── jwt-config-form.tsx (1300 tokens)
├── rbac-config-form.tsx (2.4k tokens)
├── tls-config-form.tsx (2.8k tokens)
├── listener-config.tsx (6.8k tokens)
├── loading-state.tsx (100 tokens)
├── loading-wrapper.tsx (100 tokens)
├── playground/
├── ActionPanel.tsx (2.4k tokens)
├── CapabilitiesList.tsx (1600 tokens)
├── ResponseDisplay.tsx (200 tokens)
├── policy-config.tsx (4.8k tokens)
├── policy/
├── form-components.tsx (1400 tokens)
├── form-renderers.tsx (10.7k tokens)
├── route-config.tsx (1200 tokens)
├── route/
├── route-components.tsx (6.8k tokens)
├── setup-wizard/
├── BackendStep.tsx (2.9k tokens)
├── ListenerStep.tsx (1600 tokens)
├── PolicyStep.tsx (2.5k tokens)
├── ReviewStep.tsx (2k tokens)
├── RouteStep.tsx (2.2k tokens)
├── WelcomeStep.tsx (800 tokens)
├── index.tsx (800 tokens)
├── targets/
├── A2ATargetForm.tsx (1000 tokens)
├── MCPTargetForm.tsx (1100 tokens)
├── OpenAPITargetForm.tsx (1700 tokens)
├── SSETargetForm.tsx (1700 tokens)
├── StdioTargetForm.tsx (1300 tokens)
├── sidebar-wrapper.tsx (200 tokens)
├── target-item.tsx (800 tokens)
├── theme-provider.tsx (100 tokens)
├── theme-toggle.tsx (400 tokens)
├── ui/
├── accordion.tsx (400 tokens)
├── alert.tsx (300 tokens)
├── badge.tsx (300 tokens)
├── button.tsx (400 tokens)
├── card.tsx (400 tokens)
├── checkbox.tsx (200 tokens)
├── collapsible.tsx (200 tokens)
├── command.tsx (900 tokens)
├── dialog.tsx (800 tokens)
├── dropdown-menu.tsx (1500 tokens)
├── input.tsx (200 tokens)
├── label.tsx (100 tokens)
├── popover.tsx (300 tokens)
├── radio-group.tsx (300 tokens)
├── select.tsx (1200 tokens)
├── separator.tsx (100 tokens)
├── sheet.tsx (800 tokens)
├── sidebar.tsx (4.3k tokens)
├── skeleton.tsx (100 tokens)
├── sonner.tsx (100 tokens)
├── table.tsx (500 tokens)
├── tabs.tsx (400 tokens)
├── textarea.tsx (100 tokens)
├── toaster.tsx (100 tokens)
├── tooltip.tsx (400 tokens)
├── xds-mode-notification.tsx (100 tokens)
├── hooks/
├── use-mobile.ts (100 tokens)
├── use-xds-mode.ts (500 tokens)
├── lib/
├── api.ts (4.5k tokens)
├── backend-constants.ts (500 tokens)
├── backend-hooks.ts (2.2k tokens)
├── backend-utils.ts (4.9k tokens)
├── configMapper.ts (3.4k tokens)
├── loading-context.tsx (200 tokens)
├── policy-constants.ts (700 tokens)
├── policy-defaults.ts (400 tokens)
├── policy-utils.ts (200 tokens)
├── route-constants.ts (200 tokens)
├── route-hooks.ts (2.4k tokens)
├── route-utils.ts (1100 tokens)
├── server-context.tsx (1200 tokens)
├── tls.ts (200 tokens)
├── types.ts (2.1k tokens)
├── utils.ts
├── wizard-context.tsx (700 tokens)
├── tsconfig.json (100 tokens)
```
## /.cargo/config.toml
```toml path="/.cargo/config.toml"
[alias]
xtask = "run --package xtask --"
# Enable tokio_unstable for task dump
# Not supported for non-linux
[target.'cfg(target_os = "linux")']
rustflags = [
"--cfg", "tokio_unstable",
"-C", "force-frame-pointers",
]
[env]
CXXFLAGS = "-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"
CFLAGS = "-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"
```
## /.devcontainer.json
```json path="/.devcontainer.json"
{
"image": "mcr.microsoft.com/devcontainers/rust:latest"
}
```
## /.dockerignore
```dockerignore path="/.dockerignore"
target
.idea
.vscode
.DS_Store
manifests
examples
```
## /.githooks/prepare-commit-msg
```githooks/prepare-commit-msg path="/.githooks/prepare-commit-msg"
#!/bin/sh
# This script automatically adds a Signed-off-by trailer to each commit message, so that your commits
# will adhere to the DCO (Developer Certificate of Origin) requirements.
# To use, run `make init-git-hooks` or copy this file to .git/hooks/prepare-commit-msg in your copy of the repo.
NAME=$(git config user.name)
EMAIL=$(git config user.email)
if [ -z "$NAME" ]; then
echo "empty git config user.name"
exit 1
fi
if [ -z "$EMAIL" ]; then
echo "empty git config user.email"
exit 1
fi
git interpret-trailers --if-exists doNothing --trailer \
"Signed-off-by: $NAME <$EMAIL>" \
--in-place "$1"
```
## /.github/dependabot.yml
```yml path="/.github/dependabot.yml"
version: 2
updates:
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "05:00"
timezone: "America/Los_Angeles"
groups:
cargo-weekly:
patterns:
- "*"
ignore:
- dependency-name: "nom"
- dependency-name: "criterion"
open-pull-requests-limit: 1
cooldown:
default-days: 7
# Disable regular version updates while still allowing Dependabot security PRs.
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
- package-ecosystem: "gomod"
directory: "/api"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
- package-ecosystem: "gomod"
directory: "/tools"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
- package-ecosystem: "npm"
directory: "/ui"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
- package-ecosystem: "docker"
directory: "/controller/hack/testbox"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
- package-ecosystem: "uv"
directory: "/examples/a2a/strands-agents"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
time: "09:00"
timezone: "America/Los_Angeles"
open-pull-requests-limit: 0
cooldown:
default-days: 7
```
## /.github/vex/openvex.json
```json path="/.github/vex/openvex.json"
{
"@context": "https://openvex.dev/ns/v0.2.0",
"@id": "https://github.com/agentgateway/agentgateway/.github/vex/openvex.json",
"author": "agentgateway",
"timestamp": "2026-05-14T00:00:00Z",
"version": 1,
"statements": [
{
"vulnerability": {
"name": "CVE-2019-14993"
},
"products": [
{
"@id": "pkg:golang/istio.io/istio"
}
],
"status": "fixed",
"impact_statement": "Scanner version matching is incorrect for this pseudo-version; the vendored dependency code is already patched."
},
{
"vulnerability": {
"name": "CVE-2021-39155"
},
"products": [
{
"@id": "pkg:golang/istio.io/istio"
}
],
"status": "fixed",
"impact_statement": "Scanner version matching is incorrect for this pseudo-version; the vendored dependency code is already patched."
},
{
"vulnerability": {
"name": "CVE-2021-39156"
},
"products": [
{
"@id": "pkg:golang/istio.io/istio"
}
],
"status": "fixed",
"impact_statement": "Scanner version matching is incorrect for this pseudo-version; the vendored dependency code is already patched."
},
{
"vulnerability": {
"name": "CVE-2022-23635"
},
"products": [
{
"@id": "pkg:golang/istio.io/istio"
}
],
"status": "fixed",
"impact_statement": "Scanner version matching is incorrect for this pseudo-version; the vendored dependency code is already patched."
},
{
"vulnerability": {
"name": "CVE-2022-31045"
},
"products": [
{
"@id": "pkg:golang/istio.io/istio"
}
],
"status": "fixed",
"impact_statement": "Scanner version matching is incorrect for this pseudo-version; the vendored dependency code is already patched."
}
]
}
```
## /.github/workflows/cache-e2e
```github/workflows/cache-e2e path="/.github/workflows/cache-e2e"
Workaround https://github.com/actions/setup-go/issues/358 for e2e
```
## /.github/workflows/cache-lint
```github/workflows/cache-lint path="/.github/workflows/cache-lint"
Workaround https://github.com/actions/setup-go/issues/358 for lint
```
## /.github/workflows/cache-test
```github/workflows/cache-test path="/.github/workflows/cache-test"
Workaround https://github.com/actions/setup-go/issues/358 for test
```
## /.github/workflows/debug_cache.yml
```yml path="/.github/workflows/debug_cache.yml"
name: Download cache and Upload
# Debug the cache. Example to run:
# KEY=setup-go-Linux-x64-ubuntu24-go-1.25.7-db3f66b86a16be31d89e16ce08f217df90c50b79a7cf6877f62fc3d1fc880727; VERSION="$(gh cache list --json id,key,version -q ".[] | select(.key == \"$KEY\").version")"; gh workflow run debug_cache.yml -f cache_key=$KEY -f version=$VERSION
on:
workflow_dispatch:
inputs:
cache_key:
description: 'Cache key'
required: true
type: string
version:
description: 'Cache hash version'
required: true
type: string
jobs:
cache-upload:
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Restore cache
uses: Andrej730/cache/restore@e294f7d180f76c94062d0251c60fe7362ce6667d
with:
path: .
version: ${{ github.event.inputs.version }}
key: ${{ github.event.inputs.cache_key }}
- name: Upload cached folder as artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: cache-artifact
path: |
/home/runner/work/**/*.tzst
```
## /.github/workflows/nightly.yml
```yml path="/.github/workflows/nightly.yml"
name: Nightly Release
on:
schedule:
- cron: '0 2 * * *'
workflow_dispatch: {}
permissions:
actions: read
contents: write
packages: write
id-token: write
jobs:
prepare:
if: github.repository == 'agentgateway/agentgateway'
runs-on: ubuntu-24.04
outputs:
has_commits: ${{ steps.check.outputs.has_commits }}
previous_sha: ${{ steps.previous.outputs.previous_sha }}
previous_run_id: ${{ steps.previous.outputs.previous_run_id }}
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Find previous successful nightly run
id: previous
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PREVIOUS_RUN_ID=$(gh api "repos/${{ github.repository }}/actions/workflows/nightly.yml/runs?status=completed&conclusion=success&per_page=1" --jq '.workflow_runs[0].id // empty')
PREVIOUS_SHA=$(gh api "repos/${{ github.repository }}/actions/workflows/nightly.yml/runs?status=completed&conclusion=success&per_page=1" --jq '.workflow_runs[0].head_sha // empty')
echo "previous_run_id=${PREVIOUS_RUN_ID}" >> "$GITHUB_OUTPUT"
echo "previous_sha=${PREVIOUS_SHA}" >> "$GITHUB_OUTPUT"
if [ -n "$PREVIOUS_SHA" ]; then
echo "Previous nightly run: ${PREVIOUS_RUN_ID} (${PREVIOUS_SHA})"
else
echo "No previous successful nightly run found"
fi
- name: Check for commits since the last nightly build
id: check
run: |
CURRENT_SHA=$(git rev-parse HEAD)
PREVIOUS_SHA="${{ steps.previous.outputs.previous_sha }}"
if [ -n "$PREVIOUS_SHA" ]; then
if [ "$CURRENT_SHA" != "$PREVIOUS_SHA" ]; then
echo "has_commits=true" >> "$GITHUB_OUTPUT"
echo "New commits found since previous nightly (${PREVIOUS_SHA}..${CURRENT_SHA})"
else
echo "has_commits=false" >> "$GITHUB_OUTPUT"
echo "HEAD matches the previous nightly build (${CURRENT_SHA}), skipping nightly release"
fi
else
LAST_COMMIT=$(git log -1 --format="%ct")
NOW=$(date +%s)
DIFF=$((NOW - LAST_COMMIT))
# 86400 = seconds in one day
if [ "$DIFF" -lt 86400 ]; then
echo "has_commits=true" >> "$GITHUB_OUTPUT"
echo "No prior nightly found; recent commit detected (${DIFF}s ago)"
else
echo "has_commits=false" >> "$GITHUB_OUTPUT"
echo "No prior nightly found and no recent commits (last commit was ${DIFF}s ago), skipping nightly release"
fi
fi
- name: Compute nightly version
id: version
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
echo "version=0.0.0-alpha.${SHORT_SHA}" >> $GITHUB_OUTPUT
echo "Nightly version: 0.0.0-alpha.${SHORT_SHA}"
changelog:
needs: prepare
if: ${{ needs.prepare.outputs.has_commits == 'true' || github.event_name == 'workflow_dispatch' }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
persist-credentials: false
- name: Generate nightly changelog
env:
PREVIOUS_SHA: ${{ needs.prepare.outputs.previous_sha }}
PREVIOUS_RUN_ID: ${{ needs.prepare.outputs.previous_run_id }}
VERSION: ${{ needs.prepare.outputs.version }}
run: |
if [ -n "$PREVIOUS_SHA" ]; then
COMPARE_URL="https://github.com/${{ github.repository }}/compare/${PREVIOUS_SHA}...${{ github.sha }}"
RANGE="${PREVIOUS_SHA}..HEAD"
INTRO="Changes since the previous successful nightly run ([#${PREVIOUS_RUN_ID}](https://github.com/${{ github.repository }}/actions/runs/${PREVIOUS_RUN_ID}))."
else
COMPARE_URL=""
RANGE=""
INTRO="No previous successful nightly run was found. Showing the most recent commits included in this build."
fi
{
echo "# Nightly changelog"
echo
echo "Version: \`${VERSION}\`"
echo
echo "${INTRO}"
echo
if [ -n "$COMPARE_URL" ]; then
echo "Compare: ${COMPARE_URL}"
echo
fi
if [ -n "$RANGE" ]; then
if git rev-list --count "$RANGE" | grep -q '^[1-9][0-9]*{{contextString}}#39;; then
git log --format='- `%h` %s (%an)' "$RANGE"
else
echo "- No commits since the previous nightly; this run rebuilt the same HEAD."
fi
else
git log -20 --format='- `%h` %s (%an)'
fi
} > nightly-changelog.md
cat nightly-changelog.md >> "$GITHUB_STEP_SUMMARY"
- name: Upload nightly changelog
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: nightly-changelog
path: nightly-changelog.md
if-no-files-found: error
release:
needs:
- prepare
- changelog
if: ${{ needs.prepare.outputs.has_commits == 'true' || github.event_name == 'workflow_dispatch' }}
uses: ./.github/workflows/release.yml
with:
version: ${{ needs.prepare.outputs.version }}
extra_tag: latest-dev
# Helm is special and requires a semver.
extra_helm_tag: 0.0.0-latest-dev
secrets: inherit
```
## /.github/workflows/pull_request.yml
```yml path="/.github/workflows/pull_request.yml"
name: Branch
on:
push:
branches:
- "main"
pull_request:
branches:
- "main"
concurrency:
# GitHub concurrency keeps at most one running and one pending run per group.
# Use ref_name for PRs so new commits cancel older PR runs on the same PR,
# but key pushes by SHA so postsubmit runs do not cancel each other.
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && format('pr-{0}', github.ref_name) || format('push-{0}', github.sha) }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CARGO_TERM_COLOR: always
CI: true
RUST_VERSION: "1.95.0"
GO_VERSION: "1.26.3"
jobs:
#### Proxy jobs ####
proxy-test:
strategy:
matrix:
include:
- os: blacksmith-4vcpu-ubuntu-2404
name: "Proxy Test"
- os: windows-2025
name: "Proxy Test (Windows)"
- os: macos-15
name: "Proxy Test (Mac)"
runs-on: ${{ matrix.os }}
name: ${{ matrix.name }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master
with:
toolchain: "${{ env.RUST_VERSION }}"
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
# GHA 10gb cache cannot handle all 3 builds. However, because we put all the heavy linux caches on Blacksmith,
# we have space for windows and mac.
# If we change up the runners, consider if we have space for all three (note: Blacksmith has 25gb though)
with:
# Github cache will restore from 'main' OR the current branch.
# If we cache PR branches, we may evict the 'main' cache and end up with no cache hits at all.
# Ideally, we would have main be 'high priority' and not be evicted but I don't think thats possible.
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Start validation dependencies
if: ${{ startsWith(matrix.os, 'blacksmith-') }}
run: tools/manage-validation-deps.sh start
- name: Test
run: make test
env:
KEYCLOAK_AVAILABLE: ${{ startsWith(matrix.os, 'blacksmith-') && '1' || '' }}
- name: Stop validation dependencies
if: ${{ always() && startsWith(matrix.os, 'blacksmith-') }}
run: tools/manage-validation-deps.sh stop
proxy-lint:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master
with:
toolchain: "${{ env.RUST_VERSION }}"
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
# Github cache will restore from 'main' OR the current branch.
# If we cache PR branches, we may evict the 'main' cache and end up with no cache hits at all.
# Ideally, we would have main be 'high priority' and not be evicted but I don't think thats possible.
save-if: ${{ github.ref == 'refs/heads/main' }}
- name: Generation
run: make generate-schema check-clean-repo
- name: Lint
run: make lint
#### UI jobs ####
ui-lint:
runs-on: ubuntu-24.04
defaults:
run:
working-directory: ui
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
- name: Lint
run: |
npm ci
npm run lint
#### Controller jobs ####
controller-test:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "${{ env.GO_VERSION }}"
cache-dependency-path: |
**/*.sum
.github/workflows/cache-lint
- name: Test
run: go test -race ./...
controller-lint:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "${{ env.GO_VERSION }}"
cache-dependency-path: |
**/*.sum
.github/workflows/cache-test
- name: Lint
run: make -C controller analyze
- name: go mod tidy
run: |
go mod tidy
git diff --exit-code go.mod go.sum
- name: Gen
# TODO: the rest of codegen
run: make generate-apis check-clean-repo
controller-e2e:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Check Runner Info
run: |
cat /sys/fs/cgroup/cpu.stat || true
cat /proc/pressure/cpu || true
lscpu || true
openssl speed -seconds 1 -bytes 256 sha256 || rtue
- name: Install Rust
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master
with:
toolchain: "${{ env.RUST_VERSION }}"
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
# Github cache will restore from 'main' OR the current branch.
# If we cache PR branches, we may evict the 'main' cache and end up with no cache hits at all.
# Ideally, we would have main be 'high priority' and not be evicted but I don't think thats possible.
save-if: ${{ github.ref == 'refs/heads/main' }}
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "${{ env.GO_VERSION }}"
cache-dependency-path: |
**/*.sum
.github/workflows/cache-e2e
- name: Set Path
run: |
echo "./tools" >> $GITHUB_PATH
- name: Setup
run: TEST_MODE=e2e ./controller/test/setup/setup-kind-ci.sh
- name: E2E
run: |
CGO_ENABLED=0 PERSIST_INSTALL=true go test -tags=e2e -v ./controller/test/e2e/tests -run '^TestAgentgatewayIntegration'
- name: Archive bug report directory on failure
if: ${{ failure() }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: bug-report
path: ./controller/_test/bug_report/kind
retention-days: 2
- name: Upload cargo timings
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: cargo-timings-e2e
path: target/cargo-timings/cargo-timing*.html
retention-days: 2
- name: Summary
run: |
echo '# E2E Timings\n'
cat controller/_test/ci-step-timings.log >> $GITHUB_STEP_SUMMARY
controller-conformance:
runs-on: blacksmith-4vcpu-ubuntu-2404
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Install Rust
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master
with:
toolchain: "${{ env.RUST_VERSION }}"
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
# We only read the cache from 'E2E' job, since they should have identical cache.
save-if: "false"
shared-key: "controller-e2e" # Pull E2E job's cache
- uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "${{ env.GO_VERSION }}"
cache-dependency-path: |
**/*.sum
.github/workflows/cache-e2e
- name: Set Path
run: |
echo "./tools" >> $GITHUB_PATH
- name: Setup
run: TEST_MODE=conformance ./controller/test/setup/setup-kind-ci.sh
- name: Conformance
run: |
make -C controller all-conformance
- name: Debug Info
if: ${{ failure() }}
run: |
kubectl describe deployment -A
kubectl get pods -A
kubectl logs -n agentgateway-system -l app.kubernetes.io/name=agentgateway
- name: Upload cargo timings
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: cargo-timings-conformance
path: target/cargo-timings/cargo-timing*.html
retention-days: 2
- name: Summary
run: |
cat-yamls () {
local files=("$@")
local count=$#
for ((i=0; i<count-1; i++)); do
cat "${files[i]}"
echo -e "\n---"
done
if [ $count -gt 0 ]; then
cat "${files[count-1]}"
fi
}
echo -e '\n# Conformance Reports\n\n\`\`\`yaml' >> $GITHUB_STEP_SUMMARY
cat-yamls ./controller/_test/conformance/*.yaml >> $GITHUB_STEP_SUMMARY
echo -e '\`\`\`\n' >> $GITHUB_STEP_SUMMARY
echo -e '# Conformance Timings\n' >> $GITHUB_STEP_SUMMARY
cat controller/_test/ci-step-timings.log >> $GITHUB_STEP_SUMMARY
```
## /.github/workflows/release.yml
```yml path="/.github/workflows/release.yml"
name: Release
on:
push:
tags:
- "v*.*.*"
workflow_dispatch:
inputs:
version:
description: 'Version number'
skip_gh_release:
description: 'Skip creating a GitHub release'
required: false
default: false
type: boolean
extra_helm_tag:
description: 'Additional Helm chart version to push (e.g. 0.0.0-latest-dev)'
required: false
default: ''
type: string
workflow_call:
inputs:
version:
description: 'Version number (without v prefix)'
required: true
type: string
extra_tag:
description: 'Additional Docker image tag to push (e.g. latest-dev)'
required: false
default: ''
type: string
extra_helm_tag:
description: 'Additional Helm chart version to push (e.g. 0.0.0-latest-dev)'
required: false
default: ''
type: string
env:
CARGO_TERM_COLOR: always
CI: true
RUST_VERSION: "1.95.0"
GO_VERSION: "1.26.3"
REGISTRY_IMAGE: ghcr.io/${{ github.repository_owner }}/agentgateway
CONTROLLER_REGISTRY_IMAGE: ghcr.io/${{ github.repository_owner }}/controller
VEX_FILE: .github/vex/openvex.json
# Note: /charts is added to this
CHART_REGISTRY_IMAGE_BASE: ghcr.io/${{ github.repository_owner }}
jobs:
setup:
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.version.outputs.version }}
steps:
# Help debug what exact was input for this since Github doesn't expose it.
- name: Output Inputs
run: echo "${{ toJSON(github.event.inputs) }}"
- name: Set canonical VERSION
id: version
run: |
# Determine version source
if [ -n "${{ inputs.version }}" ]; then
VERSION="${{ inputs.version }}"
else
VERSION="${{ github.ref_name }}"
fi
# Always strip 'v' prefix if present
VERSION="${VERSION#v}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Canonical VERSION: ${VERSION}"
build-image:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
needs:
- setup
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
os: blacksmith-4vcpu-ubuntu-2404
- platform: linux/arm64
os: blacksmith-4vcpu-ubuntu-2404-arm
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.REGISTRY_IMAGE }}
- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Build and push by digest
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
build-args: |
VERSION=${{ env.VERSION }}
GIT_REVISION=${{ github.sha }}
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ env.REGISTRY_IMAGE }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ env.REGISTRY_IMAGE }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY_IMAGE }}:buildcache,mode=max
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
push-image:
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
id-token: write
needs:
- setup
- build-image
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Install cosign
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1
- name: Download digests
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: ${{ runner.temp }}/digests
pattern: digests-linux-*
merge-multiple: true
- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=raw,value=v${{ env.VERSION }}
type=raw,value=${{ inputs.extra_tag }},enable=${{ inputs.extra_tag != '' }}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Sign the container image
run: cosign sign --yes ${{ env.REGISTRY_IMAGE }}:v${{ env.VERSION }}
- name: Sign the extra tag
if: ${{ inputs.extra_tag != '' }}
run: cosign sign --yes ${{ env.REGISTRY_IMAGE }}:${{ inputs.extra_tag }}
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:v${{ env.VERSION }}
musl-build-image:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
needs:
- setup
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
os: blacksmith-4vcpu-ubuntu-2404
- platform: linux/arm64
os: blacksmith-4vcpu-ubuntu-2404-arm
cargo_features: agentgateway/ui,agentgateway-app/mimalloc
cargo_no_default_features: true
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.REGISTRY_IMAGE }}-musl
- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Build and push by digest
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ env.REGISTRY_IMAGE }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
cache-from: type=registry,ref=${{ env.REGISTRY_IMAGE }}:buildcache-musl
cache-to: type=registry,ref=${{ env.REGISTRY_IMAGE }}:buildcache-musl,mode=max
build-args: |
VERSION=${{ env.VERSION }}
GIT_REVISION=${{ github.sha }}
BUILDER=musl
CARGO_FEATURES=${{ matrix.cargo_features || 'agentgateway/ui' }}
CARGO_NO_DEFAULT_FEATURES=${{ matrix.cargo_no_default_features || 'false' }}
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests-musl
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests-musl/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: digests-musl-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/digests-musl/*
if-no-files-found: error
retention-days: 1
musl-push-image:
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
id-token: write
needs:
- setup
- musl-build-image
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Install cosign
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1
- name: Download digests
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: ${{ runner.temp }}/digests-musl
pattern: digests-musl*
merge-multiple: true
- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.REGISTRY_IMAGE }}
tags: |
type=raw,value=v${{ env.VERSION }}
type=raw,value=${{ inputs.extra_tag }},enable=${{ inputs.extra_tag != '' }}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests-musl
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + . + "-musl") | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *)
- name: Sign the container image
run: cosign sign --yes ${{ env.REGISTRY_IMAGE }}:v${{ env.VERSION }}-musl
- name: Sign the extra tag
if: ${{ inputs.extra_tag != '' }}
run: cosign sign --yes ${{ env.REGISTRY_IMAGE }}:${{ inputs.extra_tag }}-musl
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:v${{ env.VERSION }}-musl
build-controller-image:
runs-on: ${{ matrix.os }}
permissions:
contents: read
packages: write
needs:
- setup
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
os: ubuntu-24.04
goarch: amd64
- platform: linux/arm64
os: blacksmith-4vcpu-ubuntu-2404-arm
goarch: arm64
defaults:
run:
working-directory: controller
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
working-directory: .
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Go
uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
with:
go-version: "${{ env.GO_VERSION }}"
cache: false
- name: Build controller binary
run: |
CGO_ENABLED=0 GOARCH=${{ matrix.goarch }} GOOS=linux go build \
-ldflags="-X github.com/agentgateway/agentgateway/controller/pkg/version.Version=${{ env.VERSION }} -s -w" \
-o _output/pkg/agentgateway/agentgateway-linux-${{ matrix.goarch }} \
./cmd/agentgateway
- name: Copy Dockerfile
run: cp cmd/agentgateway/Dockerfile.agentgateway _output/pkg/agentgateway/
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.CONTROLLER_REGISTRY_IMAGE }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Build and push by digest
id: build
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
with:
context: controller/_output/pkg/agentgateway
file: controller/_output/pkg/agentgateway/Dockerfile.agentgateway
build-args: |
GOARCH=${{ matrix.goarch }}
platforms: ${{ matrix.platform }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ env.CONTROLLER_REGISTRY_IMAGE }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/controller-digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/controller-digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: controller-digests-${{ env.PLATFORM_PAIR }}
path: ${{ runner.temp }}/controller-digests/*
if-no-files-found: error
retention-days: 1
push-controller-image:
runs-on: ubuntu-24.04
permissions:
contents: read
packages: write
id-token: write
needs:
- setup
- build-controller-image
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Install cosign
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3.9.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Download digests
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
path: ${{ runner.temp }}/controller-digests
pattern: controller-digests-*
merge-multiple: true
- name: Display structure of downloaded digests
working-directory: ${{ runner.temp }}/controller-digests
run: |
ls -R
echo "Found digest files:"
find . -type f
- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Docker meta
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
with:
images: ${{ env.CONTROLLER_REGISTRY_IMAGE }}
tags: |
type=raw,value=v${{ env.VERSION }}
type=raw,value=${{ inputs.extra_tag }},enable=${{ inputs.extra_tag != '' }}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/controller-digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(find . -type f -exec sh -c 'printf "${{ env.CONTROLLER_REGISTRY_IMAGE }}@sha256:%s " "$(basename "$1")"' _ {} \;)
- name: Sign the container image
run: cosign sign --yes ${{ env.CONTROLLER_REGISTRY_IMAGE }}:v${{ env.VERSION }}
- name: Sign the extra tag
if: ${{ inputs.extra_tag != '' }}
run: cosign sign --yes ${{ env.CONTROLLER_REGISTRY_IMAGE }}:${{ inputs.extra_tag }}
- name: Attach VEX attestation
run: |
cosign attest \
--predicate "${{ env.VEX_FILE }}" \
--type openvex \
--yes \
${{ env.CONTROLLER_REGISTRY_IMAGE }}:v${{ env.VERSION }}
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.CONTROLLER_REGISTRY_IMAGE }}:v${{ env.VERSION }}
push-helm-charts:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
needs:
- setup
- push-controller-image
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
with:
persist-credentials: false
- name: Helm login to ${{ env.CHART_REGISTRY_IMAGE_BASE }}
run: echo "${{ secrets.GITHUB_TOKEN }}" | ./tools/helm registry login ghcr.io -u ${{ github.repository_owner }} --password-stdin
- name: Push helm charts
run: make -C controller release-charts
env:
IMAGE_REGISTRY: ${{ env.CHART_REGISTRY_IMAGE_BASE }}
EXTRA_HELM_TAG: ${{ inputs.extra_helm_tag }}
build:
if: ${{ github.event_name != 'workflow_call' && (github.event_name == 'push' || ! github.event.inputs.skip_gh_release) }}
needs:
- setup
runs-on: ${{ matrix.os }}
permissions:
contents: read
env:
VERSION: ${{ needs.setup.outputs.version }}
strategy:
matrix:
include:
- os: blacksmith-4vcpu-ubuntu-2404
target: x86_64-unknown-linux-musl
# Performance is horrendous on musl without jemalloc
features: jemalloc
name: linux
- os: blacksmith-4vcpu-ubuntu-2404-arm
target: aarch64-unknown-linux-musl
# arm64 musl fails with jemalloc: https://github.com/tikv/jemallocator/issues/146
features: agentgateway-app/mimalloc
extra_cargo_args: --no-default-features
name: linux-arm
- os: macos-26
target: aarch64-apple-darwin
features: default
name: mac
- os: windows-2025
target: x86_64-pc-windows-msvc
features: default
name: windows
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
- name: Install Rust
uses: dtolnay/rust-toolchain@efa25f7f19611383d5b0ccf2d1c8914531636bf9 # master
with:
toolchain: "${{ env.RUST_VERSION }}"
targets: ${{ matrix.target }}
# TODO: build this in a separate job and just copy it over
- name: Build UI
run: |
cd ui
npm install
npm run build
- name: Prepare Linux target
if: ${{ matrix.target == 'x86_64-unknown-linux-musl' || matrix.target == 'aarch64-unknown-linux-musl' }}
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
rustup target add ${{ matrix.target }}
- name: Build
run: make build
env:
CARGO_BUILD_ARGS: "--target ${{ matrix.target }} ${{ matrix.extra_cargo_args || '' }} -F ${{ matrix.features }}"
- name: Debug dirty build
run: |
git status
- name: Upload Artifact
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: release-binary-${{ matrix.name }}
path: |
target/${{ matrix.target }}/release/agentgateway
target/${{ matrix.target }}/release/agentgateway.exe
release:
if: ${{ github.event_name != 'workflow_call' && (github.event_name == 'push' || ! github.event.inputs.skip_gh_release) }}
needs:
- setup
- push-image
- musl-push-image
- push-controller-image
- push-helm-charts
- build
runs-on: blacksmith-4vcpu-ubuntu-2404
permissions:
contents: write
env:
VERSION: ${{ needs.setup.outputs.version }}
steps:
- name: Download Artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
pattern: release-binary-*
- name: Display structure of downloaded files
run: |
ls -R
mkdir outputs
mv release-binary-mac/agentgateway outputs/agentgateway-darwin-arm64
sha256sum outputs/agentgateway-darwin-arm64 > outputs/agentgateway-darwin-arm64.sha256
mv release-binary-linux/agentgateway outputs/agentgateway-linux-amd64
sha256sum outputs/agentgateway-linux-amd64 > outputs/agentgateway-linux-amd64.sha256
mv release-binary-linux-arm/agentgateway outputs/agentgateway-linux-arm64
sha256sum outputs/agentgateway-linux-arm64 > outputs/agentgateway-linux-arm64.sha256
mv release-binary-windows/agentgateway.exe outputs/agentgateway-windows-amd64.exe
sha256sum outputs/agentgateway-windows-amd64.exe > outputs/agentgateway-windows-amd64.exe.sha256
- name: Create GitHub Release
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1
with:
files: outputs/agentgateway-*
tag_name: ${{ github.ref_name }}
generate_release_notes: true
body: |
🎉 Welcome to the ${{ env.VERSION }} release of the agentgateway project!
## Artifacts
**Docker images** are available:
* `cr.agentgateway.dev/agentgateway:v${{ env.VERSION }}`
* `cr.agentgateway.dev/controller:v${{ env.VERSION }}`
**Helm charts** are available:
* `cr.agentgateway.dev/charts/agentgateway:v${{ env.VERSION }}`
* `cr.agentgateway.dev/charts/agentgateway-crds:v${{ env.VERSION }}`
**Binaries** are available below.
## Quick Start
Follow the [Kubernetes](https://agentgateway.dev/docs/kubernetes/latest/quickstart/) or [Standalone](https://agentgateway.dev/docs/standalone/latest/quickstart/) quick start guide to get started!
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: startsWith(github.ref, 'refs/tags/')
```
## /.gitignore
```gitignore path="/.gitignore"
.cursor
.claude
.codex
/target
.vscode
.idea
.run
.DS_Store
.venv
.env
.env.*
*.local
var/
controller/_output
controller/_test
```
## /CHARTER.md
## Technical Charter (the “Charter”) for agentgateway a Series of LF Projects, LLC
This Charter sets forth the responsibilities and procedures for technical contribution to, and
oversight of, the agentgateway open source project, which has been established as agentgateway
a Series of LF Projects, LLC (the “Project”). LF Projects, LLC (“LF Projects”) is a Delaware
series limited liability company. All contributors (including committers, maintainers, and other
technical positions) and other participants in the Project (collectively, “Collaborators”) must
comply with the terms of this Charter.
### 1. Mission and Scope of the Project
a. The mission of the Project is to create a secure, scalable, and standardized
foundation for AI agents to discover, communicate with, and leverage external
tools and services—enabling seamless cooperation between agents, models, and
APIs across organizations and ecosystems.
b. The scope of the Project includes collaborative development under the Project
License (as defined herein) supporting the mission, including documentation,
testing, integration and the creation of other artifacts that aid the development,
deployment, operation or adoption of the open source project.
### 2. Technical Steering Committee
a. The Technical Steering Committee (the “TSC”) will be responsible for all
technical oversight of the open source Project.
b. The TSC voting members are initially the Project’s Maintainers. At the inception
of the project, the Maintainers of the Project will be as set forth within the
“CONTRIBUTING” file within the Project’s code repository. The TSC may
choose an alternative approach for determining the voting members of the TSC,
and any such alternative approach will be documented in the CONTRIBUTING
file. Any meetings of the Technical Steering Committee are intended to be open
to the public, and can be conducted electronically, via teleconference, or in
person.
c. TSC projects generally will involve Contributors and Maintainers. The TSC may
adopt or modify roles so long as the roles are documented in the
CONTRIBUTING file. Unless otherwise documented:
- Contributors include anyone in the technical community that contributes
code, documentation, or other technical artifacts to the Project;
- Maintainers are Contributors who have earned the ability to modify
(“commit”) source code, documentation or other technical artifacts in a
project’s repository; and
- A Contributor may become a Maintainer by a majority approval of the
TSC. A Maintainer may be removed by a majority approval of the TSCs.
d. Participation in the Project through becoming a Contributor and Maintainer is
open to anyone so long as they abide by the terms of this Charter.
e. The TSC may (1) establish work flow procedures for the submission, approval,
and closure/archiving of projects, (2) set requirements for the promotion of
Contributors to Maintainer status, as applicable, and (3) amend, adjust, refine
and/or eliminate the roles of Contributors, and Maintainer, and create new roles,
and publicly document any TSC roles, as it sees fit.
f. The TSC may elect a TSC Chair, who will preside over meetings of the TSC and
will serve until their resignation or replacement by the TSC.
g. Responsibilities: The TSC will be responsible for all aspects of oversight relating
to the Project, which may include:
- coordinating the technical direction of the Project;
- approving project or system proposals (including, but not limited to,
incubation, deprecation, and changes to a sub-project’s scope);
- organizing sub-projects and removing sub-projects;
- creating sub-committees or working groups to focus on cross-project
technical issues and requirements;
- appointing representatives to work with other open source or open
standards communities;
- establishing community norms, workflows, issuing releases, and security
issue reporting policies;
- approving and implementing policies and processes for contributing (to be
published in the CONTRIBUTING file) and coordinating with the series
viii. manager of the Project (as provided for in the Series Agreement, the
“Series Manager”) to resolve matters or concerns that may arise as set
forth in Section 7 of this Charter;
- discussions, seeking consensus, and where necessary, voting on technical
matters relating to the code base that affect multiple projects; and
- coordinating any marketing, events, or communications regarding the
Project.
### 3. TSC Voting
a. While the Project aims to operate as a consensus-based community, if any TSC
decision requires a vote to move the Project forward, the voting members of the
TSC will vote on a one vote per voting member basis.
b. Quorum for TSC meetings requires at least fifty percent of all voting members of
the TSC to be present. The TSC may continue to meet if quorum is not met but
will be prevented from making any decisions at the meeting.
c. Except as provided in Section 7.c. and 8.a, decisions by vote at a meeting require
a majority vote of those in attendance, provided quorum is met. Decisions made
by electronic vote without a meeting require a majority vote of all voting
members of the TSC.
d. In the event a vote cannot be resolved by the TSC, any voting member of the TSC
may refer the matter to the Series Manager for assistance in reaching a resolution.
### 4. Compliance with Policies
a. This Charter is subject to the Series Agreement for the Project and the Operating
Agreement of LF Projects. Contributors will comply with the policies of LF
Projects as may be adopted and amended by LF Projects, including, without
limitation the policies listed at https://lfprojects.org/policies/.
b. The TSC may adopt a code of conduct (“CoC”) for the Project, which is subject to
approval by the Series Manager. In the event that a Project-specific CoC has not
been approved, the LF Projects Code of Conduct listed at
https://lfprojects.org/policies will apply for all Collaborators in the Project.
c. When amending or adopting any policy applicable to the Project, LF Projects will
publish such policy, as to be amended or adopted, on its web site at least 30 days
prior to such policy taking effect; provided, however, that in the case of any
amendment of the Trademark Policy or Terms of Use of LF Projects, any such
amendment is effective upon publication on LF Project’s web site.
d. All Collaborators must allow open participation from any individual or
organization meeting the requirements for contributing under this Charter and any
policies adopted for all Collaborators by the TSC, regardless of competitive
interests. Put another way, the Project community must not seek to exclude any
participant based on any criteria, requirement, or reason other than those that are
reasonable and applied on a non-discriminatory basis to all Collaborators in the
Project community.
e. The Project will operate in a transparent, open, collaborative, and ethical manner
at all times. The output of all Project discussions, proposals, timelines, decisions,
and status should be made open and easily visible to all. Any potential violations
of this requirement should be reported immediately to the Series Manager.
### 5. Community Assets
a. LF Projects (or an associated hosting entity) will hold title to all trade or service
marks used by the Project (“Project Trademarks”), whether based on common law
or registered rights. Project Trademarks will be transferred and assigned to LF
Projects (or, where applicable, the associated hosting entity) to hold on behalf of
the Project. Any use of any Project Trademarks by Collaborators in the Project
will (a) either be (i) in a way that constitutes fair use or (ii) in accordance with the
license from LF Projects to the Project and the applicable trademark usage
guidelines and (b) inure to the benefit of LF Projects (or the associated hosting
entity).
b. The Project will, as permitted and in accordance with such license from LF
Projects, develop and own all Project GitHub and social media accounts, and
domain name registrations created by the Project community.
c. Under no circumstances will LF Projects be expected or required to undertake any
action on behalf of the Project that is inconsistent with the tax-exempt status or
purpose, as applicable, of the Joint Development Foundation or LF Projects, LLC.
### 6. General Rules and Operations.
a. The Project will:
- engage in the work of the Project in a professional manner consistent with
maintaining a cohesive community, while also maintaining the goodwill
and esteem of LF Projects, Joint Development Foundation and other
partner organizations in the open source community; and
- respect the rights of all trademark owners, including any branding and
trademark usage guidelines.
### 7. Intellectual Property Policy
a. Collaborators acknowledge that the copyright in all new contributions will be
retained by the copyright holder as independent works of authorship and that no
contributor or copyright holder will be required to assign copyrights to the
Project.
b. Except as described in Section 7.c., all contributions to the Project are subject to
the following:
- All new inbound code contributions to the Project must be made using
Apache License, Version 2.0 available at
http://www.apache.org/licenses/LICENSE-2.0 (the “Project License”).
- All new inbound code contributions must also be accompanied by a
Developer Certificate of Origin (http://developercertificate.org) sign-off in
the source code system that is submitted through a TSC-approved
contribution process which will bind the authorized contributor and, if not
self-employed, their employer to the applicable license.
- All outbound code will be made available under the Project License.
- Documentation will be received and made available by the Project under
the Project License.
- The Project may seek to integrate and contribute back to other open source
projects (“Upstream Projects”). In such cases, the Project will conform to
all license requirements of the Upstream Projects, including dependencies,
leveraged by the Project. Upstream Project code contributions not stored
within the Project’s main code repository will comply with the
contribution process and license terms for the applicable Upstream
Project.
c. The TSC may approve the use of an alternative license or licenses for inbound or
outbound contributions on an exception basis. To request an exception, please
describe the contribution, the alternative open source license(s), and the
justification for using an alternative open source license for the Project. License
exceptions must be approved by a two-thirds vote of the entire TSC.
d. Contributed files should contain license information, such as SPDX short form
identifiers, indicating the open source license or licenses pertaining to the file.
### 8. Amendments
a. This charter may be amended by a two-thirds vote of the entire TSC and is subject
to approval by LF Projects.
## /CODEOWNERS
``` path="/CODEOWNERS"
* @agentgateway/maintainers
```
## /CODE_OF_CONDUCT.md
# Agentgateway Community Code of Conduct
All members of the agentgateway community must abide by the [Linux Foundation projects Code of Conduct](https://lfprojects.org/policies/code-of-conduct/).
Only by respecting one another can we build a strong and collaborative community.
## Generative AI Policy
While agentgateway is a project designed to enable AI use cases, first and foremost it is a project by humans, for humans.
Usage of AI during contributions must abide by the [Linux Foundation Generative AI policy](https://www.linuxfoundation.org/legal/generative-ai).
In addition, please:
* Refrain from generating issues, comments, or PR descriptions with AI.
* Refrain from "vibe coding". AI should be used to assist and accelerate code that you (the human!) would write on your own. You should only submit code that you fully understand and take ownership of, and that you would be able to explain and justify to a reviewer.
* Make sure that you have tested the changes and verify the code works as expected! If you have used AI to help write tests, make sure the tests are useful and are testing the feature correctly.
* When using (non-trivial) AI assistance, please indicate this.
These policies help ensure that the code base is kept at a high level of quality.
Additionally, it ensures maintainers do not waste time reviewing low-quality AI-generated code.
Issues or PRs that appear to violate these guidelines may be closed without review.
## /CONTRIBUTION.md
# Contribution Guidelines
## Development
### Code of Conduct
We are committed to providing a friendly, safe, and welcoming environment for all contributors. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).
### Getting Started
1. **Fork the repository** on GitHub.
2. **Clone your fork** locally:
```bash
git clone https://github.com/YOUR-USERNAME/agentgateway.git
cd agentgateway
```
3. **Add the upstream repository** as a remote:
```bash
git remote add upstream https://github.com/agentgateway/agentgateway.git
```
4. **Create a new branch** for your changes:
```bash
git checkout -b feature/your-feature-name
```
### Development Environment Setup
See the [DEVELOPMENT.md](DEVELOPMENT.md) file for more information.
### Making Changes
#### Coding Standards
- **Rust Code**:
- Run `make lint` before submitting your changes
- Ensure all tests pass with `make test`
- Add tests for new functionality
- **UI Code**:
- Follow the project's ESLint configuration
- Run `npm run lint` before submitting changes
- Ensure all tests pass with `npm test`
- Add tests for new functionality
#### Commit Guidelines
We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
- **feat**: A new feature
- **fix**: A bug fix
- **docs**: Documentation only changes
- **style**: Changes that do not affect the meaning of the code
- **refactor**: A code change that neither fixes a bug nor adds a feature
- **perf**: A code change that improves performance
- **test**: Adding missing tests or correcting existing tests
- **chore**: Changes to the build process or auxiliary tools
### Pull Request Process
1. **Update your fork** with the latest changes from upstream:
```bash
git fetch upstream
git rebase upstream/main
```
2. **Push your changes** to your fork:
```bash
git push origin feature/your-feature-name
```
3. **Create a Pull Request** from your fork to the main repository.
4. **Fill out the PR template** with all required information.
5. **Address review comments** if requested by maintainers.
6. **Update your PR** if needed:
```bash
git add .
git commit -m "address review comments"
git push origin feature/your-feature-name
```
7. Once approved, a maintainer will merge your PR.
### Documentation
- Update documentation for any changes to APIs, CLIs, or user-facing features
- Add examples for new features
- Update the README if necessary
- Add comments to your code explaining complex logic
### Releasing
Only project maintainers can create releases. The process is:
1. Update version numbers in relevant files
2. Create a release branch
3. Create a tag for the release
4. Build and publish artifacts
5. Create a GitHub release with release notes
### Community
- Join our [Discord server](https://discord.gg/y9efgEmppm) for discussions
- Participate in our [agentgateway community calls](https://calendar.google.com/calendar/u/0?cid=Y18zZTAzNGE0OTFiMGUyYzU2OWI1Y2ZlOWNmOWM4NjYyZTljNTNjYzVlOTdmMjdkY2I5ZTZmNmM5ZDZhYzRkM2ZmQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20)
- Help answer questions in GitHub issues
- Review pull requests from other contributors
## License
By contributing to this project, you agree that your contributions will be licensed under the project's license.
## Questions?
If you have any questions about contributing, please open an issue or reach out to the maintainers.
## /Cargo.toml
```toml path="/Cargo.toml"
[patch.crates-io]
schemars = { git = "https://github.com/howardjohn/schemars", rev = "4364354fa41897a0c2001d891c0a9a38eafedb82" }
http-serde = { git = "https://gitlab.com/howardjohn/http-serde", rev = "c2e482be0ddf029895ba72ef8749b9f94b388fc7" }
wiremock = { git = "https://github.com/howardjohn/wiremock-rs", rev = "e55f5b96083125fdabc3e62f92790ee15ae3a10d" }
[workspace]
resolver = "2"
members = [
"crates/agentgateway",
"crates/agentgateway-app",
"crates/cel-fork/cel",
"crates/cel-fork/cel-derive",
"crates/celx",
"crates/pool",
"crates/core",
"crates/hbone",
"crates/protos",
"crates/xds",
"crates/xtask",
]
default-members = [
"crates/agentgateway",
"crates/agentgateway-app",
"crates/cel-fork/cel",
"crates/cel-fork/cel-derive",
"crates/celx",
"crates/pool",
"crates/core",
"crates/hbone",
"crates/protos",
"crates/xds",
]
[workspace.package]
version = "0.0.0" # We do not use this version
edition = "2024"
rust-version = "1.90"
license = "Apache-2.0"
publish = false
[workspace.dependencies]
agent-core = { path = "crates/core" }
agent-celx = { path = "crates/celx" }
agent-hbone = { path = "crates/hbone" }
agent-pool = { path = "crates/pool" }
agent-xds = { path = "crates/xds" }
agentgateway = { path = "crates/agentgateway" }
cel = { path = "crates/cel-fork/cel" }
cel-derive = { path = "crates/cel-fork/cel-derive" }
protos = { path = "crates/protos" }
atomic_float = { version = "1.1.0", features = ["serde"] }
anyhow = "1.0"
arc-swap = "1.9"
arcstr = { version = "1.2", features = ["serde"] }
assert_matches = "1.5.0"
async-openai = { version = "0.36", default-features = false, features = ["chat-completion-types", "moderation-types", "response-types", "realtime-types"] }
async-stream = "0.3"
async-trait = "0.1"
aws-config = { version = "1.8", default-features = false, features = ["default-https-client", "rt-tokio", "sso"] }
aws-credential-types = "1.2"
aws-sigv4 = "1.4"
aws-smithy-eventstream = "0.60"
aws-smithy-types = "1.3"
aws-lc-rs = "1.16"
axum = { version = "0.8", features = ["macros"] }
axum-core = "0.5"
axum-extra = { version = "0.12", features = ["json-lines", "typed-header"] }
# Disable default features to avoid pulling in native-tls and requiring openssl
# TODO: allow default features if we ever add an openssl feature
azure_identity = { version = "0.35", default-features = false }
azure_core = { version = "0.35", default-features = false }
typespec_client_core = { default-features = false, version = "0.14" }
base64 = "0.22"
cookie = { version = "0.18", default-features = false }
bcrypt = "0.19"
bytes = { version = "1.11", features = ["serde"] }
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.6", features = ["derive"] }
clocksource = "1.0"
crossbeam = "0.8"
divan = "0.1"
durationfmt = "0.1"
go-parse-duration = "0.1"
flurry = "0.5.2"
fs-err = { version = "3.3", features = ["tokio"] }
futures = "0.3"
futures-channel = "0.3"
futures-core = "0.3"
futures-util = "0.3"
google-cloud-auth = { git = "https://github.com/googleapis/google-cloud-rust/", rev = "58058110bf9a01074bf8e1fecf0f1d2b7ca831f4", default-features = false, features = [
"idtoken",
# Support the full ADC set; this one is opt in
"gdch",
# They use AWS-LC which is what we want so its fine. If they changed we would need to switch
# To installing a global default which is annoying so prefer to do it this way.
"default-rustls-provider",
] }
hashbrown = "0.17"
h2 = "0.4"
headers = "0.4"
hex = "0.4"
hickory-resolver = { version = "0.26", features = ["serde"] }
htpasswd-verify-fork = { path = "crates/htpasswd-verify-fork" }
httpdate = "1.0"
http = "1.4"
http-body = "1"
http-body-util = "0.1.3"
hyper = { version = "1.9", features = ["full"] }
hyper-rustls = "0.27"
hyper-util = { version = "0.1", features = ["full"] }
include_dir = "0.7"
indexmap = { version = "2.13", features = ["serde"] }
insta = { version = "1.47", features = ["json", "redactions", "filters", "yaml"] }
ipnet = { version = "2.12", features = ["serde"] }
itertools = "0.14"
jsonwebtoken = { version = "10.3", features = ["aws_lc_rs"] }
lazy_static = "1.5"
libc = "0.2"
notify = "8.2"
notify-debouncer-full = "0.7"
md-5 = "0.11"
num_cpus = "1.17"
once_cell = "1.21"
openapiv3 = "2.2"
opentelemetry = "0.31"
opentelemetry-http = "0.31"
opentelemetry-otlp = { version = "0.31", default-features = false, features = ["http-proto", "internal-logs", "trace", "grpc-tonic", "logs"] }
opentelemetry-proto = { version = "0.31", features = ["gen-tonic", "logs"] }
opentelemetry_sdk = { version = "0.31", features = ["rt-tokio", "logs"] }
parking_lot = "0.12"
percent-encoding = "2.3"
phonenumber = "0.3"
pin-project-lite = "0.2"
pingora-pool = "0.8"
ppp = "2.3"
pprof-alloc = "0.2"
pprof = { version = "0.15", features = [
"protobuf",
"protobuf-codec",
"criterion",
] }
pretty_env_logger = "0.5"
prometheus-client = "0.24"
prost = "0.14"
prost-build = "0.14"
prost-types = "0.14"
prost-wkt-types = { version = "0.7", features = ["vendored-protox"] }
prost-wkt-build = "0.7"
pwhash = "1"
rand = "0.10"
rcgen = { version = "0.14", default-features = false, features = ["pem", "x509-parser", "aws_lc_rs"] }
regex = "1.12"
reqwest = { version = "0.13", default-features = false, features = [
"http2",
"charset",
"rustls",
] }
rstest = "0.26"
mimalloc = { version = "0.1", features = ["v3", "no_thp"] }
rustc_version = "0.4"
rustls = { version = "0.23", default-features = false, features = ["tls12", "aws_lc_rs"] }
rustls-native-certs = "0.8"
rustls-pki-types = "1.14"
schemars = { version = "=1.0.4", git = "https://github.com/howardjohn/schemars", rev = "4364354fa41897a0c2001d891c0a9a38eafedb82", features = [
#schemars = { version = "1.0", features = [
"bytes1",
"arcstr1",
"raw_value",
"preserve_order",
] }
secrecy = { version = "0.10", features = ["serde"] }
serde = { version = "1.0", features = ["derive", "rc"] }
serde-transcode = "1.1"
serde_json = { version = "1.0", features = ["preserve_order"] }
serde-untagged = "0.1"
serde_json_path_to_error = "0.1"
serde_regex = "1.1"
serde_yaml = "0.9"
sha1 = "0.11"
sha2 = "0.11"
shellexpand = "3.1"
socket2 = "0.6"
split-iter = "0.1"
sse-stream = "0.2"
stacker = "0.1"
tempfile = "3.27"
thiserror = "2.0"
tiktoken-rs = "0.11"
tokio = { version = "1.50", features = ["full", "macros", "sync"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs"] }
tokio-stream = { version = "0.1", features = ["net", "sync"] }
tokio-test = "0.4"
tokio-util = { version = "0.7", features = ["codec", "io"] }
tokio_sse_codec = "0.0.2"
tonic = { version = "0.14", features = ["codegen", "transport"] }
tonic-prost = { version = "0.14" }
tonic-prost-build = { version = "0.14", features = ["transport"] }
tonic-build = { version = "0.14", features = ["transport"] }
tower = { version = "0.5" }
tower-http = { version = "0.6", features = ["cors"] }
tower-serve-static = "0.1"
tower-service = "0.3"
tracing = "0.1"
tracing-appender = "0.2"
tracing-core = "0.1"
tracing-log = "0.2"
tracing-subscriber = { version = "0.3", features = [
"env-filter",
"registry",
"json",
] }
url = "2.5"
uuid = { version = "1.23", features = ["v4"] }
wiremock = { version = "0.6", features = ["tls"] }
x509-parser = { version = "0.18", default-features = false, features = ["verify-aws"] }
which = "8.0"
websocket-sans-io = '0.1'
vector-map = "1.0.2"
flagset = "0.4.7"
crossbeam-channel = "0.5"
http-serde = "2.1"
itoa = "1.0"
serde_urlencoded = "0.7"
serde_with = { version = "3.17", features = [
"schemars_1",
"macros",
"alloc",
], default-features = false }
value-bag = { version = "1.12", features = ["serde", "value-bag-serde1"] }
time = "0.3"
tikv-jemallocator = { version = "0.6", features = [
"profiling",
"unprefixed_malloc_on_supported_platforms",
] }
jemalloc_pprof = { version = "0.8", features = ["symbolize"] }
protox = "0.9"
async-compression = { version = "0.4", features = [
"brotli",
"zlib",
"gzip",
"zstd",
"tokio",
] }
core_affinity = "0.8"
frozen-collections = "0.9"
heck = "0.5"
macro_rules_attribute = "0.2"
# Release optimized but without as many dependencies, suitable for incremental development
[profile.quick-release-debug]
inherits = "quick-release"
debug = true
[profile.quick-release]
inherits = "release"
codegen-units = 16
lto = false
incremental = true
# For CI, optimize all dependencies since they are cached. Leave workspace packages, which are uncached,
[profile.ci]
inherits = "quick-release"
opt-level = 1
[profile.ci.package."*"]
opt-level = 3
[profile.release]
codegen-units = 1
lto = true
[profile.bench]
inherits = "quick-release"
debug = true
```
## /DEVELOPMENT.md
# Quickstart (GitHub, no local install)
1. Click **Code → Create codespace on main**.
2. In the terminal:
cargo fmt --all
cargo clippy --all -- -D warnings
cargo test --all
3. If you touched the UI:
cd ui
npm ci
npm test
# Local Development
This page contains instructions on how to run everything locally.
## Build from Source
Requirements:
- Rust 1.86+
- npm 10+
Build the agentgateway UI:
```bash
cd ui
npm install
npm run build
```
Build the agentgateway binary:
```bash
cd ..
export CARGO_NET_GIT_FETCH_WITH_CLI=true
make build
```
Run the agentgateway binary:
```bash
./target/release/agentgateway
```
Open your browser and navigate to `http://localhost:15000/ui` to see the agentgateway UI.
## /Dockerfile
``` path="/Dockerfile"
# syntax=docker/dockerfile:1.11
ARG BUILDER=base
FROM docker.io/library/node:23.11.0-bookworm AS node
WORKDIR /app
COPY ui .
RUN --mount=type=cache,target=/app/npm/cache npm install
RUN --mount=type=cache,target=/app/npm/cache npm run build
FROM docker.io/library/rust:1.95.0-trixie AS musl-builder
ARG TARGETARCH
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
rm -f /etc/apt/apt.conf.d/docker-clean && \
echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache && \
apt-get update && apt-get install -y --no-install-recommends \
make musl-tools
RUN <<EOF
mkdir /build
if [ "$TARGETARCH" = "arm64" ]; then
rustup target add aarch64-unknown-linux-musl;
echo aarch64-unknown-linux-musl > /build/target
else
rustup target add x86_64-unknown-linux-musl;
echo x86_64-unknown-linux-musl > /build/target
fi
EOF
FROM docker.io/library/rust:1.95.0-trixie AS base-builder
ARG TARGETARCH
RUN <<EOF
mkdir /build
if [ "$TARGETARCH" = "arm64" ]; then
echo aarch64-unknown-linux-gnu > /build/target
else
echo x86_64-unknown-linux-gnu > /build/target
fi
echo "Building $(cat /build/target)"
EOF
FROM ${BUILDER}-builder AS builder
ARG TARGETARCH
ARG PROFILE=release
ARG VERSION
ARG GIT_REVISION
ARG CARGO_FEATURES=agentgateway/ui
ARG CARGO_NO_DEFAULT_FEATURES=false
WORKDIR /app
COPY Makefile Cargo.toml Cargo.lock ./
COPY .cargo ./.cargo
COPY crates ./crates
COPY tools ./tools
COPY --from=node /app/out ./ui/out
RUN \
--mount=type=cache,id=cargo,target=/usr/local/cargo/registry \
--mount=type=cache,id=cargo-git,target=/usr/local/cargo/git \
cargo fetch --locked
RUN --mount=type=cache,target=/app/target \
--mount=type=cache,id=cargo,target=/usr/local/cargo/registry \
--mount=type=cache,id=cargo-git,target=/usr/local/cargo/git \
<<EOF
export VERSION="${VERSION}"
export GIT_REVISION="${GIT_REVISION}"
if [ "${CARGO_NO_DEFAULT_FEATURES}" = "true" ]; then
cargo build --no-default-features --features "${CARGO_FEATURES}" --target "$(cat /build/target)" --profile ${PROFILE} || exit 1
else
cargo build --features "${CARGO_FEATURES}" --target "$(cat /build/target)" --profile ${PROFILE} || exit 1
fi
mkdir /out
mv /app/target/$(cat /build/target)/${PROFILE}/agentgateway /out
/out/agentgateway --version
# Fail if version is not set
if /out/agentgateway --version | grep -q '"unknown"'; then
exit 1
fi
EOF
FROM cgr.dev/chainguard/glibc-dynamic AS runner
ARG TARGETARCH
WORKDIR /
COPY --from=builder /out/agentgateway /app/agentgateway
LABEL org.opencontainers.image.source=https://github.com/agentgateway/agentgateway
LABEL org.opencontainers.image.description="Agentgateway is an open source project that is built on AI-native protocols to connect, secure, and observe agent-to-agent and agent-to-tool communication across any agent framework and environment."
ENTRYPOINT ["/app/agentgateway"]
```
## /Dockerfile.windows
```windows path="/Dockerfile.windows"
# Windows-native Dockerfile for agentgateway
# Use Windows Server Core as the base for building
FROM mcr.microsoft.com/windows/servercore:ltsc2022 AS builder
ARG PROFILE=release
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]
WORKDIR C:/app
# Install Chocolatey and dependencies
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; \
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; \
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')); \
choco install -y rust-ms protoc make nodejs cmake nasm
# Install build tools
RUN choco install visualstudio2022buildtools -y --package-parameters '--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.22621'
# Build UI
WORKDIR C:/app/ui
COPY ui .
RUN npm install
RUN npm run build
# Prepare Rust build context
WORKDIR C:/app
COPY Makefile Cargo.toml Cargo.lock ./
COPY crates ./crates
COPY common ./common
# Build the Rust project for Windows
RUN $env:TARGET=\"x86_64-pc-windows-msvc\"; \
cargo fetch --locked; \
make build-target; \
mkdir C:/out; \
Move-Item -Path C:/app/target/x86_64-pc-windows-msvc/release/agentgateway.exe -Destination C:/out/agentgateway.exe
# Final runtime image
FROM mcr.microsoft.com/windows/nanoserver:ltsc2022 AS runner
WORKDIR C:/app
COPY --from=builder C:/out/agentgateway.exe C:/app/agentgateway.exe
LABEL org.opencontainers.image.source=https://github.com/agentgateway/agentgateway
LABEL org.opencontainers.image.description="Agentgateway is an open source project that is built on AI-native protocols to connect, secure, and observe agent-to-agent and agent-to-tool communication across any agent framework and environment."
ENTRYPOINT ["C:\\app\\agentgateway.exe"]
```
## /Makefile
``` path="/Makefile"
# Image configuration
DOCKER_REGISTRY ?= ghcr.io
DOCKER_REPO ?= agentgateway
IMAGE_NAME ?= agentgateway
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || jj log -r @ -T 'commit_id.shortest(12)' --no-graph 2>/dev/null || echo unknown)
GIT_REVISION ?= $(shell git rev-parse HEAD 2>/dev/null || jj log -r @ -T 'commit_id' --no-graph 2>/dev/null || echo unknown)
IMAGE_TAG ?= $(VERSION)
IMAGE_FULL_NAME ?= $(DOCKER_REGISTRY)/$(DOCKER_REPO)/$(IMAGE_NAME):$(IMAGE_TAG)
DOCKER_BUILDER ?= docker
DOCKER_BUILD_ARGS ?= --build-arg VERSION=$(VERSION) --build-arg GIT_REVISION=$(GIT_REVISION)
export PATH := ./tools:$(PATH)
# docker
.PHONY: docker
docker:
ifeq ($(OS),Windows_NT)
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) -f Dockerfile.windows -t $(IMAGE_FULL_NAME) .
else
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) -t $(IMAGE_FULL_NAME) . --progress=plain
endif
.PHONY: docker-ci
docker-ci:
ifeq ($(OS),Windows_NT)
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) --build-arg PROFILE=ci -f Dockerfile.windows -t $(IMAGE_FULL_NAME) .
else
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) --build-arg PROFILE=ci -t $(IMAGE_FULL_NAME) . --progress=plain
endif
.PHONY: docker-musl
docker-musl:
$(DOCKER_BUILDER) build $(DOCKER_BUILD_ARGS) -t $(IMAGE_FULL_NAME)-musl --build-arg=BUILDER=musl . --progress=plain
CARGO_BUILD_ARGS ?=
# build
.PHONY: build
build:
cargo build --release --features ui $(CARGO_BUILD_ARGS)
.PHONY: build-target
build-target:
cargo build --features ui $(CARGO_BUILD_ARGS) --target $(TARGET) --profile $(PROFILE)
# lint
.PHONY: lint
lint:
cargo fmt --check -- --config imports_granularity=Module,group_imports=StdExternalCrate,normalize_comments=true
cargo clippy --all-targets -- -D warnings
.PHONY: fix-lint
fix-lint: format
cargo clippy --fix --allow-staged --allow-dirty --allow-no-vcs
.PHONY: format
format:
cargo fmt -- --config imports_granularity=Module,group_imports=StdExternalCrate,normalize_comments=true
# test
.PHONY: test
test:
cargo test --all-targets
.PHONY: test-release
test-release:
cargo test --profile quick-release --all-targets
# clean
.PHONY: clean
clean:
cargo clean
objects := $(wildcard examples/*/config.json)
.PHONY: check-clean-repo
check-clean-repo:
@tools/check_clean_repo.sh
.PHONY: gen
gen: generate-apis generate-schema format
@:
.PHONY: generate-schema
generate-schema:
@cargo xtask schema
# Code generation for xds apis
.PHONY: generate-apis
generate-apis:
@PATH="./common/tools:$(PATH)" buf generate --path crates/protos/proto/resource.proto
.PHONY: run-validation-deps
run-validation-deps:
@tools/manage-validation-deps.sh start
.PHONY: stop-validation-deps
stop-validation-deps:
@tools/manage-validation-deps.sh stop
.PHONY: validate
validate:
@tools/validate-configs.sh
```
## /README.md
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/agentgateway/agentgateway/refs/heads/main/img/banner-light.svg" alt="agentgateway" width="400">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/agentgateway/agentgateway/refs/heads/main/img/banner-dark.svg" alt="agentgateway" width="400">
<img alt="agentgateway" src="https://raw.githubusercontent.com/agentgateway/agentgateway/refs/heads/main/img/banner-light.svg">
</picture>
<div>
<a href="https://opensource.org/licenses/Apache-2.0">
<img src="https://img.shields.io/badge/License-Apache2.0-brightgreen.svg?style=flat" alt="License: Apache 2.0">
</a>
<a href="https://github.com/agentgateway/agentgateway">
<img src="https://img.shields.io/github/stars/agentgateway/agentgateway.svg?style=flat&logo=github&label=Stars" alt="Stars">
</a>
<a href="https://discord.gg/BdJpzaPjHv">
<img src="https://img.shields.io/discord/1346225185166065826?style=flat&label=Join%20Discord&color=6D28D9" alt="Discord">
</a>
<a href="https://github.com/agentgateway/agentgateway/releases">
<img src="https://img.shields.io/github/v/release/agentgateway/agentgateway?style=flat&label=Latest%20Release&color=6D28D9" alt="Latest Release">
</a>
<a href="https://deepwiki.com/agentgateway/agentgateway"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
<a href='https://codespaces.new/agentgateway/agentgateway'>
<img src='https://github.com/codespaces/badge.svg' alt='Open in Github Codespaces' style='max-width: 100%;' height="20">
</a>
</div>
<div>
The <strong>first complete</strong> connectivity solution for Agentic AI.
</div>
</div>
---
**Agentgateway** is an open source proxy built on AI-native protocols ([MCP](https://modelcontextprotocol.io/introduction) & [A2A](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/)) that provides drop-in security, observability, and governance for agent-to-LLM, agent-to-tool, and agent-to-agent communication across any framework and environment.
<br>
<div align="center">
<img alt="agentgateway UI" src="img/architecture.svg" width="600">
</div>
<br>
## Intro to Agentgateway Video
[](https://youtu.be/SomP92JWPmE)
## Key Features
- **LLM Gateway**<br>
Route traffic to major LLM providers (OpenAI, Anthropic, Gemini, Bedrock, and more) through a unified OpenAI-compatible API with budget and spend controls, prompt enrichment, load balancing, and failover.
- **MCP Gateway**<br>
Connect LLMs to tools and external data sources via MCP with tool federation, stdio/HTTP/SSE/Streamable HTTP transports, OpenAPI integration, and OAuth authentication.
- **A2A Gateway**<br>
Enable secure agent-to-agent communication using A2A, with capability discovery, modality negotiation, and task collaboration.
- **Inference Routing**<br>
Intelligent routing to self-hosted models using Kubernetes Inference Gateway extensions, with decisions based on GPU utilization, KV cache, LoRA adapters, and queue depth.
- **Guardrails**<br>
Multi-layered content filtering with regex, OpenAI moderation, AWS Bedrock Guardrails, Google Model Armor, and custom webhooks.
- **Security & Observability**<br>
Auth (JWT, API keys, OAuth), fine-grained RBAC with CEL policy engine, rate limiting, TLS, and OpenTelemetry metrics/logs/tracing.
<br>
## Getting Started
- [Standalone Quickstart](https://agentgateway.dev/docs/quickstart) — Get started with agentgateway in minutes.
- [Kubernetes Quickstart](https://agentgateway.dev/docs/kubernetes/latest) — Deploy on Kubernetes using the built-in controller and Gateway API.
## Documentation
Depending on your deployment environment, check out the following docs:
- [agentgateway.dev/docs](https://agentgateway.dev/docs/): For standalone deployments such as local or on-prem. These docs are for this upstream `agentgateway/agentgateway` GitHub project.
- [agentgateway.dev/docs/kubernetes/latest](https://agentgateway.dev/docs/kubernetes/latest): For Kubernetes-based deployments using the built-in Kubernetes controller and Gateway API support.
Agentgateway has a built-in UI for you to explore agentgateway connecting agent-to-agent or agent-to-tool:
<div align="center">
<img alt="agentgateway UI" src="img/UI-homepage.png">
</div>
## Sponsors
<table>
<tr>
<td align="center" width="33.3%">
<a href="https://blacksmith.sh/">
<picture>
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/agentgateway/agentgateway/main/img/blacksmith-light.svg">
<img src="https://raw.githubusercontent.com/agentgateway/agentgateway/main/img/blacksmith.svg" alt="Blacksmith" height="48">
</picture>
</a>
</td>
</tr>
</table>
Thank you to our sponsors for helping to fund the development of agentgateway!
## Contributing
For instructions on how to contribute to the agentgateway project, see the [CONTRIBUTION.md](CONTRIBUTION.md) file.
## Community Meetings
To join a community meeting, add the [agentgateway calendar](https://calendar.google.com/calendar/u/0?cid=Y18zZTAzNGE0OTFiMGUyYzU2OWI1Y2ZlOWNmOWM4NjYyZTljNTNjYzVlOTdmMjdkY2I5ZTZmNmM5ZDZhYzRkM2ZmQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20) to your Google account. Then, you can find event details on the calendar.
Recordings of the community meetings will be published on our [google drive](https://drive.google.com/drive/folders/138716fESpxLkbd_KkGrUHa6TD7OA2tHs?usp=sharing).
## Roadmap
`agentgateway` is currently in active development. If you'd like a feature that's missing, open an issue in our [GitHub repo](https://github.com/agentgateway/agentgateway/issues).
## Contributors
Thanks to all contributors who are helping to make agentgateway better.
<a href="https://github.com/agentgateway/agentgateway/graphs/contributors">
<img src="https://contrib.rocks/image?repo=agentgateway/agentgateway" />
</a>
### Star History
<a href="https://www.star-history.com/#agentgateway/agentgateway&Date">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=agentgateway/agentgateway&type=Date&theme=dark" />
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=agentgateway/agentgateway&type=Date" />
<img alt="Star history of agentgateway/agentgateway over time" src="https://api.star-history.com/svg?repos=agentgateway/agentgateway&type=Date" />
</picture>
</a>
---
<div align="center">
<img src="img/lf-stacked-color.png" width="300" alt="Linux Foundation logo"/>
<p>Agentgateway is a <a href="https://www.linuxfoundation.org/">Linux Foundation</a> project.</p>
</div>
## /SECURITY.md
# Security Policy
## Reporting a Vulnerability
To report a vulnerability, [file a private vulnerability report](https://github.com/agentgateway/agentgateway/security/advisories/new).
This report will be privately reviewed by the Agentgateway security team.
**Please do not report security vulnerabilities through public GitHub issues.**
If you aren't sure if an issue is a security vulnerability, it's best to err on the side of caution and report it privately.
## /Tiltfile
``` path="/Tiltfile"
# Tiltfile for AgentGateway development
# This deploys both control plane (Go) and data plane (Rust) to Kind with live updates
load('ext://restart_process', 'docker_build_with_restart')
load('ext://helm_resource', 'helm_resource', 'helm_repo')
# Configuration
version = 'v1.0.1-dev'
cluster_name = 'kind'
install_namespace = k8s_namespace()
image_registry = 'localhost:5000'
# Ensure Kind cluster exists
allow_k8s_contexts('kind-' + cluster_name)
# Helper to run Make targets
def run_make(target, cwd='.'):
return local('make -C ' + cwd + ' ' + target)
def run_controller_make(target):
return run_make(target, cwd='./controller')
# =============================================================================
# Setup: Ensure cluster is ready
# =============================================================================
# Check if kind cluster exists, create if not
if str(local('kind get clusters 2>/dev/null | grep -c "^' + cluster_name + '{{contextString}}quot; || true')).strip() == '0':
print('No kind cluster! create one and restart tilt after doing so. You can use this command:')
print('ctlptl create cluster kind --name kind-' + cluster_name + ' --registry=ctlptl-registry')
fail("started kind cluster. Create one and run tilt again")
print('Installing Gateway API CRDs...')
run_controller_make('gw-api-crds')
run_controller_make('gie-crds')
# Install CRDs
print('Installing AgentGateway CRDs...')
helm_resource(
'agentgateway-crds',
'controller/install/helm/agentgateway-crds',
namespace=install_namespace,
flags=['--set=version=' + version],
)
# =============================================================================
# Control Plane (Go-based controller)
# =============================================================================
local_resource(
'go-compile-controller',
'make -C ./controller VERSION=' + version + ' GCFLAGS=all="-N -l" agentgateway-controller && mv ./controller/_output/pkg/agentgateway/agentgateway-linux-$(go env GOARCH) ./tools/tilt/agentgateway-controller',
deps=['./controller/'],
ignore=['./controller/_output/'],
)
# Build control plane Docker image
docker_build_with_restart(
image_registry + '/agentgateway-controller',
context='./tools/tilt/',
entrypoint='/usr/local/bin/agentgateway-controller',
dockerfile_contents="""
FROM ubuntu:24.04
COPY agentgateway-controller /usr/local/bin/agentgateway-controller
ENTRYPOINT /usr/local/bin/agentgateway-controller
""",
# Live update: sync Go binaries
live_update=[
# Sync Go code changes
sync('./tools/tilt/agentgateway-controller', '/usr/local/bin/agentgateway-controller'),
],
only=[
'./agentgateway-controller',
],
)
# =============================================================================
# Deploy via Helm
# =============================================================================
# Deploy AgentGateway via Helm
k8s_yaml(helm(
'controller/install/helm/agentgateway',
name='agentgateway',
namespace=install_namespace,
set=[
'image.registry=' + image_registry,
'image.tag=' + version,
'image.pullPolicy=IfNotPresent',
'controller.image.repository=agentgateway-controller',
'controller.image.tag=' + version,
'controller.replicaCount=1',
'controller.logLevel=debug',
'proxy.image.repository=agentgateway',
'proxy.image.tag=' + version,
],
values=[config.main_dir + '/controller/hack/helm/dev.yaml'] if os.path.exists(config.main_dir + '/controller/hack/helm/dev.yaml') else [],
))
k8s_resource('agentgateway',
resource_deps=['go-compile-controller'])
# =============================================================================
# Data Plane (Rust-based proxy)
# =============================================================================
local_resource(
'rust-compile-dataplane',
'cargo build && if [ -f "./tools/tilt/agentgateway" ]; then rm "./tools/tilt/agentgateway"; fi && mv ./target/debug/agentgateway ./tools/tilt/agentgateway',
deps=['./crates',
'./Cargo.toml',
'./Cargo.lock',
'./.cargo'])
#
# Build data plane Docker image
docker_build(
'agentgateway',
context='./tools/tilt/',
dockerfile_contents="""
FROM ubuntu:24.04
COPY start.sh /scripts/start.sh
COPY restart.sh /scripts/restart.sh
COPY agentgateway /usr/local/bin/
ENTRYPOINT ["/scripts/start.sh", "/usr/local/bin/agentgateway"]
""",
live_update=[
sync('./tools/tilt/agentgateway', '/usr/local/bin/agentgateway'),
run('/scripts/restart.sh'),
],
only=[
'./agentgateway',
'./start.sh',
'./restart.sh',
],
)
k8s_kind('AgentgatewayParameters', image_object={'json_path': '{.spec.image}', 'repo_field': 'repository', 'tag_field': 'tag'})
k8s_kind('Gateway', pod_readiness='wait')
k8s_yaml(blob("""
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayParameters
metadata:
name: dataplane-dev-gwparams
spec:
image:
registry: "" # tilt will fill in the registry in the repository field, so leave it blank here (othewise it will be duplicated)
repository: agentgateway
tag: """ + version + """
deployment:
spec:
template:
spec:
containers:
# Delete container-level securityContext so that Tilt can apply live updates
# (need root user, and file system to be writable for live updates)
- name: agentgateway
securityContext:
$patch: delete
---
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: tilt-gw
spec:
gatewayClassName: agentgateway
infrastructure:
parametersRef:
group: agentgateway.dev
kind: AgentgatewayParameters
name: dataplane-dev-gwparams
listeners:
- name: http
protocol: HTTP
port: 8080
"""))
k8s_resource(workload='dataplane-dev-gwparams', extra_pod_selectors={"gateway.networking.k8s.io/gateway-name":"tilt-gw"},
resource_deps=['rust-compile-dataplane'])
```
## /api/go.mod
```mod path="/api/go.mod"
module github.com/agentgateway/agentgateway/api
go 1.24.0
require (
github.com/golang/protobuf v1.5.4
google.golang.org/protobuf v1.36.11
)
```
## /api/go.sum
```sum path="/api/go.sum"
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
```
## /api/resource_json.gen.go
```go path="/api/resource_json.gen.go"
// Code generated by protoc-gen-jsonshim. DO NOT EDIT.
package api
import (
bytes "bytes"
jsonpb "github.com/golang/protobuf/jsonpb"
)
// MarshalJSON is a custom marshaler for Resource
func (this *Resource) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Resource
func (this *Resource) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Bind
func (this *Bind) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Bind
func (this *Bind) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for RouteName
func (this *RouteName) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for RouteName
func (this *RouteName) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for ListenerName
func (this *ListenerName) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for ListenerName
func (this *ListenerName) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for ResourceName
func (this *ResourceName) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for ResourceName
func (this *ResourceName) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TypedResourceName
func (this *TypedResourceName) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TypedResourceName
func (this *TypedResourceName) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Listener
func (this *Listener) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Listener
func (this *Listener) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Route
func (this *Route) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Route
func (this *Route) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for RouteGroup
func (this *RouteGroup) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for RouteGroup
func (this *RouteGroup) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TCPRoute
func (this *TCPRoute) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TCPRoute
func (this *TCPRoute) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for ConditionalPolicies
func (this *ConditionalPolicies) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for ConditionalPolicies
func (this *ConditionalPolicies) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for ConditionalPolicy
func (this *ConditionalPolicy) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for ConditionalPolicy
func (this *ConditionalPolicy) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Policy
func (this *Policy) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Policy
func (this *Policy) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Backend
func (this *Backend) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Backend
func (this *Backend) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TLSConfig
func (this *TLSConfig) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TLSConfig
func (this *TLSConfig) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Timeout
func (this *Timeout) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Timeout
func (this *Timeout) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Retry
func (this *Retry) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Retry
func (this *Retry) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendAuthPolicy
func (this *BackendAuthPolicy) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendAuthPolicy
func (this *BackendAuthPolicy) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AuthorizationLocation
func (this *AuthorizationLocation) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AuthorizationLocation
func (this *AuthorizationLocation) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AuthorizationLocation_Header
func (this *AuthorizationLocation_Header) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AuthorizationLocation_Header
func (this *AuthorizationLocation_Header) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AuthorizationLocation_QueryParameter
func (this *AuthorizationLocation_QueryParameter) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AuthorizationLocation_QueryParameter
func (this *AuthorizationLocation_QueryParameter) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AuthorizationLocation_Cookie
func (this *AuthorizationLocation_Cookie) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AuthorizationLocation_Cookie
func (this *AuthorizationLocation_Cookie) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Passthrough
func (this *Passthrough) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Passthrough
func (this *Passthrough) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Key
func (this *Key) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Key
func (this *Key) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Gcp
func (this *Gcp) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Gcp
func (this *Gcp) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Gcp_AccessToken
func (this *Gcp_AccessToken) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Gcp_AccessToken
func (this *Gcp_AccessToken) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Gcp_IdToken
func (this *Gcp_IdToken) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Gcp_IdToken
func (this *Gcp_IdToken) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Aws
func (this *Aws) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Aws
func (this *Aws) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Azure
func (this *Azure) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Azure
func (this *Azure) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AwsExplicitConfig
func (this *AwsExplicitConfig) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AwsExplicitConfig
func (this *AwsExplicitConfig) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AwsImplicit
func (this *AwsImplicit) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AwsImplicit
func (this *AwsImplicit) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AzureExplicitConfig
func (this *AzureExplicitConfig) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AzureExplicitConfig
func (this *AzureExplicitConfig) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AzureClientSecret
func (this *AzureClientSecret) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AzureClientSecret
func (this *AzureClientSecret) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AzureManagedIdentityCredential
func (this *AzureManagedIdentityCredential) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AzureManagedIdentityCredential
func (this *AzureManagedIdentityCredential) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AzureManagedIdentityCredential_UserAssignedIdentity
func (this *AzureManagedIdentityCredential_UserAssignedIdentity) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AzureManagedIdentityCredential_UserAssignedIdentity
func (this *AzureManagedIdentityCredential_UserAssignedIdentity) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AzureWorkloadIdentityCredential
func (this *AzureWorkloadIdentityCredential) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AzureWorkloadIdentityCredential
func (this *AzureWorkloadIdentityCredential) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AzureDeveloperImplicit
func (this *AzureDeveloperImplicit) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AzureDeveloperImplicit
func (this *AzureDeveloperImplicit) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AzureImplicit
func (this *AzureImplicit) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AzureImplicit
func (this *AzureImplicit) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for RouteMatch
func (this *RouteMatch) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for RouteMatch
func (this *RouteMatch) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for PathMatch
func (this *PathMatch) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for PathMatch
func (this *PathMatch) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for QueryMatch
func (this *QueryMatch) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for QueryMatch
func (this *QueryMatch) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for MethodMatch
func (this *MethodMatch) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for MethodMatch
func (this *MethodMatch) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for HeaderMatch
func (this *HeaderMatch) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for HeaderMatch
func (this *HeaderMatch) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for CORS
func (this *CORS) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for CORS
func (this *CORS) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for DirectResponse
func (this *DirectResponse) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for DirectResponse
func (this *DirectResponse) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for HeaderModifier
func (this *HeaderModifier) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for HeaderModifier
func (this *HeaderModifier) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for RequestMirrors
func (this *RequestMirrors) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for RequestMirrors
func (this *RequestMirrors) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for RequestMirrors_Mirror
func (this *RequestMirrors_Mirror) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for RequestMirrors_Mirror
func (this *RequestMirrors_Mirror) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for RequestRedirect
func (this *RequestRedirect) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for RequestRedirect
func (this *RequestRedirect) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for UrlRewrite
func (this *UrlRewrite) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for UrlRewrite
func (this *UrlRewrite) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Header
func (this *Header) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Header
func (this *Header) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for RouteBackend
func (this *RouteBackend) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for RouteBackend
func (this *RouteBackend) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for PolicyTarget
func (this *PolicyTarget) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for PolicyTarget
func (this *PolicyTarget) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for PolicyTarget_ServiceTarget
func (this *PolicyTarget_ServiceTarget) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for PolicyTarget_ServiceTarget
func (this *PolicyTarget_ServiceTarget) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for PolicyTarget_BackendTarget
func (this *PolicyTarget_BackendTarget) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for PolicyTarget_BackendTarget
func (this *PolicyTarget_BackendTarget) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for PolicyTarget_GatewayTarget
func (this *PolicyTarget_GatewayTarget) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for PolicyTarget_GatewayTarget
func (this *PolicyTarget_GatewayTarget) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for PolicyTarget_RouteTarget
func (this *PolicyTarget_RouteTarget) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for PolicyTarget_RouteTarget
func (this *PolicyTarget_RouteTarget) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for PolicyTarget_ListenerSetTarget
func (this *PolicyTarget_ListenerSetTarget) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for PolicyTarget_ListenerSetTarget
func (this *PolicyTarget_ListenerSetTarget) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for KeepaliveConfig
func (this *KeepaliveConfig) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for KeepaliveConfig
func (this *KeepaliveConfig) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec
func (this *FrontendPolicySpec) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec
func (this *FrontendPolicySpec) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_HTTP
func (this *FrontendPolicySpec_HTTP) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_HTTP
func (this *FrontendPolicySpec_HTTP) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_TLS
func (this *FrontendPolicySpec_TLS) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_TLS
func (this *FrontendPolicySpec_TLS) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_TCP
func (this *FrontendPolicySpec_TCP) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_TCP
func (this *FrontendPolicySpec_TCP) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_NetworkAuthorization
func (this *FrontendPolicySpec_NetworkAuthorization) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_NetworkAuthorization
func (this *FrontendPolicySpec_NetworkAuthorization) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Logging
func (this *FrontendPolicySpec_Logging) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Logging
func (this *FrontendPolicySpec_Logging) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Logging_Field
func (this *FrontendPolicySpec_Logging_Field) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Logging_Field
func (this *FrontendPolicySpec_Logging_Field) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Logging_Fields
func (this *FrontendPolicySpec_Logging_Fields) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Logging_Fields
func (this *FrontendPolicySpec_Logging_Fields) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Logging_OtlpAccessLog
func (this *FrontendPolicySpec_Logging_OtlpAccessLog) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Logging_OtlpAccessLog
func (this *FrontendPolicySpec_Logging_OtlpAccessLog) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Tracing
func (this *FrontendPolicySpec_Tracing) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Tracing
func (this *FrontendPolicySpec_Tracing) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_TracingAttribute
func (this *FrontendPolicySpec_TracingAttribute) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_TracingAttribute
func (this *FrontendPolicySpec_TracingAttribute) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_ProxyProtocol
func (this *FrontendPolicySpec_ProxyProtocol) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_ProxyProtocol
func (this *FrontendPolicySpec_ProxyProtocol) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Metrics
func (this *FrontendPolicySpec_Metrics) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Metrics
func (this *FrontendPolicySpec_Metrics) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Metrics_Field
func (this *FrontendPolicySpec_Metrics_Field) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Metrics_Field
func (this *FrontendPolicySpec_Metrics_Field) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for FrontendPolicySpec_Metrics_Fields
func (this *FrontendPolicySpec_Metrics_Fields) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for FrontendPolicySpec_Metrics_Fields
func (this *FrontendPolicySpec_Metrics_Fields) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for JWTValidationOptions
func (this *JWTValidationOptions) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for JWTValidationOptions
func (this *JWTValidationOptions) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec
func (this *TrafficPolicySpec) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec
func (this *TrafficPolicySpec) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_RemoteRateLimit
func (this *TrafficPolicySpec_RemoteRateLimit) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_RemoteRateLimit
func (this *TrafficPolicySpec_RemoteRateLimit) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_RemoteRateLimit_Descriptor
func (this *TrafficPolicySpec_RemoteRateLimit_Descriptor) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_RemoteRateLimit_Descriptor
func (this *TrafficPolicySpec_RemoteRateLimit_Descriptor) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_RemoteRateLimit_Entry
func (this *TrafficPolicySpec_RemoteRateLimit_Entry) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_RemoteRateLimit_Entry
func (this *TrafficPolicySpec_RemoteRateLimit_Entry) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_LocalRateLimit
func (this *TrafficPolicySpec_LocalRateLimit) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_LocalRateLimit
func (this *TrafficPolicySpec_LocalRateLimit) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_ExternalAuth
func (this *TrafficPolicySpec_ExternalAuth) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_ExternalAuth
func (this *TrafficPolicySpec_ExternalAuth) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_ExternalAuth_BodyOptions
func (this *TrafficPolicySpec_ExternalAuth_BodyOptions) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_ExternalAuth_BodyOptions
func (this *TrafficPolicySpec_ExternalAuth_BodyOptions) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_ExternalAuth_GRPCProtocol
func (this *TrafficPolicySpec_ExternalAuth_GRPCProtocol) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_ExternalAuth_GRPCProtocol
func (this *TrafficPolicySpec_ExternalAuth_GRPCProtocol) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_ExternalAuth_HTTPProtocol
func (this *TrafficPolicySpec_ExternalAuth_HTTPProtocol) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_ExternalAuth_HTTPProtocol
func (this *TrafficPolicySpec_ExternalAuth_HTTPProtocol) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_RBAC
func (this *TrafficPolicySpec_RBAC) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_RBAC
func (this *TrafficPolicySpec_RBAC) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_JWTProvider
func (this *TrafficPolicySpec_JWTProvider) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_JWTProvider
func (this *TrafficPolicySpec_JWTProvider) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_JWT
func (this *TrafficPolicySpec_JWT) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_JWT
func (this *TrafficPolicySpec_JWT) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_JWT_MCP
func (this *TrafficPolicySpec_JWT_MCP) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_JWT_MCP
func (this *TrafficPolicySpec_JWT_MCP) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_BasicAuthentication
func (this *TrafficPolicySpec_BasicAuthentication) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_BasicAuthentication
func (this *TrafficPolicySpec_BasicAuthentication) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_APIKey
func (this *TrafficPolicySpec_APIKey) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_APIKey
func (this *TrafficPolicySpec_APIKey) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_APIKey_User
func (this *TrafficPolicySpec_APIKey_User) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_APIKey_User
func (this *TrafficPolicySpec_APIKey_User) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_TransformationPolicy
func (this *TrafficPolicySpec_TransformationPolicy) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_TransformationPolicy
func (this *TrafficPolicySpec_TransformationPolicy) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_TransformationPolicy_Transform
func (this *TrafficPolicySpec_TransformationPolicy_Transform) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_TransformationPolicy_Transform
func (this *TrafficPolicySpec_TransformationPolicy_Transform) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_HeaderTransformation
func (this *TrafficPolicySpec_HeaderTransformation) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_HeaderTransformation
func (this *TrafficPolicySpec_HeaderTransformation) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_BodyTransformation
func (this *TrafficPolicySpec_BodyTransformation) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_BodyTransformation
func (this *TrafficPolicySpec_BodyTransformation) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_CSRF
func (this *TrafficPolicySpec_CSRF) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_CSRF
func (this *TrafficPolicySpec_CSRF) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_ExtProc
func (this *TrafficPolicySpec_ExtProc) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_ExtProc
func (this *TrafficPolicySpec_ExtProc) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_ExtProc_NamespacedMetadataContext
func (this *TrafficPolicySpec_ExtProc_NamespacedMetadataContext) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_ExtProc_NamespacedMetadataContext
func (this *TrafficPolicySpec_ExtProc_NamespacedMetadataContext) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for TrafficPolicySpec_HostRewrite
func (this *TrafficPolicySpec_HostRewrite) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for TrafficPolicySpec_HostRewrite
func (this *TrafficPolicySpec_HostRewrite) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec
func (this *BackendPolicySpec) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec
func (this *BackendPolicySpec) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai
func (this *BackendPolicySpec_Ai) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai
func (this *BackendPolicySpec_Ai) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_Message
func (this *BackendPolicySpec_Ai_Message) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_Message
func (this *BackendPolicySpec_Ai_Message) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_PromptEnrichment
func (this *BackendPolicySpec_Ai_PromptEnrichment) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_PromptEnrichment
func (this *BackendPolicySpec_Ai_PromptEnrichment) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_RegexRule
func (this *BackendPolicySpec_Ai_RegexRule) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_RegexRule
func (this *BackendPolicySpec_Ai_RegexRule) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_RegexRules
func (this *BackendPolicySpec_Ai_RegexRules) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_RegexRules
func (this *BackendPolicySpec_Ai_RegexRules) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_Webhook
func (this *BackendPolicySpec_Ai_Webhook) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_Webhook
func (this *BackendPolicySpec_Ai_Webhook) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_Moderation
func (this *BackendPolicySpec_Ai_Moderation) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_Moderation
func (this *BackendPolicySpec_Ai_Moderation) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_BedrockGuardrails
func (this *BackendPolicySpec_Ai_BedrockGuardrails) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_BedrockGuardrails
func (this *BackendPolicySpec_Ai_BedrockGuardrails) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_GoogleModelArmor
func (this *BackendPolicySpec_Ai_GoogleModelArmor) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_GoogleModelArmor
func (this *BackendPolicySpec_Ai_GoogleModelArmor) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_AzureContentSafety
func (this *BackendPolicySpec_Ai_AzureContentSafety) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_AzureContentSafety
func (this *BackendPolicySpec_Ai_AzureContentSafety) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_RequestRejection
func (this *BackendPolicySpec_Ai_RequestRejection) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_RequestRejection
func (this *BackendPolicySpec_Ai_RequestRejection) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_ResponseGuard
func (this *BackendPolicySpec_Ai_ResponseGuard) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_ResponseGuard
func (this *BackendPolicySpec_Ai_ResponseGuard) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_RequestGuard
func (this *BackendPolicySpec_Ai_RequestGuard) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_RequestGuard
func (this *BackendPolicySpec_Ai_RequestGuard) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_PromptGuard
func (this *BackendPolicySpec_Ai_PromptGuard) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_PromptGuard
func (this *BackendPolicySpec_Ai_PromptGuard) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Ai_PromptCaching
func (this *BackendPolicySpec_Ai_PromptCaching) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Ai_PromptCaching
func (this *BackendPolicySpec_Ai_PromptCaching) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_A2A
func (this *BackendPolicySpec_A2A) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_A2A
func (this *BackendPolicySpec_A2A) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_InferenceRouting
func (this *BackendPolicySpec_InferenceRouting) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_InferenceRouting
func (this *BackendPolicySpec_InferenceRouting) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Eviction
func (this *BackendPolicySpec_Eviction) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Eviction
func (this *BackendPolicySpec_Eviction) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_Health
func (this *BackendPolicySpec_Health) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_Health
func (this *BackendPolicySpec_Health) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_BackendTLS
func (this *BackendPolicySpec_BackendTLS) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_BackendTLS
func (this *BackendPolicySpec_BackendTLS) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_BackendHTTP
func (this *BackendPolicySpec_BackendHTTP) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_BackendHTTP
func (this *BackendPolicySpec_BackendHTTP) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_BackendTunnel
func (this *BackendPolicySpec_BackendTunnel) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_BackendTunnel
func (this *BackendPolicySpec_BackendTunnel) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_BackendTCP
func (this *BackendPolicySpec_BackendTCP) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_BackendTCP
func (this *BackendPolicySpec_BackendTCP) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_McpAuthorization
func (this *BackendPolicySpec_McpAuthorization) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_McpAuthorization
func (this *BackendPolicySpec_McpAuthorization) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_McpAuthentication
func (this *BackendPolicySpec_McpAuthentication) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_McpAuthentication
func (this *BackendPolicySpec_McpAuthentication) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendPolicySpec_McpAuthentication_ResourceMetadata
func (this *BackendPolicySpec_McpAuthentication_ResourceMetadata) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendPolicySpec_McpAuthentication_ResourceMetadata
func (this *BackendPolicySpec_McpAuthentication_ResourceMetadata) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for StaticBackend
func (this *StaticBackend) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for StaticBackend
func (this *StaticBackend) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for DynamicForwardProxy
func (this *DynamicForwardProxy) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for DynamicForwardProxy
func (this *DynamicForwardProxy) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AwsBackend
func (this *AwsBackend) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AwsBackend
func (this *AwsBackend) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AwsAgentCoreBackend
func (this *AwsAgentCoreBackend) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AwsAgentCoreBackend
func (this *AwsAgentCoreBackend) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend
func (this *AIBackend) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend
func (this *AIBackend) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_HostOverride
func (this *AIBackend_HostOverride) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_HostOverride
func (this *AIBackend_HostOverride) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_OpenAI
func (this *AIBackend_OpenAI) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_OpenAI
func (this *AIBackend_OpenAI) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_Gemini
func (this *AIBackend_Gemini) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_Gemini
func (this *AIBackend_Gemini) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_Vertex
func (this *AIBackend_Vertex) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_Vertex
func (this *AIBackend_Vertex) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_Anthropic
func (this *AIBackend_Anthropic) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_Anthropic
func (this *AIBackend_Anthropic) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_Bedrock
func (this *AIBackend_Bedrock) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_Bedrock
func (this *AIBackend_Bedrock) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_AzureOpenAI
func (this *AIBackend_AzureOpenAI) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_AzureOpenAI
func (this *AIBackend_AzureOpenAI) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_Azure
func (this *AIBackend_Azure) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_Azure
func (this *AIBackend_Azure) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_Provider
func (this *AIBackend_Provider) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_Provider
func (this *AIBackend_Provider) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for AIBackend_ProviderGroup
func (this *AIBackend_ProviderGroup) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for AIBackend_ProviderGroup
func (this *AIBackend_ProviderGroup) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for MCPBackend
func (this *MCPBackend) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for MCPBackend
func (this *MCPBackend) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for MCPTarget
func (this *MCPTarget) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for MCPTarget
func (this *MCPTarget) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendReference
func (this *BackendReference) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendReference
func (this *BackendReference) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for BackendReference_Service
func (this *BackendReference_Service) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for BackendReference_Service
func (this *BackendReference_Service) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
// MarshalJSON is a custom marshaler for Alpn
func (this *Alpn) MarshalJSON() ([]byte, error) {
str, err := ResourceMarshaler.MarshalToString(this)
return []byte(str), err
}
// UnmarshalJSON is a custom unmarshaler for Alpn
func (this *Alpn) UnmarshalJSON(b []byte) error {
return ResourceUnmarshaler.Unmarshal(bytes.NewReader(b), this)
}
var (
ResourceMarshaler = &jsonpb.Marshaler{}
ResourceUnmarshaler = &jsonpb.Unmarshaler{AllowUnknownFields: true}
)
```
## /architecture/README.md
# Architecture
This folder contains developer-facing documentation on the project architecture.
Recommended reading order:
1. [Configuration](configuration.md)
1. [CEL](cel.md)
## /architecture/cel.md
# CEL
Agentgateway extensively uses [CEL](https://cel.dev/) throughout the project.
CEL is an expression language that can evaluate user-defined (at runtime) expressions based on incoming requests.
A simple example of an expression that could be used for MCP authorization: `jwt.sub == "test-user" && mcp.tool.name == "add"`.
For post-request logging, tracing, and metrics CEL, MCP tool calls also expose payload fields such as
`mcp.methodName`, `mcp.sessionId`, `mcp.tool.arguments`, `mcp.tool.result`, and `mcp.tool.error`.
Request-time authorization keeps the `mcp` context identity-only, so those payload fields are absent during RBAC evaluation.
While CEL is not as powerful as alternatives like Lua or WASM, it is pretty fast and good enough for many use cases.
Agentgateway currently uses CEL for:
* Defining attributes to include in logs/traces. For example `user_agent: 'request.headers["user-agent"]'`.
* Modifying HTTP headers and bodies.
* Authorization policies
* Selecting what aspects of a request to rate limit based on.
## Architecture
CEL allows evaluating expressions in a user-defined _context_ (here, users are agentgateway developers, not end-users).
The context includes custom variables and functions.
Agentgateway exposes a variety of variables based on the request context, as well as custom functions.
CEL expressions are used throughout the request processing pipeline, which means we may have an expression run before or after we have information available.
For example, a request header transformation runs before we have the `response` available, but logging fields runs after the `request` has been discarded.
For cases where the data is not yet available, these variables are just not available to the expression.
For fields that are _no longer available_, agentgateway will dynamically decide whether to keep the data around based on whether any expression depends on it.
This is done with the `ContextBuilder`.
During CEL policy parsing (which happens on configuration change, not each request), we extract which variables are referenced in the expression.
This handles _most_ cases, though its possible to have false negatives (for example, `request.body` is fine but `request["body"]` is not).
During request processing, `ContextBuilder.with_xxx()` is called to conditionally add fields into the context.
For example, if an expression requires `request.body` we will store a copy of the body in the context, but if no expression requires it the data will be ignored.
This ensures users only pay for what they use.
This is critical for `body`, which is super expensive, but also useful for `headers` which can be costly as well.
The variables available to users is auto-generated into a [JSON schema](../schema/cel.json) and [rendered to markdown](../schema/cel.md).
The (not auto-generated) CEL functions are documented in [cel_functions.rs](../schema/cel-functions.md).
## /architecture/configuration.md
# Configuration
Agentgateway has three forms of configuration:
## Static Configuration
**Static configuration** is set exactly once early in the process lifecycle.
This is set by environment variables or a YAML/JSON configuration (typically a file, but can also be passed as inline bytes into the command line).
This information is really about global settings like logging configurations, ports to use, etc.
All routing, policies, backends, etc are not configurable here.
## Local Configuration
**Local configuration** is configured via a file (YAML/JSON) and can define the full feature set of agentgateway (backends, routes, policies, etc).
The local configuration uses a file watch to dynamically reload changes.
The local configuration will translate into a shared (with [XDS](#xds-configuration)) internal representation (IR) that is used by the proxy at runtime.
In some cases, the IR and the local configuration are identical. In other cases, there are trivial re-mappings to make the usage more ergonomic.
Others are more broad differences, allow things like fetching JWKS from URLs, or creating a backend + policy with a simple expression like `host: https://example.com`.
## XDS Configuration
**XDS configuration** allows the proxy to be configured by a remote control plane.
We use the [XDS Transport Protocol](https://www.envoyproxy.io/docs/envoy/latest/api-docs/xds_protocol), but do not use the Envoy types (Listener, Cluster, etc), and instead use [purpose-built types](../crates/agentgateway/proto/resource.proto).
Like the local configuration, these map into the same shared IR.
Unlike the local configuration, the XDS translation will not do things like fetching from URLs/files, etc, and is optimized around being simple and efficient rather than easy for humans.
A critical design philosophy for the APIs is to maintain a nearly direct mapping of user facing APIs to XDS to IR.
This simplifies operations (its easy to understand the configuration when it closely maps to the APIs the human created), but also importantly performance.
Additionally, the control plane is greatly simplified as most of the translations are trivial mechanical operations rather than complex joins.
For example, consider a user facing API that allows a user to globally configure the TLS cipher suites.
In Envoy, the user changing this 1 field would fan out to every Cluster need to change; this is expensive.
In agentgateway, instead we would have a Policy that targets a Bind.
This means the user changing 1 field will only need to change 1 small protobuf message.
Another similar example is routes. In Envoy, listeners point to a list of routes.
Changing one route requires updating all of the routes **even with delta xDS**.
This route list can be multiple megabytes, so each time the user changes 1 small field (such as a weight on a route), multiple MBs need to be fanned out to each proxy.
In agentgateway, the cardinality of protobuf resources mirrors the user API.
* One `HTTPRoute` rule maps to one agentgateway `Route` (rather than a list of all routes)
* One `Pod` maps to one `Workload` (rather than a list of all endpoints for a service)
This is generally achieved by having resources point up to their parent, rather than the parent containing a list of children.
For example, a route references which listener its a part of.
For policies, similar philosophies are applied.
Policies are generally applied to a Gateway/Listener/HTTPRoute/HTTPRouteRule, with merging semantics (some types apply to Backend instead, though).
A naive approach would have the control plane flatten these down to the lowest type (HTTPRouteRule) which has the fanout problem.
In agentgateway, the control plane will instead send all of the policies as-is with a reference to where they apply.
The precedence/merging of policies is handled at runtime.
## /buf.gen.yaml
```yaml path="/buf.gen.yaml"
version: v1
plugins:
- name: go
out: api
opt: paths=source_relative
- name: golang-jsonshim
out: api
opt: paths=source_relative
```
## /buf.yaml
```yaml path="/buf.yaml"
version: v1beta1
build:
roots:
- crates/protos/proto
```
## /common/scripts/get-agentgateway
``` path="/common/scripts/get-agentgateway"
#!/usr/bin/env bash
# Copyright The agentgateway Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The install script is based off of the MIT-licensed script from glide,
# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
: ${BINARY_NAME:="agentgateway"}
: ${USE_SUDO:="true"}
: ${DEBUG:="false"}
: ${VERIFY_CHECKSUM:="true"}
: ${AGENTGATEWAY_INSTALL_DIR:="/usr/local/bin"}
HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)"
HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)"
HAS_OPENSSL="$(type "openssl" &> /dev/null && echo true || echo false)"
HAS_GPG="$(type "gpg" &> /dev/null && echo true || echo false)"
HAS_GIT="$(type "git" &> /dev/null && echo true || echo false)"
HAS_TAR="$(type "tar" &> /dev/null && echo true || echo false)"
HAS_JQ="$(type "jq" &> /dev/null && echo true || echo false)"
# initArch discovers the architecture for this system.
initArch() {
ARCH=$(uname -m)
case $ARCH in
armv5*) ARCH="armv5";;
armv6*) ARCH="armv6";;
armv7*) ARCH="arm";;
aarch64) ARCH="arm64";;
x86) ARCH="386";;
x86_64) ARCH="amd64";;
i686) ARCH="386";;
i386) ARCH="386";;
esac
}
# initOS discovers the operating system for this system.
initOS() {
OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
case "$OS" in
# Minimalist GNU for Windows
mingw*|cygwin*) OS='windows';;
esac
}
# runs the given command as root (detects if we are root already)
runAsRoot() {
if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then
sudo "${@}"
else
"${@}"
fi
}
# verifySupported checks that the os/arch combination is supported for
# binary builds, as well whether or not necessary tools are present.
verifySupported() {
local supported="darwin-amd64\ndarwin-arm64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nlinux-riscv64\nwindows-amd64\nwindows-arm64"
if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
echo "No prebuilt binary for ${OS}-${ARCH}."
echo "To build from source, go to https://github.com/agentgateway/agentgateway"
exit 1
fi
if [ "${HAS_CURL}" != "true" ] && [ "${HAS_WGET}" != "true" ]; then
echo "Either curl or wget is required"
exit 1
fi
if [ "${VERIFY_CHECKSUM}" == "true" ] && [ "${HAS_OPENSSL}" != "true" ]; then
echo "In order to verify checksum, openssl must first be installed."
echo "Please install openssl or set VERIFY_CHECKSUM=false in your environment."
exit 1
fi
if [ "${HAS_GIT}" != "true" ]; then
echo "[WARNING] Could not find git. It is required for plugin installation."
fi
if [ "${HAS_TAR}" != "true" ]; then
echo "[ERROR] Could not find tar. It is required to extract the agentgateway binary archive."
exit 1
fi
}
# checkDesiredVersion checks if the desired version is available.
checkDesiredVersion() {
if [ "x$DESIRED_VERSION" == "x" ]; then
# Get tag from release URL
local latest_release_url="https://api.github.com/repos/agentgateway/agentgateway/releases/latest"
local latest_release_response=""
if [ "${HAS_CURL}" == "true" ]; then
latest_release_response=$( curl -L --silent --show-error --fail "$latest_release_url" 2>&1 || true )
elif [ "${HAS_WGET}" == "true" ]; then
latest_release_response=$( wget "$latest_release_url" -q -O - 2>&1 || true )
fi
TAG=$( echo "$latest_release_response" | jq -r .tag_name | grep '^v[0-9]' )
if [ "x$TAG" == "x" ]; then
printf "Could not retrieve the latest release tag information from %s: %s\n" "${latest_release_url}" "${latest_release_response}"
exit 1
fi
else
TAG=$DESIRED_VERSION
fi
}
# Different versions have different format
function current-version() {
output=$($1 --version)
if echo "$output" | jq -e . >/dev/null 2>&1; then
echo "$output" | jq -r '.version'
else
echo "$output" | sed -n 's/.*GitTag:"\([^"]*\)".*/\1/p'
fi
}
# checkAgentGatewayInstalledVersion checks which version of is installed and
# if it needs to be changed.
checkAgentGatewayInstalledVersion() {
if [[ -f "${AGENTGATEWAY_INSTALL_DIR}/${BINARY_NAME}" ]]; then
local version="$(current-version "${AGENTGATEWAY_INSTALL_DIR}/${BINARY_NAME}")"
if [[ "$version" == "$TAG" ]]; then
echo "agentgateway ${version} is already ${DESIRED_VERSION:-latest}"
return 0
else
echo "agentgateway ${TAG} is available. Changing from version ${version}."
return 1
fi
else
return 1
fi
}
# downloadFile downloads the latest binary package and also the checksum
# for that binary.
downloadFile() {
AGENTGATEWAY_DIST="agentgateway-$OS-$ARCH"
DOWNLOAD_URL="https://github.com/agentgateway/agentgateway/releases/download/$TAG/$AGENTGATEWAY_DIST"
CHECKSUM_URL="$DOWNLOAD_URL.sha256"
AGENTGATEWAY_TMP_ROOT="$(mktemp -dt agentgateway-installer-XXXXXX)"
AGENTGATEWAY_TMP_FILE="$AGENTGATEWAY_TMP_ROOT/$AGENTGATEWAY_DIST"
AGENTGATEWAY_SUM_FILE="$AGENTGATEWAY_TMP_ROOT/$AGENTGATEWAY_DIST.sha256"
echo "Downloading $DOWNLOAD_URL"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "$CHECKSUM_URL" -o "$AGENTGATEWAY_SUM_FILE"
curl -SsL "$DOWNLOAD_URL" -o "$AGENTGATEWAY_TMP_FILE"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "$AGENTGATEWAY_SUM_FILE" "$CHECKSUM_URL"
wget -q -O "$AGENTGATEWAY_TMP_FILE" "$DOWNLOAD_URL"
fi
}
# verifyFile verifies the SHA256 checksum of the binary package
# and the GPG signatures for both the package and checksum file
# (depending on settings in environment).
verifyFile() {
if [ "${VERIFY_CHECKSUM}" == "true" ]; then
verifyChecksum
fi
}
# installFile installs the agentgateway binary.
installFile() {
echo "Preparing to install $BINARY_NAME into ${AGENTGATEWAY_INSTALL_DIR}"
runAsRoot chmod +x "$AGENTGATEWAY_TMP_ROOT/$BINARY_NAME-$OS-$ARCH"
runAsRoot cp "$AGENTGATEWAY_TMP_ROOT/$BINARY_NAME-$OS-$ARCH" "$AGENTGATEWAY_INSTALL_DIR/$BINARY_NAME"
echo "$BINARY_NAME installed into $AGENTGATEWAY_INSTALL_DIR/$BINARY_NAME"
}
# verifyChecksum verifies the SHA256 checksum of the binary package.
verifyChecksum() {
printf "Verifying checksum... "
local sum=$(openssl sha1 -sha256 ${AGENTGATEWAY_TMP_FILE} | awk '{print $2}')
local expected_sum=$(cat ${AGENTGATEWAY_SUM_FILE} | awk '{print $1}')
if [ "$sum" != "$expected_sum" ]; then
echo "SHA sum of ${AGENTGATEWAY_TMP_FILE} does not match. Aborting."
exit 1
fi
echo "Done."
}
# fail_trap is executed if an error occurs.
fail_trap() {
result=$?
if [ "$result" != "0" ]; then
if [[ -n "$INPUT_ARGUMENTS" ]]; then
echo "Failed to install $BINARY_NAME with the arguments provided: $INPUT_ARGUMENTS"
help
else
echo "Failed to install $BINARY_NAME"
fi
echo -e "\tFor support, go to https://github.com/agentgateway/agentgateway."
fi
cleanup
exit $result
}
# testVersion tests the installed client to make sure it is working.
testVersion() {
set +e
AGENTGATEWAY="$(command -v $BINARY_NAME)"
if [ "$?" = "1" ]; then
echo "$BINARY_NAME not found. Is $AGENTGATEWAY_INSTALL_DIR on your "'$PATH?'
exit 1
fi
set -e
}
# help provides possible cli installation arguments
help () {
echo "Accepted cli arguments are:"
echo -e "\t[--help|-h ] ->> prints this help"
echo -e "\t[--version|-v <desired_version>] . When not defined it fetches the latest release tag from the agentgateway GitHub repository"
echo -e "\te.g. --version v3.0.0 or -v canary"
echo -e "\t[--no-sudo] ->> install without sudo"
}
# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
cleanup() {
if [[ -d "${AGENTGATEWAY_TMP_ROOT:-}" ]]; then
rm -rf "$AGENTGATEWAY_TMP_ROOT"
fi
}
# Execution
#Stop execution on any error
trap "fail_trap" EXIT
set -e
# Set debug if desired
if [ "${DEBUG}" == "true" ]; then
set -x
fi
# Parsing input arguments (if any)
export INPUT_ARGUMENTS="${@}"
set -u
while [[ $# -gt 0 ]]; do
case $1 in
'--version'|-v)
shift
if [[ $# -ne 0 ]]; then
export DESIRED_VERSION="${1}"
if [[ "$1" != "v"* ]]; then
echo "Expected version arg ('${DESIRED_VERSION}') to begin with 'v', fixing..."
export DESIRED_VERSION="v${1}"
fi
else
echo -e "Please provide the desired version. e.g. --version v0.1.0 or -v canary"
exit 0
fi
;;
'--no-sudo')
USE_SUDO="false"
;;
'--help'|-h)
help
exit 0
;;
*) exit 1
;;
esac
shift
done
set +u
initArch
initOS
verifySupported
checkDesiredVersion
if ! checkAgentGatewayInstalledVersion; then
downloadFile
verifyFile
installFile
fi
testVersion
cleanup
```
## /controller/.custom-gcl.yml
```yml path="/controller/.custom-gcl.yml"
version: v2.8.0
name: golangci-lint-custom
destination: _output
plugins:
- module: github.com/kgateway-dev/krtequals
version: 'v0.0.0-20251210234050-024ef4e99e5c'
- module: 'sigs.k8s.io/kube-api-linter'
version: 'v0.0.0-20250715075424-4fab82d26a8e' # Pin to a commit while there's no tag
```
## /controller/.golangci.yaml
```yaml path="/controller/.golangci.yaml"
version: "2"
run:
concurrency: 4
tests: true
output:
formats:
text:
path: stdout
print-linter-name: true
print-issued-lines: true
linters:
default: none
enable:
- bodyclose
- copyloopvar
- forbidigo
- ginkgolinter
- gomodguard
- gosec
- importas
- ineffassign
- krtequals
- kubeapilinter
- misspell
- modernize
- nakedret
- predeclared
- promlinter
- sloglint
- spancheck
- staticcheck
- unparam
- unused
- usestdlibvars
- whitespace
settings:
custom:
krtequals:
type: "module"
description: Checks Equals() implementations for KRT-style semantic equality issues
settings:
deepEqual: false
checkUnexported: true
kubeapilinter:
type: module
description: Kube API Linter lints Kube like APIs based on API conventions and best practices
settings:
linters:
enable:
- "*"
disable:
- commentstart
- integers
- maxlength
- nobools
- nomaps
- optionalfields
- ssatags
lintersConfig:
conditions:
isFirstField: Ignore
useProtobuf: Forbid
usePatchStrategy: Ignore
forbidigo:
forbid:
- pattern: anypb.New
msg: use utils.MessageToAny instead
- pattern: kclient.New$
msg: use kclient.NewFilteredDelayed for CRDs and kclient.NewFiltered for core types, with discovery namespace ObjectFilter instead
- pattern: ^client.Client$
msg: use apiclient.Client instead of controller-runtime's client.Client
- pattern: (\bt|\bT\(\))\.Cleanup
msg: require testutils.Cleanup in e2e tests (test/e2e/)
gomodguard:
blocked:
modules:
- github.com/rotisserie/eris:
recommendations:
- errors.Join
reason: Use the std-lib errors package with \\%w instead.
- github.com/hashicorp/go-multierror:
recommendations:
- errors.Join
reason: Use errors.Join (Go 1.20+) instead.
- github.com/pkg/errors:
recommendations:
- fmt.Errorf
- errors.New
- errors.Join
reason: Use the std-lib errors package and fmt.Errorf with \\%w instead.
importas:
alias:
- pkg: k8s.io/api/apps/v1
alias: appsv1
- pkg: k8s.io/api/core/v1
alias: corev1
- pkg: k8s.io/apimachinery/pkg/apis/meta/v1
alias: metav1
- pkg: k8s.io/api/batch/v1
alias: batchv1
- pkg: sigs.k8s.io/gateway-api/apis/v1
alias: gwv1
- pkg: sigs.k8s.io/gateway-api/apis/v1alpha2
alias: gwv1a2
- pkg: sigs.k8s.io/gateway-api/apis/v1beta1
alias: gwv1b1
- pkg: github.com/agentgateway/agentgateway/controller/api/annotations
alias: apiannotations
- pkg: github.com/agentgateway/agentgateway/controller/api/settings
alias: apisettings
misspell:
ignore-rules:
- kgateway
modernize:
disable:
# disabled because modernize gets confused with conflicting edits. we can probably rely on the kube api linter instead for this one.
- omitzero
nakedret:
# The team consensus is that naked returns hinder the readability of the code.
# However, named return values can still be useful as documentation for certain scenarios.
# By setting this to 0 in lieu of the default 30, we will effectively allow named return
# values as long as they are included in the return statement(s) e.g.
# func foo() (a, b int) {
# a = 1
# b = 2
# c := 3
# d := 4
# // These are allowed
# return a, b
# return c, d
# return d, c
# // This is NOT allowed
# return
# // This is allowed but really, really bad. DO NOT do this.
# return b, a
max-func-lines: 0
staticcheck:
checks:
- SA1019 # deprecated usage
- ST1019 # duplicate imports
sloglint:
static-msg: true
msg-style: lowercased
key-naming-case: snake
# ignore built-in keys
forbidden-keys:
- time
- level
- msg
- source
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
paths:
- test/rules
- gomock_reflect_\d*
- third_party$
- builtin$
- examples$
rules:
# Forbid t.Cleanup only in e2e tests (exclude the rule from non-e2e paths)
- path-except: test/e2e/
linters:
- forbidigo
text: 'require testutils.Cleanup'
# Skip client.Client forbidgo rule for e2e tests
- path: test/e2e/
linters:
- forbidigo
text: 'use apiclient.Client instead'
# Restrict krtequals analyzer to the pkg and internal directories
- path-except: pkg/|internal/
linters:
- krtequals
# Only run kubeapilinter inside the 'api/' directory. This prevents running API-specific checks
# on unrelated packages like controllers or tests and producing false positives.
- path-except: "^api/v1alpha1"
linters:
- kubeapilinter
issues:
max-same-issues: 0
uniq-by-line: true
formatters:
enable:
- gofmt
- gci
settings:
gci:
sections:
- standard
- default
- prefix(github.com/kgateway-dev)
- blank
- dot
- localmodule
custom-order: true
exclusions:
generated: lax
paths:
- test/rules
- gomock_reflect_\d*
- third_party$
- builtin$
- examples$
```
## /controller/Makefile
``` path="/controller/Makefile"
# imports should be after the set up flags so are lower
# https://www.gnu.org/software/make/manual/html_node/Special-Variables.html#Special-Variables
.DEFAULT_GOAL := help
SHELL := /bin/bash
export PATH := ../tools:$(PATH)
#----------------------------------------------------------------------------------
# Help
#----------------------------------------------------------------------------------
# Our Makefile is quite large, and hard to reason through
# `make help` can be used to self-document targets
# To update a target to be self-documenting (and appear with the `help` command),
# place a comment after the target that is prefixed by `##`. For example:
# custom-target: ## comment that will appear in the documentation when running `make help`
#
# **NOTE TO DEVELOPERS**
# As you encounter make targets that are frequently used, please make them self-documenting
.PHONY: help
help: NAME_COLUMN_WIDTH=35
help: LINE_COLUMN_WIDTH=5
help: ## Output the self-documenting make targets
@grep -hnE '^[%a-zA-Z0-9_-]+:.*?## .*$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = "[:]|(## )"}; {printf "\033[36mL%-$(LINE_COLUMN_WIDTH)s%-$(NAME_COLUMN_WIDTH)s\033[0m %s\n", $1, $2, $4}'
#----------------------------------------------------------------------------------
# Base
#----------------------------------------------------------------------------------
ROOTDIR := $(shell pwd)
OUTPUT_DIR ?= $(ROOTDIR)/_output
export IMAGE_REGISTRY ?= ghcr.io/agentgateway
# Kind of a hack to make sure _output exists
z := $(shell mkdir -p $(OUTPUT_DIR))
BUILDX_BUILD ?= docker buildx build -q
# A 'v'-prefixed semver used only locally. Most calling GHA jobs customize
# this. Exported for use in goreleaser.yaml. Because our docker images are
# tagged with a 'v' prefix, we use the prefix here and strip the 'v' prefix
# where actual semver is desired.
VERSION ?= v1.0.1-dev
TAG ?= $(VERSION)
export VERSION
export LDFLAGS := -X 'github.com/agentgateway/agentgateway/controller/pkg/version.Version=$(VERSION)' -s -w
export GCFLAGS ?=
UNAME_M := $(shell uname -m)
# if `GOARCH` is set, then it will keep its value. Else, it will be changed based off the machine's host architecture.
# if the machines architecture is set to arm64 then we want to set the appropriate values, else we only support amd64
IS_ARM_MACHINE := $(or $(filter $(UNAME_M), arm64), $(filter $(UNAME_M), aarch64))
ifneq ($(IS_ARM_MACHINE), )
ifneq ($(GOARCH), amd64)
GOARCH := arm64
endif
else
# currently we only support arm64 and amd64 as a GOARCH option.
ifneq ($(GOARCH), arm64)
GOARCH := amd64
endif
endif
PLATFORM := --platform=linux/$(GOARCH)
GOOS ?= $(shell uname -s | tr '[:upper:]' '[:lower:]')
GO_BUILD_FLAGS := CGO_ENABLED=0 GOARCH=$(GOARCH)
TEST_ASSET_DIR ?= $(ROOTDIR)/_test
# This is the location where assets are placed after a test failure
# This is used by our e2e tests to emit information about the running instance of agentgateway
BUG_REPORT_DIR := $(TEST_ASSET_DIR)/bug_report
$(BUG_REPORT_DIR):
mkdir -p $(BUG_REPORT_DIR)
# Base Alpine image used for all containers. Exported for use in goreleaser.yaml.
export ALPINE_BASE_IMAGE ?= alpine:3.17.6
DEPSGOBIN ?= $(OUTPUT_DIR)
ANALYZE_ARGS ?= --fix --verbose --max-issues-per-linter 0 --max-same-issues 0
CUSTOM_GOLANGCI_LINT_BIN ?= $(DEPSGOBIN)/golangci-lint-custom
CUSTOM_GOLANGCI_LINT_RUN ?= $(CUSTOM_GOLANGCI_LINT_BIN) run --build-tags e2e
CUSTOM_GOLANGCI_LINT_FMT ?= $(CUSTOM_GOLANGCI_LINT_BIN) fmt
#----------------------------------------------------------------------------------
# Macros
#----------------------------------------------------------------------------------
# This macro takes a relative path as its only argument and returns all the files
# in the tree rooted at that directory that match the given criteria.
get_sources = $(shell find $(1) -name "*.go" | grep -v test | grep -v generated.go | grep -v mock_)
#----------------------------------------------------------------------------------
# Repo setup
#----------------------------------------------------------------------------------
.PHONY: init-git-hooks
init-git-hooks: ## Use the tracked version of Git hooks from this repo
git config core.hooksPath .githooks
.PHONY: fmt
fmt: ## Format the code with golangci-lint
golangci-lint fmt ./...
.PHONY: fmt-changed
fmt-changed: ## Format only the changed code with golangci-lint (skip deleted files)
@if git -C .. rev-parse --show-toplevel >/dev/null 2>&1; then \
git -C .. status -s -uno | awk '{print $2}'; \
else \
jj -R .. diff --name-only 2>/dev/null; \
fi | sed 's#^controller/##' | awk '/.*\.go$/' | xargs -r -I{} bash -lc '[ -f "{}" ] && $(CUSTOM_GOLANGCI_LINT_FMT) "{}" || true'
# must be a separate target so that make waits for it to complete before moving on
.PHONY: mod-download
mod-download: ## Download the dependencies
cd .. && go mod download all
cd ../tools && go mod download all
.PHONY: mod-tidy-nested
mod-tidy-nested: ## Tidy go mod files in nested modules
@echo "Tidying tools..." && cd ../tools && go mod tidy
.PHONY: mod-tidy
mod-tidy: mod-download mod-tidy-nested ## Tidy the go mod file
cd .. && go mod tidy
#----------------------------------------------------------------------------
# Analyze
#----------------------------------------------------------------------------
.PHONY: analyze
analyze: ensure-custom-golangci-lint ## Run golangci-lint. Override options with ANALYZE_ARGS.
$(CUSTOM_GOLANGCI_LINT_RUN) $(ANALYZE_ARGS) ./...
.PHONY: ensure-custom-golangci-lint
ensure-custom-golangci-lint:
@expected_go_version="$(go env GOVERSION)"; \
current_go_version="$( $(CUSTOM_GOLANGCI_LINT_BIN) version 2>/dev/null | sed -n 's/.* built with \(go[0-9.]*\).*/\1/p' )"; \
if [ ! -x "$(CUSTOM_GOLANGCI_LINT_BIN)" ] || [ "$current_go_version" != "$expected_go_version" ]; then \
echo "Rebuilding golangci-lint custom with $expected_go_version..."; \
rm -f "$(CUSTOM_GOLANGCI_LINT_BIN)"; \
golangci-lint custom; \
fi
.PHONY: lint-actions
lint-actions: ## Lint the GitHub Actions workflows
actionlint
#----------------------------------------------------------------------------------
# Ginkgo Tests
#----------------------------------------------------------------------------------
FLAKE_ATTEMPTS ?= 3
GINKGO_VERSION ?= $(shell echo $(shell go list -m github.com/onsi/ginkgo/v2) | cut -d' ' -f2)
GINKGO_ENV ?= ACK_GINKGO_RC=true ACK_GINKGO_DEPRECATIONS=$(GINKGO_VERSION)
GINKGO_FLAGS ?= -tags=purego --trace -progress -race --fail-fast -fail-on-pending --randomize-all --compilers=5 --flake-attempts=$(FLAKE_ATTEMPTS)
GINKGO_REPORT_FLAGS ?= --json-report=test-report.json --junit-report=junit.xml -output-dir=$(OUTPUT_DIR)
GINKGO_COVERAGE_FLAGS ?= --cover --covermode=atomic --coverprofile=coverage.cov
TEST_PKG ?= ./... # Default to run all tests except e2e tests
# This is a way for a user executing `make test` to be able to provide flags which we do not include by default
# For example, you may want to run tests multiple times, or with various timeouts
GINKGO_USER_FLAGS ?=
GINKGO ?= ginkgo
.PHONY: test
test: ## Run all tests with ginkgo, or only run the test package at {TEST_PKG} if it is specified
$(GO_TEST_ENV) $(GINKGO_ENV) $(GINKGO) -ldflags='$(LDFLAGS)' \
$(GINKGO_FLAGS) $(GINKGO_REPORT_FLAGS) $(GINKGO_USER_FLAGS) \
$(TEST_PKG)
# To run only e2e tests, we restrict to ./test/e2e/tests. We say
# '-tags=e2e' because untagged files contain unit tests cases, not e2e test
# cases, so we have to allow `go` to see our e2e tests. Someone might forget to
# label a new e2e test case with `//go:build e2e`, in which case `make unit`
# will error because there is no kind cluster.
#
# This build-tag approach makes unit tests run faster since e2e tests are not
# compiled, but it might be better to set an environment variable `E2E=true`
# and have end-to-end test cases report that they were skipped if it's not
# truthy. As it stands, a developer who runs `make unit` or `go test ./...`
# will still have e2e tests run by Github Actions once they publish a pull
# request.
.PHONY: e2e-test
e2e-test: testbox-docker kind-load-testbox
e2e-test: go-test
e2e-test: TEST_TAG = e2e
e2e-test: GO_TEST_ARGS = $(E2E_GO_TEST_ARGS)
e2e-test: export VERSION := $(VERSION)
# https://go.dev/blog/cover#heat-maps
.PHONY: test-with-coverage
test-with-coverage: GINKGO_FLAGS += $(GINKGO_COVERAGE_FLAGS)
test-with-coverage: test
cover -html $(OUTPUT_DIR)/coverage.cov
.PHONY: golden-deployer
golden-deployer: ## Refreshes golden files for ./test/deployer snapshot testing
REFRESH_GOLDEN=true go test ./test/deployer/... > /dev/null || true
@echo ""
@echo "This must pass after refreshing:"
go test ./test/deployer/...
.PHONY: golden-helm
golden-helm: ## Refreshes golden files for ./test/helm snapshot testing
REFRESH_GOLDEN=true go test ./test/helm/... > /dev/null || true
@echo ""
@echo "This must pass after refreshing:"
go test ./test/helm/...
#----------------------------------------------------------------------------------
# Go Tests
#----------------------------------------------------------------------------------
# Fix for macOS linker warning with race detector on arm64 (which still warns
# you that -ld_classic is deprecated, but that's better than broken race
# condition detection)
# See: https://github.com/golang/go/issues/61229
GO_TEST_ENV ?=
ifeq ($(GOOS), darwin)
ifeq ($(GOARCH), arm64)
override GO_TEST_ENV := CGO_LDFLAGS="-Wl,-ld_classic"
endif
endif
# Skip -race on e2e. This requires building the codebase twice, and provides no value as the only code executed is test code.
# Skip -vet; we already run it on the linter step and its very slow.
E2E_GO_TEST_ARGS ?= -vet=off -timeout=25m -outputdir=$(OUTPUT_DIR)
# Testing flags: https://pkg.go.dev/cmd/go#hdr-Testing_flags
# The default timeout for a suite is 10 minutes, but this can be overridden by setting the -timeout flag. Currently set
# to 25 minutes based on the time it takes to run the longest test setup.
GO_TEST_ARGS ?= -timeout=25m -outputdir=$(OUTPUT_DIR) -race
GO_TEST_COVERAGE_ARGS ?= --cover --covermode=atomic --coverprofile=cover.out
GO_TEST_COVERAGE ?= github.com/vladopajic/go-test-coverage/v2
# This is a way for a user executing `make go-test` to be able to provide args which we do not include by default
# For example, you may want to run tests multiple times, or with various timeouts
GO_TEST_USER_ARGS ?=
GO_TEST_RETRIES ?= 0
GOTESTSUM ?= gotestsum
GOTESTSUM_ARGS ?= --format=standard-verbose
.PHONY: go-test
go-test: ## Run all tests, or only run the test package at {TEST_PKG} if it is specified
go-test: reset-bug-report
$(GO_TEST_ENV) $(GOTESTSUM) $(GOTESTSUM_ARGS) --rerun-fails-abort-on-data-race --rerun-fails=$(GO_TEST_RETRIES) --packages="$(TEST_PKG)" -- -ldflags='$(LDFLAGS)' $(if $(TEST_TAG),-tags=$(TEST_TAG)) $(GO_TEST_ARGS) $(GO_TEST_USER_ARGS)
# https://go.dev/blog/cover#heat-maps
.PHONY: go-test-with-coverage
go-test-with-coverage: GO_TEST_ARGS += $(GO_TEST_COVERAGE_ARGS)
go-test-with-coverage: go-test
# https://go.dev/blog/cover#heat-maps
.PHONY: unit-with-coverage
unit-with-coverage:
@$(MAKE) --no-print-directory unit GO_TEST_ARGS="$(GO_TEST_ARGS) $(GO_TEST_COVERAGE_ARGS)"
.PHONY: unit
unit: ## Run all unit tests (excludes e2e tests)
@echo "Running unit tests (excluding e2e)..."
@$(MAKE) --no-print-directory go-test TEST_TAG=""
.PHONY: validate-test-coverage
validate-test-coverage: ## Validate the test coverage
$(GO_TEST_COVERAGE) --config=./test_coverage.yml
# https://go.dev/blog/cover#heat-maps
.PHONY: view-test-coverage
view-test-coverage:
cover -html $(OUTPUT_DIR)/cover.out
#----------------------------------------------------------------------------------
# MARK: Clean
#----------------------------------------------------------------------------------
# Important to clean before pushing new releases. Dockerfiles and binaries may not update properly
.PHONY: clean
clean:
rm -rf _output
rm -rf _test
git clean -f -X install
@# Note: _output removal also cleans stamps since STAMP_DIR is in _output
.PHONY: clean-tests
clean-tests:
find * -type f -name '*.test' -exec rm {} \;
find * -type f -name '*.cov' -exec rm {} \;
find * -type f -name 'junit*.xml' -exec rm {} \;
# NB: 'reset-bug-report: clean-bug-report $(BUG_REPORT_DIR)' would be a subtle
# bug since we would never run 'mkdir' if the directory already existed.
.PHONY: reset-bug-report
reset-bug-report: clean-bug-report
@$(MAKE) --no-print-directory $(BUG_REPORT_DIR)
.PHONY: clean-bug-report
clean-bug-report:
rm -rf $(BUG_REPORT_DIR)
#----------------------------------------------------------------------------------
# MARK: Generated Code
#----------------------------------------------------------------------------------
# This section uses stamp files to optimize 'make generate-all' by tracking dependencies.
#
# For local development:
# - 'make generate-all' only regenerates code when source files change (fast!)
# - Use 'make clean-stamps' to force full regeneration
#
# For CI (always regenerates to catch dependency tracking bugs):
# - 'make verify' cleans stamps and always regenerates everything
# - This ensures CI catches any mistakes in our dependency tracking
#
# How it works:
# - Each generation step creates a stamp file in _output/stamps/
# - Make compares stamp file timestamps with source file timestamps
# - Only re-runs steps when source files are newer than stamps
#----------------------------------------------------------------------------------
# Stamp directory for tracking generation steps
STAMP_DIR := $(OUTPUT_DIR)/stamps
$(STAMP_DIR):
mkdir -p $(STAMP_DIR)
# Source files that trigger API codegen
API_SOURCE_FILES := $(shell find api/v1alpha1 -name "*.go" ! -name "zz_generated*")
API_SOURCE_FILES += hack/generate.sh hack/generate.go
# Files that track dependency changes (in root module)
MOD_FILES := ../go.mod ../go.sum
# Clean generated code
.PHONY: clean-gen
clean-gen:
rm -rf api/applyconfiguration
rm -rf pkg/generated/openapi
rm -rf pkg/client
rm -f install/helm/agentgateway-crds/templates/agentgateway.dev_*.yaml
# Clean all stamp files to force regeneration
.PHONY: clean-stamps
clean-stamps:
rm -rf $(STAMP_DIR)
# API code generation with dependency tracking
$(STAMP_DIR)/go-generate-apis: $(API_SOURCE_FILES) | $(STAMP_DIR)
@echo "Running API code generation..."
GO111MODULE=on go generate ./hack/...
$(MAKE) fmt-changed
@touch $@
# Combine both generation steps
$(STAMP_DIR)/go-generate-all: $(STAMP_DIR)/go-generate-apis
@touch $@
# Module tidy with dependency tracking
$(STAMP_DIR)/mod-tidy: $(MOD_FILES) | $(STAMP_DIR)
@echo "Running mod tidy..."
@$(MAKE) --no-print-directory mod-download
@$(MAKE) --no-print-directory mod-tidy-nested
cd .. && go mod tidy
@touch $@
# License generation with dependency tracking
$(STAMP_DIR)/generate-licenses: $(MOD_FILES) | $(STAMP_DIR)
@echo "Generating licenses..."
../tools/oss_compliance osagen -c "GNU General Public License v2.0,GNU General Public License v3.0,GNU Lesser General Public License v2.1,GNU Lesser General Public License v3.0,GNU Affero General Public License v3.0"
../tools/oss_compliance osagen -s "Mozilla Public License 2.0,GNU General Public License v2.0,GNU General Public License v3.0,GNU Lesser General Public License v2.1,GNU Lesser General Public License v3.0,GNU Affero General Public License v3.0"> hack/utils/oss_compliance/osa_provided.md
../tools/oss_compliance osagen -i "Mozilla Public License 2.0"> hack/utils/oss_compliance/osa_included.md
@touch $@
# Formatting - only runs if generation steps changed
$(STAMP_DIR)/fmt: $(STAMP_DIR)/go-generate-all ensure-custom-golangci-lint
@echo "Formatting code..."
$(CUSTOM_GOLANGCI_LINT_FMT) ./...
@touch $@
# Fast generation using stamp files (for local development)
$(STAMP_DIR)/generated-code: $(STAMP_DIR)/go-generate-all $(STAMP_DIR)/mod-tidy $(STAMP_DIR)/generate-licenses $(STAMP_DIR)/fmt
@touch $@
.PHONY: verify
verify: generated-code ## Verify that generated code is up to date (always regenerates for CI safety)
git diff -U3 --exit-code
.PHONY: generate-all
generate-all: $(STAMP_DIR)/generated-code ## Generate all code with optimized dependencies (uses stamp files for speed)
.PHONY: generate
generate: generate-all ## Alias for generate
# Force full regeneration by cleaning stamps and generated files
.PHONY: generated-code
generated-code: clean-gen clean-stamps ## Force regenerate all code (always runs, ignoring stamps)
@$(MAKE) --no-print-directory generate-all
# Convenience PHONY targets that trigger stamp-based generation
.PHONY: go-generate-all
go-generate-all: $(STAMP_DIR)/go-generate-all ## Run all go generate directives (with dependency tracking)
.PHONY: go-generate-apis
go-generate-apis: $(STAMP_DIR)/go-generate-apis ## Run all go generate directives in the repo, including codegen for protos, mockgen, and more
.PHONY: go-generate-mocks
go-generate-mocks: $(STAMP_DIR)/go-generate-mocks ## Runs all generate directives for mockgen in the repo
.PHONY: generate-licenses
generate-licenses: $(STAMP_DIR)/generate-licenses ## Generate the licenses for the project
#----------------------------------------------------------------------------------
# Controller
#----------------------------------------------------------------------------------
# TODO: rename to agentgateway-controller
CONTROLLER_OUTPUT_DIR=$(OUTPUT_DIR)/pkg/agentgateway
export AGENTGATEWAY_IMAGE_REPO ?= agentgateway-controller
.PHONY: agentgateway-controller
agentgateway-controller:
$(GO_BUILD_FLAGS) GOOS=linux go build -ldflags='$(LDFLAGS)' -gcflags='$(GCFLAGS)' -o $(CONTROLLER_OUTPUT_DIR)/agentgateway-linux-$(GOARCH) ./cmd/agentgateway
$(CONTROLLER_OUTPUT_DIR)/Dockerfile.agentgateway: cmd/agentgateway/Dockerfile.agentgateway
cp {{contextString}}lt; $@
.PHONY: agentgateway-controller-docker
agentgateway-controller-docker: agentgateway-controller $(CONTROLLER_OUTPUT_DIR)/Dockerfile.agentgateway
$(BUILDX_BUILD) --load $(PLATFORM) $(CONTROLLER_OUTPUT_DIR) -f $(CONTROLLER_OUTPUT_DIR)/Dockerfile.agentgateway \
--build-arg GOARCH=$(GOARCH) \
-t $(IMAGE_REGISTRY)/$(AGENTGATEWAY_IMAGE_REPO):$(VERSION)
.PHONY: agentgateway-docker
agentgateway-docker: ## Build the proxy Docker image from the root Makefile
$(MAKE) -C .. docker IMAGE_TAG=$(VERSION)
.PHONY: agentgateway-controller-docker-local
agentgateway-controller-docker-local: agentgateway-controller $(CONTROLLER_OUTPUT_DIR)/Dockerfile.agentgateway
docker buildx build --push $(PLATFORM) $(CONTROLLER_OUTPUT_DIR) -f $(CONTROLLER_OUTPUT_DIR)/Dockerfile.agentgateway \
--build-arg GOARCH=$(GOARCH) \
-t localhost:5000/$(AGENTGATEWAY_IMAGE_REPO):$(TAG)
#----------------------------------------------------------------------------------
# testbox (used in e2e tests)
#----------------------------------------------------------------------------------
TESTBOX_DIR=hack/testbox
TESTBOX_OUTPUT_DIR=$(OUTPUT_DIR)/$(TESTBOX_DIR)
export TESTBOX_IMAGE_REPO ?= testbox
TESTBOX_VERSION=0.0.1
.PHONY: testbox
testbox:
$(GO_BUILD_FLAGS) GOOS=linux go build -ldflags='$(LDFLAGS)' -gcflags='$(GCFLAGS)' -o $(TESTBOX_OUTPUT_DIR)/testbox-linux-$(GOARCH) ./hack/testbox...
$(TESTBOX_OUTPUT_DIR)/Dockerfile.testbox: ./hack/testbox/Dockerfile
cp {{contextString}}lt; $@
.PHONY: testbox-docker
testbox-docker: testbox $(TESTBOX_OUTPUT_DIR)/Dockerfile.testbox
$(BUILDX_BUILD) --load $(PLATFORM) $(TESTBOX_OUTPUT_DIR) -f $(TESTBOX_OUTPUT_DIR)/Dockerfile.testbox \
--build-arg GOARCH=$(GOARCH) \
-t $(IMAGE_REGISTRY)/$(TESTBOX_IMAGE_REPO):$(TESTBOX_VERSION)
.PHONY: kind-load-testbox
kind-load-testbox:
kind load docker-image $(IMAGE_REGISTRY)/$(TESTBOX_IMAGE_REPO):$(TESTBOX_VERSION) --name $(CLUSTER_NAME)
#----------------------------------------------------------------------------------
# Helm
#----------------------------------------------------------------------------------
HELM ?= helm
# Publish charts with both semver variants to preserve compatibility.
# Keep VERSION as-is for image tags and other release identifiers.
HELM_CHART_VERSION_NO_V ?= $(patsubst v%,%,$(VERSION))
HELM_CHART_VERSION_V ?= v$(HELM_CHART_VERSION_NO_V)
HELM_PACKAGE_ARGS ?= --version $(HELM_CHART_VERSION_NO_V) --app-version $(HELM_CHART_VERSION_NO_V)
EXTRA_HELM_TAG ?=
HELM_CHART_DIR_AGW=install/helm/agentgateway
HELM_CHART_DIR_AGW_CRD=install/helm/agentgateway-crds
HELM_ADDITIONAL_VALUES ?= hack/helm/dev.yaml
.PHONY: package-agentgateway-charts
package-agentgateway-charts: package-agentgateway-chart package-agentgateway-crd-chart ## Package the agentgateway charts
.PHONY: package-agentgateway-chart
package-agentgateway-chart: ## Package the agentgateway chart
mkdir -p $(TEST_ASSET_DIR); \
$(HELM) package $(HELM_PACKAGE_ARGS) --destination $(TEST_ASSET_DIR) $(HELM_CHART_DIR_AGW); \
$(HELM) repo index $(TEST_ASSET_DIR);
.PHONY: package-agentgateway-crd-chart
package-agentgateway-crd-chart: ## Package the agentgateway crd chart
mkdir -p $(TEST_ASSET_DIR); \
$(HELM) package $(HELM_PACKAGE_ARGS) --destination $(TEST_ASSET_DIR) $(HELM_CHART_DIR_AGW_CRD); \
$(HELM) repo index $(TEST_ASSET_DIR);
CHART_NAMES := agentgateway agentgateway-crds
.PHONY: release-charts
release-charts: package-agentgateway-charts
mkdir -p $(TEST_ASSET_DIR); \
$(HELM) package --version $(HELM_CHART_VERSION_V) --app-version $(HELM_CHART_VERSION_V) --destination $(TEST_ASSET_DIR) $(HELM_CHART_DIR_AGW); \
$(HELM) repo index $(TEST_ASSET_DIR);
mkdir -p $(TEST_ASSET_DIR); \
$(HELM) package --version $(HELM_CHART_VERSION_V) --app-version $(HELM_CHART_VERSION_V) --destination $(TEST_ASSET_DIR) $(HELM_CHART_DIR_AGW_CRD); \
$(HELM) repo index $(TEST_ASSET_DIR);
@if [ -n "$(EXTRA_HELM_TAG)" ]; then \
mkdir -p $(TEST_ASSET_DIR); \
$(HELM) package --version $(EXTRA_HELM_TAG) --app-version $(VERSION) --destination $(TEST_ASSET_DIR) $(HELM_CHART_DIR_AGW); \
$(HELM) repo index $(TEST_ASSET_DIR); \
mkdir -p $(TEST_ASSET_DIR); \
$(HELM) package --version $(EXTRA_HELM_TAG) --app-version $(VERSION) --destination $(TEST_ASSET_DIR) $(HELM_CHART_DIR_AGW_CRD); \
$(HELM) repo index $(TEST_ASSET_DIR); \
fi
@for chart in $(CHART_NAMES); do \
$(HELM) push $(TEST_ASSET_DIR)/$chart-$(HELM_CHART_VERSION_NO_V).tgz oci://$(IMAGE_REGISTRY)/charts; \
$(HELM) push $(TEST_ASSET_DIR)/$chart-$(HELM_CHART_VERSION_V).tgz oci://$(IMAGE_REGISTRY)/charts; \
if [ -n "$(EXTRA_HELM_TAG)" ]; then \
$(HELM) push $(TEST_ASSET_DIR)/$chart-$(EXTRA_HELM_TAG).tgz oci://$(IMAGE_REGISTRY)/charts; \
fi; \
done;
.PHONY: deploy-agentgateway-crd-chart
deploy-agentgateway-crd-chart: ## Deploy the agentgateway crd chart
$(HELM) upgrade --install agentgateway-crds $(TEST_ASSET_DIR)/agentgateway-crds-$(HELM_CHART_VERSION_NO_V).tgz --namespace $(INSTALL_NAMESPACE) --create-namespace
.PHONY: deploy-agentgateway-chart
deploy-agentgateway-chart: ## Deploy the agentgateway chart
$(HELM) upgrade --install agentgateway $(TEST_ASSET_DIR)/agentgateway-$(HELM_CHART_VERSION_NO_V).tgz \
--namespace $(INSTALL_NAMESPACE) --create-namespace \
--set image.registry=$(IMAGE_REGISTRY) \
--set image.tag=$(VERSION) \
--set controller.image.repository=$(AGENTGATEWAY_IMAGE_REPO) \
-f $(HELM_ADDITIONAL_VALUES)
.PHONY: lint-charts
lint-charts: ## Lint the agentgateway charts
$(HELM) lint $(HELM_CHART_DIR_AGW)
$(HELM) lint $(HELM_CHART_DIR_AGW_CRD)
#----------------------------------------------------------------------------------
# Release
#----------------------------------------------------------------------------------
.PHONY: release-notes
release-notes: ## Generate release notes (PREVIOUS_TAG required, CURRENT_TAG optional)
./hack/generate-release-notes.sh -p $(PREVIOUS_TAG) -c $(or $(CURRENT_TAG),HEAD)
#----------------------------------------------------------------------------------
# MARK: Development
#----------------------------------------------------------------------------------
CLUSTER_NAME ?= kind
INSTALL_NAMESPACE ?= agentgateway-system
# The version of the Node Docker image to use for booting the kind cluster: https://hub.docker.com/r/kindest/node/tags
# This version should stay in sync with `hack/kind/setup-kind.sh`.
CLUSTER_NODE_VERSION ?= v1.35.0@sha256:452d707d4862f52530247495d180205e029056831160e22870e37e3f6c1ac31f
.PHONY: kind-create
kind-create: ## Create a KinD cluster
kind get clusters | grep $(CLUSTER_NAME) || kind create cluster --name $(CLUSTER_NAME) --image kindest/node:$(CLUSTER_NODE_VERSION)
CONFORMANCE_CHANNEL ?= experimental
CONFORMANCE_VERSION ?= $(shell go list -m -f '{{.Version}}' sigs.k8s.io/gateway-api)
.PHONY: gw-api-crds
gw-api-crds: ## Install the Gateway API CRDs. HACK: Use SSA to avoid the issue with the CRD annotations being too long.
ifeq ($(shell echo $(CONFORMANCE_VERSION) | grep -q '^v[0-9]' && echo yes),yes)
kubectl apply --server-side -f "https://github.com/kubernetes-sigs/gateway-api/releases/download/$(CONFORMANCE_VERSION)/$(CONFORMANCE_CHANNEL)-install.yaml"
else
ifeq ($(CONFORMANCE_CHANNEL), standard)
kubectl apply --server-side --kustomize "https://github.com/kubernetes-sigs/gateway-api/config/crd?ref=$(CONFORMANCE_VERSION)"
else
kubectl apply --server-side --kustomize "https://github.com/kubernetes-sigs/gateway-api/config/crd/$(CONFORMANCE_CHANNEL)?ref=$(CONFORMANCE_VERSION)"
endif
endif
# The version of the k8s gateway api inference extension CRDs to install.
GIE_CRD_VERSION ?= $(shell go list -m -f '{{.Version}}' sigs.k8s.io/gateway-api-inference-extension)
.PHONY: gie-crds
gie-crds: ## Install the Gateway API Inference Extension CRDs
ifeq ($(shell echo $(GIE_CRD_VERSION) | grep -q '^v[0-9]' && echo yes),yes)
kubectl apply -f "https://github.com/kubernetes-sigs/gateway-api-inference-extension/releases/download/$(GIE_CRD_VERSION)/manifests.yaml"
else
kubectl apply --kustomize "https://github.com/kubernetes-sigs/gateway-api-inference-extension/config/crd?ref=$(GIE_CRD_VERSION)"
endif
# Source the Istio CRDs from the vendored istio.io/istio module so the CRD
# version always matches the API version agentgateway is compiled against.
# The controller consumes Istio's ambient collections (WorkloadEntry,
# ServiceEntry, AuthorizationPolicy...) so these CRDs must exist for those
# informers to receive objects.
ISTIO_CRDS_FILE := $(shell go list -m -f '{{.Dir}}' istio.io/istio)/manifests/charts/base/files/crd-all.gen.yaml
.PHONY: istio-crds
istio-crds: ## Install Istio CRDs (WorkloadEntry, ServiceEntry, etc.) from the vendored istio module
kubectl apply --server-side -f "$(ISTIO_CRDS_FILE)"
.PHONY: metallb
metallb: ## Install the MetalLB load balancer
kubectl apply -f ./test/setup/metallb.yaml
kubectl rollout status -n metallb-system deployment/controller --timeout=120s
kubectl rollout status -n metallb-system daemonset/speaker --timeout=120s
.PHONY: deploy-agentgateway
deploy-agentgateway: package-agentgateway-charts deploy-agentgateway-crd-chart deploy-agentgateway-chart ## Deploy the agentgateway chart and CRDs
.PHONY: setup-base
setup-base: kind-create gw-api-crds gie-crds istio-crds metallb ## Setup the base infrastructure (kind cluster, CRDs, and MetalLB)
# Creates a functional kind cluster, builds and loads all images, and packages charts
# Does NOT deploy anything to the cluster
.PHONY: setup
setup: setup-base kind-build-and-load package-agentgateway-charts ## Setup base infra, build/load images, and package charts (without deployment)
.PHONY: run
run: setup deploy-agentgateway ## Set up complete development environment
#----------------------------------------------------------------------------------
# Build assets for kubernetes e2e tests
#----------------------------------------------------------------------------------
kind-setup: ## Set up the KinD cluster. Deprecated: use kind-create instead.
VERSION=${VERSION} CLUSTER_NAME=${CLUSTER_NAME} ./hack/kind/setup-kind.sh
kind-load-%:
kind load docker-image $(IMAGE_REGISTRY)/$*:$(VERSION) --name $(CLUSTER_NAME)
# Build an image and load it into the KinD cluster
# Depends on: IMAGE_REGISTRY, VERSION, CLUSTER_NAME
kind-build-and-load-%: %-docker kind-load-% ; ## Use to build specified image and load it into kind
# Update the docker image used by a deployment
# This works for most of our deployments because the deployment name and container name both match
# NOTE TO DEVS:
# I explored using a special format of the wildcard to pass deployment:image,
# but ran into some challenges with that pattern, while calling this target from another one.
# It could be a cool extension to support, but didn't feel pressing so I stopped
kind-set-image-%:
kubectl rollout pause deployment $* -n $(INSTALL_NAMESPACE) || true
kubectl set image deployment/$* $*=$(IMAGE_REGISTRY)/$*:$(VERSION) -n $(INSTALL_NAMESPACE)
kubectl patch deployment $* -n $(INSTALL_NAMESPACE) -p '{"spec": {"template":{"metadata":{"annotations":{"agentgateway-kind-last-update":"$(shell date)"}}}} }'
kubectl rollout resume deployment $* -n $(INSTALL_NAMESPACE)
# Reload an image in KinD
# This is useful to developers when changing a single component
# You can reload an image, which means it will be rebuilt and reloaded into the kind cluster, and the deployment
# will be updated to reference it
# Depends on: IMAGE_REGISTRY, VERSION, INSTALL_NAMESPACE , CLUSTER_NAME
kind-reload-%: kind-build-and-load-% kind-set-image-% ; ## Use to build specified image, load it into kind, and restart its deployment
.PHONY: kind-build-and-load ## Use to build all images and load them into kind
kind-build-and-load: kind-build-and-load-agentgateway-controller
kind-build-and-load: kind-build-and-load-agentgateway
kind-build-and-load: kind-build-and-load-testbox
.PHONY: kind-load ## Use to load all images into kind
kind-load: kind-load-agentgateway-controller
kind-load: kind-load-testbox
#----------------------------------------------------------------------------------
# Targets for running Agent Gateway conformance tests
#----------------------------------------------------------------------------------
# Agent Gateway conformance test configuration
AGW_CONFORMANCE_REPORT_ARGS ?= -report-output=$(TEST_ASSET_DIR)/conformance/agw-$(VERSION)-report.yaml -organization=agentgateway -project=agentgateway -version=$(VERSION) -url=github.com/agentgateway/agentgateway -contact=github.com/agentgateway/agentgateway/issues/new/choose
AGW_CONFORMANCE_ARGS := -gateway-class=agentgateway $(AGW_CONFORMANCE_REPORT_ARGS)
.PHONY: agw-conformance ## Run the agent gateway conformance test suite
agw-conformance:
@mkdir -p $(TEST_ASSET_DIR)/conformance
CGO_ENABLED=0 go test -mod=mod -ldflags='$(LDFLAGS)' -tags conformance -test.v ./test/conformance/... -args $(AGW_CONFORMANCE_ARGS)
#----------------------------------------------------------------------------------
# Targets for running Gateway API Inference Extension conformance tests
#----------------------------------------------------------------------------------
# Reporting flags, identical to CONFORMANCE_REPORT_ARGS but with "inference-"
GIE_CONFORMANCE_REPORT_ARGS ?= \
-report-output=$(TEST_ASSET_DIR)/conformance/inference-$(VERSION)-report.yaml \
-organization=agentgateway \
-project=agentgateway \
-version=$(VERSION) \
-url=github.com/agentgateway/agentgateway \
-contact=github.com/agentgateway/agentgateway/issues/new/choose
# The args to pass into the Gateway API Inference Extension conformance test suite.
GIE_CONFORMANCE_ARGS := \
-gateway-class=agentgateway \
$(GIE_CONFORMANCE_REPORT_ARGS)
.PHONY: gie-conformance
gie-conformance: gie-crds ## Run the Gateway API Inference Extension conformance suite
@mkdir -p $(TEST_ASSET_DIR)/conformance
CGO_ENABLED=0 go test -mod=mod -ldflags='$(LDFLAGS)' \
-tags conformance \
-timeout=25m \
-v $(shell go mod download && go list -m -f '{{.Dir}}' sigs.k8s.io/gateway-api-inference-extension/conformance) \
-args $(GIE_CONFORMANCE_ARGS)
# An alias to run both Gateway API and Inference Extension conformance tests.
.PHONY: all-conformance
all-conformance: gie-conformance agw-conformance ## Run all conformance test suites
@echo "All conformance suites have completed."
#----------------------------------------------------------------------------------
# Dependency Bumping
#----------------------------------------------------------------------------------
.PHONY: bump-gtw
bump-gtw: ## Bump Gateway API deps to $DEP_REF (or $DEP_VERSION). Example: make bump-gtw DEP_REF=198e6cab...
@if [ -z "${DEP_REF:-}" ] && [ -n "${DEP_VERSION:-}" ]; then DEP_REF="$DEP_VERSION"; fi; \
if [ -z "${DEP_REF:-}" ]; then \
echo "DEP_REF is not set (or DEP_VERSION). e.g. make bump-gtw DEP_REF=v1.3.0 or DEP_REF=198e6cab6774..."; \
exit 2; \
fi; \
echo "Bumping Gateway API to ${DEP_REF}"; \
hack/bump_deps.sh gtw "$DEP_REF"; \
echo "Updating licensing..."; \
$(MAKE) generate-licenses
.PHONY: bump-gie
bump-gie: ## Bump Gateway API Inference Extension to $DEP_REF (or $DEP_VERSION). Example: make bump-gie DEP_REF=198e6cab...
@if [ -z "${DEP_REF:-}" ] && [ -n "${DEP_VERSION:-}" ]; then DEP_REF="$DEP_VERSION"; fi; \
if [ -z "${DEP_REF:-}" ]; then \
echo "DEP_REF is not set (or DEP_VERSION). e.g. make bump-gie DEP_REF=v0.5.1 or DEP_REF=198e6cab6774..."; \
exit 2; \
fi; \
echo ">>> Bumping Gateway API Inference Extension to ${DEP_REF}"; \
hack/bump_deps.sh gie "$DEP_REF"; \
echo "Updating licensing..."; \
$(MAKE) generate-licenses
#----------------------------------------------------------------------------------
# Printing makefile variables utility
#----------------------------------------------------------------------------------
# use `make print-MAKEFILE_VAR` to print the value of MAKEFILE_VAR
print-% : ; @echo $($*)
```
## /controller/api/README.md
# APIs for Agentgateway Controller
This directory contains Go types for Agentgateway Controller APIs & custom resources.
## Adding a new API / CRD
These are the steps required to add a new CRD to be used in the Kubernetes Gateway integration:
1. If creating a new API version (e.g. `v1`, `v2alpha1`), create a new directory for the version and create a `doc.go` file with the `// +kubebuilder:object:generate=true` annotation, so that Go types in that directory will be converted into CRDs when codegen is run.
- The `groupName` marker specifies the API group name for the generated CRD.
- RBAC rules are defined via the `+kubebuilder:rbac` annotation (note: this annotation should not belong to the type, but rather the file or package).
2. Create a `_types.go` file in the API version directory. Following [agentgateway_parameters_types.go](/controller/api/v1alpha1/agentgateway/agentgateway_parameters_types.go) as an example:
- Define a struct for the resource (containing the metadata fields, `Spec`, and `Status`). Follow the [API guidelines](#api-guidelines) below.
- Define a struct for the resource list (containing the metadata fields and `Items`)
3. Run codegen via `make generated-code -B`. This will invoke the `controller-gen` command specified in [generate.go](/controller/hack/generate.go), which should result in the following:
- A `zz_generated.deepcopy.go` file is created in the same directory as the Go types.
- A `zz_generated.register.go` file is created in the same directory as the Go types, to help with registering the Go types with the scheme.
- CRDs are generated in the CRD helm chart template dir: [install/helm/agentgateway-crds/templates](/controller/install/helm/agentgateway-crds/templates)
- RBAC roles are generated in [controller/install/helm/templates/role.yaml](/agentgateway/install/helm/agentgateway/templates/role.yaml)
- Updates the [api/applyconfiguration](/api/applyconfiguration), [pkg/generated](/pkg/generated) and [pkg/client](/pkg/client) folders with kube clients. These are used in plugin initialization and the fake client is used in tests.
## API guidelines
- Include documentation as well as any appropriate json and kubebuilder annotations on all fields.
- Document the default value for each field, if applicable.
- For optional fields:
- Use the `+optional` marker.
- Use the `omitempty` json struct tag.
- Use pointer types (e.g. `*string`), unless the type has a nil zero value (e.g. slices/maps). An exception is if the field has a default value (`+kubebuilder:default=...`); then it it acceptable to use a non-pointer type.
- For required fields:
- Use the `+required` marker.
- Required fields MUST NOT set the `omitempty` json struct tag.
- Avoid using slices with pointers (e.g. use `[]string` instead of `[]*string`). See: https://github.com/kubernetes/code-generator/issues/166
- For time duration fields, use the `metav1.Duration` type and use CEL validation rules to ensure it is within the correct range.
### Custom validation markers
The CRD generation pipeline supports custom kubebuilder validation markers, implemented in
`controller/hack/crdgen`.
- `+kubebuilder:validation:AtLeastOneFieldSet` requires at least one field on the struct to be set.
- `+kubebuilder:validation:ExactlyOneFieldSet` requires exactly one field on the struct to be set.
- `+kubebuilder:validation:ConditionalPolicy:fields=a;b;c` requires that `conditional` is set by itself, or,
when `conditional` is unset, all listed fields are set.
- `+kubebuilder:validation:IfThenOnlyFields:if="...",fields=a;b;c,message="..."` requires that, when `if` is true,
only the listed fields may be set.
Optional arguments for `AtLeastOneFieldSet` and `ExactlyOneFieldSet`:
- `fields=a;b;c` to explicitly pick fields to count.
- `exclude=a;b` to drop fields from the counted set.
- `message="..."` to override the generated validation message.
These markers are intended for struct/type comments (`markers.DescribesType`).
### Replicating Gateway API policies in TrafficPolicy API
Gateway API policies may be replicated as a part of the TrafficPolicy API to enable policy attachment at different levels in the config hierarchy, such as at the Gateway, Gateway's listener, or route level. The following guidelines should be considered when doing so:
- When the Gateway API types are considered sufficient to meet the requirements, they can be embedded as is in the TrafficPolicy API. TrafficPolicy's `cors` is an example where the Gateway API type `HTTPCORSFilter` is embedded directly.
- When embedding the Gateway API type, it is important to consider whether the type is marked as `<gateway:experimental>`, as experimental types may introduce breaking changes and should be noted similarly in the TrafficPolicy API. It is discouraged to embed experimental types in the TrafficPolicy API. However, if there is a breaking change in the Gateway API type, it is recommended to replicate the previous version of that type into the TrafficPolicy API and not propagate the breaking change to the TrafficPolicy API.
- When the Gateway API types are not sufficient and a more advanced API is required, a new type should be created in the TrafficPolicy API instead of embedding the Gateway API type. TrafficPolicy's `retry` and `timeouts` are examples that define new types instead of reusing the `HTTPRouteRetry` and `HTTPRouteTimeouts` types from the Gateway API.
## /controller/api/annotations/agentgateway.go
```go path="/controller/api/annotations/agentgateway.go"
package annotations
// LegacyMCPServiceHTTPPath is the legacy annotation used to specify the HTTP path for the MCP service. Users should switch to MCPServiceHTTPPath.
const LegacyMCPServiceHTTPPath = "kgateway.dev/mcp-path"
// MCPServiceHTTPPath is the annotation used to specify the HTTP path for the MCP service
const MCPServiceHTTPPath = "agentgateway.dev/mcp-path"
```
## /controller/api/settings/settings.go
```go path="/controller/api/settings/settings.go"
package settings
import (
"encoding/json"
"fmt"
"strings"
"github.com/kelseyhightower/envconfig"
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
)
// DnsLookupFamily controls the DNS lookup family for all static clusters created via Backend resources.
type DnsLookupFamily string
type XdsMode string
const (
// DnsLookupFamilyV4Preferred is the default value for DnsLookupFamily.
// The DNS resolver will first perform a lookup for addresses in the IPv4 family
// and fallback to a lookup for addresses in the IPv6 family. The callback target
// will only get v6 addresses if there were no v4 addresses to return.
DnsLookupFamilyV4Preferred DnsLookupFamily = "V4_PREFERRED"
// DnsLookupFamilyV4Only is the value for DnsLookupFamily that only performs
// DNS lookups for addresses in the IPv4 family.
DnsLookupFamilyV4Only DnsLookupFamily = "V4_ONLY"
// DnsLookupFamilyV6Only is the value for DnsLookupFamily that only performs
// DNS lookups for addresses in the IPv6 family.
DnsLookupFamilyV6Only DnsLookupFamily = "V6_ONLY"
// DnsLookupFamilyAll is the value for DnsLookupFamily that performs lookups
// for both IPv4 and IPv6 families and returns all resolved addresses.
DnsLookupFamilyAll DnsLookupFamily = "ALL"
// DnsLookupFamilyAuto is the value for DnsLookupFamily that first performs
// a lookup for addresses in the IPv6 family and falls back to a lookup for
// addresses in the IPv4 family. This is semantically equivalent to a
// non-existent V6_PREFERRED option and is a legacy name that will be
// deprecated in favor of V6_PREFERRED in a future major version.
DnsLookupFamilyAuto DnsLookupFamily = "AUTO"
XdsModePlaintext XdsMode = "plaintext"
XdsModeTLS XdsMode = "tls"
XdsModeEither XdsMode = "either"
)
// Decode implements envconfig.Decoder.
func (m *DnsLookupFamily) Decode(value string) error {
mode := DnsLookupFamily(value)
switch mode {
case DnsLookupFamilyV4Preferred, DnsLookupFamilyV4Only, DnsLookupFamilyV6Only, DnsLookupFamilyAll, DnsLookupFamilyAuto:
*m = mode
return nil
default:
return fmt.Errorf("invalid DNS lookup family: %q", value)
}
}
// Decode implements envconfig.Decoder.
func (m *XdsMode) Decode(value string) error {
mode := XdsMode(strings.ToLower(value))
switch mode {
case XdsModePlaintext, XdsModeTLS, XdsModeEither:
*m = mode
return nil
case "true":
*m = XdsModeTLS
return nil
case "false":
*m = XdsModePlaintext
return nil
default:
return fmt.Errorf("invalid xDS mode: %q (supported: plaintext, tls, either)", value)
}
}
// GatewayClassParametersRefs maps GatewayClass names to ParametersReference
type GatewayClassParametersRefs map[string]*gwv1.ParametersReference
// Decode implements envconfig.Decoder
func (r *GatewayClassParametersRefs) Decode(value string) error {
if value == "" {
*r = nil
return nil
}
// First parse as a simple map to validate name is present
var simpleParsed map[string]struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Group string `json:"group,omitempty"`
Kind string `json:"kind,omitempty"`
}
if err := json.Unmarshal([]byte(value), &simpleParsed); err != nil {
return fmt.Errorf("invalid gateway class parameters refs: %w", err)
}
parsed := make(map[string]*gwv1.ParametersReference, len(simpleParsed))
for className, ref := range simpleParsed {
if strings.TrimSpace(ref.Name) == "" {
return fmt.Errorf("gateway class %q parametersRef.name must be set", className)
}
if strings.TrimSpace(ref.Namespace) == "" {
return fmt.Errorf("gateway class %q parametersRef.namespace must be set", className)
}
ns := gwv1.Namespace(ref.Namespace)
paramsRef := &gwv1.ParametersReference{
Name: ref.Name,
Namespace: &ns,
}
if ref.Group != "" {
paramsRef.Group = gwv1.Group(ref.Group)
}
if ref.Kind != "" {
paramsRef.Kind = gwv1.Kind(ref.Kind)
}
parsed[className] = paramsRef
}
*r = parsed
return nil
}
const (
// TLSSecretName is the name of the Kubernetes Secret containing the TLS certificate,
// private key, and CA certificate for xDS communication. This secret must exist in the
// agentgateway installation namespace when TLS is enabled.
TLSSecretName = "kgateway-xds-cert" //nolint:gosec // G101: This is a well-known xDS TLS secret name, not a credential
)
type Settings struct {
// Controls the DnsLookupFamily for all static clusters created via Backend resources.
// If not set, agentgateway will default to "V4_PREFERRED". Note that this is different
// from the Envoy default of "AUTO", which is effectively "V6_PREFERRED".
// Supported values are: "ALL", "AUTO", "V4_PREFERRED", "V4_ONLY", "V6_ONLY"
// Details on the behavior of these options are available on the Envoy documentation:
// https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/cluster/v3/cluster.proto#enum-config-cluster-v3-cluster-dnslookupfamily
DnsLookupFamily DnsLookupFamily `split_words:"true" default:"V4_PREFERRED"`
// Controls the listener bind address. Can be either V4 or V6
ListenerBindIpv6 bool `split_words:"true" default:"true"`
// IstioNamespace is the namespace where Istio control plane components are installed.
// Defaults to "istio-system".
IstioNamespace string `split_words:"true" default:"istio-system"`
// IstioRevision is the Istio revision of the Istio control plane.
// Defaults to "default".
IstioRevision string `split_words:"true" default:"default"`
// XdsServiceHost is the host that serves xDS config.
// It overrides xdsServiceName if set.
XdsServiceHost string `split_words:"true"`
// AdditionalXdsTLSHosts are extra DNS names or IP addresses to include in the generated xDS serving certificate.
AdditionalXdsTLSHosts []string `split_words:"true"`
// XdsServiceName is the name of the Kubernetes Service that serves xDS config.
// It is assumed to be in the agentgateway install namespace.
// Ignored if XdsServiceHost is set.
XdsServiceName string `split_words:"true" default:"agentgateway"`
// XdsAuth enables or disables xDS authentication between the data-plane and control-plane.
// By default, this is enabled.
XdsAuth bool `split_words:"true" default:"true"`
// XdsMode configures how xDS is served by the control-plane:
// - plaintext: serve only plaintext xDS
// - tls: serve only TLS xDS
// - either: serve both TLS and plaintext xDS
XdsMode XdsMode `split_words:"true" default:"plaintext"`
// AgentgatewayXdsServicePort is the port of the Kubernetes Service that serves xDS config for agentgateway.
// This is the primary xDS port and is used for TLS mode and for plaintext when mode=plaintext.
AgentgatewayXdsServicePort uint32 `split_words:"true" default:"9978"`
// NoListenersDummyPort is the port exposed on the generated Service when a Gateway has no listeners.
// This keeps the LoadBalancer provisioned and address stable across transitions to zero listeners.
NoListenersDummyPort uint16 `split_words:"true" default:"443"`
// EnableInferExt defines whether to enable/disable support for Gateway API inference extension.
// If enabled, EnableAgentgateway should also be set to true. Enabling inference extension without agentgateway
// is deprecated in v2.1 and will not be supported in v2.2.
EnableInferExt bool `split_words:"true"`
// ProxyImageRegistry is the default image registry to use for the proxy image.
ProxyImageRegistry string `split_words:"true" default:"cr.agentgateway.dev"`
// ProxyImageRepository is the default image repository to use for the proxy image.
ProxyImageRepository string `split_words:"true" default:"agentgateway"`
// ProxyImageTag is the default image tag to use for the proxy image.
ProxyImageTag *string `split_words:"true" default:""`
// LogLevel specifies the logging level (e.g., "trace", "debug", "info", "warn", "error").
// Defaults to "info" if not set.
LogLevel string `split_words:"true" default:"info"`
// JSON representation of list of metav1.LabelSelector to select namespaces considered for resource discovery.
// Defaults to an empty list which selects all namespaces.
// E.g., [{"matchExpressions":[{"key":"kubernetes.io/metadata.name","operator":"In","values":["infra"]}]},{"matchLabels":{"app":"a"}}]
DiscoveryNamespaceSelectors string `split_words:"true" default:"[]"`
// EnableBuiltinDefaultMetrics enables the default builtin controller-runtime metrics and go runtime metrics.
// Since these metrics can be numerous, it is disabled by default.
EnableBuiltinDefaultMetrics bool `split_words:"true" default:"false"`
// GlobalPolicyNamespace is the namespace where policies that can attach to resources
// in any namespace are defined.
GlobalPolicyNamespace string `split_words:"true"`
// Controls if leader election is disabled. Defaults to false.
DisableLeaderElection bool `split_words:"true" default:"false"`
// EnableExperimentalGatewayAPIFeatures enables support for experimental features and APIs
EnableExperimentalGatewayAPIFeatures bool `split_words:"true" default:"true"`
// GatewayClassParametersRefs configures the GatewayParameters references to set on the default GatewayClasses.
// Format: JSON map where keys are GatewayClass names and values are objects with "name" (required),
// "namespace" (required), "group" (optional), and "kind" (optional) fields.
// E.g., {"gateway-class-name":{"name":"params-name","namespace":"params-namespace","group":"gateway.networking.k8s.io","kind":"GatewayParameters"}}
GatewayClassParametersRefs GatewayClassParametersRefs `split_words:"true" default:"{}"`
}
// BuildSettings returns a zero-valued Settings obj if error is encountered when parsing env
func BuildSettings() (*Settings, error) {
settings := &Settings{}
if err := envconfig.Process("AGW", settings); err != nil {
return settings, err
}
return settings, nil
}
func (s *Settings) IsXdsTLSEnabled() bool {
return s.XdsMode == XdsModeTLS || s.XdsMode == XdsModeEither
}
func (s *Settings) IsXdsPlaintextEnabled() bool {
return s.XdsMode == XdsModePlaintext || s.XdsMode == XdsModeEither
}
```
## /controller/api/settings/settings_test.go
```go path="/controller/api/settings/settings_test.go"
package settings
import (
"fmt"
"os"
"reflect"
"regexp"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/require"
"k8s.io/utils/ptr"
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
)
// allEnvVarsSet returns a map which contains keys corresponding to every ENV var that can be used to configure settings,
// with values set to a non-default value.
func allEnvVarsSet() map[string]string {
return map[string]string{
"AGW_DNS_LOOKUP_FAMILY": string(DnsLookupFamilyV4Only),
"AGW_LISTENER_BIND_IPV6": "false",
"AGW_ISTIO_NAMESPACE": "my-istio-namespace",
"AGW_ISTIO_REVISION": "my-istio-revision",
"AGW_XDS_SERVICE_HOST": "my-xds-host",
"AGW_ADDITIONAL_XDS_TLS_HOSTS": "localhost,xds.example.com",
"AGW_XDS_SERVICE_NAME": "custom-svc",
"AGW_AGENTGATEWAY_XDS_SERVICE_PORT": "5678",
"AGW_NO_LISTENERS_DUMMY_PORT": "8443",
"AGW_ENABLE_INFER_EXT": "true",
"AGW_LOG_LEVEL": "debug",
"AGW_DISCOVERY_NAMESPACE_SELECTORS": `[{"matchLabels":{"app":"test"}}]`,
"AGW_ENABLE_BUILTIN_DEFAULT_METRICS": "true",
"AGW_GLOBAL_POLICY_NAMESPACE": "policy-ns",
"AGW_DISABLE_LEADER_ELECTION": "true",
"AGW_GATEWAY_CLASS_PARAMETERS_REFS": `{"kgateway":{"name":"custom-gwp","namespace":"infra"},"agentgateway":{"name":"custom-gwp-agw","namespace":"infra"}}`,
"AGW_XDS_AUTH": "false",
"AGW_XDS_MODE": "tls",
"AGW_ENABLE_EXPERIMENTAL_GATEWAY_API_FEATURES": "false",
"AGW_PROXY_IMAGE_REGISTRY": "my-registry",
"AGW_PROXY_IMAGE_REPOSITORY": "my-repo",
"AGW_PROXY_IMAGE_TAG": "my-tag",
}
}
func TestSettings(t *testing.T) {
testCases := []struct {
// name of the test case
name string
// env vars that are set at the beginning of test (and removed after test)
envVars map[string]string
// if set, then these are the expected populated settings
expectedSettings *Settings
// if set, then an error parsing the settings is expected to occur
expectedErrorStr string
}{
{
// This test will pass if a new field is added to Settings and the default value is null value for the type.
// In this case the test will still be testing that expected default values are set, though our convention is to set it explicitly.
name: "defaults to empty or default values",
envVars: map[string]string{},
expectedSettings: &Settings{
DnsLookupFamily: DnsLookupFamilyV4Preferred,
ListenerBindIpv6: true,
IstioNamespace: "istio-system",
IstioRevision: "default",
XdsServiceHost: "",
AdditionalXdsTLSHosts: nil,
XdsServiceName: "agentgateway",
AgentgatewayXdsServicePort: 9978,
NoListenersDummyPort: 443,
EnableInferExt: false,
LogLevel: "info",
DiscoveryNamespaceSelectors: "[]",
EnableBuiltinDefaultMetrics: false,
GlobalPolicyNamespace: "",
DisableLeaderElection: false,
XdsAuth: true,
XdsMode: XdsModePlaintext,
EnableExperimentalGatewayAPIFeatures: true,
GatewayClassParametersRefs: GatewayClassParametersRefs{},
ProxyImageRegistry: "cr.agentgateway.dev",
ProxyImageRepository: "agentgateway",
},
},
{
// This test will pass if a new field is added to Settings and the default value is null value for the type.
// However, a separate test will fail if a new field with a non-default value is not added to the map returned by allEnvVarsSet()
name: "all values set",
envVars: allEnvVarsSet(),
expectedSettings: &Settings{
DnsLookupFamily: DnsLookupFamilyV4Only,
ListenerBindIpv6: false,
IstioNamespace: "my-istio-namespace",
IstioRevision: "my-istio-revision",
XdsServiceHost: "my-xds-host",
AdditionalXdsTLSHosts: []string{"localhost", "xds.example.com"},
XdsServiceName: "custom-svc",
AgentgatewayXdsServicePort: 5678,
NoListenersDummyPort: 8443,
EnableInferExt: true,
LogLevel: "debug",
DiscoveryNamespaceSelectors: `[{"matchLabels":{"app":"test"}}]`,
EnableBuiltinDefaultMetrics: true,
GlobalPolicyNamespace: "policy-ns",
DisableLeaderElection: true,
XdsAuth: false,
XdsMode: XdsModeTLS,
EnableExperimentalGatewayAPIFeatures: false,
ProxyImageRegistry: "my-registry",
ProxyImageRepository: "my-repo",
ProxyImageTag: new("my-tag"),
GatewayClassParametersRefs: GatewayClassParametersRefs{
"kgateway": {
Name: "custom-gwp",
Namespace: ptr.To(gwv1.Namespace("infra")),
},
"agentgateway": {
Name: "custom-gwp-agw",
Namespace: ptr.To(gwv1.Namespace("infra")),
},
},
},
},
{
name: "errors on invalid bool",
envVars: map[string]string{
"AGW_ENABLE_INFER_EXT": "true123",
},
expectedErrorStr: "invalid syntax",
},
{
name: "errors on invalid bool",
envVars: map[string]string{
"AGW_LISTENER_BIND_IPV6": "true123",
},
expectedErrorStr: "invalid syntax",
},
{
name: "errors on invalid port",
envVars: map[string]string{
"AGW_AGENTGATEWAY_XDS_SERVICE_PORT": "a123",
},
expectedErrorStr: "invalid syntax",
},
{
name: "errors on invalid dns lookup family",
envVars: map[string]string{
"AGW_DNS_LOOKUP_FAMILY": "invalid",
},
expectedErrorStr: `invalid DNS lookup family: "invalid"`,
},
{
name: "errors on invalid gatewayclass parameters refs: missing name",
envVars: map[string]string{
"AGW_GATEWAY_CLASS_PARAMETERS_REFS": `{"kgateway":{"namespace":"missing-name"}}`,
},
expectedErrorStr: `gateway class "kgateway" parametersRef.name must be set`,
},
{
name: "errors on invalid gatewayclass parameters refs: missing namespace",
envVars: map[string]string{
"AGW_GATEWAY_CLASS_PARAMETERS_REFS": `{"kgateway":{"name":"custom-gwp"}}`,
},
expectedErrorStr: `gateway class "kgateway" parametersRef.namespace must be set`,
},
{
name: "ignores other env vars",
envVars: map[string]string{
"AGW_DOES_NOT_EXIST": "true",
"ANOTHER_VAR": "abc",
"AGW_ENABLE_ISTIO_AUTO_MTLS": "true",
},
expectedSettings: &Settings{
DnsLookupFamily: DnsLookupFamilyV4Preferred,
ListenerBindIpv6: true,
IstioNamespace: "istio-system",
IstioRevision: "default",
XdsServiceName: "agentgateway",
AgentgatewayXdsServicePort: 9978,
EnableInferExt: false,
NoListenersDummyPort: 443,
LogLevel: "info",
DiscoveryNamespaceSelectors: "[]",
EnableBuiltinDefaultMetrics: false,
GlobalPolicyNamespace: "",
DisableLeaderElection: false,
XdsAuth: true,
XdsMode: XdsModePlaintext,
EnableExperimentalGatewayAPIFeatures: true,
GatewayClassParametersRefs: GatewayClassParametersRefs{},
ProxyImageRegistry: "cr.agentgateway.dev",
ProxyImageRepository: "agentgateway",
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Cleanup(func() {
cleanupEnvVars(t, tc.envVars)
})
for k, v := range tc.envVars {
if err := os.Setenv(k, v); err != nil {
t.Fatalf("Failed to set environment variable %s=%s: %v", k, v, err)
}
}
s, err := BuildSettings()
if tc.expectedErrorStr != "" {
require.ErrorContains(t, err, tc.expectedErrorStr)
return
}
require.NoError(t, err)
diff := cmp.Diff(tc.expectedSettings, s)
require.Emptyf(t, diff, "Settings do not match expected values (-expected +got):\n%s", diff)
})
}
}
// TestEnvVarCoverage tests that all settings are tested with non-default values.
func TestEnvVarCoverage(t *testing.T) {
s := Settings{}
settingsValue := reflect.ValueOf(s)
allEnvVars := allEnvVarsSet()
// Check for the right number of env vars defined
require.Equal(t, settingsValue.NumField(), len(allEnvVars), "Number of fields in Settings does not match number of tested env vars")
// Check that each field of Settings has a corresponding env var set in the test map
// This protects against typos when adding new settings to the test map.
for envVar, defaultValue := range expectedEnvVars(settingsValue) {
require.Contains(t, allEnvVars, envVar, "Env var %s is not tested", envVar)
require.NotEqual(t, allEnvVars[envVar], defaultValue, "Env var %s is set to the default value", envVar)
}
}
// TestExpectedEnvVars tests that the expectedEnvVars function, which is used only in this test file, parses the field tags correctly to calculate the env var names.
func TestExpectedEnvVars(t *testing.T) {
validateValue := reflect.ValueOf(validateExpectedEnvs{})
expectedEnvVars := expectedEnvVars(validateValue)
require.Equal(t, len(expectedEnvVars), validateValue.NumField())
// Check that the env vars are correct
require.Contains(t, expectedEnvVars, "AGW_FIELD_ONE", "Env var KGW_FIELD_ONE is not set")
require.Equal(t, expectedEnvVars["AGW_FIELD_ONE"], "default_value_1", "Env var KGW_FIELD_ONE is not set to the default value")
require.Contains(t, expectedEnvVars, "AGW_FIELDTWO", "Env var KGW_FIELDTWO is not set")
require.Equal(t, expectedEnvVars["AGW_FIELDTWO"], "", "Env var KGW_FIELDTWO is not set to the default value")
require.Contains(t, expectedEnvVars, "ALT_FIELD_3", "Env var ALT_FIELD_3 is not set")
require.Contains(t, expectedEnvVars, "ALT_FIELD_4", "Env var ALT_FIELD_4 is not set")
require.Contains(t, expectedEnvVars, "AGW_FIELD_SSL_CONFIG", "Env var KGW_FIELD_SSL_CONFIG is not set")
require.Contains(t, expectedEnvVars, "AGW_FIELDHTTPCONFIG", "Env var KGW_FIELDHTTPCONFIG is not set")
}
func cleanupEnvVars(t *testing.T, envVars map[string]string) {
t.Helper()
for k := range envVars {
if err := os.Unsetenv(k); err != nil {
t.Errorf("Failed to unset environment variable %s: %v", k, err)
}
}
}
var (
gatherRegexp = regexp.MustCompile("([^A-Z]+|[A-Z]+[^A-Z]+|[A-Z]+)")
acronymRegexp = regexp.MustCompile("([A-Z]+)([A-Z][^A-Z]+)")
)
// expectedEnvVars returns a map of all the env vars that should be set for the given Settings value.
// The value of the map is the default value of the field.
func expectedEnvVars(settingsValue reflect.Value) map[string]any {
// This is a modified version of the code in https://github.com/kelseyhightower/envconfig/blob/7834011875d613aec60c606b52c2b0fe8949fe91/envconfig.go#L102-L128
expectedEnvVars := make(map[string]any, settingsValue.NumField())
for i := 0; i < settingsValue.NumField(); i++ {
fieldType := settingsValue.Type().Field(i)
splitWords := fieldType.Tag.Get("split_words") == "true"
envVarName := fieldType.Name
if splitWords {
words := gatherRegexp.FindAllStringSubmatch(fieldType.Name, -1)
if len(words) > 0 {
var name []string
for _, words := range words {
if m := acronymRegexp.FindStringSubmatch(words[0]); len(m) == 3 {
name = append(name, m[1], m[2])
} else {
name = append(name, words[0])
}
}
envVarName = strings.Join(name, "_")
}
}
envVarName = strings.ToUpper(envVarName)
// Always have a prefix
envVarName = fmt.Sprintf("AGW_%s", envVarName)
// If the field has an alt tag, use that as the env var name
if fieldType.Tag.Get("alt") != "" {
envVarName = fieldType.Tag.Get("alt")
}
expectedEnvVars[envVarName] = fieldType.Tag.Get("default")
}
return expectedEnvVars
}
// validateExpectedEnvs is used to validate the expectedEnvVars function.
type validateExpectedEnvs struct {
// Field with split_words:true
FieldOne string `split_words:"true" default:"default_value_1"`
// Field with split_words:false
FieldTwo string `split_words:"false"`
// Field with split_words:true and alt name
FieldThree string `split_words:"true" alt:"ALT_FIELD_3"`
// Field with split_words:false and alt name
FieldFour string `split_words:"false" alt:"ALT_FIELD_4"`
// Field with acronym and split_words:true
FieldSSLConfig string `split_words:"true"`
// Field with acronym and split_words:false
FieldHTTPConfig string `split_words:"false"`
}
```
## /controller/api/tests/agentgateway_policy_test.go
```go path="/controller/api/tests/agentgateway_policy_test.go"
package tests
import (
"fmt"
"strings"
"testing"
"istio.io/istio/pkg/test/util/assert"
"istio.io/istio/pkg/test/util/tmpl"
)
func TestAttachments(t *testing.T) {
type Attachments struct {
Gateway bool
Port bool
Listener bool
Route bool
RouteRule bool
Backend bool
SubBackend bool
}
cases := []struct {
name string
policy string
attachments Attachments
}{
{
name: "frontend",
policy: `frontend:
tcp:
keepalive: {}`,
attachments: Attachments{
Gateway: true,
Port: false,
Listener: false,
Route: false,
RouteRule: false,
Backend: false,
SubBackend: false,
},
},
{
name: "traffic",
policy: `traffic:
extProc:
backendRef:
name: ext-processor
port: 80`,
attachments: Attachments{
Gateway: true,
Port: false,
Listener: true,
Route: true,
RouteRule: true,
Backend: false,
SubBackend: false,
},
},
{
name: "backend",
policy: `backend:
tls: {}`,
attachments: Attachments{
Gateway: true,
Port: false,
Listener: true,
Route: true,
RouteRule: true,
Backend: true,
SubBackend: true,
},
},
{
name: "backend-mcp",
policy: `backend:
mcp:
authorization:
action: Allow
policy:
matchExpressions:
- "true"`,
attachments: Attachments{
Gateway: true,
Port: false,
Listener: true,
Route: true,
RouteRule: true,
Backend: true,
SubBackend: false,
},
},
}
tm := `apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayPolicy
spec:
{{if .ref}}targetRefs{{else}}targetSelectors{{end}}:
- group: {{.group}}
kind: {{.kind}}
{{with .sectionName}}sectionName: {{.}}{{end}}
{{if .ref}}
name: t1
{{else}}
matchLabels:
app: foo
{{end}}
{{.policy|nindent 2}}
`
v := NewAgentgatewayValidator(t)
for _, tt := range cases {
for _, ref := range []bool{true, false} {
sn := "ref"
if !ref {
sn = "selector"
}
t.Run(tt.name+"/"+sn, func(t *testing.T) {
eval := func(ty string, want bool) {
t.Run(strings.ReplaceAll(ty, "/", "-"), func(t *testing.T) {
p := strings.Split(ty, "/")
inp := map[string]any{
"group": p[0],
"kind": p[1],
"policy": tt.policy,
"ref": ref,
}
if len(p) > 2 {
inp["sectionName"] = p[2]
}
res := tmpl.EvaluateOrFail(t, tm, inp)
vv := v.ValidateCustomResourceYAML(res, nil)
assert.Equal(t, want, vv == nil, fmt.Sprintf("result: %v", vv))
})
}
eval("gateway.networking.k8s.io/Gateway", tt.attachments.Gateway)
//eval("gateway.networking.k8s.io/Gateway", tt.attachments.Port)
eval("gateway.networking.k8s.io/Gateway/sec1", tt.attachments.Listener)
eval("gateway.networking.k8s.io/HTTPRoute", tt.attachments.Route)
eval("gateway.networking.k8s.io/HTTPRoute/sec1", tt.attachments.RouteRule)
eval("agentgateway.dev/AgentgatewayBackend", tt.attachments.Backend)
eval("agentgateway.dev/AgentgatewayBackend/sec1", tt.attachments.SubBackend)
})
}
}
}
```
## /controller/api/tests/cel_test.go
```go path="/controller/api/tests/cel_test.go"
package tests
import (
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"
)
// Split where the '---' appears at the very beginning of a line. This will avoid
// accidentally splitting in cases where yaml resources contain nested yaml (which
// is indented).
var splitRegex = regexp.MustCompile(`(^|\n)---`)
// SplitString splits the given yaml doc if it's multipart document.
func splitString(yamlText string) []string {
out := make([]string, 0)
parts := splitRegex.Split(yamlText, -1)
for _, part := range parts {
part := strings.TrimSpace(part)
if len(part) > 0 {
out = append(out, part)
}
}
return out
}
type TestExpectation struct {
WantErr string `json:"_err,omitempty"`
}
func TestCRDs(t *testing.T) {
v := NewAgentgatewayValidator(t)
base := "testdata"
d, err := os.ReadDir(base)
if err != nil {
t.Fatal(err)
}
for _, f := range d {
t.Run(f.Name(), func(t *testing.T) {
f, err := os.ReadFile(filepath.Join("testdata", f.Name()))
if err != nil {
t.Fatal(err)
}
for _, item := range splitString(string(f)) {
obj := &unstructured.Unstructured{}
if err := yaml.Unmarshal([]byte(item), obj); err != nil {
t.Fatal(err)
}
delete(obj.Object, "_err")
t.Run(obj.GetName(), func(t *testing.T) {
want := TestExpectation{}
if err := yaml.Unmarshal([]byte(item), &want); err != nil {
t.Fatal(err)
}
res := v.ValidateCustomResource(obj)
if want.WantErr == "" {
// Want no error
if res != nil {
t.Fatalf("configuration was invalid: %v", res)
}
} else {
if res == nil {
t.Fatalf("wanted error like %q, got none", want.WantErr)
}
if !strings.Contains(res.Error(), want.WantErr) {
t.Fatalf("wanted error like %q, got %q", want.WantErr, res)
}
}
})
}
})
}
}
```
## /controller/api/tests/testdata/agentgateway_parameters_invalid.yaml
```yaml path="/controller/api/tests/testdata/agentgateway_parameters_invalid.yaml"
_err: "min' value must be less than or equal to the 'max"
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayParameters
metadata:
name: shutdown-min-gt-max
spec:
shutdown:
min: 61
max: 60
---
# min and max are required, which avoids the more confusing error
# "AgentgatewayParameters/shutdown-min-gt-max/: spec.shutdown: Invalid value:
# \"object\": no such key: min evaluating rule: The 'min' value
# must be less than or equal to the 'max' value."
_err: "AgentgatewayParameters/shutdown-min-gt-max/: spec.shutdown.min: Required value"
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayParameters
metadata:
name: shutdown-min-gt-max
spec:
shutdown:
max: 60
---
_err: "AgentgatewayParameters/shutdown-min-gt-max/: spec.shutdown.max: Required value"
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayParameters
metadata:
name: shutdown-min-gt-max
spec:
shutdown:
min: 0
---
_err: "Unsupported value"
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayParameters
metadata:
name: logging-format-invalid
spec:
logging:
format: Unknown
```
## /controller/api/tests/testdata/agentgateway_parameters_valid.yaml
```yaml path="/controller/api/tests/testdata/agentgateway_parameters_valid.yaml"
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayParameters
metadata:
name: shutdown-min-gt-max
spec:
shutdown:
max: 0
min: 0
```
## /controller/api/tests/validator.go
```go path="/controller/api/tests/validator.go"
package tests
import (
"os"
"path/filepath"
"strings"
"testing"
"istio.io/istio/pkg/config/crd"
"istio.io/istio/pkg/lazy"
"istio.io/istio/pkg/test/util/assert"
"github.com/agentgateway/agentgateway/controller/pkg/utils/fsutils"
)
var validator = lazy.New(func() (*crd.Validator, error) {
return newAgentgatewayValidator(false)
})
var validatorSkipMissing = lazy.New(func() (*crd.Validator, error) {
return newAgentgatewayValidator(true)
})
func NewAgentgatewayValidator(t *testing.T) *crd.Validator {
v, err := validator.Get()
assert.NoError(t, err)
return v
}
func NewAgentgatewayValidatorSkipMissing(t *testing.T) *crd.Validator {
v, err := validatorSkipMissing.Get()
assert.NoError(t, err)
return v
}
func newAgentgatewayValidator(skipMissing bool) (*crd.Validator, error) {
root := fsutils.GetModuleRoot()
dirs := []string{}
agentgatewayDir, err := os.ReadDir(filepath.Join(root, "controller/install/helm/agentgateway-crds/templates/"))
if err != nil {
return nil, err
}
for _, d := range agentgatewayDir {
if strings.HasSuffix(d.Name(), ".yaml") {
dirs = append(dirs, filepath.Join(root, "controller/install/helm/agentgateway-crds/templates", d.Name()))
}
}
v, err := crd.NewValidatorFromFiles(
dirs...,
)
if err != nil {
return nil, err
}
v.SkipMissing = skipMissing
return v, nil
}
```
## /crates/cel-fork/cel/README.md
../README.md
The content has been capped at 50000 tokens. The user could consider applying other filters to refine the result. The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.