fix(config): disambiguate credential role resolution by provider#1115
Merged
zbigniewsobiecki merged 4 commits intodevfrom Apr 15, 2026
Merged
fix(config): disambiguate credential role resolution by provider#1115zbigniewsobiecki merged 4 commits intodevfrom
zbigniewsobiecki merged 4 commits intodevfrom
Conversation
Spec 004 targets the credential role-resolution ambiguity that breaks Linear wizard reopens and silently skips Linear webhook signature verification in the router. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Plan 004/1 (disambiguate-role-resolver).
The credential-resolution helper iterated all providers in a category
looking for a role-name match and returned the first hit. Because the
built-in PM registration order is trello → jira → linear, this caused:
1. Dashboard: Linear wizard reopens demanded a re-typed API key every
time. ('pm', 'api_key') resolved to TRELLO_API_KEY on a Linear-only
project, which isn't configured, so 'Linear credentials not
configured' surfaced in the Board/Project Selection step.
2. Router (production): Linear webhook signature verification silently
returned the JIRA webhook secret (or null on Linear-only projects),
causing signatures to silently skip verification.
Fix:
- roleToEnvVarKey(category, role) -> roleToEnvVarKey(category, provider, role)
- getIntegrationCredential[OrNull] now take (projectId, category,
provider, role) — compiler rejects callers that omit provider.
- 42 call sites updated across 13 src/ files to pass the explicit
provider.
- *ByProject dashboard endpoints look up project_integrations.provider
first; throw NOT_FOUND with distinguishable message on missing row.
- resolveWebhookSecret branches pass the explicit provider per branch.
New tests:
- tests/unit/config/role-resolver.test.ts (9 tests)
- tests/unit/router/resolveWebhookSecret.test.ts (6 tests)
- integrationsDiscovery tests augmented with default provider mock.
Totals: 7612 unit + 522 integration all green. Lint + typecheck clean.
Closes spec 004.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…— all plans complete Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes spec 004-credential-role-provider-disambiguation. Fixes two silent bugs that both trace to the same root cause.
What the operator sees
Before: opening or refreshing the Linear PM wizard on a project that already has
LINEAR_API_KEYstored shows "Linear credentials not configured" in the Board / Project Selection step, forcing the operator to re-type the API key on every edit.After: the wizard populates the teams dropdown from the stored credential; no re-typing required.
What else gets fixed silently
The router's
resolveWebhookSecret('linear')was affected by the same bug: it was callinggetIntegrationCredentialOrNull('pm', 'webhook_secret'), which resolved to whichever provider registeredwebhook_secretfirst in the Map (JIRA), so Linear webhook signature verification was silently resolving toJIRA_WEBHOOK_SECRETor null on Linear-only projects — meaning signatures have been silently skipping verification in production. This ships fixed in the same PR.Root cause
roleToEnvVarKey(category, role)iterated all providers in a category and returned the first role-name match. Sinceapi_keyis declared by both Trello and Linear, andwebhook_secretis declared by JIRA, Linear, GitHub, and Sentry, the helper returned the wrong env-var key for any call that happened to target a provider registered later than the first match.Fix
roleToEnvVarKey(category, provider, role)— required provider parameter; indexes directly, no iteration.getIntegrationCredential(projectId, category, provider, role)andgetIntegrationCredentialOrNull(...)— same change. Compiler rejects callers that omit the provider.src/files to pass the literal provider ('linear','trello','jira','github','sentry').*ByProjectdiscovery endpoints now look upproject_integrations.providerfirst. On missing row, throwsNOT_FOUNDwith a distinguishable message ('No PM integration configured for this project yet') — not conflated with'credentials not configured', so the frontend can surface a clearer state.resolveWebhookSecretbranches each pass the explicit provider per-branch.Tests
roleToEnvVarKeydisambiguation (tests/unit/config/role-resolver.test.ts).resolveWebhookSecretproving each of the 5 providers' branches return the right env-var key and Linear's case no longer falls back to JIRA's (tests/unit/router/resolveWebhookSecret.test.ts).integrationsDiscoverytests (~99 tests) updated to mockgetIntegrationByProjectAndCategorywith the right provider; exercises the new distinguishable-error path on missing-row cases.Totals: 7612 unit + 522 integration — all green. Lint + typecheck (root + web) clean.
Not touched
integrationRoles.ts).Out of scope
Test plan
npm test— 7612 passingTEST_DATABASE_URL=... npm run test:integration— 522 passingnpm run lint— cleannpm run typecheck(root + web) — cleanLINEAR_WEBHOOK_SECRETset; confirm the router log shows signature verified (not "skipped").*ByProjectcall on a project with no PM integration row — confirm the error reads "No PM integration configured for this project yet".🤖 Generated with Claude Code