Repository navigation
fix: replace deprecated FieldDescriptor.label with is_repeated in proto_utils - #1158
Conversation
🧪 Code Coverage (vs
|
| Base | PR | Delta | |
|---|---|---|---|
| src/a2a/utils/proto_utils.py | 90.87% | 91.16% | 🟢 +0.30% |
| Total | 93.06% | 93.06% | 🟢 +0.01% |
Generated by coverage-comment.yml
…to_utils Use the non-deprecated FieldDescriptor.is_repeated property instead of comparing field.label to LABEL_REPEATED. Remove all TODO comments referencing issue a2aproject#1011. Closes a2aproject#1011 Co-Authored-By: Claude Opus 4.8 <[email protected]>
Covers the _recurse_validation path for repeated message fields (e.g. Task.history), which was not previously tested. Co-Authored-By: Claude Opus 4.8 <[email protected]>
8806d70 to
bc8fbad
Compare
mykytanetipa
left a comment
There was a problem hiding this comment.
Blocking: this breaks users on the supported protobuf floor, field.is_repeated only exists in protobuf ≥ 6.31.0, but current project.toml pins protobuf>=5.29.5,<7. For any user on 5.29.5 ≤ protobuf ≤ 6.30.2, the 3 changed sites raise AttributeError at runtime. CI is green only because it resolves to the 6.33.6 protobuf version, masking the floor violation.
Proof (minimum version):
cd /tmp && rm -rf pbcheck && mkdir pbcheck && cd pbcheck
python3 -m venv .venv
./.venv/bin/pip install "protobuf==5.29.5"
./.venv/bin/python -c "from google.protobuf.descriptor import FieldDescriptor; print(hasattr(FieldDescriptor,'is_repeated'))"
Looking in indexes: http://airlock-proxy.uplink.goog:999/python/artifact-foundry-prod/ah-3p-staging-python/simple/
Collecting protobuf==5.29.5
Downloading protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl (319 kB)
Installing collected packages: protobuf
Successfully installed protobuf-5.29.5
False
(also False through 6.30.2; True from 6.31.0)
Suggest approach that uses a temporal fallback helper at the 3 sites, but requires neither < 7 pin nor breaking change version bump at this moment:
def _field_is_repeated(field: FieldDescriptor) -> bool:
"""protobuf>=6.31.0 exposes is_repeated; older (our >=5.29.5 floor) does not."""
is_rep = getattr(field, 'is_repeated', None)
if is_rep is not None:
return is_rep
return field.label == FieldDescriptor.LABEL_REPEATED
## Outcome - Expose a reviewed Tesserix AgentRunner and AgentDefinition through the official A2A 1.x AgentExecutor contract. - Let Google ADK 2.8 consume that endpoint through its current non-legacy RemoteA2aAgent path. - Add bounded offline onboarding, a full integration guide and ADR, CI/release extra smoke coverage, and Contributor Covenant 2.1 with private reporting to [email protected]. - Keep the bridge model-provider neutral: Groq, xAI/Grok, OpenRouter, native providers, self-hosted runtimes, and custom gateways remain runner configuration. ## Contract and design - Authentication and per-agent authorization are injected through a required principal resolver; message metadata is never trusted as identity. - Execution binds the verified tenant and subject to the normal runner. Active-task cancellation requires the original tenant and subject, and unauthorized cancellation is non-enumerating. - Text input is bounded to 64 KiB and the final text or JSON artifact to 1 MiB by default. Internal exception text never crosses the A2A boundary. - Completion and cancellation races have a single terminal-state winner. - The official request handler and deployment-supplied TaskStore continue to own transport, durability, duplicate delivery, lookup, and resubscription. Production hosting must provide authentication middleware, durable task state, recovery, quotas, and any advertised push delivery. - The base install is unchanged. A2A HTTP server and Google ADK support remain explicit optional extras. - Design rationale and rollback are recorded in ADR 0003. ## Verification - make check: passed; 9,148 tests passed, 2 expected skips, 125 coverage-profile deselections, 98.97% total coverage, plus strict Ruff, formatting, import contracts, and mypy. - make audit, make secrets, make licences, make deps, and make admissions-check: passed. - uv lock --check: passed for the 153-package all-extras graph. - uv build: source archive and universal wheel built; wheel contents and source Code of Conduct were verified. - make docs-check and git diff --check: passed after the readiness update. - Fresh public clone of commit 0ae26f0: uv sync --frozen --extra google-adk, the offline bridge example, all 11 focused bridge tests, and uv build passed. - The narrow protobuf deprecation expectation tracks a2aproject/a2a-python#1158. - [x] Focused failing tests were added before implementation; readiness-only wording changes were documentation exceptions. - [x] make check passes. - [x] Consumer-visible documentation and release notes are current. - [x] Public API/event snapshots were regenerated when deliberately changed. - [x] New dependencies/extras have admission, licence, and security decisions. - [x] Tenant, authentication, secrets, untrusted input, and side effects were reviewed. - [x] No credential, customer content, or production endpoint is present. ## Rollout and rollback This is additive and requires no state or schema migration. Consumers opt into the A2A and/or Google ADK extras, mount official routes behind their authenticated gateway, and provide their chosen task store. Roll back by unmounting those routes and removing the optional extras; core runs, provider configuration, Tesserix peer integrations, and stored schemas are unchanged. No release tag or PyPI publication is part of this PR. Trusted-publisher authorization remains an external release prerequisite. Closes #292
…loor (a2aproject#1011) field.is_repeated is only available on protobuf>=6.31.0, but the project pins protobuf>=5.29.5. The three validation sites would raise AttributeError on 5.29.5<=protobuf<=6.30.2. Route them through a _field_is_repeated helper that falls back to field.label == LABEL_REPEATED on older protobuf. Addresses review on a2aproject#1158.
mykytanetipa
left a comment
There was a problem hiding this comment.
Please update description to match the _field_is_repeated approach, right now it references the older version
LGTM after description update
Removes the `protobuf<7` (and `types-protobuf<7`) upper bounds so the SDK can resolve protobuf 7.36.1, which addresses the vulnerability reported in protobuf 6.33.6. The deprecated `FieldDescriptor.label` usage that blocked protobuf 7 was already handled by the `_field_is_repeated` shim (a2aproject#1158). Fixes a2aproject#1234
…ction on <6.31 The declared floor claimed protobuf>=5.29.5 but the code required >=6.31: _proto_schema.field_schema() used bare `field.is_repeated`, which does not exist before protobuf 6.31.0, so building FastAPI/JSON-RPC route schemas raised AttributeError on protobuf 5.29.x-6.30.x. a2aproject#1158 fixed this in proto_utils but missed _proto_schema. - route both _proto_schema call sites through the guarded proto_utils._field_is_repeated() helper (is_repeated with a label fallback) - raise the floor to protobuf>=5.29.6: closes CVE-2026-0994 for the 5.x line (patched in 5.29.6) and matches google-api-core's own protobuf floor - re-lock (resolved protobuf unchanged at 7.36.2) Verified: full test suite passes on protobuf 5.29.6, 6.30.2, 6.33.6 and 7.36.2 (5.29.6 and 6.30.2 exercise the label fallback path).
_proto_schema.field_schema() used bare `field.is_repeated`, which does not exist before protobuf 6.31.0, so building FastAPI/JSON-RPC route schemas raised AttributeError on protobuf 5.29.x-6.30.x. a2aproject#1158 fixed this in proto_utils but missed _proto_schema. Route both call sites through the shared proto_utils._field_is_repeated() helper (is_repeated with a label fallback).
Removes the protobuf/types-protobuf < 7 upper bound so the SDK and makes the code type-check cleanly against the protobuf 7 stubs. __Context:__ The <7 cap was added in #1019 because protobuf 7 removed FieldDescriptor.label, crashing validate_proto_required_fields(). #1158 already made the runtime version-agnostic ("is_repeated" with a "label" fallback), so the ceiling is no longer needed. __Changes:__ - pyproject.toml: drop <7 from protobuf + drop <7 from types-protobuf. - re-locked uv.lock - Static-typing fixes for the stricter types-protobuf 7 stubs (all runtime behavior unchanged; full test suite passes) - field.is_repeated usage fixed in src/a2a/server/routes/_proto_schema.py __Validation:__ - Full test suite passes on protobuf 5.29.5, 6.33.6, 7.36.2 - `ty check`, `ruff check` all pass
🤖 I have created a release *beep* *boop* --- ## [1.1.5](v1.1.4...v1.1.5) (2026-09-21) ### Bug Fixes * **deps:** support protobuf 7 ([#1260](#1260)) ([67ba0a4](67ba0a4)) * replace deprecated FieldDescriptor.label with is_repeated in proto_utils ([#1158](#1158)) ([4554e2d](4554e2d)) * **server:** avoid out-of-range datetime task ordering ([#1220](#1220)) ([d55a3d3](d55a3d3)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
Summary
Closes #1011
This PR introduces a compatibility helper that prefers is_repeated when available and falls back to label otherwise, fixing the deprecation without bumping the minimum protobuf version (no breaking change for downstream consumers)
Changes
FieldDescriptor.labelwithis_repeatedinproto_utils#1011) comments.Verification
is_repeatedis available in the current minimumprotobuf>=5.29.5./scripts/lint.sh)