-
Notifications
You must be signed in to change notification settings - Fork 51.5k
feat(core): Implement credential resolution service #22799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
feat(core): Implement credential resolution service #22799
Conversation
f63952b to
ce26bee
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This comment has been minimized.
This comment has been minimized.
|
E2E Tests: n8n tests passed after 6m 57.5s Run Details
This message was posted automatically by
currents.dev | Integration Settings
|
…r id and workflow settings resolver id
ce26bee to
ac3239e
Compare
…solving credential
305d84f to
dd76799
Compare
dd76799 to
2f692e9
Compare
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
4 issues found across 26 files
Prompt for AI agents (all 4 issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/cli/src/modules/dynamic-credentials.ee/services/dynamic-credential.service.ts">
<violation number="1" location="packages/cli/src/modules/dynamic-credentials.ee/services/dynamic-credential.service.ts:80">
P1: Decrypt resolver configuration before parsing it; otherwise jsonParse runs on ciphertext and throws before dynamic credentials can resolve.</violation>
<violation number="2" location="packages/cli/src/modules/dynamic-credentials.ee/services/dynamic-credential.service.ts:118">
P2: Rule violated: **Prefer Typeguards over Type casting**
The fallback logger in `handleResolutionError` also relies on `error as Error` for type narrowing, conflicting with the guideline to prefer type guards. Use an `instanceof Error` check (or similar) before accessing `.message`.</violation>
</file>
<file name="packages/core/src/execution-engine/node-execution-context/__tests__/node-execution-context.test.ts">
<violation number="1" location="packages/core/src/execution-engine/node-execution-context/__tests__/node-execution-context.test.ts:235">
P2: This assertion only verifies `executionContext` after `_getCredentials` finishes, so the test would still pass if the helper set the field after calling `getDecrypted`. Capture the argument passed into `getDecrypted` and assert its `executionContext` is already populated so the test truly guards the behavior.</violation>
</file>
<file name="packages/cli/src/modules/dynamic-credentials.ee/database/repositories/__tests__/credential-resolver.repository.integration.test.ts">
<violation number="1" location="packages/cli/src/modules/dynamic-credentials.ee/database/repositories/__tests__/credential-resolver.repository.integration.test.ts:80">
P2: The test assumes a deterministic ordering of `credentialsRepository.find` results, so it will flap whenever the database returns the two credentials in the opposite order. Make the assertion order-independent (e.g., search by property or add an explicit ORDER BY).</violation>
</file>
Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR
| } | ||
|
|
||
| // Parse resolver configuration | ||
| const resolverConfig = jsonParse<Record<string, unknown>>(resolverEntity.config); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Decrypt resolver configuration before parsing it; otherwise jsonParse runs on ciphertext and throws before dynamic credentials can resolve.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/modules/dynamic-credentials.ee/services/dynamic-credential.service.ts, line 80:
<comment>Decrypt resolver configuration before parsing it; otherwise jsonParse runs on ciphertext and throws before dynamic credentials can resolve.</comment>
<file context>
@@ -0,0 +1,203 @@
+ }
+
+ // Parse resolver configuration
+ const resolverConfig = jsonParse<Record<string, unknown>>(resolverEntity.config);
+
+ try {
</file context>
|
|
||
| await contextWithCredentials['_getCredentials']('testCredential'); | ||
|
|
||
| expect(mockAdditionalData.executionContext).toEqual(runtimeData); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: This assertion only verifies executionContext after _getCredentials finishes, so the test would still pass if the helper set the field after calling getDecrypted. Capture the argument passed into getDecrypted and assert its executionContext is already populated so the test truly guards the behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/core/src/execution-engine/node-execution-context/__tests__/node-execution-context.test.ts, line 235:
<comment>This assertion only verifies `executionContext` after `_getCredentials` finishes, so the test would still pass if the helper set the field after calling `getDecrypted`. Capture the argument passed into `getDecrypted` and assert its `executionContext` is already populated so the test truly guards the behavior.
</comment>
<file context>
@@ -195,6 +195,56 @@ describe('NodeExecutionContext', () => {
+
+ await contextWithCredentials['_getCredentials']('testCredential');
+
+ expect(mockAdditionalData.executionContext).toEqual(runtimeData);
+ expect(mockCredentialsHelper.getDecrypted).toHaveBeenCalledWith(
+ mockAdditionalData,
</file context>
| expect(mockAdditionalData.executionContext).toEqual(runtimeData); | |
| const additionalDataArg = mockCredentialsHelper.getDecrypted.mock.calls[0][0]; | |
| expect(additionalDataArg.executionContext).toEqual(runtimeData); | |
| expect(mockAdditionalData.executionContext).toEqual(runtimeData); |
|
|
||
| expect(linked).toHaveLength(2); | ||
| expect(linked[0].resolverId).toBe(resolver.id); | ||
| expect(linked[1].resolvableAllowFallback).toBe(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: The test assumes a deterministic ordering of credentialsRepository.find results, so it will flap whenever the database returns the two credentials in the opposite order. Make the assertion order-independent (e.g., search by property or add an explicit ORDER BY).
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/modules/dynamic-credentials.ee/database/repositories/__tests__/credential-resolver.repository.integration.test.ts, line 80:
<comment>The test assumes a deterministic ordering of `credentialsRepository.find` results, so it will flap whenever the database returns the two credentials in the opposite order. Make the assertion order-independent (e.g., search by property or add an explicit ORDER BY).</comment>
<file context>
@@ -0,0 +1,112 @@
+
+ expect(linked).toHaveLength(2);
+ expect(linked[0].resolverId).toBe(resolver.id);
+ expect(linked[1].resolvableAllowFallback).toBe(true);
+ });
+
</file context>
| return toCredentialContext(decrypted); | ||
| } catch (error) { | ||
| this.logger.error('Failed to decrypt credential context from execution context', { | ||
| error: (error as Error).message, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Rule violated: Prefer Typeguards over Type casting
The fallback logger in handleResolutionError also relies on error as Error for type narrowing, conflicting with the guideline to prefer type guards. Use an instanceof Error check (or similar) before accessing .message.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/cli/src/modules/dynamic-credentials.ee/services/dynamic-credential.service.ts, line 118:
<comment>The fallback logger in `handleResolutionError` also relies on `error as Error` for type narrowing, conflicting with the guideline to prefer type guards. Use an `instanceof Error` check (or similar) before accessing `.message`.</comment>
<file context>
@@ -0,0 +1,203 @@
+ return toCredentialContext(decrypted);
+ } catch (error) {
+ this.logger.error('Failed to decrypt credential context from execution context', {
+ error: (error as Error).message,
+ });
+ return undefined;
</file context>
| error: (error as Error).message, | |
| error: error instanceof Error ? error.message : String(error), |
Summary
This PR implements credential resolving mechanism, using the resolver id setup in the credential or fallback on the workflow settings.
Related Linear tickets, Github issues, and Community forum posts
https://linear.app/n8n/issue/PAY-4218/implement-pass-through-credential-resolution-service
Review / Merge checklist
release/backport(if the PR is an urgent fix that needs to be backported)