@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,69 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import { PermissionRiskLevel } from '../../classification-types.js';
3
+ import { permissionAllowedInPreset } from '../../policy-types.js';
4
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
5
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'rules.enforceClassificationPresets');
6
+ /**
7
+ * Scan userPermissions and customPermissions of a profile or permission set and
8
+ * get a unified scan result with violations (risk level not allowed) and warnings
9
+ * (risk level not classified)
10
+ *
11
+ * @param profileLike
12
+ * @param auditRun
13
+ * @param rootIdentifier Optional root identifier for messages to prepend.
14
+ * @returns
15
+ */
16
+ export function scanProfileLike(profileLike, auditRun, rootIdentifier) {
17
+ if (!profileLike.metadata) {
18
+ return { violations: [], warnings: [] };
19
+ }
20
+ const userPermsResult = scanPermissions(profileLike, 'userPermissions', auditRun, rootIdentifier);
21
+ const customPermsResult = scanPermissions(profileLike, 'customPermissions', auditRun, rootIdentifier);
22
+ userPermsResult.violations.push(...customPermsResult.violations);
23
+ userPermsResult.warnings.push(...customPermsResult.warnings);
24
+ return userPermsResult;
25
+ }
26
+ export function scanPermissions(profile, permissionListName, auditRun, rootIdentifier) {
27
+ const result = { warnings: [], violations: [] };
28
+ for (const perm of profile.metadata[permissionListName]) {
29
+ const identifier = rootIdentifier ? [...rootIdentifier, profile.name, perm.name] : [profile.name, perm.name];
30
+ const permClassification = resolvePerm(perm.name, auditRun, permissionListName);
31
+ if (permClassification) {
32
+ if (permClassification.classification === PermissionRiskLevel.BLOCKED) {
33
+ result.violations.push({
34
+ identifier,
35
+ message: messages.getMessage('violations.permission-is-blocked'),
36
+ });
37
+ }
38
+ else if (!permissionAllowedInPreset(permClassification.classification, profile.preset)) {
39
+ result.violations.push({
40
+ identifier,
41
+ message: messages.getMessage('violations.classification-preset-mismatch', [
42
+ permClassification.classification,
43
+ profile.preset,
44
+ ]),
45
+ });
46
+ }
47
+ else if (permClassification.classification === PermissionRiskLevel.UNKNOWN) {
48
+ result.warnings.push({
49
+ identifier,
50
+ message: messages.getMessage('warnings.permission-unknown'),
51
+ });
52
+ }
53
+ }
54
+ else {
55
+ result.warnings.push({
56
+ identifier,
57
+ message: messages.getMessage('warnings.permission-not-classified'),
58
+ });
59
+ }
60
+ }
61
+ return result;
62
+ }
63
+ export function resolvePerm(permName, auditRun, type) {
64
+ return nameClassification(permName, auditRun.classifications[type]?.content.permissions[permName]);
65
+ }
66
+ function nameClassification(permName, perm) {
67
+ return perm ? { name: permName, ...perm } : undefined;
68
+ }
69
+ //# sourceMappingURL=permissionsScanning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionsScanning.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/helpers/permissionsScanning.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { PermissionSet } from '@jsforce/jsforce-node/lib/api/metadata.js';
2
+ import RuleRegistry from './ruleRegistry.js';
3
+ export type ResolvedPermissionSet = {
4
+ name: string;
5
+ preset: string;
6
+ metadata: PermissionSet;
7
+ };
8
+ export default class PermSetsRuleRegistry extends RuleRegistry {
9
+ constructor();
10
+ }
11
+ export declare const PermissionSetsRegistry: PermSetsRuleRegistry;
@@ -0,0 +1,11 @@
1
+ import RuleRegistry from './ruleRegistry.js';
2
+ import EnforcePermissionsOnProfileLike from './rules/enforcePermissionsOnProfileLike.js';
3
+ export default class PermSetsRuleRegistry extends RuleRegistry {
4
+ constructor() {
5
+ super({
6
+ EnforcePermissionClassifications: EnforcePermissionsOnProfileLike,
7
+ });
8
+ }
9
+ }
10
+ export const PermissionSetsRegistry = new PermSetsRuleRegistry();
11
+ //# sourceMappingURL=permissionSets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permissionSets.js","sourceRoot":"","sources":["../../../../src/libs/core/registries/permissionSets.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAC7C,OAAO,+BAA+B,MAAM,4CAA4C,CAAC;AAOzF,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,YAAY;IAC5D;QACE,KAAK,CAAC;YACJ,gCAAgC,EAAE,+BAA+B;SAClE,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Profile as ProfileMetadata } from '@jsforce/jsforce-node/lib/api/metadata.js';
2
+ import RuleRegistry from './ruleRegistry.js';
3
+ export type ResolvedProfile = {
4
+ name: string;
5
+ preset: string;
6
+ metadata: ProfileMetadata;
7
+ };
8
+ export default class ProfilesRuleRegistry extends RuleRegistry {
9
+ constructor();
10
+ }
11
+ export declare const ProfilesRegistry: ProfilesRuleRegistry;
@@ -0,0 +1,11 @@
1
+ import RuleRegistry from './ruleRegistry.js';
2
+ import EnforcePermissionsOnProfileLike from './rules/enforcePermissionsOnProfileLike.js';
3
+ export default class ProfilesRuleRegistry extends RuleRegistry {
4
+ constructor() {
5
+ super({
6
+ EnforcePermissionClassifications: EnforcePermissionsOnProfileLike,
7
+ });
8
+ }
9
+ }
10
+ export const ProfilesRegistry = new ProfilesRuleRegistry();
11
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../../../src/libs/core/registries/profiles.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,mBAAmB,CAAC;AAC7C,OAAO,+BAA+B,MAAM,4CAA4C,CAAC;AAQzF,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,YAAY;IAC5D;QACE,KAAK,CAAC;YACJ,gCAAgC,EAAE,+BAA+B;SAClE,CAAC,CAAC;IACL,CAAC;CACF;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { EntityResolveError, PolicyRuleSkipResult } from '../result-types.js';
2
+ import { AuditRunConfig, RuleMap } from '../../core/file-mgmt/schema.js';
3
+ import { Constructor, RowLevelPolicyRule } from './types.js';
4
+ /**
5
+ * Result contains the actually available and enabled rules
6
+ * from the raw config file. Rules that are not present in the
7
+ * policie's registry are errors, disabled rules are skipped.
8
+ */
9
+ export type RegistryRuleResolveResult = {
10
+ enabledRules: Array<RowLevelPolicyRule<unknown>>;
11
+ skippedRules: PolicyRuleSkipResult[];
12
+ resolveErrors: EntityResolveError[];
13
+ };
14
+ /**
15
+ * The rule registry holds all available rules for a given policy at run time.
16
+ * It is designed to be extendible so we can easily register new rules and it will
17
+ * allow users to BYOR ("bring your own rules").
18
+ */
19
+ export default class RuleRegistry {
20
+ rules: Record<string, Constructor<RowLevelPolicyRule<unknown>>>;
21
+ constructor(rules: Record<string, Constructor<RowLevelPolicyRule<unknown>>>);
22
+ /**
23
+ * Returns the display/config names of all registered rules
24
+ *
25
+ * @returns
26
+ */
27
+ registeredRules(): string[];
28
+ /**
29
+ * Resolves a given set of rule configs to actually registered rules. Unknown
30
+ * rules are ignored and disabled rules are skipped.
31
+ *
32
+ * @param ruleObjs
33
+ * @param auditContext
34
+ * @returns
35
+ */
36
+ resolveRules(ruleObjs: RuleMap, auditContext: AuditRunConfig): RegistryRuleResolveResult;
37
+ }
@@ -0,0 +1,48 @@
1
+ import { Messages } from '@salesforce/core';
2
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
3
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'policies.general');
4
+ /**
5
+ * The rule registry holds all available rules for a given policy at run time.
6
+ * It is designed to be extendible so we can easily register new rules and it will
7
+ * allow users to BYOR ("bring your own rules").
8
+ */
9
+ export default class RuleRegistry {
10
+ rules;
11
+ constructor(rules) {
12
+ this.rules = rules;
13
+ }
14
+ /**
15
+ * Returns the display/config names of all registered rules
16
+ *
17
+ * @returns
18
+ */
19
+ registeredRules() {
20
+ return Object.keys(this.rules);
21
+ }
22
+ /**
23
+ * Resolves a given set of rule configs to actually registered rules. Unknown
24
+ * rules are ignored and disabled rules are skipped.
25
+ *
26
+ * @param ruleObjs
27
+ * @param auditContext
28
+ * @returns
29
+ */
30
+ resolveRules(ruleObjs, auditContext) {
31
+ const enabledRules = new Array();
32
+ const skippedRules = new Array();
33
+ const resolveErrors = new Array();
34
+ Object.entries(ruleObjs).forEach(([ruleName, ruleConfig]) => {
35
+ if (this.rules[ruleName] && ruleConfig.enabled) {
36
+ enabledRules.push(new this.rules[ruleName]({ auditContext, ruleDisplayName: ruleName, ruleConfig: ruleConfig.options }));
37
+ }
38
+ else if (!ruleConfig.enabled) {
39
+ skippedRules.push({ name: ruleName, skipReason: messages.getMessage('skip-reason.rule-not-enabled') });
40
+ }
41
+ else {
42
+ resolveErrors.push({ name: ruleName, message: messages.getMessage('resolve-error.rule-not-registered') });
43
+ }
44
+ });
45
+ return { enabledRules, skippedRules, resolveErrors };
46
+ }
47
+ }
48
+ //# sourceMappingURL=ruleRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruleRegistry.js","sourceRoot":"","sources":["../../../../src/libs/core/registries/ruleRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK5C,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,oCAAoC,EAAE,kBAAkB,CAAC,CAAC;AAajG;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,YAAY;IACL;IAA1B,YAA0B,KAA+D;QAA/D,UAAK,GAAL,KAAK,CAA0D;IAAG,CAAC;IAE7F;;;;OAIG;IACI,eAAe;QACpB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;OAOG;IACI,YAAY,CAAC,QAAiB,EAAE,YAA4B;QACjE,MAAM,YAAY,GAAG,IAAI,KAAK,EAA+B,CAAC;QAC9D,MAAM,YAAY,GAAG,IAAI,KAAK,EAAwB,CAAC;QACvD,MAAM,aAAa,GAAG,IAAI,KAAK,EAAsB,CAAC;QACtD,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,EAAE;YAC1D,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;gBAC/C,YAAY,CAAC,IAAI,CACf,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,EAAE,CAAC,CACtG,CAAC;YACJ,CAAC;iBAAM,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;gBAC/B,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,8BAA8B,CAAC,EAAE,CAAC,CAAC;YACzG,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,mCAAmC,CAAC,EAAE,CAAC,CAAC;YAC5G,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;IACvD,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../types.js';
2
+ import { ResolvedConnectedApp } from '../connectedApps.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
+ }
@@ -0,0 +1,23 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import PolicyRule from './policyRule.js';
3
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
4
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'rules.connectedApps');
5
+ export default class AllUsedAppsUnderManagement extends PolicyRule {
6
+ constructor(opts) {
7
+ super(opts);
8
+ }
9
+ run(context) {
10
+ const result = this.initResult();
11
+ const resolvedConnectedApps = context.resolvedEntities;
12
+ Object.values(resolvedConnectedApps).forEach((app) => {
13
+ if (app.origin === 'OauthToken') {
14
+ result.violations.push({
15
+ identifier: [app.name],
16
+ message: messages.getMessage('violations.app-used-but-not-registered', [app.users.length, app.useCount]),
17
+ });
18
+ }
19
+ });
20
+ return Promise.resolve(result);
21
+ }
22
+ }
23
+ //# sourceMappingURL=allUsedAppsUnderManagement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allUsedAppsUnderManagement.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/allUsedAppsUnderManagement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,UAA2B,MAAM,iBAAiB,CAAC;AAE1D,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,oCAAoC,EAAE,qBAAqB,CAAC,CAAC;AAEpG,MAAM,CAAC,OAAO,OAAO,0BAA2B,SAAQ,UAAgC;IACtF,YAAmB,IAAiB;QAClC,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAEM,GAAG,CAAC,OAA+C;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACnD,IAAI,GAAG,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBAChC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;oBACrB,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;oBACtB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,wCAAwC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;iBACzG,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../types.js';
2
+ import { ResolvedUser } from '../users.js';
3
+ import PolicyRule, { RuleOptions } from './policyRule.js';
4
+ export default class EnforcePermissionPresets extends PolicyRule<ResolvedUser> {
5
+ constructor(opts: RuleOptions);
6
+ run(context: RuleAuditContext<ResolvedUser>): Promise<PartialPolicyRuleResult>;
7
+ }
@@ -0,0 +1,58 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import UsersRepository from '../../mdapi/usersRepository.js';
3
+ import { ProfilesRiskPreset, resolvePresetOrdinalValue } from '../../policy-types.js';
4
+ import { capitalize } from '../../utils.js';
5
+ import PolicyRule from './policyRule.js';
6
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'rules.users');
8
+ export default class EnforcePermissionPresets extends PolicyRule {
9
+ constructor(opts) {
10
+ super(opts);
11
+ }
12
+ async run(context) {
13
+ const result = this.initResult();
14
+ const users = context.resolvedEntities;
15
+ const userRepo = new UsersRepository(context.targetOrgConnection);
16
+ // options "with/without metadata - only identifiers"
17
+ const userPerms = await userRepo.resolveUserPermissions(Object.values(users), { withMetadata: false });
18
+ for (const user of Object.values(users)) {
19
+ const profilePreset = this.auditContext.policies.profiles?.content.profiles[user.profileName];
20
+ auditPermissionsEntity(result, user, 'profile', user.profileName, profilePreset?.preset);
21
+ const permsets = userPerms.get(user.userId);
22
+ if (permsets) {
23
+ for (const assignment of permsets.assignedPermissionsets) {
24
+ const permsetPreset = this.auditContext.policies.permissionSets?.content.permissionSets[assignment.permissionSetIdentifier];
25
+ auditPermissionsEntity(result, user, 'permission set', assignment.permissionSetIdentifier, permsetPreset?.preset);
26
+ }
27
+ }
28
+ }
29
+ return result;
30
+ }
31
+ }
32
+ function auditPermissionsEntity(result, user, entityType, entityIdentifier, entityPreset) {
33
+ if (entityPreset) {
34
+ if (entityPreset === ProfilesRiskPreset.UNKNOWN) {
35
+ result.violations.push({
36
+ identifier: [user.username, entityIdentifier],
37
+ message: messages.getMessage('violations.entity-unknown-but-used', [capitalize(entityType)]),
38
+ });
39
+ }
40
+ else if (resolvePresetOrdinalValue(entityPreset) < resolvePresetOrdinalValue(user.role)) {
41
+ result.violations.push({
42
+ identifier: [user.username, entityIdentifier],
43
+ message: messages.getMessage('violations.entity-not-allowed-for-user-role', [
44
+ user.role,
45
+ entityType,
46
+ entityPreset,
47
+ ]),
48
+ });
49
+ }
50
+ }
51
+ else {
52
+ result.violations.push({
53
+ identifier: [user.username, entityIdentifier],
54
+ message: messages.getMessage('violations.entity-not-classified-but-used', [capitalize(entityType), entityType]),
55
+ });
56
+ }
57
+ }
58
+ //# sourceMappingURL=enforcePermissionPresets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcePermissionPresets.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/enforcePermissionPresets.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../types.js';
2
+ import { ResolvedProfileLike } from '../helpers/permissionsScanning.js';
3
+ import PolicyRule, { RuleOptions } from './policyRule.js';
4
+ export default class EnforcePermissionsOnProfileLike extends PolicyRule<ResolvedProfileLike> {
5
+ constructor(opts: RuleOptions);
6
+ run(context: RuleAuditContext<ResolvedProfileLike>): Promise<PartialPolicyRuleResult>;
7
+ }
@@ -0,0 +1,26 @@
1
+ import { isNullish } from '../../utils.js';
2
+ import { scanPermissions } from '../helpers/permissionsScanning.js';
3
+ import PolicyRule from './policyRule.js';
4
+ export default class EnforcePermissionsOnProfileLike extends PolicyRule {
5
+ constructor(opts) {
6
+ super(opts);
7
+ }
8
+ run(context) {
9
+ const result = this.initResult();
10
+ const resolvedProfiles = context.resolvedEntities;
11
+ for (const profile of Object.values(resolvedProfiles)) {
12
+ if (!isNullish(profile.metadata.userPermissions)) {
13
+ const userPermsScan = scanPermissions(profile, 'userPermissions', this.auditContext);
14
+ result.violations.push(...userPermsScan.violations);
15
+ result.warnings.push(...userPermsScan.warnings);
16
+ }
17
+ if (!isNullish(profile.metadata.customPermissions)) {
18
+ const customPermsScan = scanPermissions(profile, 'customPermissions', this.auditContext);
19
+ result.violations.push(...customPermsScan.violations);
20
+ result.warnings.push(...customPermsScan.warnings);
21
+ }
22
+ }
23
+ return Promise.resolve(result);
24
+ }
25
+ }
26
+ //# sourceMappingURL=enforcePermissionsOnProfileLike.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcePermissionsOnProfileLike.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/enforcePermissionsOnProfileLike.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAuB,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzF,OAAO,UAA2B,MAAM,iBAAiB,CAAC;AAE1D,MAAM,CAAC,OAAO,OAAO,+BAAgC,SAAQ,UAA+B;IAC1F,YAAmB,IAAiB;QAClC,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAEM,GAAG,CAAC,OAA8C;QACvD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;QAClD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;gBACjD,MAAM,aAAa,GAAG,eAAe,CAAC,OAAO,EAAE,iBAAiB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;gBACrF,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;gBACpD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBACnD,MAAM,eAAe,GAAG,eAAe,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;gBACzF,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;gBACtD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../types.js';
2
+ import { ResolvedUser } from '../users.js';
3
+ import PolicyRule, { RuleOptions } from './policyRule.js';
4
+ export default class EnforcePermissionsOnUser extends PolicyRule<ResolvedUser> {
5
+ constructor(opts: RuleOptions);
6
+ run(context: RuleAuditContext<ResolvedUser>): Promise<PartialPolicyRuleResult>;
7
+ private scanAssignedPermissionSets;
8
+ }
@@ -0,0 +1,42 @@
1
+ import UsersRepository from '../../mdapi/usersRepository.js';
2
+ import { scanProfileLike } from '../helpers/permissionsScanning.js';
3
+ import PolicyRule from './policyRule.js';
4
+ export default class EnforcePermissionsOnUser extends PolicyRule {
5
+ constructor(opts) {
6
+ super(opts);
7
+ }
8
+ async run(context) {
9
+ const result = this.initResult();
10
+ const users = context.resolvedEntities;
11
+ const userRepo = new UsersRepository(context.targetOrgConnection);
12
+ const userPerms = await userRepo.resolveUserPermissions(Object.values(users), { withMetadata: true });
13
+ for (const user of Object.values(users)) {
14
+ const resolvedPerms = userPerms.get(user.userId);
15
+ if (!resolvedPerms) {
16
+ continue;
17
+ }
18
+ const permsetResult = this.scanAssignedPermissionSets(user, resolvedPerms.assignedPermissionsets);
19
+ result.violations.push(...permsetResult.violations);
20
+ result.warnings.push(...permsetResult.warnings);
21
+ if (resolvedPerms.profileMetadata) {
22
+ const profileResult = scanProfileLike({ preset: user.role, metadata: resolvedPerms.profileMetadata, name: user.profileName }, this.auditContext, [user.username]);
23
+ result.violations.push(...profileResult.violations);
24
+ result.warnings.push(...profileResult.warnings);
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ scanAssignedPermissionSets(user, actualAssignments) {
30
+ const result = { violations: [], warnings: [] };
31
+ for (const assignedPermSet of actualAssignments) {
32
+ if (!assignedPermSet.metadata) {
33
+ continue;
34
+ }
35
+ const permsetScan = scanProfileLike({ preset: user.role, metadata: assignedPermSet.metadata, name: assignedPermSet.permissionSetIdentifier }, this.auditContext, [user.username]);
36
+ result.violations.push(...permsetScan.violations);
37
+ result.warnings.push(...permsetScan.warnings);
38
+ }
39
+ return result;
40
+ }
41
+ }
42
+ //# sourceMappingURL=enforcePermissionsOnUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcePermissionsOnUser.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/enforcePermissionsOnUser.ts"],"names":[],"mappings":"AAAA,OAAO,eAA4C,MAAM,gCAAgC,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAc,MAAM,mCAAmC,CAAC;AAGhF,OAAO,UAA2B,MAAM,iBAAiB,CAAC;AAE1D,MAAM,CAAC,OAAO,OAAO,wBAAyB,SAAQ,UAAwB;IAC5E,YAAmB,IAAiB;QAClC,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAEM,KAAK,CAAC,GAAG,CAAC,OAAuC;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,OAAO,CAAC,gBAAgB,CAAC;QACvC,MAAM,QAAQ,GAAG,IAAI,eAAe,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;QAClE,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,sBAAsB,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACtG,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACxC,MAAM,aAAa,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjD,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,SAAS;YACX,CAAC;YACD,MAAM,aAAa,GAAG,IAAI,CAAC,0BAA0B,CAAC,IAAI,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;YAClG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;YACpD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YAChD,IAAI,aAAa,CAAC,eAAe,EAAE,CAAC;gBAClC,MAAM,aAAa,GAAG,eAAe,CACnC,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,eAAe,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,EACtF,IAAI,CAAC,YAAY,EACjB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAChB,CAAC;gBACF,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;gBACpD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,0BAA0B,CAAC,IAAkB,EAAE,iBAA4C;QACjG,MAAM,MAAM,GAAe,EAAE,UAAU,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAC5D,KAAK,MAAM,eAAe,IAAI,iBAAiB,EAAE,CAAC;YAChD,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,CAAC;gBAC9B,SAAS;YACX,CAAC;YACD,MAAM,WAAW,GAAG,eAAe,CACjC,EAAE,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,eAAe,CAAC,uBAAuB,EAAE,EACxG,IAAI,CAAC,YAAY,EACjB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAChB,CAAC;YACF,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;YAClD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import { NoInactiveUsersOptions } from '../../file-mgmt/schema.js';
2
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../types.js';
3
+ import { ResolvedUser } from '../users.js';
4
+ import PolicyRule, { ConfigurableRuleOptions } from './policyRule.js';
5
+ export default class NoInactiveUsers extends PolicyRule<ResolvedUser> {
6
+ private ruleConfig;
7
+ constructor(localOpts: ConfigurableRuleOptions<NoInactiveUsersOptions>);
8
+ run(context: RuleAuditContext<ResolvedUser>): Promise<PartialPolicyRuleResult>;
9
+ }
@@ -0,0 +1,44 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import { NoInactiveUsersOptionsSchema } from '../../file-mgmt/schema.js';
3
+ import { differenceInDays } from '../../utils.js';
4
+ import PolicyRule, { parseRuleOptions } from './policyRule.js';
5
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
6
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'rules.users');
7
+ export default class NoInactiveUsers extends PolicyRule {
8
+ ruleConfig;
9
+ constructor(localOpts) {
10
+ super(localOpts);
11
+ this.ruleConfig = parseRuleOptions('users.yml', ['rules', 'NoInactiveUsers'], NoInactiveUsersOptionsSchema, localOpts.ruleConfig);
12
+ }
13
+ run(context) {
14
+ const result = this.initResult();
15
+ Object.values(context.resolvedEntities).forEach((user) => {
16
+ if (user.lastLogin) {
17
+ const diffInDays = differenceInDays(Date.now(), user.lastLogin);
18
+ if (diffInDays > this.ruleConfig.daysAfterUserIsInactive) {
19
+ result.violations.push({
20
+ identifier: [user.username],
21
+ message: messages.getMessage('violations.inactive-since-n-days', [
22
+ diffInDays,
23
+ new Date(user.lastLogin).toISOString(),
24
+ ]),
25
+ });
26
+ }
27
+ }
28
+ });
29
+ Object.values(context.resolvedEntities).forEach((user) => {
30
+ if (!user.lastLogin) {
31
+ const createdNDaysAgo = differenceInDays(Date.now(), user.createdDate);
32
+ result.violations.push({
33
+ identifier: [user.username],
34
+ message: messages.getMessage('violations.has-never-logged-in', [
35
+ new Date(user.createdDate).toISOString(),
36
+ createdNDaysAgo,
37
+ ]),
38
+ });
39
+ }
40
+ });
41
+ return Promise.resolve(result);
42
+ }
43
+ }
44
+ //# sourceMappingURL=noInactiveUsers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noInactiveUsers.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/noInactiveUsers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAA0B,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAEjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,UAAU,EAAE,EAA2B,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExF,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,oCAAoC,EAAE,aAAa,CAAC,CAAC;AAE5F,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,UAAwB;IAC3D,UAAU,CAAyB;IAE3C,YAAmB,SAA0D;QAC3E,KAAK,CAAC,SAAS,CAAC,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,gBAAgB,CAChC,WAAW,EACX,CAAC,OAAO,EAAE,iBAAiB,CAAC,EAC5B,4BAA4B,EAC5B,SAAS,CAAC,UAAU,CACK,CAAC;IAC9B,CAAC;IAEM,GAAG,CAAC,OAAuC;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACvD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,UAAU,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBAChE,IAAI,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC;oBACzD,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;wBACrB,UAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;wBAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,kCAAkC,EAAE;4BAC/D,UAAU;4BACV,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE;yBACvC,CAAC;qBACH,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACvD,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACpB,MAAM,eAAe,GAAG,gBAAgB,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;gBACvE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;oBACrB,UAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;oBAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,gCAAgC,EAAE;wBAC7D,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE;wBACxC,eAAe;qBAChB,CAAC;iBACH,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../types.js';
2
+ import { ResolvedUser } from '../users.js';
3
+ import PolicyRule, { RuleOptions } from './policyRule.js';
4
+ export default class NoOtherApexApiLogins extends PolicyRule<ResolvedUser> {
5
+ constructor(opts: RuleOptions);
6
+ run(context: RuleAuditContext<ResolvedUser>): Promise<PartialPolicyRuleResult>;
7
+ }
@@ -0,0 +1,27 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import PolicyRule from './policyRule.js';
3
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
4
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'rules.users');
5
+ export default class NoOtherApexApiLogins extends PolicyRule {
6
+ constructor(opts) {
7
+ super(opts);
8
+ }
9
+ run(context) {
10
+ const result = this.initResult();
11
+ for (const user of Object.values(context.resolvedEntities)) {
12
+ if (!user.logins) {
13
+ continue;
14
+ }
15
+ for (const loginSummary of user.logins) {
16
+ if (loginSummary.loginType === 'Other Apex API') {
17
+ result.violations.push({
18
+ identifier: [user.username],
19
+ message: messages.getMessage('violations.no-other-apex-api-logins', [loginSummary.loginCount]),
20
+ });
21
+ }
22
+ }
23
+ }
24
+ return Promise.resolve(result);
25
+ }
26
+ }
27
+ //# sourceMappingURL=noOtherApexApiLogins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noOtherApexApiLogins.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/noOtherApexApiLogins.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,UAA2B,MAAM,iBAAiB,CAAC;AAE1D,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,oCAAoC,EAAE,aAAa,CAAC,CAAC;AAE5F,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,UAAwB;IACxE,YAAmB,IAAiB;QAClC,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAEM,GAAG,CAAC,OAAuC;QAChD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjB,SAAS;YACX,CAAC;YACD,KAAK,MAAM,YAAY,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACvC,IAAI,YAAY,CAAC,SAAS,KAAK,gBAAgB,EAAE,CAAC;oBAChD,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;wBACrB,UAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC;wBAC3B,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,qCAAqC,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;qBAC/F,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import { PartialPolicyRuleResult, RuleAuditContext } from '../types.js';
2
+ import { ResolvedConnectedApp } from '../connectedApps.js';
3
+ import PolicyRule, { RuleOptions } from './policyRule.js';
4
+ export default class NoUserCanSelfAuthorize extends PolicyRule<ResolvedConnectedApp> {
5
+ constructor(opts: RuleOptions);
6
+ run(context: RuleAuditContext<ResolvedConnectedApp>): Promise<PartialPolicyRuleResult>;
7
+ }
@@ -0,0 +1,31 @@
1
+ import { Messages } from '@salesforce/core';
2
+ import PolicyRule from './policyRule.js';
3
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
4
+ const messages = Messages.loadMessages('@j-schreiber/sf-cli-security-audit', 'rules.connectedApps');
5
+ export default class NoUserCanSelfAuthorize extends PolicyRule {
6
+ constructor(opts) {
7
+ super(opts);
8
+ }
9
+ run(context) {
10
+ const result = this.initResult();
11
+ const resolvedConnectedApps = context.resolvedEntities;
12
+ Object.values(resolvedConnectedApps).forEach((app) => {
13
+ if (!app.onlyAdminApprovedUsersAllowed) {
14
+ if (app.overrideByApiSecurityAccess) {
15
+ result.warnings.push({
16
+ identifier: [app.name],
17
+ message: messages.getMessage('warnings.users-can-self-authorize-but-setting-overrides'),
18
+ });
19
+ }
20
+ else {
21
+ result.violations.push({
22
+ identifier: [app.name],
23
+ message: messages.getMessage('violations.users-can-self-authorize'),
24
+ });
25
+ }
26
+ }
27
+ });
28
+ return Promise.resolve(result);
29
+ }
30
+ }
31
+ //# sourceMappingURL=noUserCanSelfAuthorize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noUserCanSelfAuthorize.js","sourceRoot":"","sources":["../../../../../src/libs/core/registries/rules/noUserCanSelfAuthorize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG5C,OAAO,UAA2B,MAAM,iBAAiB,CAAC;AAE1D,QAAQ,CAAC,kCAAkC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,YAAY,CAAC,oCAAoC,EAAE,qBAAqB,CAAC,CAAC;AAEpG,MAAM,CAAC,OAAO,OAAO,sBAAuB,SAAQ,UAAgC;IAClF,YAAmB,IAAiB;QAClC,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAEM,GAAG,CAAC,OAA+C;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;YACnD,IAAI,CAAC,GAAG,CAAC,6BAA6B,EAAE,CAAC;gBACvC,IAAI,GAAG,CAAC,2BAA2B,EAAE,CAAC;oBACpC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;wBACnB,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;wBACtB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,yDAAyD,CAAC;qBACxF,CAAC,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC;wBACrB,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC;wBACtB,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,qCAAqC,CAAC;qBACpE,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import z from 'zod';
2
+ import { PartialPolicyRuleResult, RowLevelPolicyRule, RuleAuditContext } from '../types.js';
3
+ import { AuditRunConfig } from '../../file-mgmt/schema.js';
4
+ export type RuleOptions = {
5
+ auditContext: AuditRunConfig;
6
+ ruleDisplayName: string;
7
+ };
8
+ export type ConfigurableRuleOptions<T> = RuleOptions & {
9
+ ruleConfig: T;
10
+ };
11
+ export default abstract class PolicyRule<EntityType> implements RowLevelPolicyRule<EntityType> {
12
+ protected opts: RuleOptions;
13
+ auditContext: AuditRunConfig;
14
+ ruleDisplayName: string;
15
+ constructor(opts: RuleOptions);
16
+ protected initResult(): PartialPolicyRuleResult;
17
+ abstract run(context: RuleAuditContext<EntityType>): Promise<PartialPolicyRuleResult>;
18
+ }
19
+ export declare function parseRuleOptions(policyName: string, rulePath: string[], schema: z.ZodObject, anyObject?: unknown): z.infer<typeof schema>;