Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e19730c
Fix credential leak on cross-host redirect in legacy EventGrid publis…
Nishanth-MS Jul 24, 2026
231c223
Fix credential leak on cross-host redirect in legacy EventGrid publis…
Nishanth-MS Jul 24, 2026
48335f0
Bump azure-eventgrid to 4.22.1
Nishanth-MS Jul 24, 2026
7e6e381
Update CHANGELOG for 4.22.1 security fix
Nishanth-MS Jul 24, 2026
554c996
Add cross-host redirect credential-leak regression tests
Nishanth-MS Jul 24, 2026
afb98a3
Require azure-core>=1.38.3 for retry-safe sensitive header cleanup
Nishanth-MS Jul 24, 2026
c52c008
Correct SensitiveHeaderCleanupPolicy comment (sync)
Nishanth-MS Jul 24, 2026
217c960
Correct SensitiveHeaderCleanupPolicy comment (async)
Nishanth-MS Jul 24, 2026
e50025c
Note azure-core minimum bump in changelog
Nishanth-MS Jul 24, 2026
7cc3afc
Add 301->500->200 retry regression test
Nishanth-MS Jul 24, 2026
768c1ee
Drop Python 3.8 (azure-core>=1.38.3 requires >=3.9)
Nishanth-MS Jul 24, 2026
4a8c449
Use async fake token credential for async AAD redirect test
Nishanth-MS Jul 24, 2026
3852081
Add @Nishanth-MS as codeowner for /sdk/eventgrid/
Nishanth-MS Jul 24, 2026
54a8555
Remove @rajeshka from /sdk/eventgrid/ codeowners
Nishanth-MS Jul 24, 2026
0421a1d
Pin cloudevents<2.0.0 (2.0.0 removed cloudevents.http, breaking cncf …
Nishanth-MS Jul 27, 2026
a6a6af8
Merge main into eventgrid redirect fix branch
Nishanth-MS Jul 27, 2026
25c31df
Suppress unidiomatic-typecheck in generated _model_base.py (pylint 4.x)
Nishanth-MS Jul 27, 2026
7577fa6
Suppress unused-argument in generated _serialization.py (pylint 4.x)
Nishanth-MS Jul 27, 2026
2e50e1d
Use 307 (method-preserving) redirect so POST publish redirect is actu…
Nishanth-MS Jul 27, 2026
81f3527
Force deterministic retry with Retry-After header in redirect-retry test
Nishanth-MS Jul 27, 2026
70c3b80
Use line-level unidiomatic-typecheck disables in generated _model_bas…
Nishanth-MS Jul 27, 2026
d474f9e
Use line-level unused-argument disables in generated _serialization.p…
Nishanth-MS Jul 27, 2026
ff092b9
Revert _model_base.py to pristine generated output
Nishanth-MS Jul 27, 2026
e2fd13d
Revert _serialization.py to pristine generated output
Nishanth-MS Jul 27, 2026
8fc23e1
Exclude Event Grid top-level generated files from pylint (ignore-paths)
Nishanth-MS Jul 27, 2026
7dd41cf
Disclose Python 3.9 minimum in changelog
Nishanth-MS Jul 27, 2026
2c4537a
Update README Python requirement to 3.9
Nishanth-MS Jul 27, 2026
58c8ee3
Add async redirect-then-retry regression test
Nishanth-MS Jul 27, 2026
260dbca
Explain cloudevents 1.x pin in dev_requirements (latent 2.0.0 break)
Nishanth-MS Jul 27, 2026
5ddb3e8
Add generated api.md for azure-eventgrid (API.md consistency check)
Nishanth-MS Jul 28, 2026
660639d
Add generated api.metadata.yml for azure-eventgrid
Nishanth-MS Jul 28, 2026
d25db60
Revert pylintrc ignore-paths (does not apply to package-target pylint…
Nishanth-MS Jul 28, 2026
350ea8a
Inline-disable unidiomatic-typecheck in generated _model_base.py (bat…
Nishanth-MS Jul 28, 2026
7917853
Inline-disable unused-argument in generated _serialization.py (batch …
Nishanth-MS Jul 28, 2026
e2ef49b
Minimize _model_base.py diff to 3 inline-disable lines (preserve LF)
Nishanth-MS Jul 28, 2026
f96e45a
Minimize _serialization.py diff to 6 inline-disable lines (preserve LF)
Nishanth-MS Jul 28, 2026
8185745
Fix duplicate blocked_redirect_headers kwarg (merge caller list, pop …
Nishanth-MS Jul 28, 2026
8f60a28
Fix duplicate blocked_redirect_headers kwarg in async client
Nishanth-MS Jul 28, 2026
54a3ad9
Set 4.22.1 release date in changelog
Nishanth-MS Jul 28, 2026
6d526e3
Move minimum Python to 3.10 and add 3.13/3.14 classifiers (reviewer: …
Nishanth-MS Jul 28, 2026
480727a
README: Python 3.10 or later
Nishanth-MS Jul 28, 2026
fb9d34e
Changelog: minimum Python now 3.10
Nishanth-MS Jul 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@
# AzureSdkOwners: @rajeshka @shankarsama
# ServiceLabel: %Event Grid
# PRLabel: %Event Grid
/sdk/eventgrid/ @rajeshka @shankarsama
/sdk/eventgrid/ @shankarsama @Nishanth-MS
Comment thread
Nishanth-MS marked this conversation as resolved.

# PRLabel: %Event Hubs
/sdk/eventhub/ @axisc @hmlam @j7nw4r @SwayGom @sagar0207 @sjkwak
Expand Down
11 changes: 11 additions & 0 deletions sdk/eventgrid/azure-eventgrid/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Release History

## 4.22.1 (2026-07-28)

### Bugs Fixed

- Fixed a security issue where the legacy `EventGridPublisherClient` (sync and async) could re-send credential headers to a different host when following an HTTP 3xx redirect. A `SensitiveHeaderCleanupPolicy` is now added to the pipeline to strip `Authorization`, `aeg-sas-key` and `aeg-sas-token` headers on cross-host redirects.

### Other Changes

- Raised the minimum `azure-core` dependency to `1.38.3` so that credential headers remain stripped across retries following a cross-host redirect (`insecure_domain_change` flag persistence).
- Increased the minimum supported Python version to 3.10. Python 3.9 and earlier are no longer supported.

## 4.22.0 (2025-05-14)

### Features Added
Expand Down
2 changes: 1 addition & 1 deletion sdk/eventgrid/azure-eventgrid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This is a GA release of Azure Event Grid's `EventGridPublisherClient` and `Event
## Getting started

### Prerequisites
* Python 3.8 or later is required to use this package.
* Python 3.10 or later is required to use this package.
* You must have an [Azure subscription][azure_subscription] and at least one of the following:
* an Event Grid Namespace resource. To create an Event Grid Namespace resource follow [this tutorial](https://learn.microsoft.com/azure/event-grid/create-view-manage-namespaces).
* an Event Grid Basic resource. To create an Event Grid Basic resource via the Azure portal follow this [step-by-step tutorial](https://learn.microsoft.com/azure/event-grid/custom-event-quickstart-portal). To create an Event Grid Basic resource via the [Azure CLI](https://learn.microsoft.com/cli/azure) follow this [tutorial](https://learn.microsoft.com/azure/event-grid/custom-event-quickstart)
Expand Down
672 changes: 672 additions & 0 deletions sdk/eventgrid/azure-eventgrid/api.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions sdk/eventgrid/azure-eventgrid/api.metadata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
apiMdSha256: dcc804237da14b8d346f7881e23a570a9639c4784861a319246e65309b46b724
parserVersion: 0.3.30
pythonVersion: 3.13.14
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
DistributedTracingPolicy,
HttpLoggingPolicy,
UserAgentPolicy,
SensitiveHeaderCleanupPolicy,
)
from azure.core.exceptions import (
ClientAuthenticationError,
Expand Down Expand Up @@ -121,6 +122,16 @@ def _policies(
**kwargs: Any
) -> List[Any]:
auth_policy = _get_authentication_policy(credential)
# Merge any caller-supplied blocked redirect headers with the mandatory
# Event Grid credential headers, and remove the key from kwargs so it is
# not passed twice to SensitiveHeaderCleanupPolicy.
blocked_redirect_headers = [
"Authorization",
"x-ms-authorization-auxiliary",
"aeg-sas-key",
"aeg-sas-token",
*kwargs.pop("blocked_redirect_headers", []),
]
sdk_moniker = "eventgrid/{}".format(VERSION)
policies = [
RequestIdPolicy(**kwargs),
Expand All @@ -131,6 +142,14 @@ def _policies(
RedirectPolicy(**kwargs),
RetryPolicy(**kwargs),
auth_policy,
# Strip credential headers on cross-host redirects to avoid leaking them to
# a redirect target. `SensitiveHeaderCleanupPolicy` already covers
# `Authorization` and `x-ms-authorization-auxiliary` by default; the Event
# Grid SAS headers (`aeg-sas-key`/`aeg-sas-token`) are added here as well.
SensitiveHeaderCleanupPolicy(
blocked_redirect_headers=blocked_redirect_headers,
**kwargs,
),
CustomHookPolicy(**kwargs),
NetworkTraceLoggingPolicy(**kwargs),
DistributedTracingPolicy(**kwargs),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
HttpLoggingPolicy,
UserAgentPolicy,
AsyncBearerTokenCredentialPolicy,
SensitiveHeaderCleanupPolicy,
)
from azure.core.exceptions import (
ClientAuthenticationError,
Expand Down Expand Up @@ -115,6 +116,16 @@ def _policies(
credential: Union[AzureKeyCredential, AzureSasCredential, "AsyncTokenCredential"], **kwargs: Any
) -> List[Any]:
auth_policy = _get_authentication_policy(credential, AsyncBearerTokenCredentialPolicy)
# Merge any caller-supplied blocked redirect headers with the mandatory
# Event Grid credential headers, and remove the key from kwargs so it is
# not passed twice to SensitiveHeaderCleanupPolicy.
blocked_redirect_headers = [
"Authorization",
"x-ms-authorization-auxiliary",
"aeg-sas-key",
"aeg-sas-token",
*kwargs.pop("blocked_redirect_headers", []),
]
sdk_moniker = "eventgridpublisherclient/{}".format(VERSION)
policies = [
RequestIdPolicy(**kwargs),
Expand All @@ -125,6 +136,14 @@ def _policies(
AsyncRedirectPolicy(**kwargs),
AsyncRetryPolicy(**kwargs),
auth_policy,
# Strip credential headers on cross-host redirects to avoid leaking them to
# a redirect target. `SensitiveHeaderCleanupPolicy` already covers
# `Authorization` and `x-ms-authorization-auxiliary` by default; the Event
# Grid SAS headers (`aeg-sas-key`/`aeg-sas-token`) are added here as well.
SensitiveHeaderCleanupPolicy(
blocked_redirect_headers=blocked_redirect_headers,
**kwargs,
),
CustomHookPolicy(**kwargs),
NetworkTraceLoggingPolicy(**kwargs),
DistributedTracingPolicy(**kwargs),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -774,16 +774,16 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=too-many-retur

# is it optional?
try:
if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore
if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore # pylint: disable=unidiomatic-typecheck
Comment thread
Nishanth-MS marked this conversation as resolved.
if len(annotation.__args__) <= 2: # pyright: ignore
if_obj_deserializer = _get_deserialize_callable_from_annotation(
next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore
next(a for a in annotation.__args__ if a != type(None)), module, rf # pyright: ignore # pylint: disable=unidiomatic-typecheck
)

return functools.partial(_deserialize_with_optional, if_obj_deserializer)
# the type is Optional[Union[...]], we need to remove the None type from the Union
annotation_copy = copy.copy(annotation)
annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore
annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore # pylint: disable=unidiomatic-typecheck
return _get_deserialize_callable_from_annotation(annotation_copy, module, rf)
except AttributeError:
pass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]],
class UTC(datetime.tzinfo):
"""Time Zone info for handling UTC"""

def utcoffset(self, dt):
def utcoffset(self, dt): # pylint: disable=unused-argument
"""UTF offset for UTC is 0.

:param datetime.datetime dt: The datetime
Expand All @@ -198,7 +198,7 @@ def utcoffset(self, dt):
"""
return datetime.timedelta(0)

def tzname(self, dt):
def tzname(self, dt): # pylint: disable=unused-argument
"""Timestamp representation.

:param datetime.datetime dt: The datetime
Expand All @@ -207,7 +207,7 @@ def tzname(self, dt):
"""
return "Z"

def dst(self, dt):
def dst(self, dt): # pylint: disable=unused-argument
"""No daylight saving for UTC.

:param datetime.datetime dt: The datetime
Expand All @@ -230,16 +230,16 @@ class _FixedOffset(datetime.tzinfo): # type: ignore
def __init__(self, offset) -> None:
self.__offset = offset

def utcoffset(self, dt):
def utcoffset(self, dt): # pylint: disable=unused-argument
return self.__offset

def tzname(self, dt):
def tzname(self, dt): # pylint: disable=unused-argument
return str(self.__offset.total_seconds() / 3600)

def __repr__(self):
return "<FixedOffset {}>".format(self.tzname(None))

def dst(self, dt):
def dst(self, dt): # pylint: disable=unused-argument
return datetime.timedelta(0)

def __getinitargs__(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
# --------------------------------------------------------------------------

VERSION = "4.22.0"
VERSION = "4.22.1"
6 changes: 5 additions & 1 deletion sdk/eventgrid/azure-eventgrid/dev_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
azure-mgmt-resource==22.0.0
../azure-mgmt-eventgrid
azure-storage-queue
cloudevents<=2.0.0; python_version >= "3.7"
# Pin to cloudevents 1.x: 2.0.0 is a backwards-incompatible rewrite that removed the
# `cloudevents.http` module the CNCF tests/samples import. This is a test-only dependency
# (not in install_requires); the `<=2.0.0` pin was a latent issue that broke once 2.0.0
# shipped. TODO: migrate the CNCF tests/samples to the cloudevents 2.x API and relax this pin.
cloudevents<2.0.0; python_version >= "3.7"
aiohttp>=3.0
8 changes: 4 additions & 4 deletions sdk/eventgrid/azure-eventgrid/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@
"Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"License :: OSI Approved :: MIT License",
],
zip_safe=False,
Expand All @@ -63,8 +63,8 @@
},
install_requires=[
"isodate>=0.6.1",
"azure-core>=1.30.0",
"azure-core>=1.38.3",
Comment thread
Nishanth-MS marked this conversation as resolved.
"typing-extensions>=4.6.0",
],
python_requires=">=3.8",
python_requires=">=3.10",
)
Loading
Loading