sf-plugin-permission-sets 0.0.0-dev.6 → 0.0.0-dev.60

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 (128) hide show
  1. package/LICENSE.md +28 -0
  2. package/README.md +243 -85
  3. package/lib/adapters/connection-org-client.d.ts +21 -0
  4. package/lib/adapters/connection-org-client.d.ts.map +1 -0
  5. package/lib/adapters/connection-org-client.js +265 -0
  6. package/lib/adapters/connection-org-client.js.map +1 -0
  7. package/lib/adapters/index.d.ts +2 -0
  8. package/lib/adapters/index.d.ts.map +1 -0
  9. package/lib/adapters/index.js +2 -0
  10. package/lib/adapters/index.js.map +1 -0
  11. package/lib/commands/ps/apply.d.ts +41 -0
  12. package/lib/commands/ps/apply.d.ts.map +1 -0
  13. package/lib/commands/ps/apply.js +178 -0
  14. package/lib/commands/ps/apply.js.map +1 -0
  15. package/lib/commands/ps/check.d.ts +21 -0
  16. package/lib/commands/ps/check.d.ts.map +1 -0
  17. package/lib/commands/ps/check.js +55 -0
  18. package/lib/commands/ps/check.js.map +1 -0
  19. package/lib/commands/ps/export.d.ts +26 -0
  20. package/lib/commands/ps/export.d.ts.map +1 -0
  21. package/lib/commands/ps/export.js +74 -0
  22. package/lib/commands/ps/export.js.map +1 -0
  23. package/lib/commands/ps/plan.d.ts +61 -0
  24. package/lib/commands/ps/plan.d.ts.map +1 -0
  25. package/lib/commands/ps/plan.js +212 -0
  26. package/lib/commands/ps/plan.js.map +1 -0
  27. package/lib/commands/ps/validate.d.ts +21 -0
  28. package/lib/commands/ps/validate.d.ts.map +1 -0
  29. package/lib/commands/ps/validate.js +56 -0
  30. package/lib/commands/ps/validate.js.map +1 -0
  31. package/lib/core/diff.d.ts +10 -0
  32. package/lib/core/diff.d.ts.map +1 -0
  33. package/lib/core/diff.js +54 -0
  34. package/lib/core/diff.js.map +1 -0
  35. package/lib/core/finding.d.ts +41 -0
  36. package/lib/core/finding.d.ts.map +1 -0
  37. package/lib/core/finding.js +76 -0
  38. package/lib/core/finding.js.map +1 -0
  39. package/lib/core/index.d.ts +10 -0
  40. package/lib/core/index.d.ts.map +1 -0
  41. package/lib/core/index.js +9 -0
  42. package/lib/core/index.js.map +1 -0
  43. package/lib/core/load.d.ts +4 -0
  44. package/lib/core/load.d.ts.map +1 -0
  45. package/lib/core/load.js +60 -0
  46. package/lib/core/load.js.map +1 -0
  47. package/lib/core/mode.d.ts +18 -0
  48. package/lib/core/mode.d.ts.map +1 -0
  49. package/lib/core/mode.js +16 -0
  50. package/lib/core/mode.js.map +1 -0
  51. package/lib/core/model.d.ts +78 -0
  52. package/lib/core/model.d.ts.map +1 -0
  53. package/lib/core/model.js +2 -0
  54. package/lib/core/model.js.map +1 -0
  55. package/lib/core/normalize.d.ts +17 -0
  56. package/lib/core/normalize.d.ts.map +1 -0
  57. package/lib/core/normalize.js +72 -0
  58. package/lib/core/normalize.js.map +1 -0
  59. package/lib/core/parse.d.ts +10 -0
  60. package/lib/core/parse.d.ts.map +1 -0
  61. package/lib/core/parse.js +20 -0
  62. package/lib/core/parse.js.map +1 -0
  63. package/lib/core/report.d.ts +15 -0
  64. package/lib/core/report.d.ts.map +1 -0
  65. package/lib/core/report.js +122 -0
  66. package/lib/core/report.js.map +1 -0
  67. package/lib/core/resolve.d.ts +20 -0
  68. package/lib/core/resolve.d.ts.map +1 -0
  69. package/lib/core/resolve.js +88 -0
  70. package/lib/core/resolve.js.map +1 -0
  71. package/lib/core/schema.d.ts +23 -0
  72. package/lib/core/schema.d.ts.map +1 -0
  73. package/lib/core/schema.js +35 -0
  74. package/lib/core/schema.js.map +1 -0
  75. package/lib/core/serialize.d.ts +9 -0
  76. package/lib/core/serialize.d.ts.map +1 -0
  77. package/lib/core/serialize.js +36 -0
  78. package/lib/core/serialize.js.map +1 -0
  79. package/lib/index.d.ts +1 -0
  80. package/lib/index.d.ts.map +1 -0
  81. package/lib/services/adapters/index.d.ts +2 -0
  82. package/lib/services/adapters/index.d.ts.map +1 -0
  83. package/lib/services/adapters/index.js +2 -0
  84. package/lib/services/adapters/index.js.map +1 -0
  85. package/lib/services/adapters/org-client.d.ts +22 -0
  86. package/lib/services/adapters/org-client.d.ts.map +1 -0
  87. package/lib/services/adapters/org-client.js +2 -0
  88. package/lib/services/adapters/org-client.js.map +1 -0
  89. package/lib/services/apply.d.ts +39 -0
  90. package/lib/services/apply.d.ts.map +1 -0
  91. package/lib/services/apply.js +85 -0
  92. package/lib/services/apply.js.map +1 -0
  93. package/lib/services/check.d.ts +14 -0
  94. package/lib/services/check.d.ts.map +1 -0
  95. package/lib/services/check.js +18 -0
  96. package/lib/services/check.js.map +1 -0
  97. package/lib/services/export.d.ts +19 -0
  98. package/lib/services/export.d.ts.map +1 -0
  99. package/lib/services/export.js +29 -0
  100. package/lib/services/export.js.map +1 -0
  101. package/lib/services/index.d.ts +6 -0
  102. package/lib/services/index.d.ts.map +1 -0
  103. package/lib/services/index.js +6 -0
  104. package/lib/services/index.js.map +1 -0
  105. package/lib/services/plan.d.ts +29 -0
  106. package/lib/services/plan.d.ts.map +1 -0
  107. package/lib/services/plan.js +51 -0
  108. package/lib/services/plan.js.map +1 -0
  109. package/lib/services/resolution.d.ts +17 -0
  110. package/lib/services/resolution.d.ts.map +1 -0
  111. package/lib/services/resolution.js +48 -0
  112. package/lib/services/resolution.js.map +1 -0
  113. package/lib/services/validate.d.ts +21 -0
  114. package/lib/services/validate.d.ts.map +1 -0
  115. package/lib/services/validate.js +50 -0
  116. package/lib/services/validate.js.map +1 -0
  117. package/messages/ps.apply.md +85 -0
  118. package/messages/ps.check.md +33 -0
  119. package/messages/ps.export.md +45 -0
  120. package/messages/ps.plan.md +85 -0
  121. package/messages/ps.validate.md +29 -0
  122. package/package.json +115 -180
  123. package/lib/commands/ps/info.d.ts +0 -11
  124. package/lib/commands/ps/info.js +0 -17
  125. package/lib/commands/ps/info.js.map +0 -1
  126. package/messages/ps.info.md +0 -17
  127. package/oclif.lock +0 -7781
  128. package/oclif.manifest.json +0 -51
