@j-schreiber/sf-cli-security-audit 0.8.2 → 0.8.3

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 (150) hide show
  1. package/lib/commands/org/audit/init.d.ts +19 -0
  2. package/lib/commands/org/audit/init.js +72 -0
  3. package/lib/commands/org/audit/init.js.map +1 -0
  4. package/lib/commands/org/audit/run.d.ts +23 -0
  5. package/lib/commands/org/audit/run.js +124 -0
  6. package/lib/commands/org/audit/run.js.map +1 -0
  7. package/lib/commands/org/scan/user-perms.d.ts +20 -0
  8. package/lib/commands/org/scan/user-perms.js +87 -0
  9. package/lib/commands/org/scan/user-perms.js.map +1 -0
  10. package/lib/libs/conf-init/auditConfig.d.ts +35 -0
  11. package/lib/libs/conf-init/auditConfig.js +41 -0
  12. package/lib/libs/conf-init/auditConfig.js.map +1 -0
  13. package/lib/libs/conf-init/permissionsClassification.d.ts +17 -0
  14. package/lib/libs/conf-init/permissionsClassification.js +80 -0
  15. package/lib/libs/conf-init/permissionsClassification.js.map +1 -0
  16. package/lib/libs/conf-init/policyConfigs.d.ts +31 -0
  17. package/lib/libs/conf-init/policyConfigs.js +91 -0
  18. package/lib/libs/conf-init/policyConfigs.js.map +1 -0
  19. package/lib/libs/conf-init/presets/loose.d.ts +6 -0
  20. package/lib/libs/conf-init/presets/loose.js +85 -0
  21. package/lib/libs/conf-init/presets/loose.js.map +1 -0
  22. package/lib/libs/conf-init/presets/none.d.ts +30 -0
  23. package/lib/libs/conf-init/presets/none.js +54 -0
  24. package/lib/libs/conf-init/presets/none.js.map +1 -0
  25. package/lib/libs/conf-init/presets/strict.d.ts +4 -0
  26. package/lib/libs/conf-init/presets/strict.js +79 -0
  27. package/lib/libs/conf-init/presets/strict.js.map +1 -0
  28. package/lib/libs/conf-init/presets.d.ts +7 -0
  29. package/lib/libs/conf-init/presets.js +20 -0
  30. package/lib/libs/conf-init/presets.js.map +1 -0
  31. package/lib/libs/core/auditRun.d.ts +36 -0
  32. package/lib/libs/core/auditRun.js +86 -0
  33. package/lib/libs/core/auditRun.js.map +1 -0
  34. package/lib/libs/core/classification-types.d.ts +20 -0
  35. package/lib/libs/core/classification-types.js +23 -0
  36. package/lib/libs/core/classification-types.js.map +1 -0
  37. package/lib/libs/core/constants.d.ts +10 -0
  38. package/lib/libs/core/constants.js +20 -0
  39. package/lib/libs/core/constants.js.map +1 -0
  40. package/lib/libs/core/file-mgmt/auditConfigFileManager.d.ts +48 -0
  41. package/lib/libs/core/file-mgmt/auditConfigFileManager.js +145 -0
  42. package/lib/libs/core/file-mgmt/auditConfigFileManager.js.map +1 -0
  43. package/lib/libs/core/file-mgmt/schema.d.ts +123 -0
  44. package/lib/libs/core/file-mgmt/schema.js +69 -0
  45. package/lib/libs/core/file-mgmt/schema.js.map +1 -0
  46. package/lib/libs/core/mdapi/mdapiRetriever.d.ts +54 -0
  47. package/lib/libs/core/mdapi/mdapiRetriever.js +123 -0
  48. package/lib/libs/core/mdapi/mdapiRetriever.js.map +1 -0
  49. package/lib/libs/core/mdapi/metadataRegistryEntry.d.ts +40 -0
  50. package/lib/libs/core/mdapi/metadataRegistryEntry.js +46 -0
  51. package/lib/libs/core/mdapi/metadataRegistryEntry.js.map +1 -0
  52. package/lib/libs/core/mdapi/namedMetadataToolingQueryable.d.ts +33 -0
  53. package/lib/libs/core/mdapi/namedMetadataToolingQueryable.js +41 -0
  54. package/lib/libs/core/mdapi/namedMetadataToolingQueryable.js.map +1 -0
  55. package/lib/libs/core/mdapi/namedMetadataType.d.ts +20 -0
  56. package/lib/libs/core/mdapi/namedMetadataType.js +41 -0
  57. package/lib/libs/core/mdapi/namedMetadataType.js.map +1 -0
  58. package/lib/libs/core/mdapi/singletonMetadataType.d.ts +21 -0
  59. package/lib/libs/core/mdapi/singletonMetadataType.js +37 -0
  60. package/lib/libs/core/mdapi/singletonMetadataType.js.map +1 -0
  61. package/lib/libs/core/mdapi/usersRepository.d.ts +85 -0
  62. package/lib/libs/core/mdapi/usersRepository.js +126 -0
  63. package/lib/libs/core/mdapi/usersRepository.js.map +1 -0
  64. package/lib/libs/core/policies/connectedAppPolicy.d.ts +10 -0
  65. package/lib/libs/core/policies/connectedAppPolicy.js +78 -0
  66. package/lib/libs/core/policies/connectedAppPolicy.js.map +1 -0
  67. package/lib/libs/core/policies/permissionSetPolicy.d.ts +11 -0
  68. package/lib/libs/core/policies/permissionSetPolicy.js +62 -0
  69. package/lib/libs/core/policies/permissionSetPolicy.js.map +1 -0
  70. package/lib/libs/core/policies/policy.d.ts +31 -0
  71. package/lib/libs/core/policies/policy.js +100 -0
  72. package/lib/libs/core/policies/policy.js.map +1 -0
  73. package/lib/libs/core/policies/profilePolicy.d.ts +11 -0
  74. package/lib/libs/core/policies/profilePolicy.js +64 -0
  75. package/lib/libs/core/policies/profilePolicy.js.map +1 -0
  76. package/lib/libs/core/policies/salesforceStandardTypes.d.ts +58 -0
  77. package/lib/libs/core/policies/salesforceStandardTypes.js +2 -0
  78. package/lib/libs/core/policies/salesforceStandardTypes.js.map +1 -0
  79. package/lib/libs/core/policies/userPolicy.d.ts +11 -0
  80. package/lib/libs/core/policies/userPolicy.js +60 -0
  81. package/lib/libs/core/policies/userPolicy.js.map +1 -0
  82. package/lib/libs/core/policy-types.d.ts +18 -0
  83. package/lib/libs/core/policy-types.js +28 -0
  84. package/lib/libs/core/policy-types.js.map +1 -0
  85. package/lib/libs/core/policyRegistry.d.ts +23 -0
  86. package/lib/libs/core/policyRegistry.js +38 -0
  87. package/lib/libs/core/policyRegistry.js.map +1 -0
  88. package/lib/libs/core/registries/connectedApps.d.ts +13 -0
  89. package/lib/libs/core/registries/connectedApps.js +13 -0
  90. package/lib/libs/core/registries/connectedApps.js.map +1 -0
  91. package/lib/libs/core/registries/helpers/permissionsScanning.d.ts +29 -0
  92. package/lib/libs/core/registries/helpers/permissionsScanning.js +69 -0
  93. package/lib/libs/core/registries/helpers/permissionsScanning.js.map +1 -0
  94. package/lib/libs/core/registries/permissionSets.d.ts +11 -0
  95. package/lib/libs/core/registries/permissionSets.js +11 -0
  96. package/lib/libs/core/registries/permissionSets.js.map +1 -0
  97. package/lib/libs/core/registries/profiles.d.ts +11 -0
  98. package/lib/libs/core/registries/profiles.js +11 -0
  99. package/lib/libs/core/registries/profiles.js.map +1 -0
  100. package/lib/libs/core/registries/ruleRegistry.d.ts +37 -0
  101. package/lib/libs/core/registries/ruleRegistry.js +48 -0
  102. package/lib/libs/core/registries/ruleRegistry.js.map +1 -0
  103. package/lib/libs/core/registries/rules/allUsedAppsUnderManagement.d.ts +7 -0
  104. package/lib/libs/core/registries/rules/allUsedAppsUnderManagement.js +23 -0
  105. package/lib/libs/core/registries/rules/allUsedAppsUnderManagement.js.map +1 -0
  106. package/lib/libs/core/registries/rules/enforcePermissionPresets.d.ts +7 -0
  107. package/lib/libs/core/registries/rules/enforcePermissionPresets.js +58 -0
  108. package/lib/libs/core/registries/rules/enforcePermissionPresets.js.map +1 -0
  109. package/lib/libs/core/registries/rules/enforcePermissionsOnProfileLike.d.ts +7 -0
  110. package/lib/libs/core/registries/rules/enforcePermissionsOnProfileLike.js +26 -0
  111. package/lib/libs/core/registries/rules/enforcePermissionsOnProfileLike.js.map +1 -0
  112. package/lib/libs/core/registries/rules/enforcePermissionsOnUser.d.ts +8 -0
  113. package/lib/libs/core/registries/rules/enforcePermissionsOnUser.js +42 -0
  114. package/lib/libs/core/registries/rules/enforcePermissionsOnUser.js.map +1 -0
  115. package/lib/libs/core/registries/rules/noInactiveUsers.d.ts +9 -0
  116. package/lib/libs/core/registries/rules/noInactiveUsers.js +44 -0
  117. package/lib/libs/core/registries/rules/noInactiveUsers.js.map +1 -0
  118. package/lib/libs/core/registries/rules/noOtherApexApiLogins.d.ts +7 -0
  119. package/lib/libs/core/registries/rules/noOtherApexApiLogins.js +27 -0
  120. package/lib/libs/core/registries/rules/noOtherApexApiLogins.js.map +1 -0
  121. package/lib/libs/core/registries/rules/noUserCanSelfAuthorize.d.ts +7 -0
  122. package/lib/libs/core/registries/rules/noUserCanSelfAuthorize.js +31 -0
  123. package/lib/libs/core/registries/rules/noUserCanSelfAuthorize.js.map +1 -0
  124. package/lib/libs/core/registries/rules/policyRule.d.ts +19 -0
  125. package/lib/libs/core/registries/rules/policyRule.js +32 -0
  126. package/lib/libs/core/registries/rules/policyRule.js.map +1 -0
  127. package/lib/libs/core/registries/types.d.ts +37 -0
  128. package/lib/libs/core/registries/types.js +11 -0
  129. package/lib/libs/core/registries/types.js.map +1 -0
  130. package/lib/libs/core/registries/users.d.ts +10 -0
  131. package/lib/libs/core/registries/users.js +17 -0
  132. package/lib/libs/core/registries/users.js.map +1 -0
  133. package/lib/libs/core/result-types.d.ts +172 -0
  134. package/lib/libs/core/result-types.js +2 -0
  135. package/lib/libs/core/result-types.js.map +1 -0
  136. package/lib/libs/core/utils.d.ts +12 -0
  137. package/lib/libs/core/utils.js +31 -0
  138. package/lib/libs/core/utils.js.map +1 -0
  139. package/lib/libs/quick-scan/types.d.ts +17 -0
  140. package/lib/libs/quick-scan/types.js +2 -0
  141. package/lib/libs/quick-scan/types.js.map +1 -0
  142. package/lib/libs/quick-scan/userPermissionScanner.d.ts +22 -0
  143. package/lib/libs/quick-scan/userPermissionScanner.js +75 -0
  144. package/lib/libs/quick-scan/userPermissionScanner.js.map +1 -0
  145. package/lib/ux/auditRunMultiStage.d.ts +65 -0
  146. package/lib/ux/auditRunMultiStage.js +120 -0
  147. package/lib/ux/auditRunMultiStage.js.map +1 -0
  148. package/oclif.manifest.json +253 -2
  149. package/package.json +1 -1
  150. package/bin/dev.js +0 -8
