diff --git a/sdk-python/src/apip_sdk_core/policy/v1alpha2/__init__.py b/sdk-python/src/apip_sdk_core/policy/v1alpha2/__init__.py index 0f2050af4f..4cee9c72bf 100644 --- a/sdk-python/src/apip_sdk_core/policy/v1alpha2/__init__.py +++ b/sdk-python/src/apip_sdk_core/policy/v1alpha2/__init__.py @@ -44,6 +44,8 @@ AuthContext, Body, BodyProcessingMode, + DownstreamContext, + DownstreamRequest, ExecutionContext, ExecutionPhase, HeaderProcessingMode, @@ -58,12 +60,17 @@ ResponseStreamContext, SharedContext, StreamBody, + UpstreamRequestContext, + UpstreamResponse, + UpstreamResponseContext, ) __all__ = [ "AuthContext", "Body", "BodyProcessingMode", + "DownstreamContext", + "DownstreamRequest", "DownstreamResponseHeaderModifications", "DownstreamResponseModifications", "DropHeaderAction", @@ -98,6 +105,9 @@ "StreamingResponseAction", "StreamingResponsePolicy", "TerminateResponseChunk", + "UpstreamRequestContext", "UpstreamRequestHeaderModifications", "UpstreamRequestModifications", + "UpstreamResponse", + "UpstreamResponseContext", ] diff --git a/sdk-python/src/apip_sdk_core/policy/v1alpha2/types.py b/sdk-python/src/apip_sdk_core/policy/v1alpha2/types.py index a6f89a3b2a..0fe00037ba 100644 --- a/sdk-python/src/apip_sdk_core/policy/v1alpha2/types.py +++ b/sdk-python/src/apip_sdk_core/policy/v1alpha2/types.py @@ -129,6 +129,71 @@ class StreamBody: index: int = 0 +@dataclass(slots=True) +class DownstreamRequest: + """Snapshot of the request as received from the downstream client, captured + before any policy mutation. + + ``headers`` is ``Headers | None`` (defaulting to ``None``) to mirror the Go + SDK's nilable ``Headers *Headers``: the kernel leaves it ``None`` when no + snapshot is available, rather than substituting an empty ``Headers()`` that + a policy could not distinguish from "the client sent no headers". + """ + + headers: Headers | None = None + + +@dataclass(slots=True) +class DownstreamContext: + """Downstream client, carrying a snapshot of the client request. + + Access the snapshot via ``downstream.request.headers``, mirroring the + upstream side's ``upstream.response.headers``. ``request`` is + ``DownstreamRequest | None`` (defaulting to ``None``), left ``None`` by the + kernel when no snapshot is available. + """ + + request: DownstreamRequest | None = None + + +@dataclass(slots=True) +class UpstreamRequestContext: + """Route's resolved upstream target during the request phase. + + ``name`` replaces the internal Envoy cluster name. Use ``url`` to + address the actual upstream (e.g. for request signing); the client-facing + authority/scheme on the context must not be used for that. + """ + + name: str = "" + url: str = "" + base_path: str = "" + + +@dataclass(slots=True) +class UpstreamResponse: + """Snapshot of the response as received from the upstream backend, captured + before any policy mutation. + + ``headers`` is ``Headers | None`` (defaulting to ``None``), mirroring the Go + SDK's nilable ``Headers *Headers``. + """ + + headers: Headers | None = None + + +@dataclass(slots=True) +class UpstreamResponseContext: + """Route's resolved upstream target during the response phase, carrying a + snapshot of the upstream response. + """ + + name: str = "" + url: str = "" + base_path: str = "" + response: UpstreamResponse | None = None + + @dataclass(slots=True) class RequestHeaderContext: shared: SharedContext @@ -138,6 +203,8 @@ class RequestHeaderContext: authority: str = "" scheme: str = "" vhost: str = "" + downstream: DownstreamContext | None = None + upstream: UpstreamRequestContext | None = None @dataclass(slots=True) @@ -150,6 +217,8 @@ class RequestContext: authority: str = "" scheme: str = "" vhost: str = "" + downstream: DownstreamContext | None = None + upstream: UpstreamRequestContext | None = None @dataclass(slots=True) @@ -161,6 +230,8 @@ class ResponseHeaderContext: request_method: str = "" response_headers: Headers = field(default_factory=Headers) response_status: int = 200 + downstream: DownstreamContext | None = None + upstream: UpstreamResponseContext | None = None @dataclass(slots=True) @@ -173,6 +244,8 @@ class ResponseContext: response_headers: Headers = field(default_factory=Headers) response_body: Body | None = None response_status: int = 200 + downstream: DownstreamContext | None = None + upstream: UpstreamResponseContext | None = None @dataclass(slots=True) @@ -184,6 +257,8 @@ class RequestStreamContext: authority: str = "" scheme: str = "" vhost: str = "" + downstream: DownstreamContext | None = None + upstream: UpstreamRequestContext | None = None @dataclass(slots=True) @@ -195,6 +270,8 @@ class ResponseStreamContext: request_method: str = "" response_headers: Headers = field(default_factory=Headers) response_status: int = 200 + downstream: DownstreamContext | None = None + upstream: UpstreamResponseContext | None = None @dataclass(slots=True) diff --git a/sdk/core/policy/v1alpha2/context.go b/sdk/core/policy/v1alpha2/context.go index 8cd784e943..3f3973da1a 100644 --- a/sdk/core/policy/v1alpha2/context.go +++ b/sdk/core/policy/v1alpha2/context.go @@ -17,6 +17,41 @@ type Body struct { Present bool } +// DownstreamContext identifies the downstream client and carries a snapshot of +// the client request. +type DownstreamContext struct { + Request *DownstreamRequest +} + +// DownstreamRequest holds a snapshot of the request as received from the +// downstream client, captured before any policy mutation is applied. +type DownstreamRequest struct { + Headers *Headers +} + +// UpstreamRequestContext identifies the route's resolved upstream target during +// the request phase. +type UpstreamRequestContext struct { + Name string + URL string + BasePath string +} + +// UpstreamResponseContext identifies the route's resolved upstream target during +// the response phase and carries a snapshot of the upstream response. +type UpstreamResponseContext struct { + Name string + URL string + BasePath string + Response *UpstreamResponse +} + +// UpstreamResponse holds a snapshot of the response as received from the +// upstream backend, captured before any policy mutation is applied. +type UpstreamResponse struct { + Headers *Headers +} + // SharedContext contains data shared across request and response phases type SharedContext struct { // ProjectID is the project ID which the API is associated with @@ -75,6 +110,14 @@ type RequestHeaderContext struct { Authority string Scheme string Vhost string + + // Downstream holds the snapshot of the client request headers, captured + // before any policy mutation. + Downstream *DownstreamContext + + // Upstream identifies the route's resolved upstream target for this + // request. + Upstream *UpstreamRequestContext } // RequestContext is passed to RequestPolicy.OnRequestBody. @@ -93,12 +136,19 @@ type RequestContext struct { Scheme string Vhost string - // UpstreamInfo identifies the route's resolved upstream target (cluster name, URL, - // base path) for this request. Nil if no upstream has been resolved for the route. - // Authority/Scheme above reflect the inbound client-facing request and must not be - // used to address the actual upstream (e.g. for request signing) — use - // UpstreamInfo.URL instead. + // Deprecated: UpstreamInfo exposes the internal Envoy cluster name and its + // resolved-upstream shape was incorrect. Use Upstream (*UpstreamRequestContext) + // instead, which exposes Name rather than the internal cluster name. + // Retained for backward compatibility; will be removed in a future release. UpstreamInfo *policyenginev1.UpstreamInfo + + // Downstream holds the snapshot of the client request headers, captured + // before any policy mutation. + Downstream *DownstreamContext + + // Upstream identifies the route's resolved upstream target for this + // request. + Upstream *UpstreamRequestContext } // ─── Response-phase contexts ───────────────────────────────────────────────── @@ -119,6 +169,15 @@ type ResponseHeaderContext struct { // Current response status code ResponseStatus int + + // Downstream holds the snapshot of the client request headers, captured + // before any policy mutation. + Downstream *DownstreamContext + + // Upstream identifies the route's resolved upstream target and carries the + // snapshot of the upstream response headers, captured before any policy + // mutation. + Upstream *UpstreamResponseContext } // ResponseContext is passed to ResponsePolicy.OnResponseBody. @@ -143,6 +202,15 @@ type ResponseContext struct { // Current response status code ResponseStatus int + + // Downstream holds the snapshot of the client request headers, captured + // before any policy mutation. + Downstream *DownstreamContext + + // Upstream identifies the route's resolved upstream target and carries the + // snapshot of the upstream response headers, captured before any policy + // mutation. + Upstream *UpstreamResponseContext } // ─── Streaming contexts ────────────────────────────────────────────────────── @@ -180,6 +248,14 @@ type RequestStreamContext struct { Authority string Scheme string Vhost string + + // Downstream holds the snapshot of the client request headers, captured + // before any policy mutation. + Downstream *DownstreamContext + + // Upstream identifies the route's resolved upstream target for this + // request. + Upstream *UpstreamRequestContext } // ResponseStreamContext is the per-chunk context passed to StreamingResponseBodyPolicy. @@ -199,4 +275,13 @@ type ResponseStreamContext struct { // Current response status code ResponseStatus int + + // Downstream holds the snapshot of the client request headers, captured + // before any policy mutation. + Downstream *DownstreamContext + + // Upstream identifies the route's resolved upstream target and carries the + // snapshot of the upstream response headers, captured before any policy + // mutation. + Upstream *UpstreamResponseContext }