Skip to content
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

feat: Add external secrets #6477

Merged
merged 119 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
119 commits
Select commit Hold shift + click to select a range
b7afbaa
use vars in creds expressions
romainminaud May 5, 2023
ff26cfe
remove console.log
valya May 17, 2023
7029369
Merge remote-tracking branch 'origin/master' into pay-442-add-secrets…
valya May 23, 2023
034a8e8
feat: add $secrets variable for credentials
valya May 25, 2023
9cda5d8
add some REST endpoints
valya Jun 7, 2023
4275cee
add secrets redacting
valya Jun 8, 2023
03fe092
add infisical secrets provider
valya Jun 8, 2023
9e1b36d
Merge remote-tracking branch 'origin/master' into pay-442-add-secrets…
valya Jun 12, 2023
c69e9e6
add connect and secrets list apis
valya Jun 12, 2023
a786d22
feat: add external-secrets-front-end (#6425)
alexgrozav Jun 14, 2023
7eba8da
feat: add correct secret provider images
alexgrozav Jun 14, 2023
084f372
test endpoint
valya Jun 14, 2023
f3f7d1e
feat: add $secrets to credentials modal expressions
alexgrozav Jun 14, 2023
08bb319
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
valya Jun 14, 2023
5078e11
feat: add external secrets connection test
alexgrozav Jun 14, 2023
eb21acc
fix: update test connection data format
alexgrozav Jun 14, 2023
91a8e71
lock secrets down to owners
valya Jun 14, 2023
b2b16fd
add secrets update interval
valya Jun 14, 2023
e7e1752
chore: merge master
alexgrozav Jun 16, 2023
e79f97d
feat: add external secrets connection switch
alexgrozav Jun 19, 2023
be14436
return settings on connect api and return status on test api
valya Jun 19, 2023
e2a83ff
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
valya Jun 19, 2023
6d875a7
rename test state field
valya Jun 19, 2023
4290283
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
alexgrozav Jun 19, 2023
d0d9142
fix: fix connection testing
alexgrozav Jun 19, 2023
3188f92
fix: add $vars to credentials expressions
alexgrozav Jun 19, 2023
7fd868b
Be more precise on Infisical fields name + hint
romainminaud Jun 21, 2023
203c661
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
romainminaud Jun 21, 2023
06a0129
fix(editor): Update external secrets paywall (#6549)
cstuncsik Jun 27, 2023
0a5a255
secrets licensing and test error message on backend
valya Jul 4, 2023
f376d55
Minor copy tweaks.
gandreini Jul 4, 2023
95e365f
hashicorp vault provider
valya Jul 6, 2023
e9291f6
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
valya Jul 6, 2023
fa31e4a
make secrets return objects instead of just strings
valya Jul 6, 2023
daeaa4c
Merge remote-tracking branch 'origin/master' into pay-442-add-secrets…
valya Jul 11, 2023
e7491d6
make secrets expression suggestions work on nested secrets
valya Jul 12, 2023
1e894c1
feat: add conditional parameter display and data normalization in ext…
alexgrozav Jul 12, 2023
4516fe7
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
alexgrozav Jul 12, 2023
4a57495
fix: change ellipsis menu
alexgrozav Jul 12, 2023
2866f95
fix hashicorp vault image
valya Jul 12, 2023
b41e1fb
feat: various ux improvements
alexgrozav Jul 12, 2023
65d70b9
add provider refresh endpoint
valya Jul 12, 2023
6c51566
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
valya Jul 12, 2023
413735d
update provider service token placeholders
valya Jul 12, 2023
6354219
disable expressions for secrets providers
valya Jul 12, 2023
91e7fcf
fix: remove success toasts
alexgrozav Jul 12, 2023
788fa74
chore: merge conflicts
alexgrozav Jul 12, 2023
5cfbb1c
fix: update loading overlay
alexgrozav Jul 12, 2023
8ac0e25
feat: update secrets and vars autocompletion
alexgrozav Jul 13, 2023
4de3743
feat: add upsell to external secrets in credentials modal
alexgrozav Jul 13, 2023
121633d
update infisical sdk
valya Jul 13, 2023
17a33f6
fix cutting off first character of secrets in autocomplete
valya Jul 13, 2023
d12d975
fix dot at start of secrets autocomplete on partial completion
valya Jul 13, 2023
c4750a7
feat: add telemetry for external secrets usage
alexgrozav Jul 13, 2023
e340e8c
Merge branch 'pay-442-add-secrets-to-ct push
alexgrozav Jul 13, 2023
cf072f2
add secrets provider init retry with backoff
valya Jul 13, 2023
fa30693
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
valya Jul 13, 2023
5522aaf
add secrets provider save telemetry
valya Jul 13, 2023
af3640d
fix: show upsell message only if external secrets is disabled
alexgrozav Jul 14, 2023
bf1e871
fix: add timeout before triggering connection change
alexgrozav Jul 14, 2023
5682a25
fix: disable connection switch when provider error and not connected
alexgrozav Jul 17, 2023
3ec5eb4
fix: add back vars to credentials
alexgrozav Jul 18, 2023
1202598
Copy tweaks.
gandreini Jul 21, 2023
2042ed2
fix vault provider not throwing errors when trying to use vault secrets
valya Jul 25, 2023
cd5a597
fix: secrets autocompletions
valya Jul 27, 2023
5b269f6
Merge remote-tracking branch 'origin/master' into pay-442-add-secrets…
valya Jul 27, 2023
28c5105
use allSettled in secrets manager
valya Jul 27, 2023
1ed6bf4
add namespaces and approle auth method to make HCP work
valya Jul 27, 2023
3ac9686
remove transaction for secrets manager save settings
valya Jul 27, 2023
3607777
fix secrets deeper dot autocomplete and don't just show all at once
valya Jul 27, 2023
043d378
enable testing crednetials with expression if they're secrets
valya Jul 27, 2023
c71f289
remove console.log
valya Jul 27, 2023
9badbb6
better $secrets autocompletion by evaluating the path
valya Jul 27, 2023
0340cf2
hide renew token option for vault
valya Jul 27, 2023
d693631
return error status if test or update fails on provider
valya Jul 31, 2023
ed714ac
fix infisical environments
valya Aug 1, 2023
245e183
fix: fix double hiring banner logging (no-changelog)
alexgrozav Aug 1, 2023
f2d3c9a
Merge branch 'master' of github.com:n8n-io/n8n
alexgrozav Aug 2, 2023
0189e46
chore: merge master
alexgrozav Aug 2, 2023
fb13c34
rename secrets to ExternalSecrets and throw ExpressionError if not found
valya Aug 2, 2023
68f4971
feat: update external secrets front end to vue 3
alexgrozav Aug 2, 2023
63fad5d
external secrets tests
valya Aug 3, 2023
ccea8af
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
valya Aug 3, 2023
5ce2109
Minor copy tweaks.
gandreini Aug 4, 2023
57c8b60
Updated copy of the paywall page.
gandreini Aug 7, 2023
59bc28e
feat: sort providers by name
alexgrozav Aug 7, 2023
4610f9b
fix: add space after secrets usage code
alexgrozav Aug 7, 2023
14e203d
fix: change default icon for danger callout
alexgrozav Aug 7, 2023
1f098ac
fix: update how initial connection state is handled
alexgrozav Aug 7, 2023
bee94b8
feat: reload provider when opening modal and enabled
alexgrozav Aug 7, 2023
45fe308
fix: show disabled connection switch on load
alexgrozav Aug 7, 2023
55b0b93
fix: update connection state syncing
alexgrozav Aug 7, 2023
50e9c9e
Callout copy changed (removed mention of variables).
gandreini Aug 10, 2023
2fabffe
Links to docs.
gandreini Aug 10, 2023
ebb83b0
feat: update external-secrets docs translations
alexgrozav Aug 10, 2023
66d5534
feat: update provider switch design
alexgrozav Aug 10, 2023
678478d
fix: fix required credential edit number input expression
alexgrozav Aug 10, 2023
cd1d934
fix: fix missing resolve data for credential expressions
alexgrozav Aug 10, 2023
57a8d42
Merge remote-tracking branch 'origin/master' into pay-442-add-secrets…
valya Aug 15, 2023
d637ec7
change some vault properties
valya Aug 15, 2023
8c58b4a
add better errors for secrets evaluation
valya Aug 16, 2023
0bb646d
Merge remote-tracking branch 'origin/master' into pay-442-add-secrets…
valya Aug 16, 2023
de26f7a
fix: update callout snapshot
alexgrozav Aug 16, 2023
1461d10
remove deleted helpers file
valya Aug 16, 2023
c91c98f
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
valya Aug 16, 2023
06eb022
misc linting fixes
valya Aug 16, 2023
9b9393f
fix: fix failing external secrets tests
alexgrozav Aug 17, 2023
80203c9
Merge branch 'pay-442-add-secrets-to-credentials-expressions' of gith…
alexgrozav Aug 17, 2023
bf553f3
Merge remote-tracking branch 'origin/master' into pay-442-add-secrets…
valya Aug 23, 2023
5fae83d
hide secrets with invalid auto complete names
valya Aug 23, 2023
8ba8d49
review changes
valya Aug 23, 2023
3685036
test: add completion tests for secrets
alexgrozav Aug 24, 2023
82d3b26
fix: remove localStorage check for external secrets route
alexgrozav Aug 24, 2023
65cae1c
fix: remove console.log
alexgrozav Aug 24, 2023
0e65ebb
fix: add try/catch to external secrets view
alexgrozav Aug 24, 2023
580bb9e
fix credentials testing
valya Aug 24, 2023
e6fc273
chore: Merge master
krynble Aug 25, 2023
8856b23
fix: Remove .only from test
krynble Aug 25, 2023
c177788
chore: merge master
krynble Aug 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
"formidable": "^3.5.0",
"google-timezones-json": "^1.1.0",
"handlebars": "4.7.7",
"infisical-node": "^1.3.0",
"inquirer": "^7.0.1",
"ioredis": "^5.2.4",
"json-diff": "^1.0.6",
Expand Down
70 changes: 64 additions & 6 deletions packages/cli/src/CredentialsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
IHttpRequestHelper,
INodeTypeData,
INodeTypes,
IWorkflowExecuteAdditionalData,
ICredentialTestFunctions,
} from 'n8n-workflow';
import {
Expand Down Expand Up @@ -342,6 +343,7 @@ export class CredentialsHelper extends ICredentialsHelper {
* @param {boolean} [raw] Return the data as supplied without defaults or overwrites
*/
async getDecrypted(
additionalData: IWorkflowExecuteAdditionalData,
nodeCredentials: INodeCredentialsDetails,
type: string,
mode: WorkflowExecuteMode,
Expand All @@ -356,24 +358,32 @@ export class CredentialsHelper extends ICredentialsHelper {
return decryptedDataOriginal;
}

await additionalData?.secretsHelpers?.waitForInit();

const canUseSecrets = await this.credentialOwnedByOwner(nodeCredentials);

return this.applyDefaultsAndOverwrites(
additionalData,
decryptedDataOriginal,
type,
mode,
defaultTimezone,
expressionResolveValues,
canUseSecrets,
);
}

/**
* Applies credential default data and overwrites
*/
applyDefaultsAndOverwrites(
additionalData: IWorkflowExecuteAdditionalData,
decryptedDataOriginal: ICredentialDataDecryptedObject,
type: string,
mode: WorkflowExecuteMode,
defaultTimezone: string,
expressionResolveValues?: ICredentialsExpressionResolveValues,
canUseSecrets?: boolean,
): ICredentialDataDecryptedObject {
const credentialsProperties = this.getCredentialsProperties(type);

Expand All @@ -395,6 +405,10 @@ export class CredentialsHelper extends ICredentialsHelper {
decryptedData.oauthTokenData = decryptedDataOriginal.oauthTokenData;
}

const additionalKeys = NodeExecuteFunctions.getAdditionalKeys(additionalData, mode, null, {
secretsEnabled: canUseSecrets,
});

if (expressionResolveValues) {
const timezone = expressionResolveValues.workflow.settings.timezone ?? defaultTimezone;

Expand All @@ -408,7 +422,7 @@ export class CredentialsHelper extends ICredentialsHelper {
expressionResolveValues.connectionInputData,
mode,
timezone,
{},
additionalKeys,
undefined,
false,
decryptedData,
Expand All @@ -431,7 +445,7 @@ export class CredentialsHelper extends ICredentialsHelper {
decryptedData as INodeParameters,
mode,
defaultTimezone,
{},
additionalKeys,
undefined,
undefined,
decryptedData,
Expand Down Expand Up @@ -573,10 +587,24 @@ export class CredentialsHelper extends ICredentialsHelper {
}

if (credentialsDecrypted.data) {
credentialsDecrypted.data = CredentialsOverwrites().applyOverwrite(
credentialType,
credentialsDecrypted.data,
);
try {
const additionalData = await WorkflowExecuteAdditionalData.getBase(user.id);
credentialsDecrypted.data = this.applyDefaultsAndOverwrites(
additionalData,
credentialsDecrypted.data,
credentialType,
'internal' as WorkflowExecuteMode,
additionalData.timezone,
undefined,
user.isOwner,
);
} catch (error) {
Logger.debug('Credential test failed', error);
return {
status: 'Error',
message: error.message.toString(),
};
}
}

if (typeof credentialTestFunction === 'function') {
Expand Down Expand Up @@ -759,6 +787,36 @@ export class CredentialsHelper extends ICredentialsHelper {
message: 'Connection successful!',
};
}

async credentialOwnedByOwner(nodeCredential: INodeCredentialsDetails): Promise<boolean> {
if (!nodeCredential.id) {
return false;
}

const credential = await Db.collections.SharedCredentials.findOne({
where: {
role: {
scope: 'credential',
name: 'owner',
},
user: {
globalRole: {
scope: 'global',
name: 'owner',
},
},
credentials: {
id: nodeCredential.id,
},
},
});

if (!credential) {
return false;
}

return true;
}
}

/**
Expand Down
102 changes: 102 additions & 0 deletions packages/cli/src/ExternalSecrets/ExternalSecrets.controller.ee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { Authorized, Get, Post, RestController } from '@/decorators';
import { ExternalSecretsRequest } from '@/requests';
import { NotFoundError } from '@/ResponseHelper';
import { Response } from 'express';
import { Service } from 'typedi';
import { ProviderNotFoundError, ExternalSecretsService } from './ExternalSecrets.service.ee';

@Service()
@Authorized(['global', 'owner'])
@RestController('/external-secrets')
export class ExternalSecretsController {
constructor(private readonly secretsService: ExternalSecretsService) {}

@Get('/providers')
async getProviders() {
return this.secretsService.getProviders();
}

@Get('/providers/:provider')
async getProvider(req: ExternalSecretsRequest.GetProvider) {
const providerName = req.params.provider;
try {
return this.secretsService.getProvider(providerName);
} catch (e) {
if (e instanceof ProviderNotFoundError) {
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
}
throw e;
}
}

@Post('/providers/:provider/test')
async testProviderSettings(req: ExternalSecretsRequest.TestProviderSettings, res: Response) {
const providerName = req.params.provider;
try {
const result = await this.secretsService.testProviderSettings(providerName, req.body);
if (result.success) {
res.statusCode = 200;
} else {
res.statusCode = 400;
}
return result;
} catch (e) {
if (e instanceof ProviderNotFoundError) {
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
}
throw e;
}
}

@Post('/providers/:provider')
async setProviderSettings(req: ExternalSecretsRequest.SetProviderSettings) {
const providerName = req.params.provider;
try {
await this.secretsService.saveProviderSettings(providerName, req.body, req.user.id);
} catch (e) {
if (e instanceof ProviderNotFoundError) {
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
}
throw e;
}
return {};
}

@Post('/providers/:provider/connect')
async setProviderConnected(req: ExternalSecretsRequest.SetProviderConnected) {
const providerName = req.params.provider;
try {
await this.secretsService.saveProviderConnected(providerName, req.body.connected);
} catch (e) {
if (e instanceof ProviderNotFoundError) {
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
}
throw e;
}
return {};
}

@Post('/providers/:provider/update')
async updateProvider(req: ExternalSecretsRequest.UpdateProvider, res: Response) {
const providerName = req.params.provider;
try {
const resp = await this.secretsService.updateProvider(providerName);
if (resp) {
res.statusCode = 200;
} else {
res.statusCode = 400;
}
return { updated: resp };
} catch (e) {
if (e instanceof ProviderNotFoundError) {
throw new NotFoundError(`Could not find provider "${e.providerName}"`);
}
throw e;
}
}

@Get('/secrets')
getSecretNames() {
return this.secretsService.getAllSecrets();
valya marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading
Loading