@appland/scanner 1.78.0 → 1.80.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 +19 -0
- package/built/cli/scan/watchScan.js +10 -3
- package/built/cli/upload.js +1 -13
- package/built/integration/github/commitStatus.js +6 -3
- package/built/lastGitOrFSModifiedDate.js +87 -0
- package/built/ruleChecker.js +98 -11
- package/built/rules/lib/util.js +14 -1
- package/package.json +9 -7
- package/src/types.d.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# [@appland/scanner-v1.80.0](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.79.0...@appland/scanner-v1.80.0) (2023-07-19)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Make sure to not process the same appmap multiple times ([da0a0d8](https://github.com/getappmap/appmap-js/commit/da0a0d8826844b4bd92bb671a3ea1b74a5563cb1))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* upgrade @appland/models to 2.6.3 ([6e31f9c](https://github.com/getappmap/appmap-js/commit/6e31f9cc179ac0edfcde2861b937cd104ed4c687))
|
|
12
|
+
|
|
13
|
+
# [@appland/scanner-v1.79.0](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.78.0...@appland/scanner-v1.79.0) (2023-06-23)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* Modified dates on Finding ([b67d766](https://github.com/getappmap/appmap-js/commit/b67d766722f7d9101f295c7e5fddad5b83e9e032))
|
|
19
|
+
|
|
1
20
|
# [@appland/scanner-v1.78.0](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.77.2...@appland/scanner-v1.78.0) (2023-06-02)
|
|
2
21
|
|
|
3
22
|
|
|
@@ -49,6 +49,8 @@ const telemetry_1 = __importDefault(require("../../telemetry"));
|
|
|
49
49
|
const events_1 = __importDefault(require("events"));
|
|
50
50
|
const watchScanTelemetry_1 = require("./watchScanTelemetry");
|
|
51
51
|
const isAncestorPath_1 = __importDefault(require("../../util/isAncestorPath"));
|
|
52
|
+
const util_1 = require("util");
|
|
53
|
+
const debug = (0, util_1.debuglog)('scanner:watch');
|
|
52
54
|
function isDir(targetPath) {
|
|
53
55
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
56
|
try {
|
|
@@ -76,6 +78,7 @@ class Watcher {
|
|
|
76
78
|
// do not remove callbackify, apparently on windows
|
|
77
79
|
// passing plain async function doesn't work (?)
|
|
78
80
|
this.queue = (0, async_1.queue)((0, node_util_1.callbackify)(this.scan.bind(this)), 2);
|
|
81
|
+
this.processing = new Set();
|
|
79
82
|
watchScanTelemetry_1.WatchScanTelemetry.watch(this.scanEventEmitter, options.appmapDir);
|
|
80
83
|
this.queue.error((error, task) => console.warn(`Problem processing ${task}:\n`, error));
|
|
81
84
|
}
|
|
@@ -165,8 +168,9 @@ class Watcher {
|
|
|
165
168
|
});
|
|
166
169
|
}
|
|
167
170
|
enqueue(mtimePath) {
|
|
168
|
-
if (
|
|
171
|
+
if (this.processing.has(mtimePath))
|
|
169
172
|
return;
|
|
173
|
+
this.processing.add(mtimePath);
|
|
170
174
|
this.queue.push(mtimePath);
|
|
171
175
|
}
|
|
172
176
|
scan(mtimePath) {
|
|
@@ -177,9 +181,11 @@ class Watcher {
|
|
|
177
181
|
const [appmapStats, reportStats] = yield Promise.all([appmapFile, reportFile].map((f) => (0, promises_1.stat)(f).catch(() => null)));
|
|
178
182
|
if (!appmapStats)
|
|
179
183
|
return;
|
|
184
|
+
const cut = (str) => str.substring(str.length - 8);
|
|
185
|
+
debug('%s: %s, findings: %s, config: %s', appmapFile, cut(appmapStats.mtimeMs.toFixed(3)), reportStats && cut(reportStats.mtimeMs.toFixed(3)), cut(this.config.timestampMs.toFixed(3)));
|
|
180
186
|
if (reportStats &&
|
|
181
|
-
reportStats.mtimeMs > appmapStats.mtimeMs &&
|
|
182
|
-
reportStats.mtimeMs > this.config.timestampMs)
|
|
187
|
+
reportStats.mtimeMs > appmapStats.mtimeMs - 1000 &&
|
|
188
|
+
reportStats.mtimeMs > this.config.timestampMs - 1000)
|
|
183
189
|
return; // report is up to date
|
|
184
190
|
const startTime = Date.now();
|
|
185
191
|
const scanner = yield (0, scanner_1.default)(true, this.config, [appmapFile]);
|
|
@@ -188,6 +194,7 @@ class Watcher {
|
|
|
188
194
|
this.scanEventEmitter.emit('scan', { scanResults: rawScanResults, elapsed });
|
|
189
195
|
// Always report the raw data
|
|
190
196
|
yield (0, promises_1.writeFile)(reportFile, (0, formatReport_1.formatReport)(rawScanResults));
|
|
197
|
+
this.processing.delete(mtimePath);
|
|
191
198
|
});
|
|
192
199
|
}
|
|
193
200
|
reloadConfig() {
|
package/built/cli/upload.js
CHANGED
|
@@ -15,20 +15,8 @@ const src_1 = require("@appland/client/dist/src");
|
|
|
15
15
|
const util_1 = require("../rules/lib/util");
|
|
16
16
|
const create_1 = require("../integration/appland/scannerJob/create");
|
|
17
17
|
const vars_1 = require("../integration/vars");
|
|
18
|
-
const promises_2 = require("fs/promises");
|
|
19
18
|
const path_1 = require("path");
|
|
20
19
|
const pruneAppMap_1 = require("./upload/pruneAppMap");
|
|
21
|
-
function fileExists(file) {
|
|
22
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
23
|
-
try {
|
|
24
|
-
yield (0, promises_2.stat)(file);
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
catch (e) {
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
20
|
function create(scanResults, appId, appMapDir, mergeKey, mapsetOptions = {}, retryOptions = {}) {
|
|
33
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
34
22
|
if ((0, util_1.verbose)())
|
|
@@ -47,7 +35,7 @@ function create(scanResults, appId, appMapDir, mergeKey, mapsetOptions = {}, ret
|
|
|
47
35
|
if ((0, util_1.verbose)())
|
|
48
36
|
console.log(`Uploading AppMap ${filePath}`);
|
|
49
37
|
const filePaths = [filePath, (0, path_1.join)(appMapDir, filePath)];
|
|
50
|
-
const filePathsExist = yield Promise.all(filePaths.map(fileExists));
|
|
38
|
+
const filePathsExist = yield Promise.all(filePaths.map(util_1.fileExists));
|
|
51
39
|
const fullPath = filePaths.find((_, fileIndex) => filePathsExist[fileIndex]);
|
|
52
40
|
if (!fullPath)
|
|
53
41
|
throw new Error(`File ${filePath} not found`);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const octokit_1 = require("octokit");
|
|
3
4
|
const vars_1 = require("../vars");
|
|
4
5
|
function postCommitStatus(state, description) {
|
|
5
6
|
(0, vars_1.validateToken)();
|
|
@@ -7,9 +8,11 @@ function postCommitStatus(state, description) {
|
|
|
7
8
|
(0, vars_1.validateOwner)();
|
|
8
9
|
(0, vars_1.validateSha)();
|
|
9
10
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const octo = new octokit_1.Octokit({ auth: (0, vars_1.token)() });
|
|
12
|
+
return octo.rest.repos.createCommitStatus({
|
|
13
|
+
owner: (0, vars_1.owner)(),
|
|
14
|
+
repo: (0, vars_1.repo)(),
|
|
15
|
+
sha: (0, vars_1.sha)(),
|
|
13
16
|
state: state,
|
|
14
17
|
context: 'appland/scanner',
|
|
15
18
|
description: description,
|
|
@@ -0,0 +1,87 @@
|
|
|
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.fileModifiedDate = exports.gitModifiedDate = exports.gitExists = exports.isCached = exports.resetCache = void 0;
|
|
13
|
+
const console_1 = require("console");
|
|
14
|
+
const util_1 = require("./rules/lib/util");
|
|
15
|
+
const child_process_1 = require("child_process");
|
|
16
|
+
const promises_1 = require("fs/promises");
|
|
17
|
+
const FileModifiedDate = new Map();
|
|
18
|
+
let GitExists;
|
|
19
|
+
function resetCache() {
|
|
20
|
+
FileModifiedDate.clear();
|
|
21
|
+
}
|
|
22
|
+
exports.resetCache = resetCache;
|
|
23
|
+
function isCached(file) {
|
|
24
|
+
return FileModifiedDate.has(file);
|
|
25
|
+
}
|
|
26
|
+
exports.isCached = isCached;
|
|
27
|
+
function detectGitExists() {
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
(0, child_process_1.exec)('git --version', (err) => {
|
|
30
|
+
if (err && err.code && err.code > 0)
|
|
31
|
+
resolve(false);
|
|
32
|
+
resolve(true);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function gitExists() {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
if (GitExists === undefined) {
|
|
39
|
+
GitExists = yield detectGitExists();
|
|
40
|
+
}
|
|
41
|
+
return GitExists;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
exports.gitExists = gitExists;
|
|
45
|
+
function gitModifiedDate(file) {
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
(0, child_process_1.exec)(`git log -n 1 --pretty=format:%cI ${file}`, (err, stdout) => {
|
|
48
|
+
if (err && err.code && err.code > 0)
|
|
49
|
+
resolve(undefined);
|
|
50
|
+
if (stdout.trim() === '')
|
|
51
|
+
resolve(undefined);
|
|
52
|
+
resolve(new Date(stdout));
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
exports.gitModifiedDate = gitModifiedDate;
|
|
57
|
+
function fileModifiedDate(file) {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
try {
|
|
60
|
+
const stats = yield (0, promises_1.stat)(file);
|
|
61
|
+
return stats.mtime;
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
(0, console_1.warn)(e);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
exports.fileModifiedDate = fileModifiedDate;
|
|
69
|
+
function lastGitOrFSModifiedDate(file) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
let result = FileModifiedDate.get(file);
|
|
72
|
+
if (result) {
|
|
73
|
+
if ((0, util_1.verbose)())
|
|
74
|
+
(0, console_1.debug)(`Using cached modified date for ${file}`);
|
|
75
|
+
return result.getTime() === 0 ? undefined : result;
|
|
76
|
+
}
|
|
77
|
+
if ((0, util_1.verbose)())
|
|
78
|
+
(0, console_1.debug)(`Computing modified date for ${file}`);
|
|
79
|
+
if (yield gitExists())
|
|
80
|
+
result = yield gitModifiedDate(file);
|
|
81
|
+
if (!result)
|
|
82
|
+
result = yield fileModifiedDate(file);
|
|
83
|
+
FileModifiedDate.set(file, result || new Date(0));
|
|
84
|
+
return result;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
exports.default = lastGitOrFSModifiedDate;
|
package/built/ruleChecker.js
CHANGED
|
@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const models_1 = require("@appland/models");
|
|
15
16
|
const errors_1 = require("./errors");
|
|
16
17
|
const util_1 = require("./rules/lib/util");
|
|
17
18
|
const rootScope_1 = __importDefault(require("./scope/rootScope"));
|
|
@@ -23,6 +24,18 @@ const checkInstance_1 = __importDefault(require("./checkInstance"));
|
|
|
23
24
|
const eventUtil_1 = require("./eventUtil");
|
|
24
25
|
const hashV1_1 = __importDefault(require("./algorithms/hash/hashV1"));
|
|
25
26
|
const hashV2_1 = __importDefault(require("./algorithms/hash/hashV2"));
|
|
27
|
+
const path_1 = require("path");
|
|
28
|
+
const lastGitOrFSModifiedDate_1 = __importDefault(require("./lastGitOrFSModifiedDate"));
|
|
29
|
+
const console_1 = require("console");
|
|
30
|
+
const assert_1 = __importDefault(require("assert"));
|
|
31
|
+
function locationToFilePath(location) {
|
|
32
|
+
const [file] = location.split(':');
|
|
33
|
+
let filePath = file;
|
|
34
|
+
if ((0, path_1.isAbsolute)(file) && file.startsWith(process.cwd())) {
|
|
35
|
+
filePath = file.slice(process.cwd().length + 1);
|
|
36
|
+
}
|
|
37
|
+
return filePath;
|
|
38
|
+
}
|
|
26
39
|
class RuleChecker {
|
|
27
40
|
constructor(progress) {
|
|
28
41
|
this.progress = progress;
|
|
@@ -93,10 +106,44 @@ class RuleChecker {
|
|
|
93
106
|
if (!checkInstance.filterEvent(event, appMapIndex)) {
|
|
94
107
|
return;
|
|
95
108
|
}
|
|
109
|
+
let appmapConfigDir;
|
|
110
|
+
{
|
|
111
|
+
let searchDir = (0, path_1.dirname)((0, path_1.resolve)(appMapFileName));
|
|
112
|
+
while (!appmapConfigDir) {
|
|
113
|
+
if (yield (0, util_1.fileExists)((0, path_1.join)(searchDir, 'appmap.yml'))) {
|
|
114
|
+
appmapConfigDir = searchDir;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
if ((0, path_1.dirname)(searchDir) === searchDir)
|
|
118
|
+
break;
|
|
119
|
+
searchDir = (0, path_1.dirname)(searchDir);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const resolvePath = (path) => __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
const candidates = [path];
|
|
125
|
+
if (appmapConfigDir)
|
|
126
|
+
candidates.push((0, path_1.join)(appmapConfigDir, path));
|
|
127
|
+
for (const candidate of candidates)
|
|
128
|
+
if (yield (0, util_1.fileExists)(candidate))
|
|
129
|
+
return candidate;
|
|
130
|
+
});
|
|
131
|
+
const mostRecentModifiedDate = (filePaths) => __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
const dates = new Array();
|
|
133
|
+
for (const filePath of filePaths) {
|
|
134
|
+
const resolvedPath = yield resolvePath(filePath);
|
|
135
|
+
if (!resolvedPath)
|
|
136
|
+
continue;
|
|
137
|
+
const date = yield (0, lastGitOrFSModifiedDate_1.default)(resolvedPath);
|
|
138
|
+
if (date)
|
|
139
|
+
dates.push(date);
|
|
140
|
+
}
|
|
141
|
+
return dates.sort((a, b) => (a && b ? b.getTime() - a.getTime() : 0))[0];
|
|
142
|
+
});
|
|
96
143
|
const buildFinding = (matchEvent, participatingEvents, message, groupMessage, occurranceCount,
|
|
97
144
|
// matchEvent will be added to additionalEvents and participatingEvents.values
|
|
98
145
|
// to create the relatedEvents array
|
|
99
|
-
additionalEvents) => {
|
|
146
|
+
additionalEvents) => __awaiter(this, void 0, void 0, function* () {
|
|
100
147
|
const findingEvent = matchEvent || event;
|
|
101
148
|
// Fixes:
|
|
102
149
|
// TypeError: Cannot read property 'forEach' of undefined
|
|
@@ -112,18 +159,56 @@ class RuleChecker {
|
|
|
112
159
|
// findingEvent gets passed here as a relatedEvent, and if you look at HashV1 it
|
|
113
160
|
// gets added to the hash again. That's how it worked in V1 so it's here for compatibility.
|
|
114
161
|
additionalEvents || []);
|
|
162
|
+
let scopeModifiedDate;
|
|
163
|
+
{
|
|
164
|
+
const scopeNavigator = new models_1.EventNavigator(scope);
|
|
165
|
+
const scopeFiles = new Set();
|
|
166
|
+
const collectScope = (event) => {
|
|
167
|
+
if (!event.codeObject.location)
|
|
168
|
+
return;
|
|
169
|
+
const filePath = locationToFilePath(event.codeObject.location);
|
|
170
|
+
if (!filePath)
|
|
171
|
+
return;
|
|
172
|
+
scopeFiles.add(filePath);
|
|
173
|
+
};
|
|
174
|
+
collectScope(scope);
|
|
175
|
+
for (const descendant of scopeNavigator.descendants()) {
|
|
176
|
+
const { event } = descendant;
|
|
177
|
+
collectScope(event);
|
|
178
|
+
}
|
|
179
|
+
const localScopeFiles = [...scopeFiles].filter((filePath) => ((0, assert_1.default)(filePath), !(0, path_1.isAbsolute)(filePath)));
|
|
180
|
+
scopeModifiedDate = yield mostRecentModifiedDate(localScopeFiles);
|
|
181
|
+
}
|
|
115
182
|
const hashV2 = new hashV2_1.default(checkInstance.ruleId, findingEvent, participatingEvents);
|
|
116
183
|
const uniqueEvents = new Set();
|
|
117
184
|
const relatedEvents = [];
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
185
|
+
const relatedEventFiles = new Set();
|
|
186
|
+
const collectEventFile = (event) => {
|
|
187
|
+
if (!event.codeObject.location)
|
|
188
|
+
return;
|
|
189
|
+
const filePath = locationToFilePath(event.codeObject.location);
|
|
190
|
+
if (!filePath)
|
|
191
|
+
return;
|
|
192
|
+
if ((0, path_1.isAbsolute)(filePath))
|
|
193
|
+
return;
|
|
194
|
+
relatedEventFiles.add(filePath);
|
|
195
|
+
};
|
|
196
|
+
[findingEvent, ...(additionalEvents || []), ...Object.values(participatingEvents)].forEach((event) => {
|
|
121
197
|
if (uniqueEvents.has(event.id)) {
|
|
122
198
|
return;
|
|
123
199
|
}
|
|
200
|
+
collectEventFile(event);
|
|
201
|
+
for (const ancestor of new models_1.EventNavigator(event).ancestors()) {
|
|
202
|
+
collectEventFile(ancestor.event);
|
|
203
|
+
}
|
|
124
204
|
uniqueEvents.add(event.id);
|
|
125
205
|
relatedEvents.push((0, eventUtil_1.cloneEvent)(event));
|
|
126
206
|
});
|
|
207
|
+
const eventsModifiedDate = yield mostRecentModifiedDate([...relatedEventFiles]);
|
|
208
|
+
if ((0, util_1.verbose)()) {
|
|
209
|
+
(0, console_1.warn)(`Scope modified date: ${scopeModifiedDate}`);
|
|
210
|
+
(0, console_1.warn)(`Events modified date: ${eventsModifiedDate}`);
|
|
211
|
+
}
|
|
127
212
|
return {
|
|
128
213
|
appMapFile: appMapFileName,
|
|
129
214
|
checkId: checkInstance.checkId,
|
|
@@ -140,8 +225,10 @@ class RuleChecker {
|
|
|
140
225
|
relatedEvents: relatedEvents.sort((event) => event.id),
|
|
141
226
|
impactDomain: checkInstance.checkImpactDomain,
|
|
142
227
|
participatingEvents: Object.fromEntries(Object.entries(participatingEvents).map(([k, v]) => [k, (0, eventUtil_1.cloneEvent)(v)])),
|
|
228
|
+
scopeModifiedDate,
|
|
229
|
+
eventsModifiedDate,
|
|
143
230
|
};
|
|
144
|
-
};
|
|
231
|
+
});
|
|
145
232
|
if (this.progress)
|
|
146
233
|
yield this.progress.matchEvent(event, appMapIndex);
|
|
147
234
|
const matchResult = yield checkInstance.ruleLogic.matcher(event, appMapIndex, checkInstance.filterEvent.bind(checkInstance));
|
|
@@ -152,23 +239,23 @@ class RuleChecker {
|
|
|
152
239
|
let finding;
|
|
153
240
|
if (checkInstance.ruleLogic.message) {
|
|
154
241
|
const message = checkInstance.ruleLogic.message(scope, event);
|
|
155
|
-
finding = buildFinding(event, {}, message);
|
|
242
|
+
finding = yield buildFinding(event, {}, message);
|
|
156
243
|
}
|
|
157
244
|
else {
|
|
158
|
-
finding = buildFinding(event, {});
|
|
245
|
+
finding = yield buildFinding(event, {});
|
|
159
246
|
}
|
|
160
247
|
findings.push(finding);
|
|
161
248
|
}
|
|
162
249
|
else if (typeof matchResult === 'string') {
|
|
163
|
-
const finding = buildFinding(event, {}, matchResult);
|
|
250
|
+
const finding = yield buildFinding(event, {}, matchResult);
|
|
164
251
|
finding.message = matchResult;
|
|
165
252
|
findings.push(finding);
|
|
166
253
|
}
|
|
167
254
|
else if (matchResult) {
|
|
168
|
-
|
|
169
|
-
const finding = buildFinding(mr.event, mr.participatingEvents || {}, mr.message, mr.groupMessage, mr.occurranceCount, mr.relatedEvents);
|
|
255
|
+
for (const mr of matchResult) {
|
|
256
|
+
const finding = yield buildFinding(mr.event, mr.participatingEvents || {}, mr.message, mr.groupMessage, mr.occurranceCount, mr.relatedEvents);
|
|
170
257
|
findings.push(finding);
|
|
171
|
-
}
|
|
258
|
+
}
|
|
172
259
|
}
|
|
173
260
|
if ((0, util_1.verbose)()) {
|
|
174
261
|
if (findings.length > numFindings) {
|
package/built/rules/lib/util.js
CHANGED
|
@@ -12,11 +12,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
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 = exports.collectAppMapFiles = void 0;
|
|
15
|
+
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.fileExists = exports.emptyValue = exports.capitalize = exports.appMapDir = exports.collectAppMapFiles = void 0;
|
|
16
16
|
const path_1 = require("path");
|
|
17
17
|
const util_1 = require("util");
|
|
18
18
|
const glob_1 = require("glob");
|
|
19
19
|
const assert_1 = __importDefault(require("assert"));
|
|
20
|
+
const promises_1 = require("fs/promises");
|
|
20
21
|
function collectAppMapFiles(appmapFile, appmapDir) {
|
|
21
22
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
23
|
let files = [];
|
|
@@ -164,3 +165,15 @@ function pluralize(word, count) {
|
|
|
164
165
|
return count === 1 ? word : [word, 's'].join('');
|
|
165
166
|
}
|
|
166
167
|
exports.pluralize = pluralize;
|
|
168
|
+
function fileExists(file) {
|
|
169
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
170
|
+
try {
|
|
171
|
+
yield (0, promises_1.stat)(file);
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
exports.fileExists = fileExists;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appland/scanner",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.80.0",
|
|
4
4
|
"description": "Analyze AppMaps for code flaws",
|
|
5
5
|
"bin": "built/cli.js",
|
|
6
6
|
"files": [
|
|
@@ -20,12 +20,14 @@
|
|
|
20
20
|
"lint": "eslint src --ext .ts",
|
|
21
21
|
"ci": "yarn lint && yarn build && yarn schema-up-to-date && yarn doc-up-to-date && yarn test",
|
|
22
22
|
"test": "jest --filter=./test/testFilter.js",
|
|
23
|
+
"jest": "jest --filter=./test/testFilter.js",
|
|
23
24
|
"semantic-release": "semantic-release",
|
|
24
25
|
"watch": "node bin/preBuild.js && tsc -p tsconfig.build.json --watch"
|
|
25
26
|
},
|
|
26
27
|
"author": "AppLand, Inc.",
|
|
27
28
|
"license": "Commons Clause + MIT",
|
|
28
29
|
"devDependencies": {
|
|
30
|
+
"@appland/appmap-agent-js": "^13.9.0",
|
|
29
31
|
"@semantic-release/changelog": "^6.0.1",
|
|
30
32
|
"@semantic-release/git": "^10.0.1",
|
|
31
33
|
"@types/async": "^3.2.12",
|
|
@@ -61,25 +63,25 @@
|
|
|
61
63
|
},
|
|
62
64
|
"dependencies": {
|
|
63
65
|
"@appland/client": "^1.5.0",
|
|
64
|
-
"@appland/models": "^2.6.
|
|
65
|
-
"@appland/openapi": "1.
|
|
66
|
+
"@appland/models": "^2.6.3",
|
|
67
|
+
"@appland/openapi": "1.6.0",
|
|
66
68
|
"@appland/sql-parser": "^1.5.0",
|
|
67
69
|
"@types/cli-progress": "^3.9.2",
|
|
68
70
|
"ajv": "^8.8.2",
|
|
69
71
|
"applicationinsights": "^2.1.4",
|
|
70
|
-
"async": "^3.2.
|
|
72
|
+
"async": "^3.2.4",
|
|
71
73
|
"boxen": "^5.0.1",
|
|
72
74
|
"chalk": "^4.1.2",
|
|
73
75
|
"chokidar": "^3.5.1",
|
|
74
|
-
"cli-progress": "^3.
|
|
75
|
-
"conf": "
|
|
76
|
+
"cli-progress": "^3.12.0",
|
|
77
|
+
"conf": "10.2.0",
|
|
76
78
|
"crypto-js": "^4.0.0",
|
|
77
79
|
"glob": "7.2.3",
|
|
78
80
|
"inquirer": "^8.1.2",
|
|
79
81
|
"js-yaml": "^4.1.0",
|
|
80
82
|
"lru-cache": "^6.0.0",
|
|
81
83
|
"minimatch": "^5.1.2",
|
|
82
|
-
"
|
|
84
|
+
"octokit": "^2.0.19",
|
|
83
85
|
"openapi-diff": "^0.23.5",
|
|
84
86
|
"ora": "~5",
|
|
85
87
|
"pretty-format": "^27.4.6",
|
package/src/types.d.ts
CHANGED
|
@@ -116,6 +116,8 @@ interface Finding {
|
|
|
116
116
|
impactDomain?: ImpactDomain;
|
|
117
117
|
// Map of events by functional role name; for example, logEvent, secret, scope, etc.
|
|
118
118
|
participatingEvents?: Record<string, Event>;
|
|
119
|
+
scopeModifiedDate?: Date;
|
|
120
|
+
eventsModifiedDate?: Date;
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
interface RuleLogic {
|