Skip to content

fix(workflow-executor): sign agent JWT with snake_case identity claims (PRD-432)#1620

Open
christophebrun-forest wants to merge 1 commit into
feat/prd-214-server-step-mapperfrom
fix/prd-432-agent-jwt-snake-case-claims
Open

fix(workflow-executor): sign agent JWT with snake_case identity claims (PRD-432)#1620
christophebrun-forest wants to merge 1 commit into
feat/prd-214-server-step-mapperfrom
fix/prd-432-agent-jwt-snake-case-claims

Conversation

@christophebrun-forest
Copy link
Copy Markdown
Member

@christophebrun-forest christophebrun-forest commented Jun 3, 2026

Problem

The executor mints the JWT it sends to the agent from StepUser (camelCase). Ruby/Python agents splat JWT claims straight into Caller.new, which requires snake_case kwargs (first_name, last_name, rendering_id, permission_level). The camelCase-only token made that call fail with a 500 ArgumentError.

The TypeScript agent reads camelCase, so there is no single canonical casing.

Fix

Emit both casings in the signed JWT:

  • The Ruby Caller absorbs the extra camelCase keys via **_extra_args.
  • The TS agent ignores the snake_case ones.

Only the 4 multi-word identity fields get aliases — id, email, team, role, tags are already identical across casings.

Testing

  • New test decodes the signed JWT and asserts both camelCase and snake_case claims (+ scope) are present.
  • yarn workspace @forestadmin/workflow-executor test → 35/35 pass.
  • Lint clean (0 errors).

fixes PRD-432

🤖 Generated with Claude Code

Note

Sign agent JWTs with snake_case identity claims in AgentClientAgentPort.createClient

Adds first_name, last_name, rendering_id, and permission_level snake_case fields to the JWT payload alongside the existing camelCase equivalents. Adds a test suite in agent-client-agent-port.test.ts that verifies both camelCase and snake_case claims and the expected scope are present in the signed token.

Macroscope summarized 74349e2.

…s (PRD-432)

The executor mints the JWT it sends to the agent from StepUser (camelCase).
Ruby/Python agents splat JWT claims straight into Caller.new, which requires
snake_case kwargs (first_name, last_name, rendering_id, permission_level), so
the call failed with a 500 ArgumentError. The TS agent reads camelCase. There
is no single canonical casing, so emit both: the Ruby Caller absorbs the extra
camelCase keys via **_extra_args and the TS agent ignores the snake_case ones.

fixes PRD-432

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@linear-code
Copy link
Copy Markdown

linear-code Bot commented Jun 3, 2026

PRD-432

@qltysh
Copy link
Copy Markdown

qltysh Bot commented Jun 3, 2026

Qlty


Coverage Impact

Unable to calculate total coverage change because base branch coverage was not found.

Modified Files with Diff Coverage (1)

RatingFile% DiffUncovered Line #s
New Coverage rating: A
...ages/workflow-executor/src/adapters/agent-client-agent-port.ts100.0%
Total100.0%
🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

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.

2 participants