@appland/scanner 1.88.1 → 1.88.2

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 CHANGED
@@ -1,3 +1,10 @@
1
+ # [@appland/scanner-v1.88.2](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.88.1...@appland/scanner-v1.88.2) (2025-10-07)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **scanner:** Update to @appland/telemetry ([1672e65](https://github.com/getappmap/appmap-js/commit/1672e651d5119d5779c797f8013b079d9087fc81))
7
+
1
8
  # [@appland/scanner-v1.88.1](https://github.com/getappmap/appmap-js/compare/@appland/scanner-v1.88.0...@appland/scanner-v1.88.1) (2025-05-22)
2
9
 
3
10
 
@@ -45,7 +45,7 @@ const node_util_1 = require("node:util");
45
45
  const formatReport_1 = require("./formatReport");
46
46
  const scanner_1 = __importDefault(require("./scanner"));
47
47
  const configurationProvider_1 = require("../../configuration/configurationProvider");
48
- const telemetry_1 = __importDefault(require("../../telemetry"));
48
+ const telemetry_1 = require("@appland/telemetry");
49
49
  const events_1 = __importDefault(require("events"));
50
50
  const isAncestorPath_1 = __importDefault(require("../../util/isAncestorPath"));
51
51
  const util_1 = require("util");
@@ -139,7 +139,7 @@ class Watcher {
139
139
  yield ((_a = this.appmapWatcher) === null || _a === void 0 ? void 0 : _a.close());
140
140
  this.appmapWatcher = undefined;
141
141
  console.warn('File watching disabled.');
142
- telemetry_1.default.sendEvent({
142
+ telemetry_1.Telemetry.sendEvent({
143
143
  name: `scan:watcher_error:enospc`,
144
144
  properties: {
145
145
  errorMessage: error.message,
package/built/cli.js CHANGED
@@ -9,7 +9,7 @@ const command_1 = __importDefault(require("./cli/scan/command"));
9
9
  const util_1 = require("./rules/lib/util");
10
10
  const errors_1 = require("./errors");
11
11
  const exitCode_1 = require("./cli/exitCode");
12
- const telemetry_1 = __importDefault(require("./telemetry"));
12
+ const telemetry_1 = require("@appland/telemetry");
13
13
  const models_1 = require("@appland/models");
14
14
  const sqlWarning_1 = __importDefault(require("./sqlWarning"));
15
15
  function errorInfo(err) {
@@ -29,8 +29,16 @@ function handleError(err) {
29
29
  };
30
30
  if (label === 'error')
31
31
  telemetry.properties.errorStack = err.stack;
32
- telemetry_1.default.sendEvent(telemetry);
32
+ telemetry_1.Telemetry.sendEvent(telemetry);
33
33
  }
34
+ telemetry_1.Telemetry.configure({
35
+ product: {
36
+ name: '@appland/scanner',
37
+ // Importing this would change the directory structure of our build, so we use require
38
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
39
+ version: require('../package.json').version,
40
+ },
41
+ });
34
42
  (0, models_1.setSQLErrorHandler)(sqlWarning_1.default);
35
43
  (0, yargs_1.default)(process.argv.slice(2))
36
44
  .option('verbose', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appland/scanner",
3
- "version": "1.88.1",
3
+ "version": "1.88.2",
4
4
  "description": "Analyze AppMaps for code flaws",
5
5
  "bin": "built/cli.js",
6
6
  "main": "built/index.js",
@@ -27,7 +27,6 @@
27
27
  "author": "AppLand, Inc.",
28
28
  "license": "Commons Clause + MIT",
29
29
  "devDependencies": {
30
- "@appland/appmap-agent-js": "^13.9.0",
31
30
  "@semantic-release/changelog": "^6.0.1",
32
31
  "@semantic-release/git": "^10.0.1",
33
32
  "@types/async": "^3.2.12",
@@ -66,6 +65,7 @@
66
65
  "@appland/models": "^2.10.0",
67
66
  "@appland/openapi": "^1.7.0",
68
67
  "@appland/sql-parser": "^1.5.0",
68
+ "@appland/telemetry": "^1.1.0",
69
69
  "@types/cli-progress": "^3.9.2",
70
70
  "ajv": "^8.8.2",
71
71
  "applicationinsights": "^2.1.4",
@@ -1,50 +0,0 @@
1
- /// <reference types="node" />
2
- import { TelemetryClient } from 'applicationinsights';
3
- import { PathLike } from 'fs';
4
- declare class Session {
5
- id: string;
6
- expiration: number;
7
- constructor();
8
- static beyondExpiration(expiration: number): boolean;
9
- static expirationFromNow(): number;
10
- static newSessionId(): string;
11
- touch(): void;
12
- get valid(): boolean;
13
- }
14
- export interface TelemetryData {
15
- name: string;
16
- properties?: Record<string, string | undefined>;
17
- metrics?: Record<string, number | undefined>;
18
- }
19
- export interface TelemetryOptions {
20
- includeEnvironment: boolean;
21
- }
22
- export default class Telemetry {
23
- private static _session?;
24
- private static _client?;
25
- private static debug;
26
- static readonly machineId: string;
27
- static get enabled(): boolean;
28
- static get session(): Session;
29
- static get client(): TelemetryClient;
30
- static sendEvent(data: TelemetryData, options?: TelemetryOptions): void;
31
- static flush(exitCB: () => unknown): void;
32
- }
33
- export declare enum GitState {
34
- NotInstalled = 0,
35
- NoRepository = 1,
36
- Ok = 2
37
- }
38
- export declare const GitRepositoryEnvKeys: readonly ["GITHUB_REPOSITORY", "CIRCLE_REPOSITORY_URL", "GIT_URL", "CI_REPOSITORY_URL"];
39
- export declare const GitBranchEnvKeys: readonly ["GITHUB_REF_NAME", "CIRCLE_BRANCH", "GIT_BRANCH", "TRAVIS_BRANCH", "CI_COMMIT_REF_NAME"];
40
- export declare const GitCommitEnvKeys: readonly ["GITHUB_SHA", "CIRCLE_SHA1", "GIT_COMMIT", "TRAVIS_COMMIT", "CI_COMMIT_SHA"];
41
- declare class GitProperties {
42
- static contributors(sinceDaysAgo: number, cwd?: PathLike): Promise<Array<string>>;
43
- static repository(cwd?: PathLike): Promise<string | undefined>;
44
- static branch(cwd?: PathLike): Promise<string | undefined>;
45
- static commit(cwd?: PathLike): Promise<string | undefined>;
46
- static state(cwd?: PathLike): Promise<GitState>;
47
- static clearCache(): void;
48
- }
49
- export declare const Git: typeof GitProperties;
50
- export {};
@@ -1,394 +0,0 @@
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
- var __importDefault = (this && this.__importDefault) || function (mod) {
35
- return (mod && mod.__esModule) ? mod : { "default": mod };
36
- };
37
- Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.Git = exports.GitCommitEnvKeys = exports.GitBranchEnvKeys = exports.GitRepositoryEnvKeys = exports.GitState = void 0;
39
- const os_1 = require("os");
40
- const crypto_1 = require("crypto");
41
- const os = __importStar(require("os"));
42
- const read_pkg_up_1 = require("read-pkg-up");
43
- const applicationinsights_1 = require("applicationinsights");
44
- const conf_1 = __importDefault(require("conf"));
45
- const child_process_1 = require("child_process");
46
- const util_1 = require("util");
47
- const exec = (0, util_1.promisify)(child_process_1.exec);
48
- const { name, version } = (() => {
49
- var _a;
50
- const result = (_a = (0, read_pkg_up_1.sync)({ cwd: __dirname })) === null || _a === void 0 ? void 0 : _a.packageJson;
51
- if (!result)
52
- throw 'cannot find package.json';
53
- return result;
54
- })();
55
- const config = new conf_1.default({
56
- projectName: '@appland/appmap',
57
- projectVersion: '0.0.1', // note this is actually config version
58
- });
59
- const invalidMacAddresses = new Set([
60
- '00:00:00:00:00:00',
61
- 'ff:ff:ff:ff:ff:ff',
62
- 'ac:de:48:00:11:22',
63
- ]);
64
- // This key is meant to be publically shared. However, I'm adding a simple
65
- // obfuscation to mitigate key scraping bots on GitHub. The key is split on
66
- // hypens and base64 encoded without padding.
67
- // key.split('-').map((x) => x.toString('base64').replace(/=*/, ''))
68
- const INSTRUMENTATION_KEY = ['NTBjMWE1YzI', 'NDliNA', 'NDkxMw', 'YjdjYw', 'ODZhNzhkNDA3NDVm']
69
- .map((x) => Buffer.from(x, 'base64').toString('utf8'))
70
- .join('-');
71
- function getMachineId() {
72
- const machineId = config.get('machineId');
73
- if (machineId) {
74
- return machineId;
75
- }
76
- let machineIdSource;
77
- // Derive a machine ID from the first network interface
78
- machineIdSource = Object.values((0, os_1.networkInterfaces)())
79
- .flat()
80
- .map((iface) => iface === null || iface === void 0 ? void 0 : iface.mac)
81
- .filter((mac) => mac && !invalidMacAddresses.has(mac))
82
- .shift();
83
- if (!machineIdSource) {
84
- // Fallback to a random string
85
- machineIdSource = (0, crypto_1.randomBytes)(32);
86
- }
87
- const machineIdHash = (0, crypto_1.createHash)('sha256')
88
- .update(machineIdSource)
89
- .digest('hex');
90
- config.set('machineId', machineIdHash);
91
- return machineIdHash;
92
- }
93
- class Session {
94
- constructor() {
95
- const sessionId = config.get('sessionId');
96
- const sessionExpiration = config.get('sessionExpiration');
97
- if (sessionId && sessionExpiration && !Session.beyondExpiration(sessionExpiration)) {
98
- this.id = sessionId;
99
- this.expiration = sessionExpiration;
100
- }
101
- else {
102
- this.id = Session.newSessionId();
103
- this.expiration = Session.expirationFromNow();
104
- config.set('sessionId', this.id);
105
- config.set('sessionExpiration', this.expiration);
106
- }
107
- }
108
- static beyondExpiration(expiration) {
109
- return expiration <= Date.now();
110
- }
111
- static expirationFromNow() {
112
- return Date.now() + 1000 * 60 * 30;
113
- }
114
- static newSessionId() {
115
- return (0, crypto_1.createHash)('sha256').update((0, crypto_1.randomBytes)(32)).digest('hex');
116
- }
117
- touch() {
118
- this.expiration = Session.expirationFromNow();
119
- config.set('sessionExpiration', this.expiration);
120
- }
121
- get valid() {
122
- return !Session.beyondExpiration(this.expiration);
123
- }
124
- }
125
- const propPrefix = name === '@appland/appmap' ? 'appmap.cli.' : name.replace('@', '').replace('/', '.') + '.';
126
- /**
127
- * Append the prefix to the name of each property and drop undefined values
128
- */
129
- const transformProps = (obj) => {
130
- const result = {};
131
- for (const [k, v] of Object.entries(obj)) {
132
- if (v === undefined)
133
- continue;
134
- if (k.includes('.')) {
135
- result[k] = v;
136
- continue;
137
- }
138
- const prefixedKey = k.startsWith(propPrefix) ? k : `${propPrefix}${k}`;
139
- result[prefixedKey] = v;
140
- }
141
- return result;
142
- };
143
- class Telemetry {
144
- static get enabled() {
145
- return process.env.APPMAP_TELEMETRY_DISABLED === undefined;
146
- }
147
- static get session() {
148
- var _a;
149
- if (!((_a = this._session) === null || _a === void 0 ? void 0 : _a.valid)) {
150
- this._session = new Session();
151
- }
152
- return this._session;
153
- }
154
- static get client() {
155
- if (!this._client) {
156
- // Do not allow Application Insights to try and collect additional metadata
157
- process.env.APPLICATION_INSIGHTS_NO_STATSBEAT = '1';
158
- // Disable everything we can, we don't any additional collection from Application Insights.
159
- (0, applicationinsights_1.setup)(INSTRUMENTATION_KEY)
160
- .setAutoCollectRequests(false)
161
- .setAutoCollectPerformance(false)
162
- .setAutoCollectExceptions(false)
163
- .setAutoCollectDependencies(false)
164
- .setAutoCollectHeartbeat(false)
165
- .setAutoDependencyCorrelation(false)
166
- .setAutoCollectConsole(false)
167
- .setInternalLogging(false, false)
168
- .setSendLiveMetrics(false)
169
- .setUseDiskRetryCaching(true);
170
- const client = new applicationinsights_1.TelemetryClient(INSTRUMENTATION_KEY);
171
- client.context.tags[client.context.keys.userId] = Telemetry.machineId;
172
- client.context.tags[client.context.keys.sessionId] = Telemetry.session.id;
173
- client.context.tags[client.context.keys.cloudRole] = name;
174
- client.setAutoPopulateAzureProperties(false);
175
- this._client = client;
176
- }
177
- return this._client;
178
- }
179
- static sendEvent(data, options = { includeEnvironment: false }) {
180
- try {
181
- const transformedProperties = transformProps(Object.assign({ version: version, args: process.argv.slice(1).join(' ') }, data.properties));
182
- const transformedMetrics = transformProps(data.metrics || {});
183
- const properties = Object.assign({ 'common.source': name, 'common.os': os.platform(), 'common.platformversion': os.release(), 'common.arch': os.arch(), 'appmap.cli.machineId': Telemetry.machineId, 'appmap.cli.sessionId': Telemetry.session.id }, transformedProperties);
184
- if (options.includeEnvironment) {
185
- properties['common.environmentVariables'] = Object.keys(process.env).sort().join(',');
186
- }
187
- const event = {
188
- name: `${name}/${data.name}`,
189
- measurements: transformedMetrics,
190
- properties,
191
- };
192
- if (this.debug) {
193
- console.log(JSON.stringify(event, null, 2));
194
- }
195
- if (this.enabled) {
196
- Telemetry.client.trackEvent(event);
197
- Telemetry.session.touch();
198
- Telemetry.client.flush();
199
- }
200
- }
201
- catch (e) {
202
- // Don't let telemetry fail the entire command
203
- // Do nothing other than log for now, we can't do anything about it
204
- if (this.debug) {
205
- if (e instanceof Error) {
206
- console.error(e.stack);
207
- }
208
- else {
209
- console.error(e);
210
- }
211
- }
212
- }
213
- }
214
- static flush(exitCB) {
215
- if (this.enabled) {
216
- // Telemetry.client.flush is broken:
217
- // https://github.com/microsoft/ApplicationInsights-node.js/issues/871 .
218
- // As a result, we can fail to send telemetry data when exiting.
219
- //
220
- // If we got passed a callback, flush the data and wait for a second
221
- // before calling it.
222
- if (exitCB) {
223
- Telemetry.client.flush();
224
- setTimeout(exitCB, 1000);
225
- }
226
- }
227
- else {
228
- exitCB();
229
- }
230
- }
231
- }
232
- exports.default = Telemetry;
233
- Telemetry.debug = process.env.APPMAP_TELEMETRY_DEBUG !== undefined;
234
- Telemetry.machineId = getMachineId();
235
- var GitState;
236
- (function (GitState) {
237
- GitState[GitState["NotInstalled"] = 0] = "NotInstalled";
238
- GitState[GitState["NoRepository"] = 1] = "NoRepository";
239
- GitState[GitState["Ok"] = 2] = "Ok";
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
- ];
261
- class GitProperties {
262
- static contributors(sinceDaysAgo, cwd) {
263
- return __awaiter(this, void 0, void 0, function* () {
264
- const unixTimeNow = Math.floor(Number(new Date()) / 1000);
265
- const unixTimeAgo = unixTimeNow - sinceDaysAgo * 24 * 60 * 60;
266
- try {
267
- const { stdout } = yield exec([
268
- 'git',
269
- cwd && `-C ${cwd.toString()}`,
270
- '--no-pager',
271
- 'log',
272
- `--since=${unixTimeAgo}`,
273
- '--format="%ae"',
274
- ].join(' '));
275
- return [
276
- ...stdout
277
- .trim()
278
- .split('\n')
279
- .reduce((acc, email) => {
280
- acc.add(email);
281
- return acc;
282
- }, new Set()),
283
- ];
284
- }
285
- catch (_a) {
286
- return [];
287
- }
288
- });
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
- }
338
- static state(cwd) {
339
- return __awaiter(this, void 0, void 0, function* () {
340
- return new Promise((resolve) => {
341
- try {
342
- const commandProcess = (0, child_process_1.spawn)('git', ['status', '--porcelain'], {
343
- shell: true,
344
- cwd: cwd === null || cwd === void 0 ? void 0 : cwd.toString(),
345
- stdio: 'ignore',
346
- timeout: 2000,
347
- });
348
- commandProcess.on('exit', (code) => {
349
- switch (code) {
350
- case 127:
351
- return resolve(GitState.NotInstalled);
352
- case 128:
353
- return resolve(GitState.NoRepository);
354
- default:
355
- return resolve(GitState.Ok);
356
- }
357
- });
358
- commandProcess.on('error', () => resolve(GitState.NotInstalled));
359
- }
360
- catch (_a) {
361
- resolve(GitState.NotInstalled);
362
- }
363
- });
364
- });
365
- }
366
- static clearCache() {
367
- gitCache.clear();
368
- }
369
- }
370
- const gitCache = new Map();
371
- const noCacheList = ['clearCache'];
372
- // GitProperties is available externally as Git.
373
- // This export provides a simple caching layer around GitProperties to avoid
374
- // excessive shelling out to git.
375
- exports.Git = new Proxy(GitProperties, {
376
- get(target, prop) {
377
- if (!noCacheList.includes(prop.toString()) &&
378
- typeof target[prop] === 'function') {
379
- return new Proxy(target[prop], {
380
- apply(target, thisArg, argArray) {
381
- const cacheKey = `${prop.toString()}(${JSON.stringify(argArray)})`;
382
- if (gitCache.has(cacheKey)) {
383
- return gitCache.get(cacheKey);
384
- }
385
- /* eslint-disable-next-line @typescript-eslint/ban-types */
386
- const result = Reflect.apply(target, thisArg, argArray);
387
- gitCache.set(cacheKey, result);
388
- return result;
389
- },
390
- });
391
- }
392
- return Reflect.get(target, prop);
393
- },
394
- });