From 366430a72fcd3353ed99d1c5d2c4c17d01fd6f9c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 11 Aug 2026 20:29:19 +0900 Subject: [PATCH 01/12] test: reproduce scalar integer policy gap on current main --- tests/test_policy_integer_value_types.py | 125 +++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 tests/test_policy_integer_value_types.py diff --git a/tests/test_policy_integer_value_types.py b/tests/test_policy_integer_value_types.py new file mode 100644 index 00000000..f1a51126 --- /dev/null +++ b/tests/test_policy_integer_value_types.py @@ -0,0 +1,125 @@ +"""Security contracts for exact built-in integer policy values.""" + +from __future__ import annotations + +from pathlib import Path + +import pytest + +from egressweave import EgressPolicy + + +class _PolicyIntegerSubclass(int): + """Represent an unreviewed integer subclass crossing trusted configuration.""" + + +def test_policy_rejects_integer_subclass_for_allowed_port() -> None: + """Reject non-exact ports before retaining normalized authority state.""" + with pytest.raises(TypeError, match="allowed_ports"): + EgressPolicy.from_hosts( + "api.example.com", + allowed_ports=[_PolicyIntegerSubclass(443)], + ) + + +def test_policy_rejects_integer_subclass_for_exact_authority_port() -> None: + """Reject a non-exact port in the exact-authority constructor as well.""" + with pytest.raises(TypeError, match="allowed_ports"): + EgressPolicy.from_authorities( + [("api.example.com", _PolicyIntegerSubclass(443))], + ) + + +@pytest.mark.parametrize( + "field_name", + [ + "max_resolved_addresses", + "max_request_header_fields", + "max_response_header_fields", + "max_request_bytes", + "max_response_bytes", + "max_response_header_bytes", + "max_request_header_bytes", + "max_request_target_bytes", + ], +) +def test_policy_rejects_integer_subclass_for_resource_limits(field_name: str) -> None: + """Reject non-exact integers before retaining finite resource limits.""" + with pytest.raises(TypeError, match=field_name): + EgressPolicy.from_hosts( + "api.example.com", + **{field_name: _PolicyIntegerSubclass(8)}, # type: ignore[arg-type] + ) + + +def test_policy_keeps_exact_integer_and_decimal_string_configuration() -> None: + """Preserve reviewed exact integers and decimal environment values.""" + exact_integer = EgressPolicy.from_hosts( + "api.example.com", + allowed_ports=[8443], + max_resolved_addresses=8, + max_request_header_fields=32, + max_response_header_fields=32, + max_request_bytes=4096, + max_response_bytes=4096, + max_response_header_bytes=4096, + max_request_header_bytes=4096, + max_request_target_bytes=8192, + ) + decimal_string = EgressPolicy.from_hosts( + "api.example.com", + allowed_ports=["8443"], + max_resolved_addresses="8", + max_request_header_fields="32", + max_response_header_fields="32", + max_request_bytes="4096", + max_response_bytes="4096", + max_response_header_bytes="4096", + max_request_header_bytes="4096", + max_request_target_bytes="8192", + ) + + assert decimal_string == exact_integer + assert all(type(port) is int for port in decimal_string.allowed_ports) + assert type(decimal_string.max_resolved_addresses) is int + assert type(decimal_string.max_request_header_fields) is int + assert type(decimal_string.max_response_header_fields) is int + assert type(decimal_string.max_request_bytes) is int + assert type(decimal_string.max_response_bytes) is int + assert type(decimal_string.max_response_header_bytes) is int + assert type(decimal_string.max_request_header_bytes) is int + assert type(decimal_string.max_request_target_bytes) is int + + +def test_exact_authority_keeps_integer_and_decimal_string_port_equivalent() -> None: + """Preserve exact-authority ergonomics while storing canonical integer ports.""" + exact_integer = EgressPolicy.from_authorities([("api.example.com", 8443)]) + decimal_string = EgressPolicy.from_authorities([("api.example.com", "8443")]) + + assert decimal_string == exact_integer + assert decimal_string.allowed_authorities == frozenset( + {("api.example.com", 8443)} + ) + assert all(type(port) is int for port in decimal_string.allowed_ports) + assert all( + type(port) is int for _, port in decimal_string.allowed_authorities + ) + + +def test_policy_configuration_integrity_guide_is_discoverable_and_current() -> None: + """Document the supported primitive-value boundary without sandbox claims.""" + guide_path = Path("docs/research/policy-configuration-integrity.md") + + assert guide_path.is_file() + guide = guide_path.read_text(encoding="utf-8") + assert "exact built-in `int`" in guide + assert "ASCII decimal strings" in guide + assert "does not make EgressWeave a Python sandbox" in guide + assert "https://docs.python.org/3.14/reference/datamodel.html" in guide + + +def test_changelog_records_shared_policy_integer_value_sealing() -> None: + """Record the trusted scalar policy tightening in release history.""" + changelog = Path("CHANGELOG.md").read_text(encoding="utf-8") + + assert "Reject non-exact integer subclasses in shared policy integer fields" in changelog From 9cec74a3d9872af0a1bc4483b24d218f4135af2e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 11 Aug 2026 20:33:28 +0900 Subject: [PATCH 02/12] fix: seal scalar integer policy values on current main --- src/egressweave/_policy_normalization.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/egressweave/_policy_normalization.py b/src/egressweave/_policy_normalization.py index 8292fa31..0a190a5d 100644 --- a/src/egressweave/_policy_normalization.py +++ b/src/egressweave/_policy_normalization.py @@ -125,7 +125,7 @@ def _normalize_allowed_port(value: object) -> int | None: raise ValueError("allowed_ports entries must be decimal port numbers") port = int(normalized) else: - if isinstance(value, bool) or not isinstance(value, int): + if type(value) is not int: raise TypeError("allowed_ports entries must be integer port numbers") port = value @@ -188,7 +188,7 @@ def _normalize_max_resolved_addresses(value: object) -> int: ) address_count = int(normalized) else: - if isinstance(value, bool) or not isinstance(value, int): + if type(value) is not int: raise TypeError("max_resolved_addresses must be an integer count") address_count = value @@ -205,7 +205,7 @@ def _normalize_positive_count(value: object, field_name: str) -> int: raise ValueError(f"{field_name} must be a positive decimal count") item_count = int(normalized) else: - if isinstance(value, bool) or not isinstance(value, int): + if type(value) is not int: raise TypeError(f"{field_name} must be an integer count") item_count = value @@ -224,7 +224,7 @@ def _normalize_positive_byte_count(value: object, field_name: str) -> int: ) byte_count = int(normalized) else: - if isinstance(value, bool) or not isinstance(value, int): + if type(value) is not int: raise TypeError(f"{field_name} must be an integer byte count") byte_count = value From 0c33c2691ac9d5e36bc4120cdb945a01869396d9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 11 Aug 2026 20:38:58 +0900 Subject: [PATCH 03/12] docs: define scalar policy configuration integrity --- .../policy-configuration-integrity.md | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 docs/research/policy-configuration-integrity.md diff --git a/docs/research/policy-configuration-integrity.md b/docs/research/policy-configuration-integrity.md new file mode 100644 index 00000000..ea35b13f --- /dev/null +++ b/docs/research/policy-configuration-integrity.md @@ -0,0 +1,76 @@ +# Trusted policy configuration value integrity + +## Decision + +EgressWeave treats policy construction as a trusted startup boundary and stores a +canonical immutable policy value after normalization. Integer-form policy inputs +that become durable authority or resource-limit state therefore accept only an +exact built-in `int`. Non-exact integer subclasses are rejected instead of being +retained inside `EgressPolicy`. + +The reviewed environment-configuration contract remains unchanged: ASCII decimal +strings are accepted where the corresponding public field already supports them +and are converted to exact built-in integers before range checks, relational +checks, policy fingerprinting, DNS validation, request validation, or transport +delegation. Exact built-in integers continue to be accepted directly. + +This restriction applies to the shared integer normalization paths for allowed +ports, maximum resolved-address count, positive header-field counts, and positive +request/response byte budgets. It does not change configured defaults, allowed +ranges, authority pairing, DNS policy, TLS identity, proxy isolation, HTTP method +policy, request/response framing, or the generic request-time denial boundary. + +## Why exact type matters at this boundary + +Python deliberately supports subclassing immutable built-in types such as `int`, +and `isinstance(value, int)` is true for instances of subclasses. Python's data +model also permits subclasses of immutable built-ins to customize instance +creation. A broad `isinstance` check is therefore a polymorphism contract, not +proof that the stored object is the canonical built-in integer value expected by +a closed immutable policy representation. + +EgressWeave does not need that polymorphism for policy scalar fields. Supported +customization is expressed through documented values, not user-defined numeric +classes. Requiring `type(value) is int` on integer-form inputs prevents a subclass +object from surviving normalization and later participating in policy hashing or +equality, authority tuples, arithmetic or comparison boundaries, or provider +delegation. Environment text still reaches the same canonical state through +explicit decimal conversion. + +This supported-value sealing does not make EgressWeave a Python sandbox. Code +that is already executing inside the embedding process retains ordinary Python +capabilities. The boundary exists to make the documented policy value object +canonical, predictable, reviewable, and stable across standalone and modular +integrations. + +## Enforcement invariants + +1. Integer-form allowed ports must be exact built-in integers; reviewed ASCII + decimal strings are converted to built-in integers. +2. Integer-form DNS candidate limits must be exact built-in integers; reviewed + ASCII decimal strings are converted before positivity checks. +3. Shared positive field-count and byte-budget normalizers reject integer + subclasses and preserve their existing positive-value constraints. +4. Booleans remain invalid integer configuration even though Python defines + `bool` as an `int` subclass. +5. Existing decimal-string syntax, defaults, public builder signatures, and + request-time generic denial behavior remain unchanged. +6. Invalid trusted startup configuration continues to raise actionable + field-specific `TypeError` or `ValueError` rather than becoming an opaque + request-time policy denial. +7. Regression tests exercise the public `EgressPolicy` constructors so the + contract is proven at the API boundary rather than only against internal + helpers. + +## Operator migration + +Applications that supply plain integers or ASCII decimal environment values need +no change. Applications that pass custom subclasses of `int` for ports or finite +resource budgets should materialize an exact built-in integer before policy +construction. This is a pre-1.0 tightening of an ambiguous configuration shape; +it does not widen egress authority or change any finite default. + +## Reference — APA 7th + +Python Software Foundation. (2026). *Data model — Python 3.14.6 documentation*. +https://docs.python.org/3.14/reference/datamodel.html From 2730ef688cff5a2e9d253374121061f8aae2dd4a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 11 Aug 2026 20:40:07 +0900 Subject: [PATCH 04/12] docs: record scalar integer policy sealing --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 197cb091..705f2661 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,6 +68,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). disable the recurring loop. ### Security +- Reject non-exact integer subclasses in shared policy integer fields before + retaining trusted configuration state. Exact built-in integers and existing + ASCII decimal strings remain supported, preserving defaults and ranges while + preventing subclass-controlled values from crossing immutable policy construction. - Enforce one hard connection deadline across every staggered asynchronous attempt and coordinator wait, and make the synchronous pinned transport refuse a TCP attempt when the zero remaining connection budget is already exhausted. From 1d31a0438c60a466d7bbb59a1f376a87ce27bb3a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:10:27 +0900 Subject: [PATCH 05/12] test(security): reproduce non-exact HTTP method policy acceptance --- tests/test_policy_method_value_integrity.py | 63 +++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/test_policy_method_value_integrity.py diff --git a/tests/test_policy_method_value_integrity.py b/tests/test_policy_method_value_integrity.py new file mode 100644 index 00000000..9bcb6eee --- /dev/null +++ b/tests/test_policy_method_value_integrity.py @@ -0,0 +1,63 @@ +"""Regression tests for exact built-in HTTP method policy values.""" + +from __future__ import annotations + +import pytest + +from egressweave.policy import EgressPolicy + + +class _NonExactMethod(str): + """Keep subclass identity if trusted normalization invokes polymorphic methods.""" + + def strip(self, chars: str | None = None) -> "_NonExactMethod": + """Return this subclass instead of a canonical built-in string.""" + return self + + def upper(self) -> "_NonExactMethod": + """Return this subclass instead of a canonical built-in string.""" + return self + + +class _ExplodingMethodList(str): + """Expose polymorphic dispatch in comma-separated method parsing.""" + + def split(self, sep: str | None = None, maxsplit: int = -1) -> list[str]: + """Fail if trusted construction invokes subclass-controlled splitting.""" + raise AssertionError("string subclass split executed") + + +def test_method_policy_rejects_str_subclass_before_normalization() -> None: + """Reject subclass-controlled method normalization during policy construction.""" + with pytest.raises(TypeError, match="allowed_methods"): + EgressPolicy.from_hosts( + "api.example.com", + allowed_methods={_NonExactMethod("GET")}, + ) + + +def test_direct_policy_rejects_str_subclass_before_comma_split() -> None: + """Reject a direct comma-string subclass before invoking its split method.""" + with pytest.raises(TypeError, match="allowed_methods"): + EgressPolicy( + allowed_hosts=frozenset({"api.example.com"}), + allowed_methods=_ExplodingMethodList("GET,POST"), + ) + + +def test_from_hosts_rejects_str_subclass_before_comma_split() -> None: + """Reject a host-factory comma-string subclass before invoking split.""" + with pytest.raises(TypeError, match="allowed_methods"): + EgressPolicy.from_hosts( + "api.example.com", + allowed_methods=_ExplodingMethodList("GET,POST"), + ) + + +def test_from_authorities_rejects_str_subclass_before_comma_split() -> None: + """Reject an authority-factory comma-string subclass before invoking split.""" + with pytest.raises(TypeError, match="allowed_methods"): + EgressPolicy.from_authorities( + [("api.example.com", 443)], + allowed_methods=_ExplodingMethodList("GET,POST"), + ) From 350c495a50d7e0cd206f72d9304e81bf16f38eaf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:12:30 +0900 Subject: [PATCH 06/12] test(security): keep RED fixture lint-clean --- tests/test_policy_method_value_integrity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_policy_method_value_integrity.py b/tests/test_policy_method_value_integrity.py index 9bcb6eee..b4c12912 100644 --- a/tests/test_policy_method_value_integrity.py +++ b/tests/test_policy_method_value_integrity.py @@ -10,11 +10,11 @@ class _NonExactMethod(str): """Keep subclass identity if trusted normalization invokes polymorphic methods.""" - def strip(self, chars: str | None = None) -> "_NonExactMethod": + def strip(self, chars: str | None = None) -> _NonExactMethod: """Return this subclass instead of a canonical built-in string.""" return self - def upper(self) -> "_NonExactMethod": + def upper(self) -> _NonExactMethod: """Return this subclass instead of a canonical built-in string.""" return self From 1862130966e728acd4c5e2c605a218c7bc9357c4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:15:52 +0900 Subject: [PATCH 07/12] fix(security): reject non-exact HTTP method values --- src/egressweave/_policy_normalization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/egressweave/_policy_normalization.py b/src/egressweave/_policy_normalization.py index 0a190a5d..52ecdb86 100644 --- a/src/egressweave/_policy_normalization.py +++ b/src/egressweave/_policy_normalization.py @@ -164,7 +164,7 @@ def _normalize_allowed_method(value: object) -> str: is never accepted: its semantics create an application-layer tunnel whose destination is independent of the validated URL authority. """ - if not isinstance(value, str): + if type(value) is not str: raise TypeError("allowed_methods entries must be HTTP method strings") normalized = value.strip().upper() From 9492bc952502d1aedf164e42ee035c7ed24f1844 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:23:00 +0900 Subject: [PATCH 08/12] fix(security): reject subclass-controlled method list splitting --- src/egressweave/policy.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/egressweave/policy.py b/src/egressweave/policy.py index 1c69a1ff..159b66db 100644 --- a/src/egressweave/policy.py +++ b/src/egressweave/policy.py @@ -69,6 +69,13 @@ ) +def _split_exact_method_string(value: object) -> list[str]: + """Split a comma-separated method list only after exact-string validation.""" + if type(value) is not str: + raise TypeError("allowed_methods must use exact built-in strings") + return value.split(",") + + @dataclass(frozen=True) class EgressPolicy: """Immutable outbound-egress allowlist and resource policy. @@ -244,7 +251,7 @@ def __post_init__(self) -> None: method_values: Iterable[object] if isinstance(self.allowed_methods, str): - method_values = self.allowed_methods.split(",") + method_values = _split_exact_method_string(self.allowed_methods) else: method_values = self.allowed_methods normalized_methods = frozenset( @@ -371,7 +378,7 @@ def from_hosts( method_items: Iterable[str] if isinstance(allowed_methods, str): - method_items = allowed_methods.split(",") + method_items = _split_exact_method_string(allowed_methods) else: method_items = allowed_methods @@ -434,7 +441,7 @@ def from_authorities( ) method_items: Iterable[str] if isinstance(allowed_methods, str): - method_items = allowed_methods.split(",") + method_items = _split_exact_method_string(allowed_methods) else: method_items = allowed_methods From fe1070002080c66c83a989657795c660296c3d71 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:37:33 +0900 Subject: [PATCH 09/12] test: require method-policy documentation parity --- tests/test_policy_method_value_integrity.py | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/test_policy_method_value_integrity.py b/tests/test_policy_method_value_integrity.py index b4c12912..c80c8ee3 100644 --- a/tests/test_policy_method_value_integrity.py +++ b/tests/test_policy_method_value_integrity.py @@ -2,6 +2,8 @@ from __future__ import annotations +from pathlib import Path + import pytest from egressweave.policy import EgressPolicy @@ -61,3 +63,32 @@ def test_from_authorities_rejects_str_subclass_before_comma_split() -> None: [("api.example.com", 443)], allowed_methods=_ExplodingMethodList("GET,POST"), ) + + +def test_runtime_method_authorization_rejects_str_subclass_before_normalization() -> None: + """Reject subclass-controlled normalization at the request authorization boundary.""" + policy = EgressPolicy.from_hosts( + "api.example.com", + allowed_methods={"GET"}, + ) + + assert policy.allows_http_method(_NonExactMethod("GET")) is False + + +def test_policy_configuration_integrity_guide_covers_exact_method_strings() -> None: + """Document the exact HTTP method value boundary and preserved string syntax.""" + guide = Path("docs/research/policy-configuration-integrity.md").read_text( + encoding="utf-8" + ) + + assert "exact built-in `str`" in guide + assert "HTTP method" in guide + assert "comma-separated" in guide + assert "does not make EgressWeave a Python sandbox" in guide + + +def test_changelog_records_http_method_value_sealing() -> None: + """Record the method-string policy tightening in release history.""" + changelog = Path("CHANGELOG.md").read_text(encoding="utf-8") + + assert "Reject non-exact string subclasses in HTTP method policy values" in changelog From 119d06e1adbaf220e8a1f10f5b06880ba8a95e6d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:46:59 +0900 Subject: [PATCH 10/12] docs: seal HTTP method policy string values --- .../policy-configuration-integrity.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/research/policy-configuration-integrity.md b/docs/research/policy-configuration-integrity.md index ea35b13f..9c0c4dfb 100644 --- a/docs/research/policy-configuration-integrity.md +++ b/docs/research/policy-configuration-integrity.md @@ -20,6 +20,21 @@ request/response byte budgets. It does not change configured defaults, allowed ranges, authority pairing, DNS policy, TLS identity, proxy isolation, HTTP method policy, request/response framing, or the generic request-time denial boundary. +HTTP method policy values are sealed at the same trusted startup boundary. Each +method value must be an exact built-in `str` before trimming, uppercase +canonicalization, or RFC 9110 token validation can invoke string behavior. +Supported comma-separated operator syntax remains available only when the outer +configuration value itself is an exact built-in `str`; non-exact string +subclasses are rejected before `split()` can run. Runtime method authorization +uses the same exact-string boundary and returns the existing generic denial for +unsupported caller values. + +This method-value restriction preserves the documented default and deny-all sets, +ordinary exact strings, comma-separated ergonomics, uppercase canonicalization, +RFC 9110 token validation, and unconditional `CONNECT` denial. It does not make +EgressWeave a Python sandbox: arbitrary trusted Python already executing in the +embedding process retains ordinary Python capabilities. + ## Why exact type matters at this boundary Python deliberately supports subclassing immutable built-in types such as `int`, @@ -61,6 +76,11 @@ integrations. 7. Regression tests exercise the public `EgressPolicy` constructors so the contract is proven at the API boundary rather than only against internal helpers. +8. HTTP method entries and supported comma-separated method configuration must + be exact built-in strings before any subclass-controllable normalization or + splitting operation. +9. Runtime HTTP method authorization rejects non-exact string subclasses without + invoking their normalization methods. ## Operator migration @@ -70,6 +90,12 @@ resource budgets should materialize an exact built-in integer before policy construction. This is a pre-1.0 tightening of an ambiguous configuration shape; it does not widen egress authority or change any finite default. +Applications that supply ordinary method strings or the existing comma-separated +method syntax also need no change. Integrations that pass subclasses of `str` for +method configuration should materialize exact built-in strings before policy +construction. This is likewise a supported-value tightening, not an expansion of +HTTP authority. + ## Reference — APA 7th Python Software Foundation. (2026). *Data model — Python 3.14.6 documentation*. From 9e87ec675b4f6f3134d4bdffd95ccb239b308754 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:49:21 +0900 Subject: [PATCH 11/12] docs: record exact HTTP method string sealing --- CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 597c636e..a96af541 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). retaining trusted configuration state. Exact built-in integers and existing ASCII decimal strings remain supported, preserving defaults and ranges while preventing subclass-controlled values from crossing immutable policy construction. +- Reject non-exact string subclasses in HTTP method policy values before + normalization or comma-separated parsing. Exact built-in strings and existing + comma-separated syntax remain supported, while runtime authorization rejects + subclass-controlled values before method normalization. - Pin the credential-free verifier to a reviewed Python 3.13 `python@sha256:<64-hex>` digest, validate it before Docker execution, and remove mutable-tag and `RepoDigests` promotion from the verifier boundary. @@ -357,7 +361,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). authority-drift rejection, proxy/redirect isolation, and Unix-socket refusal as the asynchronous transport, while retrying validated addresses within one caller-supplied connection-timeout budget. - ### Security - Isolate autonomous maintenance across credential-separated runners. A protected guard now rejects out-of-bound patch metadata and files, while @@ -397,4 +400,4 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). gap (CWE-350), with redirects and environment proxies disabled. - `EgressNotAllowedError` (a `ValueError` subclass) and `ValidatedEgressURL`. - 35 tests covering URL rejection, address classification, the `allow_local` - container case, DNS-to-private rejection, and transport pinning. + container case, DNS-to-private rejection, and transport pinning. \ No newline at end of file From 365a38820474b4e8a5325b02dbdf3aa1a6f24a37 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 02:51:16 +0900 Subject: [PATCH 12/12] chore: preserve changelog formatting --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a96af541..0bb802a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -361,6 +361,7 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). authority-drift rejection, proxy/redirect isolation, and Unix-socket refusal as the asynchronous transport, while retrying validated addresses within one caller-supplied connection-timeout budget. + ### Security - Isolate autonomous maintenance across credential-separated runners. A protected guard now rejects out-of-bound patch metadata and files, while @@ -400,4 +401,4 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). gap (CWE-350), with redirects and environment proxies disabled. - `EgressNotAllowedError` (a `ValueError` subclass) and `ValidatedEgressURL`. - 35 tests covering URL rejection, address classification, the `allow_local` - container case, DNS-to-private rejection, and transport pinning. \ No newline at end of file + container case, DNS-to-private rejection, and transport pinning.