Socket
Socket
Sign inDemoInstall

@contrast/agentify

Package Overview
Dependencies
Maintainers
9
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@contrast/agentify - npm Package Compare versions

Comparing version 1.15.0 to 1.16.0

lib/log-diagnostic-files.js

42

lib/index.d.ts

@@ -17,5 +17,6 @@ /*

import { Config } from '@contrast/config';
import { Installable } from '@contrast/common';
import { Logger } from '@contrast/logger';
import { Rewriter } from '@contrast/rewriter';
import RequireHook from '@contrast/require-hook';
import { Rewriter } from '@contrast/rewriter';

@@ -39,37 +40,24 @@ declare module 'module' {

interface AgentifyOptions {
install: boolean;
svcList: string[];
// TODO: this is now much larger with all of the existing core deps
export interface Core {
readonly config: Config;
readonly depHooks: RequireHook;
readonly logger: Logger;
readonly rewriter: Rewriter;
}
interface AgentOptions<T> {
install: boolean;
preRunMain: PreRunMain<T>;
export interface AgentifyOptions {
installOrder?: string[];
}
declare class Agent<T> {
constructor(deps: T, opts: AgentOptions<T>);
hookRunMain(): void;
handleInstallFailure(err: Error): Promise<void>;
install(): Promise<void>;
export interface PreRunMain {
(core: any): Installable | void | Promise<Installable | void>;
}
interface PreRunMain<T> {
(core: T, agent: Agent<T>): void | Promise<void>;
export interface Agentify {
(preRunMain: PreRunMain, opts?: AgentifyOptions): any;
}
export interface Agentify<T> {
(preRunMain: PreRunMain<T>, opts?: AgentifyOptions): Agent<T>;
}
declare function init(core: any): Agentify;
export interface Core<T> {
readonly config: Config;
readonly depHooks: RequireHook;
readonly logger: Logger;
readonly rewriter: Rewriter;
agentify: Agentify<T>;
}
declare function init<T>(core: Core<T>): Agentify<T>;
export = init;

@@ -18,152 +18,126 @@ /*

const fs = require('fs').promises;
const path = require('path');
const Module = require('module');
const defaultOpts = {
installOrder: [
'reporter',
'contrastMethods',
'deadzones',
'scopes',
'sources',
'architectureComponents',
'assess',
'protect',
'depHooks',
'routeCoverage',
'libraryAnalysis',
'heapSnapshots',
'rewriteHooks',
'functionHooks'
]
};
const ERROR_MESSAGE = 'A fatal agent installation error has occurred. The application will be run without instrumentation.';
const DEFAULT_INSTALL_ORDER = [
'reporter',
'contrastMethods',
'deadzones',
'scopes',
'sources',
'architectureComponents',
'assess',
'protect',
'depHooks',
'routeCoverage',
'libraryAnalysis',
'heapSnapshots',
'rewriteHooks',
'functionHooks',
'metrics',
];
module.exports = function (core) {
// compose add'l local services
require('./heap-snapshots')(core);
require('./sources')(core);
require('./function-hooks')(core);
require('./rewrite-hooks')(core);
/**
* @param {any} core
* @returns {import('.').Agentify}
*/
module.exports = function init(core = {}) {
try {
require('@contrast/core/lib/events')(core);
require('@contrast/config')(core);
require('@contrast/logger').default(core);
// @contrast/info ?
require('@contrast/core/lib/agent-info')(core);
require('@contrast/core/lib/system-info')(core);
require('@contrast/core/lib/app-info')(core);
require('@contrast/core/lib/sensitive-data-masking')(core);
require('@contrast/core/lib/is-agent-path')(core);
require('@contrast/core/lib/capture-stacktrace')(core);
/**
* The interface is a function, which when called, will hook runMain
* @param {function} preRunMain
* @param {object} opts
*/
function agentify(preRunMain, opts = defaultOpts) {
if (typeof preRunMain !== 'function') {
throw new Error('Invalid usage: first argument must be a function');
}
require('@contrast/patcher')(core);
require('@contrast/rewriter')(core); // merge contrast-methods?
require('@contrast/core/lib/contrast-methods')(core); // can we remove dependency on patcher?
opts.preRunMain = preRunMain;
require('@contrast/dep-hooks')(core);
require('@contrast/scopes')(core);
require('@contrast/deadzones')(core);
require('@contrast/reporter').default(core);
require('@contrast/instrumentation')(core);
require('@contrast/metrics')(core);
if (opts !== defaultOpts) {
opts = { ...defaultOpts, ...opts };
}
// compose add'l local services
require('./heap-snapshots')(core);
require('./sources')(core);
require('./function-hooks')(core);
require('./log-diagnostic-files')(core); // this doesn't really belong in agentify
require('./rewrite-hooks')(core);
return new Agent(core, opts);
}
/**
* The interface is a function, which when called, will hook runMain
* @type {import('.').Agentify}
*/
core.agentify = function agentify(
preRunMain,
{ installOrder = DEFAULT_INSTALL_ORDER } = {},
) {
if (typeof preRunMain !== 'function') {
throw new Error('Invalid usage: first argument must be a function');
}
core.agentify = agentify;
const { runMain } = Module;
const { config, logger } = core;
return agentify;
};
/**
* This is one side effect that will always occur, even with `installOrder: []`.
* The act of calling `agentify()` is enough to cause this side effect, by design.
*/
Module.runMain = async function (...args) {
try {
for (const err of config._errors) {
throw err; // move this into config itself since we now handle errors
}
class Agent {
/**
*
* @param {object} core dependencies
* @param {object} opts
* @param {function} opts.preRunMain custom function for registering services
* @param {boolean} opts.install whether to automatically install
*/
constructor(core, opts) {
const self = this;
const { config, logger } = core;
logger.info('Starting %s v%s', core.agentName, core.agentVersion);
logger.info({ config }, 'Agent configuration');
this.core = core;
this.opts = opts;
this.runMain = Module.runMain;
const plugin = await preRunMain(core);
/**
* This is one side effect that will always occur, even with `install: false`.
* The act of calling `agentify()` is enough to cause this side effect, by design.
*/
Module.runMain = async function (...args) {
try {
for (const err of config._errors) {
throw err;
}
for (const svcName of installOrder ?? []) {
const svc = core[svcName];
if (svc?.install) {
logger.trace('installing service: %s', svcName);
await svc.install();
}
}
logger.info('Starting the Contrast agent');
logger.info({ config }, 'Agent configuration');
if (plugin?.install) {
await plugin.install();
}
const plugin = await opts.preRunMain(core);
if (opts.installOrder?.length) {
await self.install();
core.logDiagnosticFiles(); // should this be moved into a separate install side-effect?
} catch (err) {
// TODO: Consider proper UNINSTALLATION and normal startup w/o agent
logger.error({ err }, ERROR_MESSAGE);
}
if (plugin?.install) {
await plugin.install();
}
} catch (err) {
await self.handleInstallFailure(err);
}
return runMain.apply(this, args);
};
self.logDiagnosticFiles();
return self.runMain.apply(this, args);
return core;
};
}
/**
* Original `runMain` will get called after this.
*
* TODO: Consider proper UNINSTALLATION and normal startup w/o agent
*
* @param {error} err Error thrown during install
*/
async handleInstallFailure(err) {
this.core.logger.error(
{ err },
'A fatal agent installation error has occurred. The application will be run without instrumentation.'
);
}
async install() {
for (const svcName of this.opts.installOrder) {
const svc = this.core[svcName];
if (svc?.install) {
this.core.logger.trace('installing service: %s', svcName);
await svc.install();
}
} catch (err) {
// TODO: Consider proper UNINSTALLATION and normal startup w/o agent
if (core.logger) {
core.logger.error({ err }, ERROR_MESSAGE);
} else {
console.error(new Error(ERROR_MESSAGE, { cause: err }));
}
}
logDiagnosticFiles() {
const { config, logger } = this.core;
if (!config.agent.diagnostics.enable) return;
const { report_path } = config.agent.diagnostics;
// let these run async so they don't block agent startup.
fs.writeFile(
path.join(report_path, 'contrast_effective_config.json'),
JSON.stringify(config.getReport({ redact: true }), null, 2)
).catch((err) => {
logger.warn({ err }, 'unable to write effective config file');
});
fs.writeFile(
path.join(report_path, 'contrast_system_info.json'),
JSON.stringify(this.core.getSystemInfo(), null, 2)
).catch((err) => {
logger.warn({ err }, 'unable to write system info file');
});
core.agentify = function agentify() {
return core;
};
}
}
module.exports.Agent = Agent;
return core.agentify;
};
{
"name": "@contrast/agentify",
"version": "1.15.0",
"version": "1.16.0",
"description": "Configures Contrast agent services and instrumentation within an application",

@@ -21,5 +21,14 @@ "license": "SEE LICENSE IN LICENSE",

"@contrast/common": "1.15.1",
"@contrast/config": "1.20.0",
"@contrast/logger": "1.6.0"
"@contrast/config": "1.21.0",
"@contrast/core": "1.26.1",
"@contrast/deadzones": "1.1.1",
"@contrast/dep-hooks": "^1.3.0",
"@contrast/instrumentation": "^1.2.1",
"@contrast/logger": "1.7.0",
"@contrast/metrics": "1.1.0",
"@contrast/patcher": "1.7.1",
"@contrast/reporter": "1.21.1",
"@contrast/rewriter": "^1.4.2",
"@contrast/scopes": "^1.4.0"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc