@scarf/scarf
Advanced tools
Comparing version 0.1.4 to 0.1.5
{ | ||
"name": "@scarf/scarf", | ||
"version": "0.1.4", | ||
"version": "0.1.5", | ||
"description": "Scarf is like Google Analytics for your npm packages. Gain insights into how your packages are installed and used, and by which companies.", | ||
"main": "report.js", | ||
"homepage": "https://github.com/scarf-sh/scarf-js", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/scarf-sh/scarf-js.git" | ||
}, | ||
"files": [ | ||
@@ -7,0 +12,0 @@ "report.js" |
@@ -69,12 +69,31 @@ # scarf-js | ||
- The operating system you are using | ||
- The version of the package you're installing that depends on Scarf | ||
- Your IP address will be used to look up any available company information. The | ||
IP address itself will be subsequently deleted | ||
IP address itself will be subsequently deleted. | ||
- Dependency tree information. Scarf sends the package name and version for | ||
certain packages (provided they are not scoped packages, `@org/package-name`, | ||
which are assumed to be private): | ||
- Packages in the dependency tree that directly depend on | ||
Scarf. | ||
- Packages that depend on a package that depends on Scarf. | ||
- The root package of the dependency tree. | ||
### As a user of a package using Scarf, how can I opt out of analytics? | ||
Scarf's analytics help support developers of the open source packages you are using, so | ||
and leaving the anlytics enabled is appreciated. However, if you'd like to opt out, | ||
set this variable in your environment: | ||
Scarf's analytics help support developers of the open source packages you are | ||
using, so enabling analytics is appreciated. However, if you'd like to opt out, | ||
you can add your preference to your project's `package.json`: | ||
```json5 | ||
// your-package/package.json | ||
{ | ||
// ... | ||
"scarfSettings": { | ||
"enabled": false | ||
} | ||
// ... | ||
} | ||
``` | ||
Alternatively, you can set this variable in your environment: | ||
```shell | ||
@@ -84,2 +103,4 @@ export SCARF_ANALYTICS=false | ||
Either route will disable Scarf for all packages. | ||
### Developing | ||
@@ -86,0 +107,0 @@ |
101
report.js
@@ -11,2 +11,4 @@ const path = require('path') | ||
const rootPath = path.resolve(__dirname).split('node_modules')[0] | ||
const makeDefaultSettings = () => { | ||
@@ -34,3 +36,4 @@ return { | ||
function redactScopedPackageInfo (dependencyInfo) { | ||
// We don't send any paths, we don't send any scoped package names or versions | ||
function redactSensitivePackageInfo (dependencyInfo) { | ||
const scopedRegex = /@\S+\// | ||
@@ -47,2 +50,9 @@ const privatePackageRewrite = '@private/private' | ||
} | ||
delete (dependencyInfo.rootPackage.packageJsonPath) | ||
delete (dependencyInfo.rootPackage.path) | ||
delete (dependencyInfo.parent.path) | ||
delete (dependencyInfo.scarf.path) | ||
if (dependencyInfo.grandparent) { | ||
delete (dependencyInfo.grandparent.path) | ||
} | ||
return dependencyInfo | ||
@@ -52,7 +62,4 @@ } | ||
async function getDependencyInfo () { | ||
const moduleSeparated = path.resolve(__dirname).split('node_modules') | ||
const dependentPath = moduleSeparated.slice(0, moduleSeparated.length - 1).join('node_modules') | ||
return new Promise((resolve, reject) => { | ||
exec(`cd ${dependentPath} && npm ls @scarf/scarf --json --long`, function (error, stdout, stderr) { | ||
exec(`cd ${rootPath} && npm ls @scarf/scarf --json --long`, function (error, stdout, stderr) { | ||
if (error) { | ||
@@ -64,4 +71,5 @@ return reject(new Error(`Scarf received an error from npm -ls: ${error}`)) | ||
const depsToScarf = findScarfInFullDependencyTree(output) | ||
if (depsToScarf.length < 2) { | ||
let depsToScarf = findScarfInFullDependencyTree(output) | ||
depsToScarf = depsToScarf.filter(depChain => depChain.length > 2) | ||
if (depsToScarf.length === 0) { | ||
return reject(new Error('No Scarf parent package found')) | ||
@@ -72,13 +80,22 @@ } | ||
const dependencyInfo = { | ||
scarf: depsToScarf[depsToScarf.length - 1], | ||
parent: depsToScarf[depsToScarf.length - 2], | ||
grandparent: depsToScarf[depsToScarf.length - 3], // might be undefined | ||
rootPackage: rootPackageDetails | ||
const dependencyInfo = depsToScarf.map(depChain => { | ||
return { | ||
scarf: depChain[depChain.length - 1], | ||
parent: depChain[depChain.length - 2], | ||
grandparent: depChain[depChain.length - 3], // might be undefined | ||
rootPackage: rootPackageDetails | ||
} | ||
}) | ||
dependencyInfo.forEach(d => { | ||
d.parent.scarfSettings = Object.assign(makeDefaultSettings(), d.parent.scarfSettings || {}) | ||
}) | ||
// Here, we find the dependency chain that corresponds to the scarf package we're currently in | ||
const dependencyToReport = dependencyInfo.find(dep => (dep.scarf.path === __dirname)) | ||
if (!dependencyToReport) { | ||
return reject(new Error(`Couldn't find dependency info for path ${__dirname}`)) | ||
} | ||
dependencyInfo.parent.scarfSettings = Object.assign(makeDefaultSettings(), dependencyInfo.parent.scarfSettings || {}) | ||
redactScopedPackageInfo(dependencyInfo) | ||
return resolve(dependencyInfo) | ||
return resolve(dependencyToReport) | ||
}) | ||
@@ -183,3 +200,3 @@ }) | ||
delete (dependencyInfo.rootPackage.packageJsonPath) | ||
redactSensitivePackageInfo(dependencyInfo) | ||
@@ -192,3 +209,5 @@ const infoPayload = { | ||
} | ||
const data = JSON.stringify(infoPayload) | ||
logIfVerbose(`Scarf payload: ${data}`) | ||
@@ -227,12 +246,12 @@ const reqOptions = { | ||
// Find a path to Scarf from the json output of npm ls @scarf/scarf --json in | ||
// the package that's directly including Scarf | ||
// Find all paths to Scarf from the json output of npm ls @scarf/scarf --json in | ||
// the root package being installed by the user | ||
// | ||
// { | ||
// [{ | ||
// scarfPackage: {name: `@scarf/scarf`, version: '0.0.1'}, | ||
// parentPackage: { name: 'scarfed-library', version: '1.0.0', scarfSettings: { defaultOptIn: true } }, | ||
// grandparentPackage: { name: 'scarfed-lib-consumer', version: '1.0.0' } | ||
// } | ||
// }] | ||
function findScarfInSubDepTree (pathToDep, deps) { | ||
const depNames = Object.keys(deps) | ||
const depNames = Object.keys(deps || {}) | ||
@@ -244,22 +263,25 @@ if (!depNames) { | ||
const scarfFound = depNames.find(depName => depName === scarfLibName) | ||
const output = [] | ||
if (scarfFound) { | ||
return pathToDep.concat([{ name: scarfLibName, version: deps[scarfLibName].version }]) | ||
} else { | ||
for (let i = 0; i < depNames.length; i++) { | ||
const depName = depNames[i] | ||
const newPathToDep = pathToDep.concat([ | ||
{ | ||
name: depName, | ||
version: deps[depName].version, | ||
scarfSettings: deps[depName].scarfSettings | ||
} | ||
]) | ||
const result = findScarfInSubDepTree(newPathToDep, deps[depName].dependencies) | ||
if (result) { | ||
return result | ||
output.push(pathToDep.concat([{ name: scarfLibName, version: deps[scarfLibName].version, path: deps[scarfLibName].path }])) | ||
} | ||
for (let i = 0; i < depNames.length; i++) { | ||
const depName = depNames[i] | ||
const newPathToDep = pathToDep.concat([ | ||
{ | ||
name: depName, | ||
version: deps[depName].version, | ||
scarfSettings: deps[depName].scarfSettings, | ||
path: deps[depName].path | ||
} | ||
]) | ||
const results = findScarfInSubDepTree(newPathToDep, deps[depName].dependencies) | ||
if (results) { | ||
for (let j = 0; j < results.length; j++) { | ||
output.push(results[j]) | ||
} | ||
} | ||
} | ||
return [] | ||
return output | ||
} | ||
@@ -269,3 +291,3 @@ | ||
if (tree.name === scarfLibName) { | ||
return [{ name: scarfLibName, version: tree.version }] | ||
return [[{ name: scarfLibName, version: tree.version }]] | ||
} else { | ||
@@ -280,3 +302,4 @@ return findScarfInSubDepTree([packageDetailsFromDepInfo(tree)], tree.dependencies) | ||
version: tree.version, | ||
scarfSettings: tree.scarfSettings | ||
scarfSettings: tree.scarfSettings, | ||
path: tree.path | ||
} | ||
@@ -283,0 +306,0 @@ } |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 5 instances in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
16235
279
0
1
113
13