@appland/scanner 1.59.2 → 1.62.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 +22 -0
- package/built/analyzer/recordSecrets.js +1 -1
- package/built/check.js +2 -0
- package/built/checkInstance.js +3 -0
- package/built/cli/appmapDirFromConfig.js +29 -0
- package/built/cli/ci/command.js +7 -6
- package/built/cli/handleWorkingDirectory.js +8 -0
- package/built/cli/scan/command.js +5 -2
- package/built/cli/scanArgs.js +5 -1
- package/built/cli/upload/command.js +16 -2
- package/built/ruleChecker.js +17 -7
- package/built/rules/circularDependency.js +2 -1
- package/built/rules/illegalPackageDependency.js +5 -2
- package/built/rules/insecureCompare.js +8 -2
- package/built/rules/jobNotCancelled.js +5 -8
- package/built/rules/lib/util.js +1 -27
- package/built/rules/nPlusOneQuery.js +1 -0
- package/built/rules/queryFromInvalidPackage.js +6 -3
- package/built/rules/secretInLog.js +27 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
# [@appland/scanner-v1.62.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.61.0...@appland/scanner-v1.62.0) (2022-07-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Support working directory -d arg ([2bd280f](https://github.com/applandinc/appmap-js/commit/2bd280fa2e6bb2d13c6bc1c578b1b78c3a62492a))
|
|
7
|
+
* upload command uses appmap_dir from config ([801b75b](https://github.com/applandinc/appmap-js/commit/801b75bf008b6188d4aacd143a1992149aafebd3))
|
|
8
|
+
|
|
9
|
+
# [@appland/scanner-v1.61.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.60.0...@appland/scanner-v1.61.0) (2022-07-11)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* Add participating events to each finding ([f3e8033](https://github.com/applandinc/appmap-js/commit/f3e80332833ec3305ef530d89b12763781a8c85b))
|
|
15
|
+
|
|
16
|
+
# [@appland/scanner-v1.60.0](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.59.2...@appland/scanner-v1.60.0) (2022-06-30)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* pass down impactDomain from Rule to Finding ([8755041](https://github.com/applandinc/appmap-js/commit/875504183a8517fec316b5f188d269de053ceef8))
|
|
22
|
+
|
|
1
23
|
# [@appland/scanner-v1.59.2](https://github.com/applandinc/appmap-js/compare/@appland/scanner-v1.59.1...@appland/scanner-v1.59.2) (2022-06-29)
|
|
2
24
|
|
|
3
25
|
|
package/built/check.js
CHANGED
|
@@ -14,6 +14,8 @@ class Check {
|
|
|
14
14
|
this.excludeScope = [];
|
|
15
15
|
this.includeEvent = [];
|
|
16
16
|
this.excludeEvent = [];
|
|
17
|
+
//TODO: Create Default value for impact domain
|
|
18
|
+
this.impactDomain = rule.impactDomain;
|
|
17
19
|
}
|
|
18
20
|
filterScope(event, appMapIndex) {
|
|
19
21
|
if (this.includeScope.length > 0 && !this.includeScope.every((fn) => fn(event, appMapIndex))) {
|
package/built/checkInstance.js
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.appmapDirFromConfig = void 0;
|
|
13
|
+
const fs_1 = require("fs");
|
|
14
|
+
const promises_1 = require("fs/promises");
|
|
15
|
+
const js_yaml_1 = require("js-yaml");
|
|
16
|
+
const util_1 = require("util");
|
|
17
|
+
function appmapDirFromConfig() {
|
|
18
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
19
|
+
const appMapConfigExists = yield (0, util_1.promisify)(fs_1.exists)('appmap.yml');
|
|
20
|
+
if (appMapConfigExists) {
|
|
21
|
+
const appMapConfigData = (0, js_yaml_1.load)((yield (0, promises_1.readFile)('appmap.yml')).toString());
|
|
22
|
+
if (appMapConfigData && typeof appMapConfigData === 'object') {
|
|
23
|
+
const configData = appMapConfigData;
|
|
24
|
+
return configData['appmap_dir'];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
exports.appmapDirFromConfig = appmapDirFromConfig;
|
package/built/cli/ci/command.js
CHANGED
|
@@ -18,6 +18,7 @@ const util_1 = require("util");
|
|
|
18
18
|
const configurationProvider_1 = require("../../configuration/configurationProvider");
|
|
19
19
|
const errors_1 = require("../../errors");
|
|
20
20
|
const util_2 = require("../../rules/lib/util");
|
|
21
|
+
const appmapDirFromConfig_1 = require("../appmapDirFromConfig");
|
|
21
22
|
const findings_1 = require("../../findings");
|
|
22
23
|
const findingsReport_1 = __importDefault(require("../../report/findingsReport"));
|
|
23
24
|
const summaryReport_1 = __importDefault(require("../../report/summaryReport"));
|
|
@@ -30,6 +31,7 @@ const updateCommitStatus_1 = __importDefault(require("../updateCommitStatus"));
|
|
|
30
31
|
const reportUploadURL_1 = __importDefault(require("../reportUploadURL"));
|
|
31
32
|
const fail_1 = __importDefault(require("../fail"));
|
|
32
33
|
const codeVersionArgs_1 = __importDefault(require("../codeVersionArgs"));
|
|
34
|
+
const handleWorkingDirectory_1 = require("../handleWorkingDirectory");
|
|
33
35
|
exports.default = {
|
|
34
36
|
command: 'ci',
|
|
35
37
|
describe: 'Scan AppMaps, report findings to AppMap Server, and update SCM status',
|
|
@@ -59,17 +61,16 @@ exports.default = {
|
|
|
59
61
|
handler(options) {
|
|
60
62
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61
63
|
let { appmapDir } = options;
|
|
62
|
-
const { config, verbose: isVerbose, fail: failOption, app: appIdArg, reportFile, upload: doUpload, updateCommitStatus: updateCommitStatusOption, mergeKey, commit, branch, environment, } = options;
|
|
64
|
+
const { config, verbose: isVerbose, fail: failOption, app: appIdArg, directory, reportFile, upload: doUpload, updateCommitStatus: updateCommitStatusOption, mergeKey, commit, branch, environment, } = options;
|
|
63
65
|
if (isVerbose) {
|
|
64
66
|
(0, util_2.verbose)(true);
|
|
65
67
|
}
|
|
68
|
+
(0, handleWorkingDirectory_1.handleWorkingDirectory)(directory);
|
|
66
69
|
if (!appmapDir) {
|
|
67
|
-
appmapDir = yield (0,
|
|
68
|
-
}
|
|
69
|
-
if (!appmapDir) {
|
|
70
|
-
appmapDir = yield (0, util_2.appmapDirFromConfig)();
|
|
71
|
-
throw new errors_1.ValidationError('--appmap-dir is required');
|
|
70
|
+
appmapDir = yield (0, appmapDirFromConfig_1.appmapDirFromConfig)();
|
|
72
71
|
}
|
|
72
|
+
if (!appmapDir)
|
|
73
|
+
throw new errors_1.ValidationError('appmapDir must be provided as a command option, or available in appmap.yml');
|
|
73
74
|
yield (0, validateFile_1.default)('directory', appmapDir);
|
|
74
75
|
const appId = yield (0, resolveAppId_1.default)(appIdArg, appmapDir);
|
|
75
76
|
const glob = (0, util_1.promisify)(glob_1.glob);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleWorkingDirectory = void 0;
|
|
4
|
+
function handleWorkingDirectory(directory) {
|
|
5
|
+
if (directory)
|
|
6
|
+
process.chdir(directory);
|
|
7
|
+
}
|
|
8
|
+
exports.handleWorkingDirectory = handleWorkingDirectory;
|
|
@@ -14,12 +14,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const errors_1 = require("../../errors");
|
|
16
16
|
const util_1 = require("../../rules/lib/util");
|
|
17
|
+
const appmapDirFromConfig_1 = require("../appmapDirFromConfig");
|
|
17
18
|
const validateFile_1 = __importDefault(require("../validateFile"));
|
|
18
19
|
const scanArgs_1 = __importDefault(require("../scanArgs"));
|
|
19
20
|
const resolveAppId_1 = __importDefault(require("../resolveAppId"));
|
|
20
21
|
const singleScan_1 = __importDefault(require("./singleScan"));
|
|
21
22
|
const watchScan_1 = __importDefault(require("./watchScan"));
|
|
22
23
|
const configurationProvider_1 = require("../../configuration/configurationProvider");
|
|
24
|
+
const handleWorkingDirectory_1 = require("../handleWorkingDirectory");
|
|
23
25
|
exports.default = {
|
|
24
26
|
command: 'scan',
|
|
25
27
|
describe: 'Scan AppMaps for code behavior findings',
|
|
@@ -48,10 +50,11 @@ exports.default = {
|
|
|
48
50
|
handler(options) {
|
|
49
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
52
|
let { appmapDir } = options;
|
|
51
|
-
const { appmapFile, config, verbose: isVerbose, all: reportAllFindings, watch, app: appIdArg, apiKey, ide, reportFile, } = options;
|
|
53
|
+
const { appmapFile, config, directory, verbose: isVerbose, all: reportAllFindings, watch, app: appIdArg, apiKey, ide, reportFile, } = options;
|
|
52
54
|
if (isVerbose) {
|
|
53
55
|
(0, util_1.verbose)(true);
|
|
54
56
|
}
|
|
57
|
+
(0, handleWorkingDirectory_1.handleWorkingDirectory)(directory);
|
|
55
58
|
if (apiKey) {
|
|
56
59
|
process.env.APPLAND_API_KEY = apiKey;
|
|
57
60
|
}
|
|
@@ -65,7 +68,7 @@ exports.default = {
|
|
|
65
68
|
throw new errors_1.ValidationError(`Don't use --app with --watch, because in watch mode all findings are reported`);
|
|
66
69
|
}
|
|
67
70
|
if (!appmapFile && !appmapDir) {
|
|
68
|
-
appmapDir = (yield (0,
|
|
71
|
+
appmapDir = (yield (0, appmapDirFromConfig_1.appmapDirFromConfig)()) || '.';
|
|
69
72
|
}
|
|
70
73
|
if (appmapDir)
|
|
71
74
|
yield (0, validateFile_1.default)('directory', appmapDir);
|
package/built/cli/scanArgs.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
function default_1(args) {
|
|
4
|
+
args.option('directory', {
|
|
5
|
+
describe: 'program working directory',
|
|
6
|
+
type: 'string',
|
|
7
|
+
alias: 'd',
|
|
8
|
+
});
|
|
4
9
|
args.option('appmap-dir', {
|
|
5
10
|
describe: 'directory to recursively inspect for AppMaps',
|
|
6
|
-
alias: 'd',
|
|
7
11
|
});
|
|
8
12
|
args.option('config', {
|
|
9
13
|
describe: 'path to assertions config file (TypeScript or YAML, check docs for configuration format)',
|
|
@@ -14,19 +14,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
const promises_1 = require("fs/promises");
|
|
16
16
|
const util_1 = require("../../rules/lib/util");
|
|
17
|
+
const appmapDirFromConfig_1 = require("../appmapDirFromConfig");
|
|
17
18
|
const validateFile_1 = __importDefault(require("../validateFile"));
|
|
18
19
|
const resolveAppId_1 = __importDefault(require("../resolveAppId"));
|
|
19
20
|
const reportUploadURL_1 = __importDefault(require("../reportUploadURL"));
|
|
20
21
|
const upload_1 = __importDefault(require("../upload"));
|
|
21
22
|
const codeVersionArgs_1 = __importDefault(require("../codeVersionArgs"));
|
|
23
|
+
const errors_1 = require("../../errors");
|
|
24
|
+
const handleWorkingDirectory_1 = require("../handleWorkingDirectory");
|
|
22
25
|
exports.default = {
|
|
23
26
|
command: 'upload',
|
|
24
27
|
describe: 'Upload Findings to the AppMap Server',
|
|
25
28
|
builder(args) {
|
|
26
29
|
(0, codeVersionArgs_1.default)(args);
|
|
30
|
+
args.option('directory', {
|
|
31
|
+
describe: 'program working directory',
|
|
32
|
+
type: 'string',
|
|
33
|
+
alias: 'd',
|
|
34
|
+
});
|
|
27
35
|
args.option('appmap-dir', {
|
|
28
36
|
describe: 'base directory of AppMaps',
|
|
29
|
-
alias: 'd',
|
|
30
37
|
});
|
|
31
38
|
args.option('report-file', {
|
|
32
39
|
describe: 'file containing the findings report',
|
|
@@ -42,10 +49,17 @@ exports.default = {
|
|
|
42
49
|
},
|
|
43
50
|
handler(options) {
|
|
44
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
45
|
-
|
|
52
|
+
let { appmapDir } = options;
|
|
53
|
+
const { verbose: isVerbose, directory, reportFile, app: appIdArg, mergeKey, branch, commit, environment, } = options;
|
|
46
54
|
if (isVerbose) {
|
|
47
55
|
(0, util_1.verbose)(true);
|
|
48
56
|
}
|
|
57
|
+
(0, handleWorkingDirectory_1.handleWorkingDirectory)(directory);
|
|
58
|
+
if (!appmapDir) {
|
|
59
|
+
appmapDir = yield (0, appmapDirFromConfig_1.appmapDirFromConfig)();
|
|
60
|
+
}
|
|
61
|
+
if (!appmapDir)
|
|
62
|
+
throw new errors_1.ValidationError('appmapDir must be provided as a command option, or available in appmap.yml');
|
|
49
63
|
yield (0, validateFile_1.default)('directory', appmapDir);
|
|
50
64
|
const appId = yield (0, resolveAppId_1.default)(appIdArg, appmapDir);
|
|
51
65
|
const scanResults = JSON.parse((yield (0, promises_1.readFile)(reportFile)).toString());
|
package/built/ruleChecker.js
CHANGED
|
@@ -94,8 +94,9 @@ class RuleChecker {
|
|
|
94
94
|
if (!checkInstance.filterEvent(event, appMapIndex)) {
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
-
const buildFinding = (matchEvent, message, groupMessage, occurranceCount,
|
|
98
|
-
// matchEvent will be added to additionalEvents
|
|
97
|
+
const buildFinding = (matchEvent, participatingEvents, message, groupMessage, occurranceCount,
|
|
98
|
+
// matchEvent will be added to additionalEvents and participatingEvents.values
|
|
99
|
+
// to create the relatedEvents array
|
|
99
100
|
additionalEvents) => {
|
|
100
101
|
const findingEvent = matchEvent || event;
|
|
101
102
|
// Fixes:
|
|
@@ -118,12 +119,19 @@ class RuleChecker {
|
|
|
118
119
|
return;
|
|
119
120
|
}
|
|
120
121
|
uniqueEvents.add(event.id);
|
|
121
|
-
relatedEvents.push(event);
|
|
122
|
+
relatedEvents.push((0, eventUtil_1.cloneEvent)(event));
|
|
122
123
|
});
|
|
123
124
|
// Update event hash with unique hashes of related events
|
|
124
125
|
new Set(relatedEvents.map((e) => e.hash)).forEach((eventHash) => {
|
|
125
126
|
hash.update(eventHash);
|
|
126
127
|
});
|
|
128
|
+
Object.values(participatingEvents).forEach((event) => {
|
|
129
|
+
if (uniqueEvents.has(event.id)) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
uniqueEvents.add(event.id);
|
|
133
|
+
relatedEvents.push((0, eventUtil_1.cloneEvent)(event));
|
|
134
|
+
});
|
|
127
135
|
return {
|
|
128
136
|
appMapFile,
|
|
129
137
|
checkId: checkInstance.checkId,
|
|
@@ -137,6 +145,8 @@ class RuleChecker {
|
|
|
137
145
|
groupMessage,
|
|
138
146
|
occurranceCount,
|
|
139
147
|
relatedEvents: relatedEvents.sort((event) => event.id),
|
|
148
|
+
impactDomain: checkInstance.checkImpactDomain,
|
|
149
|
+
participatingEvents: Object.fromEntries(Object.entries(participatingEvents).map(([k, v]) => [k, (0, eventUtil_1.cloneEvent)(v)])),
|
|
140
150
|
};
|
|
141
151
|
};
|
|
142
152
|
const matchResult = yield checkInstance.ruleLogic.matcher(event, appMapIndex, checkInstance.filterEvent.bind(checkInstance));
|
|
@@ -145,21 +155,21 @@ class RuleChecker {
|
|
|
145
155
|
let finding;
|
|
146
156
|
if (checkInstance.ruleLogic.message) {
|
|
147
157
|
const message = checkInstance.ruleLogic.message(scope, event);
|
|
148
|
-
finding = buildFinding(event, message);
|
|
158
|
+
finding = buildFinding(event, {}, message);
|
|
149
159
|
}
|
|
150
160
|
else {
|
|
151
|
-
finding = buildFinding(event);
|
|
161
|
+
finding = buildFinding(event, {});
|
|
152
162
|
}
|
|
153
163
|
findings.push(finding);
|
|
154
164
|
}
|
|
155
165
|
else if (typeof matchResult === 'string') {
|
|
156
|
-
const finding = buildFinding(event, matchResult);
|
|
166
|
+
const finding = buildFinding(event, {}, matchResult);
|
|
157
167
|
finding.message = matchResult;
|
|
158
168
|
findings.push(finding);
|
|
159
169
|
}
|
|
160
170
|
else if (matchResult) {
|
|
161
171
|
matchResult.forEach((mr) => {
|
|
162
|
-
const finding = buildFinding(mr.event, mr.message, mr.groupMessage, mr.occurranceCount, mr.relatedEvents);
|
|
172
|
+
const finding = buildFinding(mr.event, mr.participatingEvents || {}, mr.message, mr.groupMessage, mr.occurranceCount, mr.relatedEvents);
|
|
163
173
|
findings.push(finding);
|
|
164
174
|
});
|
|
165
175
|
}
|
|
@@ -173,13 +173,14 @@ function build(options) {
|
|
|
173
173
|
.map((cycle) => searchForCycle(cycle, ignoredPackages))
|
|
174
174
|
.filter((path) => path)
|
|
175
175
|
.map((path) => {
|
|
176
|
+
path = path;
|
|
176
177
|
return {
|
|
177
178
|
event: path[0],
|
|
178
179
|
message: [
|
|
179
180
|
'Cycle in package dependency graph',
|
|
180
181
|
path.map((event) => event.codeObject.packageOf).join(' -> '),
|
|
181
182
|
].join(': '),
|
|
182
|
-
|
|
183
|
+
participatingEvents: Object.fromEntries(path.map((event, index) => [`path[${index}]`, event])),
|
|
183
184
|
};
|
|
184
185
|
});
|
|
185
186
|
}
|
|
@@ -19,18 +19,21 @@ function build(options) {
|
|
|
19
19
|
return !!e.parent && !!e.parent.codeObject.packageOf && calleePattern(e.codeObject.packageOf);
|
|
20
20
|
}
|
|
21
21
|
function matcher(e) {
|
|
22
|
+
const parent = e.parent;
|
|
23
|
+
if (!parent)
|
|
24
|
+
return;
|
|
22
25
|
const packageNamesStr = options.callerPackages
|
|
23
26
|
.map((config) => config.equal || config.include || config.match)
|
|
24
27
|
.map(String)
|
|
25
28
|
.join(' or ');
|
|
26
|
-
const parentPackage =
|
|
29
|
+
const parentPackage = parent.codeObject.packageOf;
|
|
27
30
|
if (!(e.codeObject.packageOf === parentPackage ||
|
|
28
31
|
callerPatterns.some((pattern) => pattern(parentPackage)))) {
|
|
29
32
|
return [
|
|
30
33
|
{
|
|
31
34
|
event: e,
|
|
32
35
|
message: `Code object ${e.codeObject.id} was invoked from ${parentPackage}, not from ${packageNamesStr}`,
|
|
33
|
-
|
|
36
|
+
participatingEvents: { parent },
|
|
34
37
|
},
|
|
35
38
|
];
|
|
36
39
|
}
|
|
@@ -8,7 +8,8 @@ const recordSecrets_1 = __importDefault(require("../analyzer/recordSecrets"));
|
|
|
8
8
|
const secretsRegexes_1 = require("../analyzer/secretsRegexes");
|
|
9
9
|
const parseRuleDescription_1 = __importDefault(require("./lib/parseRuleDescription"));
|
|
10
10
|
const BCRYPT_REGEXP = /^[$]2[abxy]?[$](?:0[4-9]|[12][0-9]|3[01])[$][./0-9a-zA-Z]{53}$/;
|
|
11
|
-
const secrets =
|
|
11
|
+
const secrets = [];
|
|
12
|
+
const secretStrings = new Set();
|
|
12
13
|
function stringEquals(e) {
|
|
13
14
|
if (!e.parameters || !e.receiver || e.parameters.length !== 1) {
|
|
14
15
|
return false;
|
|
@@ -18,7 +19,7 @@ function stringEquals(e) {
|
|
|
18
19
|
return BCRYPT_REGEXP.test(str);
|
|
19
20
|
}
|
|
20
21
|
function isSecret(str) {
|
|
21
|
-
return
|
|
22
|
+
return secretStrings.has(str) || (0, secretsRegexes_1.looksSecret)(str);
|
|
22
23
|
}
|
|
23
24
|
// BCrypted strings are safe to compare using equals()
|
|
24
25
|
return args.some(isSecret) && !args.some(isBcrypt);
|
|
@@ -26,7 +27,12 @@ function stringEquals(e) {
|
|
|
26
27
|
function build() {
|
|
27
28
|
function matcher(e) {
|
|
28
29
|
if (e.codeObject.labels.has(Secret)) {
|
|
30
|
+
const numSecrets = secrets.length;
|
|
29
31
|
(0, recordSecrets_1.default)(secrets, e);
|
|
32
|
+
for (let index = numSecrets; index < secrets.length; index++) {
|
|
33
|
+
const secret = secrets[index];
|
|
34
|
+
secretStrings.add(secret.value);
|
|
35
|
+
}
|
|
30
36
|
}
|
|
31
37
|
if (e.codeObject.labels.has(StringEquals)) {
|
|
32
38
|
return stringEquals(e);
|
|
@@ -18,14 +18,11 @@ function build() {
|
|
|
18
18
|
const missing = creationEvents.length - cancellationEvents.length;
|
|
19
19
|
if (missing === 0)
|
|
20
20
|
return;
|
|
21
|
-
|
|
22
|
-
event:
|
|
23
|
-
message:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
relatedEvents: [...creationEvents, ...cancellationEvents],
|
|
27
|
-
};
|
|
28
|
-
return [result];
|
|
21
|
+
return creationEvents.map((jobCreationEvent) => ({
|
|
22
|
+
event: jobCreationEvent,
|
|
23
|
+
message: `Job created by ${jobCreationEvent.codeObject.prettyName} was not cancelled when the enclosing transaction rolled back`,
|
|
24
|
+
participatingEvents: { beginTransaction: event },
|
|
25
|
+
}));
|
|
29
26
|
}
|
|
30
27
|
return {
|
|
31
28
|
matcher,
|
package/built/rules/lib/util.js
CHANGED
|
@@ -1,33 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.verbose = exports.toRegExpArray = exports.responseContentType = exports.toRegExp = exports.providesAuthentication = exports.pluralize = exports.dasherize = exports.camelize = exports.parseValue = exports.isRoot = exports.ideLink = exports.isTruthy = exports.isFalsey = exports.emptyValue = exports.capitalize = exports.appMapDir =
|
|
13
|
-
const fs_1 = require("fs");
|
|
14
|
-
const promises_1 = require("fs/promises");
|
|
15
|
-
const js_yaml_1 = require("js-yaml");
|
|
3
|
+
exports.verbose = exports.toRegExpArray = exports.responseContentType = exports.toRegExp = exports.providesAuthentication = exports.pluralize = exports.dasherize = exports.camelize = exports.parseValue = exports.isRoot = exports.ideLink = exports.isTruthy = exports.isFalsey = exports.emptyValue = exports.capitalize = exports.appMapDir = void 0;
|
|
16
4
|
const path_1 = require("path");
|
|
17
|
-
const util_1 = require("util");
|
|
18
|
-
function appmapDirFromConfig() {
|
|
19
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
-
const appMapConfigExists = yield (0, util_1.promisify)(fs_1.exists)('appmap.yml');
|
|
21
|
-
if (appMapConfigExists) {
|
|
22
|
-
const appMapConfigData = (0, js_yaml_1.load)((yield (0, promises_1.readFile)('appmap.yml')).toString());
|
|
23
|
-
if (appMapConfigData && typeof appMapConfigData === 'object') {
|
|
24
|
-
const configData = appMapConfigData;
|
|
25
|
-
return configData['appmap_dir'];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
exports.appmapDirFromConfig = appmapDirFromConfig;
|
|
31
5
|
let isVerbose = false;
|
|
32
6
|
function verbose(v = null) {
|
|
33
7
|
if (v === true || v === false) {
|
|
@@ -18,12 +18,15 @@ function build(options) {
|
|
|
18
18
|
const allowedPackages = (0, matchPattern_1.buildFilters)(options.allowedPackages);
|
|
19
19
|
const allowedQueries = (0, matchPattern_1.buildFilters)(options.allowedQueries);
|
|
20
20
|
function matcher(e) {
|
|
21
|
-
if (!
|
|
21
|
+
if (!e.parent)
|
|
22
|
+
return;
|
|
23
|
+
const parent = e.parent;
|
|
24
|
+
if (!allowedPackages.some((filter) => filter(parent.codeObject.packageOf))) {
|
|
22
25
|
return [
|
|
23
26
|
{
|
|
24
27
|
event: e,
|
|
25
|
-
message: `${e.codeObject.id} is invoked from illegal package ${
|
|
26
|
-
|
|
28
|
+
message: `${e.codeObject.id} is invoked from illegal package ${parent.codeObject.packageOf}`,
|
|
29
|
+
participatingEvents: { parent: parent },
|
|
27
30
|
},
|
|
28
31
|
];
|
|
29
32
|
}
|
|
@@ -32,12 +32,19 @@ const recordSecrets_1 = __importDefault(require("../analyzer/recordSecrets"));
|
|
|
32
32
|
const url_1 = require("url");
|
|
33
33
|
const parseRuleDescription_1 = __importDefault(require("./lib/parseRuleDescription"));
|
|
34
34
|
class Match {
|
|
35
|
-
constructor(pattern, value) {
|
|
35
|
+
constructor(pattern, value, generatorEvent) {
|
|
36
36
|
this.pattern = pattern;
|
|
37
37
|
this.value = value;
|
|
38
|
+
this.generatorEvent = generatorEvent;
|
|
39
|
+
}
|
|
40
|
+
static fromPattern(pattern, value) {
|
|
41
|
+
return new Match(pattern, value);
|
|
42
|
+
}
|
|
43
|
+
static fromSecret(secret, value) {
|
|
44
|
+
return new Match(secret.value, value, secret.generatorEvent);
|
|
38
45
|
}
|
|
39
46
|
}
|
|
40
|
-
const secrets =
|
|
47
|
+
const secrets = [];
|
|
41
48
|
const findInLog = (event) => {
|
|
42
49
|
if (!event.parameters)
|
|
43
50
|
return;
|
|
@@ -45,24 +52,32 @@ const findInLog = (event) => {
|
|
|
45
52
|
for (const { value } of event.parameters) {
|
|
46
53
|
if ((0, util_1.emptyValue)(value))
|
|
47
54
|
continue;
|
|
48
|
-
const patterns = [];
|
|
49
55
|
if ((0, secretsRegexes_1.looksSecret)(value)) {
|
|
50
56
|
// Only look for the exact matching regexes if it matches the catchall regex
|
|
51
|
-
|
|
57
|
+
matches.push(...Object.values(secretsRegexes_1.default)
|
|
52
58
|
.flat()
|
|
53
|
-
.filter((re) => re.test(value))
|
|
59
|
+
.filter((re) => re.test(value))
|
|
60
|
+
.map((re) => Match.fromPattern(re, value)));
|
|
54
61
|
}
|
|
55
62
|
for (const secret of secrets) {
|
|
56
|
-
if (value.includes(secret))
|
|
57
|
-
|
|
63
|
+
if (value.includes(secret.value)) {
|
|
64
|
+
matches.push(Match.fromSecret(secret, value));
|
|
65
|
+
}
|
|
58
66
|
}
|
|
59
|
-
matches.push(...patterns.map((pattern) => new Match(pattern, value)));
|
|
60
67
|
}
|
|
61
68
|
if (matches.length > 0) {
|
|
62
|
-
return matches.map((match) =>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
return matches.map((match) => {
|
|
70
|
+
const { pattern, value } = match;
|
|
71
|
+
const participatingEvents = { logEvent: event };
|
|
72
|
+
if (match.generatorEvent) {
|
|
73
|
+
participatingEvents.generatorEvent = match.generatorEvent;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
event,
|
|
77
|
+
message: `Log message contains secret ${match.generatorEvent ? match.generatorEvent.codeObject.prettyName || 'data' : 'data'} "${pattern}": ${value}`,
|
|
78
|
+
participatingEvents,
|
|
79
|
+
};
|
|
80
|
+
});
|
|
66
81
|
}
|
|
67
82
|
};
|
|
68
83
|
function build() {
|