feat(server): implement `Resource Scoping` for tasks and push notifications by sokoliva · Pull Request #709 · a2aproject/a2a-python · GitHub
Skip to content

feat(server): implement Resource Scoping for tasks and push notifications - #709

Merged
sokoliva merged 58 commits into
a2aproject:1.0-devfrom
sokoliva:resource-scoping
Feb 27, 2026
Merged

sokoliva merged 58 commits into
a2aproject:1.0-devfrom
sokoliva:resource-scoping

Conversation

@sokoliva

@sokoliva sokoliva commented Feb 18, 2026 •

Copy link
Copy Markdown
Member

Description

Introduces caller indentity isolation to ensure clients only access authorized resources, as mandated by the A2A spec.

  • Add ownerfield to TaskMixin and PushNotificationConfig database models.
  • Add last_updated field to TaskMixin for optimized sorting and indexing.
  • Update DatabaseTaskStore, InMemoryTaskStore and DatabasePushNotificationConfigStore to use OwnerResolver.
  • Add Resource Scoping related Unit tests.
  • Add Alembic configuration to enable users to update their own databases with non-optional owner column in tasks and push_notification_configs table and optional last_updated and index (owner, last_updated) in tasks .
  • Distribute alembic configuration, enable CLI commands such as uv run a2a-db for database updating.

Note

  • In src/a2a/server/tasks/database_task_store.py list method, Gemini suggested a refactor of pagination. I thoroughly reviewed it and comfirmed that the logic is the same and that readability of code improved so I decided to accept it.
  • It seems there was a functional bug in InMemoryPushNotificationConfigStore delete_info method. When config_id is None and only task_id was provided it would search for configs mapped to task_id with config.id=task_id, contrary to delete_info method of DatabasePushNotificationConfigStore where if config_id is None, all configurations for the task are deleted. Unfortunately, I did not find intended behavior defined in the spec, but behavior of DatabasePushNotificationConfigStore's delete_info seems more logical.

Breaking changes

  • added non-optional owner field to the Task Model. Use alembic configuration to update your database.

  • Ensure the tests and linter pass (Run bash scripts/format.sh from the repository root to format)

  • Appropriate docs were updated (if necessary)

Fixes #610 🦕

