@j-schreiber/sf-cli-security-audit 0.4.1 → 0.5.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/README.md +20 -5
- package/lib/commands/org/audit/init.d.ts +2 -0
- package/lib/commands/org/audit/init.js +10 -0
- package/lib/commands/org/audit/init.js.map +1 -1
- package/lib/libs/conf-init/auditConfig.d.ts +8 -0
- package/lib/libs/conf-init/auditConfig.js +1 -1
- package/lib/libs/conf-init/auditConfig.js.map +1 -1
- package/lib/libs/conf-init/permissionsClassification.d.ts +3 -2
- package/lib/libs/conf-init/permissionsClassification.js +37 -27
- package/lib/libs/conf-init/permissionsClassification.js.map +1 -1
- package/lib/libs/conf-init/presets/loose.d.ts +6 -0
- package/lib/libs/conf-init/presets/loose.js +35 -0
- package/lib/libs/conf-init/presets/loose.js.map +1 -0
- package/lib/libs/conf-init/presets/none.d.ts +30 -0
- package/lib/libs/conf-init/presets/none.js +54 -0
- package/lib/libs/conf-init/presets/none.js.map +1 -0
- package/lib/libs/conf-init/presets/strict.d.ts +4 -0
- package/lib/libs/conf-init/presets/strict.js +28 -0
- package/lib/libs/conf-init/presets/strict.js.map +1 -0
- package/lib/libs/conf-init/presets.d.ts +7 -0
- package/lib/libs/conf-init/presets.js +20 -0
- package/lib/libs/conf-init/presets.js.map +1 -0
- package/lib/libs/core/classification-types.d.ts +1 -1
- package/lib/libs/core/classification-types.js +1 -1
- package/lib/libs/core/classification-types.js.map +1 -1
- package/lib/libs/core/mdapi/mdapiRetriever.d.ts +10 -68
- package/lib/libs/core/mdapi/mdapiRetriever.js +13 -90
- package/lib/libs/core/mdapi/mdapiRetriever.js.map +1 -1
- package/lib/libs/core/mdapi/metadataRegistryEntry.d.ts +39 -0
- package/lib/libs/core/mdapi/metadataRegistryEntry.js +31 -0
- package/lib/libs/core/mdapi/metadataRegistryEntry.js.map +1 -0
- package/lib/libs/core/mdapi/namedMetadataToolingQueryable.d.ts +33 -0
- package/lib/libs/core/mdapi/namedMetadataToolingQueryable.js +41 -0
- package/lib/libs/core/mdapi/namedMetadataToolingQueryable.js.map +1 -0
- package/lib/libs/core/mdapi/namedMetadataType.d.ts +20 -0
- package/lib/libs/core/mdapi/namedMetadataType.js +36 -0
- package/lib/libs/core/mdapi/namedMetadataType.js.map +1 -0
- package/lib/libs/core/mdapi/singletonMetadataType.d.ts +21 -0
- package/lib/libs/core/mdapi/singletonMetadataType.js +35 -0
- package/lib/libs/core/mdapi/singletonMetadataType.js.map +1 -0
- package/lib/libs/policies/profilePolicy.js +21 -28
- package/lib/libs/policies/profilePolicy.js.map +1 -1
- package/messages/org.audit.init.md +12 -0
- package/messages/policyclassifications.md +38 -2
- package/oclif.manifest.json +18 -2
- package/package.json +1 -1
- package/lib/libs/conf-init/defaultPolicyClassification.d.ts +0 -2
- package/lib/libs/conf-init/defaultPolicyClassification.js +0 -63
- package/lib/libs/conf-init/defaultPolicyClassification.js.map +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { ComponentSet } from '@salesforce/source-deploy-retrieve';
|
|
3
1
|
import { XMLParser } from 'fast-xml-parser';
|
|
2
|
+
import NamedMetadata from './namedMetadataType.js';
|
|
3
|
+
import SingletonMetadata from './singletonMetadataType.js';
|
|
4
|
+
import NamedMetadataQueryable from './namedMetadataToolingQueryable.js';
|
|
4
5
|
export default class MDAPI {
|
|
5
6
|
connection;
|
|
6
7
|
cache;
|
|
@@ -80,94 +81,6 @@ class MetadataCache {
|
|
|
80
81
|
this.components[cmpName] = content;
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
|
-
class MetadataRegistryEntry {
|
|
84
|
-
opts;
|
|
85
|
-
parser;
|
|
86
|
-
retrieveType;
|
|
87
|
-
rootNodeName;
|
|
88
|
-
constructor(opts) {
|
|
89
|
-
this.opts = opts;
|
|
90
|
-
this.retrieveType = this.opts.retrieveType;
|
|
91
|
-
this.parser = this.opts.parser ?? new XMLParser();
|
|
92
|
-
this.rootNodeName = this.opts.rootNodeName;
|
|
93
|
-
}
|
|
94
|
-
parse(fullFilePath) {
|
|
95
|
-
const fileContent = readFileSync(fullFilePath, 'utf-8');
|
|
96
|
-
const parsedContent = this.parser.parse(fileContent);
|
|
97
|
-
if (this.opts.parsePostProcessor) {
|
|
98
|
-
return this.opts.parsePostProcessor(parsedContent[this.rootNodeName]);
|
|
99
|
-
}
|
|
100
|
-
return parsedContent[this.rootNodeName];
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* The entry is a type that only has one single instance on the org, such as
|
|
105
|
-
* a Setting. The component is retrieved by its root node name
|
|
106
|
-
* (e.g. ConnectedAppSettings, AccountSettings, etc).
|
|
107
|
-
*/
|
|
108
|
-
class SingletonMetadata extends MetadataRegistryEntry {
|
|
109
|
-
retrieveName;
|
|
110
|
-
constructor(opts) {
|
|
111
|
-
super(opts);
|
|
112
|
-
this.retrieveName = opts.retrieveName ?? String(this.rootNodeName);
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Resolves component names, retrieves the metadata and returns
|
|
116
|
-
* as a strongly typed result.
|
|
117
|
-
*
|
|
118
|
-
* @param con
|
|
119
|
-
* @param componentNames
|
|
120
|
-
* @returns
|
|
121
|
-
*/
|
|
122
|
-
async resolve(con) {
|
|
123
|
-
const cmpSet = new ComponentSet([{ type: this.retrieveType, fullName: this.retrieveName }]);
|
|
124
|
-
const retrieveResult = await retrieve(cmpSet, con);
|
|
125
|
-
return this.parseSourceFile(retrieveResult.components);
|
|
126
|
-
}
|
|
127
|
-
parseSourceFile(componentSet) {
|
|
128
|
-
const cmps = componentSet.getSourceComponents({ type: this.retrieveType, fullName: this.retrieveName }).toArray();
|
|
129
|
-
if (cmps.length > 0 && cmps[0].xml) {
|
|
130
|
-
return this.parse(cmps[0].xml);
|
|
131
|
-
}
|
|
132
|
-
throw new Error('Failed to resolve settings for: ' + this.retrieveName);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
class NamedMetadata extends MetadataRegistryEntry {
|
|
136
|
-
constructor(opts) {
|
|
137
|
-
super(opts);
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Resolves component names, retrieves the metadata and returns
|
|
141
|
-
* as a strongly typed result.
|
|
142
|
-
*
|
|
143
|
-
* @param con
|
|
144
|
-
* @param componentNames
|
|
145
|
-
* @returns
|
|
146
|
-
*/
|
|
147
|
-
async resolve(con, componentNames) {
|
|
148
|
-
const cmpSet = new ComponentSet(componentNames.map((cname) => ({ type: this.retrieveType, fullName: cname })));
|
|
149
|
-
const retrieveResult = await retrieve(cmpSet, con);
|
|
150
|
-
return this.parseSourceFiles(retrieveResult.components, componentNames);
|
|
151
|
-
}
|
|
152
|
-
parseSourceFiles(componentSet, retrievedNames) {
|
|
153
|
-
const cmps = componentSet.getSourceComponents().toArray();
|
|
154
|
-
const result = {};
|
|
155
|
-
cmps.forEach((sourceComponent) => {
|
|
156
|
-
if (sourceComponent.xml && retrievedNames.includes(sourceComponent.name)) {
|
|
157
|
-
result[sourceComponent.name] = this.parse(sourceComponent.xml);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
return result;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
async function retrieve(compSet, con) {
|
|
164
|
-
const retrieveRequest = await compSet.retrieve({
|
|
165
|
-
usernameOrConnection: con,
|
|
166
|
-
output: '.jsc/retrieves',
|
|
167
|
-
});
|
|
168
|
-
const retrieveResult = await retrieveRequest.pollStatus();
|
|
169
|
-
return retrieveResult;
|
|
170
|
-
}
|
|
171
84
|
export const NamedTypesRegistry = {
|
|
172
85
|
PermissionSet: new NamedMetadata({
|
|
173
86
|
retrieveType: 'PermissionSet',
|
|
@@ -182,6 +95,16 @@ export const NamedTypesRegistry = {
|
|
|
182
95
|
classAccesses: parseResult.classAccesses ?? [],
|
|
183
96
|
}),
|
|
184
97
|
}),
|
|
98
|
+
Profile: new NamedMetadataQueryable({
|
|
99
|
+
objectName: 'Profile',
|
|
100
|
+
nameField: 'Name',
|
|
101
|
+
parsePostProcessor: (parseResult) => ({
|
|
102
|
+
...parseResult,
|
|
103
|
+
userPermissions: parseResult.userPermissions ?? [],
|
|
104
|
+
customPermissions: parseResult.customPermissions ?? [],
|
|
105
|
+
classAccesses: parseResult.classAccesses ?? [],
|
|
106
|
+
}),
|
|
107
|
+
}),
|
|
185
108
|
};
|
|
186
109
|
export const SingletonRegistry = {
|
|
187
110
|
ConnectedAppSettings: new SingletonMetadata({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdapiRetriever.js","sourceRoot":"","sources":["../../../../src/libs/core/mdapi/mdapiRetriever.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mdapiRetriever.js","sourceRoot":"","sources":["../../../../src/libs/core/mdapi/mdapiRetriever.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { PathLike } from 'node:fs';
|
|
2
|
+
import { XMLParser } from 'fast-xml-parser';
|
|
3
|
+
import { ComponentSet, RetrieveResult } from '@salesforce/source-deploy-retrieve';
|
|
4
|
+
import { Connection } from '@salesforce/core';
|
|
5
|
+
export type MetadataRegistryEntryOpts<Type, Key extends keyof Type> = {
|
|
6
|
+
/**
|
|
7
|
+
* Metadata API name of the type.
|
|
8
|
+
*/
|
|
9
|
+
retrieveType: string;
|
|
10
|
+
/**
|
|
11
|
+
* Metadata API name entity.
|
|
12
|
+
*/
|
|
13
|
+
retrieveName?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional XML parser instance. Typically used to fix errors for
|
|
16
|
+
* properties that must be parsed as list.
|
|
17
|
+
*/
|
|
18
|
+
parser?: XMLParser;
|
|
19
|
+
/**
|
|
20
|
+
* Name of the root node in XML file content
|
|
21
|
+
*/
|
|
22
|
+
rootNodeName: Key;
|
|
23
|
+
/**
|
|
24
|
+
* Post processor function that sanitises the XML parse result
|
|
25
|
+
*/
|
|
26
|
+
parsePostProcessor?: (parseResult: Type[Key]) => Type[Key];
|
|
27
|
+
};
|
|
28
|
+
export type NamedMetadataResolver<Type> = {
|
|
29
|
+
resolve(con: Connection, componentNames: string[]): Promise<Record<string, Type>>;
|
|
30
|
+
};
|
|
31
|
+
export default abstract class MetadataRegistryEntry<Type, Key extends keyof Type> {
|
|
32
|
+
private opts;
|
|
33
|
+
parser: XMLParser;
|
|
34
|
+
retrieveType: string;
|
|
35
|
+
rootNodeName: Key;
|
|
36
|
+
constructor(opts: MetadataRegistryEntryOpts<Type, Key>);
|
|
37
|
+
parse(fullFilePath: PathLike): Type[Key];
|
|
38
|
+
}
|
|
39
|
+
export declare function retrieve(compSet: ComponentSet, con: Connection): Promise<RetrieveResult>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { XMLParser } from 'fast-xml-parser';
|
|
3
|
+
export default class MetadataRegistryEntry {
|
|
4
|
+
opts;
|
|
5
|
+
parser;
|
|
6
|
+
retrieveType;
|
|
7
|
+
rootNodeName;
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
this.opts = opts;
|
|
10
|
+
this.retrieveType = this.opts.retrieveType;
|
|
11
|
+
this.parser = this.opts.parser ?? new XMLParser();
|
|
12
|
+
this.rootNodeName = this.opts.rootNodeName;
|
|
13
|
+
}
|
|
14
|
+
parse(fullFilePath) {
|
|
15
|
+
const fileContent = readFileSync(fullFilePath, 'utf-8');
|
|
16
|
+
const parsedContent = this.parser.parse(fileContent);
|
|
17
|
+
if (this.opts.parsePostProcessor) {
|
|
18
|
+
return this.opts.parsePostProcessor(parsedContent[this.rootNodeName]);
|
|
19
|
+
}
|
|
20
|
+
return parsedContent[this.rootNodeName];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function retrieve(compSet, con) {
|
|
24
|
+
const retrieveRequest = await compSet.retrieve({
|
|
25
|
+
usernameOrConnection: con,
|
|
26
|
+
output: '.jsc/retrieves',
|
|
27
|
+
});
|
|
28
|
+
const retrieveResult = await retrieveRequest.pollStatus();
|
|
29
|
+
return retrieveResult;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=metadataRegistryEntry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadataRegistryEntry.js","sourceRoot":"","sources":["../../../../src/libs/core/mdapi/metadataRegistryEntry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,YAAY,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAgC5C,MAAM,CAAC,OAAO,OAAgB,qBAAqB;IAKtB;IAJpB,MAAM,CAAY;IAClB,YAAY,CAAS;IACrB,YAAY,CAAM;IAEzB,YAA2B,IAA0C;QAA1C,SAAI,GAAJ,IAAI,CAAsC;QACnE,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAClD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;IAC7C,CAAC;IAEM,KAAK,CAAC,YAAsB;QACjC,MAAM,WAAW,GAAG,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;QACxD,MAAM,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAS,CAAC;QAC7D,IAAI,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;YACjC,OAAO,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;QACxE,CAAC;QACD,OAAO,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC1C,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAqB,EAAE,GAAe;IACnE,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC;QAC7C,oBAAoB,EAAE,GAAG;QACzB,MAAM,EAAE,gBAAgB;KACzB,CAAC,CAAC;IACH,MAAM,cAAc,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC;IAC1D,OAAO,cAAc,CAAC;AACxB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Connection } from '@salesforce/core';
|
|
2
|
+
import { NamedMetadataResolver } from './metadataRegistryEntry.js';
|
|
3
|
+
export type NamedMetadataQueryableOpts<Type> = {
|
|
4
|
+
/**
|
|
5
|
+
* Object API name to retrieve. Must be available in tooling API
|
|
6
|
+
*/
|
|
7
|
+
objectName: string;
|
|
8
|
+
/**
|
|
9
|
+
* Unique name field that is used to retrieve the object
|
|
10
|
+
*/
|
|
11
|
+
nameField: string;
|
|
12
|
+
/**
|
|
13
|
+
* Post processor function that sanitises the XML parse result
|
|
14
|
+
*/
|
|
15
|
+
parsePostProcessor?: (parseResult: Type) => Type;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* The entry is a typical named metadata that is organized in a dedicated source folder
|
|
19
|
+
* where all entities have the same format. The components are queries from tooling API
|
|
20
|
+
* and organized by their developer name.
|
|
21
|
+
*/
|
|
22
|
+
export default class NamedMetadataQueryable<Type, Key extends keyof Type> implements NamedMetadataResolver<Type[Key]> {
|
|
23
|
+
private opts;
|
|
24
|
+
constructor(opts: NamedMetadataQueryableOpts<Type[Key]>);
|
|
25
|
+
/**
|
|
26
|
+
* Resolves a set of component names by querying "Metadata" property from tooling API
|
|
27
|
+
*
|
|
28
|
+
* @param con
|
|
29
|
+
* @param componentNames
|
|
30
|
+
* @returns
|
|
31
|
+
*/
|
|
32
|
+
resolve(con: Connection, componentNames: string[]): Promise<Record<string, Type[Key]>>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { isNullish } from '../utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* The entry is a typical named metadata that is organized in a dedicated source folder
|
|
4
|
+
* where all entities have the same format. The components are queries from tooling API
|
|
5
|
+
* and organized by their developer name.
|
|
6
|
+
*/
|
|
7
|
+
export default class NamedMetadataQueryable {
|
|
8
|
+
opts;
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
this.opts = opts;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolves a set of component names by querying "Metadata" property from tooling API
|
|
14
|
+
*
|
|
15
|
+
* @param con
|
|
16
|
+
* @param componentNames
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
async resolve(con, componentNames) {
|
|
20
|
+
const pendingQueries = new Array();
|
|
21
|
+
componentNames.forEach((cname) => {
|
|
22
|
+
const qr = Promise.resolve(con.tooling.query(`SELECT ${this.opts.nameField},Metadata FROM ${this.opts.objectName} WHERE ${this.opts.nameField} = '${cname}'`));
|
|
23
|
+
pendingQueries.push(qr);
|
|
24
|
+
});
|
|
25
|
+
const queryResults = await Promise.all(pendingQueries);
|
|
26
|
+
const resultMap = {};
|
|
27
|
+
queryResults.forEach((qr) => {
|
|
28
|
+
if (qr.totalSize > 0) {
|
|
29
|
+
const record = qr.records[0];
|
|
30
|
+
const identifier = record[this.opts.nameField];
|
|
31
|
+
if (identifier && !isNullish(record.Metadata)) {
|
|
32
|
+
resultMap[identifier] = this.opts.parsePostProcessor
|
|
33
|
+
? this.opts.parsePostProcessor(record.Metadata)
|
|
34
|
+
: record.Metadata;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return resultMap;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=namedMetadataToolingQueryable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namedMetadataToolingQueryable.js","sourceRoot":"","sources":["../../../../src/libs/core/mdapi/namedMetadataToolingQueryable.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoBxC;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB;IACd;IAA3B,YAA2B,IAA2C;QAA3C,SAAI,GAAJ,IAAI,CAAuC;IAAG,CAAC;IAC1E;;;;;;OAMG;IACI,KAAK,CAAC,OAAO,CAAC,GAAe,EAAE,cAAwB;QAC5D,MAAM,cAAc,GAAG,IAAI,KAAK,EAAmD,CAAC;QACpF,cAAc,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAC/B,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CACxB,GAAG,CAAC,OAAO,CAAC,KAAK,CACf,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS,kBAAkB,IAAI,CAAC,IAAI,CAAC,UAAU,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS,OAAO,KAAK,GAAG,CAChH,CACF,CAAC;YACF,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACvD,MAAM,SAAS,GAA8B,EAAE,CAAC;QAChD,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE;YAC1B,IAAI,EAAE,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAW,CAAC;gBACzD,IAAI,UAAU,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC9C,SAAS,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB;wBAClD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC;wBAC/C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;gBACtB,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Connection } from '@salesforce/core';
|
|
2
|
+
import MetadataRegistryEntry, { MetadataRegistryEntryOpts } from './metadataRegistryEntry.js';
|
|
3
|
+
/**
|
|
4
|
+
* The entry is a typical named metadata that is organized in a dedicated source folder
|
|
5
|
+
* where all entities have the same format. The components are retrieved and organized
|
|
6
|
+
* by their developer name.
|
|
7
|
+
*/
|
|
8
|
+
export default class NamedMetadata<Type, Key extends keyof Type> extends MetadataRegistryEntry<Type, Key> {
|
|
9
|
+
constructor(opts: MetadataRegistryEntryOpts<Type, Key>);
|
|
10
|
+
/**
|
|
11
|
+
* Resolves component names, retrieves the metadata and returns
|
|
12
|
+
* as a strongly typed result.
|
|
13
|
+
*
|
|
14
|
+
* @param con
|
|
15
|
+
* @param componentNames
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
resolve(con: Connection, componentNames: string[]): Promise<Record<string, Type[Key]>>;
|
|
19
|
+
private parseSourceFiles;
|
|
20
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ComponentSet } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import MetadataRegistryEntry, { retrieve } from './metadataRegistryEntry.js';
|
|
3
|
+
/**
|
|
4
|
+
* The entry is a typical named metadata that is organized in a dedicated source folder
|
|
5
|
+
* where all entities have the same format. The components are retrieved and organized
|
|
6
|
+
* by their developer name.
|
|
7
|
+
*/
|
|
8
|
+
export default class NamedMetadata extends MetadataRegistryEntry {
|
|
9
|
+
constructor(opts) {
|
|
10
|
+
super(opts);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Resolves component names, retrieves the metadata and returns
|
|
14
|
+
* as a strongly typed result.
|
|
15
|
+
*
|
|
16
|
+
* @param con
|
|
17
|
+
* @param componentNames
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
async resolve(con, componentNames) {
|
|
21
|
+
const cmpSet = new ComponentSet(componentNames.map((cname) => ({ type: this.retrieveType, fullName: cname })));
|
|
22
|
+
const retrieveResult = await retrieve(cmpSet, con);
|
|
23
|
+
return this.parseSourceFiles(retrieveResult.components, componentNames);
|
|
24
|
+
}
|
|
25
|
+
parseSourceFiles(componentSet, retrievedNames) {
|
|
26
|
+
const cmps = componentSet.getSourceComponents().toArray();
|
|
27
|
+
const result = {};
|
|
28
|
+
cmps.forEach((sourceComponent) => {
|
|
29
|
+
if (sourceComponent.xml && retrievedNames.includes(sourceComponent.name)) {
|
|
30
|
+
result[sourceComponent.name] = this.parse(sourceComponent.xml);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=namedMetadataType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"namedMetadataType.js","sourceRoot":"","sources":["../../../../src/libs/core/mdapi/namedMetadataType.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,qBAAqB,EAAE,EAA6B,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAExG;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,aAA4C,SAAQ,qBAAgC;IACvG,YAAmB,IAA0C;QAC3D,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IACD;;;;;;;OAOG;IACI,KAAK,CAAC,OAAO,CAAC,GAAe,EAAE,cAAwB;QAC5D,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/G,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAC1E,CAAC;IAEO,gBAAgB,CAAC,YAA0B,EAAE,cAAwB;QAC3E,MAAM,IAAI,GAAG,YAAY,CAAC,mBAAmB,EAAE,CAAC,OAAO,EAAE,CAAC;QAC1D,MAAM,MAAM,GAA8B,EAAE,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,CAAC,eAAe,EAAE,EAAE;YAC/B,IAAI,eAAe,CAAC,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzE,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;YACjE,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Connection } from '@salesforce/core';
|
|
2
|
+
import MetadataRegistryEntry, { MetadataRegistryEntryOpts } from './metadataRegistryEntry.js';
|
|
3
|
+
/**
|
|
4
|
+
* The entry is a type that only has one single instance on the org, such as
|
|
5
|
+
* a Setting. The component is typically retrieved by a more generic name and
|
|
6
|
+
* organized & cached by the explicit name.
|
|
7
|
+
*/
|
|
8
|
+
export default class SingletonMetadata<Type, Key extends keyof Type> extends MetadataRegistryEntry<Type, Key> {
|
|
9
|
+
retrieveName: string;
|
|
10
|
+
constructor(opts: MetadataRegistryEntryOpts<Type, Key>);
|
|
11
|
+
/**
|
|
12
|
+
* Resolves component names, retrieves the metadata and returns
|
|
13
|
+
* as a strongly typed result.
|
|
14
|
+
*
|
|
15
|
+
* @param con
|
|
16
|
+
* @param componentNames
|
|
17
|
+
* @returns
|
|
18
|
+
*/
|
|
19
|
+
resolve(con: Connection): Promise<Type[Key]>;
|
|
20
|
+
private parseSourceFile;
|
|
21
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ComponentSet } from '@salesforce/source-deploy-retrieve';
|
|
2
|
+
import MetadataRegistryEntry, { retrieve } from './metadataRegistryEntry.js';
|
|
3
|
+
/**
|
|
4
|
+
* The entry is a type that only has one single instance on the org, such as
|
|
5
|
+
* a Setting. The component is typically retrieved by a more generic name and
|
|
6
|
+
* organized & cached by the explicit name.
|
|
7
|
+
*/
|
|
8
|
+
export default class SingletonMetadata extends MetadataRegistryEntry {
|
|
9
|
+
retrieveName;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
super(opts);
|
|
12
|
+
this.retrieveName = opts.retrieveName ?? String(this.rootNodeName);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolves component names, retrieves the metadata and returns
|
|
16
|
+
* as a strongly typed result.
|
|
17
|
+
*
|
|
18
|
+
* @param con
|
|
19
|
+
* @param componentNames
|
|
20
|
+
* @returns
|
|
21
|
+
*/
|
|
22
|
+
async resolve(con) {
|
|
23
|
+
const cmpSet = new ComponentSet([{ type: this.retrieveType, fullName: this.retrieveName }]);
|
|
24
|
+
const retrieveResult = await retrieve(cmpSet, con);
|
|
25
|
+
return this.parseSourceFile(retrieveResult.components);
|
|
26
|
+
}
|
|
27
|
+
parseSourceFile(componentSet) {
|
|
28
|
+
const cmps = componentSet.getSourceComponents({ type: this.retrieveType, fullName: this.retrieveName }).toArray();
|
|
29
|
+
if (cmps.length > 0 && cmps[0].xml) {
|
|
30
|
+
return this.parse(cmps[0].xml);
|
|
31
|
+
}
|
|
32
|
+
throw new Error('Failed to resolve settings for: ' + this.retrieveName);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=singletonMetadataType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"singletonMetadataType.js","sourceRoot":"","sources":["../../../../src/libs/core/mdapi/singletonMetadataType.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,qBAAqB,EAAE,EAA6B,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAExG;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,iBAAgD,SAAQ,qBAAgC;IACpG,YAAY,CAAS;IAC5B,YAAmB,IAA0C;QAC3D,KAAK,CAAC,IAAI,CAAC,CAAC;QACZ,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACrE,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,OAAO,CAAC,GAAe;QAClC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;QAC5F,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACzD,CAAC;IAEO,eAAe,CAAC,YAA0B;QAChD,MAAM,IAAI,GAAG,YAAY,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;QAClH,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACnC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;IAC1E,CAAC;CACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Messages } from '@salesforce/core';
|
|
2
|
-
import
|
|
2
|
+
import MDAPI from '../core/mdapi/mdapiRetriever.js';
|
|
3
3
|
import { RuleRegistries } from '../core/registries/types.js';
|
|
4
4
|
import { ProfilesRiskPreset } from '../core/policy-types.js';
|
|
5
5
|
import Policy, { getTotal } from './policy.js';
|
|
@@ -22,42 +22,35 @@ export default class ProfilePolicy extends Policy {
|
|
|
22
22
|
});
|
|
23
23
|
const successfullyResolved = {};
|
|
24
24
|
const ignoredEntities = {};
|
|
25
|
-
const profileQueryResults = Array();
|
|
26
25
|
const definitiveProfiles = this.config.profiles ?? {};
|
|
26
|
+
const classifiedProfiles = [];
|
|
27
27
|
Object.entries(definitiveProfiles).forEach(([profileName, profileDef]) => {
|
|
28
|
-
if (profileDef.preset
|
|
29
|
-
const qr = Promise.resolve(context.targetOrgConnection.tooling.query(`SELECT Name,Metadata FROM Profile WHERE Name = '${profileName}'`));
|
|
30
|
-
profileQueryResults.push(qr);
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
28
|
+
if (profileDef.preset === ProfilesRiskPreset.UNKNOWN) {
|
|
33
29
|
ignoredEntities[profileName] = {
|
|
34
30
|
name: profileName,
|
|
35
31
|
message: messages.getMessage('preset-unknown', ['Profile']),
|
|
36
32
|
};
|
|
37
33
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
queryResults.forEach((qr) => {
|
|
41
|
-
if (qr.records && qr.records.length > 0) {
|
|
42
|
-
const record = qr.records[0];
|
|
43
|
-
if (isNullish(record.Metadata)) {
|
|
44
|
-
ignoredEntities[record.Name] = {
|
|
45
|
-
name: record.Name,
|
|
46
|
-
message: messages.getMessage('profile-invalid-no-metadata'),
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
successfullyResolved[record.Name] = {
|
|
51
|
-
name: record.Name,
|
|
52
|
-
preset: definitiveProfiles[record.Name].preset,
|
|
53
|
-
metadata: record.Metadata,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
34
|
+
else {
|
|
35
|
+
classifiedProfiles.push(profileName);
|
|
56
36
|
}
|
|
57
37
|
});
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
38
|
+
const mdapi = new MDAPI(context.targetOrgConnection);
|
|
39
|
+
const resolvedProfiles = await mdapi.resolve('Profile', classifiedProfiles);
|
|
40
|
+
classifiedProfiles.forEach((profileName) => {
|
|
41
|
+
const resolvedProfile = resolvedProfiles[profileName];
|
|
42
|
+
if (!resolvedProfile) {
|
|
43
|
+
ignoredEntities[profileName] = {
|
|
44
|
+
name: profileName,
|
|
45
|
+
message: messages.getMessage('entity-not-found'),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
successfullyResolved[profileName] = {
|
|
50
|
+
name: profileName,
|
|
51
|
+
preset: definitiveProfiles[profileName].preset,
|
|
52
|
+
metadata: resolvedProfile,
|
|
53
|
+
};
|
|
61
54
|
}
|
|
62
55
|
});
|
|
63
56
|
const result = { resolvedEntities: successfullyResolved, ignoredEntities: Object.values(ignoredEntities) };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profilePolicy.js","sourceRoot":"","sources":["../../../src/libs/policies/profilePolicy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"profilePolicy.js","sourceRoot":"","sources":["../../../src/libs/policies/profilePolicy.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,12 +14,24 @@ Target org to export permissions, profiles, users, etc.
|
|
|
14
14
|
|
|
15
15
|
Directory where the audit config is initialised. If not set, the root directory will be used.
|
|
16
16
|
|
|
17
|
+
# flags.preset.summary
|
|
18
|
+
|
|
19
|
+
Select a preset to initialise permission classifications (risk levels).
|
|
20
|
+
|
|
21
|
+
# flags.preset.description
|
|
22
|
+
|
|
23
|
+
The selected preset is applied before any other default mechanisms (such as template configs). This means, values from a selected template override the preset. Consult the documentation to learn more about the rationale behind the default risk levels. The risk levels interact with the configured preset on profiles and permission sets and essentially control, if a permission is allowed in a certain profile / permission set.
|
|
24
|
+
|
|
17
25
|
# examples
|
|
18
26
|
|
|
19
27
|
- Initialise audit policies at the root directory
|
|
20
28
|
|
|
21
29
|
<%= config.bin %> <%= command.id %> -o MyTargetOrg
|
|
22
30
|
|
|
31
|
+
- Initialise audit config at custom directory with preset
|
|
32
|
+
|
|
33
|
+
<%= config.bin %> <%= command.id %> -o MyTargetOrg -d my_dir -p loose
|
|
34
|
+
|
|
23
35
|
# success.perm-classification-summary
|
|
24
36
|
|
|
25
37
|
Initialised %s permissions at %s.
|
|
@@ -2,9 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
Allows to modify all parts of the app, including security settings.
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# ModifyMetadata
|
|
6
6
|
|
|
7
|
-
Allows to
|
|
7
|
+
Allows to modify all parts of the app, including security settings.
|
|
8
|
+
|
|
9
|
+
# Packaging2
|
|
10
|
+
|
|
11
|
+
General permissions for 2nd generation packages.
|
|
12
|
+
|
|
13
|
+
# InstallPackaging
|
|
14
|
+
|
|
15
|
+
Install unlocked and managed packages.
|
|
16
|
+
|
|
17
|
+
# Packaging2PromoteVersion
|
|
18
|
+
|
|
19
|
+
Promote 2nd generation packages for distribution and install on production orgs.
|
|
20
|
+
|
|
21
|
+
# Packaging2Delete
|
|
22
|
+
|
|
23
|
+
Delete versions of 2nd generation packages.
|
|
8
24
|
|
|
9
25
|
# ViewSetup
|
|
10
26
|
|
|
@@ -14,6 +30,10 @@ Allows to browse setup and view sensitive configurations.
|
|
|
14
30
|
|
|
15
31
|
Bypass all sharing, making all sharing architecture obsolete.
|
|
16
32
|
|
|
33
|
+
# ModifyAllData
|
|
34
|
+
|
|
35
|
+
Bypass all sharing and layout permissions.
|
|
36
|
+
|
|
17
37
|
# AuthorApex
|
|
18
38
|
|
|
19
39
|
Apex can perform harmful actions, and deployed Apex runs in system mode.
|
|
@@ -33,3 +53,19 @@ Set up and reset the connected MFA for a user.
|
|
|
33
53
|
# CanApproveUninstalledApps
|
|
34
54
|
|
|
35
55
|
Allows to authorize new connected apps and therefore new integrations.
|
|
56
|
+
|
|
57
|
+
# UseAnyApiClient
|
|
58
|
+
|
|
59
|
+
Bypass all security settings and use deprecated login types.
|
|
60
|
+
|
|
61
|
+
# ViewClientSecret
|
|
62
|
+
|
|
63
|
+
Access and export secrets from connected apps.
|
|
64
|
+
|
|
65
|
+
# ExportReport
|
|
66
|
+
|
|
67
|
+
Reports allow to export classified or sensitive data.
|
|
68
|
+
|
|
69
|
+
# ManageRemoteAccess
|
|
70
|
+
|
|
71
|
+
Manage, create, edit, and delete connected applications.
|
package/oclif.manifest.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"args": {},
|
|
6
6
|
"description": "Exports permissions (standard and custom), permission sets, profiles, users, etc from the target org. All classifications are initialised with sane defaults that you can customize later.",
|
|
7
7
|
"examples": [
|
|
8
|
-
"Initialise audit policies at the root directory\n<%= config.bin %> <%= command.id %> -o MyTargetOrg"
|
|
8
|
+
"Initialise audit policies at the root directory\n<%= config.bin %> <%= command.id %> -o MyTargetOrg",
|
|
9
|
+
"Initialise audit config at custom directory with preset\n<%= config.bin %> <%= command.id %> -o MyTargetOrg -d my_dir -p loose"
|
|
9
10
|
],
|
|
10
11
|
"flags": {
|
|
11
12
|
"json": {
|
|
@@ -43,6 +44,21 @@
|
|
|
43
44
|
"multiple": false,
|
|
44
45
|
"type": "option"
|
|
45
46
|
},
|
|
47
|
+
"preset": {
|
|
48
|
+
"char": "p",
|
|
49
|
+
"description": "The selected preset is applied before any other default mechanisms (such as template configs). This means, values from a selected template override the preset. Consult the documentation to learn more about the rationale behind the default risk levels. The risk levels interact with the configured preset on profiles and permission sets and essentially control, if a permission is allowed in a certain profile / permission set.",
|
|
50
|
+
"name": "preset",
|
|
51
|
+
"summary": "Select a preset to initialise permission classifications (risk levels).",
|
|
52
|
+
"default": "strict",
|
|
53
|
+
"hasDynamicHelp": false,
|
|
54
|
+
"multiple": false,
|
|
55
|
+
"options": [
|
|
56
|
+
"strict",
|
|
57
|
+
"loose",
|
|
58
|
+
"none"
|
|
59
|
+
],
|
|
60
|
+
"type": "option"
|
|
61
|
+
},
|
|
46
62
|
"api-version": {
|
|
47
63
|
"description": "Override the api version used for api requests made by this command",
|
|
48
64
|
"name": "api-version",
|
|
@@ -157,5 +173,5 @@
|
|
|
157
173
|
]
|
|
158
174
|
}
|
|
159
175
|
},
|
|
160
|
-
"version": "0.
|
|
176
|
+
"version": "0.5.0"
|
|
161
177
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@j-schreiber/sf-cli-security-audit",
|
|
3
3
|
"description": "Salesforce CLI plugin to automate highly configurable security audits",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "https",
|
|
7
7
|
"url": "https://github.com/j-schreiber/js-sf-cli-security-audit"
|