From 5d2640d993490e50bcbc30492740da4a1775a634 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2026 22:19:48 +0000 Subject: [PATCH 1/7] deps: bump sse-starlette Bumps the uv-all-updates group with 1 update: [sse-starlette](https://github.com/sysid/sse-starlette). Updates `sse-starlette` from 3.4.11 to 3.5.0 - [Release notes](https://github.com/sysid/sse-starlette/releases) - [Commits](https://github.com/sysid/sse-starlette/compare/v3.4.11...v3.5.0) --- updated-dependencies: - dependency-name: sse-starlette dependency-version: 3.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: uv-all-updates ... Signed-off-by: dependabot[bot] --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index 5360519..7bf0430 100644 --- a/uv.lock +++ b/uv.lock @@ -1957,15 +1957,15 @@ asyncio = [ [[package]] name = "sse-starlette" -version = "3.4.11" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2b/54/6767bb789b2f2fed6e0f953df949cd39dc263a384c1b65a95232598621d6/sse_starlette-3.4.11.tar.gz", hash = "sha256:1bae716c02f3e6f294be41ff333220692dae7c3cbab077c900f159676719dade", size = 34972, upload-time = "2026-09-05T12:11:04.607Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/be/0123026f719d1a7936f214a88b553bb5701e04ff2511147c1dab0c5035eb/sse_starlette-3.5.0.tar.gz", hash = "sha256:75de713aa8a9441513cc283220826da079d982770965b951e9437720e8bafdb2", size = 36794, upload-time = "2026-09-28T17:48:14.7Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/6a/2ba3ed4a69babf3afdddf7d8314a48d87562c0a442206bbc2a1b50d5efc0/sse_starlette-3.4.11-py3-none-any.whl", hash = "sha256:c7b2244bdff016fe7f64e10075e89a3e6bbf899649cc89b0fe884b5545042453", size = 17122, upload-time = "2026-09-05T12:11:03.195Z" }, + { url = "https://files.pythonhosted.org/packages/be/e4/cdda14023c316d71493bc54fdffc3dd006631b88866145c9d3cc33e0f1df/sse_starlette-3.5.0-py3-none-any.whl", hash = "sha256:3e6e1070df3f0f5d9cea81496de92dbb72f6721871d99748ece67441dd8b7997", size = 17407, upload-time = "2026-09-28T17:48:13.228Z" }, ] [[package]] From 63b9c94575cb108651cf8634891f84bffe64ea52 Mon Sep 17 00:00:00 2001 From: "jjliu@ubuntu.home" Date: Fri, 2 Oct 2026 10:04:04 +0800 Subject: [PATCH 2/7] fix(deps): clear runtime and dev dependency audits - urllib3: add runtime floor >=2.8.0 for PYSEC-2026-4175/4176/4177 (via requests <- google-api-core <- a2a-sdk) and lock to 2.8.0 - virtualenv: refresh to 21.14.3 for PYSEC-2026-4011/4012/4013/4014 Refs #536 --- pyproject.toml | 2 ++ uv.lock | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 41de429..7c97f93 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,8 @@ dependencies = [ "pyasn1>=0.6.4", "sqlalchemy[asyncio]>=2.0,<3.0", "sse-starlette>=2.1,<4.0", + # urllib3: PYSEC-2026-4175/4176/4177 (via requests <- google-api-core <- a2a-sdk). + "urllib3>=2.8.0", "uvicorn>=0.29,<1.0", ] diff --git a/uv.lock b/uv.lock index 7bf0430..bad60ec 100644 --- a/uv.lock +++ b/uv.lock @@ -1300,6 +1300,7 @@ dependencies = [ { name = "pydantic-settings" }, { name = "sqlalchemy", extra = ["asyncio"] }, { name = "sse-starlette" }, + { name = "urllib3" }, { name = "uvicorn" }, ] @@ -1340,6 +1341,7 @@ requires-dist = [ { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.5,<0.17" }, { name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0,<3.0" }, { name = "sse-starlette", specifier = ">=2.1,<4.0" }, + { name = "urllib3", specifier = ">=2.8.0" }, { name = "uvicorn", specifier = ">=0.29,<1.0" }, ] provides-extras = ["migrations", "dev"] @@ -1723,14 +1725,14 @@ wheels = [ [[package]] name = "python-discovery" -version = "1.5.2" +version = "1.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/b7/ac44da2cf0e53ada0e419033c2d058219c95dc1403126f163304c9e814b1/python_discovery-1.5.2.tar.gz", hash = "sha256:45fd4f20a4e3f9b7bf2e0817870bc8e3b320a19658da177af800768c82dbf354", size = 82350, upload-time = "2026-08-12T14:05:26.419Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/57/250bd238b966cece44328235eb85290045d059265fdaf7527a3a958123db/python_discovery-1.6.1.tar.gz", hash = "sha256:cf87d3627dfb4412437fdd5b13eae402607722998d21567993aedbc59b23c15e", size = 84338, upload-time = "2026-09-18T01:31:53.971Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/45/689603d04b3bb8d7faa00f25c24acef993aab7813b3dbbfc472a459ab0b5/python_discovery-1.5.2-py3-none-any.whl", hash = "sha256:3e338c2d0f15dfaeea57493f4c2c6caebe0e998ea815c30ae8bf8ee21f1112d3", size = 38350, upload-time = "2026-08-12T14:05:25.113Z" }, + { url = "https://files.pythonhosted.org/packages/16/7d/e9ffbadfbf89c93848412d04594135c4ae8c1d37d9e053b9c3ed718fabc4/python_discovery-1.6.1-py3-none-any.whl", hash = "sha256:d43fcdef879fe795352bd13ccf8d185ba5a9f86f36cfcd00529f596e737442b3", size = 38664, upload-time = "2026-09-18T01:31:52.448Z" }, ] [[package]] @@ -2067,11 +2069,11 @@ wheels = [ [[package]] name = "urllib3" -version = "2.7.0" +version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size = 458972, upload-time = "2026-09-15T19:29:36.253Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, + { url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size = 135717, upload-time = "2026-09-15T19:29:34.577Z" }, ] [[package]] @@ -2089,17 +2091,18 @@ wheels = [ [[package]] name = "virtualenv" -version = "21.7.4" +version = "21.14.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, + { name = "packaging" }, { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2d/dc/a6eb1ddfa7f1e390fa599b078453c97edb3f6f846b34fb4eac3e8ea16401/virtualenv-21.7.4.tar.gz", hash = "sha256:c9d960c95fa458171e58222a5ccab7465298e4b6559977865e627c4719f1e825", size = 5345511, upload-time = "2026-08-10T22:54:33.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/59/5ebdaa984350ae7ef1dc14b4d0bd618f6e0d3fb13e7b336939433eebf37b/virtualenv-21.14.3.tar.gz", hash = "sha256:cb5cd3a87f12a6cfdc0cef6bc8bead6138221767f7718e0c00fee5fb907f9858", size = 5464634, upload-time = "2026-10-01T22:55:31.895Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/4c/eb2f52aeeaf30dbd073d315a251a63ae2b8263171ec4428c135140cb0802/virtualenv-21.7.4-py3-none-any.whl", hash = "sha256:376ec93cd6aab3044fa395d7db226db38043b7b5748948044b2a87168525e843", size = 5324444, upload-time = "2026-08-10T22:54:31.515Z" }, + { url = "https://files.pythonhosted.org/packages/5c/dc/33782ebe90eb4e582295642c5c13e874b5a8c9c75d482988c54f1c21a5d4/virtualenv-21.14.3-py3-none-any.whl", hash = "sha256:4acc848a57a3bdb2ae0873d0689664bccad2230784de3753f57128eb126d3934", size = 5487108, upload-time = "2026-10-01T22:55:29.913Z" }, ] [[package]] From 2f706e3b5ff5f99c824b75dc130286211d05f5f3 Mon Sep 17 00:00:00 2001 From: "jjliu@ubuntu.home" Date: Fri, 2 Oct 2026 10:18:01 +0800 Subject: [PATCH 3/7] test(deps): cover urllib3 floor in dependency contract and docs - parametrize the installed-metadata floor test with urllib3 2.7.0 -> 2.8.0 - list urllib3>=2.8.0 alongside the existing floors in compatibility and guide docs Refs #536 --- docs/compatibility.md | 2 +- docs/guide.md | 2 +- tests/package/test_dependency_contract.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/compatibility.md b/docs/compatibility.md index 47891d5..7782cd0 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -24,7 +24,7 @@ The [SDK 1.1.2 to 1.1.5 changes](https://github.com/a2aproject/a2a-python/compar | Request-handler hooks and queue lifecycle | Retained for output negotiation, cancel idempotency, and persistence after client disconnect. Handler regressions exercise these behaviors against the pinned SDK; private hooks remain an SDK upgrade review boundary. | | Outbound header forwarding | Uses the SDK `service_parameters` channel. Client transport tests check the final HTTP request, including authentication and tracing headers. | | Protobuf | Supports `>=6.33.5,<8.0`. The default CI uses locked 7.36.2; a separate Python 3.11 job installs 6.33.6 and disables uv synchronization throughout the test process tree, so nested protocol probes also exercise protobuf 6. SDK 1.1.5 removes the former protobuf 7 blocker, so the obsolete Dependabot ignore is removed. | -| Security floors | `click>=8.3.3` and `pyasn1>=0.6.4` remain necessary because upstream metadata permits older versions. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect these floors and the SQLAlchemy asyncio extra. | +| Security floors | `click>=8.3.3`, `pyasn1>=0.6.4`, and `urllib3>=2.8.0` remain necessary because upstream metadata permits older versions. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect these floors and the SQLAlchemy asyncio extra. | The missing-import typing overrides for `google.protobuf.*` and `jsonrpc.*` remain limited to those third-party modules. Runtime support is validated by the SDK and transport regressions, not inferred from the typing overrides. Ruff's local pre-commit hooks run through `uv run --locked --extra dev`, so `uv.lock` is the single version source for linting and formatting. diff --git a/docs/guide.md b/docs/guide.md index 877e2b6..b67d550 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -215,7 +215,7 @@ Empty SQLite URLs, `:memory:` URLs, and `mode=memory` URIs explicitly use `Stati The package declares `sqlalchemy[asyncio]` so standalone installs such as `uv tool install opencode-a2a` include `greenlet`, which is required by the async database engine. SQLAlchemy 2.1 no longer installs `greenlet` by default; declaring the extra in package metadata keeps wheel installs independent of the repository's `uv.lock`. -Published package metadata also enforces the security floors `click>=8.3.3` and `pyasn1>=0.6.4`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. +Published package metadata also enforces the security floors `click>=8.3.3`, `pyasn1>=0.6.4`, and `urllib3>=2.8.0`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. Unhandled execution errors and shutdown interruptions persist `FAILED` when storage is available, preserving existing terminal states. Shutdown drains buffered output before closing clients and stores. SSE disconnects allow execution to continue; use `CancelTask` to request an upstream abort before stopping the application. diff --git a/tests/package/test_dependency_contract.py b/tests/package/test_dependency_contract.py index 5a5658a..096c47d 100644 --- a/tests/package/test_dependency_contract.py +++ b/tests/package/test_dependency_contract.py @@ -17,7 +17,7 @@ def _runtime_requirement(name: str) -> Requirement: @pytest.mark.parametrize( ("name", "unsafe_version", "safe_version"), - [("click", "8.3.2", "8.3.3"), ("pyasn1", "0.6.3", "0.6.4")], + [("click", "8.3.2", "8.3.3"), ("pyasn1", "0.6.3", "0.6.4"), ("urllib3", "2.7.0", "2.8.0")], ) def test_installed_metadata_enforces_security_floors( name: str, unsafe_version: str, safe_version: str From cb5fab28c5ab89d614a48ddaf7a71281cd8c4202 Mon Sep 17 00:00:00 2001 From: "jjliu@ubuntu.home" Date: Fri, 2 Oct 2026 10:30:49 +0800 Subject: [PATCH 4/7] revert(deps): keep dependency floors in dependency files only The urllib3 security floor is declared in pyproject.toml and locked in uv.lock, which stay the single source of truth for dependency management. Revert the duplicated mention added in 2f706e3 so docs and dependency-contract tests remain identical to main. Refs #536 --- docs/compatibility.md | 2 +- docs/guide.md | 2 +- tests/package/test_dependency_contract.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/compatibility.md b/docs/compatibility.md index 7782cd0..47891d5 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -24,7 +24,7 @@ The [SDK 1.1.2 to 1.1.5 changes](https://github.com/a2aproject/a2a-python/compar | Request-handler hooks and queue lifecycle | Retained for output negotiation, cancel idempotency, and persistence after client disconnect. Handler regressions exercise these behaviors against the pinned SDK; private hooks remain an SDK upgrade review boundary. | | Outbound header forwarding | Uses the SDK `service_parameters` channel. Client transport tests check the final HTTP request, including authentication and tracing headers. | | Protobuf | Supports `>=6.33.5,<8.0`. The default CI uses locked 7.36.2; a separate Python 3.11 job installs 6.33.6 and disables uv synchronization throughout the test process tree, so nested protocol probes also exercise protobuf 6. SDK 1.1.5 removes the former protobuf 7 blocker, so the obsolete Dependabot ignore is removed. | -| Security floors | `click>=8.3.3`, `pyasn1>=0.6.4`, and `urllib3>=2.8.0` remain necessary because upstream metadata permits older versions. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect these floors and the SQLAlchemy asyncio extra. | +| Security floors | `click>=8.3.3` and `pyasn1>=0.6.4` remain necessary because upstream metadata permits older versions. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect these floors and the SQLAlchemy asyncio extra. | The missing-import typing overrides for `google.protobuf.*` and `jsonrpc.*` remain limited to those third-party modules. Runtime support is validated by the SDK and transport regressions, not inferred from the typing overrides. Ruff's local pre-commit hooks run through `uv run --locked --extra dev`, so `uv.lock` is the single version source for linting and formatting. diff --git a/docs/guide.md b/docs/guide.md index b67d550..877e2b6 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -215,7 +215,7 @@ Empty SQLite URLs, `:memory:` URLs, and `mode=memory` URIs explicitly use `Stati The package declares `sqlalchemy[asyncio]` so standalone installs such as `uv tool install opencode-a2a` include `greenlet`, which is required by the async database engine. SQLAlchemy 2.1 no longer installs `greenlet` by default; declaring the extra in package metadata keeps wheel installs independent of the repository's `uv.lock`. -Published package metadata also enforces the security floors `click>=8.3.3`, `pyasn1>=0.6.4`, and `urllib3>=2.8.0`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. +Published package metadata also enforces the security floors `click>=8.3.3` and `pyasn1>=0.6.4`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. Unhandled execution errors and shutdown interruptions persist `FAILED` when storage is available, preserving existing terminal states. Shutdown drains buffered output before closing clients and stores. SSE disconnects allow execution to continue; use `CancelTask` to request an upstream abort before stopping the application. diff --git a/tests/package/test_dependency_contract.py b/tests/package/test_dependency_contract.py index 096c47d..5a5658a 100644 --- a/tests/package/test_dependency_contract.py +++ b/tests/package/test_dependency_contract.py @@ -17,7 +17,7 @@ def _runtime_requirement(name: str) -> Requirement: @pytest.mark.parametrize( ("name", "unsafe_version", "safe_version"), - [("click", "8.3.2", "8.3.3"), ("pyasn1", "0.6.3", "0.6.4"), ("urllib3", "2.7.0", "2.8.0")], + [("click", "8.3.2", "8.3.3"), ("pyasn1", "0.6.3", "0.6.4")], ) def test_installed_metadata_enforces_security_floors( name: str, unsafe_version: str, safe_version: str From e068f45e3b9222d7cc145e502c4def8921da1e6f Mon Sep 17 00:00:00 2001 From: "jjliu@ubuntu.home" Date: Fri, 2 Oct 2026 10:51:37 +0800 Subject: [PATCH 5/7] refactor(deps): drop duplicated dependency versions from docs and tests Remove the security-floor and version-range literals that restated what pyproject.toml and uv.lock already declare, in docs/compatibility.md, docs/guide.md, and tests/package/test_dependency_contract.py. Keep the installed-metadata assertion for the sqlalchemy asyncio extra, which expresses a packaging contract rather than a version restatement. Dependency files remain the single source of truth. Refs #536 --- docs/compatibility.md | 4 ++-- docs/guide.md | 2 +- tests/package/test_dependency_contract.py | 24 ----------------------- 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/docs/compatibility.md b/docs/compatibility.md index 47891d5..30f1038 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -23,8 +23,8 @@ The [SDK 1.1.2 to 1.1.5 changes](https://github.com/a2aproject/a2a-python/compar | Legacy stored task conversion | Retained for SDK-owned persisted rows. This does not restore legacy A2A 0.3 wire support. | | Request-handler hooks and queue lifecycle | Retained for output negotiation, cancel idempotency, and persistence after client disconnect. Handler regressions exercise these behaviors against the pinned SDK; private hooks remain an SDK upgrade review boundary. | | Outbound header forwarding | Uses the SDK `service_parameters` channel. Client transport tests check the final HTTP request, including authentication and tracing headers. | -| Protobuf | Supports `>=6.33.5,<8.0`. The default CI uses locked 7.36.2; a separate Python 3.11 job installs 6.33.6 and disables uv synchronization throughout the test process tree, so nested protocol probes also exercise protobuf 6. SDK 1.1.5 removes the former protobuf 7 blocker, so the obsolete Dependabot ignore is removed. | -| Security floors | `click>=8.3.3` and `pyasn1>=0.6.4` remain necessary because upstream metadata permits older versions. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect these floors and the SQLAlchemy asyncio extra. | +| Protobuf | The supported `protobuf` range is declared in `pyproject.toml`. The default CI exercises the locked release; a separate Python 3.11 job installs the supported protobuf 6 release and disables uv synchronization throughout the test process tree, so nested protocol probes also exercise protobuf 6. SDK 1.1.5 removes the former protobuf 7 blocker, so the obsolete Dependabot ignore is removed. | +| Security floors | Upstream metadata can permit older, vulnerable releases of transitive runtime dependencies, so the package declares explicit floors for them; the authoritative list is `pyproject.toml`. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect the SQLAlchemy asyncio extra. | The missing-import typing overrides for `google.protobuf.*` and `jsonrpc.*` remain limited to those third-party modules. Runtime support is validated by the SDK and transport regressions, not inferred from the typing overrides. Ruff's local pre-commit hooks run through `uv run --locked --extra dev`, so `uv.lock` is the single version source for linting and formatting. diff --git a/docs/guide.md b/docs/guide.md index 877e2b6..3b567eb 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -215,7 +215,7 @@ Empty SQLite URLs, `:memory:` URLs, and `mode=memory` URIs explicitly use `Stati The package declares `sqlalchemy[asyncio]` so standalone installs such as `uv tool install opencode-a2a` include `greenlet`, which is required by the async database engine. SQLAlchemy 2.1 no longer installs `greenlet` by default; declaring the extra in package metadata keeps wheel installs independent of the repository's `uv.lock`. -Published package metadata also enforces the security floors `click>=8.3.3` and `pyasn1>=0.6.4`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. +Published package metadata also enforces the explicit security floors for transitive runtime dependencies; the authoritative list is declared in `pyproject.toml`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. Unhandled execution errors and shutdown interruptions persist `FAILED` when storage is available, preserving existing terminal states. Shutdown drains buffered output before closing clients and stores. SSE disconnects allow execution to continue; use `CancelTask` to request an upstream abort before stopping the application. diff --git a/tests/package/test_dependency_contract.py b/tests/package/test_dependency_contract.py index 5a5658a..fb6769c 100644 --- a/tests/package/test_dependency_contract.py +++ b/tests/package/test_dependency_contract.py @@ -1,6 +1,5 @@ from importlib.metadata import requires -import pytest from packaging.requirements import Requirement @@ -15,29 +14,6 @@ def _runtime_requirement(name: str) -> Requirement: return requirements[0] -@pytest.mark.parametrize( - ("name", "unsafe_version", "safe_version"), - [("click", "8.3.2", "8.3.3"), ("pyasn1", "0.6.3", "0.6.4")], -) -def test_installed_metadata_enforces_security_floors( - name: str, unsafe_version: str, safe_version: str -) -> None: - requirement = _runtime_requirement(name) - assert unsafe_version not in requirement.specifier - assert safe_version in requirement.specifier - - def test_installed_metadata_requests_sqlalchemy_asyncio() -> None: requirement = _runtime_requirement("sqlalchemy") assert "asyncio" in requirement.extras - assert "2.0.54" in requirement.specifier - assert "2.1.1" in requirement.specifier - assert "3.0.0" not in requirement.specifier - - -def test_installed_metadata_bounds_supported_protobuf_versions() -> None: - requirement = _runtime_requirement("protobuf") - assert "6.33.4" not in requirement.specifier - assert "6.33.5" in requirement.specifier - assert "7.36.2" in requirement.specifier - assert "8.0.0" not in requirement.specifier From b33e34202c0a8354b1b95c4787b50d91c0b435fc Mon Sep 17 00:00:00 2001 From: "jjliu@ubuntu.home" Date: Fri, 2 Oct 2026 10:57:28 +0800 Subject: [PATCH 6/7] docs(deps): drop remaining SQLAlchemy version literal from guide The guide keeps the rationale for the sqlalchemy[asyncio] extra without restating an upstream release number. Refs #536 --- docs/guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide.md b/docs/guide.md index 3b567eb..ae634b6 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -213,7 +213,7 @@ The runtime configures local durability-oriented SQLite connection settings (`WA Empty SQLite URLs, `:memory:` URLs, and `mode=memory` URIs explicitly use `StaticPool` to share one database connection across checkouts. This preserves the existing ephemeral database behavior when SQLAlchemy changes its automatic pool selection. File-backed databases retain SQLAlchemy's default connection pool and the file hardening described below. -The package declares `sqlalchemy[asyncio]` so standalone installs such as `uv tool install opencode-a2a` include `greenlet`, which is required by the async database engine. SQLAlchemy 2.1 no longer installs `greenlet` by default; declaring the extra in package metadata keeps wheel installs independent of the repository's `uv.lock`. +The package declares `sqlalchemy[asyncio]` so standalone installs such as `uv tool install opencode-a2a` include `greenlet`, which is required by the async database engine. SQLAlchemy no longer installs `greenlet` by default; declaring the extra in package metadata keeps wheel installs independent of the repository's `uv.lock`. Published package metadata also enforces the explicit security floors for transitive runtime dependencies; the authoritative list is declared in `pyproject.toml`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. From 949379d17b172105fab273838cef52bf5df2aa18 Mon Sep 17 00:00:00 2001 From: "jjliu@ubuntu.home" Date: Fri, 2 Oct 2026 11:04:13 +0800 Subject: [PATCH 7/7] docs: drop dependency-management details from compatibility and guide Remove descriptions that restated dependency policy handled by pyproject.toml, uv.lock, and CI config: the protobuf range/CI matrix and security-floor rows, the uv.lock lint-source note, the SDK pin/upgrade guidance, the sqlalchemy[asyncio] declaration note, and the pinned-SDK wording. Compatibility promises and adapter review decisions stay intact. Refs #536 --- docs/compatibility.md | 12 +++++------- docs/guide.md | 6 +----- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/docs/compatibility.md b/docs/compatibility.md index 30f1038..ed75718 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -11,22 +11,20 @@ This document defines the compatibility promises `opencode-a2a` currently uphold This is the single canonical place where the supported upstream OpenCode version line is declared. Keep it updated together with the live integration smoke check (`./scripts/live_opencode_smoke.sh`) and do not duplicate the version line elsewhere. -The repository currently pins one concrete SDK release in `pyproject.toml` within that v1 line. Upgrade the SDK deliberately rather than relying on floating dependency resolution. The SDK-owned core JSON-RPC method set follows that pinned release and is locked by repository tests so SDK upgrades trigger an explicit compatibility review. +The SDK-owned core JSON-RPC method set follows the supported SDK line and is locked by repository tests so SDK upgrades trigger an explicit compatibility review. -### SDK and Dependency Review +### SDK and Adapter Review -The [SDK 1.1.2 to 1.1.5 changes](https://github.com/a2aproject/a2a-python/compare/v1.1.2...v1.1.5) include cross-event-loop locking fixes, task-list ordering fixes, and protobuf 7 support. The adapter's reviewed integration boundaries are: +The [SDK 1.1.2 to 1.1.5 changes](https://github.com/a2aproject/a2a-python/compare/v1.1.2...v1.1.5) include cross-event-loop locking fixes and task-list ordering fixes. The adapter's reviewed integration boundaries are: | Boundary | Decision and regression evidence | | --- | --- | | `DatabaseTaskStoreCompat` | Retained: SDK `DatabaseTaskStore.save` still performs an unconditional ORM merge. The adapter needs an atomic first-terminal-state-wins guard; task-store tests cover shape drift, ORM conversion parity, and independent store instances. | | Legacy stored task conversion | Retained for SDK-owned persisted rows. This does not restore legacy A2A 0.3 wire support. | -| Request-handler hooks and queue lifecycle | Retained for output negotiation, cancel idempotency, and persistence after client disconnect. Handler regressions exercise these behaviors against the pinned SDK; private hooks remain an SDK upgrade review boundary. | +| Request-handler hooks and queue lifecycle | Retained for output negotiation, cancel idempotency, and persistence after client disconnect. Handler regressions exercise these behaviors against the SDK; private hooks remain an SDK upgrade review boundary. | | Outbound header forwarding | Uses the SDK `service_parameters` channel. Client transport tests check the final HTTP request, including authentication and tracing headers. | -| Protobuf | The supported `protobuf` range is declared in `pyproject.toml`. The default CI exercises the locked release; a separate Python 3.11 job installs the supported protobuf 6 release and disables uv synchronization throughout the test process tree, so nested protocol probes also exercise protobuf 6. SDK 1.1.5 removes the former protobuf 7 blocker, so the obsolete Dependabot ignore is removed. | -| Security floors | Upstream metadata can permit older, vulnerable releases of transitive runtime dependencies, so the package declares explicit floors for them; the authoritative list is `pyproject.toml`. They are runtime requirements so wheel and sdist installs enforce them without uv-specific constraints. Installed-metadata tests protect the SQLAlchemy asyncio extra. | -The missing-import typing overrides for `google.protobuf.*` and `jsonrpc.*` remain limited to those third-party modules. Runtime support is validated by the SDK and transport regressions, not inferred from the typing overrides. Ruff's local pre-commit hooks run through `uv run --locked --extra dev`, so `uv.lock` is the single version source for linting and formatting. +The missing-import typing overrides for `google.protobuf.*` and `jsonrpc.*` remain limited to those third-party modules. Runtime support is validated by the SDK and transport regressions, not inferred from the typing overrides. ## Contract Honesty diff --git a/docs/guide.md b/docs/guide.md index ae634b6..8d6ef94 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -213,10 +213,6 @@ The runtime configures local durability-oriented SQLite connection settings (`WA Empty SQLite URLs, `:memory:` URLs, and `mode=memory` URIs explicitly use `StaticPool` to share one database connection across checkouts. This preserves the existing ephemeral database behavior when SQLAlchemy changes its automatic pool selection. File-backed databases retain SQLAlchemy's default connection pool and the file hardening described below. -The package declares `sqlalchemy[asyncio]` so standalone installs such as `uv tool install opencode-a2a` include `greenlet`, which is required by the async database engine. SQLAlchemy no longer installs `greenlet` by default; declaring the extra in package metadata keeps wheel installs independent of the repository's `uv.lock`. - -Published package metadata also enforces the explicit security floors for transitive runtime dependencies; the authoritative list is declared in `pyproject.toml`. These apply to standalone wheel/sdist installs as well as repository environments; no separate uv constraint configuration is needed. - Unhandled execution errors and shutdown interruptions persist `FAILED` when storage is available, preserving existing terminal states. Shutdown drains buffered output before closing clients and stores. SSE disconnects allow execution to continue; use `CancelTask` to request an upstream abort before stopping the application. ### SQLite Persistence Hardening @@ -364,7 +360,7 @@ Current behavior: - `all_jsonrpc_methods` is the runtime truth for the current deployment. - The current SDK-owned core JSON-RPC surface includes `GetExtendedAgentCard` and `tasks/pushNotificationConfig/*`. - The current SDK-owned REST surface also includes `GET /tasks` and the task push notification config routes. -- The SDK-owned core JSON-RPC method set follows the pinned `a2a-sdk` release and is locked by repository tests; review that surface deliberately when upgrading the SDK. +- The SDK-owned core JSON-RPC method set is locked by repository tests; review that surface deliberately when upgrading the SDK. - Push notification config routes/methods are currently exposed only because they are part of the SDK-owned core surface. This runtime does not configure a push config store or push sender, so operations return the A2A 1.0 `PushNotificationNotSupportedError` contract: HTTP `400` for REST and JSON-RPC code `-32003`. When `A2A_ENABLE_SESSION_SHELL=false`, `opencode.sessions.shell` is omitted from `all_jsonrpc_methods` and exposed only through `extensions.conditionally_available_methods`.