Skip to content

fix: replace deprecated FieldDescriptor.label with is_repeated in proto_utils - #1158

Merged
mykytanetipa merged 4 commits into
a2aproject:mainfrom
Linux2010:fix/1011-proto-utils-is-repeated-v2
Sep 15, 2026
Merged

mykytanetipa merged 4 commits into
a2aproject:mainfrom
Linux2010:fix/1011-proto-utils-is-repeated-v2

Conversation

@Linux2010

@Linux2010 Linux2010 commented Aug 2, 2026 •

Copy link
Copy Markdown
Contributor

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

  • src/a2a/utils/proto_utils.py:
  • tests/utils/test_proto_utils.py: add tests covering both helper branches (new is_repeated API and the legacy label fallback), plus repeated-nested-message validation (Task.history).

Verification

  • is_repeated is available in the current minimum protobuf>=5.29.5
  • All existing proto_utils tests pass (14 passed)
  • Lint passes (./scripts/lint.sh)

@Linux2010
Linux2010 requested a review from a team as a code owner August 2, 2026 15:44
@github-actions

github-actions Bot commented Aug 2, 2026 •

Copy link
Copy Markdown

🧪 Code Coverage (vs main)

⬇️ Download Full Report

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

Linux2010 and others added 2 commits August 14, 2026 22:08
…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]>
@Linux2010
Linux2010 force-pushed the fix/1011-proto-utils-is-repeated-v2 branch from 8806d70 to bc8fbad Compare August 14, 2026 14:08

@mykytanetipa mykytanetipa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Sam123ben added a commit to tesserix/agent-development-kit that referenced this pull request Aug 28, 2026
## 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 mykytanetipa left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update description to match the _field_is_repeated approach, right now it references the older version

LGTM after description update

@mykytanetipa
mykytanetipa merged commit 4554e2d into a2aproject:main Sep 15, 2026
17 checks passed
mykytanetipa added a commit to mykytanetipa/a2a-python that referenced this pull request Sep 15, 2026
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
mykytanetipa added a commit to mykytanetipa/a2a-python that referenced this pull request Sep 21, 2026
…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).
mykytanetipa added a commit to mykytanetipa/a2a-python that referenced this pull request Sep 21, 2026
_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).
mykytanetipa added a commit that referenced this pull request Sep 21, 2026
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
mykytanetipa pushed a commit that referenced this pull request Sep 21, 2026
🤖 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).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Task]: Replace deprecated FieldDescriptor.label with is_repeated in proto_utils

2 participants