@j-schreiber/sf-cli-security-audit 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +10 -2
  2. package/lib/commands/org/audit/init.d.ts +17 -0
  3. package/lib/commands/org/audit/init.js +61 -0
  4. package/lib/commands/org/audit/init.js.map +1 -0
  5. package/lib/commands/org/audit/run.d.ts +22 -0
  6. package/lib/commands/org/audit/run.js +113 -0
  7. package/lib/commands/org/audit/run.js.map +1 -0
  8. package/lib/libs/audit/types.d.ts +154 -0
  9. package/lib/libs/audit/types.js +2 -0
  10. package/lib/libs/audit/types.js.map +1 -0
  11. package/lib/libs/config/audit-run/auditConfigFileManager.d.ts +26 -0
  12. package/lib/libs/config/audit-run/auditConfigFileManager.js +98 -0
  13. package/lib/libs/config/audit-run/auditConfigFileManager.js.map +1 -0
  14. package/lib/libs/config/audit-run/schema.d.ts +100 -0
  15. package/lib/libs/config/audit-run/schema.js +45 -0
  16. package/lib/libs/config/audit-run/schema.js.map +1 -0
  17. package/lib/libs/config/defaultPolicyClassification.d.ts +2 -0
  18. package/lib/libs/config/defaultPolicyClassification.js +63 -0
  19. package/lib/libs/config/defaultPolicyClassification.js.map +1 -0
  20. package/lib/libs/config/queries.d.ts +5 -0
  21. package/lib/libs/config/queries.js +6 -0
  22. package/lib/libs/config/queries.js.map +1 -0
  23. package/lib/libs/config/registries/connectedApps.d.ts +5 -0
  24. package/lib/libs/config/registries/connectedApps.js +13 -0
  25. package/lib/libs/config/registries/connectedApps.js.map +1 -0
  26. package/lib/libs/config/registries/permissionSets.d.ts +5 -0
  27. package/lib/libs/config/registries/permissionSets.js +11 -0
  28. package/lib/libs/config/registries/permissionSets.js.map +1 -0
  29. package/lib/libs/config/registries/profiles.d.ts +5 -0
  30. package/lib/libs/config/registries/profiles.js +13 -0
  31. package/lib/libs/config/registries/profiles.js.map +1 -0
  32. package/lib/libs/config/registries/ruleRegistry.d.ts +29 -0
  33. package/lib/libs/config/registries/ruleRegistry.js +48 -0
  34. package/lib/libs/config/registries/ruleRegistry.js.map +1 -0
  35. package/lib/libs/config/registries/types.d.ts +7 -0
  36. package/lib/libs/config/registries/types.js +2 -0
  37. package/lib/libs/config/registries/types.js.map +1 -0
  38. package/lib/libs/mdapiRetriever.d.ts +18 -0
  39. package/lib/libs/mdapiRetriever.js +60 -0
  40. package/lib/libs/mdapiRetriever.js.map +1 -0
  41. package/lib/libs/policies/auditRun.d.ts +36 -0
  42. package/lib/libs/policies/auditRun.js +92 -0
  43. package/lib/libs/policies/auditRun.js.map +1 -0
  44. package/lib/libs/policies/connectedAppPolicy.d.ts +18 -0
  45. package/lib/libs/policies/connectedAppPolicy.js +78 -0
  46. package/lib/libs/policies/connectedAppPolicy.js.map +1 -0
  47. package/lib/libs/policies/initialisation/auditConfig.d.ts +27 -0
  48. package/lib/libs/policies/initialisation/auditConfig.js +41 -0
  49. package/lib/libs/policies/initialisation/auditConfig.js.map +1 -0
  50. package/lib/libs/policies/initialisation/permissionsClassification.d.ts +17 -0
  51. package/lib/libs/policies/initialisation/permissionsClassification.js +71 -0
  52. package/lib/libs/policies/initialisation/permissionsClassification.js.map +1 -0
  53. package/lib/libs/policies/initialisation/policyConfigs.d.ts +25 -0
  54. package/lib/libs/policies/initialisation/policyConfigs.js +67 -0
  55. package/lib/libs/policies/initialisation/policyConfigs.js.map +1 -0
  56. package/lib/libs/policies/interfaces/policyRuleInterfaces.d.ts +30 -0
  57. package/lib/libs/policies/interfaces/policyRuleInterfaces.js +2 -0
  58. package/lib/libs/policies/interfaces/policyRuleInterfaces.js.map +1 -0
  59. package/lib/libs/policies/permissionSetPolicy.d.ts +17 -0
  60. package/lib/libs/policies/permissionSetPolicy.js +61 -0
  61. package/lib/libs/policies/permissionSetPolicy.js.map +1 -0
  62. package/lib/libs/policies/policy.d.ts +32 -0
  63. package/lib/libs/policies/policy.js +95 -0
  64. package/lib/libs/policies/policy.js.map +1 -0
  65. package/lib/libs/policies/profilePolicy.d.ts +17 -0
  66. package/lib/libs/policies/profilePolicy.js +71 -0
  67. package/lib/libs/policies/profilePolicy.js.map +1 -0
  68. package/lib/libs/policies/rules/allUsedAppsUnderManagement.d.ts +7 -0
  69. package/lib/libs/policies/rules/allUsedAppsUnderManagement.js +23 -0
  70. package/lib/libs/policies/rules/allUsedAppsUnderManagement.js.map +1 -0
  71. package/lib/libs/policies/rules/enforceCustomPermsClassificationOnProfiles.d.ts +7 -0
  72. package/lib/libs/policies/rules/enforceCustomPermsClassificationOnProfiles.js +51 -0
  73. package/lib/libs/policies/rules/enforceCustomPermsClassificationOnProfiles.js.map +1 -0
  74. package/lib/libs/policies/rules/enforceUserPermsClassificationOnPermSets.d.ts +7 -0
  75. package/lib/libs/policies/rules/enforceUserPermsClassificationOnPermSets.js +51 -0
  76. package/lib/libs/policies/rules/enforceUserPermsClassificationOnPermSets.js.map +1 -0
  77. package/lib/libs/policies/rules/enforceUserPermsClassificationOnProfiles.d.ts +7 -0
  78. package/lib/libs/policies/rules/enforceUserPermsClassificationOnProfiles.js +53 -0
  79. package/lib/libs/policies/rules/enforceUserPermsClassificationOnProfiles.js.map +1 -0
  80. package/lib/libs/policies/rules/noUserCanSelfAuthorize.d.ts +7 -0
  81. package/lib/libs/policies/rules/noUserCanSelfAuthorize.js +31 -0
  82. package/lib/libs/policies/rules/noUserCanSelfAuthorize.js.map +1 -0
  83. package/lib/libs/policies/rules/policyRule.d.ts +16 -0
  84. package/lib/libs/policies/rules/policyRule.js +29 -0
  85. package/lib/libs/policies/rules/policyRule.js.map +1 -0
  86. package/lib/libs/policies/salesforceStandardTypes.d.ts +39 -0
  87. package/lib/libs/policies/salesforceStandardTypes.js +2 -0
  88. package/lib/libs/policies/salesforceStandardTypes.js.map +1 -0
  89. package/lib/libs/policies/types.d.ts +36 -0
  90. package/lib/libs/policies/types.js +45 -0
  91. package/lib/libs/policies/types.js.map +1 -0
  92. package/lib/libs/utils.d.ts +3 -0
  93. package/lib/libs/utils.js +13 -0
  94. package/lib/libs/utils.js.map +1 -0
  95. package/lib/ux/auditRunMultiStage.d.ts +65 -0
  96. package/lib/ux/auditRunMultiStage.js +117 -0
  97. package/lib/ux/auditRunMultiStage.js.map +1 -0
  98. package/messages/org.audit.init.md +1 -1
  99. package/messages/org.audit.run.md +0 -4
  100. package/messages/policies.general.md +12 -0
  101. package/messages/rules.connectedApps.md +11 -0
  102. package/oclif.manifest.json +159 -2
  103. package/package.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectedAppPolicy.js","sourceRoot":"","sources":["../../../src/libs/policies/connectedAppPolicy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Connection } from '@salesforce/core';
