@appland/scanner 1.82.0 → 1.83.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 +14 -0
- package/built/cli/scan/singleScan.js +0 -15
- package/built/cli/scan/watchScan.js +32 -24
- package/built/report/scanResults.js +1 -55
- package/built/telemetry.js +73 -2
- package/package.json +1 -1
- package/built/cli/scan/watchScanTelemetry.js +0 -44
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [@appland/scanner-v1.83.0](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.82.1...@appland/scanner-v1.83.0) (2023-09-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* Clean up telemetry ([c7d0a92](https://github.com/getappmap/appmap-js/commit/c7d0a928661351bc10e51c0531689caa3ff98b1f))
|
|
7
|
+
|
|
8
|
+
# [@appland/scanner-v1.82.1](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.82.0...@appland/scanner-v1.82.1) (2023-08-25)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* Ensure that AppMaps are un-marked as being scanned ([e051d8d](https://github.com/getappmap/appmap-js/commit/e051d8db4e7d7b6b8ad8420573f0f02939d9e3bc))
|
|
14
|
+
|
|
1
15
|
# [@appland/scanner-v1.82.0](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.81.1...@appland/scanner-v1.82.0) (2023-08-11)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -19,19 +19,11 @@ const findings_1 = require("../../findings");
|
|
|
19
19
|
const findingsReport_1 = __importDefault(require("../../report/findingsReport"));
|
|
20
20
|
const summaryReport_1 = __importDefault(require("../../report/summaryReport"));
|
|
21
21
|
const formatReport_1 = require("./formatReport");
|
|
22
|
-
const telemetry_1 = __importDefault(require("../../telemetry"));
|
|
23
|
-
const scanResults_1 = require("../../report/scanResults");
|
|
24
22
|
const util_1 = require("../../rules/lib/util");
|
|
25
23
|
const validateFile_1 = __importDefault(require("../validateFile"));
|
|
26
24
|
function singleScan(options) {
|
|
27
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
28
26
|
const { appmapFile, appmapDir, configuration, reportAllFindings, appId, ide, reportFile } = options;
|
|
29
|
-
telemetry_1.default.sendEvent({
|
|
30
|
-
name: 'scan:started',
|
|
31
|
-
properties: {
|
|
32
|
-
ide,
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
27
|
const skipErrors = appmapDir !== undefined;
|
|
36
28
|
const files = yield (0, util_1.collectAppMapFiles)(appmapFile, appmapDir);
|
|
37
29
|
yield Promise.all(files.map((file) => __awaiter(this, void 0, void 0, function* () { return (0, validateFile_1.default)('file', file); })));
|
|
@@ -59,13 +51,6 @@ function singleScan(options) {
|
|
|
59
51
|
const elapsed = Date.now() - startTime;
|
|
60
52
|
const numChecks = scanResults.checks.length * scanResults.summary.numAppMaps;
|
|
61
53
|
console.log(`Performed ${numChecks} checks in ${elapsed}ms (${Math.floor(numChecks / (elapsed / 1000.0))} checks/sec)`);
|
|
62
|
-
(0, scanResults_1.sendScanResultsTelemetry)({
|
|
63
|
-
ruleIds: scanResults.summary.rules,
|
|
64
|
-
numAppMaps: scanResults.summary.numAppMaps,
|
|
65
|
-
numFindings: scanResults.summary.numFindings,
|
|
66
|
-
elapsedMs: elapsed,
|
|
67
|
-
appmapDir: options.appmapDir,
|
|
68
|
-
});
|
|
69
54
|
});
|
|
70
55
|
}
|
|
71
56
|
exports.default = singleScan;
|
|
@@ -47,9 +47,9 @@ const scanner_1 = __importDefault(require("./scanner"));
|
|
|
47
47
|
const configurationProvider_1 = require("../../configuration/configurationProvider");
|
|
48
48
|
const telemetry_1 = __importDefault(require("../../telemetry"));
|
|
49
49
|
const events_1 = __importDefault(require("events"));
|
|
50
|
-
const watchScanTelemetry_1 = require("./watchScanTelemetry");
|
|
51
50
|
const isAncestorPath_1 = __importDefault(require("../../util/isAncestorPath"));
|
|
52
51
|
const util_1 = require("util");
|
|
52
|
+
const console_1 = require("console");
|
|
53
53
|
const debug = (0, util_1.debuglog)('scanner:watch');
|
|
54
54
|
function isDir(targetPath) {
|
|
55
55
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -79,15 +79,11 @@ class Watcher {
|
|
|
79
79
|
// passing plain async function doesn't work (?)
|
|
80
80
|
this.queue = (0, async_1.queue)((0, node_util_1.callbackify)(this.scan.bind(this)), 2);
|
|
81
81
|
this.processing = new Set();
|
|
82
|
-
watchScanTelemetry_1.WatchScanTelemetry.watch(this.scanEventEmitter, options.appmapDir);
|
|
83
82
|
this.queue.error((error, task) => console.warn(`Problem processing ${task}:\n`, error));
|
|
84
83
|
}
|
|
85
84
|
watch() {
|
|
86
85
|
return __awaiter(this, void 0, void 0, function* () {
|
|
87
86
|
yield this.reloadConfig();
|
|
88
|
-
telemetry_1.default.sendEvent({
|
|
89
|
-
name: 'scan:started',
|
|
90
|
-
});
|
|
91
87
|
this.configWatcher = chokidar.watch(this.options.configFile, {
|
|
92
88
|
ignoreInitial: true,
|
|
93
89
|
});
|
|
@@ -176,25 +172,37 @@ class Watcher {
|
|
|
176
172
|
scan(mtimePath) {
|
|
177
173
|
return __awaiter(this, void 0, void 0, function* () {
|
|
178
174
|
(0, assert_1.default)(this.config, `config should always be loaded before appmapWatcher triggers a scan`);
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
175
|
+
const perform = () => __awaiter(this, void 0, void 0, function* () {
|
|
176
|
+
const appmapFile = [path_1.default.dirname(mtimePath), 'appmap.json'].join('.');
|
|
177
|
+
const reportFile = mtimePath.replace(/mtime$/, 'appmap-findings.json');
|
|
178
|
+
const [appmapStats, reportStats] = yield Promise.all([appmapFile, reportFile].map((f) => (0, promises_1.stat)(f).catch(() => null)));
|
|
179
|
+
if (!appmapStats) {
|
|
180
|
+
(0, console_1.warn)(`[scan] AppMap file ${appmapFile} does not exist`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const cut = (str) => str.substring(str.length - 8);
|
|
184
|
+
(0, assert_1.default)(this.config);
|
|
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)));
|
|
186
|
+
if (reportStats &&
|
|
187
|
+
reportStats.mtimeMs > appmapStats.mtimeMs - 1000 &&
|
|
188
|
+
reportStats.mtimeMs > this.config.timestampMs - 1000) {
|
|
189
|
+
(0, console_1.warn)(`[scan] Report file ${reportFile} is already up to date`);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const startTime = Date.now();
|
|
193
|
+
const scanner = yield (0, scanner_1.default)(true, this.config, [appmapFile]);
|
|
194
|
+
const rawScanResults = yield scanner.scan();
|
|
195
|
+
const elapsed = Date.now() - startTime;
|
|
196
|
+
this.scanEventEmitter.emit('scan', { scanResults: rawScanResults, elapsed });
|
|
197
|
+
// Always report the raw data
|
|
198
|
+
yield (0, promises_1.writeFile)(reportFile, (0, formatReport_1.formatReport)(rawScanResults));
|
|
199
|
+
});
|
|
200
|
+
try {
|
|
201
|
+
yield perform();
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
this.processing.delete(mtimePath);
|
|
205
|
+
}
|
|
198
206
|
});
|
|
199
207
|
}
|
|
200
208
|
reloadConfig() {
|
|
@@ -1,39 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
-
});
|
|
33
|
-
};
|
|
34
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.
|
|
36
|
-
const telemetry_1 = __importStar(require("../telemetry"));
|
|
3
|
+
exports.ScanResults = void 0;
|
|
37
4
|
class DistinctItems {
|
|
38
5
|
constructor() {
|
|
39
6
|
this.members = {};
|
|
@@ -118,24 +85,3 @@ class ScanResults {
|
|
|
118
85
|
}
|
|
119
86
|
}
|
|
120
87
|
exports.ScanResults = ScanResults;
|
|
121
|
-
function sendScanResultsTelemetry(telemetry) {
|
|
122
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
123
|
-
const gitState = telemetry_1.GitState[yield telemetry_1.Git.state(telemetry.appmapDir)];
|
|
124
|
-
const contributors = (yield telemetry_1.Git.contributors(60, telemetry.appmapDir)).length;
|
|
125
|
-
telemetry_1.default.sendEvent({
|
|
126
|
-
name: 'scan:completed',
|
|
127
|
-
properties: {
|
|
128
|
-
rules: telemetry.ruleIds.sort().join(', '),
|
|
129
|
-
git_state: gitState,
|
|
130
|
-
},
|
|
131
|
-
metrics: {
|
|
132
|
-
duration: telemetry.elapsedMs / 1000,
|
|
133
|
-
numRules: telemetry.ruleIds.length,
|
|
134
|
-
numAppMaps: telemetry.numAppMaps,
|
|
135
|
-
numFindings: telemetry.numFindings,
|
|
136
|
-
contributors: contributors,
|
|
137
|
-
},
|
|
138
|
-
}, { includeEnvironment: true });
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
exports.sendScanResultsTelemetry = sendScanResultsTelemetry;
|
package/built/telemetry.js
CHANGED
|
@@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.Git = exports.GitState = void 0;
|
|
38
|
+
exports.Git = exports.GitCommitEnvKeys = exports.GitBranchEnvKeys = exports.GitRepositoryEnvKeys = exports.GitState = void 0;
|
|
39
39
|
const os_1 = require("os");
|
|
40
40
|
const crypto_1 = require("crypto");
|
|
41
41
|
const os = __importStar(require("os"));
|
|
@@ -238,6 +238,26 @@ var GitState;
|
|
|
238
238
|
GitState[GitState["NoRepository"] = 1] = "NoRepository";
|
|
239
239
|
GitState[GitState["Ok"] = 2] = "Ok";
|
|
240
240
|
})(GitState = exports.GitState || (exports.GitState = {}));
|
|
241
|
+
exports.GitRepositoryEnvKeys = [
|
|
242
|
+
'GITHUB_REPOSITORY',
|
|
243
|
+
'CIRCLE_REPOSITORY_URL',
|
|
244
|
+
'GIT_URL',
|
|
245
|
+
'CI_REPOSITORY_URL', // GitLab
|
|
246
|
+
];
|
|
247
|
+
exports.GitBranchEnvKeys = [
|
|
248
|
+
'GITHUB_REF_NAME',
|
|
249
|
+
'CIRCLE_BRANCH',
|
|
250
|
+
'GIT_BRANCH',
|
|
251
|
+
'TRAVIS_BRANCH',
|
|
252
|
+
'CI_COMMIT_REF_NAME', // GitLab
|
|
253
|
+
];
|
|
254
|
+
exports.GitCommitEnvKeys = [
|
|
255
|
+
'GITHUB_SHA',
|
|
256
|
+
'CIRCLE_SHA1',
|
|
257
|
+
'GIT_COMMIT',
|
|
258
|
+
'TRAVIS_COMMIT',
|
|
259
|
+
'CI_COMMIT_SHA', // GitLab
|
|
260
|
+
];
|
|
241
261
|
class GitProperties {
|
|
242
262
|
static contributors(sinceDaysAgo, cwd) {
|
|
243
263
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -267,11 +287,59 @@ class GitProperties {
|
|
|
267
287
|
}
|
|
268
288
|
});
|
|
269
289
|
}
|
|
290
|
+
// Returns the repository URL, first by checking the environment, then by
|
|
291
|
+
// shelling out to git.
|
|
292
|
+
static repository(cwd) {
|
|
293
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
294
|
+
const envKey = exports.GitRepositoryEnvKeys.find((key) => process.env[key]);
|
|
295
|
+
if (envKey)
|
|
296
|
+
return process.env[envKey];
|
|
297
|
+
try {
|
|
298
|
+
const { stdout } = yield exec(['git', cwd && `-C ${cwd.toString()}`, 'config', '--get', 'remote.origin.url'].join(' '));
|
|
299
|
+
return stdout.trim();
|
|
300
|
+
}
|
|
301
|
+
catch (_a) {
|
|
302
|
+
return undefined;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
// Returns the branch, first by checking the environment, then by
|
|
307
|
+
// shelling out to git.
|
|
308
|
+
static branch(cwd) {
|
|
309
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
+
const envKey = exports.GitBranchEnvKeys.find((key) => process.env[key]);
|
|
311
|
+
if (envKey)
|
|
312
|
+
return process.env[envKey];
|
|
313
|
+
try {
|
|
314
|
+
const { stdout } = yield exec(['git', cwd && `-C ${cwd.toString()}`, 'rev-parse', '--abbrev-ref', 'HEAD'].join(' '));
|
|
315
|
+
return stdout.trim();
|
|
316
|
+
}
|
|
317
|
+
catch (_a) {
|
|
318
|
+
return undefined;
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
// Returns the commit SHA, first by checking the environment, then by
|
|
323
|
+
// shelling out to git.
|
|
324
|
+
static commit(cwd) {
|
|
325
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
326
|
+
const envKey = exports.GitCommitEnvKeys.find((key) => process.env[key]);
|
|
327
|
+
if (envKey)
|
|
328
|
+
return process.env[envKey];
|
|
329
|
+
try {
|
|
330
|
+
const { stdout } = yield exec(['git', cwd && `-C ${cwd.toString()}`, 'rev-parse', 'HEAD'].join(' '));
|
|
331
|
+
return stdout.trim();
|
|
332
|
+
}
|
|
333
|
+
catch (_a) {
|
|
334
|
+
return undefined;
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
}
|
|
270
338
|
static state(cwd) {
|
|
271
339
|
return __awaiter(this, void 0, void 0, function* () {
|
|
272
340
|
return new Promise((resolve) => {
|
|
273
341
|
try {
|
|
274
|
-
const commandProcess = (0, child_process_1.spawn)('git', ['status'], {
|
|
342
|
+
const commandProcess = (0, child_process_1.spawn)('git', ['status', '--porcelain'], {
|
|
275
343
|
shell: true,
|
|
276
344
|
cwd: cwd === null || cwd === void 0 ? void 0 : cwd.toString(),
|
|
277
345
|
stdio: 'ignore',
|
|
@@ -295,6 +363,9 @@ class GitProperties {
|
|
|
295
363
|
});
|
|
296
364
|
});
|
|
297
365
|
}
|
|
366
|
+
static clearCache() {
|
|
367
|
+
gitCache.clear();
|
|
368
|
+
}
|
|
298
369
|
}
|
|
299
370
|
const gitCache = new Map();
|
|
300
371
|
// GitProperties is available externally as Git.
|
package/package.json
CHANGED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.WatchScanTelemetry = void 0;
|
|
7
|
-
const eventAggregator_1 = __importDefault(require("../../util/eventAggregator"));
|
|
8
|
-
const scanResults_1 = require("../../report/scanResults");
|
|
9
|
-
class WatchScanTelemetry {
|
|
10
|
-
constructor(scanEvents, appmapDir) {
|
|
11
|
-
this.appmapDir = appmapDir;
|
|
12
|
-
this.cancelFn = new eventAggregator_1.default((events) => {
|
|
13
|
-
const scanEvents = events.map((e) => e.arg);
|
|
14
|
-
this.sendTelemetry(scanEvents);
|
|
15
|
-
}).attach(scanEvents, 'scan');
|
|
16
|
-
}
|
|
17
|
-
cancel() {
|
|
18
|
-
if (this.cancelFn)
|
|
19
|
-
this.cancelFn();
|
|
20
|
-
this.cancelFn = undefined;
|
|
21
|
-
}
|
|
22
|
-
static watch(scanEvents, appmapDir) {
|
|
23
|
-
const telemetry = new WatchScanTelemetry(scanEvents, appmapDir);
|
|
24
|
-
return () => telemetry.cancel();
|
|
25
|
-
}
|
|
26
|
-
sendTelemetry(scanEvents) {
|
|
27
|
-
const ruleIds = new Set();
|
|
28
|
-
let elapsed = 0;
|
|
29
|
-
const telemetryScanResults = new scanResults_1.ScanResults();
|
|
30
|
-
for (const scanEvent of scanEvents) {
|
|
31
|
-
telemetryScanResults.aggregate(scanEvent.scanResults);
|
|
32
|
-
elapsed += scanEvent.elapsed;
|
|
33
|
-
}
|
|
34
|
-
telemetryScanResults.summary.rules.forEach((rule) => ruleIds.add(rule));
|
|
35
|
-
(0, scanResults_1.sendScanResultsTelemetry)({
|
|
36
|
-
ruleIds: [...ruleIds],
|
|
37
|
-
numAppMaps: telemetryScanResults.summary.numAppMaps,
|
|
38
|
-
numFindings: telemetryScanResults.summary.numFindings,
|
|
39
|
-
elapsedMs: elapsed,
|
|
40
|
-
appmapDir: this.appmapDir,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
exports.WatchScanTelemetry = WatchScanTelemetry;
|