Skip to content

fix(states): update states by state ID only#278

Merged
deepthi-rao-scale merged 4 commits into
mainfrom
deepthirao/agx1-319-reject-state-update-requests-when-body-task_id-mismatches
Jun 5, 2026
Merged

fix(states): update states by state ID only#278
deepthi-rao-scale merged 4 commits into
mainfrom
deepthirao/agx1-319-reject-state-update-requests-when-body-task_id-mismatches

Conversation

@deepthi-rao-scale

@deepthi-rao-scale deepthi-rao-scale commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Summary

  • make state updates identify the row only by the path state_id
  • keep legacy task_id and agent_id update payloads accepted but ignored
  • rely on DAuthorizedId(TaskChildResourceType.state, update) to resolve state_id to the stored parent task_id and authorize against that task before the handler runs
  • update only replaces the persisted state's .state field; stored task_id and agent_id are preserved by the read-modify-write flow
  • return 404 when the state lookup fails, and collapse parent-task auth denial to 404 through the existing authorization helper

Verification

  • uv run --group test pytest tests/unit/api/test_states_schema.py tests/unit/use_cases/test_states_use_case.py -q

Note: the focused local state API integration test was attempted earlier, but Docker/Testcontainers could not reach the local Docker socket before executing the test body. GitHub Actions integration shards passed.

Greptile Summary

This PR simplifies the state-update path by removing task_id / agent_id from UpdateStateRequest and relying solely on the state_id path parameter. Authorization is handled upstream by DAuthorizedId(TaskChildResourceType.state, update), which looks up the parent task and checks the caller's permissions before the handler runs.

  • Schema cleanup: UpdateStateRequest drops the two previously-required parent-identifier fields; extra fields sent by legacy clients are silently ignored (confirmed by the new unit test).
  • Use-case hardening: StatesUseCase.update now raises ItemDoesNotExist (→ 404) instead of silently returning None when the state is not found, providing defensive protection for race conditions between the auth lookup and the handler.
  • Test coverage: Two new unit-test modules cover the schema ignore-behaviour and the use-case not-found path; the integration test is updated to reflect that body-level parent identifiers are now ignored rather than enforced.

Confidence Score: 5/5

Safe to merge — the change correctly narrows the update contract to state_id-only routing, with authorization handled entirely by the existing DAuthorizedId dependency.

All changed files are consistent with each other: schema, route, use case, OpenAPI spec, and tests all agree on the new contract. The defensive ItemDoesNotExist guard in the use case correctly handles race conditions. Legacy clients sending task_id/agent_id in the request body continue to work without errors. New unit tests verify both the happy path and the not-found path.

No files require special attention.

Important Files Changed

Filename Overview
agentex/src/domain/use_cases/states_use_case.py Removes task_id parameter from update(); adds ItemDoesNotExist guard for the not-found case. Logic is clean and tests cover both paths.
agentex/src/api/routes/states.py Drops task_id forwarding to the use case; auth is fully delegated to DAuthorizedId. No issues.
agentex/src/api/schemas/states.py task_id and agent_id removed from UpdateStateRequest; BaseModel ignores unknown extra fields, preserving backwards compatibility for legacy clients.
agentex/openapi.yaml UpdateStateRequest schema updated to remove task_id/agent_id from both properties and required array; consistent with schema change.
agentex/tests/unit/use_cases/test_states_use_case.py New unit tests cover update-by-id happy path and ItemDoesNotExist raise; well-structured with AsyncMock and pytest-asyncio.
agentex/tests/unit/api/test_states_schema.py Validates that extra legacy fields in the request body are silently dropped by UpdateStateRequest.
agentex/tests/integration/api/states/test_states_api.py Removes the stale 'wrong task_id is a no-op' test and replaces it with a test confirming legacy body fields are accepted but ignored.

Sequence Diagram

sequenceDiagram
    participant Client
    participant DAuthorizedId
    participant _get_parent_task_id
    participant StateRepo
    participant AuthService
    participant StatesUseCase

    Client->>DAuthorizedId: "PUT /states/{state_id}"
    DAuthorizedId->>_get_parent_task_id: resolve state_id
    _get_parent_task_id->>StateRepo: "get(id=state_id)"
    StateRepo-->>_get_parent_task_id: StateEntity
    _get_parent_task_id-->>DAuthorizedId: task_id
    DAuthorizedId->>AuthService: check_task_or_collapse_to_404
    AuthService-->>DAuthorizedId: authorized
    DAuthorizedId-->>Client: state_id resolved
    Client->>StatesUseCase: "update(id=state_id, state=new_state)"
    StatesUseCase->>StateRepo: "get(id=state_id)"
    StateRepo-->>StatesUseCase: StateEntity
    StatesUseCase->>StateRepo: update(task_state)
    StateRepo-->>StatesUseCase: updated StateEntity
    StatesUseCase-->>Client: 200 State
Loading

Reviews (2): Last reviewed commit: "chore(states): update OpenAPI spec" | Re-trigger Greptile

@deepthi-rao-scale deepthi-rao-scale force-pushed the deepthirao/agx1-319-reject-state-update-requests-when-body-task_id-mismatches branch from 9146f3e to 0235fad Compare June 4, 2026 19:31
Comment thread agentex/src/domain/use_cases/states_use_case.py
Comment thread agentex/tests/integration/api/states/test_states_api.py Outdated
Comment thread agentex/tests/unit/api/test_states_schema.py Outdated
@deepthi-rao-scale deepthi-rao-scale changed the title DRAFT: Update states by state ID only fix(states): update states by state ID only Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

✱ Stainless preview builds

This PR will update the agentex-sdk SDKs with the following commit messages.

openapi

feat(api): remove task_id and agent_id from UpdateStateRequest

python

fix(api): remove agent_id and task_id parameters from states update method

typescript

fix(api): remove agent_id and task_id parameters from states update method
agentex-sdk-openapi studio · code

Your SDK build had at least one "note" diagnostic.
generate ✅

⚠️ agentex-sdk-typescript studio · code

Your SDK build had at least one "warning" diagnostic.
generate ⚠️build ✅lint ✅test ✅

npm install https://pkg.stainless.com/s/agentex-sdk-typescript/50badd473cbd141f31ed8074c7a2b1c448429794/dist.tar.gz
⚠️ agentex-sdk-python studio · code

Your SDK build had a failure in the lint CI job, which is a regression from the base state.
generate ⚠️build ✅lint ❗test ✅

pip install https://pkg.stainless.com/s/agentex-sdk-python/a7cbaae4416e2d712623ecfac5e251c07c537958/agentex_sdk-0.12.0-py3-none-any.whl

This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-06-05 15:28:07 UTC

@deepthi-rao-scale deepthi-rao-scale marked this pull request as ready for review June 4, 2026 23:14
@deepthi-rao-scale deepthi-rao-scale requested a review from a team as a code owner June 4, 2026 23:14
@deepthi-rao-scale

Copy link
Copy Markdown
Contributor Author

@greptile

if task_state and task_state.task_id == task_id:
# Update the state field but preserve other fields
task_state.state = state
return await self.task_state_repository.update(task_state)

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.

@smoreinis any reason not having the task_id would introduce a regression?

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.

we should be fine here, thanks for double checking

@deepthi-rao-scale deepthi-rao-scale merged commit 829fb2e into main Jun 5, 2026
33 checks passed
@deepthi-rao-scale deepthi-rao-scale deleted the deepthirao/agx1-319-reject-state-update-requests-when-body-task_id-mismatches branch June 5, 2026 15:25
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.

3 participants