Skip to content

Commit

Permalink
add guardrail to completely bail out in very old versions (#4878)
Browse files Browse the repository at this point in the history
  • Loading branch information
rochdev authored Nov 12, 2024
1 parent 29ff735 commit 1e1a2a1
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 49 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ jobs:
- uses: ./.github/actions/install
- run: node node_modules/.bin/mocha --colors --timeout 30000 integration-tests/init.spec.js

integration-guardrails-unsupported:
strategy:
matrix:
version: ['0.10', '4', '6', '8', '10']
runs-on: ubuntu-latest
env:
DD_INJECTION_ENABLED: 'true'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.version }}
- run: node ./init

integration-ci:
strategy:
matrix:
Expand Down
107 changes: 60 additions & 47 deletions init.js
Original file line number Diff line number Diff line change
@@ -1,58 +1,71 @@
'use strict'

const path = require('path')
const Module = require('module')
const semver = require('semver')
const log = require('./packages/dd-trace/src/log')
const { isTrue } = require('./packages/dd-trace/src/util')
const telemetry = require('./packages/dd-trace/src/telemetry/init-telemetry')
/* eslint-disable no-var */

let initBailout = false
let clobberBailout = false
const forced = isTrue(process.env.DD_INJECT_FORCE)
var NODE_MAJOR = require('./version').NODE_MAJOR

if (process.env.DD_INJECTION_ENABLED) {
// If we're running via single-step install, and we're not in the app's
// node_modules, then we should not initialize the tracer. This prevents
// single-step-installed tracer from clobbering the manually-installed tracer.
let resolvedInApp
const entrypoint = process.argv[1]
try {
resolvedInApp = Module.createRequire(entrypoint).resolve('dd-trace')
} catch (e) {
// Ignore. If we can't resolve the module, we assume it's not in the app.
}
if (resolvedInApp) {
const ourselves = path.join(__dirname, 'index.js')
if (ourselves !== resolvedInApp) {
clobberBailout = true
// We use several things that are not supported by older versions of Node:
// - AsyncLocalStorage
// - The `semver` module
// - dc-polyfill
// - Mocha (for testing)
// and probably others.
// TODO: Remove all these dependencies so that we can report telemetry.
if (NODE_MAJOR >= 12) {
var path = require('path')
var Module = require('module')
var semver = require('semver')
var log = require('./packages/dd-trace/src/log')
var isTrue = require('./packages/dd-trace/src/util').isTrue
var telemetry = require('./packages/dd-trace/src/telemetry/init-telemetry')

var initBailout = false
var clobberBailout = false
var forced = isTrue(process.env.DD_INJECT_FORCE)

if (process.env.DD_INJECTION_ENABLED) {
// If we're running via single-step install, and we're not in the app's
// node_modules, then we should not initialize the tracer. This prevents
// single-step-installed tracer from clobbering the manually-installed tracer.
var resolvedInApp
var entrypoint = process.argv[1]
try {
resolvedInApp = Module.createRequire(entrypoint).resolve('dd-trace')
} catch (e) {
// Ignore. If we can't resolve the module, we assume it's not in the app.
}
if (resolvedInApp) {
var ourselves = path.join(__dirname, 'index.js')
if (ourselves !== resolvedInApp) {
clobberBailout = true
}
}
}

// If we're running via single-step install, and the runtime doesn't match
// the engines field in package.json, then we should not initialize the tracer.
if (!clobberBailout) {
const { engines } = require('./package.json')
const version = process.versions.node
if (!semver.satisfies(version, engines.node)) {
initBailout = true
telemetry([
{ name: 'abort', tags: ['reason:incompatible_runtime'] },
{ name: 'abort.runtime', tags: [] }
])
log.info('Aborting application instrumentation due to incompatible_runtime.')
log.info(`Found incompatible runtime nodejs ${version}, Supported runtimes: nodejs ${engines.node}.`)
if (forced) {
log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.')
// If we're running via single-step install, and the runtime doesn't match
// the engines field in package.json, then we should not initialize the tracer.
if (!clobberBailout) {
var engines = require('./package.json').engines
var version = process.versions.node
if (!semver.satisfies(version, engines.node)) {
initBailout = true
telemetry([
{ name: 'abort', tags: ['reason:incompatible_runtime'] },
{ name: 'abort.runtime', tags: [] }
])
log.info('Aborting application instrumentation due to incompatible_runtime.')
log.info('Found incompatible runtime nodejs ' + version + ', Supported runtimes: nodejs ' + engines.node + '.')
if (forced) {
log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.')
}
}
}
}
}

if (!clobberBailout && (!initBailout || forced)) {
const tracer = require('.')
tracer.init()
module.exports = tracer
telemetry('complete', [`injection_forced:${forced && initBailout ? 'true' : 'false'}`])
log.info('Application instrumentation bootstrapping complete')
if (!clobberBailout && (!initBailout || forced)) {
var tracer = require('.')
tracer.init()
module.exports = tracer
telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')])
log.info('Application instrumentation bootstrapping complete')
}
}
6 changes: 4 additions & 2 deletions version.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
'use strict'

const ddMatches = require('./package.json').version.match(/^(\d+)\.(\d+)\.(\d+)/)
const nodeMatches = process.versions.node.match(/^(\d+)\.(\d+)\.(\d+)/)
/* eslint-disable no-var */

var ddMatches = require('./package.json').version.match(/^(\d+)\.(\d+)\.(\d+)/)
var nodeMatches = process.versions.node.match(/^(\d+)\.(\d+)\.(\d+)/)

module.exports = {
DD_MAJOR: parseInt(ddMatches[1]),
Expand Down

0 comments on commit 1e1a2a1

Please sign in to comment.