sfdx-hardis 6.12.10 → 6.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -3
- package/lib/commands/hardis/org/purge/profile.d.ts +53 -0
- package/lib/commands/hardis/org/purge/profile.js +384 -0
- package/lib/commands/hardis/org/purge/profile.js.map +1 -0
- package/lib/commands/hardis/project/clean/profiles-extract.d.ts +103 -0
- package/lib/commands/hardis/project/clean/profiles-extract.js +605 -0
- package/lib/commands/hardis/project/clean/profiles-extract.js.map +1 -0
- package/lib/common/utils/filesUtils.d.ts +5 -0
- package/lib/common/utils/filesUtils.js +64 -1
- package/lib/common/utils/filesUtils.js.map +1 -1
- package/lib/common/utils/orgUtils.d.ts +1 -1
- package/lib/common/utils/orgUtils.js +34 -3
- package/lib/common/utils/orgUtils.js.map +1 -1
- package/lib/hooks/prerun/check-dependencies.js +5 -3
- package/lib/hooks/prerun/check-dependencies.js.map +1 -1
- package/oclif.manifest.json +504 -289
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image `hardisgroupcom/sfdx-hardis@beta`
|
|
6
6
|
|
|
7
|
+
## [6.13.0] 2025-11-28
|
|
8
|
+
|
|
9
|
+
- New command [hardis:org:purge:profile](https://sfdx-hardis.cloudity.com/hardis/org/purge/profile/): Removes or "mutes" Permission Sets attributes from selected Salesforce Profile metadata files and redeploys the cleaned profiles to the target org.
|
|
10
|
+
- New command [hardis:project:clean:profiles-extract](https://sfdx-hardis.cloudity.com/hardis/project/clean/profiles-extract/)
|
|
11
|
+
- Adds site/ to .gitignore only in monitoring repositories
|
|
12
|
+
|
|
7
13
|
## [6.12.10] 2025-11-25
|
|
8
14
|
|
|
9
15
|
- Temporary downgrade isomorphic-dompurify package (jsdom dep not compliant with NodeJS < 20.19.5 and CodeBuilder / Agentforce Vibes is below)
|
|
@@ -27,7 +33,7 @@ Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image
|
|
|
27
33
|
|
|
28
34
|
## [6.12.5] 2025-11-18
|
|
29
35
|
|
|
30
|
-
- Improve JIRA authentication and display
|
|
36
|
+
- Improve JIRA authentication and display
|
|
31
37
|
- [hardis:project:deploy:notify](https://sfdx-hardis.cloudity.com/hardis/project/deploy/notify/): Make default org optional
|
|
32
38
|
- Improve pre/post deployment commands details display in PR comments
|
|
33
39
|
|
|
@@ -69,7 +75,7 @@ Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image
|
|
|
69
75
|
|
|
70
76
|
- [hardis:org:test:apex](https://sfdx-hardis.cloudity.com/hardis/org/test/apex/): Fix bug when there are no Apex classes in the org
|
|
71
77
|
- GitHub integration: Fix way to get Pull Request number
|
|
72
|
-
- As SF Cli now requires NodeJs >= 24, set the same requirement to sfdx-hardis default
|
|
78
|
+
- As SF Cli now requires NodeJs >= 24, set the same requirement to sfdx-hardis default workflows
|
|
73
79
|
|
|
74
80
|
## [6.11.3] 2025-11-04
|
|
75
81
|
|
|
@@ -98,7 +104,6 @@ Note: Can be used with `sfdx plugins:install sfdx-hardis@beta` and docker image
|
|
|
98
104
|
- Allow to override SFDX_TEST_WAIT_MINUTES and SFDX_DEPLOY_WAIT_MINUTES using CI/CD variables, and set 120 minutes as default value everywhere
|
|
99
105
|
- Fix Validation Rules formula field in doc generation
|
|
100
106
|
|
|
101
|
-
|
|
102
107
|
## [6.9.0] 2025-10-23
|
|
103
108
|
|
|
104
109
|
- Bring back Microsoft Teams notifications [using Teams Workflow](https://sfdx-hardis.cloudity.com/salesforce-ci-cd-setup-integration-ms-teams/)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
|
+
import { AnyJson } from '@salesforce/ts-types';
|
|
3
|
+
export default class OrgPurgeProfile extends SfCommand<any> {
|
|
4
|
+
static title: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: string[];
|
|
7
|
+
static flags: any;
|
|
8
|
+
protected attributesToMuteDefinition: ({
|
|
9
|
+
packageType: string;
|
|
10
|
+
nodeNameOnProfile: string;
|
|
11
|
+
attributesToMute: string[];
|
|
12
|
+
muteValue: boolean;
|
|
13
|
+
includedNames?: undefined;
|
|
14
|
+
action?: undefined;
|
|
15
|
+
excludedNames?: undefined;
|
|
16
|
+
excludedFiles?: undefined;
|
|
17
|
+
} | {
|
|
18
|
+
nodeNameOnProfile: string;
|
|
19
|
+
attributesToMute: never[];
|
|
20
|
+
includedNames: string[];
|
|
21
|
+
action: string;
|
|
22
|
+
packageType?: undefined;
|
|
23
|
+
muteValue?: undefined;
|
|
24
|
+
excludedNames?: undefined;
|
|
25
|
+
excludedFiles?: undefined;
|
|
26
|
+
} | {
|
|
27
|
+
nodeNameOnProfile: string;
|
|
28
|
+
attributesToMute: string[];
|
|
29
|
+
muteValue: boolean;
|
|
30
|
+
excludedNames: string[];
|
|
31
|
+
excludedFiles: string[];
|
|
32
|
+
packageType?: undefined;
|
|
33
|
+
includedNames?: undefined;
|
|
34
|
+
action?: undefined;
|
|
35
|
+
})[];
|
|
36
|
+
protected outputFile: any;
|
|
37
|
+
protected outputFilesRes: any;
|
|
38
|
+
protected allChanges: {
|
|
39
|
+
profile: string;
|
|
40
|
+
node: string;
|
|
41
|
+
name: string;
|
|
42
|
+
attribute: string;
|
|
43
|
+
oldValue: any;
|
|
44
|
+
newValue: any;
|
|
45
|
+
}[];
|
|
46
|
+
run(): Promise<AnyJson>;
|
|
47
|
+
private checkUncommittedChanges;
|
|
48
|
+
private loadFullOrgManifest;
|
|
49
|
+
private muteProfileAttributes;
|
|
50
|
+
filterFullOrgPackageByNamespaces(packageFullOrgPath: string, packageFilteredPackagesPath: string): Promise<void>;
|
|
51
|
+
filterFullOrgPackageByRelevantMetadataTypes(packageFilteredPackagesPath: string, packageFilteredProfilePath: string, selectedProfiles: string[]): Promise<void>;
|
|
52
|
+
deployToOrg(orgUsername: string, selectedProfiles: string[]): Promise<void>;
|
|
53
|
+
}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { SfCommand, Flags, requiredOrgFlagWithDeprecations } from '@salesforce/sf-plugins-core';
|
|
2
|
+
import { Messages } from '@salesforce/core';
|
|
3
|
+
import { promptProfiles } from '../../../../common/utils/orgUtils.js';
|
|
4
|
+
import { getReportDirectory } from '../../../../config/index.js';
|
|
5
|
+
import { buildOrgManifest } from '../../../../common/utils/deployUtils.js';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { execCommand, filterPackageXml, uxLog } from '../../../../common/utils/index.js';
|
|
8
|
+
import c from 'chalk';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import { parsePackageXmlFile, parseXmlFile, writePackageXmlFile, writeXmlFile } from '../../../../common/utils/xmlUtils.js';
|
|
11
|
+
import { prompts } from '../../../../common/utils/prompts.js';
|
|
12
|
+
import { MetadataUtils } from '../../../../common/metadata-utils/index.js';
|
|
13
|
+
import { WebSocketClient } from '../../../../common/websocketClient.js';
|
|
14
|
+
import { generateCsvFile, generateReportPath } from '../../../../common/utils/filesUtils.js';
|
|
15
|
+
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
|
|
16
|
+
const messages = Messages.loadMessages('sfdx-hardis', 'org');
|
|
17
|
+
export default class OrgPurgeProfile extends SfCommand {
|
|
18
|
+
static title = 'Remove PS attributes from Profile';
|
|
19
|
+
static description = `
|
|
20
|
+
## Command Behavior
|
|
21
|
+
|
|
22
|
+
**Removes or "mutes" Permission Sets attributes from selected Salesforce Profile metadata files and redeploys the cleaned profiles to the target org.**
|
|
23
|
+
|
|
24
|
+
This command is intended to safely remove PS attributes from Profiles after a migration from Profile-based to PS-based permission management. It:
|
|
25
|
+
- Builds or reuses a full org manifest to determine metadata present in the org.
|
|
26
|
+
- Filters the manifest to remove selected managed package namespaces and keep only relevant metadata types required for profile processing.
|
|
27
|
+
- Retrieves the necessary metadata (profiles, objects, fields, classes) into the local project.
|
|
28
|
+
- Iterates over selected profile files and mutes configured attributes (for example: classAccesses.enabled, fieldPermissions.readable/editable, objectPermissions.* and userPermissions.enabled).
|
|
29
|
+
- Writes the modified profile XML files back to the repository
|
|
30
|
+
- Deploys the updated profiles to the target org.
|
|
31
|
+
|
|
32
|
+
The command checks for uncommitted changes and will not run if the working tree has modifications, and it allows reusing a previously generated full org manifest to speed up repeated runs.
|
|
33
|
+
|
|
34
|
+
<details markdown="1">
|
|
35
|
+
<summary>Technical explanations</summary>
|
|
36
|
+
|
|
37
|
+
- **Manifest generation:** Uses 'buildOrgManifest' to create a full org 'package.xml'. If an existing manifest file is available the user can choose to reuse it.
|
|
38
|
+
- **Namespace filtering:** Queries installed packages using 'MetadataUtils.listInstalledPackages' to propose namespaces to remove from the manifest.
|
|
39
|
+
- **Metadata filtering:** Keeps only metadata types required to safely mute profiles (Profile plus the package types configured in the command).
|
|
40
|
+
- **Profile processing:** Parses profile XML files, iterates nodes ('classAccesses', 'fieldPermissions', 'objectPermissions', 'userPermissions') and sets attributes to configured mute values, skipping configured excluded names/files.
|
|
41
|
+
- **Retrieval & Deployment:** Uses the Salesforce CLI ('sf project retrieve' / 'sf project deploy') via 'execCommand' to retrieve metadata and deploy the updated profiles.
|
|
42
|
+
- **Exit behavior:** Returns an object with 'orgId' and an 'outputString'. Errors are logged to the console and do not throw uncaught exceptions within the command.
|
|
43
|
+
</details>
|
|
44
|
+
`;
|
|
45
|
+
static examples = [
|
|
46
|
+
`sf hardis:org:purge:profile`,
|
|
47
|
+
`sf hardis:org:purge:profile --target-org my-org@example.com`,
|
|
48
|
+
];
|
|
49
|
+
/* jscpd:ignore-start */
|
|
50
|
+
static flags = {
|
|
51
|
+
outputfile: Flags.string({
|
|
52
|
+
char: 'f',
|
|
53
|
+
description: 'Force the path and name of output report file. Must end with .csv',
|
|
54
|
+
}),
|
|
55
|
+
debug: Flags.boolean({
|
|
56
|
+
char: 'd',
|
|
57
|
+
default: false,
|
|
58
|
+
description: messages.getMessage('debugMode'),
|
|
59
|
+
}),
|
|
60
|
+
websocket: Flags.string({
|
|
61
|
+
description: messages.getMessage('websocket'),
|
|
62
|
+
}),
|
|
63
|
+
skipauth: Flags.boolean({
|
|
64
|
+
description: 'Skip authentication check when a default username is required',
|
|
65
|
+
}),
|
|
66
|
+
'target-org': requiredOrgFlagWithDeprecations,
|
|
67
|
+
};
|
|
68
|
+
/* jscpd:ignore-end */
|
|
69
|
+
attributesToMuteDefinition = [
|
|
70
|
+
{
|
|
71
|
+
"packageType": "ApexClass",
|
|
72
|
+
"nodeNameOnProfile": "classAccesses",
|
|
73
|
+
"attributesToMute": ["enabled"],
|
|
74
|
+
"muteValue": false
|
|
75
|
+
}, {
|
|
76
|
+
"packageType": "CustomField",
|
|
77
|
+
"nodeNameOnProfile": "fieldPermissions",
|
|
78
|
+
"attributesToMute": ["readable", "editable"],
|
|
79
|
+
"muteValue": false
|
|
80
|
+
}, {
|
|
81
|
+
"packageType": "CustomObject",
|
|
82
|
+
"nodeNameOnProfile": "objectPermissions",
|
|
83
|
+
"attributesToMute": ["allowCreate", "allowDelete", "allowEdit", "allowRead", "modifyAllRecords", "viewAllFields", "viewAllRecords"],
|
|
84
|
+
"muteValue": false
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"nodeNameOnProfile": "tabVisibilities",
|
|
88
|
+
"attributesToMute": [],
|
|
89
|
+
"includedNames": ["standard-DelegatedAccount"],
|
|
90
|
+
"action": "remove"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"nodeNameOnProfile": "userPermissions",
|
|
94
|
+
"attributesToMute": ["enabled"],
|
|
95
|
+
"muteValue": false,
|
|
96
|
+
"excludedNames": [
|
|
97
|
+
"ActivitiesAccess",
|
|
98
|
+
"ChatterInternalUser",
|
|
99
|
+
"LightningConsoleAllowedForUser",
|
|
100
|
+
"ViewHelpLink",
|
|
101
|
+
],
|
|
102
|
+
"excludedFiles": ["Admin.profile-meta.xml"]
|
|
103
|
+
}
|
|
104
|
+
];
|
|
105
|
+
outputFile;
|
|
106
|
+
outputFilesRes = {};
|
|
107
|
+
allChanges = [];
|
|
108
|
+
async run() {
|
|
109
|
+
const { flags } = await this.parse(OrgPurgeProfile);
|
|
110
|
+
this.outputFile = flags.outputfile || null;
|
|
111
|
+
const orgUsername = flags['target-org'].getUsername();
|
|
112
|
+
const conn = flags['target-org'].getConnection();
|
|
113
|
+
const instanceUrlKey = conn.instanceUrl.replace(/https?:\/\//, '').replace(/\./g, '_').toUpperCase();
|
|
114
|
+
uxLog("action", this, c.cyan(`Starting profile attributes purge process on org: ${conn.instanceUrl}`));
|
|
115
|
+
const reportDir = await getReportDirectory();
|
|
116
|
+
const packageFullOrgPath = path.join(reportDir, `org-package-xml-full_${instanceUrlKey}.xml`);
|
|
117
|
+
const packageFilteredPackagesPath = path.join(reportDir, `org-package-xml-filtered-packages_${instanceUrlKey}.xml`);
|
|
118
|
+
const packageFilteredProfilePath = path.join(reportDir, `org-package-xml-filtered-profile-purge_${instanceUrlKey}.xml`);
|
|
119
|
+
// Check if user has uncommitted changes
|
|
120
|
+
if (!await this.checkUncommittedChanges()) {
|
|
121
|
+
const confirmPromptRes = await prompts({
|
|
122
|
+
type: "confirm",
|
|
123
|
+
message: `You have uncommitted changes in your git repository, do you want to continue anyway? This may lead to overwrite your uncommitted changes.`,
|
|
124
|
+
description: "It's recommended to commit, stash or discard your changes before proceeding.",
|
|
125
|
+
});
|
|
126
|
+
if (!confirmPromptRes.value === true) {
|
|
127
|
+
uxLog("error", this, c.blue(`Operation cancelled by user. Exiting without making changes.`));
|
|
128
|
+
return {};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
uxLog("action", this, c.cyan(`Loading full org manifest for profile retrieval...`));
|
|
132
|
+
await this.loadFullOrgManifest(conn, orgUsername, packageFullOrgPath);
|
|
133
|
+
await this.filterFullOrgPackageByNamespaces(packageFullOrgPath, packageFilteredPackagesPath);
|
|
134
|
+
const selectedProfiles = await promptProfiles(flags['target-org'].getConnection(), { multiselect: true, returnApiName: true });
|
|
135
|
+
uxLog("action", this, c.cyan(`Filtering full org manifest to only keep relevant metadata types...`));
|
|
136
|
+
await this.filterFullOrgPackageByRelevantMetadataTypes(packageFilteredPackagesPath, packageFilteredProfilePath, selectedProfiles);
|
|
137
|
+
uxLog("action", this, c.cyan(`Retrieving metadatas required for profile purge (this will take some time)...`));
|
|
138
|
+
await execCommand(`sf project retrieve start --manifest ${packageFilteredProfilePath} --target-org ${orgUsername} --ignore-conflicts --json`, this, { output: false, fail: true });
|
|
139
|
+
uxLog("action", this, c.cyan(`Muting unwanted profile attributes...`));
|
|
140
|
+
const profilesDir = path.join('force-app', 'main', 'default', 'profiles');
|
|
141
|
+
for (const selectedProfile of selectedProfiles) {
|
|
142
|
+
const profileFilePath = path.join(profilesDir, `${selectedProfile}.profile-meta.xml`);
|
|
143
|
+
if (!fs.existsSync(profileFilePath)) {
|
|
144
|
+
uxLog("warning", this, c.yellow(`Profile file ${profileFilePath} does not exist. Skipping.`));
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const profileWithMutedAttributes = await this.muteProfileAttributes(profileFilePath);
|
|
148
|
+
await writeXmlFile(profileFilePath, profileWithMutedAttributes);
|
|
149
|
+
uxLog("success", this, c.green(`Profile ${selectedProfile} processed and unwanted attributes muted.`));
|
|
150
|
+
WebSocketClient.sendReportFileMessage(profileFilePath, `See updated ${path.basename(profileFilePath, ".profile-meta.xml")} profile `, 'report');
|
|
151
|
+
}
|
|
152
|
+
// Generate output CSV file
|
|
153
|
+
this.outputFile = await generateReportPath('profile-muted-attributes', this.outputFile);
|
|
154
|
+
this.outputFilesRes = await generateCsvFile(this.allChanges, this.outputFile, { fileTitle: 'Profile muted attributes report' });
|
|
155
|
+
const promptDeployRes = await prompts({
|
|
156
|
+
type: "confirm",
|
|
157
|
+
message: `Do you want to deploy ${selectedProfiles} profiles back to the org now?`,
|
|
158
|
+
description: "Deploying the profiles will overwrite the existing profiles in the target org with the muted versions. Profiles: " + selectedProfiles.join(", "),
|
|
159
|
+
initial: true,
|
|
160
|
+
});
|
|
161
|
+
if (!promptDeployRes.value === true) {
|
|
162
|
+
uxLog("error", this, c.blue(`Deployment cancelled by user. Exiting without deploying profiles.`));
|
|
163
|
+
return { orgId: flags['target-org'].getOrgId(), outputString: "Profile purge completed without deployment." };
|
|
164
|
+
}
|
|
165
|
+
uxLog("action", this, c.cyan(`Deploying muted profiles back to the org...`));
|
|
166
|
+
await this.deployToOrg(orgUsername, selectedProfiles);
|
|
167
|
+
return {
|
|
168
|
+
orgId: flags['target-org'].getOrgId(),
|
|
169
|
+
outputString: "Successfully purged profiles.",
|
|
170
|
+
outputFile: this.outputFile,
|
|
171
|
+
outputFilesRes: this.outputFilesRes
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async checkUncommittedChanges() {
|
|
175
|
+
const gitResult = await execCommand('git status --porcelain', this, { output: true, fail: false });
|
|
176
|
+
const output = typeof gitResult === 'string' ? gitResult : (gitResult && gitResult.stdout) || '';
|
|
177
|
+
return output.trim() === '';
|
|
178
|
+
}
|
|
179
|
+
async loadFullOrgManifest(conn, orgUsername, packageFullOrgPath) {
|
|
180
|
+
// Check if full org manifest already exists
|
|
181
|
+
let useExistingManifest = false;
|
|
182
|
+
if (fs.existsSync(packageFullOrgPath)) {
|
|
183
|
+
const promptResults = await prompts({
|
|
184
|
+
type: "select",
|
|
185
|
+
name: "useExistingManifest",
|
|
186
|
+
message: "Do you want to use the existing full org manifest or generate a new one?",
|
|
187
|
+
description: "A full org manifest file was found from a previous run. You can either use it or generate a new one to ensure it's up to date. It may take some time to generate a new one.",
|
|
188
|
+
choices: [
|
|
189
|
+
{
|
|
190
|
+
title: `Use the existing full org manifest`,
|
|
191
|
+
description: `Cache file is located at ${path.relative(process.cwd(), packageFullOrgPath)}`,
|
|
192
|
+
value: true
|
|
193
|
+
},
|
|
194
|
+
{ title: "Generate a new full org manifest", value: false },
|
|
195
|
+
],
|
|
196
|
+
});
|
|
197
|
+
useExistingManifest = promptResults.useExistingManifest;
|
|
198
|
+
}
|
|
199
|
+
if (!useExistingManifest) {
|
|
200
|
+
uxLog("action", this, c.cyan(`Generating full org manifest for profile retrieval...`));
|
|
201
|
+
await buildOrgManifest(orgUsername, packageFullOrgPath, conn);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async muteProfileAttributes(profileFilePath) {
|
|
205
|
+
const profileName = path.basename(profileFilePath, '.profile-meta.xml');
|
|
206
|
+
uxLog("action", this, c.cyan(`Processing profile: ${profileName}`));
|
|
207
|
+
const profileParsedXml = await parseXmlFile(profileFilePath);
|
|
208
|
+
const filename = path.basename(profileFilePath);
|
|
209
|
+
const changes = [];
|
|
210
|
+
for (const attributeConfig of this.attributesToMuteDefinition) {
|
|
211
|
+
const excludedFiles = attributeConfig.excludedFiles || [];
|
|
212
|
+
if (excludedFiles.includes(filename)) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const nodeName = attributeConfig.nodeNameOnProfile;
|
|
216
|
+
if (!profileParsedXml?.Profile?.[nodeName]) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
// Ensure we work with an array to simplify processing
|
|
220
|
+
if (!Array.isArray(profileParsedXml.Profile[nodeName])) {
|
|
221
|
+
profileParsedXml.Profile[nodeName] = [profileParsedXml.Profile[nodeName]];
|
|
222
|
+
}
|
|
223
|
+
const muteValue = attributeConfig.muteValue || false;
|
|
224
|
+
const attributesToMute = attributeConfig.attributesToMute;
|
|
225
|
+
const includedNames = attributeConfig.includedNames || [];
|
|
226
|
+
const excludedNames = attributeConfig.excludedNames || [];
|
|
227
|
+
const action = attributeConfig.action || 'mute';
|
|
228
|
+
if (action === 'remove') {
|
|
229
|
+
// Remove nodes with names in includedNames
|
|
230
|
+
profileParsedXml.Profile[nodeName] = profileParsedXml.Profile[nodeName].filter((nodeObj) => {
|
|
231
|
+
let memberName = nodeObj.apexClass || nodeObj.field || nodeObj.object || nodeObj.apexPage || nodeObj.tab || nodeObj.recordType || nodeObj.application || nodeObj.name || 'unknown';
|
|
232
|
+
if (Array.isArray(memberName)) {
|
|
233
|
+
memberName = memberName[0];
|
|
234
|
+
}
|
|
235
|
+
if (includedNames.includes(memberName)) {
|
|
236
|
+
changes.push({
|
|
237
|
+
node: nodeName,
|
|
238
|
+
name: memberName,
|
|
239
|
+
attribute: 'entire node',
|
|
240
|
+
oldValue: JSON.stringify(nodeObj),
|
|
241
|
+
newValue: 'removed',
|
|
242
|
+
});
|
|
243
|
+
return false; // Exclude this node
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
continue; // Move to next attributeConfig
|
|
247
|
+
}
|
|
248
|
+
for (let i = 0; i < profileParsedXml.Profile[nodeName].length; i++) {
|
|
249
|
+
/* jscpd:ignore-start */
|
|
250
|
+
const nodeObj = profileParsedXml.Profile[nodeName][i];
|
|
251
|
+
let memberName = nodeObj.apexClass || nodeObj.field || nodeObj.object || nodeObj.apexPage || nodeObj.tab || nodeObj.recordType || nodeObj.application || nodeObj.name || 'unknown';
|
|
252
|
+
if (Array.isArray(memberName)) {
|
|
253
|
+
memberName = memberName[0];
|
|
254
|
+
}
|
|
255
|
+
/* jscpd:ignore-end */
|
|
256
|
+
for (const attr of attributesToMute) {
|
|
257
|
+
if (memberName && excludedNames.includes(memberName)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (nodeObj && Object.prototype.hasOwnProperty.call(nodeObj, attr)) {
|
|
261
|
+
let oldVal = nodeObj[attr];
|
|
262
|
+
if (Array.isArray(oldVal)) {
|
|
263
|
+
oldVal = oldVal[0];
|
|
264
|
+
}
|
|
265
|
+
// Only record a change if the value actually differs
|
|
266
|
+
if (oldVal !== muteValue) {
|
|
267
|
+
changes.push({
|
|
268
|
+
node: nodeName,
|
|
269
|
+
name: memberName,
|
|
270
|
+
attribute: attr,
|
|
271
|
+
oldValue: oldVal,
|
|
272
|
+
newValue: muteValue,
|
|
273
|
+
});
|
|
274
|
+
nodeObj[attr] = muteValue;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Build a single summary string and emit it with one uxLog("log") call
|
|
281
|
+
const summaryLines = [];
|
|
282
|
+
summaryLines.push(`Profile: ${profileName}`);
|
|
283
|
+
if (changes.length === 0) {
|
|
284
|
+
summaryLines.push('No attributes muted.');
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
summaryLines.push(`Muted ${changes.length} attribute(s):`);
|
|
288
|
+
for (const ch of changes) {
|
|
289
|
+
summaryLines.push(`- [${ch.node}] ${ch.name} -> ${ch.attribute}: ${JSON.stringify(ch.oldValue)} => ${JSON.stringify(ch.newValue)}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
uxLog('log', this, c.cyan(summaryLines.join('\n')));
|
|
293
|
+
this.allChanges.push(...changes.map(change => ({ profile: profileName, ...change })));
|
|
294
|
+
return profileParsedXml;
|
|
295
|
+
}
|
|
296
|
+
async filterFullOrgPackageByNamespaces(packageFullOrgPath, packageFilteredPackagesPath) {
|
|
297
|
+
const namespaceOptions = [];
|
|
298
|
+
try {
|
|
299
|
+
uxLog("action", this, c.cyan(`Retrieving installed packages to list namespaces...`));
|
|
300
|
+
const installedPackages = await MetadataUtils.listInstalledPackages(null, this);
|
|
301
|
+
for (const installedPackage of installedPackages) {
|
|
302
|
+
if (installedPackage?.SubscriberPackageNamespace !== '' && installedPackage?.SubscriberPackageNamespace != null) {
|
|
303
|
+
namespaceOptions.push({
|
|
304
|
+
title: installedPackage.SubscriberPackageNamespace, // Display title
|
|
305
|
+
value: installedPackage.SubscriberPackageNamespace
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
uxLog("warning", this, c.yellow(`Could not retrieve installed packages. Listing namespaces by parsing the XML file.`));
|
|
312
|
+
uxLog("other", this, error?.message);
|
|
313
|
+
}
|
|
314
|
+
if (namespaceOptions.length === 0) {
|
|
315
|
+
uxLog("action", this, c.cyan(`No installed packages found via API. Parsing package XML to list namespaces...`));
|
|
316
|
+
// Fallback: parse the package XML to find namespaces
|
|
317
|
+
const parsedPackageXml = await parsePackageXmlFile(packageFullOrgPath);
|
|
318
|
+
const allTypes = Object.keys(parsedPackageXml);
|
|
319
|
+
const namespaceSet = new Set();
|
|
320
|
+
for (const typeEntry of allTypes) {
|
|
321
|
+
for (const member of parsedPackageXml[typeEntry]) {
|
|
322
|
+
const parts = member.split('__');
|
|
323
|
+
if (parts.length > 2 && !member.includes(".")) {
|
|
324
|
+
const namespace = parts[0];
|
|
325
|
+
namespaceSet.add(namespace);
|
|
326
|
+
}
|
|
327
|
+
else if (parts.length > 1 && !member.includes(".") && !member.includes("__c") && parts[1].length > 1) {
|
|
328
|
+
const namespace = parts[0];
|
|
329
|
+
namespaceSet.add(namespace);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
for (const namespace of namespaceSet) {
|
|
334
|
+
namespaceOptions.push({
|
|
335
|
+
title: namespace,
|
|
336
|
+
value: namespace
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const selectedNamespacesPrompt = await prompts({
|
|
341
|
+
type: 'multiselect',
|
|
342
|
+
name: "namespaces",
|
|
343
|
+
message: "Select the namespaces you want to ignore in the selected profiles that will be processed.",
|
|
344
|
+
description: "You will NOT disable access to elements related to namespaces that you will select.",
|
|
345
|
+
choices: namespaceOptions
|
|
346
|
+
});
|
|
347
|
+
uxLog("action", this, c.cyan(`Filtering full org manifest to remove unwanted namespaces...`));
|
|
348
|
+
await filterPackageXml(packageFullOrgPath, packageFilteredPackagesPath, {
|
|
349
|
+
removeNamespaces: selectedNamespacesPrompt.namespaces,
|
|
350
|
+
removeStandard: false
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
async filterFullOrgPackageByRelevantMetadataTypes(packageFilteredPackagesPath, packageFilteredProfilePath, selectedProfiles) {
|
|
354
|
+
const parsedPackage = await parsePackageXmlFile(packageFilteredPackagesPath);
|
|
355
|
+
const keysToKeep = Array.from(new Set([
|
|
356
|
+
...this.attributesToMuteDefinition
|
|
357
|
+
.map((a) => a.packageType)
|
|
358
|
+
.filter((pkgType) => pkgType != null),
|
|
359
|
+
'Profile',
|
|
360
|
+
]));
|
|
361
|
+
for (const key of Object.keys(parsedPackage)) {
|
|
362
|
+
if (!keysToKeep.includes(key)) {
|
|
363
|
+
delete parsedPackage[key];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
parsedPackage['Profile'] = selectedProfiles;
|
|
367
|
+
await writePackageXmlFile(packageFilteredProfilePath, parsedPackage);
|
|
368
|
+
}
|
|
369
|
+
async deployToOrg(orgUsername, selectedProfiles) {
|
|
370
|
+
try {
|
|
371
|
+
const metadataArgs = selectedProfiles
|
|
372
|
+
.map((p) => `--metadata "Profile:${p}"`)
|
|
373
|
+
.join(' ');
|
|
374
|
+
await execCommand(`sf project deploy start ${metadataArgs} --target-org ${orgUsername} --ignore-conflicts --json`, this, { output: true, fail: true });
|
|
375
|
+
uxLog("action", this, c.cyan(`Successfully deployed ${selectedProfiles.length}`));
|
|
376
|
+
uxLog("success", this, c.green(`Profiles deployed successfully:\n${selectedProfiles.join(', ')}`));
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
379
|
+
uxLog("action", this, c.red(`Failed to deploy profiles.`));
|
|
380
|
+
uxLog("error", this, c.red(JSON.stringify(error, null, 2)));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
//# sourceMappingURL=profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../../../src/commands/hardis/org/purge/profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { SfCommand } from '@salesforce/sf-plugins-core';
|
|
2
|
+
export default class ProfilesExtract extends SfCommand<void> {
|
|
3
|
+
static readonly description = "\n## Command Behavior\n\n**Guides administrators through extracting Salesforce profiles, personas, and related metadata into structured CSV/XLSX deliverables.**\n\nThe command inventories SObjects that contain data, lets the user pick the ones to document, and then produces persona-centric spreadsheets that cover users, personas, relationships, record types, apps, permissions, tabs, fields, and permission sets. The output consolidates everything into both CSV files and a single Excel workbook, making it easy to audit access models or prepare remediation plans.\n\nKey capabilities:\n\n- **Interactive object discovery:** Lists queryable objects with records and allows multi-selection.\n- **Persona modeling:** Lets users define the number of personas and generates cross-object matrices that leverage Excel formulas for faster updates.\n- **Comprehensive metadata export:** Captures users, record types, apps, permissions, tabs, fields, and permission sets with persona/profile visibility indicators.\n- **Profile field access coverage:** Retrieves FieldPermissions to surface read/edit status per profile and field.\n- **Consolidated reporting:** Produces standalone CSVs plus an aggregated XLSX stored in the report directory.\n\n<details markdown=\"1\">\n<summary>Technical explanations</summary>\n\n- **Salesforce connectivity:** Uses the requested target org connection from `Flags.requiredOrg` to fetch metadata and records.\n- **Bulk/REST queries:** Relies on `bulkQuery` and standard SOQL to evaluate record counts and pull FieldPermissions, Users, RecordTypes, Applications, Tabs, and PermissionSets.\n- **Describe calls:** Invokes `describeGlobal` and `describeSObject` to enumerate objects and field-level metadata, including picklists and formulas.\n- **Prompt-driven input:** Utilizes the shared `prompts` utility to collect object selections and persona counts, ensuring consistent CLI UX.\n- **Reporting pipeline:** Writes intermediate CSV files via `generateCsvFile`, stores them under the report directory from `getReportDirectory`, and finally merges them using `createXlsxFromCsvFiles`.\n- **Logging & diagnostics:** Uses `uxLog` with chalk coloring for progress, warnings, and debug output, integrating with the project-wide logging style.\n\n</details>\n";
|
|
4
|
+
static readonly examples: string[];
|
|
5
|
+
static readonly flags: {
|
|
6
|
+
'target-org': import("@oclif/core/interfaces").OptionFlag<import("@salesforce/core").Org, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
debug: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
websocket: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
9
|
+
skipauth: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
protected csvFiles: string[];
|
|
12
|
+
protected outputFile: string;
|
|
13
|
+
protected activeProfileNames: Set<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Main entry point for the command. Orchestrates the extraction process:
|
|
16
|
+
* - Prompts user to select objects
|
|
17
|
+
* - Extracts users, personas, relations, record types, apps, permissions, tabs, and object fields
|
|
18
|
+
* - Generates CSV and XLSX reports
|
|
19
|
+
*/
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Extracts field-level access for profiles using FieldPermissions object.
|
|
23
|
+
* Generates a CSV report of profile-field access.
|
|
24
|
+
* @param conn Salesforce connection
|
|
25
|
+
*/
|
|
26
|
+
getProfileFieldAccessData(conn: any, selectedObjects: string[]): Promise<{
|
|
27
|
+
Profile: string;
|
|
28
|
+
SObjectType: string;
|
|
29
|
+
Field: string;
|
|
30
|
+
PermissionsRead: string;
|
|
31
|
+
PermissionsEdit: string;
|
|
32
|
+
}[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Prompts the user to select Salesforce objects (SObjects) that have records in the org.
|
|
35
|
+
* Generates a CSV report of the selected objects.
|
|
36
|
+
* @param conn Salesforce connection
|
|
37
|
+
* @returns Array of selected object API names
|
|
38
|
+
*/
|
|
39
|
+
private generateObjectsList;
|
|
40
|
+
/**
|
|
41
|
+
* Extracts active users from the org, including their username, role, and profile.
|
|
42
|
+
* Generates a CSV report of users.
|
|
43
|
+
* @param conn Salesforce connection
|
|
44
|
+
*/
|
|
45
|
+
generateUsersExtract(conn: any): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Prompts the user for the number of personas to create.
|
|
48
|
+
* Generates a CSV report listing the personas.
|
|
49
|
+
* @returns The number of personas
|
|
50
|
+
*/
|
|
51
|
+
private generatePersonaExtract;
|
|
52
|
+
/**
|
|
53
|
+
* Generates a CSV mapping each selected object to persona permissions (Read, Create, Edit, Delete).
|
|
54
|
+
* @param selectedObjects Array of object API names
|
|
55
|
+
* @param numberOfPersonas Number of personas
|
|
56
|
+
*/
|
|
57
|
+
generateRelationExtract(selectedObjects: string[], numberOfPersonas: number): Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Extracts record types for each selected object and maps persona access (Active, Default).
|
|
60
|
+
* Generates a CSV report of record types per object.
|
|
61
|
+
* @param conn Salesforce connection
|
|
62
|
+
* @param selectedObjects Array of object API names
|
|
63
|
+
* @param numberOfPersonas Number of personas
|
|
64
|
+
*/
|
|
65
|
+
generateRTExtract(conn: any, selectedObjects: string[], numberOfPersonas: number): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Extracts custom applications (AppDefinition) and maps persona access (Active, Default).
|
|
68
|
+
* Generates a CSV report of applications.
|
|
69
|
+
* @param conn Salesforce connection
|
|
70
|
+
* @param numberOfPersonas Number of personas
|
|
71
|
+
*/
|
|
72
|
+
generateAppsExtract(conn: any, numberOfPersonas: number): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Extracts all boolean permission fields from PermissionSet object.
|
|
75
|
+
* Generates a CSV report mapping each permission to personas.
|
|
76
|
+
* @param conn Salesforce connection
|
|
77
|
+
* @param numberOfPersonas Number of personas
|
|
78
|
+
*/
|
|
79
|
+
generatePermissionsExtract(conn: any, numberOfPersonas: number): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Extracts custom tabs and maps persona access.
|
|
82
|
+
* Generates a CSV report of tabs.
|
|
83
|
+
* @param conn Salesforce connection
|
|
84
|
+
* @param numberOfPersonas Number of personas
|
|
85
|
+
*/
|
|
86
|
+
generateTabsExtract(conn: any, numberOfPersonas: number): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* For each selected object, extracts all fields and their metadata (label, type, picklist values, etc.).
|
|
89
|
+
* Maps persona visibility and read-only status for each field.
|
|
90
|
+
* Generates a CSV report per object.
|
|
91
|
+
* @param conn Salesforce connection
|
|
92
|
+
* @param selectedObjects Array of object API names
|
|
93
|
+
* @param numberOfPersonas Number of personas
|
|
94
|
+
*/
|
|
95
|
+
generateObjectFieldsExtract(conn: any, selectedObjects: string[], numberOfPersonas: number, profileNames?: string[], profileFieldAccess?: any[]): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Extracts all Permission Sets in the org.
|
|
98
|
+
* Generates a CSV report mapping each permission set to personas.
|
|
99
|
+
* @param conn
|
|
100
|
+
* @param numberOfPersonas
|
|
101
|
+
*/
|
|
102
|
+
generatePermissionSetsExtract(conn: any, numberOfPersonas: number): Promise<void>;
|
|
103
|
+
}
|