From 2e39783b36a2b56f4dfd5cc3da3fc96c05cf8c89 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Apr 2025 10:59:02 -0700 Subject: [PATCH] grpc-js-xds: Implement RBAC engine --- packages/grpc-js-xds/package.json | 2 +- .../generated/envoy/config/rbac/v3/Action.ts | 63 +++ .../envoy/config/rbac/v3/Permission.ts | 198 +++++++ .../generated/envoy/config/rbac/v3/Policy.ts | 76 +++ .../envoy/config/rbac/v3/Principal.ts | 209 ++++++++ .../generated/envoy/config/rbac/v3/RBAC.ts | 335 ++++++++++++ .../type/matcher/v3/FilterStateMatcher.ts | 33 ++ .../envoy/type/matcher/v3/PathMatcher.ts | 29 ++ .../google/api/expr/v1alpha1/CheckedExpr.ts | 90 ++++ .../google/api/expr/v1alpha1/Constant.ts | 134 +++++ .../google/api/expr/v1alpha1/Decl.ts | 266 ++++++++++ .../google/api/expr/v1alpha1/Expr.ts | 493 ++++++++++++++++++ .../google/api/expr/v1alpha1/ParsedExpr.ts | 32 ++ .../google/api/expr/v1alpha1/Reference.ts | 55 ++ .../google/api/expr/v1alpha1/SourceInfo.ts | 87 ++++ .../api/expr/v1alpha1/SourcePosition.ts | 50 ++ .../google/api/expr/v1alpha1/Type.ts | 416 +++++++++++++++ .../generated/google/protobuf/FieldOptions.ts | 2 - packages/grpc-js-xds/src/generated/rbac.ts | 253 +++++++++ packages/grpc-js-xds/src/rbac.ts | 396 ++++++++++++++ packages/grpc-js-xds/src/route.ts | 41 +- packages/grpc-js-xds/test/test-rbac.ts | 376 +++++++++++++ 22 files changed, 3612 insertions(+), 24 deletions(-) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Action.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Permission.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Policy.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Principal.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/RBAC.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/FilterStateMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/PathMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/CheckedExpr.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Constant.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Decl.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Expr.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/ParsedExpr.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Reference.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourceInfo.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourcePosition.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Type.ts create mode 100644 packages/grpc-js-xds/src/generated/rbac.ts create mode 100644 packages/grpc-js-xds/src/rbac.ts create mode 100644 packages/grpc-js-xds/test/test-rbac.ts diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 80512613..1666d2aa 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run generate-types && npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.proto envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.proto envoy/extensions/clusters/aggregate/v3/cluster.proto envoy/extensions/transport_sockets/tls/v3/tls.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto envoy/extensions/load_balancing_policies/ring_hash/v3/ring_hash.proto envoy/extensions/load_balancing_policies/pick_first/v3/pick_first.proto envoy/extensions/clusters/aggregate/v3/cluster.proto envoy/extensions/transport_sockets/tls/v3/tls.proto envoy/config/rbac/v3/rbac.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto", "generate-test-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O test/generated --grpcLib @grpc/grpc-js grpc/testing/echo.proto" }, diff --git a/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Action.ts b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Action.ts new file mode 100644 index 00000000..e8af2d59 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Action.ts @@ -0,0 +1,63 @@ +// Original file: deps/envoy-api/envoy/config/rbac/v3/rbac.proto + +import type { _envoy_config_rbac_v3_RBAC_Action, _envoy_config_rbac_v3_RBAC_Action__Output } from '../../../../envoy/config/rbac/v3/RBAC'; + +/** + * Action defines the result of allowance or denial when a request matches the matcher. + */ +export interface Action { + /** + * The name indicates the policy name. + */ + 'name'?: (string); + /** + * The action to take if the matcher matches. Every action either allows or denies a request, + * and can also carry out action-specific operations. + * + * Actions: + * + * * ``ALLOW``: If the request gets matched on ALLOW, it is permitted. + * * ``DENY``: If the request gets matched on DENY, it is not permitted. + * * ``LOG``: If the request gets matched on LOG, it is permitted. Besides, the + * dynamic metadata key ``access_log_hint`` under the shared key namespace + * ``envoy.common`` will be set to the value ``true``. + * * If the request cannot get matched, it will fallback to ``DENY``. + * + * Log behavior: + * + * If the RBAC matcher contains at least one LOG action, the dynamic + * metadata key ``access_log_hint`` will be set based on if the request + * get matched on the LOG action. + */ + 'action'?: (_envoy_config_rbac_v3_RBAC_Action); +} + +/** + * Action defines the result of allowance or denial when a request matches the matcher. + */ +export interface Action__Output { + /** + * The name indicates the policy name. + */ + 'name': (string); + /** + * The action to take if the matcher matches. Every action either allows or denies a request, + * and can also carry out action-specific operations. + * + * Actions: + * + * * ``ALLOW``: If the request gets matched on ALLOW, it is permitted. + * * ``DENY``: If the request gets matched on DENY, it is not permitted. + * * ``LOG``: If the request gets matched on LOG, it is permitted. Besides, the + * dynamic metadata key ``access_log_hint`` under the shared key namespace + * ``envoy.common`` will be set to the value ``true``. + * * If the request cannot get matched, it will fallback to ``DENY``. + * + * Log behavior: + * + * If the RBAC matcher contains at least one LOG action, the dynamic + * metadata key ``access_log_hint`` will be set based on if the request + * get matched on the LOG action. + */ + 'action': (_envoy_config_rbac_v3_RBAC_Action__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Permission.ts b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Permission.ts new file mode 100644 index 00000000..94a9047b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Permission.ts @@ -0,0 +1,198 @@ +// Original file: deps/envoy-api/envoy/config/rbac/v3/rbac.proto + +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; +import type { CidrRange as _envoy_config_core_v3_CidrRange, CidrRange__Output as _envoy_config_core_v3_CidrRange__Output } from '../../../../envoy/config/core/v3/CidrRange'; +import type { MetadataMatcher as _envoy_type_matcher_v3_MetadataMatcher, MetadataMatcher__Output as _envoy_type_matcher_v3_MetadataMatcher__Output } from '../../../../envoy/type/matcher/v3/MetadataMatcher'; +import type { Permission as _envoy_config_rbac_v3_Permission, Permission__Output as _envoy_config_rbac_v3_Permission__Output } from '../../../../envoy/config/rbac/v3/Permission'; +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; +import type { PathMatcher as _envoy_type_matcher_v3_PathMatcher, PathMatcher__Output as _envoy_type_matcher_v3_PathMatcher__Output } from '../../../../envoy/type/matcher/v3/PathMatcher'; +import type { Int32Range as _envoy_type_v3_Int32Range, Int32Range__Output as _envoy_type_v3_Int32Range__Output } from '../../../../envoy/type/v3/Int32Range'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +/** + * Used in the ``and_rules`` and ``or_rules`` fields in the ``rule`` oneof. Depending on the context, + * each are applied with the associated behavior. + */ +export interface _envoy_config_rbac_v3_Permission_Set { + 'rules'?: (_envoy_config_rbac_v3_Permission)[]; +} + +/** + * Used in the ``and_rules`` and ``or_rules`` fields in the ``rule`` oneof. Depending on the context, + * each are applied with the associated behavior. + */ +export interface _envoy_config_rbac_v3_Permission_Set__Output { + 'rules': (_envoy_config_rbac_v3_Permission__Output)[]; +} + +/** + * Permission defines an action (or actions) that a principal can take. + * [#next-free-field: 14] + */ +export interface Permission { + /** + * A set of rules that all must match in order to define the action. + */ + 'and_rules'?: (_envoy_config_rbac_v3_Permission_Set | null); + /** + * A set of rules where at least one must match in order to define the action. + */ + 'or_rules'?: (_envoy_config_rbac_v3_Permission_Set | null); + /** + * When any is set, it matches any action. + */ + 'any'?: (boolean); + /** + * A header (or pseudo-header such as :path or :method) on the incoming HTTP request. Only + * available for HTTP request. + * Note: the pseudo-header :path includes the query and fragment string. Use the ``url_path`` + * field if you want to match the URL path without the query and fragment string. + */ + 'header'?: (_envoy_config_route_v3_HeaderMatcher | null); + /** + * A CIDR block that describes the destination IP. + */ + 'destination_ip'?: (_envoy_config_core_v3_CidrRange | null); + /** + * A port number that describes the destination port connecting to. + */ + 'destination_port'?: (number); + /** + * Metadata that describes additional information about the action. + */ + 'metadata'?: (_envoy_type_matcher_v3_MetadataMatcher | null); + /** + * Negates matching the provided permission. For instance, if the value of + * ``not_rule`` would match, this permission would not match. Conversely, if + * the value of ``not_rule`` would not match, this permission would match. + */ + 'not_rule'?: (_envoy_config_rbac_v3_Permission | null); + /** + * The request server from the client's connection request. This is + * typically TLS SNI. + * + * .. attention:: + * + * The behavior of this field may be affected by how Envoy is configured + * as explained below. + * + * * If the :ref:`TLS Inspector ` + * filter is not added, and if a ``FilterChainMatch`` is not defined for + * the :ref:`server name + * `, + * a TLS connection's requested SNI server name will be treated as if it + * wasn't present. + * + * * A :ref:`listener filter ` may + * overwrite a connection's requested server name within Envoy. + * + * Please refer to :ref:`this FAQ entry ` to learn to + * setup SNI. + */ + 'requested_server_name'?: (_envoy_type_matcher_v3_StringMatcher | null); + /** + * A URL path on the incoming HTTP request. Only available for HTTP. + */ + 'url_path'?: (_envoy_type_matcher_v3_PathMatcher | null); + /** + * A port number range that describes a range of destination ports connecting to. + */ + 'destination_port_range'?: (_envoy_type_v3_Int32Range | null); + /** + * Extension for configuring custom matchers for RBAC. + * [#extension-category: envoy.rbac.matchers] + */ + 'matcher'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + /** + * URI template path matching. + * [#extension-category: envoy.path.match] + */ + 'uri_template'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + 'rule'?: "and_rules"|"or_rules"|"any"|"header"|"url_path"|"destination_ip"|"destination_port"|"destination_port_range"|"metadata"|"not_rule"|"requested_server_name"|"matcher"|"uri_template"; +} + +/** + * Permission defines an action (or actions) that a principal can take. + * [#next-free-field: 14] + */ +export interface Permission__Output { + /** + * A set of rules that all must match in order to define the action. + */ + 'and_rules'?: (_envoy_config_rbac_v3_Permission_Set__Output | null); + /** + * A set of rules where at least one must match in order to define the action. + */ + 'or_rules'?: (_envoy_config_rbac_v3_Permission_Set__Output | null); + /** + * When any is set, it matches any action. + */ + 'any'?: (boolean); + /** + * A header (or pseudo-header such as :path or :method) on the incoming HTTP request. Only + * available for HTTP request. + * Note: the pseudo-header :path includes the query and fragment string. Use the ``url_path`` + * field if you want to match the URL path without the query and fragment string. + */ + 'header'?: (_envoy_config_route_v3_HeaderMatcher__Output | null); + /** + * A CIDR block that describes the destination IP. + */ + 'destination_ip'?: (_envoy_config_core_v3_CidrRange__Output | null); + /** + * A port number that describes the destination port connecting to. + */ + 'destination_port'?: (number); + /** + * Metadata that describes additional information about the action. + */ + 'metadata'?: (_envoy_type_matcher_v3_MetadataMatcher__Output | null); + /** + * Negates matching the provided permission. For instance, if the value of + * ``not_rule`` would match, this permission would not match. Conversely, if + * the value of ``not_rule`` would not match, this permission would match. + */ + 'not_rule'?: (_envoy_config_rbac_v3_Permission__Output | null); + /** + * The request server from the client's connection request. This is + * typically TLS SNI. + * + * .. attention:: + * + * The behavior of this field may be affected by how Envoy is configured + * as explained below. + * + * * If the :ref:`TLS Inspector ` + * filter is not added, and if a ``FilterChainMatch`` is not defined for + * the :ref:`server name + * `, + * a TLS connection's requested SNI server name will be treated as if it + * wasn't present. + * + * * A :ref:`listener filter ` may + * overwrite a connection's requested server name within Envoy. + * + * Please refer to :ref:`this FAQ entry ` to learn to + * setup SNI. + */ + 'requested_server_name'?: (_envoy_type_matcher_v3_StringMatcher__Output | null); + /** + * A URL path on the incoming HTTP request. Only available for HTTP. + */ + 'url_path'?: (_envoy_type_matcher_v3_PathMatcher__Output | null); + /** + * A port number range that describes a range of destination ports connecting to. + */ + 'destination_port_range'?: (_envoy_type_v3_Int32Range__Output | null); + /** + * Extension for configuring custom matchers for RBAC. + * [#extension-category: envoy.rbac.matchers] + */ + 'matcher'?: (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + /** + * URI template path matching. + * [#extension-category: envoy.path.match] + */ + 'uri_template'?: (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + 'rule'?: "and_rules"|"or_rules"|"any"|"header"|"url_path"|"destination_ip"|"destination_port"|"destination_port_range"|"metadata"|"not_rule"|"requested_server_name"|"matcher"|"uri_template"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Policy.ts b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Policy.ts new file mode 100644 index 00000000..a384fde8 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Policy.ts @@ -0,0 +1,76 @@ +// Original file: deps/envoy-api/envoy/config/rbac/v3/rbac.proto + +import type { Permission as _envoy_config_rbac_v3_Permission, Permission__Output as _envoy_config_rbac_v3_Permission__Output } from '../../../../envoy/config/rbac/v3/Permission'; +import type { Principal as _envoy_config_rbac_v3_Principal, Principal__Output as _envoy_config_rbac_v3_Principal__Output } from '../../../../envoy/config/rbac/v3/Principal'; +import type { Expr as _google_api_expr_v1alpha1_Expr, Expr__Output as _google_api_expr_v1alpha1_Expr__Output } from '../../../../google/api/expr/v1alpha1/Expr'; +import type { CheckedExpr as _google_api_expr_v1alpha1_CheckedExpr, CheckedExpr__Output as _google_api_expr_v1alpha1_CheckedExpr__Output } from '../../../../google/api/expr/v1alpha1/CheckedExpr'; + +/** + * Policy specifies a role and the principals that are assigned/denied the role. + * A policy matches if and only if at least one of its permissions match the + * action taking place AND at least one of its principals match the downstream + * AND the condition is true if specified. + */ +export interface Policy { + /** + * Required. The set of permissions that define a role. Each permission is + * matched with OR semantics. To match all actions for this policy, a single + * Permission with the ``any`` field set to true should be used. + */ + 'permissions'?: (_envoy_config_rbac_v3_Permission)[]; + /** + * Required. The set of principals that are assigned/denied the role based on + * “action”. Each principal is matched with OR semantics. To match all + * downstreams for this policy, a single Principal with the ``any`` field set to + * true should be used. + */ + 'principals'?: (_envoy_config_rbac_v3_Principal)[]; + /** + * An optional symbolic expression specifying an access control + * :ref:`condition `. The condition is combined + * with the permissions and the principals as a clause with AND semantics. + * Only be used when checked_condition is not used. + */ + 'condition'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * [#not-implemented-hide:] + * An optional symbolic expression that has been successfully type checked. + * Only be used when condition is not used. + */ + 'checked_condition'?: (_google_api_expr_v1alpha1_CheckedExpr | null); +} + +/** + * Policy specifies a role and the principals that are assigned/denied the role. + * A policy matches if and only if at least one of its permissions match the + * action taking place AND at least one of its principals match the downstream + * AND the condition is true if specified. + */ +export interface Policy__Output { + /** + * Required. The set of permissions that define a role. Each permission is + * matched with OR semantics. To match all actions for this policy, a single + * Permission with the ``any`` field set to true should be used. + */ + 'permissions': (_envoy_config_rbac_v3_Permission__Output)[]; + /** + * Required. The set of principals that are assigned/denied the role based on + * “action”. Each principal is matched with OR semantics. To match all + * downstreams for this policy, a single Principal with the ``any`` field set to + * true should be used. + */ + 'principals': (_envoy_config_rbac_v3_Principal__Output)[]; + /** + * An optional symbolic expression specifying an access control + * :ref:`condition `. The condition is combined + * with the permissions and the principals as a clause with AND semantics. + * Only be used when checked_condition is not used. + */ + 'condition': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * [#not-implemented-hide:] + * An optional symbolic expression that has been successfully type checked. + * Only be used when condition is not used. + */ + 'checked_condition': (_google_api_expr_v1alpha1_CheckedExpr__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Principal.ts b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Principal.ts new file mode 100644 index 00000000..67b25d15 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/Principal.ts @@ -0,0 +1,209 @@ +// Original file: deps/envoy-api/envoy/config/rbac/v3/rbac.proto + +import type { CidrRange as _envoy_config_core_v3_CidrRange, CidrRange__Output as _envoy_config_core_v3_CidrRange__Output } from '../../../../envoy/config/core/v3/CidrRange'; +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; +import type { MetadataMatcher as _envoy_type_matcher_v3_MetadataMatcher, MetadataMatcher__Output as _envoy_type_matcher_v3_MetadataMatcher__Output } from '../../../../envoy/type/matcher/v3/MetadataMatcher'; +import type { Principal as _envoy_config_rbac_v3_Principal, Principal__Output as _envoy_config_rbac_v3_Principal__Output } from '../../../../envoy/config/rbac/v3/Principal'; +import type { PathMatcher as _envoy_type_matcher_v3_PathMatcher, PathMatcher__Output as _envoy_type_matcher_v3_PathMatcher__Output } from '../../../../envoy/type/matcher/v3/PathMatcher'; +import type { FilterStateMatcher as _envoy_type_matcher_v3_FilterStateMatcher, FilterStateMatcher__Output as _envoy_type_matcher_v3_FilterStateMatcher__Output } from '../../../../envoy/type/matcher/v3/FilterStateMatcher'; +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; + +/** + * Authentication attributes for a downstream. + */ +export interface _envoy_config_rbac_v3_Principal_Authenticated { + /** + * The name of the principal. If set, The URI SAN or DNS SAN in that order + * is used from the certificate, otherwise the subject field is used. If + * unset, it applies to any user that is authenticated. + */ + 'principal_name'?: (_envoy_type_matcher_v3_StringMatcher | null); +} + +/** + * Authentication attributes for a downstream. + */ +export interface _envoy_config_rbac_v3_Principal_Authenticated__Output { + /** + * The name of the principal. If set, The URI SAN or DNS SAN in that order + * is used from the certificate, otherwise the subject field is used. If + * unset, it applies to any user that is authenticated. + */ + 'principal_name': (_envoy_type_matcher_v3_StringMatcher__Output | null); +} + +/** + * Used in the ``and_ids`` and ``or_ids`` fields in the ``identifier`` oneof. + * Depending on the context, each are applied with the associated behavior. + */ +export interface _envoy_config_rbac_v3_Principal_Set { + 'ids'?: (_envoy_config_rbac_v3_Principal)[]; +} + +/** + * Used in the ``and_ids`` and ``or_ids`` fields in the ``identifier`` oneof. + * Depending on the context, each are applied with the associated behavior. + */ +export interface _envoy_config_rbac_v3_Principal_Set__Output { + 'ids': (_envoy_config_rbac_v3_Principal__Output)[]; +} + +/** + * Principal defines an identity or a group of identities for a downstream + * subject. + * [#next-free-field: 13] + */ +export interface Principal { + /** + * A set of identifiers that all must match in order to define the + * downstream. + */ + 'and_ids'?: (_envoy_config_rbac_v3_Principal_Set | null); + /** + * A set of identifiers at least one must match in order to define the + * downstream. + */ + 'or_ids'?: (_envoy_config_rbac_v3_Principal_Set | null); + /** + * When any is set, it matches any downstream. + */ + 'any'?: (boolean); + /** + * Authenticated attributes that identify the downstream. + */ + 'authenticated'?: (_envoy_config_rbac_v3_Principal_Authenticated | null); + /** + * A CIDR block that describes the downstream IP. + * This address will honor proxy protocol, but will not honor XFF. + * + * This field is deprecated; either use :ref:`remote_ip + * ` for the same + * behavior, or use + * :ref:`direct_remote_ip `. + * @deprecated + */ + 'source_ip'?: (_envoy_config_core_v3_CidrRange | null); + /** + * A header (or pseudo-header such as :path or :method) on the incoming HTTP + * request. Only available for HTTP request. Note: the pseudo-header :path + * includes the query and fragment string. Use the ``url_path`` field if you + * want to match the URL path without the query and fragment string. + */ + 'header'?: (_envoy_config_route_v3_HeaderMatcher | null); + /** + * Metadata that describes additional information about the principal. + */ + 'metadata'?: (_envoy_type_matcher_v3_MetadataMatcher | null); + /** + * Negates matching the provided principal. For instance, if the value of + * ``not_id`` would match, this principal would not match. Conversely, if the + * value of ``not_id`` would not match, this principal would match. + */ + 'not_id'?: (_envoy_config_rbac_v3_Principal | null); + /** + * A URL path on the incoming HTTP request. Only available for HTTP. + */ + 'url_path'?: (_envoy_type_matcher_v3_PathMatcher | null); + /** + * A CIDR block that describes the downstream remote/origin address. + * Note: This is always the physical peer even if the + * :ref:`remote_ip ` is + * inferred from for example the x-forwarder-for header, proxy protocol, + * etc. + */ + 'direct_remote_ip'?: (_envoy_config_core_v3_CidrRange | null); + /** + * A CIDR block that describes the downstream remote/origin address. + * Note: This may not be the physical peer and could be different from the + * :ref:`direct_remote_ip + * `. E.g, if the + * remote ip is inferred from for example the x-forwarder-for header, proxy + * protocol, etc. + */ + 'remote_ip'?: (_envoy_config_core_v3_CidrRange | null); + /** + * Identifies the principal using a filter state object. + */ + 'filter_state'?: (_envoy_type_matcher_v3_FilterStateMatcher | null); + 'identifier'?: "and_ids"|"or_ids"|"any"|"authenticated"|"source_ip"|"direct_remote_ip"|"remote_ip"|"header"|"url_path"|"metadata"|"filter_state"|"not_id"; +} + +/** + * Principal defines an identity or a group of identities for a downstream + * subject. + * [#next-free-field: 13] + */ +export interface Principal__Output { + /** + * A set of identifiers that all must match in order to define the + * downstream. + */ + 'and_ids'?: (_envoy_config_rbac_v3_Principal_Set__Output | null); + /** + * A set of identifiers at least one must match in order to define the + * downstream. + */ + 'or_ids'?: (_envoy_config_rbac_v3_Principal_Set__Output | null); + /** + * When any is set, it matches any downstream. + */ + 'any'?: (boolean); + /** + * Authenticated attributes that identify the downstream. + */ + 'authenticated'?: (_envoy_config_rbac_v3_Principal_Authenticated__Output | null); + /** + * A CIDR block that describes the downstream IP. + * This address will honor proxy protocol, but will not honor XFF. + * + * This field is deprecated; either use :ref:`remote_ip + * ` for the same + * behavior, or use + * :ref:`direct_remote_ip `. + * @deprecated + */ + 'source_ip'?: (_envoy_config_core_v3_CidrRange__Output | null); + /** + * A header (or pseudo-header such as :path or :method) on the incoming HTTP + * request. Only available for HTTP request. Note: the pseudo-header :path + * includes the query and fragment string. Use the ``url_path`` field if you + * want to match the URL path without the query and fragment string. + */ + 'header'?: (_envoy_config_route_v3_HeaderMatcher__Output | null); + /** + * Metadata that describes additional information about the principal. + */ + 'metadata'?: (_envoy_type_matcher_v3_MetadataMatcher__Output | null); + /** + * Negates matching the provided principal. For instance, if the value of + * ``not_id`` would match, this principal would not match. Conversely, if the + * value of ``not_id`` would not match, this principal would match. + */ + 'not_id'?: (_envoy_config_rbac_v3_Principal__Output | null); + /** + * A URL path on the incoming HTTP request. Only available for HTTP. + */ + 'url_path'?: (_envoy_type_matcher_v3_PathMatcher__Output | null); + /** + * A CIDR block that describes the downstream remote/origin address. + * Note: This is always the physical peer even if the + * :ref:`remote_ip ` is + * inferred from for example the x-forwarder-for header, proxy protocol, + * etc. + */ + 'direct_remote_ip'?: (_envoy_config_core_v3_CidrRange__Output | null); + /** + * A CIDR block that describes the downstream remote/origin address. + * Note: This may not be the physical peer and could be different from the + * :ref:`direct_remote_ip + * `. E.g, if the + * remote ip is inferred from for example the x-forwarder-for header, proxy + * protocol, etc. + */ + 'remote_ip'?: (_envoy_config_core_v3_CidrRange__Output | null); + /** + * Identifies the principal using a filter state object. + */ + 'filter_state'?: (_envoy_type_matcher_v3_FilterStateMatcher__Output | null); + 'identifier'?: "and_ids"|"or_ids"|"any"|"authenticated"|"source_ip"|"direct_remote_ip"|"remote_ip"|"header"|"url_path"|"metadata"|"filter_state"|"not_id"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/RBAC.ts b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/RBAC.ts new file mode 100644 index 00000000..12563493 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/rbac/v3/RBAC.ts @@ -0,0 +1,335 @@ +// Original file: deps/envoy-api/envoy/config/rbac/v3/rbac.proto + +import type { Policy as _envoy_config_rbac_v3_Policy, Policy__Output as _envoy_config_rbac_v3_Policy__Output } from '../../../../envoy/config/rbac/v3/Policy'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +// Original file: deps/envoy-api/envoy/config/rbac/v3/rbac.proto + +/** + * Should we do safe-list or block-list style access control? + */ +export const _envoy_config_rbac_v3_RBAC_Action = { + /** + * The policies grant access to principals. The rest are denied. This is safe-list style + * access control. This is the default type. + */ + ALLOW: 'ALLOW', + /** + * The policies deny access to principals. The rest are allowed. This is block-list style + * access control. + */ + DENY: 'DENY', + /** + * The policies set the ``access_log_hint`` dynamic metadata key based on if requests match. + * All requests are allowed. + */ + LOG: 'LOG', +} as const; + +/** + * Should we do safe-list or block-list style access control? + */ +export type _envoy_config_rbac_v3_RBAC_Action = + /** + * The policies grant access to principals. The rest are denied. This is safe-list style + * access control. This is the default type. + */ + | 'ALLOW' + | 0 + /** + * The policies deny access to principals. The rest are allowed. This is block-list style + * access control. + */ + | 'DENY' + | 1 + /** + * The policies set the ``access_log_hint`` dynamic metadata key based on if requests match. + * All requests are allowed. + */ + | 'LOG' + | 2 + +/** + * Should we do safe-list or block-list style access control? + */ +export type _envoy_config_rbac_v3_RBAC_Action__Output = typeof _envoy_config_rbac_v3_RBAC_Action[keyof typeof _envoy_config_rbac_v3_RBAC_Action] + +// Original file: deps/envoy-api/envoy/config/rbac/v3/rbac.proto + +/** + * Deny and allow here refer to RBAC decisions, not actions. + */ +export const _envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditCondition = { + /** + * Never audit. + */ + NONE: 'NONE', + /** + * Audit when RBAC denies the request. + */ + ON_DENY: 'ON_DENY', + /** + * Audit when RBAC allows the request. + */ + ON_ALLOW: 'ON_ALLOW', + /** + * Audit whether RBAC allows or denies the request. + */ + ON_DENY_AND_ALLOW: 'ON_DENY_AND_ALLOW', +} as const; + +/** + * Deny and allow here refer to RBAC decisions, not actions. + */ +export type _envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditCondition = + /** + * Never audit. + */ + | 'NONE' + | 0 + /** + * Audit when RBAC denies the request. + */ + | 'ON_DENY' + | 1 + /** + * Audit when RBAC allows the request. + */ + | 'ON_ALLOW' + | 2 + /** + * Audit whether RBAC allows or denies the request. + */ + | 'ON_DENY_AND_ALLOW' + | 3 + +/** + * Deny and allow here refer to RBAC decisions, not actions. + */ +export type _envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditCondition__Output = typeof _envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditCondition[keyof typeof _envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditCondition] + +/** + * [#not-implemented-hide:] + */ +export interface _envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig { + /** + * Typed logger configuration. + * + * [#extension-category: envoy.rbac.audit_loggers] + */ + 'audit_logger'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + /** + * If true, when the logger is not supported, the data plane will not NACK but simply ignore it. + */ + 'is_optional'?: (boolean); +} + +/** + * [#not-implemented-hide:] + */ +export interface _envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig__Output { + /** + * Typed logger configuration. + * + * [#extension-category: envoy.rbac.audit_loggers] + */ + 'audit_logger': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + /** + * If true, when the logger is not supported, the data plane will not NACK but simply ignore it. + */ + 'is_optional': (boolean); +} + +export interface _envoy_config_rbac_v3_RBAC_AuditLoggingOptions { + /** + * Condition for the audit logging to happen. + * If this condition is met, all the audit loggers configured here will be invoked. + * + * [#not-implemented-hide:] + */ + 'audit_condition'?: (_envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditCondition); + /** + * Configurations for RBAC-based authorization audit loggers. + * + * [#not-implemented-hide:] + */ + 'logger_configs'?: (_envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig)[]; +} + +export interface _envoy_config_rbac_v3_RBAC_AuditLoggingOptions__Output { + /** + * Condition for the audit logging to happen. + * If this condition is met, all the audit loggers configured here will be invoked. + * + * [#not-implemented-hide:] + */ + 'audit_condition': (_envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditCondition__Output); + /** + * Configurations for RBAC-based authorization audit loggers. + * + * [#not-implemented-hide:] + */ + 'logger_configs': (_envoy_config_rbac_v3_RBAC_AuditLoggingOptions_AuditLoggerConfig__Output)[]; +} + +/** + * Role Based Access Control (RBAC) provides service-level and method-level access control for a + * service. Requests are allowed or denied based on the ``action`` and whether a matching policy is + * found. For instance, if the action is ALLOW and a matching policy is found the request should be + * allowed. + * + * RBAC can also be used to make access logging decisions by communicating with access loggers + * through dynamic metadata. When the action is LOG and at least one policy matches, the + * ``access_log_hint`` value in the shared key namespace 'envoy.common' is set to ``true`` indicating + * the request should be logged. + * + * Here is an example of RBAC configuration. It has two policies: + * + * * Service account ``cluster.local/ns/default/sa/admin`` has full access to the service, and so + * does "cluster.local/ns/default/sa/superuser". + * + * * Any user can read (``GET``) the service at paths with prefix ``/products``, so long as the + * destination port is either 80 or 443. + * + * .. code-block:: yaml + * + * action: ALLOW + * policies: + * "service-admin": + * permissions: + * - any: true + * principals: + * - authenticated: + * principal_name: + * exact: "cluster.local/ns/default/sa/admin" + * - authenticated: + * principal_name: + * exact: "cluster.local/ns/default/sa/superuser" + * "product-viewer": + * permissions: + * - and_rules: + * rules: + * - header: + * name: ":method" + * string_match: + * exact: "GET" + * - url_path: + * path: { prefix: "/products" } + * - or_rules: + * rules: + * - destination_port: 80 + * - destination_port: 443 + * principals: + * - any: true + */ +export interface RBAC { + /** + * The action to take if a policy matches. Every action either allows or denies a request, + * and can also carry out action-specific operations. + * + * Actions: + * + * * ``ALLOW``: Allows the request if and only if there is a policy that matches + * the request. + * * ``DENY``: Allows the request if and only if there are no policies that + * match the request. + * * ``LOG``: Allows all requests. If at least one policy matches, the dynamic + * metadata key ``access_log_hint`` is set to the value ``true`` under the shared + * key namespace ``envoy.common``. If no policies match, it is set to ``false``. + * Other actions do not modify this key. + */ + 'action'?: (_envoy_config_rbac_v3_RBAC_Action); + /** + * Maps from policy name to policy. A match occurs when at least one policy matches the request. + * The policies are evaluated in lexicographic order of the policy name. + */ + 'policies'?: ({[key: string]: _envoy_config_rbac_v3_Policy}); + /** + * Audit logging options that include the condition for audit logging to happen + * and audit logger configurations. + * + * [#not-implemented-hide:] + */ + 'audit_logging_options'?: (_envoy_config_rbac_v3_RBAC_AuditLoggingOptions | null); +} + +/** + * Role Based Access Control (RBAC) provides service-level and method-level access control for a + * service. Requests are allowed or denied based on the ``action`` and whether a matching policy is + * found. For instance, if the action is ALLOW and a matching policy is found the request should be + * allowed. + * + * RBAC can also be used to make access logging decisions by communicating with access loggers + * through dynamic metadata. When the action is LOG and at least one policy matches, the + * ``access_log_hint`` value in the shared key namespace 'envoy.common' is set to ``true`` indicating + * the request should be logged. + * + * Here is an example of RBAC configuration. It has two policies: + * + * * Service account ``cluster.local/ns/default/sa/admin`` has full access to the service, and so + * does "cluster.local/ns/default/sa/superuser". + * + * * Any user can read (``GET``) the service at paths with prefix ``/products``, so long as the + * destination port is either 80 or 443. + * + * .. code-block:: yaml + * + * action: ALLOW + * policies: + * "service-admin": + * permissions: + * - any: true + * principals: + * - authenticated: + * principal_name: + * exact: "cluster.local/ns/default/sa/admin" + * - authenticated: + * principal_name: + * exact: "cluster.local/ns/default/sa/superuser" + * "product-viewer": + * permissions: + * - and_rules: + * rules: + * - header: + * name: ":method" + * string_match: + * exact: "GET" + * - url_path: + * path: { prefix: "/products" } + * - or_rules: + * rules: + * - destination_port: 80 + * - destination_port: 443 + * principals: + * - any: true + */ +export interface RBAC__Output { + /** + * The action to take if a policy matches. Every action either allows or denies a request, + * and can also carry out action-specific operations. + * + * Actions: + * + * * ``ALLOW``: Allows the request if and only if there is a policy that matches + * the request. + * * ``DENY``: Allows the request if and only if there are no policies that + * match the request. + * * ``LOG``: Allows all requests. If at least one policy matches, the dynamic + * metadata key ``access_log_hint`` is set to the value ``true`` under the shared + * key namespace ``envoy.common``. If no policies match, it is set to ``false``. + * Other actions do not modify this key. + */ + 'action': (_envoy_config_rbac_v3_RBAC_Action__Output); + /** + * Maps from policy name to policy. A match occurs when at least one policy matches the request. + * The policies are evaluated in lexicographic order of the policy name. + */ + 'policies': ({[key: string]: _envoy_config_rbac_v3_Policy__Output}); + /** + * Audit logging options that include the condition for audit logging to happen + * and audit logger configurations. + * + * [#not-implemented-hide:] + */ + 'audit_logging_options': (_envoy_config_rbac_v3_RBAC_AuditLoggingOptions__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/FilterStateMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/FilterStateMatcher.ts new file mode 100644 index 00000000..dab35612 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/FilterStateMatcher.ts @@ -0,0 +1,33 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/filter_state.proto + +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; + +/** + * FilterStateMatcher provides a general interface for matching the filter state objects. + */ +export interface FilterStateMatcher { + /** + * The filter state key to retrieve the object. + */ + 'key'?: (string); + /** + * Matches the filter state object as a string value. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher | null); + 'matcher'?: "string_match"; +} + +/** + * FilterStateMatcher provides a general interface for matching the filter state objects. + */ +export interface FilterStateMatcher__Output { + /** + * The filter state key to retrieve the object. + */ + 'key': (string); + /** + * Matches the filter state object as a string value. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output | null); + 'matcher'?: "string_match"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/PathMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/PathMatcher.ts new file mode 100644 index 00000000..1bad5414 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/PathMatcher.ts @@ -0,0 +1,29 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/path.proto + +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; + +/** + * Specifies the way to match a path on HTTP request. + */ +export interface PathMatcher { + /** + * The ``path`` must match the URL path portion of the :path header. The query and fragment + * string (if present) are removed in the URL path portion. + * For example, the path ``/data`` will match the ``:path`` header ``/data#fragment?param=value``. + */ + 'path'?: (_envoy_type_matcher_v3_StringMatcher | null); + 'rule'?: "path"; +} + +/** + * Specifies the way to match a path on HTTP request. + */ +export interface PathMatcher__Output { + /** + * The ``path`` must match the URL path portion of the :path header. The query and fragment + * string (if present) are removed in the URL path portion. + * For example, the path ``/data`` will match the ``:path`` header ``/data#fragment?param=value``. + */ + 'path'?: (_envoy_type_matcher_v3_StringMatcher__Output | null); + 'rule'?: "path"; +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/CheckedExpr.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/CheckedExpr.ts new file mode 100644 index 00000000..4702978d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/CheckedExpr.ts @@ -0,0 +1,90 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/checked.proto + +import type { Reference as _google_api_expr_v1alpha1_Reference, Reference__Output as _google_api_expr_v1alpha1_Reference__Output } from '../../../../google/api/expr/v1alpha1/Reference'; +import type { Type as _google_api_expr_v1alpha1_Type, Type__Output as _google_api_expr_v1alpha1_Type__Output } from '../../../../google/api/expr/v1alpha1/Type'; +import type { Expr as _google_api_expr_v1alpha1_Expr, Expr__Output as _google_api_expr_v1alpha1_Expr__Output } from '../../../../google/api/expr/v1alpha1/Expr'; +import type { SourceInfo as _google_api_expr_v1alpha1_SourceInfo, SourceInfo__Output as _google_api_expr_v1alpha1_SourceInfo__Output } from '../../../../google/api/expr/v1alpha1/SourceInfo'; + +/** + * A CEL expression which has been successfully type checked. + */ +export interface CheckedExpr { + /** + * A map from expression ids to resolved references. + * + * The following entries are in this table: + * + * - An Ident or Select expression is represented here if it resolves to a + * declaration. For instance, if `a.b.c` is represented by + * `select(select(id(a), b), c)`, and `a.b` resolves to a declaration, + * while `c` is a field selection, then the reference is attached to the + * nested select expression (but not to the id or or the outer select). + * In turn, if `a` resolves to a declaration and `b.c` are field selections, + * the reference is attached to the ident expression. + * - Every Call expression has an entry here, identifying the function being + * called. + * - Every CreateStruct expression for a message has an entry, identifying + * the message. + */ + 'reference_map'?: ({[key: number]: _google_api_expr_v1alpha1_Reference}); + /** + * A map from expression ids to types. + * + * Every expression node which has a type different than DYN has a mapping + * here. If an expression has type DYN, it is omitted from this map to save + * space. + */ + 'type_map'?: ({[key: number]: _google_api_expr_v1alpha1_Type}); + /** + * The checked expression. Semantically equivalent to the parsed `expr`, but + * may have structural differences. + */ + 'expr'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * The source info derived from input that generated the parsed `expr` and + * any optimizations made during the type-checking pass. + */ + 'source_info'?: (_google_api_expr_v1alpha1_SourceInfo | null); +} + +/** + * A CEL expression which has been successfully type checked. + */ +export interface CheckedExpr__Output { + /** + * A map from expression ids to resolved references. + * + * The following entries are in this table: + * + * - An Ident or Select expression is represented here if it resolves to a + * declaration. For instance, if `a.b.c` is represented by + * `select(select(id(a), b), c)`, and `a.b` resolves to a declaration, + * while `c` is a field selection, then the reference is attached to the + * nested select expression (but not to the id or or the outer select). + * In turn, if `a` resolves to a declaration and `b.c` are field selections, + * the reference is attached to the ident expression. + * - Every Call expression has an entry here, identifying the function being + * called. + * - Every CreateStruct expression for a message has an entry, identifying + * the message. + */ + 'reference_map': ({[key: number]: _google_api_expr_v1alpha1_Reference__Output}); + /** + * A map from expression ids to types. + * + * Every expression node which has a type different than DYN has a mapping + * here. If an expression has type DYN, it is omitted from this map to save + * space. + */ + 'type_map': ({[key: number]: _google_api_expr_v1alpha1_Type__Output}); + /** + * The checked expression. Semantically equivalent to the parsed `expr`, but + * may have structural differences. + */ + 'expr': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * The source info derived from input that generated the parsed `expr` and + * any optimizations made during the type-checking pass. + */ + 'source_info': (_google_api_expr_v1alpha1_SourceInfo__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Constant.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Constant.ts new file mode 100644 index 00000000..fc876003 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Constant.ts @@ -0,0 +1,134 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/syntax.proto + +import type { NullValue as _google_protobuf_NullValue, NullValue__Output as _google_protobuf_NullValue__Output } from '../../../../google/protobuf/NullValue'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../../google/protobuf/Timestamp'; +import type { Long } from '@grpc/proto-loader'; + +/** + * Represents a primitive literal. + * + * Named 'Constant' here for backwards compatibility. + * + * This is similar as the primitives supported in the well-known type + * `google.protobuf.Value`, but richer so it can represent CEL's full range of + * primitives. + * + * Lists and structs are not included as constants as these aggregate types may + * contain [Expr][google.api.expr.v1alpha1.Expr] elements which require evaluation and are thus not constant. + * + * Examples of literals include: `"hello"`, `b'bytes'`, `1u`, `4.2`, `-2`, + * `true`, `null`. + */ +export interface Constant { + /** + * null value. + */ + 'null_value'?: (_google_protobuf_NullValue); + /** + * boolean value. + */ + 'bool_value'?: (boolean); + /** + * int64 value. + */ + 'int64_value'?: (number | string | Long); + /** + * uint64 value. + */ + 'uint64_value'?: (number | string | Long); + /** + * double value. + */ + 'double_value'?: (number | string); + /** + * string value. + */ + 'string_value'?: (string); + /** + * bytes value. + */ + 'bytes_value'?: (Buffer | Uint8Array | string); + /** + * protobuf.Duration value. + * + * Deprecated: duration is no longer considered a builtin cel type. + * @deprecated + */ + 'duration_value'?: (_google_protobuf_Duration | null); + /** + * protobuf.Timestamp value. + * + * Deprecated: timestamp is no longer considered a builtin cel type. + * @deprecated + */ + 'timestamp_value'?: (_google_protobuf_Timestamp | null); + /** + * Required. The valid constant kinds. + */ + 'constant_kind'?: "null_value"|"bool_value"|"int64_value"|"uint64_value"|"double_value"|"string_value"|"bytes_value"|"duration_value"|"timestamp_value"; +} + +/** + * Represents a primitive literal. + * + * Named 'Constant' here for backwards compatibility. + * + * This is similar as the primitives supported in the well-known type + * `google.protobuf.Value`, but richer so it can represent CEL's full range of + * primitives. + * + * Lists and structs are not included as constants as these aggregate types may + * contain [Expr][google.api.expr.v1alpha1.Expr] elements which require evaluation and are thus not constant. + * + * Examples of literals include: `"hello"`, `b'bytes'`, `1u`, `4.2`, `-2`, + * `true`, `null`. + */ +export interface Constant__Output { + /** + * null value. + */ + 'null_value'?: (_google_protobuf_NullValue__Output); + /** + * boolean value. + */ + 'bool_value'?: (boolean); + /** + * int64 value. + */ + 'int64_value'?: (string); + /** + * uint64 value. + */ + 'uint64_value'?: (string); + /** + * double value. + */ + 'double_value'?: (number); + /** + * string value. + */ + 'string_value'?: (string); + /** + * bytes value. + */ + 'bytes_value'?: (Buffer); + /** + * protobuf.Duration value. + * + * Deprecated: duration is no longer considered a builtin cel type. + * @deprecated + */ + 'duration_value'?: (_google_protobuf_Duration__Output | null); + /** + * protobuf.Timestamp value. + * + * Deprecated: timestamp is no longer considered a builtin cel type. + * @deprecated + */ + 'timestamp_value'?: (_google_protobuf_Timestamp__Output | null); + /** + * Required. The valid constant kinds. + */ + 'constant_kind'?: "null_value"|"bool_value"|"int64_value"|"uint64_value"|"double_value"|"string_value"|"bytes_value"|"duration_value"|"timestamp_value"; +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Decl.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Decl.ts new file mode 100644 index 00000000..4e7f56c2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Decl.ts @@ -0,0 +1,266 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/checked.proto + +import type { Type as _google_api_expr_v1alpha1_Type, Type__Output as _google_api_expr_v1alpha1_Type__Output } from '../../../../google/api/expr/v1alpha1/Type'; +import type { Constant as _google_api_expr_v1alpha1_Constant, Constant__Output as _google_api_expr_v1alpha1_Constant__Output } from '../../../../google/api/expr/v1alpha1/Constant'; + +/** + * Function declaration specifies one or more overloads which indicate the + * function's parameter types and return type, and may optionally specify a + * function definition in terms of CEL expressions. + * + * Functions have no observable side-effects (there may be side-effects like + * logging which are not observable from CEL). + */ +export interface _google_api_expr_v1alpha1_Decl_FunctionDecl { + /** + * Required. List of function overloads, must contain at least one overload. + */ + 'overloads'?: (_google_api_expr_v1alpha1_Decl_FunctionDecl_Overload)[]; +} + +/** + * Function declaration specifies one or more overloads which indicate the + * function's parameter types and return type, and may optionally specify a + * function definition in terms of CEL expressions. + * + * Functions have no observable side-effects (there may be side-effects like + * logging which are not observable from CEL). + */ +export interface _google_api_expr_v1alpha1_Decl_FunctionDecl__Output { + /** + * Required. List of function overloads, must contain at least one overload. + */ + 'overloads': (_google_api_expr_v1alpha1_Decl_FunctionDecl_Overload__Output)[]; +} + +/** + * Identifier declaration which specifies its type and optional `Expr` value. + * + * An identifier without a value is a declaration that must be provided at + * evaluation time. An identifier with a value should resolve to a constant, + * but may be used in conjunction with other identifiers bound at evaluation + * time. + */ +export interface _google_api_expr_v1alpha1_Decl_IdentDecl { + /** + * Required. The type of the identifier. + */ + 'type'?: (_google_api_expr_v1alpha1_Type | null); + /** + * The constant value of the identifier. If not specified, the identifier + * must be supplied at evaluation time. + */ + 'value'?: (_google_api_expr_v1alpha1_Constant | null); + /** + * Documentation string for the identifier. + */ + 'doc'?: (string); +} + +/** + * Identifier declaration which specifies its type and optional `Expr` value. + * + * An identifier without a value is a declaration that must be provided at + * evaluation time. An identifier with a value should resolve to a constant, + * but may be used in conjunction with other identifiers bound at evaluation + * time. + */ +export interface _google_api_expr_v1alpha1_Decl_IdentDecl__Output { + /** + * Required. The type of the identifier. + */ + 'type': (_google_api_expr_v1alpha1_Type__Output | null); + /** + * The constant value of the identifier. If not specified, the identifier + * must be supplied at evaluation time. + */ + 'value': (_google_api_expr_v1alpha1_Constant__Output | null); + /** + * Documentation string for the identifier. + */ + 'doc': (string); +} + +/** + * An overload indicates a function's parameter types and return type, and + * may optionally include a function body described in terms of [Expr][google.api.expr.v1alpha1.Expr] + * values. + * + * Functions overloads are declared in either a function or method + * call-style. For methods, the `params[0]` is the expected type of the + * target receiver. + * + * Overloads must have non-overlapping argument types after erasure of all + * parameterized type variables (similar as type erasure in Java). + */ +export interface _google_api_expr_v1alpha1_Decl_FunctionDecl_Overload { + /** + * Required. Globally unique overload name of the function which reflects + * the function name and argument types. + * + * This will be used by a [Reference][google.api.expr.v1alpha1.Reference] to indicate the `overload_id` that + * was resolved for the function `name`. + */ + 'overload_id'?: (string); + /** + * List of function parameter [Type][google.api.expr.v1alpha1.Type] values. + * + * Param types are disjoint after generic type parameters have been + * replaced with the type `DYN`. Since the `DYN` type is compatible with + * any other type, this means that if `A` is a type parameter, the + * function types `int` and `int` are not disjoint. Likewise, + * `map` is not disjoint from `map`. + * + * When the `result_type` of a function is a generic type param, the + * type param name also appears as the `type` of on at least one params. + */ + 'params'?: (_google_api_expr_v1alpha1_Type)[]; + /** + * The type param names associated with the function declaration. + * + * For example, `function ex(K key, map map) : V` would yield + * the type params of `K, V`. + */ + 'type_params'?: (string)[]; + /** + * Required. The result type of the function. For example, the operator + * `string.isEmpty()` would have `result_type` of `kind: BOOL`. + */ + 'result_type'?: (_google_api_expr_v1alpha1_Type | null); + /** + * Whether the function is to be used in a method call-style `x.f(...)` + * of a function call-style `f(x, ...)`. + * + * For methods, the first parameter declaration, `params[0]` is the + * expected type of the target receiver. + */ + 'is_instance_function'?: (boolean); + /** + * Documentation string for the overload. + */ + 'doc'?: (string); +} + +/** + * An overload indicates a function's parameter types and return type, and + * may optionally include a function body described in terms of [Expr][google.api.expr.v1alpha1.Expr] + * values. + * + * Functions overloads are declared in either a function or method + * call-style. For methods, the `params[0]` is the expected type of the + * target receiver. + * + * Overloads must have non-overlapping argument types after erasure of all + * parameterized type variables (similar as type erasure in Java). + */ +export interface _google_api_expr_v1alpha1_Decl_FunctionDecl_Overload__Output { + /** + * Required. Globally unique overload name of the function which reflects + * the function name and argument types. + * + * This will be used by a [Reference][google.api.expr.v1alpha1.Reference] to indicate the `overload_id` that + * was resolved for the function `name`. + */ + 'overload_id': (string); + /** + * List of function parameter [Type][google.api.expr.v1alpha1.Type] values. + * + * Param types are disjoint after generic type parameters have been + * replaced with the type `DYN`. Since the `DYN` type is compatible with + * any other type, this means that if `A` is a type parameter, the + * function types `int` and `int` are not disjoint. Likewise, + * `map` is not disjoint from `map`. + * + * When the `result_type` of a function is a generic type param, the + * type param name also appears as the `type` of on at least one params. + */ + 'params': (_google_api_expr_v1alpha1_Type__Output)[]; + /** + * The type param names associated with the function declaration. + * + * For example, `function ex(K key, map map) : V` would yield + * the type params of `K, V`. + */ + 'type_params': (string)[]; + /** + * Required. The result type of the function. For example, the operator + * `string.isEmpty()` would have `result_type` of `kind: BOOL`. + */ + 'result_type': (_google_api_expr_v1alpha1_Type__Output | null); + /** + * Whether the function is to be used in a method call-style `x.f(...)` + * of a function call-style `f(x, ...)`. + * + * For methods, the first parameter declaration, `params[0]` is the + * expected type of the target receiver. + */ + 'is_instance_function': (boolean); + /** + * Documentation string for the overload. + */ + 'doc': (string); +} + +/** + * Represents a declaration of a named value or function. + * + * A declaration is part of the contract between the expression, the agent + * evaluating that expression, and the caller requesting evaluation. + */ +export interface Decl { + /** + * The fully qualified name of the declaration. + * + * Declarations are organized in containers and this represents the full path + * to the declaration in its container, as in `google.api.expr.Decl`. + * + * Declarations used as [FunctionDecl.Overload][google.api.expr.v1alpha1.Decl.FunctionDecl.Overload] parameters may or may not + * have a name depending on whether the overload is function declaration or a + * function definition containing a result [Expr][google.api.expr.v1alpha1.Expr]. + */ + 'name'?: (string); + /** + * Identifier declaration. + */ + 'ident'?: (_google_api_expr_v1alpha1_Decl_IdentDecl | null); + /** + * Function declaration. + */ + 'function'?: (_google_api_expr_v1alpha1_Decl_FunctionDecl | null); + /** + * Required. The declaration kind. + */ + 'decl_kind'?: "ident"|"function"; +} + +/** + * Represents a declaration of a named value or function. + * + * A declaration is part of the contract between the expression, the agent + * evaluating that expression, and the caller requesting evaluation. + */ +export interface Decl__Output { + /** + * The fully qualified name of the declaration. + * + * Declarations are organized in containers and this represents the full path + * to the declaration in its container, as in `google.api.expr.Decl`. + * + * Declarations used as [FunctionDecl.Overload][google.api.expr.v1alpha1.Decl.FunctionDecl.Overload] parameters may or may not + * have a name depending on whether the overload is function declaration or a + * function definition containing a result [Expr][google.api.expr.v1alpha1.Expr]. + */ + 'name': (string); + /** + * Identifier declaration. + */ + 'ident'?: (_google_api_expr_v1alpha1_Decl_IdentDecl__Output | null); + /** + * Function declaration. + */ + 'function'?: (_google_api_expr_v1alpha1_Decl_FunctionDecl__Output | null); + /** + * Required. The declaration kind. + */ + 'decl_kind'?: "ident"|"function"; +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Expr.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Expr.ts new file mode 100644 index 00000000..2c00b10e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Expr.ts @@ -0,0 +1,493 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/syntax.proto + +import type { Constant as _google_api_expr_v1alpha1_Constant, Constant__Output as _google_api_expr_v1alpha1_Constant__Output } from '../../../../google/api/expr/v1alpha1/Constant'; +import type { Expr as _google_api_expr_v1alpha1_Expr, Expr__Output as _google_api_expr_v1alpha1_Expr__Output } from '../../../../google/api/expr/v1alpha1/Expr'; +import type { Long } from '@grpc/proto-loader'; + +/** + * A call expression, including calls to predefined functions and operators. + * + * For example, `value == 10`, `size(map_value)`. + */ +export interface _google_api_expr_v1alpha1_Expr_Call { + /** + * The target of an method call-style expression. For example, `x` in + * `x.f()`. + */ + 'target'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * Required. The name of the function or method being called. + */ + 'function'?: (string); + /** + * The arguments. + */ + 'args'?: (_google_api_expr_v1alpha1_Expr)[]; +} + +/** + * A call expression, including calls to predefined functions and operators. + * + * For example, `value == 10`, `size(map_value)`. + */ +export interface _google_api_expr_v1alpha1_Expr_Call__Output { + /** + * The target of an method call-style expression. For example, `x` in + * `x.f()`. + */ + 'target': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * Required. The name of the function or method being called. + */ + 'function': (string); + /** + * The arguments. + */ + 'args': (_google_api_expr_v1alpha1_Expr__Output)[]; +} + +/** + * A comprehension expression applied to a list or map. + * + * Comprehensions are not part of the core syntax, but enabled with macros. + * A macro matches a specific call signature within a parsed AST and replaces + * the call with an alternate AST block. Macro expansion happens at parse + * time. + * + * The following macros are supported within CEL: + * + * Aggregate type macros may be applied to all elements in a list or all keys + * in a map: + * + * * `all`, `exists`, `exists_one` - test a predicate expression against + * the inputs and return `true` if the predicate is satisfied for all, + * any, or only one value `list.all(x, x < 10)`. + * * `filter` - test a predicate expression against the inputs and return + * the subset of elements which satisfy the predicate: + * `payments.filter(p, p > 1000)`. + * * `map` - apply an expression to all elements in the input and return the + * output aggregate type: `[1, 2, 3].map(i, i * i)`. + * + * The `has(m.x)` macro tests whether the property `x` is present in struct + * `m`. The semantics of this macro depend on the type of `m`. For proto2 + * messages `has(m.x)` is defined as 'defined, but not set`. For proto3, the + * macro tests whether the property is set to its default. For map and struct + * types, the macro tests whether the property `x` is defined on `m`. + */ +export interface _google_api_expr_v1alpha1_Expr_Comprehension { + /** + * The name of the iteration variable. + */ + 'iter_var'?: (string); + /** + * The range over which var iterates. + */ + 'iter_range'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * The name of the variable used for accumulation of the result. + */ + 'accu_var'?: (string); + /** + * The initial value of the accumulator. + */ + 'accu_init'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * An expression which can contain iter_var and accu_var. + * + * Returns false when the result has been computed and may be used as + * a hint to short-circuit the remainder of the comprehension. + */ + 'loop_condition'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * An expression which can contain iter_var and accu_var. + * + * Computes the next value of accu_var. + */ + 'loop_step'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * An expression which can contain accu_var. + * + * Computes the result. + */ + 'result'?: (_google_api_expr_v1alpha1_Expr | null); +} + +/** + * A comprehension expression applied to a list or map. + * + * Comprehensions are not part of the core syntax, but enabled with macros. + * A macro matches a specific call signature within a parsed AST and replaces + * the call with an alternate AST block. Macro expansion happens at parse + * time. + * + * The following macros are supported within CEL: + * + * Aggregate type macros may be applied to all elements in a list or all keys + * in a map: + * + * * `all`, `exists`, `exists_one` - test a predicate expression against + * the inputs and return `true` if the predicate is satisfied for all, + * any, or only one value `list.all(x, x < 10)`. + * * `filter` - test a predicate expression against the inputs and return + * the subset of elements which satisfy the predicate: + * `payments.filter(p, p > 1000)`. + * * `map` - apply an expression to all elements in the input and return the + * output aggregate type: `[1, 2, 3].map(i, i * i)`. + * + * The `has(m.x)` macro tests whether the property `x` is present in struct + * `m`. The semantics of this macro depend on the type of `m`. For proto2 + * messages `has(m.x)` is defined as 'defined, but not set`. For proto3, the + * macro tests whether the property is set to its default. For map and struct + * types, the macro tests whether the property `x` is defined on `m`. + */ +export interface _google_api_expr_v1alpha1_Expr_Comprehension__Output { + /** + * The name of the iteration variable. + */ + 'iter_var': (string); + /** + * The range over which var iterates. + */ + 'iter_range': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * The name of the variable used for accumulation of the result. + */ + 'accu_var': (string); + /** + * The initial value of the accumulator. + */ + 'accu_init': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * An expression which can contain iter_var and accu_var. + * + * Returns false when the result has been computed and may be used as + * a hint to short-circuit the remainder of the comprehension. + */ + 'loop_condition': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * An expression which can contain iter_var and accu_var. + * + * Computes the next value of accu_var. + */ + 'loop_step': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * An expression which can contain accu_var. + * + * Computes the result. + */ + 'result': (_google_api_expr_v1alpha1_Expr__Output | null); +} + +/** + * A list creation expression. + * + * Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogenous, e.g. + * `dyn([1, 'hello', 2.0])` + */ +export interface _google_api_expr_v1alpha1_Expr_CreateList { + /** + * The elements part of the list. + */ + 'elements'?: (_google_api_expr_v1alpha1_Expr)[]; +} + +/** + * A list creation expression. + * + * Lists may either be homogenous, e.g. `[1, 2, 3]`, or heterogenous, e.g. + * `dyn([1, 'hello', 2.0])` + */ +export interface _google_api_expr_v1alpha1_Expr_CreateList__Output { + /** + * The elements part of the list. + */ + 'elements': (_google_api_expr_v1alpha1_Expr__Output)[]; +} + +/** + * A map or message creation expression. + * + * Maps are constructed as `{'key_name': 'value'}`. Message construction is + * similar, but prefixed with a type name and composed of field ids: + * `types.MyType{field_id: 'value'}`. + */ +export interface _google_api_expr_v1alpha1_Expr_CreateStruct { + /** + * The type name of the message to be created, empty when creating map + * literals. + */ + 'message_name'?: (string); + /** + * The entries in the creation expression. + */ + 'entries'?: (_google_api_expr_v1alpha1_Expr_CreateStruct_Entry)[]; +} + +/** + * A map or message creation expression. + * + * Maps are constructed as `{'key_name': 'value'}`. Message construction is + * similar, but prefixed with a type name and composed of field ids: + * `types.MyType{field_id: 'value'}`. + */ +export interface _google_api_expr_v1alpha1_Expr_CreateStruct__Output { + /** + * The type name of the message to be created, empty when creating map + * literals. + */ + 'message_name': (string); + /** + * The entries in the creation expression. + */ + 'entries': (_google_api_expr_v1alpha1_Expr_CreateStruct_Entry__Output)[]; +} + +/** + * Represents an entry. + */ +export interface _google_api_expr_v1alpha1_Expr_CreateStruct_Entry { + /** + * Required. An id assigned to this node by the parser which is unique + * in a given expression tree. This is used to associate type + * information and other attributes to the node. + */ + 'id'?: (number | string | Long); + /** + * The field key for a message creator statement. + */ + 'field_key'?: (string); + /** + * The key expression for a map creation statement. + */ + 'map_key'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * Required. The value assigned to the key. + */ + 'value'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * The `Entry` key kinds. + */ + 'key_kind'?: "field_key"|"map_key"; +} + +/** + * Represents an entry. + */ +export interface _google_api_expr_v1alpha1_Expr_CreateStruct_Entry__Output { + /** + * Required. An id assigned to this node by the parser which is unique + * in a given expression tree. This is used to associate type + * information and other attributes to the node. + */ + 'id': (string); + /** + * The field key for a message creator statement. + */ + 'field_key'?: (string); + /** + * The key expression for a map creation statement. + */ + 'map_key'?: (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * Required. The value assigned to the key. + */ + 'value': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * The `Entry` key kinds. + */ + 'key_kind'?: "field_key"|"map_key"; +} + +/** + * An identifier expression. e.g. `request`. + */ +export interface _google_api_expr_v1alpha1_Expr_Ident { + /** + * Required. Holds a single, unqualified identifier, possibly preceded by a + * '.'. + * + * Qualified names are represented by the [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression. + */ + 'name'?: (string); +} + +/** + * An identifier expression. e.g. `request`. + */ +export interface _google_api_expr_v1alpha1_Expr_Ident__Output { + /** + * Required. Holds a single, unqualified identifier, possibly preceded by a + * '.'. + * + * Qualified names are represented by the [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression. + */ + 'name': (string); +} + +/** + * A field selection expression. e.g. `request.auth`. + */ +export interface _google_api_expr_v1alpha1_Expr_Select { + /** + * Required. The target of the selection expression. + * + * For example, in the select expression `request.auth`, the `request` + * portion of the expression is the `operand`. + */ + 'operand'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * Required. The name of the field to select. + * + * For example, in the select expression `request.auth`, the `auth` portion + * of the expression would be the `field`. + */ + 'field'?: (string); + /** + * Whether the select is to be interpreted as a field presence test. + * + * This results from the macro `has(request.auth)`. + */ + 'test_only'?: (boolean); +} + +/** + * A field selection expression. e.g. `request.auth`. + */ +export interface _google_api_expr_v1alpha1_Expr_Select__Output { + /** + * Required. The target of the selection expression. + * + * For example, in the select expression `request.auth`, the `request` + * portion of the expression is the `operand`. + */ + 'operand': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * Required. The name of the field to select. + * + * For example, in the select expression `request.auth`, the `auth` portion + * of the expression would be the `field`. + */ + 'field': (string); + /** + * Whether the select is to be interpreted as a field presence test. + * + * This results from the macro `has(request.auth)`. + */ + 'test_only': (boolean); +} + +/** + * An abstract representation of a common expression. + * + * Expressions are abstractly represented as a collection of identifiers, + * select statements, function calls, literals, and comprehensions. All + * operators with the exception of the '.' operator are modelled as function + * calls. This makes it easy to represent new operators into the existing AST. + * + * All references within expressions must resolve to a [Decl][google.api.expr.v1alpha1.Decl] provided at + * type-check for an expression to be valid. A reference may either be a bare + * identifier `name` or a qualified identifier `google.api.name`. References + * may either refer to a value or a function declaration. + * + * For example, the expression `google.api.name.startsWith('expr')` references + * the declaration `google.api.name` within a [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression, and + * the function declaration `startsWith`. + */ +export interface Expr { + /** + * Required. An id assigned to this node by the parser which is unique in a + * given expression tree. This is used to associate type information and other + * attributes to a node in the parse tree. + */ + 'id'?: (number | string | Long); + /** + * A literal expression. + */ + 'const_expr'?: (_google_api_expr_v1alpha1_Constant | null); + /** + * An identifier expression. + */ + 'ident_expr'?: (_google_api_expr_v1alpha1_Expr_Ident | null); + /** + * A field selection expression, e.g. `request.auth`. + */ + 'select_expr'?: (_google_api_expr_v1alpha1_Expr_Select | null); + /** + * A call expression, including calls to predefined functions and operators. + */ + 'call_expr'?: (_google_api_expr_v1alpha1_Expr_Call | null); + /** + * A list creation expression. + */ + 'list_expr'?: (_google_api_expr_v1alpha1_Expr_CreateList | null); + /** + * A map or message creation expression. + */ + 'struct_expr'?: (_google_api_expr_v1alpha1_Expr_CreateStruct | null); + /** + * A comprehension expression. + */ + 'comprehension_expr'?: (_google_api_expr_v1alpha1_Expr_Comprehension | null); + /** + * Required. Variants of expressions. + */ + 'expr_kind'?: "const_expr"|"ident_expr"|"select_expr"|"call_expr"|"list_expr"|"struct_expr"|"comprehension_expr"; +} + +/** + * An abstract representation of a common expression. + * + * Expressions are abstractly represented as a collection of identifiers, + * select statements, function calls, literals, and comprehensions. All + * operators with the exception of the '.' operator are modelled as function + * calls. This makes it easy to represent new operators into the existing AST. + * + * All references within expressions must resolve to a [Decl][google.api.expr.v1alpha1.Decl] provided at + * type-check for an expression to be valid. A reference may either be a bare + * identifier `name` or a qualified identifier `google.api.name`. References + * may either refer to a value or a function declaration. + * + * For example, the expression `google.api.name.startsWith('expr')` references + * the declaration `google.api.name` within a [Expr.Select][google.api.expr.v1alpha1.Expr.Select] expression, and + * the function declaration `startsWith`. + */ +export interface Expr__Output { + /** + * Required. An id assigned to this node by the parser which is unique in a + * given expression tree. This is used to associate type information and other + * attributes to a node in the parse tree. + */ + 'id': (string); + /** + * A literal expression. + */ + 'const_expr'?: (_google_api_expr_v1alpha1_Constant__Output | null); + /** + * An identifier expression. + */ + 'ident_expr'?: (_google_api_expr_v1alpha1_Expr_Ident__Output | null); + /** + * A field selection expression, e.g. `request.auth`. + */ + 'select_expr'?: (_google_api_expr_v1alpha1_Expr_Select__Output | null); + /** + * A call expression, including calls to predefined functions and operators. + */ + 'call_expr'?: (_google_api_expr_v1alpha1_Expr_Call__Output | null); + /** + * A list creation expression. + */ + 'list_expr'?: (_google_api_expr_v1alpha1_Expr_CreateList__Output | null); + /** + * A map or message creation expression. + */ + 'struct_expr'?: (_google_api_expr_v1alpha1_Expr_CreateStruct__Output | null); + /** + * A comprehension expression. + */ + 'comprehension_expr'?: (_google_api_expr_v1alpha1_Expr_Comprehension__Output | null); + /** + * Required. Variants of expressions. + */ + 'expr_kind'?: "const_expr"|"ident_expr"|"select_expr"|"call_expr"|"list_expr"|"struct_expr"|"comprehension_expr"; +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/ParsedExpr.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/ParsedExpr.ts new file mode 100644 index 00000000..7c682279 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/ParsedExpr.ts @@ -0,0 +1,32 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/syntax.proto + +import type { Expr as _google_api_expr_v1alpha1_Expr, Expr__Output as _google_api_expr_v1alpha1_Expr__Output } from '../../../../google/api/expr/v1alpha1/Expr'; +import type { SourceInfo as _google_api_expr_v1alpha1_SourceInfo, SourceInfo__Output as _google_api_expr_v1alpha1_SourceInfo__Output } from '../../../../google/api/expr/v1alpha1/SourceInfo'; + +/** + * An expression together with source information as returned by the parser. + */ +export interface ParsedExpr { + /** + * The parsed expression. + */ + 'expr'?: (_google_api_expr_v1alpha1_Expr | null); + /** + * The source info derived from input that generated the parsed `expr`. + */ + 'source_info'?: (_google_api_expr_v1alpha1_SourceInfo | null); +} + +/** + * An expression together with source information as returned by the parser. + */ +export interface ParsedExpr__Output { + /** + * The parsed expression. + */ + 'expr': (_google_api_expr_v1alpha1_Expr__Output | null); + /** + * The source info derived from input that generated the parsed `expr`. + */ + 'source_info': (_google_api_expr_v1alpha1_SourceInfo__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Reference.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Reference.ts new file mode 100644 index 00000000..c0d1e0d8 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Reference.ts @@ -0,0 +1,55 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/checked.proto + +import type { Constant as _google_api_expr_v1alpha1_Constant, Constant__Output as _google_api_expr_v1alpha1_Constant__Output } from '../../../../google/api/expr/v1alpha1/Constant'; + +/** + * Describes a resolved reference to a declaration. + */ +export interface Reference { + /** + * The fully qualified name of the declaration. + */ + 'name'?: (string); + /** + * For references to functions, this is a list of `Overload.overload_id` + * values which match according to typing rules. + * + * If the list has more than one element, overload resolution among the + * presented candidates must happen at runtime because of dynamic types. The + * type checker attempts to narrow down this list as much as possible. + * + * Empty if this is not a reference to a [Decl.FunctionDecl][google.api.expr.v1alpha1.Decl.FunctionDecl]. + */ + 'overload_id'?: (string)[]; + /** + * For references to constants, this may contain the value of the + * constant if known at compile time. + */ + 'value'?: (_google_api_expr_v1alpha1_Constant | null); +} + +/** + * Describes a resolved reference to a declaration. + */ +export interface Reference__Output { + /** + * The fully qualified name of the declaration. + */ + 'name': (string); + /** + * For references to functions, this is a list of `Overload.overload_id` + * values which match according to typing rules. + * + * If the list has more than one element, overload resolution among the + * presented candidates must happen at runtime because of dynamic types. The + * type checker attempts to narrow down this list as much as possible. + * + * Empty if this is not a reference to a [Decl.FunctionDecl][google.api.expr.v1alpha1.Decl.FunctionDecl]. + */ + 'overload_id': (string)[]; + /** + * For references to constants, this may contain the value of the + * constant if known at compile time. + */ + 'value': (_google_api_expr_v1alpha1_Constant__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourceInfo.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourceInfo.ts new file mode 100644 index 00000000..e3aeea8d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourceInfo.ts @@ -0,0 +1,87 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/syntax.proto + +import type { Expr as _google_api_expr_v1alpha1_Expr, Expr__Output as _google_api_expr_v1alpha1_Expr__Output } from '../../../../google/api/expr/v1alpha1/Expr'; + +/** + * Source information collected at parse time. + */ +export interface SourceInfo { + /** + * The syntax version of the source, e.g. `cel1`. + */ + 'syntax_version'?: (string); + /** + * The location name. All position information attached to an expression is + * relative to this location. + * + * The location could be a file, UI element, or similar. For example, + * `acme/app/AnvilPolicy.cel`. + */ + 'location'?: (string); + /** + * Monotonically increasing list of character offsets where newlines appear. + * + * The line number of a given position is the index `i` where for a given + * `id` the `line_offsets[i] < id_positions[id] < line_offsets[i+1]`. The + * column may be derivd from `id_positions[id] - line_offsets[i]`. + */ + 'line_offsets'?: (number)[]; + /** + * A map from the parse node id (e.g. `Expr.id`) to the character offset + * within source. + */ + 'positions'?: ({[key: number]: number}); + /** + * A map from the parse node id where a macro replacement was made to the + * call `Expr` that resulted in a macro expansion. + * + * For example, `has(value.field)` is a function call that is replaced by a + * `test_only` field selection in the AST. Likewise, the call + * `list.exists(e, e > 10)` translates to a comprehension expression. The key + * in the map corresponds to the expression id of the expanded macro, and the + * value is the call `Expr` that was replaced. + */ + 'macro_calls'?: ({[key: number]: _google_api_expr_v1alpha1_Expr}); +} + +/** + * Source information collected at parse time. + */ +export interface SourceInfo__Output { + /** + * The syntax version of the source, e.g. `cel1`. + */ + 'syntax_version': (string); + /** + * The location name. All position information attached to an expression is + * relative to this location. + * + * The location could be a file, UI element, or similar. For example, + * `acme/app/AnvilPolicy.cel`. + */ + 'location': (string); + /** + * Monotonically increasing list of character offsets where newlines appear. + * + * The line number of a given position is the index `i` where for a given + * `id` the `line_offsets[i] < id_positions[id] < line_offsets[i+1]`. The + * column may be derivd from `id_positions[id] - line_offsets[i]`. + */ + 'line_offsets': (number)[]; + /** + * A map from the parse node id (e.g. `Expr.id`) to the character offset + * within source. + */ + 'positions': ({[key: number]: number}); + /** + * A map from the parse node id where a macro replacement was made to the + * call `Expr` that resulted in a macro expansion. + * + * For example, `has(value.field)` is a function call that is replaced by a + * `test_only` field selection in the AST. Likewise, the call + * `list.exists(e, e > 10)` translates to a comprehension expression. The key + * in the map corresponds to the expression id of the expanded macro, and the + * value is the call `Expr` that was replaced. + */ + 'macro_calls': ({[key: number]: _google_api_expr_v1alpha1_Expr__Output}); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourcePosition.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourcePosition.ts new file mode 100644 index 00000000..cc5ad412 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/SourcePosition.ts @@ -0,0 +1,50 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/syntax.proto + + +/** + * A specific position in source. + */ +export interface SourcePosition { + /** + * The soucre location name (e.g. file name). + */ + 'location'?: (string); + /** + * The character offset. + */ + 'offset'?: (number); + /** + * The 1-based index of the starting line in the source text + * where the issue occurs, or 0 if unknown. + */ + 'line'?: (number); + /** + * The 0-based index of the starting position within the line of source text + * where the issue occurs. Only meaningful if line is nonzero. + */ + 'column'?: (number); +} + +/** + * A specific position in source. + */ +export interface SourcePosition__Output { + /** + * The soucre location name (e.g. file name). + */ + 'location': (string); + /** + * The character offset. + */ + 'offset': (number); + /** + * The 1-based index of the starting line in the source text + * where the issue occurs, or 0 if unknown. + */ + 'line': (number); + /** + * The 0-based index of the starting position within the line of source text + * where the issue occurs. Only meaningful if line is nonzero. + */ + 'column': (number); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Type.ts b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Type.ts new file mode 100644 index 00000000..b92e4a3e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/expr/v1alpha1/Type.ts @@ -0,0 +1,416 @@ +// Original file: deps/googleapis/google/api/expr/v1alpha1/checked.proto + +import type { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../../../google/protobuf/Empty'; +import type { NullValue as _google_protobuf_NullValue, NullValue__Output as _google_protobuf_NullValue__Output } from '../../../../google/protobuf/NullValue'; +import type { Type as _google_api_expr_v1alpha1_Type, Type__Output as _google_api_expr_v1alpha1_Type__Output } from '../../../../google/api/expr/v1alpha1/Type'; + +/** + * Application defined abstract type. + */ +export interface _google_api_expr_v1alpha1_Type_AbstractType { + /** + * The fully qualified name of this abstract type. + */ + 'name'?: (string); + /** + * Parameter types for this abstract type. + */ + 'parameter_types'?: (_google_api_expr_v1alpha1_Type)[]; +} + +/** + * Application defined abstract type. + */ +export interface _google_api_expr_v1alpha1_Type_AbstractType__Output { + /** + * The fully qualified name of this abstract type. + */ + 'name': (string); + /** + * Parameter types for this abstract type. + */ + 'parameter_types': (_google_api_expr_v1alpha1_Type__Output)[]; +} + +/** + * Function type with result and arg types. + */ +export interface _google_api_expr_v1alpha1_Type_FunctionType { + /** + * Result type of the function. + */ + 'result_type'?: (_google_api_expr_v1alpha1_Type | null); + /** + * Argument types of the function. + */ + 'arg_types'?: (_google_api_expr_v1alpha1_Type)[]; +} + +/** + * Function type with result and arg types. + */ +export interface _google_api_expr_v1alpha1_Type_FunctionType__Output { + /** + * Result type of the function. + */ + 'result_type': (_google_api_expr_v1alpha1_Type__Output | null); + /** + * Argument types of the function. + */ + 'arg_types': (_google_api_expr_v1alpha1_Type__Output)[]; +} + +/** + * List type with typed elements, e.g. `list`. + */ +export interface _google_api_expr_v1alpha1_Type_ListType { + /** + * The element type. + */ + 'elem_type'?: (_google_api_expr_v1alpha1_Type | null); +} + +/** + * List type with typed elements, e.g. `list`. + */ +export interface _google_api_expr_v1alpha1_Type_ListType__Output { + /** + * The element type. + */ + 'elem_type': (_google_api_expr_v1alpha1_Type__Output | null); +} + +/** + * Map type with parameterized key and value types, e.g. `map`. + */ +export interface _google_api_expr_v1alpha1_Type_MapType { + /** + * The type of the key. + */ + 'key_type'?: (_google_api_expr_v1alpha1_Type | null); + /** + * The type of the value. + */ + 'value_type'?: (_google_api_expr_v1alpha1_Type | null); +} + +/** + * Map type with parameterized key and value types, e.g. `map`. + */ +export interface _google_api_expr_v1alpha1_Type_MapType__Output { + /** + * The type of the key. + */ + 'key_type': (_google_api_expr_v1alpha1_Type__Output | null); + /** + * The type of the value. + */ + 'value_type': (_google_api_expr_v1alpha1_Type__Output | null); +} + +// Original file: deps/googleapis/google/api/expr/v1alpha1/checked.proto + +/** + * CEL primitive types. + */ +export const _google_api_expr_v1alpha1_Type_PrimitiveType = { + /** + * Unspecified type. + */ + PRIMITIVE_TYPE_UNSPECIFIED: 'PRIMITIVE_TYPE_UNSPECIFIED', + /** + * Boolean type. + */ + BOOL: 'BOOL', + /** + * Int64 type. + * + * Proto-based integer values are widened to int64. + */ + INT64: 'INT64', + /** + * Uint64 type. + * + * Proto-based unsigned integer values are widened to uint64. + */ + UINT64: 'UINT64', + /** + * Double type. + * + * Proto-based float values are widened to double values. + */ + DOUBLE: 'DOUBLE', + /** + * String type. + */ + STRING: 'STRING', + /** + * Bytes type. + */ + BYTES: 'BYTES', +} as const; + +/** + * CEL primitive types. + */ +export type _google_api_expr_v1alpha1_Type_PrimitiveType = + /** + * Unspecified type. + */ + | 'PRIMITIVE_TYPE_UNSPECIFIED' + | 0 + /** + * Boolean type. + */ + | 'BOOL' + | 1 + /** + * Int64 type. + * + * Proto-based integer values are widened to int64. + */ + | 'INT64' + | 2 + /** + * Uint64 type. + * + * Proto-based unsigned integer values are widened to uint64. + */ + | 'UINT64' + | 3 + /** + * Double type. + * + * Proto-based float values are widened to double values. + */ + | 'DOUBLE' + | 4 + /** + * String type. + */ + | 'STRING' + | 5 + /** + * Bytes type. + */ + | 'BYTES' + | 6 + +/** + * CEL primitive types. + */ +export type _google_api_expr_v1alpha1_Type_PrimitiveType__Output = typeof _google_api_expr_v1alpha1_Type_PrimitiveType[keyof typeof _google_api_expr_v1alpha1_Type_PrimitiveType] + +// Original file: deps/googleapis/google/api/expr/v1alpha1/checked.proto + +/** + * Well-known protobuf types treated with first-class support in CEL. + */ +export const _google_api_expr_v1alpha1_Type_WellKnownType = { + /** + * Unspecified type. + */ + WELL_KNOWN_TYPE_UNSPECIFIED: 'WELL_KNOWN_TYPE_UNSPECIFIED', + /** + * Well-known protobuf.Any type. + * + * Any types are a polymorphic message type. During type-checking they are + * treated like `DYN` types, but at runtime they are resolved to a specific + * message type specified at evaluation time. + */ + ANY: 'ANY', + /** + * Well-known protobuf.Timestamp type, internally referenced as `timestamp`. + */ + TIMESTAMP: 'TIMESTAMP', + /** + * Well-known protobuf.Duration type, internally referenced as `duration`. + */ + DURATION: 'DURATION', +} as const; + +/** + * Well-known protobuf types treated with first-class support in CEL. + */ +export type _google_api_expr_v1alpha1_Type_WellKnownType = + /** + * Unspecified type. + */ + | 'WELL_KNOWN_TYPE_UNSPECIFIED' + | 0 + /** + * Well-known protobuf.Any type. + * + * Any types are a polymorphic message type. During type-checking they are + * treated like `DYN` types, but at runtime they are resolved to a specific + * message type specified at evaluation time. + */ + | 'ANY' + | 1 + /** + * Well-known protobuf.Timestamp type, internally referenced as `timestamp`. + */ + | 'TIMESTAMP' + | 2 + /** + * Well-known protobuf.Duration type, internally referenced as `duration`. + */ + | 'DURATION' + | 3 + +/** + * Well-known protobuf types treated with first-class support in CEL. + */ +export type _google_api_expr_v1alpha1_Type_WellKnownType__Output = typeof _google_api_expr_v1alpha1_Type_WellKnownType[keyof typeof _google_api_expr_v1alpha1_Type_WellKnownType] + +/** + * Represents a CEL type. + */ +export interface Type { + /** + * Dynamic type. + */ + 'dyn'?: (_google_protobuf_Empty | null); + /** + * Null value. + */ + 'null'?: (_google_protobuf_NullValue); + /** + * Primitive types: `true`, `1u`, `-2.0`, `'string'`, `b'bytes'`. + */ + 'primitive'?: (_google_api_expr_v1alpha1_Type_PrimitiveType); + /** + * Wrapper of a primitive type, e.g. `google.protobuf.Int64Value`. + */ + 'wrapper'?: (_google_api_expr_v1alpha1_Type_PrimitiveType); + /** + * Well-known protobuf type such as `google.protobuf.Timestamp`. + */ + 'well_known'?: (_google_api_expr_v1alpha1_Type_WellKnownType); + /** + * Parameterized list with elements of `list_type`, e.g. `list`. + */ + 'list_type'?: (_google_api_expr_v1alpha1_Type_ListType | null); + /** + * Parameterized map with typed keys and values. + */ + 'map_type'?: (_google_api_expr_v1alpha1_Type_MapType | null); + /** + * Function type. + */ + 'function'?: (_google_api_expr_v1alpha1_Type_FunctionType | null); + /** + * Protocol buffer message type. + * + * The `message_type` string specifies the qualified message type name. For + * example, `google.plus.Profile`. + */ + 'message_type'?: (string); + /** + * Type param type. + * + * The `type_param` string specifies the type parameter name, e.g. `list` + * would be a `list_type` whose element type was a `type_param` type + * named `E`. + */ + 'type_param'?: (string); + /** + * Type type. + * + * The `type` value specifies the target type. e.g. int is type with a + * target type of `Primitive.INT`. + */ + 'type'?: (_google_api_expr_v1alpha1_Type | null); + /** + * Error type. + * + * During type-checking if an expression is an error, its type is propagated + * as the `ERROR` type. This permits the type-checker to discover other + * errors present in the expression. + */ + 'error'?: (_google_protobuf_Empty | null); + /** + * Abstract, application defined type. + */ + 'abstract_type'?: (_google_api_expr_v1alpha1_Type_AbstractType | null); + /** + * The kind of type. + */ + 'type_kind'?: "dyn"|"null"|"primitive"|"wrapper"|"well_known"|"list_type"|"map_type"|"function"|"message_type"|"type_param"|"type"|"error"|"abstract_type"; +} + +/** + * Represents a CEL type. + */ +export interface Type__Output { + /** + * Dynamic type. + */ + 'dyn'?: (_google_protobuf_Empty__Output | null); + /** + * Null value. + */ + 'null'?: (_google_protobuf_NullValue__Output); + /** + * Primitive types: `true`, `1u`, `-2.0`, `'string'`, `b'bytes'`. + */ + 'primitive'?: (_google_api_expr_v1alpha1_Type_PrimitiveType__Output); + /** + * Wrapper of a primitive type, e.g. `google.protobuf.Int64Value`. + */ + 'wrapper'?: (_google_api_expr_v1alpha1_Type_PrimitiveType__Output); + /** + * Well-known protobuf type such as `google.protobuf.Timestamp`. + */ + 'well_known'?: (_google_api_expr_v1alpha1_Type_WellKnownType__Output); + /** + * Parameterized list with elements of `list_type`, e.g. `list`. + */ + 'list_type'?: (_google_api_expr_v1alpha1_Type_ListType__Output | null); + /** + * Parameterized map with typed keys and values. + */ + 'map_type'?: (_google_api_expr_v1alpha1_Type_MapType__Output | null); + /** + * Function type. + */ + 'function'?: (_google_api_expr_v1alpha1_Type_FunctionType__Output | null); + /** + * Protocol buffer message type. + * + * The `message_type` string specifies the qualified message type name. For + * example, `google.plus.Profile`. + */ + 'message_type'?: (string); + /** + * Type param type. + * + * The `type_param` string specifies the type parameter name, e.g. `list` + * would be a `list_type` whose element type was a `type_param` type + * named `E`. + */ + 'type_param'?: (string); + /** + * Type type. + * + * The `type` value specifies the target type. e.g. int is type with a + * target type of `Primitive.INT`. + */ + 'type'?: (_google_api_expr_v1alpha1_Type__Output | null); + /** + * Error type. + * + * During type-checking if an expression is an error, its type is propagated + * as the `ERROR` type. This permits the type-checker to discover other + * errors present in the expression. + */ + 'error'?: (_google_protobuf_Empty__Output | null); + /** + * Abstract, application defined type. + */ + 'abstract_type'?: (_google_api_expr_v1alpha1_Type_AbstractType__Output | null); + /** + * The kind of type. + */ + 'type_kind'?: "dyn"|"null"|"primitive"|"wrapper"|"well_known"|"list_type"|"map_type"|"function"|"message_type"|"type_param"|"type"|"error"|"abstract_type"; +} diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index d8f1a7f0..52afce9b 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -50,7 +50,6 @@ export interface FieldOptions { 'weak'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.rules'?: (_validate_FieldRules | null); - '.udpa.annotations.sensitive'?: (boolean); '.envoy.annotations.deprecated_at_minor_version'?: (string); '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation | null); '.envoy.annotations.disallowed_by_default'?: (boolean); @@ -66,7 +65,6 @@ export interface FieldOptions__Output { 'weak': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.rules': (_validate_FieldRules__Output | null); - '.udpa.annotations.sensitive': (boolean); '.envoy.annotations.deprecated_at_minor_version': (string); '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output | null); '.envoy.annotations.disallowed_by_default': (boolean); diff --git a/packages/grpc-js-xds/src/generated/rbac.ts b/packages/grpc-js-xds/src/generated/rbac.ts new file mode 100644 index 00000000..bc2ed797 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/rbac.ts @@ -0,0 +1,253 @@ +import type * as grpc from '@grpc/grpc-js'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + envoy: { + annotations: { + } + config: { + core: { + v3: { + Address: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition + Extension: MessageTypeDefinition + ExtraSourceAddress: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + KeyValue: MessageTypeDefinition + KeyValueAppend: MessageTypeDefinition + KeyValueMutation: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + ProxyProtocolConfig: MessageTypeDefinition + ProxyProtocolPassThroughTLVs: MessageTypeDefinition + QueryParameter: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + SocketOptionsOverride: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition + } + } + rbac: { + v3: { + Action: MessageTypeDefinition + Permission: MessageTypeDefinition + Policy: MessageTypeDefinition + Principal: MessageTypeDefinition + RBAC: MessageTypeDefinition + } + } + route: { + v3: { + ClusterSpecifierPlugin: MessageTypeDefinition + CorsPolicy: MessageTypeDefinition + Decorator: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + FilterAction: MessageTypeDefinition + FilterConfig: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition + HedgePolicy: MessageTypeDefinition + InternalRedirectPolicy: MessageTypeDefinition + NonForwardingAction: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + RateLimit: MessageTypeDefinition + RedirectAction: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + Route: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RouteList: MessageTypeDefinition + RouteMatch: MessageTypeDefinition + Tracing: MessageTypeDefinition + VirtualCluster: MessageTypeDefinition + VirtualHost: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition + } + } + } + type: { + matcher: { + v3: { + DoubleMatcher: MessageTypeDefinition + FilterStateMatcher: MessageTypeDefinition + ListMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + MetadataMatcher: MessageTypeDefinition + OrMatcher: MessageTypeDefinition + PathMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + ValueMatcher: MessageTypeDefinition + } + } + metadata: { + v3: { + MetadataKey: MessageTypeDefinition + MetadataKind: MessageTypeDefinition + } + } + tracing: { + v3: { + CustomTag: MessageTypeDefinition + } + } + v3: { + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } + } + } + google: { + api: { + expr: { + v1alpha1: { + CheckedExpr: MessageTypeDefinition + Constant: MessageTypeDefinition + Decl: MessageTypeDefinition + Expr: MessageTypeDefinition + ParsedExpr: MessageTypeDefinition + Reference: MessageTypeDefinition + SourceInfo: MessageTypeDefinition + SourcePosition: MessageTypeDefinition + Type: MessageTypeDefinition + } + } + } + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } + xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + core: { + v3: { + ContextParams: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition + } + } + type: { + matcher: { + v3: { + ListStringMatcher: MessageTypeDefinition + Matcher: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + } + } + } + } +} + diff --git a/packages/grpc-js-xds/src/rbac.ts b/packages/grpc-js-xds/src/rbac.ts new file mode 100644 index 00000000..89b95db3 --- /dev/null +++ b/packages/grpc-js-xds/src/rbac.ts @@ -0,0 +1,396 @@ +/* + * Copyright 2025 gRPC 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. + */ + +import { Metadata } from "@grpc/grpc-js"; +import { Matcher, ValueMatcher } from "./matcher"; +import { CidrRange, cidrRangeMessageToCidrRange, inCidrRange } from "./cidr"; +import { PeerCertificate } from "tls"; +import { RBAC__Output } from "./generated/envoy/config/rbac/v3/RBAC"; +import { Policy__Output } from "./generated/envoy/config/rbac/v3/Policy"; +import { Permission__Output } from "./generated/envoy/config/rbac/v3/Permission"; +import { Principal__Output } from "./generated/envoy/config/rbac/v3/Principal"; +import { getPredicateForHeaderMatcher, getPredicateForStringMatcher } from "./route"; + +export interface RbacRule { + apply(info: InfoType): boolean; + toString(): string; +} + +export class AndRules implements RbacRule { + constructor(private childRules: RbacRule[]) {} + + apply(info: InfoType) { + return this.childRules.every(rule => rule.apply(info)); + } + + toString(): string { + return `And(${this.childRules.map(rule => rule.toString())})`; + } +} + +export class OrRules implements RbacRule { + constructor(private childRules: RbacRule[]) {} + + apply(info: InfoType) { + return this.childRules.some(rule => rule.apply(info)); + } + + toString(): string { + return `Or(${this.childRules.map(rule => rule.toString())})`; + } +} + +export class NotRule implements RbacRule { + constructor(private childRule: RbacRule) {} + + apply(info: InfoType) { + return !this.childRule.apply(info); + } + + toString(): string { + return `Not(${this.childRule.toString()})`; + } +} + +export class AnyRule implements RbacRule { + constructor() {} + + apply(info: InfoType) { + return true; + } + + toString(): string { + return `Any()`; + } +} + +export class NoneRule implements RbacRule { + constructor() {} + + apply(info: InfoType) { + return false; + } + + toString(): string { + return `None()`; + } +} + +export interface PermissionInfo { + headers: Metadata; + urlPath: string; + destinationIp: string; + destinationPort: number; +} + +export type PermissionRule = RbacRule; + +export class HeaderPermission implements PermissionRule { + constructor(private matcher: Matcher) {} + + apply(info: PermissionInfo) { + return this.matcher.apply(info.urlPath, info.headers); + } + + toString(): string { + return `Header(${this.matcher.toString()})`; + } +} + +export class UrlPathPermission implements PermissionRule { + constructor(private matcher: ValueMatcher) {} + + apply(info: PermissionInfo): boolean { + return this.matcher.apply(info.urlPath); + } + + toString(): string { + return `UrlPath(${this.matcher.toString()})`; + } +} + +export class DestinationIpPermission implements PermissionRule { + constructor(private cidrRange: CidrRange) {} + + apply(info: PermissionInfo): boolean { + return inCidrRange(this.cidrRange, info.destinationIp); + } + + toString(): string { + return `DestinationIp(${this.cidrRange.addressPrefix}/${this.cidrRange.prefixLen})`; + } +} + +export class DestinationPortPermission implements PermissionRule { + constructor(private port: number) {} + + apply(info: PermissionInfo): boolean { + return info.destinationPort === this.port; + } + toString(): string { + return `DestinationPort(${this.port})`; + } +} + +export class MetadataPermission implements PermissionRule { + constructor() {} + + apply(info: PermissionInfo): boolean { + return false; + } + toString(): string { + return `Metadata()`; + } +} + +export class RequestedServerNamePermission implements PermissionRule { + constructor(private matcher: ValueMatcher) {} + + apply(info: PermissionInfo): boolean { + return this.matcher.apply(''); + } + toString(): string { + return `RequestedServerName(${this.matcher.toString()})`; + } +} + +export type BasicPeerCertificate = Pick; + +export interface PrincipalInfo { + tls: boolean; + peerCertificate: BasicPeerCertificate | null; + sourceIp: string; + headers: Metadata; + urlPath: string; +} + +export type PrincipalRule = RbacRule; + +interface SanEntry { + type: string; + value: string; +} + +function splitSanEntry(entry: string): SanEntry | null { + const colonIndex = entry.indexOf(':'); + if (colonIndex < 0) { + return null; + } + return { + type: entry.substring(0, colonIndex), + value: entry.substring(colonIndex + 1) + } +} + +export class AuthenticatedPrincipal implements PrincipalRule { + constructor(private nameMatcher: ValueMatcher | null) {} + + apply(info: PrincipalInfo): boolean { + if (this.nameMatcher === null) { + return info.tls; + } + if (!info.peerCertificate) { + return this.nameMatcher.apply(''); + } + if (info.peerCertificate.subjectaltname) { + const sanEntries = info.peerCertificate.subjectaltname.split(', ').map(splitSanEntry).filter(x => x !== null); + if (sanEntries.some(entry => entry.type === 'URI')) { + for (const entry of sanEntries) { + if (entry.type === 'URI') { + if (this.nameMatcher.apply(entry.value)) { + return true; + } + } + } + } else if (sanEntries.some(entry => entry.type === 'DNS')) { + for (const entry of sanEntries) { + if (entry.type === 'DNS') { + if (this.nameMatcher.apply(entry.value)) { + return true; + } + } + } + } + } + return this.nameMatcher.apply(info.peerCertificate.subject.CN); + } + toString(): string { + return `Authenticated(principal=${this.nameMatcher?.toString() ?? null})`; + } +} + +export class SourceIpPrincipal implements PrincipalRule { + constructor(private cidrRange: CidrRange) {} + + apply(info: PrincipalInfo): boolean { + return inCidrRange(this.cidrRange, info.sourceIp); + } + toString(): string { + return `SourceIp(${this.cidrRange.addressPrefix}/${this.cidrRange.prefixLen})`; + } +} + +export class HeaderPrincipal implements PrincipalRule { + constructor(private matcher: Matcher) {} + + apply(info: PrincipalInfo) { + return this.matcher.apply(info.urlPath, info.headers); + } + + toString(): string { + return `Header(${this.matcher.toString()})`; + } +} + +export class UrlPathPrincipal implements PrincipalRule { + constructor(private matcher: ValueMatcher) {} + + apply(info: PrincipalInfo): boolean { + return this.matcher.apply(info.urlPath); + } + + toString(): string { + return `UrlPath(${this.matcher.toString()})`; + } +} + +export class MetadataPrincipal implements PrincipalRule { + constructor() {} + + apply(info: PrincipalInfo): boolean { + return false; + } + toString(): string { + return `Metadata()`; + } +} + +export type RbacAction = 'ALLOW' | 'DENY'; + +export interface UnifiedInfo extends PermissionInfo, PrincipalInfo {} + +export class RbacPolicy { + private permission: PermissionRule; + private principal: PrincipalRule; + + constructor(permissions: PermissionRule[], principals: PrincipalRule[]) { + this.permission = new OrRules(permissions); + this.principal = new OrRules(principals); + } + + matches(info: UnifiedInfo) { + return this.principal.apply(info) && this.permission.apply(info); + } + + toString() { + return `principal=${this.principal.toString()} permission=${this.permission.toString()}`; + } +} + +export class RbacPolicyGroup { + constructor(private policies: Map, private action: RbacAction) {} + + apply(info: UnifiedInfo): RbacAction | null { + for (const policy of this.policies.values()) { + if (policy.matches(info)) { + return this.action; + } + } + return null; + } + + toString() { + const policyStrings: string[] = []; + for (const [name, policy] of this.policies) { + policyStrings.push(`${name}: ${policy.toString()}`); + } + return `RBAC + action=${this.action} + policies: + ${policyStrings.join('\n')}`; + } +} + +export function parsePermission(permission: Permission__Output): PermissionRule { + switch (permission.rule) { + case 'and_rules': + return new AndRules(permission.and_rules!.rules.map(parsePermission)); + case 'or_rules': + return new OrRules(permission.or_rules!.rules.map(parsePermission)); + case 'not_rule': + return new NotRule(parsePermission(permission.not_rule!)); + case 'any': + return new AnyRule(); + case 'destination_ip': + return new DestinationIpPermission(cidrRangeMessageToCidrRange(permission.destination_ip!)); + case 'destination_port': + return new DestinationPortPermission(permission.destination_port!); + case 'header': + return new HeaderPermission(getPredicateForHeaderMatcher(permission.header!)); + case 'metadata': + return new MetadataPermission(); + case 'requested_server_name': + return new RequestedServerNamePermission(getPredicateForStringMatcher(permission.requested_server_name!)); + case 'url_path': + return new UrlPathPermission(getPredicateForStringMatcher(permission.url_path!.path!)); + default: + return new NoneRule(); + } +} + +export function parsePrincipal(principal: Principal__Output): PrincipalRule { + switch (principal.identifier) { + case 'and_ids': + return new AndRules(principal.and_ids!.ids.map(parsePrincipal)); + case 'or_ids': + return new OrRules(principal.or_ids!.ids.map(parsePrincipal)); + case 'not_id': + return new NotRule(parsePrincipal(principal.not_id!)); + case 'any': + return new AnyRule(); + case 'authenticated': + return new AuthenticatedPrincipal(principal.authenticated?.principal_name ? getPredicateForStringMatcher(principal.authenticated.principal_name) : null); + case 'direct_remote_ip': + return new SourceIpPrincipal(cidrRangeMessageToCidrRange(principal.direct_remote_ip!)); + case 'remote_ip': + return new SourceIpPrincipal(cidrRangeMessageToCidrRange(principal.remote_ip!)); + case 'source_ip': + return new SourceIpPrincipal(cidrRangeMessageToCidrRange(principal.source_ip!)); + case 'header': + return new HeaderPrincipal(getPredicateForHeaderMatcher(principal.header!)); + case 'metadata': + return new MetadataPrincipal(); + case 'url_path': + return new UrlPathPrincipal(getPredicateForStringMatcher(principal.url_path!.path!)); + default: + return new NoneRule(); + } +} + +export function parsePolicy(policy: Policy__Output): RbacPolicy { + return new RbacPolicy(policy.permissions.map(parsePermission), policy.principals.map(parsePrincipal)); +} + +export function parseConfig(rbac: RBAC__Output): RbacPolicyGroup { + if (rbac.action === 'LOG') { + throw new Error('Invalid RBAC action LOG'); + } + const policyMap = new Map(); + for (const [name, policyConfig] of Object.entries(rbac.policies)) { + policyMap.set(name, parsePolicy(policyConfig)); + } + return new RbacPolicyGroup(policyMap, rbac.action); +} diff --git a/packages/grpc-js-xds/src/route.ts b/packages/grpc-js-xds/src/route.ts index 38d23632..ae606f29 100644 --- a/packages/grpc-js-xds/src/route.ts +++ b/packages/grpc-js-xds/src/route.ts @@ -18,8 +18,26 @@ import { RouteMatch__Output } from './generated/envoy/config/route/v3/RouteMatch import { HeaderMatcher__Output } from './generated/envoy/config/route/v3/HeaderMatcher'; import { ContainsValueMatcher, ExactValueMatcher, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; import { envoyFractionToFraction, Fraction } from "./fraction"; +import { StringMatcher__Output } from './generated/envoy/type/matcher/v3/StringMatcher'; -function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Matcher { +export function getPredicateForStringMatcher(stringMatch: StringMatcher__Output): ValueMatcher { + switch (stringMatch.match_pattern) { + case 'exact': + return new ExactValueMatcher(stringMatch.exact!, stringMatch.ignore_case); + case 'safe_regex': + return new SafeRegexValueMatcher(stringMatch.safe_regex!.regex); + case 'prefix': + return new PrefixValueMatcher(stringMatch.prefix!, stringMatch.ignore_case); + case 'suffix': + return new SuffixValueMatcher(stringMatch.suffix!, stringMatch.ignore_case); + case 'contains': + return new ContainsValueMatcher(stringMatch.contains!, stringMatch.ignore_case); + default: + return new RejectValueMatcher(); + } +} + +export function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Matcher { let valueChecker: ValueMatcher; switch (headerMatch.header_match_specifier) { case 'exact_match': @@ -43,26 +61,7 @@ function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Match valueChecker = new SuffixValueMatcher(headerMatch.suffix_match!, false); break; case 'string_match': - const stringMatch = headerMatch.string_match!; - switch (stringMatch.match_pattern) { - case 'exact': - valueChecker = new ExactValueMatcher(stringMatch.exact!, stringMatch.ignore_case); - break; - case 'safe_regex': - valueChecker = new SafeRegexValueMatcher(stringMatch.safe_regex!.regex); - break; - case 'prefix': - valueChecker = new PrefixValueMatcher(stringMatch.prefix!, stringMatch.ignore_case); - break; - case 'suffix': - valueChecker = new SuffixValueMatcher(stringMatch.suffix!, stringMatch.ignore_case); - break; - case 'contains': - valueChecker = new ContainsValueMatcher(stringMatch.contains!, stringMatch.ignore_case); - break; - default: - valueChecker = new RejectValueMatcher(); - } + valueChecker = getPredicateForStringMatcher(headerMatch.string_match!); break; default: valueChecker = new RejectValueMatcher(); diff --git a/packages/grpc-js-xds/test/test-rbac.ts b/packages/grpc-js-xds/test/test-rbac.ts new file mode 100644 index 00000000..716a243b --- /dev/null +++ b/packages/grpc-js-xds/test/test-rbac.ts @@ -0,0 +1,376 @@ +/* + * Copyright 2023 gRPC 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. + * + */ + +import { Metadata } from '@grpc/grpc-js'; +import * as rbac from '../src/rbac'; +import * as assert from 'assert'; +import { ExactValueMatcher, HeaderMatcher } from '../src/matcher'; + +interface TestCase { + rule: rbac.RbacRule, + input: any, + expectedResult: boolean +} + +function createMetadata(key: string, value: string): Metadata { + const metadata = new Metadata(); + metadata.set(key, value); + return metadata; +} + +const testCases: TestCase[] = [ + { + rule: new rbac.AnyRule(), + input: {}, + expectedResult: true + }, + { + rule: new rbac.NoneRule(), + input: {}, + expectedResult: false + }, + { + rule: new rbac.OrRules([new rbac.NoneRule(), new rbac.NoneRule(), new rbac.NoneRule()]), + input: {}, + expectedResult: false + }, + { + rule: new rbac.OrRules([new rbac.NoneRule(), new rbac.NoneRule(), new rbac.AnyRule()]), + input: {}, + expectedResult: true + }, + { + rule: new rbac.AndRules([new rbac.AnyRule(), new rbac.AnyRule(), new rbac.AnyRule()]), + input: {}, + expectedResult: true + }, + { + rule: new rbac.AndRules([new rbac.AnyRule(), new rbac.AnyRule(), new rbac.NoneRule()]), + input: {}, + expectedResult: false + }, + { + rule: new rbac.NotRule(new rbac.NoneRule()), + input: {}, + expectedResult: true + }, + { + rule: new rbac.NotRule(new rbac.AnyRule()), + input: {}, + expectedResult: false + }, + { + rule: new rbac.DestinationIpPermission({addressPrefix: '127.0.0.0', prefixLen: 8}), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: true + }, + { + rule: new rbac.DestinationIpPermission({addressPrefix: '127.0.0.0', prefixLen: 8}), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '10.0.0.1', + destinationPort: 443 + }, + expectedResult: false + }, + { + rule: new rbac.DestinationPortPermission(443), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: true + }, + { + rule: new rbac.DestinationPortPermission(443), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 80 + }, + expectedResult: false + }, + { + rule: new rbac.UrlPathPermission(new ExactValueMatcher('/', false)), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: true + }, + { + rule: new rbac.UrlPathPermission(new ExactValueMatcher('/', false)), + input: { + headers: new Metadata(), + urlPath: '/service/method', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: false + }, + { + rule: new rbac.HeaderPermission(new HeaderMatcher('test', new ExactValueMatcher('value', false), false)), + input: { + headers: createMetadata('test', 'value'), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: true + }, + { + rule: new rbac.HeaderPermission(new HeaderMatcher('test', new ExactValueMatcher('value', false), false)), + input: { + headers: createMetadata('test', 'incorrect'), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: false + }, + { + rule: new rbac.MetadataPermission(), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: false + }, + { + rule: new rbac.RequestedServerNamePermission(new ExactValueMatcher('', false)), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: true + }, + { + rule: new rbac.RequestedServerNamePermission(new ExactValueMatcher('test', false)), + input: { + headers: new Metadata(), + urlPath: '/', + destinationIp: '127.0.0.1', + destinationPort: 443 + }, + expectedResult: false + }, + { + rule: new rbac.AuthenticatedPrincipal(null), + input: { + tls: true, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: true + }, + { + rule: new rbac.AuthenticatedPrincipal(null), + input: { + tls: false, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: false + }, + { + rule: new rbac.AuthenticatedPrincipal(new ExactValueMatcher('test', false)), + input: { + tls: true, + peerCertificate: { + subject: { + C: '', + ST: '', + L: '', + O: '', + OU: '', + CN: '' + }, + subjectaltname: 'URI:test' + }, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: true + }, + { + rule: new rbac.AuthenticatedPrincipal(new ExactValueMatcher('test', false)), + input: { + tls: true, + peerCertificate: { + subject: { + C: '', + ST: '', + L: '', + O: '', + OU: '', + CN: '' + }, + subjectaltname: 'DNS:test' + }, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: true + }, + { + rule: new rbac.AuthenticatedPrincipal(new ExactValueMatcher('test', false)), + input: { + tls: true, + peerCertificate: { + subject: { + C: '', + ST: '', + L: '', + O: '', + OU: '', + CN: '' + }, + subjectaltname: 'URI:incorrect, DNS:test' + }, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: false + }, + { + rule: new rbac.AuthenticatedPrincipal(new ExactValueMatcher('test', false)), + input: { + tls: true, + peerCertificate: { + subject: { + C: '', + ST: '', + L: '', + O: '', + OU: '', + CN: 'test' + }, + }, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: true + }, + { + rule: new rbac.SourceIpPrincipal({addressPrefix: '127.0.0.0', prefixLen: 8}), + input: { + tls: true, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: true + }, + { + rule: new rbac.SourceIpPrincipal({addressPrefix: '127.0.0.0', prefixLen: 8}), + input: { + tls: true, + peerCertificate: null, + sourceIp: '10.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: false + }, + { + rule: new rbac.HeaderPrincipal(new HeaderMatcher('test', new ExactValueMatcher('value', false), false)), + input: { + tls: true, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: createMetadata('test', 'value'), + urlPath: '/' + }, + expectedResult: true + }, + { + rule: new rbac.HeaderPrincipal(new HeaderMatcher('test', new ExactValueMatcher('value', false), false)), + input: { + tls: true, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: createMetadata('test', 'incorrect'), + urlPath: '/' + }, + expectedResult: false + }, + { + rule: new rbac.UrlPathPrincipal(new ExactValueMatcher('/', false)), + input: { + tls: true, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: true + }, + { + rule: new rbac.UrlPathPrincipal(new ExactValueMatcher('/', false)), + input: { + tls: true, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/service/method' + }, + expectedResult: false + }, + { + rule: new rbac.MetadataPrincipal(), + input: { + tls: true, + peerCertificate: null, + sourceIp: '127.0.0.1', + headers: new Metadata(), + urlPath: '/' + }, + expectedResult: false + }, +]; + +describe('RBAC engine', () => { + for (const testCase of testCases) { + it(`rule=${testCase.rule.toString()} input=${JSON.stringify(testCase.input)} result=${testCase.expectedResult}`, () => { + assert.strictEqual(testCase.rule.apply(testCase.input), testCase.expectedResult); + }); + } +});