@@ -0,0 +1,26 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ export type PsExportResult = {
3
+ outputFile: string | null;
4
+ users: number;
5
+ assignments: number;
6
+ unmatchedUsers: string[];
7
+ /** The YAML document, present only when it was written to stdout rather than a file. */
8
+ content?: string;
9
+ };
10
+ export default class Export extends SfCommand<PsExportResult> {
11
+ static readonly summary: string;
12
+ static readonly description: string;
13
+ static readonly examples: string[];
14
+ static readonly flags: {
15
+ 'target-org': import("@oclif/core/interfaces").OptionFlag<import("@salesforce/core").Org, import("@oclif/core/interfaces").CustomOptions>;
16
+ 'output-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ user: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
+ kind: import("@oclif/core/interfaces").OptionFlag<("permissionSets" | "permissionSetGroups" | "permissionSetLicenses")[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
+ };
20
+ run(): Promise<PsExportResult>;
21
+ private warnUnmatchedUsers;
22
+ private logExportSuccess;
23
+ /** Write the document to stdout with no extra trailing newline, so it is byte-identical to the file. */
24
+ private logDocument;
25
+ }
26
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/commands/ps/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAS,MAAM,6BAA6B,CAAC;AAU/D,MAAM,MAAM,cAAc,GAAG;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,SAAS,CAAC,cAAc,CAAC;IACzD,gBAAuB,OAAO,SAAkC;IAChE,gBAAuB,WAAW,SAAsC;IACxE,gBAAuB,QAAQ,WAAoC;IAEnE,gBAAuB,KAAK;;;;;MAe1B;IAEW,GAAG,IAAI,OAAO,CAAC,cAAc,CAAC;IAmC3C,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,gBAAgB;IAUxB,wGAAwG;IACxG,OAAO,CAAC,WAAW;CAGtB"}
@@ -0,0 +1,74 @@
1
+ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
2
+ import { Messages } from '@salesforce/core';
3
+ import { ConnectionOrgClient } from '../../adapters/index.js';
4
+ import { kindForScopeKey } from '../../core/index.js';
5
+ import { ExportService } from '../../services/index.js';
6
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
+ const messages = Messages.loadMessages('sf-plugin-permission-sets', 'ps.export');
8
+ export default class Export extends SfCommand {
9
+ static summary = messages.getMessage('summary');
10
+ static description = messages.getMessage('description');
11
+ static examples = messages.getMessages('examples');
12
+ static flags = {
13
+ 'target-org': Flags.requiredOrg(),
14
+ 'output-file': Flags.string({
15
+ char: 'f',
16
+ summary: messages.getMessage('flags.output-file.summary'),
17
+ }),
18
+ user: Flags.string({
19
+ summary: messages.getMessage('flags.user.summary'),
20
+ multiple: true,
21
+ }),
22
+ kind: Flags.option({
23
+ summary: messages.getMessage('flags.kind.summary'),
24
+ options: ['permissionSets', 'permissionSetGroups', 'permissionSetLicenses'],
25
+ multiple: true,
26
+ })(),
27
+ };
28
+ async run() {
29
+ const { flags } = await this.parse(Export);
30
+ const filter = {
31
+ usernames: flags.user,
32
+ kinds: flags.kind?.map(kindForScopeKey),
33
+ };
34
+ const connection = flags['target-org'].getConnection();
35
+ const orgClient = new ConnectionOrgClient(connection);
36
+ const service = new ExportService(orgClient);
37
+ const result = await service.run(flags['output-file'], filter);
38
+ this.warnUnmatchedUsers(result.unmatchedUsers);
39
+ if (result.outputFile) {
40
+ this.logExportSuccess(result.assignments, result.users, result.outputFile);
41
+ return {
42
+ outputFile: result.outputFile,
43
+ users: result.users,
44
+ assignments: result.assignments,
45
+ unmatchedUsers: result.unmatchedUsers,
46
+ };
47
+ }
48
+ this.logDocument(result.content);
49
+ return {
50
+ outputFile: null,
51
+ users: result.users,
52
+ assignments: result.assignments,
53
+ unmatchedUsers: result.unmatchedUsers,
54
+ content: result.content,
55
+ };
56
+ }
57
+ warnUnmatchedUsers(unmatchedUsers) {
58
+ for (const username of unmatchedUsers) {
59
+ this.warn(messages.getMessage('warnNoAssignments', [username]));
60
+ }
61
+ }
62
+ logExportSuccess(assignments, users, outputFile) {
63
+ this.log(messages.getMessage('success', [
64
+ assignments,
65
+ users,
66
+ outputFile,
67
+ ]));
68
+ }
69
+ /** Write the document to stdout with no extra trailing newline, so it is byte-identical to the file. */
70
+ logDocument(content) {
71
+ this.log(content.endsWith('\n') ? content.slice(0, -1) : content);
72
+ }
73
+ }
74
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/commands/ps/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ import { ActualAssignment, AssignmentUpdate, DesiredAssignment } from '../../core/index.js';
3
+ export type PsPlanResult = {
4
+ org: {
5
+ username: string;
6
+ id: string;
7
+ };
8
+ mode: string;
9
+ counts: {
10
+ toAdd: number;
11
+ toUpdate: number;
12
+ toRemove: number;
13
+ unchanged: number;
14
+ usersAffected: number;
15
+ };
16
+ /** What the chosen mode would not act on (surfaced as drift). */
17
+ drift: {
18
+ adds: number;
19
+ updates: number;
20
+ removes: number;
21
+ };
22
+ /** The full diff, regardless of mode, so machine consumers see everything the text scopes away. */
23
+ changes: {
24
+ toAdd: DesiredAssignment[];
25
+ toUpdate: AssignmentUpdate[];
26
+ toRemove: ActualAssignment[];
27
+ unchanged: ActualAssignment[];
28
+ };
29
+ };
30
+ export default class Plan extends SfCommand<PsPlanResult> {
31
+ static readonly summary: string;
32
+ static readonly description: string;
33
+ static readonly examples: string[];
34
+ static readonly flags: {
35
+ 'target-org': import("@oclif/core/interfaces").OptionFlag<import("@salesforce/core").Org, import("@oclif/core/interfaces").CustomOptions>;
36
+ file: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
37
+ mode: import("@oclif/core/interfaces").OptionFlag<"additive" | "destructive" | "sync", import("@oclif/core/interfaces").CustomOptions>;
38
+ 'show-unchanged': import("@oclif/core/interfaces").BooleanFlag<boolean>;
39
+ };
40
+ run(): Promise<PsPlanResult>;
41
+ /** Render the human-readable plan body once the run is known to be valid. */
42
+ private logPlan;
43
+ /** The assignments the chosen mode would actually act on. */
44
+ private actionable;
45
+ private logBody;
46
+ private countsLine;
47
+ private reportDrift;
48
+ private reportUnchanged;
49
+ private applyCommand;
50
+ private errorInvalid;
51
+ private logHeaderTitle;
52
+ private logHeaderOrg;
53
+ private logEmptyNoChanges;
54
+ private logEmptyNothingToApply;
55
+ private logSummaryNext;
56
+ private logDriftAdditive;
57
+ private logDriftDestructive;
58
+ private logSummaryUnchanged;
59
+ private logSummaryUnchangedListed;
60
+ }
61
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/ps/plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAS,MAAM,6BAA6B,CAAC;AAK/D,OAAO,EAGH,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EAGpB,MAAM,qBAAqB,CAAC;AAK7B,MAAM,MAAM,YAAY,GAAG;IACvB,GAAG,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACxG,iEAAiE;IACjE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1D,mGAAmG;IACnG,OAAO,EAAE;QACL,KAAK,EAAE,iBAAiB,EAAE,CAAC;QAC3B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAC7B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;QAC7B,SAAS,EAAE,gBAAgB,EAAE,CAAC;KACjC,CAAC;CACL,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,SAAS,CAAC,YAAY,CAAC;IACrD,gBAAuB,OAAO,SAAkC;IAChE,gBAAuB,WAAW,SAAsC;IACxE,gBAAuB,QAAQ,WAAoC;IAEnE,gBAAuB,KAAK;;;;;MAgB1B;IAEW,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC;IA6DzC,6EAA6E;IAC7E,OAAO,CAAC,OAAO;IA0Cf,6DAA6D;IAC7D,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,OAAO;IAMf,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,YAAY;IAUpB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,sBAAsB;IAI9B,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,yBAAyB;CAGpC"}
@@ -0,0 +1,212 @@
1
+ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
2
+ import { Messages } from '@salesforce/core';
3
+ import { ConnectionOrgClient } from '../../adapters/index.js';
4
+ import { PlanService } from '../../services/index.js';
5
+ import { formatDiff, formatFindings, } from '../../core/index.js';
6
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
+ const messages = Messages.loadMessages('sf-plugin-permission-sets', 'ps.plan');
8
+ export default class Plan extends SfCommand {
9
+ static summary = messages.getMessage('summary');
10
+ static description = messages.getMessage('description');
11
+ static examples = messages.getMessages('examples');
12
+ static flags = {
13
+ 'target-org': Flags.requiredOrg(),
14
+ file: Flags.string({
15
+ char: 'f',
16
+ summary: messages.getMessage('flags.file.summary'),
17
+ required: true,
18
+ multiple: true,
19
+ }),
20
+ mode: Flags.option({
21
+ summary: messages.getMessage('flags.mode.summary'),
22
+ options: ['additive', 'destructive', 'sync'],
23
+ default: 'additive',
24
+ })(),
25
+ 'show-unchanged': Flags.boolean({
26
+ summary: messages.getMessage('flags.show-unchanged.summary'),
27
+ }),
28
+ };
29
+ async run() {
30
+ const { flags } = await this.parse(Plan);
31
+ const mode = flags.mode;
32
+ const targetOrg = flags['target-org'];
33
+ const connection = targetOrg.getConnection();
34
+ const orgClient = new ConnectionOrgClient(connection);
35
+ const service = new PlanService(orgClient);
36
+ const result = await service.run(flags.file, mode);
37
+ for (const line of formatFindings(result.findings)) {
38
+ this.log(line);
39
+ }
40
+ const diff = result.diff;
41
+ const orgId = targetOrg.getOrgId();
42
+ const username = targetOrg.getUsername() ?? '';
43
+ const orgName = username || orgId;
44
+ const actionable = this.actionable(diff, mode);
45
+ const usersAffected = new Set(actionable.map((assignment) => assignment.assignee.toLowerCase())).size;
46
+ const summary = {
47
+ org: { username, id: orgId },
48
+ mode,
49
+ counts: {
50
+ toAdd: diff.toAdd.length,
51
+ toUpdate: diff.toUpdate.length,
52
+ toRemove: diff.toRemove.length,
53
+ unchanged: diff.unchanged.length,
54
+ usersAffected,
55
+ },
56
+ drift: result.drift,
57
+ changes: {
58
+ toAdd: diff.toAdd,
59
+ toUpdate: diff.toUpdate,
60
+ toRemove: diff.toRemove,
61
+ unchanged: diff.unchanged,
62
+ },
63
+ };
64
+ if (result.status === 'invalid') {
65
+ process.exitCode = 1;
66
+ if (!this.jsonEnabled())
67
+ this.errorInvalid();
68
+ return summary;
69
+ }
70
+ this.logPlan({
71
+ diff,
72
+ mode,
73
+ orgName,
74
+ orgId,
75
+ files: flags.file,
76
+ showUnchanged: flags['show-unchanged'],
77
+ actionable,
78
+ usersAffected,
79
+ });
80
+ return summary;
81
+ }
82
+ /** Render the human-readable plan body once the run is known to be valid. */
83
+ logPlan(args) {
84
+ const { diff, mode, orgName, orgId, files, showUnchanged, actionable, usersAffected } = args;
85
+ this.logHeaderTitle();
86
+ this.logHeaderOrg(orgName, orgId, mode);
87
+ const totalChanges = diff.toAdd.length + diff.toUpdate.length + diff.toRemove.length;
88
+ if (totalChanges === 0) {
89
+ if (showUnchanged && diff.unchanged.length > 0) {
90
+ this.logBody(formatDiff(diff, { mode, showUnchanged: true }));
91
+ }
92
+ else {
93
+ this.log('');
94
+ }
95
+ this.logEmptyNoChanges(orgName);
96
+ return;
97
+ }
98
+ this.logBody(formatDiff(diff, { mode, showUnchanged }));
99
+ if (actionable.length === 0) {
100
+ this.logEmptyNothingToApply(mode);
101
+ }
102
+ else {
103
+ this.log(this.countsLine(diff, mode, usersAffected));
104
+ }
105
+ this.reportDrift(diff, mode);
106
+ this.reportUnchanged(diff.unchanged.length, showUnchanged);
107
+ if (actionable.length > 0) {
108
+ this.logSummaryNext(this.applyCommand(orgName, files, mode));
109
+ }
110
+ }
111
+ /** The assignments the chosen mode would actually act on. */
112
+ actionable(diff, mode) {
113
+ if (mode === 'destructive')
114
+ return diff.toRemove;
115
+ if (mode === 'additive')
116
+ return [
117
+ ...diff.toAdd,
118
+ ...diff.toUpdate,
119
+ ];
120
+ return [
121
+ ...diff.toAdd,
122
+ ...diff.toUpdate,
123
+ ...diff.toRemove,
124
+ ];
125
+ }
126
+ logBody(body) {
127
+ this.log('');
128
+ for (const line of body)
129
+ this.log(line);
130
+ if (body.length > 0)
131
+ this.log('');
132
+ }
133
+ countsLine(diff, mode, usersAffected) {
134
+ if (mode === 'destructive') {
135
+ return messages.getMessage('summary.counts.destructive', [
136
+ diff.toRemove.length,
137
+ usersAffected,
138
+ ]);
139
+ }
140
+ if (mode === 'additive') {
141
+ return messages.getMessage('summary.counts.additive', [
142
+ diff.toAdd.length,
143
+ diff.toUpdate.length,
144
+ usersAffected,
145
+ ]);
146
+ }
147
+ return messages.getMessage('summary.counts.sync', [
148
+ diff.toAdd.length,
149
+ diff.toUpdate.length,
150
+ diff.toRemove.length,
151
+ usersAffected,
152
+ ]);
153
+ }
154
+ reportDrift(diff, mode) {
155
+ if (mode === 'additive' && diff.toRemove.length > 0) {
156
+ this.logDriftAdditive(diff.toRemove.length);
157
+ }
158
+ if (mode === 'destructive') {
159
+ const skipped = diff.toAdd.length + diff.toUpdate.length;
160
+ if (skipped > 0)
161
+ this.logDriftDestructive(skipped);
162
+ }
163
+ }
164
+ reportUnchanged(count, showUnchanged) {
165
+ if (count === 0)
166
+ return;
167
+ if (showUnchanged)
168
+ this.logSummaryUnchangedListed(count);
169
+ else
170
+ this.logSummaryUnchanged(count);
171
+ }
172
+ applyCommand(orgName, files, mode) {
173
+ const fileArgs = files.map((file) => `-f "${file}"`).join(' ');
174
+ const modeArg = mode === 'additive' ? '' : ` --mode ${mode}`;
175
+ return `${this.config.bin} ps apply -o ${orgName} ${fileArgs}${modeArg}`;
176
+ }
177
+ errorInvalid() {
178
+ this.error(messages.getMessage('error.invalid'), { exit: 1 });
179
+ }
180
+ logHeaderTitle() {
181
+ this.log(messages.getMessage('header.title'));
182
+ }
183
+ logHeaderOrg(orgName, orgId, mode) {
184
+ this.log(messages.getMessage('header.org', [
185
+ orgName,
186
+ orgId,
187
+ mode,
188
+ ]));
189
+ }
190
+ logEmptyNoChanges(orgName) {
191
+ this.log(messages.getMessage('empty.noChanges', [orgName]));
192
+ }
193
+ logEmptyNothingToApply(mode) {
194
+ this.log(messages.getMessage('empty.nothingToApply', [mode]));
195
+ }
196
+ logSummaryNext(applyCommand) {
197
+ this.log(messages.getMessage('summary.next', [applyCommand]));
198
+ }
199
+ logDriftAdditive(count) {
200
+ this.log(messages.getMessage('drift.additive', [count]));
201
+ }
202
+ logDriftDestructive(count) {
203
+ this.log(messages.getMessage('drift.destructive', [count]));
204
+ }
205
+ logSummaryUnchanged(count) {
206
+ this.log(messages.getMessage('summary.unchanged', [count]));
207
+ }
208
+ logSummaryUnchangedListed(count) {
209
+ this.log(messages.getMessage('summary.unchangedListed', [count]));
210
+ }
211
+ }
212
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/commands/ps/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { SfCommand } from '@salesforce/sf-plugins-core';
2
+ import { Finding } from '../../core/index.js';
3
+ export type PsValidateResult = {
4
+ files: number;
5
+ users: number;
6
+ assignments: number;
7
+ findings: Finding[];
8
+ };
9
+ export default class Validate extends SfCommand<PsValidateResult> {
10
+ static readonly summary: string;
11
+ static readonly description: string;
12
+ static readonly examples: string[];
13
+ static readonly flags: {
14
+ 'target-org': import("@oclif/core/interfaces").OptionFlag<import("@salesforce/core").Org, import("@oclif/core/interfaces").CustomOptions>;
15
+ file: import("@oclif/core/interfaces").OptionFlag<string[], import("@oclif/core/interfaces").CustomOptions>;
16
+ };
17
+ run(): Promise<PsValidateResult>;
18
+ private logSummaryCounts;
19
+ private errorFailed;
20
+ }
21
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/commands/ps/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAS,MAAM,6BAA6B,CAAC;AAK/D,OAAO,EAAkB,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAK9D,MAAM,MAAM,gBAAgB,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,EAAE,CAAC;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,SAAS,CAAC,gBAAgB,CAAC;IAC7D,gBAAuB,OAAO,SAAkC;IAChE,gBAAuB,WAAW,SAAsC;IACxE,gBAAuB,QAAQ,WAAoC;IAEnE,gBAAuB,KAAK;;;MAQ1B;IAEW,GAAG,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAgC7C,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,WAAW;CAGtB"}
@@ -0,0 +1,56 @@
1
+ import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
2
+ import { Messages } from '@salesforce/core';
3
+ import { ConnectionOrgClient } from '../../adapters/index.js';
4
+ import { ValidateService } from '../../services/index.js';
5
+ import { formatFindings } from '../../core/index.js';
6
+ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
7
+ const messages = Messages.loadMessages('sf-plugin-permission-sets', 'ps.validate');
8
+ export default class Validate extends SfCommand {
9
+ static summary = messages.getMessage('summary');
10
+ static description = messages.getMessage('description');
11
+ static examples = messages.getMessages('examples');
12
+ static flags = {
13
+ 'target-org': Flags.requiredOrg(),
14
+ file: Flags.string({
15
+ char: 'f',
16
+ summary: messages.getMessage('flags.file.summary'),
17
+ required: true,
18
+ multiple: true,
19
+ }),
20
+ };
21
+ async run() {
22
+ const { flags } = await this.parse(Validate);
23
+ const connection = flags['target-org'].getConnection();
24
+ const orgClient = new ConnectionOrgClient(connection);
25
+ const service = new ValidateService(orgClient);
26
+ const result = await service.run(flags.file);
27
+ for (const line of formatFindings(result.findings)) {
28
+ this.log(line);
29
+ }
30
+ const assignees = new Set(result.assignments.map((assignment) => assignment.assignee));
31
+ this.log('');
32
+ this.logSummaryCounts(result.errors, result.warnings);
33
+ if (result.failed) {
34
+ process.exitCode = 1;
35
+ if (!this.jsonEnabled()) {
36
+ this.errorFailed();
37
+ }
38
+ }
39
+ return {
40
+ files: result.files.length,
41
+ users: assignees.size,
42
+ assignments: result.assignments.length,
43
+ findings: result.findings,
44
+ };
45
+ }
46
+ logSummaryCounts(errors, warnings) {
47
+ this.log(messages.getMessage('summary.counts', [
48
+ errors,
49
+ warnings,
50
+ ]));
51
+ }
52
+ errorFailed() {
53
+ this.error(messages.getMessage('error.failed'), { exit: 1 });
54
+ }
55
+ }
56
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/ps/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { ActualAssignment, DesiredAssignment, Diff } from './model.js';
2
+ /**
3
+ * Compare the desired assignments against the org's current memberships of the
4
+ * managed targets. `actual` must hold only assignments for targets that appear
5
+ * in `desired` (the managed set), so any actual row not in `desired` is an
6
+ * undeclared assignment eligible for removal. A declared assignment whose
7
+ * expiration differs from the org's is an update rather than unchanged.
8
+ */
9
+ export declare function diffAssignments(desired: DesiredAssignment[], actual: ActualAssignment[]): Diff;
10
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/core/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAoB,iBAAiB,EAAE,IAAI,EAAQ,MAAM,YAAY,CAAC;AAe/F;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAsC9F"}
@@ -0,0 +1,54 @@
1
+ /** Case-insensitive key for an (assignee, kind, target) tuple, matching how the org compares them. */
2
+ function assignmentKey(assignee, kind, target) {
3
+ return `${assignee.toLowerCase()} ${kind} ${target.toLowerCase()}`;
4
+ }
5
+ /** Whether two expirations name the same instant. Both absent (null) counts as equal. */
6
+ function sameExpiration(left, right) {
7
+ if (!left || !right) {
8
+ return left === right;
9
+ }
10
+ return Date.parse(left) === Date.parse(right);
11
+ }
12
+ /**
13
+ * Compare the desired assignments against the org's current memberships of the
14
+ * managed targets. `actual` must hold only assignments for targets that appear
15
+ * in `desired` (the managed set), so any actual row not in `desired` is an
16
+ * undeclared assignment eligible for removal. A declared assignment whose
17
+ * expiration differs from the org's is an update rather than unchanged.
18
+ */
19
+ export function diffAssignments(desired, actual) {
20
+ const actualByKey = new Map();
21
+ for (const assignment of actual) {
22
+ actualByKey.set(assignmentKey(assignment.assignee, assignment.kind, assignment.target), assignment);
23
+ }
24
+ const desiredKeys = new Set();
25
+ const toAdd = [];
26
+ const toUpdate = [];
27
+ const unchanged = [];
28
+ for (const assignment of desired) {
29
+ const key = assignmentKey(assignment.assignee, assignment.kind, assignment.target);
30
+ if (desiredKeys.has(key))
31
+ continue;
32
+ desiredKeys.add(key);
33
+ const existing = actualByKey.get(key);
34
+ if (!existing) {
35
+ toAdd.push(assignment);
36
+ }
37
+ else if (sameExpiration(existing.expiration, assignment.expiration)) {
38
+ unchanged.push(existing);
39
+ }
40
+ else {
41
+ toUpdate.push({
42
+ recordId: existing.recordId,
43
+ assignee: existing.assignee,
44
+ kind: existing.kind,
45
+ target: existing.target,
46
+ expiration: assignment.expiration,
47
+ previousExpiration: existing.expiration,
48
+ });
49
+ }
50
+ }
51
+ const toRemove = actual.filter((assignment) => !desiredKeys.has(assignmentKey(assignment.assignee, assignment.kind, assignment.target)));
52
+ return { toAdd, toUpdate, toRemove, unchanged };
53
+ }
54
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/core/diff.ts"],"names":[],"mappings":"AAEA,sGAAsG;AACtG,SAAS,aAAa,CAAC,QAAgB,EAAE,IAAU,EAAE,MAAc;IAC/D,OAAO,GAAG,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,IAAI,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;AACvE,CAAC;AAED,yFAAyF;AACzF,SAAS,cAAc,CAAC,IAAmB,EAAE,KAAoB;IAC7D,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,IAAI,KAAK,KAAK,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAClD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,OAA4B,EAAE,MAA0B;IACpF,MAAM,WAAW,GAAG,IAAI,GAAG,EAA4B,CAAC;IACxD,KAAK,MAAM,UAAU,IAAI,MAAM,EAAE,CAAC;QAC9B,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC;IACxG,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAAU,CAAC;IACtC,MAAM,KAAK,GAAwB,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAuB,EAAE,CAAC;IACxC,MAAM,SAAS,GAAuB,EAAE,CAAC;IAEzC,KAAK,MAAM,UAAU,IAAI,OAAO,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;QACnF,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACnC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAErB,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;aAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACpE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACJ,QAAQ,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,UAAU,EAAE,UAAU,CAAC,UAAU;gBACjC,kBAAkB,EAAE,QAAQ,CAAC,UAAU;aAC1C,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAC1B,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAC3G,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACpD,CAAC"}
@@ -0,0 +1,41 @@
1
+ type FindingLevel = 'error' | 'warning';
2
+ /** The closed vocabulary of finding codes. Adding one here is required to emit it. */
3
+ type FindingCode = 'YAML' | 'EMPTY_FILE' | 'SCHEMA' | 'EMPTY_LIST' | 'DUP_TARGET' | 'EMPTY_USER' | 'NO_FILES' | 'USER_NOT_FOUND' | 'USER_INACTIVE' | 'TARGET_NOT_FOUND' | 'TARGET_AMBIGUOUS';
4
+ export type Finding = {
5
+ level: FindingLevel;
6
+ code: FindingCode;
7
+ message: string;
8
+ file?: string;
9
+ line?: number;
10
+ };
11
+ /** Invalid YAML: the parser rejected the document. */
12
+ export declare function yamlError(message: string, file: string, line?: number): Finding;
13
+ /** The document parsed to nothing. */
14
+ export declare function emptyFileWarning(file: string): Finding;
15
+ /** The file violates the schema at `path`. */
16
+ export declare function schemaError(path: string, message: string, file: string): Finding;
17
+ /** A scope key is present but its list is empty. */
18
+ export declare function emptyListWarning(username: string, scopeKey: string, file: string): Finding;
19
+ /** A target appears more than once under one scope for one user. */
20
+ export declare function dupTargetWarning(username: string, target: string, scopeKey: string, file: string): Finding;
21
+ /** A user declares no scopes at all. */
22
+ export declare function emptyUserWarning(username: string, file: string): Finding;
23
+ /** No file on disk matched the given glob patterns. */
24
+ export declare function noFilesError(patterns: string[]): Finding;
25
+ /** A declared user does not exist in the org. */
26
+ export declare function userNotFoundError(username: string): Finding;
27
+ /** A declared user exists but is inactive. */
28
+ export declare function userInactiveError(username: string): Finding;
29
+ /** A declared target does not exist in the org. `label` is the kind's human name. */
30
+ export declare function targetNotFoundError(target: string, label: string): Finding;
31
+ /** A declared target resolves to more than one record in the org. */
32
+ export declare function targetAmbiguousError(target: string, label: string): Finding;
33
+ /** Render findings as human-readable lines. Shared by check, validate, and apply. */
34
+ export declare function formatFindings(findings: Finding[]): string[];
35
+ /** Count findings by level. */
36
+ export declare function countFindings(findings: Finding[]): {
37
+ errors: number;
38
+ warnings: number;
39
+ };
40
+ export {};
41
+ //# sourceMappingURL=finding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding.d.ts","sourceRoot":"","sources":["../../src/core/finding.ts"],"names":[],"mappings":"AAAA,KAAK,YAAY,GAAG,OAAO,GAAG,SAAS,CAAC;AAExC,sFAAsF;AACtF,KAAK,WAAW,GACV,MAAM,GACN,YAAY,GACZ,QAAQ,GACR,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,UAAU,GACV,gBAAgB,GAChB,eAAe,GACf,kBAAkB,GAClB,kBAAkB,CAAC;AAEzB,MAAM,MAAM,OAAO,GAAG;IAClB,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAiBF,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAE/E;AAED,sCAAsC;AACtC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,8CAA8C;AAC9C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhF;AAED,oDAAoD;AACpD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1F;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE1G;AAED,wCAAwC;AACxC,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAExD;AAID,iDAAiD;AACjD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,8CAA8C;AAC9C,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1E;AAED,qEAAqE;AACrE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3E;AAUD,qFAAqF;AACrF,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAM5D;AAED,+BAA+B;AAC/B,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAKvF"}