Merge pull request #10795 from ever-co/feat/gw-export-redact-ever-works

fix(integration-ever-works): redact the connection secrets in export archives
This commit is contained in:
Ruslan Konviser
2026-10-16 21:20:28 +00:00
committed by GitHub
2 changed files with 26 additions and 2 deletions
@@ -404,6 +404,23 @@ describe('export redaction of the real entity graph', () => {
expect(redactForExport(address, custom).address).toBe('docs@acme.com');
});
it('masks the Ever Works connection secrets without breaking the NOT NULL key column', () => {
const connection = pluginEntities.find((entity) => entity.name === 'EverWorksConnection');
expect(connection).toBeDefined();
const row = Object.assign(new (connection as any)(), {
apiBaseUrl: 'https://api.example.com/api',
apiKeyEncrypted: 'v1:k:' + 'a'.repeat(24) + ':' + 'b'.repeat(32) + ':' + 'c'.repeat(64),
webhookSecretEncrypted: 'v1:k:' + 'd'.repeat(24) + ':' + 'e'.repeat(32) + ':' + 'f'.repeat(64)
});
const redacted = redactForExport(connection, row);
// `apiKeyEncrypted` is NOT NULL: a fixed mask imports, an empty cell would not.
expect(redacted.apiKeyEncrypted).toBe(OPAQUE_EXPORT_MASK);
expect(redacted.webhookSecretEncrypted).toBe('');
expect(redacted.apiBaseUrl).toBe('https://api.example.com/api');
});
it('still covers the two key/value columns the name pattern cannot see', () => {
// `settingsValue` and `value` look like nothing; they hold every integration token and
// every object-storage secret key in the product.
@@ -1,5 +1,5 @@
import { ID } from '@gauzy/contracts';
import { ColumnIndex, MultiORMColumn, MultiORMEntity, TenantOrganizationBaseEntity } from '@gauzy/core';
import { ColumnIndex, ExportRedacted, MultiORMColumn, MultiORMEntity, TenantOrganizationBaseEntity } from '@gauzy/core';
import { MikroOrmEverWorksConnectionRepository } from './repository/mikro-orm-ever-works-connection.repository';
/** How the connection authenticates to Ever Works: an integration key now, an Ever ID token later (plan 02 §5). */
@@ -63,7 +63,13 @@ export class EverWorksConnection extends TenantOrganizationBaseEntity {
@MultiORMColumn({ type: 'varchar', length: 32, nullable: true })
keyPrefix?: string | null;
/** The integration key, encrypted. */
/**
* The integration key, encrypted. An export archive carries a fixed mask instead (`opaque`, not
* `blank`: the column is NOT NULL, and an empty cell would make the import refuse the row). The
* ciphertext is bound to this row's id and the instance's key, so it could not be read after an
* import anyway: an imported connection fails its health check and asks for a new key.
*/
@ExportRedacted({ opaque: true })
@MultiORMColumn({ type: 'text' })
apiKeyEncrypted!: string;
@@ -82,6 +88,7 @@ export class EverWorksConnection extends TenantOrganizationBaseEntity {
@MultiORMColumn({ type: 'varchar', length: 64, nullable: true })
webhookSubscriptionId?: string | null;
@ExportRedacted({ blank: true })
@MultiORMColumn({ type: 'text', nullable: true })
webhookSecretEncrypted?: string | null;