…fications`

Introduces caller indentity isolation to ensure clients only access authorized resources, as mandated by the A2A spec.

- Add 'owner' field to `TaskMixin` and `PushNotificationConfig` database models.
 - Add 'last_updated' field to `TaskMixin` for optimized sorting and indexing.
- Update `DatabaseTaskStore`, `InMemoryTaskStore` and `DatabasePushNotificationConfigStore` to use `OwnerResolver`.
- Add relevant Unit tests.
- Add Alembic configuration to enable users to update their own databases with non-optional `owner` field in `tasks` table.
@sokoliva
sokoliva requested review from a team and a2a-bot as code owners February 18, 2026 16:19
@sokoliva
sokoliva changed the base branch from main to 1.0-dev February 18, 2026 16:22
@gemini-code-assist

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces resource scoping by adding an owner field to tasks and push notification configurations, which is a great step towards multi-tenancy and security. The implementation across the database and in-memory stores is consistent. I've also noticed the addition of Alembic for database migrations, which is excellent for managing schema changes. My feedback focuses on improving the Alembic configuration, strengthening the data model for timestamps, and making the owner resolution logic more robust.

Comment thread pyproject.toml Outdated
Comment thread src/a2a/server/models.py Outdated
Comment thread src/a2a/server/tasks/database_task_store.py Outdated
Comment thread alembic/README Outdated
Comment thread src/a2a/server/models.py Outdated
Comment thread src/a2a/server/owner_resolver.py Outdated
@sokoliva
sokoliva requested a review from ishymko February 19, 2026 10:48
sokoliva and others added 7 commits February 19, 2026 10:55
- remove redundant 'index=True' in owner field declaration
- add owner resource scoping to `InMemoryPushNotificationConfigStore` and a related unit test
Comment thread src/a2a/server/tasks/push_notification_config_store.py Outdated
Comment thread src/a2a/server/tasks/inmemory_task_store.py Outdated
Comment thread pyproject.toml
Comment thread alembic/README Outdated
@sokoliva
sokoliva requested a review from ishymko February 27, 2026 11:05
Comment thread pyproject.toml Outdated
Comment thread src/a2a/migrations/versions/6419d2d130f6_add_columns_owner_last_updated.py Outdated
Comment thread src/a2a/server/models.py Outdated
Comment thread src/a2a/a2a_db_cli.py
@sokoliva
sokoliva merged commit f0d4669 into a2aproject:1.0-dev Feb 27, 2026
6 checks passed
@sokoliva
sokoliva deleted the resource-scoping branch February 27, 2026 16:56
@ishymko ishymko mentioned this pull request Mar 2, 2026
1 task done
ishymko added a commit that referenced this pull request Mar 17, 2026
🤖 I have created a release *beep* *boop*
---


### ⚠ BREAKING CHANGES

* **spec**: upgrade SDK to A2A 1.0 spec and use proto-based types
([#572](#572),
[#665](#665),
[#804](#804),
[#765](#765))
* **client:** introduce ServiceParameters for extensions and include it
in ClientCallContext
([#784](#784))
* **client:** rename "callback" -> "push_notification_config"
([#749](#749))
* **client:** transport agnostic interceptors
([#796](#796))
([a910cbc](a910cbc))
* add `protocol_version` column to Task and PushNotificationConfig
models and create a migration
([#789](#789))
([2e2d431](2e2d431))
* **server:** implement `Resource Scoping` for tasks and push
notifications
([#709](#709))
([f0d4669](f0d4669))

### Features

* add GetExtendedAgentCardRequest as input parameter to
GetExtendedAgentCard method
([#767](#767))
([13a092f](13a092f))
* add validation for the JSON-RPC version
([#808](#808))
([6eb7e41](6eb7e41))
* **client:** expose close() and async context manager support on
abstract Client
([#719](#719))
([e25ba7b](e25ba7b))
* **compat:** AgentCard backward compatibility helpers and tests
([#760](#760))
([81f3494](81f3494))
* **compat:** GRPC client compatible with 0.3 server
([#779](#779))
([0ebca93](0ebca93))
* **compat:** GRPC server compatible with 0.3 client
([#772](#772))
([80d827a](80d827a))
* **compat:** legacy v0.3 protocol models, conversion logic and
utilities ([#754](#754))
([26835ad](26835ad))
* **compat:** REST and JSONRPC clients compatible with 0.3 servers
([#798](#798))
([08794f7](08794f7))
* **compat:** REST and JSONRPC servers compatible with 0.3 clients
([#795](#795))
([9856054](9856054))
* **compat:** set a2a-version header to 1.0.0
([#764](#764))
([4cb68aa](4cb68aa))
* **compat:** unify v0.3 REST url prefix and expand cross-version tests
([#820](#820))
([0925f0a](0925f0a))
* database forward compatibility: make `owner` field optional
([#812](#812))
([cc29d1f](cc29d1f))
* handle tenant in Client
([#758](#758))
([5b354e4](5b354e4))
* implement missing push notifications related methods
([#711](#711))
([041f0f5](041f0f5))
* implement rich gRPC error details per A2A v1.0 spec
([#790](#790))
([245eca3](245eca3))
* **rest:** add tenant support to rest
([#773](#773))
([4771b5a](4771b5a))
* send task as a first subscribe event
([#716](#716))
([e71ac62](e71ac62))
* **server, grpc:** Implement tenant context propagation for gRPC
requests. ([#781](#781))
([164f919](164f919))
* **server, json-rpc:** Implement tenant context propagation for
JSON-RPC requests.
([#778](#778))
([72a330d](72a330d))
* **server:** add v0.3 legacy compatibility for database models
([#783](#783))
([08c491e](08c491e))
* **spec:** add `tasks/list` method with filtering and pagination to the
specification
([#511](#511))
([d5818e5](d5818e5))
* use StreamResponse as push notifications payload
([#724](#724))
([a149a09](a149a09))
* **rest:** update REST error handling to use `google.rpc.Status`
([#838](#838))
([ea7d3ad](ea7d3ad))


### Bug Fixes

* add history length and page size validations
([#726](#726))
([e67934b](e67934b))
* allign error codes with the latest spec
([#826](#826))
([709b1ff](709b1ff))
* **client:** align send_message signature with BaseClient
([#740](#740))
([57cb529](57cb529))
* get_agent_card trailing slash when agent_card_path=""
([#799](#799))
([#800](#800))
([a55c97e](a55c97e))
* handle parsing error in REST
([#806](#806))
([bbd09f2](bbd09f2))
* Improve error handling for Timeout exceptions on REST and JSON-RPC
clients ([#690](#690))
([2acd838](2acd838))
* Improve streaming errors handling
([#576](#576))
([7ea7475](7ea7475))
* properly handle unset and zero history length
([#717](#717))
([72a1007](72a1007))
* return entire history when history_length=0
([#537](#537))
([acdc0de](acdc0de))
* return mandatory fields from list_tasks
([#710](#710))
([6132053](6132053))
* taskslist error on invalid page token and response serialization
([#814](#814))
([a102d31](a102d31))
* use correct REST path for Get Extended Agent Card operation
([#769](#769))
([ced3f99](ced3f99))
* Use POST method for REST endpoint /tasks/{id}:subscribe
([#843](#843))
([a0827d0](a0827d0))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: Ivan Shymko <ishymko@google.com>
bartek-gralewicz added a commit to a2aproject/a2a-js that referenced this pull request May 8, 2026
# Description

Resource scoping

This PR mimics the logic that was added in `a2a-python`
(a2aproject/a2a-python#709).
Since the `multi-tenancy` feature already enabled `Task` and
`PushNotificationConfig` filtration based on the `tenant` ownership,
this PR only extends this to allow for `User` ownership within the
`tenant` scope.

The ownership flow is the following:
`tenant` -> `User` -> CONTENT_UNDER_OWNERSHIP

Renamed `test/server/tenant_isolation.spec.ts` to more generic
`test/server/resource_scoping.spec.ts` and added new cases for `user`
based scoping. Lines 21-245 in `test/server/resource_scoping.spec.ts`
are identical to the original `test/server/tenant_isolation.spec.ts`.

@lkk7 lkk7 Aug 26, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I know it's late, but I caught this now:

MySQL docs say:

The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.

Using datetime.min here pushes year 0001 into the query which is against the specification.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thank you for pointing this out! I opened an issue about this: #1219. I was unable to replicate the issue, could you tell me more if this cause any problems to you?

@lkk7 lkk7 Aug 28, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Honestly, not really. Just a spec issue that I noticed. It's not critical.
In terms of just storing data, it works on modern MySQL versions.
I'm just not sure about what will happen when you start sorting that date, doing arithmetic operations on it, etc. This could lead to an unfindable problem in the future.

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.

[Feat]: Resource Scoping

4 participants