mirror of
https://github.com/hanzoai/scarf-js.git
synced 2026-09-24 17:02:30 +00:00
* get git sha on install * we should only inject sha if the root package allows top level * only get the git sha from root when root = parent * fix up parentIsRoot to be safe against optional values * update runner matrix to supported node.js versions see https://github.com/nodejs/Release/tree/7b8e0ac1b97b4ce4057e64ae024995052408926a#release-schedule * update runner matrix to supported node.js versions see https://github.com/nodejs/Release/tree/7b8e0ac1b97b4ce4057e64ae024995052408926a#release-schedule
176 lines
7.3 KiB
JavaScript
176 lines
7.3 KiB
JavaScript
const report = require('../report')
|
|
const fs = require('fs')
|
|
|
|
const rateLimitKey = 'testKey'
|
|
const tmpFileReturnVal = './scarf-js-test-history.log'
|
|
const scarfExecPath = '/path/scarfed-lib-consumer-consumer/node_modules/@scarf/scarf'
|
|
|
|
function wipeLogHistoryIfPresent () {
|
|
try {
|
|
fs.unlinkSync(tmpFileReturnVal)
|
|
} catch (e) {}
|
|
}
|
|
|
|
describe('Reporting tests', () => {
|
|
beforeAll(() => {
|
|
report.tmpFileName = jest.fn(() => {
|
|
return tmpFileReturnVal
|
|
})
|
|
report.dirName = jest.fn(() => {
|
|
return scarfExecPath
|
|
})
|
|
wipeLogHistoryIfPresent()
|
|
})
|
|
|
|
afterAll(() => {
|
|
wipeLogHistoryIfPresent()
|
|
})
|
|
|
|
test('Logging rate limit check', () => {
|
|
let history = report.getRateLimitedLogHistory()
|
|
expect(report.hasHitRateLimit(rateLimitKey, history)).toBe(false)
|
|
report.rateLimitedUserLog(rateLimitKey, 'A user message')
|
|
history = report.getRateLimitedLogHistory()
|
|
expect(report.hasHitRateLimit(rateLimitKey, history)).toBe(true)
|
|
})
|
|
|
|
test('Redact sensitive data', () => {
|
|
const rootPackageName = '@org/scarfed-lib-consumer-consumer'
|
|
const rootPackageVersion = '1.0.0'
|
|
const grandparentName = 'scarfed-lib-consumer'
|
|
const grandparentVersion = '1.0.1'
|
|
|
|
const depInfo = {
|
|
scarf: { name: '@scarf/scarf', version: '0.0.1', path: '/local/directory/deeper/deeper' },
|
|
parent: { name: 'scarfed-library', version: '1.0.0', scarfSettings: { defaultOptIn: true }, path: '/local/directory/deeper/' },
|
|
grandparent: { name: grandparentName, version: grandparentVersion, path: '/local/directory/' },
|
|
rootPackage: { name: rootPackageName, version: rootPackageVersion, packageJsonPath: '/local/directory', path: '/local/directory' }
|
|
}
|
|
|
|
const redacted = report.redactSensitivePackageInfo(depInfo)
|
|
|
|
expect(redacted.scarf.path).toBeUndefined()
|
|
expect(redacted.parent.path).toBeUndefined()
|
|
expect(redacted.grandparent.path).toBeUndefined()
|
|
expect(redacted.rootPackage.path).toBeUndefined()
|
|
expect(redacted.rootPackage.packageJsonPath).toBeUndefined()
|
|
|
|
expect(redacted.grandparent.nameHash).toBe(report.hashWithDefault(grandparentName, 'Fail: used hash fallback for name'))
|
|
expect(redacted.grandparent.versionHash).toBe(report.hashWithDefault(grandparentVersion, 'Fail: used hash fallback for version'))
|
|
expect(redacted.rootPackage.nameHash).toBe(report.hashWithDefault(rootPackageName, 'Fail: used hash fallback for name'))
|
|
expect(redacted.rootPackage.versionHash).toBe(report.hashWithDefault(rootPackageVersion, 'Fail: used hash fallback for version'))
|
|
|
|
expect(redacted.grandparent.name).toBeUndefined()
|
|
expect(redacted.grandparent.version).toBeUndefined()
|
|
expect(redacted.rootPackage.name).toBeUndefined()
|
|
expect(redacted.rootPackage.version).toBeUndefined()
|
|
|
|
expect(redacted.scarf.name).toBe('@scarf/scarf')
|
|
expect(redacted.scarf.version).toBe('0.0.1')
|
|
|
|
expect(redacted.parent.name).toBe('scarfed-library')
|
|
expect(redacted.parent.version).toBe('1.0.0')
|
|
})
|
|
|
|
test('Intermediate packages can disable Scarf for their dependents', async () => {
|
|
const exampleLsOutput = fs.readFileSync('./test/example-ls-output.json')
|
|
|
|
await expect(new Promise((resolve, reject) => {
|
|
return report.processDependencyTreeOutput(resolve, reject)(null, exampleLsOutput, null)
|
|
})).rejects.toEqual(new Error('Scarf has been disabled via a package.json in the dependency chain.'))
|
|
|
|
const parsedLsOutput = JSON.parse(exampleLsOutput)
|
|
delete (parsedLsOutput.dependencies['scarfed-lib-consumer'].scarfSettings)
|
|
|
|
await new Promise((resolve, reject) => {
|
|
return report.processDependencyTreeOutput(resolve, reject)(null, JSON.stringify(parsedLsOutput), null)
|
|
}).then(output => {
|
|
expect(output).toBeTruthy()
|
|
expect(output.anyInChainDisabled).toBe(false)
|
|
})
|
|
})
|
|
|
|
test('Disable when package manager is yarn', async () => {
|
|
const parsedLsOutput = dependencyTreeScarfEnabled()
|
|
|
|
await new Promise((resolve, reject) => {
|
|
return report.processDependencyTreeOutput(resolve, reject)(null, JSON.stringify(parsedLsOutput), null)
|
|
}).then(output => {
|
|
expect(output).toBeTruthy()
|
|
expect(output.anyInChainDisabled).toBe(false)
|
|
})
|
|
|
|
// Simulate a yarn install by mocking the env variable npm_execpath
|
|
// leading to a yarn executable
|
|
report.npmExecPath = jest.fn(() => {
|
|
return '/usr/local/lib/node_modules/yarn/bin/yarn.js'
|
|
})
|
|
|
|
report.getDependencyInfo = jest.fn(() => {
|
|
return Promise.resolve({
|
|
scarf: { name: '@scarf/scarf', version: '0.0.1' },
|
|
parent: { name: 'scarfed-library', version: '1.0.0', scarfSettings: { defaultOptIn: true } },
|
|
grandparent: { name: 'scarfed-lib-consumer', version: '1.0.0' }
|
|
})
|
|
})
|
|
|
|
try {
|
|
await report.reportPostInstall()
|
|
throw new Error("report.reportPostInstall() didn't throw an error")
|
|
} catch (err) {
|
|
expect(err.message).toContain('yarn')
|
|
}
|
|
})
|
|
|
|
test('Configurable for top level installs, and enabled for global installs', async () => {
|
|
const parsedLsOutput = dependencyTreeTopLevelInstall()
|
|
|
|
await expect(new Promise((resolve, reject) => {
|
|
return report.processDependencyTreeOutput(resolve, reject)(null, JSON.stringify(parsedLsOutput), null)
|
|
})).rejects.toEqual(new Error('The package depending on Scarf is the root package being installed, but Scarf is not configured to run in this case. To enable it, set `scarfSettings.allowTopLevel = true` in your package.json'))
|
|
|
|
process.env.npm_config_global = true
|
|
|
|
await expect(new Promise((resolve, reject) => {
|
|
return report.processDependencyTreeOutput(resolve, reject)(null, JSON.stringify(parsedLsOutput), null)
|
|
})).toBeTruthy()
|
|
|
|
process.env.npm_config_global = ''
|
|
parsedLsOutput.scarfSettings = { allowTopLevel: true }
|
|
|
|
await expect(new Promise((resolve, reject) => {
|
|
return report.processDependencyTreeOutput(resolve, reject)(null, JSON.stringify(parsedLsOutput), null)
|
|
})).toBeTruthy()
|
|
|
|
parsedLsOutput.scarfSettings = { allowTopLevel: false }
|
|
await expect(new Promise((resolve, reject) => {
|
|
return report.processDependencyTreeOutput(resolve, reject)(null, JSON.stringify(parsedLsOutput), null)
|
|
})).rejects.toEqual(new Error('The package depending on Scarf is the root package being installed, but Scarf is not configured to run in this case. To enable it, set `scarfSettings.allowTopLevel = true` in your package.json'))
|
|
})
|
|
|
|
test('Can parse example git rev-parse HEAD output', async () => {
|
|
await expect(new Promise((resolve, reject) => {
|
|
return report.processGitRevParseOutput(resolve, reject)(null, '9ace16b9e3833ad4e761a49f17fe607723d5bd5e\n', null)
|
|
})).resolves.toEqual('9ace16b9e3833ad4e761a49f17fe607723d5bd5e')
|
|
})
|
|
|
|
test('getGitShaFromRootPath resolves in test run of cloned repository', async () => {
|
|
await expect(report.getGitShaFromRootPath()).resolves.toBeTruthy()
|
|
})
|
|
})
|
|
|
|
function dependencyTreeScarfEnabled () {
|
|
const exampleLsOutput = fs.readFileSync('./test/example-ls-output.json')
|
|
|
|
const parsedLsOutput = JSON.parse(exampleLsOutput)
|
|
delete (parsedLsOutput.dependencies['scarfed-lib-consumer'].scarfSettings)
|
|
|
|
return parsedLsOutput
|
|
}
|
|
|
|
function dependencyTreeTopLevelInstall () {
|
|
const exampleLsOutput = fs.readFileSync('./test/top-level-package-ls-output.json')
|
|
const parsedLsOutput = JSON.parse(exampleLsOutput)
|
|
return parsedLsOutput
|
|
}
|