Skip to content

Commit

Permalink
Merge branch 'master' into ADO-1933-fix-tigger-connections
Browse files Browse the repository at this point in the history
* master:
  refactor(core)!: Remove legacy `--file` flag for `execute` CLI command (#9054)
  fix(core): Ensure TTL safeguard for test webhooks applies only to multi-main setup (#9062)
  ci: Delete some duplicate code in cli tests (no-changelog) (#9049)
  refactor(core, editor): Remove legacy `nodesAccess` (no-changelog) (#9016)
  refactor(editor): Remove legacy audit logs view (no-changelog) (#9053)
  refactor(editor): Do not make rest api calls for disabled features (no-changelog) (#9046)
  • Loading branch information
MiloradFilipovic committed Apr 5, 2024
2 parents 632199e + 4052b6c commit 3703bfe
Show file tree
Hide file tree
Showing 60 changed files with 157 additions and 522 deletions.
12 changes: 11 additions & 1 deletion packages/cli/BREAKING-CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@

This list shows all the versions which include breaking changes and how to upgrade.

## 1.37.0

### What changed?

The `--file` flag for the `execute` CLI command has been removed.

### When is action necessary?

If you have scripts relying on the `--file` flag for the `execute` CLI command, update them to first import the workflow and then execute it using the `--id` flag.

## 1.32.0

### What changed?

N8n auth cookie has `Secure` flag set by default now.
n8n auth cookie has `Secure` flag set by default now.

### When is action necessary?

Expand Down
7 changes: 3 additions & 4 deletions packages/cli/src/CredentialsHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ export class CredentialsHelper extends ICredentialsHelper {
return new Credentials(
{ id: credential.id, name: credential.name },
credential.type,
credential.nodesAccess,
credential.data,
);
}
Expand Down Expand Up @@ -483,9 +482,9 @@ export function createCredentialsFromCredentialsEntity(
credential: CredentialsEntity,
encrypt = false,
): Credentials {
const { id, name, type, nodesAccess, data } = credential;
const { id, name, type, data } = credential;
if (encrypt) {
return new Credentials({ id: null, name }, type, nodesAccess);
return new Credentials({ id: null, name }, type);
}
return new Credentials({ id, name }, type, nodesAccess, data);
return new Credentials({ id, name }, type, data);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,6 @@ export async function createCredential(

Object.assign(newCredential, properties);

if (!newCredential.nodesAccess || newCredential.nodesAccess.length === 0) {
newCredential.nodesAccess = [
{
nodeType: `n8n-nodes-base.${properties.type?.toLowerCase() ?? 'unknown'}`,
date: new Date(),
},
];
} else {
// Add the added date for node access permissions
newCredential.nodesAccess.forEach((nodeAccess) => {
nodeAccess.date = new Date();
});
}

return newCredential;
}

Expand Down Expand Up @@ -91,11 +77,7 @@ export async function removeCredential(credentials: CredentialsEntity): Promise<

export async function encryptCredential(credential: CredentialsEntity): Promise<ICredentialsDb> {
// Encrypt the data
const coreCredential = new Credentials(
{ id: null, name: credential.name },
credential.type,
credential.nodesAccess,
);
const coreCredential = new Credentials({ id: null, name: credential.name }, credential.type);

// @ts-ignore
coreCredential.setData(credential.data);
Expand All @@ -115,7 +97,7 @@ export function sanitizeCredentials(
const credentialsList = argIsArray ? credentials : [credentials];

const sanitizedCredentials = credentialsList.map((credential) => {
const { data, nodesAccess, shared, ...rest } = credential;
const { data, shared, ...rest } = credential;
return rest;
});

Expand Down
43 changes: 8 additions & 35 deletions packages/cli/src/commands/execute.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { Container } from 'typedi';
import { Flags } from '@oclif/core';
import { promises as fs } from 'fs';
import { PLACEHOLDER_EMPTY_WORKFLOW_ID } from 'n8n-core';
import type { IWorkflowBase } from 'n8n-workflow';
import { ApplicationError, ExecutionBaseError } from 'n8n-workflow';

Expand All @@ -17,13 +15,10 @@ import { OwnershipService } from '@/services/ownership.service';
export class Execute extends BaseCommand {
static description = '\nExecutes a given workflow';

static examples = ['$ n8n execute --id=5', '$ n8n execute --file=workflow.json'];
static examples = ['$ n8n execute --id=5'];

static flags = {
help: Flags.help({ char: 'h' }),
file: Flags.string({
description: 'path to a workflow file to execute',
}),
id: Flags.string({
description: 'id of the workflow to execute',
}),
Expand All @@ -41,42 +36,20 @@ export class Execute extends BaseCommand {
async run() {
const { flags } = await this.parse(Execute);

if (!flags.id && !flags.file) {
this.logger.info('Either option "--id" or "--file" have to be set!');
if (!flags.id) {
this.logger.info('"--id" has to be set!');
return;
}

if (flags.id && flags.file) {
this.logger.info('Either "id" or "file" can be set never both!');
return;
if (flags.file) {
throw new ApplicationError(
'The --file flag is no longer supported. Please first import the workflow and then execute it using the --id flag.',
{ level: 'warning' },
);
}

let workflowId: string | undefined;
let workflowData: IWorkflowBase | null = null;
if (flags.file) {
// Path to workflow is given
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
workflowData = JSON.parse(await fs.readFile(flags.file, 'utf8'));
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (error.code === 'ENOENT') {
this.logger.info(`The file "${flags.file}" could not be found.`);
return;
}

throw error;
}

// Do a basic check if the data in the file looks right
// TODO: Later check with the help of TypeScript data if it is valid or not
if (workflowData?.nodes === undefined || workflowData.connections === undefined) {
this.logger.info(`The file "${flags.file}" does not contain valid workflow data.`);
return;
}

workflowId = workflowData.id ?? PLACEHOLDER_EMPTY_WORKFLOW_ID;
}

if (flags.id) {
// Id of workflow is given
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/export/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ export class ExportCredentialsCommand extends BaseCommand {

if (flags.decrypted) {
for (let i = 0; i < credentials.length; i++) {
const { name, type, nodesAccess, data } = credentials[i];
const { name, type, data } = credentials[i];
const id = credentials[i].id;
const credential = new Credentials({ id, name }, type, nodesAccess, data);
const credential = new Credentials({ id, name }, type, data);
const plainData = credential.getData();
(credentials[i] as ICredentialsDecryptedDb).data = plainData;
}
Expand Down
3 changes: 0 additions & 3 deletions packages/cli/src/commands/import/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,6 @@ export class ImportCredentialsCommand extends BaseCommand {
}

private async storeCredential(credential: Partial<CredentialsEntity>, user: User) {
if (!credential.nodesAccess) {
credential.nodesAccess = [];
}
const result = await this.transactionManager.upsert(CredentialsEntity, credential, ['id']);
await this.transactionManager.upsert(
SharedCredentials,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export abstract class AbstractOAuthController {
credential: ICredentialsDb,
decryptedData: ICredentialDataDecryptedObject,
) {
const credentials = new Credentials(credential, credential.type, credential.nodesAccess);
const credentials = new Credentials(credential, credential.type);
credentials.setData(decryptedData);
await this.credentialsRepository.update(credential.id, {
...credentials.getDataToSave(),
Expand Down
18 changes: 1 addition & 17 deletions packages/cli/src/credentials/credentials.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,6 @@ export class CredentialsService {

await validateEntity(newCredentials);

// Add the date for newly added node access permissions
for (const nodeAccess of newCredentials.nodesAccess) {
nodeAccess.date = new Date();
}

return newCredentials;
}

Expand All @@ -132,13 +127,6 @@ export class CredentialsService {

await validateEntity(updateData);

// Add the date for newly added node access permissions
for (const nodeAccess of updateData.nodesAccess) {
if (!nodeAccess.date) {
nodeAccess.date = new Date();
}
}

// Do not overwrite the oauth data else data like the access or refresh token would get lost
// everytime anybody changes anything on the credentials even if it is just the name.
if (decryptedData.oauthTokenData) {
Expand All @@ -149,11 +137,7 @@ export class CredentialsService {
}

createEncryptedData(credentialId: string | null, data: CredentialsEntity): ICredentialsDb {
const credentials = new Credentials(
{ id: credentialId, name: data.name },
data.type,
data.nodesAccess,
);
const credentials = new Credentials({ id: credentialId, name: data.name }, data.type);

credentials.setData(data.data as unknown as ICredentialDataDecryptedObject);

Expand Down
9 changes: 2 additions & 7 deletions packages/cli/src/databases/entities/CredentialsEntity.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { ICredentialNodeAccess } from 'n8n-workflow';
import { Column, Entity, Index, OneToMany } from '@n8n/typeorm';
import { IsArray, IsObject, IsString, Length } from 'class-validator';
import { IsObject, IsString, Length } from 'class-validator';
import type { SharedCredentials } from './SharedCredentials';
import { WithTimestampsAndStringId, jsonColumnType } from './AbstractEntity';
import { WithTimestampsAndStringId } from './AbstractEntity';
import type { ICredentialsDb } from '@/Interfaces';

@Entity()
Expand All @@ -27,8 +26,4 @@ export class CredentialsEntity extends WithTimestampsAndStringId implements ICre

@OneToMany('SharedCredentials', 'credentials')
shared: SharedCredentials[];

@Column(jsonColumnType)
@IsArray()
nodesAccess: ICredentialNodeAccess[];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { IrreversibleMigration, MigrationContext } from '@db/types';

export class RemoveNodesAccess1712044305787 implements IrreversibleMigration {
async up({ schemaBuilder: { dropColumns } }: MigrationContext) {
await dropColumns('credentials_entity', ['nodesAccess']);
}
}
2 changes: 2 additions & 0 deletions packages/cli/src/databases/migrations/mysqldb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { AddGlobalAdminRole1700571993961 } from '../common/1700571993961-AddGlob
import { DropRoleMapping1705429061930 } from '../common/1705429061930-DropRoleMapping';
import { RemoveFailedExecutionStatus1711018413374 } from '../common/1711018413374-RemoveFailedExecutionStatus';
import { MoveSshKeysToDatabase1711390882123 } from '../common/1711390882123-MoveSshKeysToDatabase';
import { RemoveNodesAccess1712044305787 } from '../common/1712044305787-RemoveNodesAccess';

export const mysqlMigrations: Migration[] = [
InitialMigration1588157391238,
Expand Down Expand Up @@ -111,4 +112,5 @@ export const mysqlMigrations: Migration[] = [
DropRoleMapping1705429061930,
RemoveFailedExecutionStatus1711018413374,
MoveSshKeysToDatabase1711390882123,
RemoveNodesAccess1712044305787,
];
2 changes: 2 additions & 0 deletions packages/cli/src/databases/migrations/postgresdb/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import { AddGlobalAdminRole1700571993961 } from '../common/1700571993961-AddGlob
import { DropRoleMapping1705429061930 } from '../common/1705429061930-DropRoleMapping';
import { RemoveFailedExecutionStatus1711018413374 } from '../common/1711018413374-RemoveFailedExecutionStatus';
import { MoveSshKeysToDatabase1711390882123 } from '../common/1711390882123-MoveSshKeysToDatabase';
import { RemoveNodesAccess1712044305787 } from '../common/1712044305787-RemoveNodesAccess';

export const postgresMigrations: Migration[] = [
InitialMigration1587669153312,
Expand Down Expand Up @@ -109,4 +110,5 @@ export const postgresMigrations: Migration[] = [
DropRoleMapping1705429061930,
RemoveFailedExecutionStatus1711018413374,
MoveSshKeysToDatabase1711390882123,
RemoveNodesAccess1712044305787,
];
2 changes: 2 additions & 0 deletions packages/cli/src/databases/migrations/sqlite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { AddGlobalAdminRole1700571993961 } from '../common/1700571993961-AddGlob
import { DropRoleMapping1705429061930 } from './1705429061930-DropRoleMapping';
import { RemoveFailedExecutionStatus1711018413374 } from '../common/1711018413374-RemoveFailedExecutionStatus';
import { MoveSshKeysToDatabase1711390882123 } from '../common/1711390882123-MoveSshKeysToDatabase';
import { RemoveNodesAccess1712044305787 } from '../common/1712044305787-RemoveNodesAccess';

const sqliteMigrations: Migration[] = [
InitialMigration1588102412422,
Expand Down Expand Up @@ -105,6 +106,7 @@ const sqliteMigrations: Migration[] = [
DropRoleMapping1705429061930,
RemoveFailedExecutionStatus1711018413374,
MoveSshKeysToDatabase1711390882123,
RemoveNodesAccess1712044305787,
];

export { sqliteMigrations };
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class CredentialsRepository extends Repository<CredentialsEntity> {
type Select = Array<keyof CredentialsEntity>;

const defaultRelations = ['shared', 'shared.user'];
const defaultSelect: Select = ['id', 'name', 'type', 'nodesAccess', 'createdAt', 'updatedAt'];
const defaultSelect: Select = ['id', 'name', 'type', 'createdAt', 'updatedAt'];

if (!listQueryOptions) return { select: defaultSelect, relations: defaultRelations };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { SourceControlPreferencesService } from './sourceControlPreferences.serv
import { writeFileSync } from 'fs';
import { SourceControlImportService } from './sourceControlImport.service.ee';
import type { User } from '@db/entities/User';
import isEqual from 'lodash/isEqual';
import type { SourceControlGetStatus } from './types/sourceControlGetStatus';
import type { TagEntity } from '@db/entities/TagEntity';
import type { Variables } from '@db/entities/Variables';
Expand Down Expand Up @@ -384,7 +383,7 @@ export class SourceControlService {
* Does a comparison between the local and remote workfolder based on NOT the git status,
* but certain parameters within the items being synced.
* For workflows, it compares the versionIds
* For credentials, it compares the name, type and nodeAccess
* For credentials, it compares the name and type
* For variables, it compares the name
* For tags, it compares the name and mapping
* @returns either SourceControlledFile[] if verbose is false,
Expand Down Expand Up @@ -565,12 +564,7 @@ export class SourceControlService {
> = [];
credLocalIds.forEach((local) => {
const mismatchingCreds = credRemoteIds.find((remote) => {
return (
remote.id === local.id &&
(remote.name !== local.name ||
remote.type !== local.type ||
!isEqual(remote.nodesAccess, local.nodesAccess))
);
return remote.id === local.id && (remote.name !== local.name || remote.type !== local.type);
});
if (mismatchingCreds) {
credModifiedInEither.push({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,15 +240,14 @@ export class SourceControlExportService {
}
await Promise.all(
credentialsToBeExported.map(async (sharing) => {
const { name, type, nodesAccess, data, id } = sharing.credentials;
const credentials = new Credentials({ id, name }, type, nodesAccess, data);
const { name, type, data, id } = sharing.credentials;
const credentials = new Credentials({ id, name }, type, data);

const stub: ExportableCredential = {
id,
name,
type,
data: this.replaceCredentialData(credentials.getData()),
nodesAccess,
ownedBy: sharing.user.email,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,12 @@ export class SourceControlImportService {
Array<ExportableCredential & { filename: string }>
> {
const localCredentials = await Container.get(CredentialsRepository).find({
select: ['id', 'name', 'type', 'nodesAccess'],
select: ['id', 'name', 'type'],
});
return localCredentials.map((local) => ({
id: local.id,
name: local.name,
type: local.type,
nodesAccess: local.nodesAccess,
filename: getCredentialExportPath(local.id, this.credentialExportFolder),
})) as Array<ExportableCredential & { filename: string }>;
}
Expand Down Expand Up @@ -339,14 +338,13 @@ export class SourceControlImportService {
(e) => e.id === credential.id && e.type === credential.type,
);

const { name, type, data, id, nodesAccess } = credential;
const newCredentialObject = new Credentials({ id, name }, type, []);
const { name, type, data, id } = credential;
const newCredentialObject = new Credentials({ id, name }, type);
if (existingCredential?.data) {
newCredentialObject.data = existingCredential.data;
} else {
newCredentialObject.setData(data);
}
newCredentialObject.nodesAccess = nodesAccess || existingCredential?.nodesAccess || [];

this.logger.debug(`Updating credential id ${newCredentialObject.id as string}`);
await Container.get(CredentialsRepository).upsert(newCredentialObject, ['id']);
Expand Down
Loading

0 comments on commit 3703bfe

Please sign in to comment.