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

DXCDT-84: Resource Exclusion #468

Merged
merged 11 commits into from
Apr 1, 2022
11 changes: 7 additions & 4 deletions src/context/directory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { loadFileAndReplaceKeywords, Auth0 } from '../../tools';

import cleanAssets from '../../readonly';
import log from '../../logger';
import handlers from './handlers';
import handlers, { DirectoryHandler } from './handlers';
import {
isDirectory, isFile, stripIdentifiers, toConfigFn
} from '../../utils';
import { Assets, Auth0APIClient, Config } from '../../types'
import { Assets, Auth0APIClient, Config, AssetTypes } from '../../types'

type KeywordMappings = { [key: string]: (string | number)[] | string | number }

Expand Down Expand Up @@ -78,14 +78,17 @@ export default class DirectoryContext {
// Copy clients to be used by handlers which require converting client_id to the name
// Must copy as the client_id will be stripped if AUTH0_EXPORT_IDENTIFIERS is false
//@ts-ignore because assets haven't been typed yet TODO: type assets
this.assets.clientsOrig = [...this.assets.clients];
this.assets.clientsOrig = [...this.assets.clients || []];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clients could theoretically be excluded and thus be empty so need to default to empty array.


// Optionally Strip identifiers
if (!this.config.AUTH0_EXPORT_IDENTIFIERS) {
this.assets = stripIdentifiers(auth0, this.assets);
}

await Promise.all(Object.entries(handlers).map(async ([name, handler]) => {
await Promise.all(Object.entries(handlers).filter(([handlerName]: [AssetTypes, DirectoryHandler<any>]) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This array filter function is the primary mechanism for exclusion.

const excludedAssetTypes = this.config.AUTH0_EXCLUDED || []
return !excludedAssetTypes.includes(handlerName)
}).map(async ([name, handler]) => {
try {
await handler.dump(this);
} catch (err) {
Expand Down
1 change: 1 addition & 0 deletions src/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const nonPrimitiveProps: (keyof Config)[] = [
'AUTH0_EXCLUDED_CONNECTIONS',
'AUTH0_EXCLUDED_RESOURCE_SERVERS',
'AUTH0_EXCLUDED_DEFAULTS',
'AUTH0_EXCLUDED',
'EXCLUDED_PROPS',
'INCLUDED_PROPS'
];
Expand Down
9 changes: 6 additions & 3 deletions src/context/yaml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import log from '../../logger';
import {
isFile, toConfigFn, stripIdentifiers, formatResults, recordsSorter
} from '../../utils';
import handlers from './handlers';
import handlers, { YAMLHandler } from './handlers';
import cleanAssets from '../../readonly';
import { Assets, Config, Auth0APIClient } from '../../types'
import { Assets, Config, Auth0APIClient, AssetTypes } from '../../types'

type KeywordMappings = { [key: string]: (string | number)[] | string | number }

Expand Down Expand Up @@ -101,7 +101,10 @@ export default class YAMLContext {
throw new Error(`Problem loading tenant data from Auth0 ${err}${extraMessage}`);
}

await Promise.all(Object.entries(handlers).map(async ([name, handler]) => {
await Promise.all(Object.entries(handlers).filter(([handlerName]: [AssetTypes, YAMLHandler<any>]) => {
const excludedAssetTypes = this.config.AUTH0_EXCLUDED || []
return !excludedAssetTypes.includes(handlerName)
}).map(async ([name, handler]) => {
try {
const data = await handler.dump(this);
if (data) {
Expand Down
12 changes: 7 additions & 5 deletions src/tools/auth0/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ export default class Auth0 {
this.config = config;
this.assets = assets;

this.handlers = Object.values(handlers).map((h) => {
//@ts-ignore because prompts don't appear to have been universally implemented yet
const handler = new h.default({ client: this.client, config: this.config });
return handler
});
this.handlers = Object.values(handlers).map((handler) => {
//@ts-ignore because class expects `type` property but gets directly injected into class constructors
return new handler.default({ client: this.client, config: this.config });
}).filter((handler) => {
const excludedAssetTypes = config('AUTH0_EXCLUDED') || []
return !excludedAssetTypes.includes(handler.type)
})
}

async runStage(stage: Stage): Promise<void> {
Expand Down
14 changes: 8 additions & 6 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,25 +115,27 @@ export type Config = {
AUTH0_CLIENT_SECRET: string
AUTH0_INPUT_FILE: string
AUTH0_ALLOW_DELETE: boolean
AUTH0_EXCLUDED: AssetTypes[]
EXTENSION_SECRET: string
AUTH0_ACCESS_TOKEN?: string
AUTH0_BASE_PATH?: string
AUTH0_AUDIENCE?: string
AUTH0_API_MAX_RETRIES?: number
AUTH0_KEYWORD_REPLACE_MAPPINGS?: { [key: string]: string[] | string }
AUTH0_EXCLUDED_RULES?: string[]
AUTH0_EXCLUDED_CLIENTS?: string[]
AUTH0_EXCLUDED_DATABASES?: string[]
AUTH0_EXCLUDED_CONNECTIONS?: string[]
AUTH0_EXCLUDED_RESOURCE_SERVERS?: string[]
AUTH0_EXCLUDED_DEFAULTS?: string[]
AUTH0_EXPORT_IDENTIFIERS?: boolean
AUTH0_CONNECTIONS_DIRECTORY?: string
EXCLUDED_PROPS?: {
[key: string]: string[]
}
INCLUDED_PROPS?: {}
AUTH0_IGNORE_UNAVAILABLE_MIGRATIONS?: boolean
// Eventually deprecate:
AUTH0_EXCLUDED_RULES?: string[]
AUTH0_EXCLUDED_CLIENTS?: string[]
AUTH0_EXCLUDED_DATABASES?: string[]
AUTH0_EXCLUDED_CONNECTIONS?: string[]
AUTH0_EXCLUDED_RESOURCE_SERVERS?: string[]
AUTH0_EXCLUDED_DEFAULTS?: string[]
}// TODO: replace with a more accurate representation of the Config type

export type Asset = { [key: string]: any }
Expand Down
34 changes: 34 additions & 0 deletions test/tools/auth0/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { expect } from 'chai';
import Auth0 from '../../../src/tools/auth0'
import { Auth0APIClient, Assets } from '../../../src/types'

const mockEmptyClient = {} as Auth0APIClient
const mockEmptyAssets = {} as Assets

describe("#Auth0 class", () => {

describe("#resource exclusion", () => {
it('should exclude handlers listed in AUTH0_EXCLUDED from Auth0 class', () => {

const auth0WithoutExclusions = new Auth0(mockEmptyClient, mockEmptyAssets, () => []);

const AUTH0_EXCLUDED = ['rules', 'organizations', 'connections']
const auth0WithExclusions = new Auth0(mockEmptyClient, mockEmptyAssets, () => AUTH0_EXCLUDED);

expect(auth0WithoutExclusions.handlers.length).to.equal(auth0WithExclusions.handlers.length + AUTH0_EXCLUDED.length) // Number of handlers is reduced by number of exclusions

const areAllExcludedHandlersAbsent = auth0WithExclusions.handlers.some((handler) => {
return AUTH0_EXCLUDED.includes(handler.type)
})

expect(areAllExcludedHandlersAbsent).to.be.false;
})

it('should not exclude any handlers if AUTH0_EXCLUDED is undefined', () => {
const AUTH0_EXCLUDED = undefined
const auth0 = new Auth0(mockEmptyClient, mockEmptyAssets, () => AUTH0_EXCLUDED);

expect(auth0.handlers.length).to.be.greaterThan(0)
})
})
})
32 changes: 17 additions & 15 deletions test/tools/auth0/validator.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { expect } from 'chai';
import Auth0 from '../../../src/tools/auth0';
import constants from '../../../src/tools/constants';

const mockConfigFn = () => { };

describe('#schema validation tests', () => {
const client = {
rules: {
Expand Down Expand Up @@ -33,13 +35,13 @@ describe('#schema validation tests', () => {
};

const checkPassed = (data, done) => {
const auth0 = new Auth0(client, data, {});
const auth0 = new Auth0(client, data, mockConfigFn);

auth0.validate().then(passedCb(done), failedCb(done));
};

const checkRequired = (field, data, done) => {
const auth0 = new Auth0({}, data, {});
const auth0 = new Auth0({}, data, mockConfigFn);

auth0
.validate()
Expand All @@ -50,7 +52,7 @@ describe('#schema validation tests', () => {
};

const checkEnum = (data, done) => {
const auth0 = new Auth0({}, data, {});
const auth0 = new Auth0({}, data, mockConfigFn);

auth0
.validate()
Expand All @@ -61,7 +63,7 @@ describe('#schema validation tests', () => {
};

const checkTypeError = (field, expectedType, data, done) => {
const auth0 = new Auth0({}, data, {});
const auth0 = new Auth0({}, data, mockConfigFn);

auth0
.validate()
Expand All @@ -77,7 +79,7 @@ describe('#schema validation tests', () => {
anything: 'anything'
} ];

const auth0 = new Auth0({}, { branding: data }, {});
const auth0 = new Auth0({}, { branding: data }, mockConfigFn);

auth0.validate().then(failedCb(done), passedCb(done, 'should be object'));
});
Expand Down Expand Up @@ -125,7 +127,7 @@ describe('#schema validation tests', () => {
audience: 'audience'
} ];

const auth0 = new Auth0({}, { clientGrants: data }, {});
const auth0 = new Auth0({}, { clientGrants: data }, mockConfigFn);

auth0.validate().then(failedCb(done), passedCb(done, 'should be array'));
});
Expand Down Expand Up @@ -155,7 +157,7 @@ describe('#schema validation tests', () => {
name: ''
} ];

const auth0 = new Auth0({}, { clients: data }, {});
const auth0 = new Auth0({}, { clients: data }, mockConfigFn);

auth0
.validate()
Expand Down Expand Up @@ -235,7 +237,7 @@ describe('#schema validation tests', () => {
anything: 'anything'
} ];

const auth0 = new Auth0({}, { emailProvider: data }, {});
const auth0 = new Auth0({}, { emailProvider: data }, mockConfigFn);

auth0.validate().then(failedCb(done), passedCb(done, 'should be object'));
});
Expand Down Expand Up @@ -490,7 +492,7 @@ describe('#schema validation tests', () => {
anything: 'anything'
} ];

const auth0 = new Auth0({}, { prompts: data }, {});
const auth0 = new Auth0({}, { prompts: data }, mockConfigFn);

auth0.validate().then(failedCb(done), passedCb(done, 'should be object'));
});
Expand Down Expand Up @@ -545,7 +547,7 @@ describe('#schema validation tests', () => {
name: '-rule-'
} ];

const auth0 = new Auth0({}, { rules: data }, {});
const auth0 = new Auth0({}, { rules: data }, mockConfigFn);

auth0
.validate()
Expand Down Expand Up @@ -595,7 +597,7 @@ describe('#schema validation tests', () => {
value: 'value'
} ];

const auth0 = new Auth0({}, { rulesConfigs: data }, {});
const auth0 = new Auth0({}, { rulesConfigs: data }, mockConfigFn);

auth0
.validate()
Expand Down Expand Up @@ -626,7 +628,7 @@ describe('#schema validation tests', () => {
name: '-hook-'
} ];

const auth0 = new Auth0({}, { hooks: data }, {});
const auth0 = new Auth0({}, { hooks: data }, mockConfigFn);

auth0
.validate()
Expand Down Expand Up @@ -668,7 +670,7 @@ describe('#schema validation tests', () => {
anything: 'anything'
} ];

const auth0 = new Auth0({}, { tenant: data }, {});
const auth0 = new Auth0({}, { tenant: data }, mockConfigFn);

auth0.validate().then(failedCb(done), passedCb(done, 'should be object'));
});
Expand All @@ -686,7 +688,7 @@ describe('#schema validation tests', () => {
it('should fail validation if migrations is not an object', (done) => {
const data = '';

const auth0 = new Auth0({}, { migrations: data }, {});
const auth0 = new Auth0({}, { migrations: data }, mockConfigFn);

auth0.validate().then(failedCb(done), passedCb(done, 'should be object'));
});
Expand All @@ -696,7 +698,7 @@ describe('#schema validation tests', () => {
migration_flag: 'string'
};

const auth0 = new Auth0({}, { migrations: data }, {});
const auth0 = new Auth0({}, { migrations: data }, mockConfigFn);

auth0.validate().then(failedCb(done), passedCb(done, 'should be boolean'));
});
Expand Down
4 changes: 3 additions & 1 deletion test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
toConfigFn
} from '../src/utils';

const mockConfigFn = () => { };

describe('#utils', function() {
it('should check if directory exist', () => {
const dirExist = path.join(testDataDir, 'utils', 'isdir');
Expand Down Expand Up @@ -95,7 +97,7 @@ describe('#utils', function() {
rulesConfigs: [ { key: 'test', value: 'test' } ]
};

const auth0 = new Auth0(mockMgmtClient(), {}, {});
const auth0 = new Auth0(mockMgmtClient(), {}, mockConfigFn);

expect(stripIdentifiers(auth0, assets)).to.deep.equal({
clients: [
Expand Down