fix(editor): Resolve $vars and $secrets in expressions in credentials fields (#9289)

This commit is contained in:
Iván Ovejero 2024-05-03 14:39:31 +02:00 committed by GitHub
parent 6ab3781570
commit d92f994913
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 55 additions and 22 deletions

View file

@ -202,14 +202,18 @@ export default defineComponent({
? this.modelValue.value
: this.modelValue;
if (!this.activeNode || !this.isValueExpression || typeof value !== 'string') {
if (
!this.isForCredential &&
(!this.activeNode || !this.isValueExpression || typeof value !== 'string')
) {
return { ok: false, error: new Error() };
}
try {
let opts;
let opts = { isForCredential: this.isForCredential };
if (this.ndvStore.isInputParentOfActiveNode) {
opts = {
...opts,
targetItem: this.targetItem ?? undefined,
inputNodeName: this.ndvStore.ndvInputNodeName,
inputRunIndex: this.ndvStore.ndvInputRunIndex,

View file

@ -82,16 +82,51 @@ export function resolveParameter(
inputRunIndex?: number;
inputBranchIndex?: number;
additionalKeys?: IWorkflowDataProxyAdditionalKeys;
isForCredential?: boolean;
} = {},
): IDataObject | null {
let itemIndex = opts?.targetItem?.itemIndex || 0;
const workflow = getCurrentWorkflow();
const additionalKeys: IWorkflowDataProxyAdditionalKeys = {
$execution: {
id: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
mode: 'test',
resumeUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
resumeFormUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
},
$vars: useEnvironmentsStore().variablesAsObject,
// deprecated
$executionId: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
$resumeWebhookUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
...opts.additionalKeys,
};
if (opts.isForCredential) {
// node-less expression resolution
return workflow.expression.getParameterValue(
parameter,
null,
0,
itemIndex,
'',
[],
'manual',
additionalKeys,
undefined,
false,
undefined,
'',
) as IDataObject;
}
const inputName = NodeConnectionType.Main;
const activeNode = useNDVStore().activeNode;
let contextNode = activeNode;
const workflow = getCurrentWorkflow();
if (activeNode) {
contextNode = workflow.getParentMainInputNode(activeNode);
}
@ -159,22 +194,6 @@ export function resolveParameter(
_connectionInputData = [];
}
const additionalKeys: IWorkflowDataProxyAdditionalKeys = {
$execution: {
id: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
mode: 'test',
resumeUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
resumeFormUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
},
$vars: useEnvironmentsStore().variablesAsObject,
// deprecated
$executionId: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
$resumeWebhookUrl: PLACEHOLDER_FILLED_AT_EXECUTION_TIME,
...opts.additionalKeys,
};
if (activeNode?.type === HTTP_REQUEST_NODE_TYPE) {
const EMPTY_RESPONSE = { statusCode: 200, headers: {}, body: {} };
const EMPTY_REQUEST = { headers: {}, body: {}, qs: {} };
@ -793,6 +812,7 @@ export function useWorkflowHelpers(options: { router: ReturnType<typeof useRoute
inputBranchIndex?: number;
c?: number;
additionalKeys?: IWorkflowDataProxyAdditionalKeys;
isForCredential?: boolean;
} = {},
stringifyObject = true,
) {

View file

@ -50,7 +50,7 @@ import { defineComponent } from 'vue';
import ResourcesListLayout from '@/components/layouts/ResourcesListLayout.vue';
import CredentialCard from '@/components/CredentialCard.vue';
import type { ICredentialType } from 'n8n-workflow';
import { CREDENTIAL_SELECT_MODAL_KEY } from '@/constants';
import { CREDENTIAL_SELECT_MODAL_KEY, EnterpriseEditionFeature } from '@/constants';
import { mapStores } from 'pinia';
import { useUIStore } from '@/stores/ui.store';
import { useUsersStore } from '@/stores/users.store';
@ -58,6 +58,8 @@ import { useNodeTypesStore } from '@/stores/nodeTypes.store';
import { useCredentialsStore } from '@/stores/credentials.store';
import { useExternalSecretsStore } from '@/stores/externalSecrets.ee.store';
import { useSourceControlStore } from '@/stores/sourceControl.store';
import useEnvironmentsStore from '@/stores/environments.ee.store';
import { useSettingsStore } from '@/stores/settings.store';
type IResourcesListLayoutInstance = InstanceType<typeof ResourcesListLayout>;
@ -123,11 +125,16 @@ export default defineComponent({
});
},
async initialize() {
const isVarsEnabled = useSettingsStore().isEnterpriseFeatureEnabled(
EnterpriseEditionFeature.Variables,
);
const loadPromises = [
this.credentialsStore.fetchAllCredentials(),
this.credentialsStore.fetchCredentialTypes(false),
this.externalSecretsStore.fetchAllSecrets(),
this.nodeTypesStore.loadNodeTypesIfNotLoaded(),
isVarsEnabled ? useEnvironmentsStore().fetchAllVariables() : Promise.resolve(), // for expression resolution
];
await Promise.all(loadPromises);

View file

@ -164,7 +164,9 @@ export class WorkflowDataProxy {
const that = this;
const node = this.workflow.nodes[nodeName];
return new Proxy(node.parameters, {
// `node` is `undefined` only in expressions in credentials
return new Proxy(node?.parameters ?? {}, {
has: () => true,
ownKeys(target) {
return Reflect.ownKeys(target);