diff --git a/packages/cli/src/__tests__/credentials-overwrites.test.ts b/packages/cli/src/__tests__/credentials-overwrites.test.ts index 247472b2580..4359dd28531 100644 --- a/packages/cli/src/__tests__/credentials-overwrites.test.ts +++ b/packages/cli/src/__tests__/credentials-overwrites.test.ts @@ -113,6 +113,36 @@ describe('CredentialsOverwrites', () => { expect(result).toEqual(data); }); + it('should not crash when skipTypes is undefined', () => { + // Simulate version mismatch where skipTypes is not present on the config object + globalConfig.credentials.overwrite.skipTypes = + undefined as unknown as CommaSeparatedStringArray; + + const result = credentialsOverwrites.applyOverwrite('test', { + username: '', + password: '', + }); + + expect(result).toEqual({ username: 'user', password: 'pass' }); + }); + + it('should not crash when overwrite config object is undefined', () => { + // Simulate a DI/version mismatch where the nested overwrite config is undefined + const savedOverwrite = globalConfig.credentials.overwrite; + globalConfig.credentials.overwrite = undefined as never; + + try { + const result = credentialsOverwrites.applyOverwrite('test', { + username: '', + password: '', + }); + + expect(result).toEqual({ username: 'user', password: 'pass' }); + } finally { + globalConfig.credentials.overwrite = savedOverwrite; + } + }); + describe('N8N_SKIP_CREDENTIAL_OVERWRITE', () => { beforeEach(() => { globalConfig.credentials.overwrite.skipTypes = [ diff --git a/packages/cli/src/credentials-overwrites.ts b/packages/cli/src/credentials-overwrites.ts index a2f6fb63901..632d8f7dfa9 100644 --- a/packages/cli/src/credentials-overwrites.ts +++ b/packages/cli/src/credentials-overwrites.ts @@ -147,7 +147,7 @@ export class CredentialsOverwrites { // customized (any overwrite field has a non-empty value that differs from // the overwrite value). Since overwrites are never persisted to the DB, // any non-empty stored value that differs from the overwrite is user-set. - if (this.globalConfig.credentials.overwrite.skipTypes.includes(type)) { + if (this.globalConfig.credentials.overwrite?.skipTypes?.includes(type)) { const isFieldCustomized = (key: string) => { const storedValue = data[key]; return ( @@ -208,11 +208,17 @@ export class CredentialsOverwrites { private get(name: string): ICredentialDataDecryptedObject | undefined { const parentTypes = this.credentialTypes.getParentTypes(name); - return [name, ...parentTypes] + const entries = [name, ...parentTypes] .reverse() .map((type) => this.overwriteData[type]) - .filter((type) => !!type) - .reduce((acc, current) => Object.assign(acc, current), {}); + .filter((type): type is ICredentialDataDecryptedObject => !!type); + + if (entries.length === 0) return undefined; + + return entries.reduce( + (acc, current) => Object.assign(acc, current), + {} as ICredentialDataDecryptedObject, + ); } getAll(): ICredentialsOverwrite {