@@ -0,0 +1,32 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import { throwAsSfError } from '../../file-mgmt/schema.js';
3
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
4
+ export default class PolicyRule {
5
+ opts;
6
+ auditContext;
7
+ ruleDisplayName;
8
+ constructor(opts) {
9
+ this.opts = opts;
10
+ this.auditContext = opts.auditContext;
11
+ this.ruleDisplayName = opts.ruleDisplayName;
12
+ }
13
+ initResult() {
14
+ return {
15
+ ruleName: this.ruleDisplayName,
16
+ violations: new Array(),
17
+ mutedViolations: new Array(),
18
+ warnings: new Array(),
19
+ errors: new Array(),
20
+ };
21
+ }
22
+ }
23
+ export function parseRuleOptions(policyName, rulePath, schema, anyObject) {
24
+ const parseResult = schema.safeParse(anyObject ?? {});
25
+ if (parseResult.success) {
26
+ return parseResult.data;
27
+ }
28
+ else {
29
+ throwAsSfError(policyName, parseResult.error, [...rulePath, 'options']);
30
+ }
31
+ }
32
+ //# sourceMappingURL=policyRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policyRule.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/policyRule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5C,OAAO,EAAkB,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3E,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAW7D,MAAM,CAAC,OAAO,OAAgB,UAAU;IAIT;IAHtB,YAAY,CAAiB;IAC7B,eAAe,CAAS;IAE/B,YAA6B,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;QAC5C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACtC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;IAC9C,CAAC;IAES,UAAU;QAClB,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,eAAe;YAC9B,UAAU,EAAE,IAAI,KAAK,EAAuB;YAC5C,eAAe,EAAE,IAAI,KAAK,EAA2B;YACrD,QAAQ,EAAE,IAAI,KAAK,EAAwB;YAC3C,MAAM,EAAE,IAAI,KAAK,EAAwB;SAC1C,CAAC;IACJ,CAAC;CAGF;AAED,MAAM,UAAU,gBAAgB,CAC9B,UAAkB,EAClB,QAAkB,EAClB,MAAmB,EACnB,SAAmB;IAEnB,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IACtD,IAAI,WAAW,CAAC,OAAO,EAAE,CAAC;QACxB,OAAO,WAAW,CAAC,IAAI,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,cAAc,CAAC,UAAU,EAAE,WAAW,CAAC,KAAK,EAAE,CAAC,GAAG,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IAC1E,CAAC;AACH,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { Connection } from '@salesforce/core';
2
+ import { AuditPolicyResult, PolicyRuleExecutionResult } from '../result-types.js';
3
+ import { Optional } from '../utils.js';
4
+ export declare const RuleRegistries: {
5
+ ConnectedApps: import("./connectedApps.js").default;
6
+ Profiles: import("./profiles.js").default;
7
+ PermissionSets: import("./permissionSets.js").default;
8
+ Users: import("./users.js").default;
9
+ };
10
+ export type Constructor<T, Args extends any[] = any[]> = new (...args: Args) => T;
11
+ /**
12
+ * A rule must only implement a subset of the rule result. All optional
13
+ * properties are completed by the policy.
14
+ */
15
+ export type PartialPolicyRuleResult = Optional<PolicyRuleExecutionResult, 'isCompliant' | 'compliantEntities' | 'violatedEntities'>;
16
+ /**
17
+ *
18
+ */
19
+ export type RowLevelPolicyRule<ResolvedEntityType> = {
20
+ run(context: RuleAuditContext<ResolvedEntityType>): Promise<PartialPolicyRuleResult>;
21
+ };
22
+ export type IPolicy = {
23
+ run(context: AuditContext): Promise<AuditPolicyResult>;
24
+ };
25
+ export type AuditContext = {
26
+ /**
27
+ * Connection to the target org
28
+ */
29
+ targetOrgConnection: Connection;
30
+ };
31
+ export type RuleAuditContext<T> = AuditContext & {
32
+ /**
33
+ * Resolved entities from the policy. Can be permission sets,
34
+ * profiles, users, connected apps, etc.
35
+ */
36
+ resolvedEntities: Record<string, T>;
37
+ };
@@ -0,0 +1,11 @@
1
+ import { ConnectedAppsRegistry } from './connectedApps.js';
2
+ import { PermissionSetsRegistry } from './permissionSets.js';
3
+ import { ProfilesRegistry } from './profiles.js';
4
+ import { UsersRegistry } from './users.js';
5
+ export const RuleRegistries = {
6
+ ConnectedApps: ConnectedAppsRegistry,
7
+ Profiles: ProfilesRegistry,
8
+ PermissionSets: PermissionSetsRegistry,
9
+ Users: UsersRegistry,
10
+ };
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/libs/core/registries/types.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,aAAa,EAAE,qBAAqB;IACpC,QAAQ,EAAE,gBAAgB;IAC1B,cAAc,EAAE,sBAAsB;IACtC,KAAK,EAAE,aAAa;CACrB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { User } from '../mdapi/usersRepository.js';
2
+ import { ProfilesRiskPreset } from '../policy-types.js';
3
+ import RuleRegistry from './ruleRegistry.js';
4
+ export type ResolvedUser = User & {
5
+ role: ProfilesRiskPreset;
6
+ };
7
+ export default class UsersRuleRegistry extends RuleRegistry {
8
+ constructor();
9
+ }
10
+ export declare const UsersRegistry: UsersRuleRegistry;
@@ -0,0 +1,17 @@
1
+ import RuleRegistry from './ruleRegistry.js';
2
+ import EnforcePermissionPresets from './rules/enforcePermissionPresets.js';
3
+ import EnforcePermissionsOnUser from './rules/enforcePermissionsOnUser.js';
4
+ import NoInactiveUsers from './rules/noInactiveUsers.js';
5
+ import NoOtherApexApiLogins from './rules/noOtherApexApiLogins.js';
6
+ export default class UsersRuleRegistry extends RuleRegistry {
7
+ constructor() {
8
+ super({
9
+ NoOtherApexApiLogins,
10
+ NoInactiveUsers,
11
+ EnforcePermissionClassifications: EnforcePermissionsOnUser,
12
+ EnforcePermissionPresets,
13
+ });
14
+ }
15
+ }
16
+ export const UsersRegistry = new UsersRuleRegistry();
17
+ //# sourceMappingURL=users.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"users.js","sourceRoot":"","sources":["../../../../src/libs/core/registries/users.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAC7C,OAAO,wBAAwB,MAAM,qCAAqC,CAAC;AAC3E,OAAO,wBAAwB,MAAM,qCAAqC,CAAC;AAC3E,OAAO,eAAe,MAAM,4BAA4B,CAAC;AACzD,OAAO,oBAAoB,MAAM,iCAAiC,CAAC;AAMnE,MAAM,CAAC,OAAO,OAAO,iBAAkB,SAAQ,YAAY;IACzD;QACE,KAAK,CAAC;YACJ,oBAAoB;YACpB,eAAe;YACf,gCAAgC,EAAE,wBAAwB;YAC1D,wBAAwB;SACzB,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,172 @@
1
+ import { AuditRunConfigPolicies } from './file-mgmt/schema.js';
2
+ /**
3
+ * A single violation from a policy rule execution.
4
+ */
5
+ export type PolicyRuleViolation = RuleComponentMessage & {
6
+ /**
7
+ * Optional descriptive message that explains how to fix the violation.
8
+ */
9
+ hint?: string;
10
+ };
11
+ /**
12
+ * A muted violation with additional information why it was muted
13
+ */
14
+ export type PolicyRuleViolationMute = PolicyRuleViolation & {
15
+ /**
16
+ * Descriptive reason from allow-config why this violation is muted.
17
+ */
18
+ reason: string;
19
+ /**
20
+ * Path to the config file that allowed this violation for reference.
21
+ */
22
+ allowListEntryPath?: string;
23
+ };
24
+ /**
25
+ * Details about s config entity of a policy (such as a profile, perm set, user)
26
+ * that did not resolve successfully. This may be because the entity does not exist
27
+ * on the target org or because it is not registered.
28
+ */
29
+ export type EntityResolveError = {
30
+ /**
31
+ * Identifier of the entity, e.g. profile name, username, rule, policy, etc
32
+ */
33
+ name: string;
34
+ /**
35
+ * Message that explains, why the entity was not successfully resolved
36
+ */
37
+ message: string;
38
+ };
39
+ /**
40
+ * Generic message for a particular element of a rule
41
+ */
42
+ export type RuleComponentMessage = {
43
+ /**
44
+ * Path to a component. This can be a developer name of a connected app,
45
+ * permission set name or the permission within a profile.
46
+ */
47
+ identifier: string | string[];
48
+ /**
49
+ * Descriptive message of the error, warning or violation.
50
+ */
51
+ message: string;
52
+ };
53
+ /**
54
+ *
55
+ */
56
+ export type PolicyRuleSkipResult = {
57
+ /**
58
+ * Identifier of the rule, as it is configured in the policy.yml.
59
+ */
60
+ name: string;
61
+ /**
62
+ * Descriptive message why the rule was skipped.
63
+ */
64
+ skipReason: string;
65
+ };
66
+ /**
67
+ * Full execution summary of a single rule. Includes audited entities,
68
+ * violations, execution errors, etc.
69
+ */
70
+ export type PolicyRuleExecutionResult = {
71
+ /**
72
+ * Identifier of the rule, as it is configured in the policy.yml.
73
+ */
74
+ ruleName: string;
75
+ /**
76
+ * Short-hand accessor, if an execution had at least one violation.
77
+ */
78
+ isCompliant: boolean;
79
+ /**
80
+ * All violations of the rule that were reported.
81
+ */
82
+ violations: PolicyRuleViolation[];
83
+ /**
84
+ * Identifiers of compliant entities. An entity is compliant, if it has
85
+ * zero violations.
86
+ */
87
+ compliantEntities: string[];
88
+ /**
89
+ * Identifiers of violated entities. Each entity may have several violations,
90
+ * depending on the analysis depth of the rule.
91
+ */
92
+ violatedEntities: string[];
93
+ /**
94
+ * Violations that were identified, but were muted by a matching allow-list.
95
+ * Muted violations do not affect compliance.
96
+ */
97
+ mutedViolations: PolicyRuleViolationMute[];
98
+ /**
99
+ * Components of a rule that were not successfully processed and returned errors from the org
100
+ */
101
+ errors: RuleComponentMessage[];
102
+ /**
103
+ * Components that were not auditable, but did not hinder the execution of the audit
104
+ * Such as permissions on the org that are not classified.
105
+ */
106
+ warnings: RuleComponentMessage[];
107
+ };
108
+ /**
109
+ * Full execution result of a policy. Contains full results of each executed
110
+ * rule and more information about skipped rules, audited entities, etc.
111
+ */
112
+ export type AuditPolicyResult = {
113
+ /**
114
+ * Flag that indicates, if the policy was executed.
115
+ */
116
+ enabled: boolean;
117
+ /**
118
+ * All executed rules were compliant.
119
+ */
120
+ isCompliant: boolean;
121
+ /**
122
+ * Record of rules that were executed. Rules are mapped by their name.
123
+ */
124
+ executedRules: {
125
+ [ruleName: string]: PolicyRuleExecutionResult;
126
+ };
127
+ /**
128
+ * List of rules that exist for the policy that were not executed.
129
+ */
130
+ skippedRules: PolicyRuleSkipResult[];
131
+ /**
132
+ * If the policy was not enabled, a brief message that explains why.
133
+ */
134
+ disabledReason?: string;
135
+ /**
136
+ * Path to the config file that was processed for this audit.
137
+ */
138
+ configPath?: string;
139
+ /**
140
+ * A full list of audited entities. Use together with violations to see, which
141
+ * entities were not compliant.
142
+ */
143
+ auditedEntities: string[];
144
+ /**
145
+ * Full list of entities that were present in the config file, but could not
146
+ * be resolved for this org.
147
+ */
148
+ ignoredEntities: EntityResolveError[];
149
+ };
150
+ /**
151
+ * The final audit result, contains all policy results.
152
+ */
153
+ export type AuditResult = {
154
+ /**
155
+ * All executed policies were compliant.
156
+ */
157
+ isCompliant: boolean;
158
+ /**
159
+ * Id of the audited org.
160
+ */
161
+ orgId: string;
162
+ /**
163
+ * ISO date time of the audit
164
+ */
165
+ auditDate: string;
166
+ /**
167
+ * Record map of all modules (policies) that were run.
168
+ */
169
+ policies: {
170
+ [P in keyof AuditRunConfigPolicies]: AuditPolicyResult;
171
+ };
172
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=result-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-types.js","sourceRoot":"","sources":["../../../src/libs/core/result-types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,12 @@
1
+ export declare function isEmpty(anything?: unknown): boolean;
2
+ export declare function isNullish(anything: unknown): boolean;
3
+ export declare function capitalize(anyString: string): string;
4
+ export declare function uncapitalize(anyString: string): string;
5
+ /**
6
+ * Both dates have to be UNIX timestamps
7
+ *
8
+ * @param date1
9
+ * @param date2
10
+ */
11
+ export declare function differenceInDays(date1: number | string, date2: number | string): number;
12
+ export type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
@@ -0,0 +1,31 @@
1
+ export function isEmpty(anything) {
2
+ if (isNullish(anything)) {
3
+ return true;
4
+ }
5
+ if (typeof anything === 'object') {
6
+ return Object.entries(anything).length === 0;
7
+ }
8
+ return false;
9
+ }
10
+ export function isNullish(anything) {
11
+ return !(Boolean(anything) && anything !== null);
12
+ }
13
+ export function capitalize(anyString) {
14
+ return `${anyString[0].toUpperCase()}${anyString.slice(1)}`;
15
+ }
16
+ export function uncapitalize(anyString) {
17
+ return `${anyString[0].toLowerCase()}${anyString.slice(1)}`;
18
+ }
19
+ /**
20
+ * Both dates have to be UNIX timestamps
21
+ *
22
+ * @param date1
23
+ * @param date2
24
+ */
25
+ export function differenceInDays(date1, date2) {
26
+ const convertedDate1 = typeof date1 === 'number' ? date1 : Date.parse(date1);
27
+ const convertedDate2 = typeof date2 === 'number' ? date2 : Date.parse(date2);
28
+ const diff = Math.abs(convertedDate2 - convertedDate1);
29
+ return Math.floor(diff / (1000 * 60 * 60 * 24));
30
+ }
31
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/libs/core/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,OAAO,CAAC,QAAkB;IACxC,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,MAAM,CAAC,OAAO,CAAC,QAAS,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAiB;IACzC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,KAAK,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAsB,EAAE,KAAsB;IAC7E,MAAM,cAAc,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7E,MAAM,cAAc,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,GAAG,cAAc,CAAC,CAAC;IACvD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { Connection } from '@salesforce/core';
2
+ export type QuickScanResult = {
3
+ permissions: QuickScanPermissionResult;
4
+ scannedProfiles: string[];
5
+ scannedPermissionSets: string[];
6
+ };
7
+ export type QuickScanPermissionResult = {
8
+ [permissionName: string]: PermissionScanResult;
9
+ };
10
+ export type PermissionScanResult = {
11
+ profiles: string[];
12
+ permissionSets: string[];
13
+ };
14
+ export type QuickScanOptions = {
15
+ targetOrg: Connection;
16
+ permissions: string[];
17
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/libs/quick-scan/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,22 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { QuickScanOptions, QuickScanResult } from './types.js';
3
+ export type ScanStatusEvent = {
4
+ profiles: EntityScanStatus;
5
+ permissionSets: EntityScanStatus;
6
+ users: EntityScanStatus;
7
+ status: 'Pending' | 'In Progress' | 'Completed';
8
+ };
9
+ export type EntityScanStatus = {
10
+ total?: number;
11
+ resolved?: number;
12
+ status?: string;
13
+ };
14
+ export default class UserPermissionScanner extends EventEmitter {
15
+ private status;
16
+ constructor();
17
+ quickScan(opts: QuickScanOptions): Promise<QuickScanResult>;
18
+ private resolveEntities;
19
+ private resolveProfiles;
20
+ private resolvePermissionSets;
21
+ private emitProgress;
22
+ }
@@ -0,0 +1,75 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import MDAPI from '../core/mdapi/mdapiRetriever.js';
3
+ import { PERMISSION_SETS_QUERY, PROFILES_QUERY } from '../core/constants.js';
4
+ export default class UserPermissionScanner extends EventEmitter {
5
+ status = {
6
+ profiles: {},
7
+ permissionSets: {},
8
+ users: {},
9
+ status: 'Pending',
10
+ };
11
+ constructor() {
12
+ super();
13
+ }
14
+ async quickScan(opts) {
15
+ this.emitProgress({ status: 'Pending' });
16
+ const scannedEntities = await this.resolveEntities(opts.targetOrg);
17
+ const scanResult = {
18
+ permissions: {},
19
+ scannedProfiles: Object.keys(scannedEntities.profiles),
20
+ scannedPermissionSets: Object.keys(scannedEntities.permissionSets),
21
+ };
22
+ opts.permissions.forEach((permName) => {
23
+ const profiles = findGrantingEntities(permName, scannedEntities.profiles);
24
+ const permissionSets = findGrantingEntities(permName, scannedEntities.permissionSets);
25
+ scanResult.permissions[permName] = { permissionSets, profiles };
26
+ });
27
+ this.emitProgress({ status: 'Completed' });
28
+ return scanResult;
29
+ }
30
+ async resolveEntities(targetOrg) {
31
+ const promises = [];
32
+ this.emitProgress({ status: 'In Progress' });
33
+ promises.push(this.resolveProfiles(targetOrg));
34
+ promises.push(this.resolvePermissionSets(targetOrg));
35
+ const resolvedEntities = await Promise.all(promises);
36
+ return {
37
+ profiles: resolvedEntities[0],
38
+ permissionSets: resolvedEntities[1],
39
+ };
40
+ }
41
+ async resolveProfiles(targetOrg) {
42
+ const profiles = await targetOrg.query(PROFILES_QUERY);
43
+ this.emitProgress({ profiles: { total: profiles.records.length, resolved: 0 } });
44
+ const mdapi = MDAPI.create(targetOrg);
45
+ const resolved = await mdapi.resolve('Profile', profiles.records.map((permsetRecord) => permsetRecord.Profile.Name));
46
+ this.emitProgress({ profiles: { resolved: Object.keys(resolved).length } });
47
+ return resolved;
48
+ }
49
+ async resolvePermissionSets(targetOrg) {
50
+ const permSets = await targetOrg.query(PERMISSION_SETS_QUERY);
51
+ this.emitProgress({ permissionSets: { total: permSets.records.length, resolved: 0 } });
52
+ const mdapi = MDAPI.create(targetOrg);
53
+ const resolved = await mdapi.resolve('PermissionSet', permSets.records.map((permsetRecord) => permsetRecord.Name));
54
+ this.emitProgress({ permissionSets: { resolved: Object.keys(resolved).length } });
55
+ return resolved;
56
+ }
57
+ emitProgress(update) {
58
+ this.status.profiles = { ...this.status.profiles, ...update.profiles };
59
+ this.status.permissionSets = { ...this.status.permissionSets, ...update.permissionSets };
60
+ this.status.users = { ...this.status.users, ...update.users };
61
+ this.status.status = update.status ?? this.status.status;
62
+ this.emit('progress', structuredClone(this.status));
63
+ }
64
+ }
65
+ function findGrantingEntities(permName, resolvedEntities) {
66
+ const entities = new Set();
67
+ Object.entries(resolvedEntities).forEach(([entityName, metadata]) => {
68
+ const userPerms = metadata.userPermissions.map((userPerm) => userPerm.name);
69
+ if (userPerms.includes(permName)) {
70
+ entities.add(entityName);
71
+ }
72
+ });
73
+ return Array.from(entities);
74
+ }
75
+ //# sourceMappingURL=userPermissionScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"userPermissionScanner.js","sourceRoot":"","sources":["../../../src/libs/quick-scan/userPermissionScanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ import { MultiStageOutput, MultiStageOutputOptions } from '@oclif/multi-stage-output';
2
+ import AuditRun from '../libs/core/auditRun.js';
3
+ export declare const LOAD_AUDIT_CONFIG = "Loading audit config";
4
+ export declare const RESOLVE_POLICIES = "Resolving policies";
5
+ export declare const EXECUTE_RULES = "Executing rules";
6
+ export declare const FINALISE = "Formatting results";
7
+ export type AuditRunStageOptions = {
8
+ targetOrg: string;
9
+ directoryRootPath: string;
10
+ jsonEnabled?: boolean;
11
+ };
12
+ /**
13
+ * This type mimics the original "StageBlockInfo" type from
14
+ * MultiStageOutput and allows us to make test asserts.
15
+ */
16
+ type StageBlockInfo<T> = {
17
+ stage: string;
18
+ type: 'dynamic-key-value' | 'static-key-value' | 'message';
19
+ label?: string;
20
+ get(data: T): string;
21
+ };
22
+ export default class AuditRunMultiStageOutput {
23
+ mso: MultiStageOutput<AuditRunData>;
24
+ stageSpecificBlocks: Array<StageBlockInfo<AuditRunData>>;
25
+ private polStats;
26
+ constructor(opts: MultiStageOutputOptions<AuditRunData>);
27
+ /**
28
+ * In unit tests, we stub the actual UX class to hide output in terminal.
29
+ *
30
+ * @param opts
31
+ * @returns
32
+ */
33
+ static initUx(opts: MultiStageOutputOptions<AuditRunData>): MultiStageOutput<AuditRunData>;
34
+ /**
35
+ * This pattern allows to stub multi-stage outputs in tests to mute output
36
+ * to stdout during test execution.
37
+ *
38
+ * In your code, create a new instance like this
39
+ * ```
40
+ * const ms = AuditRunMultiStageOutput.create(sobj, flags.json);
41
+ * ```
42
+ *
43
+ * @param opts
44
+ * @param jsonEnabled
45
+ * @returns
46
+ */
47
+ static create(opts: AuditRunStageOptions): AuditRunMultiStageOutput;
48
+ start(): void;
49
+ startPolicyResolve(runInstance: AuditRun): void;
50
+ startRuleExecution(): void;
51
+ finish(): void;
52
+ private addPolicyStatsListener;
53
+ }
54
+ export type AuditRunData = {
55
+ enabledRulesInPolicy: string[];
56
+ currentStatus: string;
57
+ policies: PolicyStatistics;
58
+ };
59
+ type PolicyStatistics = {
60
+ [policyName: string]: {
61
+ total?: number;
62
+ resolved?: number;
63
+ };
64
+ };
65
+ export {};