Add scope owner NyxID schedule auth#2253
Conversation
Allow scheduled workflow service invocations to mint NyxID tokens from the authoritative scope owner identity while preserving explicit delegated sender auth. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0920a24ae9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (dispatch.Auth.ScopeOwnerNyxId != null) | ||
| { | ||
| return ExchangeScopeOwnerNyxIdAsync( | ||
| dispatch.Auth.ScopeOwnerNyxId, | ||
| dispatch.Request.Identity, | ||
| ct); |
There was a problem hiding this comment.
Route scope-owner tokens into owner credential fields
When ScopeOwnerNyxId is selected here, the owner token is fed into the same enrichment path as SenderNyxId and is later written only to ChatRequestEvent.LlmControl.SenderNyxIdAccessToken unless the schedule kind is Workflow. For generic service-invocation schedules created via /api/schedules, this means scope-owner auth never populates LlmControl.NyxIdAccessToken/NyxIdOrgToken, which downstream tool context treats as the owner credential, so scheduled service invocations that request scope-owner auth still run without owner NyxID credentials. Preserve the credential source kind through enrichment and put scope-owner tokens in the owner credential fields.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in db14b52 and covered by the follow-up tests in 2abc411. Scope-owner NyxID exchanges now route the token into owner credential fields (LlmControl.NyxIdAccessToken / NyxIdOrgToken) instead of SenderNyxIdAccessToken, while workflow caller projection still uses the exchanged token for connector authorization.
There was a problem hiding this comment.
Follow-up pushed in 31dd50c after re-review. In addition to the earlier dispatch fix (scope-owner tokens now populate LlmControl.NyxIdAccessToken / NyxIdOrgToken instead of sender credentials), scope-owner schedules now require a persisted owner subject at the application/workflow boundary, and the HTTP owner resolver no longer treats scope_id as a NyxID user subject. Added regression coverage for distinct scope_id vs uid/sub claims and missing owner subject rejection.
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## feature/integrate #2253 +/- ##
=====================================================
- Coverage 84.08% 84.07% -0.02%
=====================================================
Files 1139 1207 +68
Lines 82320 91770 +9450
Branches 10705 12024 +1319
=====================================================
+ Hits 69219 77154 +7935
- Misses 8414 9293 +879
- Partials 4687 5323 +636
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 197 files with indirect coverage changes 🚀 New features to boost your workflow:
|
Keep the scope-owner schedule auth plumbing but prevent owner tokens from masquerading as sender credentials during scheduled invocation dispatch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cover scope-owner NyxID auth validation, mapping, noop exchange, and GAgent fire-time propagation so the patch coverage gate exercises the new scheduled auth paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bind scope-owner schedule auth to the authenticated HTTP owner at create/update time so scheduled fires no longer infer the owner from service tenant ids. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-06-18-owner-nyxid-schedule-auth
Account for upstream voice-presence changes merged from feature/integrate so the guard baseline matches current line locations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensure scope-owner schedules persist an explicit owner subject instead of accepting scope or tenant identity as a late-bound credential source. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…-06-18-owner-nyxid-schedule-auth
…-06-18-owner-nyxid-schedule-auth
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Route Studio login code exchange through the backend so NyxID can return a broker binding id, then keep schedule create/update as read-only validation of the durable owner binding instead of deriving bindings from bearer claims. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ensure backend-owned NyxID login finalization can publish the broker OAuth client configuration that must be used to generate authorization codes, and cover the endpoint/error branches for CI coverage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update schedule and hosting tests to match current service invocation auth and off-grain LLM run execution registrations so the coverage quality gate can complete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Keep this PR backend-only and leave frontend NyxID callback integration to the follow-up issue. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Return accepted-dispatch semantics from Studio login finalization instead of implying the binding read model is already committed and visible. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolve the GAgentService hosting test conflict by keeping current off-grain LLM execution registration assertions from both branches. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
binding_id, and queues durablenyxid::<userId> -> binding_idpersistence through Channel.Identity.bindingDispatchAccepted) from finalization; binding readmodel visibility remains eventually consistent and schedule create/update validates the durable binding readmodel.scopeOwnerNyxId.OwnerSubject; schedule APIs no longer derive or commit bindings from bearer-token claims.Fixes #2250
Follow-up
/api/auth/nyxid/configand finalize login through/api/auth/nyxid/finalizeso the OAuth authorize client id matches backend token exchange.Test plan
dotnet test test/Aevatar.Studio.Tests/Aevatar.Studio.Tests.csproj --nologo --filter NyxId --consoleLoggerParameters:ErrorsOnly— passed, 47 testsdotnet test test/Aevatar.GAgentService.Tests/Aevatar.GAgentService.Tests.csproj --nologo --filter \"ScheduledDispatchApplicationServiceTests|ScheduledDispatchServiceInvocationTests\" --consoleLoggerParameters:ErrorsOnly— passed, 69 testsdotnet test test/Aevatar.GAgentService.Integration.Tests/Aevatar.GAgentService.Integration.Tests.csproj --nologo --filter GAgentServiceHostingServiceCollectionExtensionsTests --consoleLoggerParameters:ErrorsOnly— passed, 22 testsdotnet test test/Aevatar.GAgentService.Integration.Tests/Aevatar.GAgentService.Integration.Tests.csproj --nologo --filter FullyQualifiedName~ScheduledDispatchEndpointsTests --consoleLoggerParameters:ErrorsOnly— passed, 33 testsbash tools/ci/test_stability_guards.sh— passedbash tools/ci/coverage_quality_guard.sh— passed, filtered coverage line 89.8% / branch 73.1%pnpm --dir apps/aevatar-console-web install --frozen-lockfileandpnpm --dir apps/aevatar-console-web tsc— passed before frontend changes were removed from this PR🤖 Generated with Claude Code