2
+ import { AuditRunConfig } from '../../config/audit-run/schema.js';
3
+ /**
4
+ * Additional options how the config should be initialised.
5
+ */
6
+ export type AuditInitOptions = {
7
+ targetDir?: string;
8
+ };
9
+ /**
10
+ * Exposes key functionality to load an audit config as static methods. This makes
11
+ * it easy to mock the results during tests.
12
+ */
13
+ export default class AuditConfig {
14
+ /**
15
+ * Initialise a new audit config from target org and writes
16
+ * files to the destination directory.
17
+ *
18
+ * @param con
19
+ */
20
+ static init(targetCon: Connection, opts?: AuditInitOptions): Promise<AuditRunConfig>;
21
+ /**
22
+ * Loads an existing audit config from a source directory
23
+ *
24
+ * @param sourceDir
25
+ */
26
+ static load(sourceDir: string): AuditRunConfig;
27
+ }
@@ -0,0 +1,41 @@
1
+ import AuditConfigFileManager from '../../config/audit-run/auditConfigFileManager.js';
2
+ import { initCustomPermissions, initUserPermissions } from './permissionsClassification.js';
3
+ import { initConnectedApps, initPermissionSets, initProfiles } from './policyConfigs.js';
4
+ /**
5
+ * Exposes key functionality to load an audit config as static methods. This makes
6
+ * it easy to mock the results during tests.
7
+ */
8
+ export default class AuditConfig {
9
+ /**
10
+ * Initialise a new audit config from target org and writes
11
+ * files to the destination directory.
12
+ *
13
+ * @param con
14
+ */
15
+ static async init(targetCon, opts) {
16
+ const fileManager = new AuditConfigFileManager();
17
+ const conf = { classifications: {}, policies: {} };
18
+ conf.classifications.userPermissions = { content: await initUserPermissions(targetCon) };
19
+ const customPerms = await initCustomPermissions(targetCon);
20
+ if (customPerms) {
21
+ conf.classifications.customPermissions = { content: customPerms };
22
+ }
23
+ conf.policies.Profiles = { content: await initProfiles(targetCon) };
24
+ conf.policies.PermissionSets = { content: await initPermissionSets(targetCon) };
25
+ conf.policies.ConnectedApps = { content: initConnectedApps() };
26
+ if (opts?.targetDir) {
27
+ fileManager.save(opts.targetDir, conf);
28
+ }
29
+ return conf;
30
+ }
31
+ /**
32
+ * Loads an existing audit config from a source directory
33
+ *
34
+ * @param sourceDir
35
+ */
36
+ static load(sourceDir) {
37
+ const fileManager = new AuditConfigFileManager();
38
+ return fileManager.parse(sourceDir);
39
+ }
40
+ }
41
+ //# sourceMappingURL=auditConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditConfig.js","sourceRoot":"","sources":["../../../../src/libs/policies/initialisation/auditConfig.ts"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,MAAM,kDAAkD,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC5F,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AASzF;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IAC9B;;;;;OAKG;IACI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAqB,EAAE,IAAuB;QACrE,MAAM,WAAW,GAAG,IAAI,sBAAsB,EAAE,CAAC;QACjD,MAAM,IAAI,GAAmB,EAAE,eAAe,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACnE,IAAI,CAAC,eAAe,CAAC,eAAe,GAAG,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC,SAAS,CAAC,EAAE,CAAC;QACzF,MAAM,WAAW,GAAG,MAAM,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC3D,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,eAAe,CAAC,iBAAiB,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,GAAG,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC,SAAS,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,QAAQ,CAAC,cAAc,GAAG,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;QAChF,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,CAAC;QAC/D,IAAI,IAAI,EAAE,SAAS,EAAE,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,IAAI,CAAC,SAAiB;QAClC,MAAM,WAAW,GAAG,IAAI,sBAAsB,EAAE,CAAC;QACjD,OAAO,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import { Connection } from '@salesforce/core';
2
+ import { NamedPermissionsClassification, PermissionsConfig } from '../../config/audit-run/schema.js';
3
+ /**
4
+ * Initialises a fresh set of user permissions from target org connection
5
+ *
6
+ * @param con
7
+ * @returns
8
+ */
9
+ export declare function initUserPermissions(con: Connection): Promise<PermissionsConfig>;
10
+ /**
11
+ * Initialises a fresh set of custom permissions from the target org
12
+ *
13
+ * @param con
14
+ * @returns
15
+ */
16
+ export declare function initCustomPermissions(con: Connection): Promise<PermissionsConfig | undefined>;
17
+ export declare const classificationSorter: (a: NamedPermissionsClassification, b: NamedPermissionsClassification) => number;
@@ -0,0 +1,71 @@
1
+ import { DEFAULT_CLASSIFICATIONS } from '../../config/defaultPolicyClassification.js';
2
+ import { PolicyRiskLevel, resolveRiskLevelOrdinalValue } from '../types.js';
3
+ import { CUSTOM_PERMS_QUERY } from '../../config/queries.js';
4
+ /**
5
+ * Initialises a fresh set of user permissions from target org connection
6
+ *
7
+ * @param con
8
+ * @returns
9
+ */
10
+ export async function initUserPermissions(con) {
11
+ const permSet = await con.describe('PermissionSet');
12
+ const result = { permissions: {} };
13
+ const perms = parsePermissionsFromPermSet(permSet);
14
+ perms.sort(classificationSorter);
15
+ perms.forEach((perm) => (result.permissions[perm.name] = {
16
+ label: sanitiseLabel(perm.label),
17
+ classification: perm.classification,
18
+ reason: perm.reason,
19
+ }));
20
+ return result;
21
+ }
22
+ /**
23
+ * Initialises a fresh set of custom permissions from the target org
24
+ *
25
+ * @param con
26
+ * @returns
27
+ */
28
+ export async function initCustomPermissions(con) {
29
+ const result = { permissions: {} };
30
+ const customPerms = await con.query(CUSTOM_PERMS_QUERY);
31
+ if (customPerms.records.length === 0) {
32
+ return undefined;
33
+ }
34
+ const perms = customPerms.records.map((cp) => ({
35
+ name: cp.DeveloperName,
36
+ label: cp.MasterLabel,
37
+ classification: PolicyRiskLevel.UNKNOWN,
38
+ }));
39
+ perms.forEach((perm) => (result.permissions[perm.name] = {
40
+ label: perm.label,
41
+ classification: perm.classification,
42
+ }));
43
+ return result;
44
+ }
45
+ function parsePermissionsFromPermSet(describe) {
46
+ const permFields = describe.fields.filter((field) => field.name.startsWith('Permissions'));
47
+ return permFields.map((field) => {
48
+ const policyName = field.name.replace('Permissions', '');
49
+ const defaultDef = DEFAULT_CLASSIFICATIONS[policyName];
50
+ if (defaultDef) {
51
+ return {
52
+ label: field.label,
53
+ name: policyName,
54
+ classification: defaultDef.classification,
55
+ reason: defaultDef.reason,
56
+ };
57
+ }
58
+ else {
59
+ return {
60
+ label: field.label,
61
+ name: policyName,
62
+ classification: PolicyRiskLevel.UNKNOWN,
63
+ };
64
+ }
65
+ });
66
+ }
67
+ function sanitiseLabel(rawLabel) {
68
+ return rawLabel?.replace(/[ \t]+$|[\r\n]+/g, '');
69
+ }
70
+ export const classificationSorter = (a, b) => resolveRiskLevelOrdinalValue(a.classification) - resolveRiskLevelOrdinalValue(b.classification);
71
+ //# sourceMappingURL=permissionsClassification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionsClassification.js","sourceRoot":"","sources":["../../../../src/libs/policies/initialisation/permissionsClassification.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { Connection } from '@salesforce/core';
2
+ import { BasePolicyFileContent, PermSetsPolicyFileContent, ProfilesPolicyFileContent } from '../../config/audit-run/schema.js';
3
+ /**
4
+ * Initialises a new profiles policy with the local org's
5
+ * profiles and all default rules enabled.
6
+ *
7
+ * @param targetOrgCon
8
+ * @param targetDir
9
+ * @returns
10
+ */
11
+ export declare function initProfiles(targetOrgCon: Connection): Promise<ProfilesPolicyFileContent>;
12
+ /**
13
+ * Initialises a new permission sets policy with the local org's custom
14
+ * permissions and all default rules enabled.
15
+ *
16
+ * @param targetOrgCon
17
+ * @returns
18
+ */
19
+ export declare function initPermissionSets(targetOrgCon: Connection): Promise<PermSetsPolicyFileContent>;
20
+ /**
21
+ * Initialises a new connected apps policy with default rules enabled.
22
+ *
23
+ * @returns
24
+ */
25
+ export declare function initConnectedApps(): BasePolicyFileContent;
@@ -0,0 +1,67 @@
1
+ import { PERMISSION_SETS_QUERY, PROFILES_QUERY } from '../../config/queries.js';
2
+ import { ProfilesRegistry } from '../../config/registries/profiles.js';
3
+ import { PermissionRiskLevelPresets } from '../types.js';
4
+ import { PermissionSetsRegistry } from '../../config/registries/permissionSets.js';
5
+ import { ConnectedAppsRegistry } from '../../config/registries/connectedApps.js';
6
+ /**
7
+ * Initialises a new profiles policy with the local org's
8
+ * profiles and all default rules enabled.
9
+ *
10
+ * @param targetOrgCon
11
+ * @param targetDir
12
+ * @returns
13
+ */
14
+ export async function initProfiles(targetOrgCon) {
15
+ const profiles = await targetOrgCon.query(PROFILES_QUERY);
16
+ const content = { enabled: true, profiles: {}, rules: {} };
17
+ profiles.records.forEach((permsetRecord) => {
18
+ content.profiles[permsetRecord.Profile.Name] = { preset: PermissionRiskLevelPresets.UNKNOWN };
19
+ });
20
+ ProfilesRegistry.registeredRules().forEach((ruleName) => {
21
+ content.rules[ruleName] = {
22
+ enabled: true,
23
+ };
24
+ });
25
+ return content;
26
+ }
27
+ /**
28
+ * Initialises a new permission sets policy with the local org's custom
29
+ * permissions and all default rules enabled.
30
+ *
31
+ * @param targetOrgCon
32
+ * @returns
33
+ */
34
+ export async function initPermissionSets(targetOrgCon) {
35
+ const permSets = await targetOrgCon.query(PERMISSION_SETS_QUERY);
36
+ const content = {
37
+ enabled: true,
38
+ permissionSets: {},
39
+ rules: {},
40
+ };
41
+ permSets.records
42
+ .filter((permsetRecord) => permsetRecord.IsCustom)
43
+ .forEach((permsetRecord) => {
44
+ content.permissionSets[permsetRecord.Name] = { preset: PermissionRiskLevelPresets.UNKNOWN };
45
+ });
46
+ PermissionSetsRegistry.registeredRules().forEach((ruleName) => {
47
+ content.rules[ruleName] = {
48
+ enabled: true,
49
+ };
50
+ });
51
+ return content;
52
+ }
53
+ /**
54
+ * Initialises a new connected apps policy with default rules enabled.
55
+ *
56
+ * @returns
57
+ */
58
+ export function initConnectedApps() {
59
+ const content = { enabled: true, rules: {} };
60
+ ConnectedAppsRegistry.registeredRules().forEach((ruleName) => {
61
+ content.rules[ruleName] = {
62
+ enabled: true,
63
+ };
64
+ });
65
+ return content;
66
+ }
67
+ //# sourceMappingURL=policyConfigs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policyConfigs.js","sourceRoot":"","sources":["../../../../src/libs/policies/initialisation/policyConfigs.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAOhF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEjF;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,YAAwB;IACzD,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,KAAK,CAAgB,cAAc,CAAC,CAAC;IACzE,MAAM,OAAO,GAA8B,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACtF,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,EAAE;QACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,0BAA0B,CAAC,OAAO,EAAE,CAAC;IAChG,CAAC,CAAC,CAAC;IACH,gBAAgB,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QACtD,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG;YACxB,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,YAAwB;IAC/D,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,KAAK,CAAgB,qBAAqB,CAAC,CAAC;IAChF,MAAM,OAAO,GAA8B;QACzC,OAAO,EAAE,IAAI;QACb,cAAc,EAAE,EAAE;QAClB,KAAK,EAAE,EAAE;KACV,CAAC;IACF,QAAQ,CAAC,OAAO;SACb,MAAM,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC;SACjD,OAAO,CAAC,CAAC,aAAa,EAAE,EAAE;QACzB,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,0BAA0B,CAAC,OAAO,EAAE,CAAC;IAC9F,CAAC,CAAC,CAAC;IACL,sBAAsB,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC5D,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG;YACxB,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,OAAO,GAA0B,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACpE,qBAAqB,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,EAAE;QAC3D,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG;YACxB,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { Connection } from '@salesforce/core';
2
+ import { AuditPolicyResult, PolicyRuleExecutionResult } from '../../audit/types.js';
3
+ import { Optional } from '../../utils.js';
4
+ /**
5
+ * A rule must only implement a subset of the rule result. All optional
6
+ * properties are completed by the policy.
7
+ */
8
+ export type PartialPolicyRuleResult = Optional<PolicyRuleExecutionResult, 'isCompliant' | 'compliantEntities' | 'violatedEntities'>;
9
+ /**
10
+ *
11
+ */
12
+ export type RowLevelPolicyRule<ResolvedEntityType> = {
13
+ run(context: RuleAuditContext<ResolvedEntityType>): Promise<PartialPolicyRuleResult>;
14
+ };
15
+ export type IPolicy = {
16
+ run(context: AuditContext): Promise<AuditPolicyResult>;
17
+ };
18
+ export type AuditContext = {
19
+ /**
20
+ * Connection to the target org
21
+ */
22
+ targetOrgConnection: Connection;
23
+ };
24
+ export type RuleAuditContext<T> = AuditContext & {
25
+ /**
26
+ * Resolved entities from the policy. Can be permission sets,
27
+ * profiles, users, connected apps, etc.
28
+ */
29
+ resolvedEntities: Record<string, T>;
30
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=policyRuleInterfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policyRuleInterfaces.js","sourceRoot":"","sources":["../../../../src/libs/policies/interfaces/policyRuleInterfaces.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import { PermissionSet } from '@jsforce/jsforce-node/lib/api/metadata.js';
2
+ import { AuditRunConfig, PermSetsPolicyFileContent } from '../config/audit-run/schema.js';
3
+ import RuleRegistry from '../config/registries/ruleRegistry.js';
4
+ import { AuditContext } from './interfaces/policyRuleInterfaces.js';
5
+ import Policy, { ResolveEntityResult } from './policy.js';
6
+ export type ResolvedPermissionSet = {
7
+ name: string;
8
+ preset: string;
9
+ metadata: PermissionSet;
10
+ };
11
+ export default class PermissionSetPolicy extends Policy {
12
+ config: PermSetsPolicyFileContent;
13
+ auditContext: AuditRunConfig;
14
+ private totalEntities;
15
+ constructor(config: PermSetsPolicyFileContent, auditContext: AuditRunConfig, registry?: RuleRegistry);
16
+ protected resolveEntities(context: AuditContext): Promise<ResolveEntityResult>;
17
+ }
@@ -0,0 +1,61 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import MdapiRetriever from '../mdapiRetriever.js';
3
+ import PermSetsRuleRegistry from '../config/registries/permissionSets.js';
4
+ import Policy, { getTotal } from './policy.js';
5
+ import { PermissionRiskLevelPresets } from './types.js';
6
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'policies.general');
8
+ export default class PermissionSetPolicy extends Policy {
9
+ config;
10
+ auditContext;
11
+ totalEntities;
12
+ constructor(config, auditContext, registry = new PermSetsRuleRegistry()) {
13
+ super(config, auditContext, registry);
14
+ this.config = config;
15
+ this.auditContext = auditContext;
16
+ this.totalEntities = this.config.permissionSets ? Object.keys(this.config.permissionSets).length : 0;
17
+ }
18
+ async resolveEntities(context) {
19
+ this.emit('entityresolve', {
20
+ total: this.totalEntities,
21
+ resolved: 0,
22
+ });
23
+ const successfullyResolved = {};
24
+ const unresolved = {};
25
+ const retriever = new MdapiRetriever(context.targetOrgConnection);
26
+ const resolvedPermsets = await retriever.retrievePermissionsets(filterCategorizedPermsets(this.config.permissionSets));
27
+ Object.entries(resolvedPermsets).forEach(([permsetName, resolvedPermset]) => {
28
+ successfullyResolved[permsetName] = {
29
+ metadata: resolvedPermset,
30
+ preset: this.config.permissionSets[permsetName].preset,
31
+ name: permsetName,
32
+ };
33
+ });
34
+ Object.entries(this.config.permissionSets).forEach(([key, val]) => {
35
+ if (successfullyResolved[key] === undefined) {
36
+ if (val.preset === PermissionRiskLevelPresets.UNKNOWN) {
37
+ unresolved[key] = { name: key, message: messages.getMessage('preset-unknown', ['Permission Set']) };
38
+ }
39
+ else {
40
+ unresolved[key] = { name: key, message: messages.getMessage('entity-not-found') };
41
+ }
42
+ }
43
+ });
44
+ const result = { resolvedEntities: successfullyResolved, ignoredEntities: Object.values(unresolved) };
45
+ this.emit('entityresolve', {
46
+ total: this.totalEntities,
47
+ resolved: getTotal(result),
48
+ });
49
+ return result;
50
+ }
51
+ }
52
+ function filterCategorizedPermsets(permSets) {
53
+ const filteredNames = [];
54
+ Object.entries(permSets).forEach(([key, val]) => {
55
+ if (val.preset !== PermissionRiskLevelPresets.UNKNOWN) {
56
+ filteredNames.push(key);
57
+ }
58
+ });
59
+ return filteredNames;
60
+ }
61
+ //# sourceMappingURL=permissionSetPolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionSetPolicy.js","sourceRoot":"","sources":["../../../src/libs/policies/permissionSetPolicy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import EventEmitter from 'node:events';
2
+ import { AuditPolicyResult, EntityResolveError } from '../audit/types.js';
3
+ import { AuditRunConfig, BasePolicyFileContent } from '../config/audit-run/schema.js';
4
+ import RuleRegistry from '../config/registries/ruleRegistry.js';
5
+ import { RegistryRuleResolveResult } from '../config/registries/types.js';
6
+ import { AuditContext, IPolicy } from './interfaces/policyRuleInterfaces.js';
7
+ export type ResolveEntityResult = {
8
+ resolvedEntities: Record<string, unknown>;
9
+ ignoredEntities: EntityResolveError[];
10
+ };
11
+ export default abstract class Policy extends EventEmitter implements IPolicy {
12
+ config: BasePolicyFileContent;
13
+ auditConfig: AuditRunConfig;
14
+ protected registry: RuleRegistry;
15
+ protected resolvedRules: RegistryRuleResolveResult;
16
+ protected entities?: ResolveEntityResult;
17
+ constructor(config: BasePolicyFileContent, auditConfig: AuditRunConfig, registry: RuleRegistry);
18
+ /**
19
+ * Resolves all entities of the policy.
20
+ */
21
+ resolve(context: AuditContext): Promise<ResolveEntityResult>;
22
+ /**
23
+ * Runs all rules of a policy. If the entities are not yet resolved, they are
24
+ * resolved on the fly before rules are executed.
25
+ *
26
+ * @param context
27
+ * @returns
28
+ */
29
+ run(context: AuditContext): Promise<AuditPolicyResult>;
30
+ protected abstract resolveEntities(context: AuditContext): Promise<ResolveEntityResult>;
31
+ }
32
+ export declare function getTotal(resolveResult: ResolveEntityResult): number;
@@ -0,0 +1,95 @@
1
+ import EventEmitter from 'node:events';
2
+ export default class Policy extends EventEmitter {
3
+ config;
4
+ auditConfig;
5
+ registry;
6
+ resolvedRules;
7
+ entities;
8
+ constructor(config, auditConfig, registry) {
9
+ super();
10
+ this.config = config;
11
+ this.auditConfig = auditConfig;
12
+ this.registry = registry;
13
+ this.resolvedRules = registry.resolveRules(config.rules, auditConfig);
14
+ }
15
+ /**
16
+ * Resolves all entities of the policy.
17
+ */
18
+ async resolve(context) {
19
+ if (!this.entities) {
20
+ this.entities = await this.resolveEntities(context);
21
+ }
22
+ return this.entities;
23
+ }
24
+ /**
25
+ * Runs all rules of a policy. If the entities are not yet resolved, they are
26
+ * resolved on the fly before rules are executed.
27
+ *
28
+ * @param context
29
+ * @returns
30
+ */
31
+ async run(context) {
32
+ if (!this.config.enabled) {
33
+ return {
34
+ isCompliant: true,
35
+ enabled: false,
36
+ executedRules: {},
37
+ skippedRules: [],
38
+ auditedEntities: [],
39
+ ignoredEntities: [],
40
+ };
41
+ }
42
+ const resolveResult = await this.resolve(context);
43
+ const ruleResultPromises = Array();
44
+ for (const rule of this.resolvedRules.enabledRules) {
45
+ ruleResultPromises.push(rule.run({ ...context, resolvedEntities: resolveResult.resolvedEntities }));
46
+ }
47
+ const ruleResults = await Promise.all(ruleResultPromises);
48
+ const executedRules = {};
49
+ for (const ruleResult of ruleResults) {
50
+ const { compliantEntities, violatedEntities } = evalResolvedEntities(ruleResult, resolveResult);
51
+ executedRules[ruleResult.ruleName] = {
52
+ ...ruleResult,
53
+ isCompliant: ruleResult.violations.length === 0,
54
+ compliantEntities,
55
+ violatedEntities,
56
+ };
57
+ }
58
+ return {
59
+ isCompliant: isCompliant(executedRules),
60
+ enabled: true,
61
+ executedRules,
62
+ skippedRules: this.resolvedRules.skippedRules,
63
+ auditedEntities: Object.keys(resolveResult.resolvedEntities),
64
+ ignoredEntities: resolveResult.ignoredEntities,
65
+ };
66
+ }
67
+ }
68
+ function isCompliant(ruleResults) {
69
+ const list = Object.values(ruleResults);
70
+ if (list.length === 0) {
71
+ return true;
72
+ }
73
+ return list.reduce((prevVal, currentVal) => prevVal && currentVal.isCompliant, list[0].isCompliant);
74
+ }
75
+ function evalResolvedEntities(ruleResult, entities) {
76
+ const compliantEntities = [];
77
+ const violatedEntities = new Set();
78
+ ruleResult.violations.forEach((vio) => {
79
+ if (vio.identifier.length > 0) {
80
+ violatedEntities.add(vio.identifier[0]);
81
+ }
82
+ });
83
+ Object.keys(entities.resolvedEntities).forEach((entityIdentifier) => {
84
+ if (!violatedEntities.has(entityIdentifier)) {
85
+ compliantEntities.push(entityIdentifier);
86
+ }
87
+ });
88
+ return { compliantEntities, violatedEntities: Array.from(violatedEntities) };
89
+ }
90
+ export function getTotal(resolveResult) {
91
+ const resolvedCount = resolveResult.resolvedEntities ? Object.keys(resolveResult.resolvedEntities).length : 0;
92
+ const ignoredCount = resolveResult.ignoredEntities ? resolveResult.ignoredEntities.length : 0;
93
+ return resolvedCount + ignoredCount;
94
+ }
95
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../src/libs/policies/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Profile as ProfileMetadata } from '@jsforce/jsforce-node/lib/api/metadata.js';
2
+ import { AuditRunConfig, ProfilesPolicyFileContent } from '../config/audit-run/schema.js';
3
+ import RuleRegistry from '../config/registries/ruleRegistry.js';
4
+ import { AuditContext } from './interfaces/policyRuleInterfaces.js';
5
+ import Policy, { ResolveEntityResult } from './policy.js';
6
+ export type ResolvedProfile = {
7
+ name: string;
8
+ preset: string;
9
+ metadata: ProfileMetadata;
10
+ };
11
+ export default class ProfilePolicy extends Policy {
12
+ config: ProfilesPolicyFileContent;
13
+ auditConfig: AuditRunConfig;
14
+ private totalEntities;
15
+ constructor(config: ProfilesPolicyFileContent, auditConfig: AuditRunConfig, registry?: RuleRegistry);
16
+ protected resolveEntities(context: AuditContext): Promise<ResolveEntityResult>;
17
+ }
@@ -0,0 +1,71 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import { isNullish } from '../utils.js';
3
+ import ProfilesRuleRegistry from '../config/registries/profiles.js';
4
+ import Policy, { getTotal } from './policy.js';
5
+ import { PermissionRiskLevelPresets } from './types.js';
6
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'policies.general');
8
+ export default class ProfilePolicy extends Policy {
9
+ config;
10
+ auditConfig;
11
+ totalEntities;
12
+ constructor(config, auditConfig, registry = new ProfilesRuleRegistry()) {
13
+ super(config, auditConfig, registry);
14
+ this.config = config;
15
+ this.auditConfig = auditConfig;
16
+ this.totalEntities = this.config.profiles ? Object.keys(this.config.profiles).length : 0;
17
+ }
18
+ async resolveEntities(context) {
19
+ this.emit('entityresolve', {
20
+ total: this.totalEntities,
21
+ resolved: 0,
22
+ });
23
+ const successfullyResolved = {};
24
+ const ignoredEntities = {};
25
+ const profileQueryResults = Array();
26
+ const definitiveProfiles = this.config.profiles ?? {};
27
+ Object.entries(definitiveProfiles).forEach(([profileName, profileDef]) => {
28
+ if (profileDef.preset !== PermissionRiskLevelPresets.UNKNOWN) {
29
+ const qr = Promise.resolve(context.targetOrgConnection.tooling.query(`SELECT Name,Metadata FROM Profile WHERE Name = '${profileName}'`));
30
+ profileQueryResults.push(qr);
31
+ }
32
+ else {
33
+ ignoredEntities[profileName] = {
34
+ name: profileName,
35
+ message: messages.getMessage('preset-unknown', ['Profile']),
36
+ };
37
+ }
38
+ });
39
+ const queryResults = await Promise.all(profileQueryResults);
40
+ queryResults.forEach((qr) => {
41
+ if (qr.records && qr.records.length > 0) {
42
+ const record = qr.records[0];
43
+ if (isNullish(record.Metadata)) {
44
+ ignoredEntities[record.Name] = {
45
+ name: record.Name,
46
+ message: messages.getMessage('profile-invalid-no-metadata'),
47
+ };
48
+ }
49
+ else {
50
+ successfullyResolved[record.Name] = {
51
+ name: record.Name,
52
+ preset: definitiveProfiles[record.Name].preset,
53
+ metadata: record.Metadata,
54
+ };
55
+ }
56
+ }
57
+ });
58
+ Object.keys(definitiveProfiles).forEach((profileName) => {
59
+ if (successfullyResolved[profileName] === undefined && ignoredEntities[profileName] === undefined) {
60
+ ignoredEntities[profileName] = { name: profileName, message: messages.getMessage('entity-not-found') };
61
+ }
62
+ });
63
+ const result = { resolvedEntities: successfullyResolved, ignoredEntities: Object.values(ignoredEntities) };
64
+ this.emit('entityresolve', {
65
+ total: this.totalEntities,
66
+ resolved: getTotal(result),
67
+ });
68
+ return result;
69
+ }
70
+ }
71
+ //# sourceMappingURL=profilePolicy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profilePolicy.js","sourceRoot":"","sources":["../../../src/libs/policies/profilePolicy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { ResolvedConnectedApp } from '../connectedAppPolicy.js';
2
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../interfaces/policyRuleInterfaces.js';
3
+ import PolicyRule, { RuleOptions } from './policyRule.js';
4
+ export default class AllUsedAppsUnderManagement extends PolicyRule<ResolvedConnectedApp> {
5
+ constructor(opts: RuleOptions);
6
+ run(context: RuleAuditContext<ResolvedConnectedApp>): Promise<PartialPolicyRuleResult>;
7
+ }