diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 5518eacca..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "env": { - "browser": false, - "es6": true, - "node": true, - "mocha": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module" - }, - "rules": { - "indent": ["error", 2, { "SwitchCase": 1 }], - "quotes": ["error", "single"], - "semi": ["error", "never"], - "no-console": 0 - } -} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index caaf4fc1a..340535fcf 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,8 +4,22 @@ updates: directory: '/' schedule: interval: weekly + groups: + dev-dependencies: + dependency-type: 'development' - package-ecosystem: 'github-actions' directory: '/' schedule: interval: 'weekly' + groups: + azure-actions: + patterns: + - 'azure/*' + docker-actions: + patterns: + - 'docker/*' + github-actions: + patterns: + - 'actions/*' + - 'github/*' diff --git a/.github/workflows/build-and-deploy-dev.yml b/.github/workflows/build-and-deploy-dev.yml index ba08dd167..5a9b83a1c 100644 --- a/.github/workflows/build-and-deploy-dev.yml +++ b/.github/workflows/build-and-deploy-dev.yml @@ -1,95 +1,21 @@ # This workflow will build a docker image, push it to ghcr.io, and deploy it to an Azure WebApp. -name: Build and Deploy to dev service app +name: Build and Deploy -- DEV -# Update the triggers based on the environment that is being deployed to. -# Triggers for dev deployments: 1) manually triggered, 2) push to branch `master` -# Triggers for prod deployments: 1) manually triggered, 2) release created on: workflow_dispatch: push: branches: [master] -# There are secrets and environment variables that need to be set that control what is pushed to -# ghcr and Azure. -# -# Secrets: -# AZURE_CREDENTIALS: service principal that has access to the Azure WebApp -# AZURE_WEBAPP_PUBLISH_PROFILE_DEV: publish profile for the Azure WebApp NOTE: The name of the secret changes. For dev, it ends in `_DEV`. Production does not have an extension. -# -# Environment Variables: -# APPLICATION_TYPE: type of application that is being deployed; used to add a label to the Docker image (values: api | web | worker) -# AZURE_WEBAPP_NAME: name of the Azure WebApp being deployed -# DEPLOY_ENVIRONMENT: environment that the code is being deployed to; used to add a label to the Docker image (values: dev | prod) -# DEPLOY_DOCKER_TAG: the tag used for deploying a specific Docker image to Azure. For dev, use the `github.sha`. For production, use the SEMVER -# version of the release. Make sure to add this tag to the `DOCKER_TAGS` in the `Build and push Docker image` step. -# DOCKER_IMAGE_NAME: name of the Docker image that is being built and pushed to ghcr.io. - -env: - APPLICATION_TYPE: api - AZURE_WEBAPP_NAME: clearlydefined-api-dev - DEPLOY_ENVIRONMENT: dev - DEPLOY_DOCKER_TAG: ${{ github.sha }} - DOCKER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/${{ github.repository }}-dev - jobs: build-and-deploy: - name: Build and Deploy - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Log into ghcr registry - uses: docker/login-action@v3.0.0 - with: - registry: ghcr.io - username: ${{ github.actor }} # user that kicked off the action - password: ${{ secrets.GITHUB_TOKEN }} # token created when the action launched (short lived) - - - name: Build and push Docker image - env: - DOCKER_TAGS: | - ${{ env.DOCKER_IMAGE_NAME }}:${{ env.DEPLOY_DOCKER_TAG }} - uses: docker/build-push-action@v5.1.0 - with: - context: . - push: true - file: Dockerfile - tags: ${{ env.DOCKER_TAGS }} - labels: | - env=${{ env.DEPLOY_ENVIRONMENT }} - type=${{ env.APPLICATION_TYPE }} - - - name: Login for Azure cli commands - uses: azure/login@v1.6.1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - - name: Set DOCKER configs in Azure web app - uses: azure/appservice-settings@v1.1.1 - with: - app-name: ${{ env.AZURE_WEBAPP_NAME }} - app-settings-json: | - [ - { - "name": "DOCKER_CUSTOM_IMAGE_NAME", - "value": "${{ env.DOCKER_IMAGE_NAME }}:${{ env.DEPLOY_DOCKER_TAG }}", - "slotSetting": false - }, - { - "name": "DOCKER_REGISTRY_SERVER_URL", - "value": "https://ghcr.io", - "slotSetting": false - }, - { - "name": "BUILD_SHA", - "value": "${{ github.sha }}", - "slotSetting": false - } - ] - - - name: Deploy to Azure WebApp - uses: azure/webapps-deploy@v3.0.0 - with: - app-name: ${{ env.AZURE_WEBAPP_NAME }} - publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_DEV }} - images: '${{ env.DOCKER_IMAGE_NAME }}:${{ env.DEPLOY_DOCKER_TAG }}' + uses: clearlydefined/operations/.github/workflows/app-build-and-deploy.yml@v1.0.0 + secrets: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + AZURE_WEBAPP_PUBLISH_PROFILE: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_DEV }} + DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} + PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }} + with: + deploy-env: dev + application-type: api + azure-app-base-name: clearlydefined-api + azure-app-name-postfix: -dev diff --git a/.github/workflows/build-and-deploy-prod.yml b/.github/workflows/build-and-deploy-prod.yml new file mode 100644 index 000000000..189a84562 --- /dev/null +++ b/.github/workflows/build-and-deploy-prod.yml @@ -0,0 +1,36 @@ +# This workflow will build a docker image, push it to ghcr.io, and deploy it to an Azure WebApp. +name: Build and Deploy -- PROD + +on: + workflow_dispatch: + release: + types: [published] + +jobs: + determine-trigger: + name: Determine if this was triggered by a release or workflow_dispatch + runs-on: ubuntu-latest + outputs: + is-release: ${{ env.IS_RELEASE }} + steps: + - name: Check if this was triggered by a release + id: release + run: | + echo "IS_RELEASE"=${{ github.event_name == 'release' }} >> $GITHUB_ENV + + build-and-deploy-prod: + uses: clearlydefined/operations/.github/workflows/app-build-and-deploy.yml@v1.0.0 + needs: determine-trigger + secrets: + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + AZURE_WEBAPP_PUBLISH_PROFILE: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_PROD }} + AZURE_SECONDARY_WEBAPP_PUBLISH_PROFILE: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_PROD_EU }} + DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }} + PRODUCTION_DEPLOYERS: ${{ secrets.PRODUCTION_DEPLOYERS }} + with: + deploy-env: prod + application-type: api + azure-app-base-name: clearlydefined-api + azure-app-name-postfix: -prod + secondary-azure-app-name-postfix: -prod-europe + is-release: ${{ needs.determine-trigger.outputs.is-release }} diff --git a/.github/workflows/build_and_deploy_prod.yml b/.github/workflows/build_and_deploy_prod.yml deleted file mode 100644 index 8c2e066cf..000000000 --- a/.github/workflows/build_and_deploy_prod.yml +++ /dev/null @@ -1,148 +0,0 @@ -# This workflow will build a docker image, push it to ghcr.io, and deploy it to an Azure WebApp. -name: Build and Deploy to prod service app - -# Update the triggers based on the environment that is being deployed to. -# Triggers for dev deployments: 1) manually triggered, 2) push to branch `master` -# Triggers for prod deployments: 1) manually triggered, 2) release [published] -on: - workflow_dispatch: - release: - types: [published] - -# There are secrets and environment variables that need to be set that control what is pushed to -# ghcr and Azure. -# -# Secrets: -# AZURE_CREDENTIALS_PROD: service principal that has access to the Azure prod WebApp -# AZURE_WEBAPP_PUBLISH_PROFILE: publish profile for the Azure WebApp -# AZURE_WEBAPP_PUBLISH_PROFILE_EU: publish profile for the Azure WebApp in Europe -# -# Environment Variables: -# APPLICATION_TYPE: type of application that is being deployed; used to add a label to the Docker image (values: api | web | worker) -# AZURE_WEBAPP_NAME: name of the Azure WebApp being deployed -# AZURE_EU_WEBAPP_NAME: name of the Azure WebApp being deployed -# DEPLOY_ENVIRONMENT: environment that the code is being deployed to; used to add a label to the Docker image (values: dev | prod) -# DEPLOY_DOCKER_TAG: _NOT used as a ENV for production. To be able to always have the version, get it from package.json._ -# DOCKER_IMAGE_NAME: name of the Docker image that is being built and pushed to ghcr.io. - -env: - APPLICATION_TYPE: api - AZURE_WEBAPP_NAME: clearlydefined-api-prod - AZURE_EU_WEBAPP_NAME: clearlydefined-api-prod-europe - DEPLOY_ENVIRONMENT: prod - # DEPLOY_DOCKER_TAG: ${{ github.event.release.tag_name }} - DOCKER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/${{ github.repository }} - -jobs: - build-and-deploy: - name: Build and Deploy - runs-on: ubuntu-latest - steps: - - name: Get version - id: package - run: | - echo "::set-output name=version::$(curl --silent "https://api.github.com/repos/clearlydefined/service/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')" - shell: bash - - - name: Use version - run: | - echo "Version is ${{ steps.package.outputs.version }}" - shell: bash - - - uses: actions/checkout@v4.1.1 - - - name: Log into ghcr registry - uses: docker/login-action@v3.0.0 - with: - registry: ghcr.io - username: ${{ github.actor }} # user that kicked off the action - password: ${{ secrets.GITHUB_TOKEN }} # token created when the action launched (short lived) - - - name: Build and push Docker image - env: - DOCKER_TAGS: | - ${{ env.DOCKER_IMAGE_NAME }}:${{ steps.package.outputs.version }} - uses: docker/build-push-action@v5.1.0 - with: - context: . - push: true - file: Dockerfile - tags: ${{ env.DOCKER_TAGS }} - labels: | - env=${{ env.DEPLOY_ENVIRONMENT }} - type=${{ env.APPLICATION_TYPE }} - - - name: Login for Azure cli commands - uses: azure/login@v1.6.1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS_PROD }} - - - name: Set DOCKER configs in Azure web app - uses: azure/appservice-settings@v1.1.1 - with: - app-name: ${{ env.AZURE_WEBAPP_NAME }} - app-settings-json: | - [ - { - "name": "DOCKER_CUSTOM_IMAGE_NAME", - "value": "${{ env.DOCKER_IMAGE_NAME }}:${{ steps.package.outputs.version }}", - "slotSetting": false - }, - { - "name": "DOCKER_REGISTRY_SERVER_URL", - "value": "https://ghcr.io", - "slotSetting": false - }, - { - "name": "APP_VERSION", - "value": "${{ steps.package.outputs.version }}", - "slotSetting": false - }, - { - "name": "BUILD_SHA", - "value": "${{ github.sha }}", - "slotSetting": false - } - ] - - - name: Deploy to Azure WebApp - uses: azure/webapps-deploy@v3.0.0 - with: - app-name: ${{ env.AZURE_WEBAPP_NAME }} - publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_PROD }} - images: '${{ env.DOCKER_IMAGE_NAME }}:${{ steps.package.outputs.version }}' - - - name: Set DOCKER configs in Azure EU web app - uses: azure/appservice-settings@v1.1.1 - with: - app-name: ${{ env.AZURE_EU_WEBAPP_NAME }} - app-settings-json: | - [ - { - "name": "DOCKER_CUSTOM_IMAGE_NAME", - "value": "${{ env.DOCKER_IMAGE_NAME }}:${{ steps.package.outputs.version }}", - "slotSetting": false - }, - { - "name": "DOCKER_REGISTRY_SERVER_URL", - "value": "https://ghcr.io", - "slotSetting": false - }, - { - "name": "APP_VERSION", - "value": "${{ steps.package.outputs.version }}", - "slotSetting": false - }, - { - "name": "BUILD_SHA", - "value": "${{ github.sha }}", - "slotSetting": false - } - ] - - - name: Deploy to Azure EU WebApp - uses: azure/webapps-deploy@v3.0.0 - with: - app-name: ${{ env.AZURE_EU_WEBAPP_NAME }} - publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_PROD_EU }} - images: '${{ env.DOCKER_IMAGE_NAME }}:${{ steps.package.outputs.version }}' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5e0ae2971..076689b29 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,7 @@ permissions: contents: read jobs: - build: + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -23,7 +23,7 @@ jobs: cache: 'npm' - name: Install dependencies - run: npm install + run: npm ci - name: Run tests run: npm test diff --git a/.github/workflows/update-scancode-licensedb.yml b/.github/workflows/update-scancode-licensedb.yml index cbd230b8e..b7f8bc2db 100644 --- a/.github/workflows/update-scancode-licensedb.yml +++ b/.github/workflows/update-scancode-licensedb.yml @@ -30,7 +30,7 @@ jobs: node ./scripts/transform-scancode-licensedb.js - name: Create Pull Request - uses: peter-evans/create-pull-request@v6.0.1 + uses: peter-evans/create-pull-request@v6.0.4 with: add-paths: lib/scancodeMap.js commit-message: Update ScanCode license mapping diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..57d87ce42 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,5 @@ +.github/workflows/* +.vscode/launch.json +schemas/*.json +test/**/*.json +test/**/*.yaml diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index bf3b19903..000000000 --- a/.prettierrc +++ /dev/null @@ -1,4 +0,0 @@ -printWidth: 120 -singleQuote: true -semi: false -trailingComma: "none" \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..449ecaa31 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "arrowParens": "avoid", + "printWidth": 120, + "singleQuote": true, + "semi": false, + "trailingComma": "none" +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..d7df89c9c --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 95c693898..2102d8b75 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, "editor.tabSize": 2 } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index da960baa5..c4b57fbac 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9887a88a..c9bea7536 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ The ClearlyDefined project welcomes your suggestions and contributions! Before o ## Contribution Licensing -Most of our code is distributed under the terms of the [MIT license](LICENSE), and when you contribute code that you wrote to our repositories, +Most of our code is distributed under the terms of the [MIT license](LICENSE), and when you contribute code that you wrote to our repositories, you agree that you are contributing under those same terms. In addition, by submitting your contributions you are indicating that you have the right to submit those contributions under those terms. diff --git a/README.md b/README.md index 0f2439663..ae3689ba6 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ TBD Configuration properties can be found at: -* [service/full.env.json](https://github.com/clearlydefined/service/blob/master/full.env.json) -* [service/bin/config.js](https://github.com/clearlydefined/service/blob/master/bin/config.js) +- [service/full.env.json](https://github.com/clearlydefined/service/blob/master/full.env.json) +- [service/bin/config.js](https://github.com/clearlydefined/service/blob/master/bin/config.js) # Contributing @@ -243,6 +243,7 @@ The format of harvested data is tool-specific. Tool output is stored in the tool - composer - rubygem - deb +- conda ## Provider Registry @@ -258,6 +259,9 @@ The format of harvested data is tool-specific. Tool output is stored in the tool - packagist.org - proxy.golang.org - ftp.debian.org +- repo.anaconda.com/pkgs/main (anaconda-main) +- repo.anaconda.com/pkgs/r (anaconda-r) +- conda.anaconda.org/conda-forge (conda-forge) ## Tool Name Registry diff --git a/app.js b/app.js index c3e3e6574..846a54618 100644 --- a/app.js +++ b/app.js @@ -126,31 +126,27 @@ function createApp(config) { app.set('trust-proxy', true) // If Redis is configured for caching, connect to it - const client = config.caching.caching_redis_service ? - redis.createClient( - 6380, - config.caching.caching_redis_service, - { + const client = config.caching.caching_redis_service + ? redis.createClient(6380, config.caching.caching_redis_service, { auth_pass: config.caching.caching_redis_api_key, tls: { servername: config.caching_redis_service } - } - ) : - undefined + }) + : undefined // rate-limit the remaining routes - const apiLimiter = config.caching.caching_redis_service ? - rateLimit({ - store: new rateLimitRedisStore({ - client: client, - prefix: 'api' - }), - windowMs: config.limits.windowSeconds * 1000, - max: config.limits.max - }) : - rateLimit({ - windowMs: config.limits.windowSeconds * 1000, - max: config.limits.max - }) + const apiLimiter = config.caching.caching_redis_service + ? rateLimit({ + store: new rateLimitRedisStore({ + client: client, + prefix: 'api' + }), + windowMs: config.limits.windowSeconds * 1000, + max: config.limits.max + }) + : rateLimit({ + windowMs: config.limits.windowSeconds * 1000, + max: config.limits.max + }) app.use(apiLimiter) @@ -160,20 +156,19 @@ function createApp(config) { // * POST /definitions // * POST /curations // * POST /notices - const batchApiLimiter = config.caching.caching_redis_service ? - rateLimit({ - store: new rateLimitRedisStore({ - client: client, - prefix: 'batch-api' - }), - windowMs: config.limits.batchWindowSeconds * 1000, - max: config.limits.batchMax - }) : - rateLimit({ - windowMs: config.limits.batchWindowSeconds * 1000, - max: config.limits.batchMax - }) - + const batchApiLimiter = config.caching.caching_redis_service + ? rateLimit({ + store: new rateLimitRedisStore({ + client: client, + prefix: 'batch-api' + }), + windowMs: config.limits.batchWindowSeconds * 1000, + max: config.limits.batchMax + }) + : rateLimit({ + windowMs: config.limits.batchWindowSeconds * 1000, + max: config.limits.batchMax + }) app.post('/definitions', batchApiLimiter) app.post('/curations', batchApiLimiter) @@ -181,9 +176,10 @@ function createApp(config) { app.use(require('./middleware/querystring')) - app.use('/', require('./routes/index')(config.buildsha)) + app.use('/', require('./routes/index')(config.buildsha, config.appVersion)) app.use('/origins/github', require('./routes/originGitHub')()) app.use('/origins/crate', require('./routes/originCrate')()) + app.use('/origins/conda', require('./routes/originConda')()) app.use('/origins/pod', require('./routes/originPod')()) app.use('/origins/npm', require('./routes/originNpm')()) app.use('/origins/maven', require('./routes/originMaven')()) @@ -208,7 +204,14 @@ function createApp(config) { // catch 404 and forward to error handler const requestHandler = (req, res, next) => { - logger.info('Error when handling a request', { rawUrl: req._parsedUrl._raw, baseUrl: req.baseUrl, originalUrl: req.originalUrl, params: req.params, route: req.route, url: req.url }) + logger.info('Error when handling a request', { + rawUrl: req._parsedUrl._raw, + baseUrl: req.baseUrl, + originalUrl: req.originalUrl, + params: req.params, + route: req.route, + url: req.url + }) const err = new Error('Not Found') err.status = 404 next(err) diff --git a/bin/config.js b/bin/config.js index 39cb366c7..eea97035a 100644 --- a/bin/config.js +++ b/bin/config.js @@ -67,7 +67,6 @@ module.exports = { service: loadFactory(config.get('CACHING_PROVIDER') || 'memory', 'caching'), caching_redis_service: config.get('CACHING_REDIS_SERVICE'), caching_redis_api_key: config.get('CACHING_REDIS_API_KEY') - }, endpoints: { service: config.get('SERVICE_ENDPOINT') || 'http://localhost:4000', @@ -77,11 +76,19 @@ module.exports = { windowSeconds: parseInt(config.get('RATE_LIMIT_WINDOW')) || 1, max: parseInt(config.get('RATE_LIMIT_MAX')) || 0, batchWindowSeconds: parseInt(config.get('BATCH_RATE_LIMIT_WINDOW')) || 1, - batchMax: parseInt(config.get('BATCH_RATE_LIMIT_MAX')) || 0, + batchMax: parseInt(config.get('BATCH_RATE_LIMIT_MAX')) || 0 }, webhook: { - githubSecret: config.get('WEBHOOK_GITHUB_SECRET') || 'secret', - crawlerSecret: config.get('WEBHOOK_CRAWLER_SECRET') || 'secret' + githubSecret: + config.get('WEBHOOK_GITHUB_SECRET') || + (() => { + throw new Error('WEBHOOK_GITHUB_SECRET is required') + })(), + crawlerSecret: + config.get('WEBHOOK_CRAWLER_SECRET') || + (() => { + throw new Error('WEBHOOK_CRAWLER_SECRET is required') + })() }, search: { service: loadFactory(config.get('SEARCH_PROVIDER') || 'memory', 'search') @@ -92,5 +99,6 @@ module.exports = { crawlerId: config.get('APPINSIGHTS_CRAWLER_APPLICATIONID'), crawlerKey: config.get('APPINSIGHTS_CRAWLER_APIKEY') }, - buildsha : config.get('BUILD_SHA') + appVersion: config.get('APP_VERSION'), + buildsha: config.get('BUILD_SHA') } diff --git a/business/definitionService.js b/business/definitionService.js index d2db8bb01..f114d2f97 100644 --- a/business/definitionService.js +++ b/business/definitionService.js @@ -162,7 +162,10 @@ class DefinitionService { */ async listAll(coordinatesList) { //Take the array of coordinates, strip out the revision and only return uniques - const searchCoordinates = uniqWith(coordinatesList.map(coordinates => coordinates.asRevisionless()), isEqual) + const searchCoordinates = uniqWith( + coordinatesList.map(coordinates => coordinates.asRevisionless()), + isEqual + ) const promises = searchCoordinates.map( throat(10, async coordinates => { try { @@ -386,7 +389,7 @@ class DefinitionService { if (!definition.files) return 0 const coreFiles = definition.files.filter(DefinitionService._isInCoreFacet) if (!coreFiles.length) return 0 - const completeFiles = coreFiles.filter(file => file.license && (file.attributions && file.attributions.length)) + const completeFiles = coreFiles.filter(file => file.license && file.attributions && file.attributions.length) return Math.round((completeFiles.length / coreFiles.length) * weights.discovered) } @@ -558,10 +561,10 @@ class DefinitionService { if (get(definition, 'described.sourceLocation')) return updateSourceLocation(definition.described.sourceLocation) // For source components there may not be an explicit harvested source location (it is self-evident) // Make it explicit in the definition - switch (coordinates.provider) { - case 'golang': - case 'gitlab': - case 'github': + switch (coordinates.type) { + case 'go': + case 'git': + case 'sourcearchive': case 'pypi': { const url = buildSourceUrl(coordinates) if (!url) return @@ -579,9 +582,7 @@ class DefinitionService { } _getCacheKey(coordinates) { - return `def_${EntityCoordinates.fromObject(coordinates) - .toString() - .toLowerCase()}` + return `def_${EntityCoordinates.fromObject(coordinates).toString().toLowerCase()}` } } diff --git a/business/noticeService.js b/business/noticeService.js index 90e1038d3..2bcdabf8a 100644 --- a/business/noticeService.js +++ b/business/noticeService.js @@ -20,7 +20,10 @@ class NoticeService { async generate(coordinates, output, options) { options = options || {} - this.logger.info('1:notice_generate:get_definitions:start', { ts: new Date().toISOString(), cnt: coordinates.length }) + this.logger.info('1:notice_generate:get_definitions:start', { + ts: new Date().toISOString(), + cnt: coordinates.length + }) const definitions = await this.definitionService.getAll(coordinates) this.logger.info('1:notice_generate:get_definitions:end', { ts: new Date().toISOString(), cnt: coordinates.length }) this.logger.info('2:notice_generate:get_blobs:start', { ts: new Date().toISOString(), cnt: coordinates.length }) @@ -50,25 +53,27 @@ class NoticeService { const noDefinition = [] const noLicense = [] const noCopyright = [] - const packages = (await Promise.all( - Object.keys(definitions).map(async id => { - const definition = definitions[id] - if (!get(definition, 'described.tools[0]')) { - noDefinition.push(id) - return - } - if (!isDeclaredLicense(get(definition, 'licensed.declared'))) noLicense.push(id) - if (!get(definition, 'licensed.facets.core.attribution.parties[0]')) noCopyright.push(id) - return { - name: [definition.coordinates.namespace, definition.coordinates.name].filter(x => x).join('/'), - version: get(definition, 'coordinates.revision'), - license: get(definition, 'licensed.declared'), - copyrights: get(definition, 'licensed.facets.core.attribution.parties'), - website: get(definition, 'described.projectWebsite') || '', - text: await this._getPackageText(definition) - } - }) - )).filter(x => x && isDeclaredLicense(x.license)) + const packages = ( + await Promise.all( + Object.keys(definitions).map(async id => { + const definition = definitions[id] + if (!get(definition, 'described.tools[0]')) { + noDefinition.push(id) + return + } + if (!isDeclaredLicense(get(definition, 'licensed.declared'))) noLicense.push(id) + if (!get(definition, 'licensed.facets.core.attribution.parties[0]')) noCopyright.push(id) + return { + name: [definition.coordinates.namespace, definition.coordinates.name].filter(x => x).join('/'), + version: get(definition, 'coordinates.revision'), + license: get(definition, 'licensed.declared'), + copyrights: get(definition, 'licensed.facets.core.attribution.parties'), + website: get(definition, 'described.projectWebsite') || '', + text: await this._getPackageText(definition) + } + }) + ) + ).filter(x => x && isDeclaredLicense(x.license)) return { packages, noDefinition, noLicense, noCopyright } } @@ -91,21 +96,28 @@ class NoticeService { async _getPackageText(definition) { if (!definition.files) return '' - this.logger.info('2:1:notice_generate:get_single_package_files:start', { ts: new Date().toISOString(), coordinates: definition.coordinates.toString() }) + this.logger.info('2:1:notice_generate:get_single_package_files:start', { + ts: new Date().toISOString(), + coordinates: definition.coordinates.toString() + }) const texts = await Promise.all( definition.files - .filter(file => - file.token - && file.natures - && file.natures.includes('license') - && file.path - && ( - file.path.indexOf('/') === -1 - || (definition.coordinates.type === 'npm' && file.path.startsWith('package/')) - )) + .filter( + file => + file.token && + file.natures && + file.natures.includes('license') && + file.path && + (file.path.indexOf('/') === -1 || + (definition.coordinates.type === 'npm' && file.path.startsWith('package/'))) + ) .map(file => this.attachmentStore.get(file.token)) ) - this.logger.info('2:1:notice_generate:get_single_package_files:end', { ts: new Date().toISOString(), cnt: texts.length, coordinates: definition.coordinates.toString() }) + this.logger.info('2:1:notice_generate:get_single_package_files:end', { + ts: new Date().toISOString(), + cnt: texts.length, + coordinates: definition.coordinates.toString() + }) return texts.join('\n\n') } } diff --git a/business/statsService.js b/business/statsService.js index 8167713a1..84bcf22c6 100644 --- a/business/statsService.js +++ b/business/statsService.js @@ -35,6 +35,8 @@ class StatsService { _getStatLookup() { return { total: () => this._getType('total'), + conda: () => this._getType('conda'), + condasrc: () => this._getType('condasrc'), crate: () => this._getType('crate'), gem: () => this._getType('gem'), git: () => this._getType('git'), @@ -45,7 +47,7 @@ class StatsService { composer: () => this._getType('composer'), pypi: () => this._getType('pypi'), deb: () => this._getType('deb'), - debsrc: () => this._getType('debsrc'), + debsrc: () => this._getType('debsrc') } } diff --git a/business/suggestionService.js b/business/suggestionService.js index 3c85a1862..759114e93 100644 --- a/business/suggestionService.js +++ b/business/suggestionService.js @@ -22,8 +22,11 @@ class SuggestionService { let hasSuggested = false const suggestion = { coordinates } if (Array.isArray(definitions.related) && definitions.related.length > 0) { - hasSuggested = this._collectSuggestionsForField(definitions, suggestion, 'licensed.declared', (definition, field) => - isDeclaredLicense(get(definition, field)) + hasSuggested = this._collectSuggestionsForField( + definitions, + suggestion, + 'licensed.declared', + (definition, field) => isDeclaredLicense(get(definition, field)) ) hasSuggested |= this._collectSuggestionsForField(definitions, suggestion, 'described.sourceLocation') } @@ -31,13 +34,15 @@ class SuggestionService { if (!isDeclaredLicense(get(definitions.original, 'licensed.declared'))) { let discoveredExpressions = get(definitions.original, 'licensed.facets.core.discovered.expressions') if (Array.isArray(discoveredExpressions)) { - let appendDeclared = discoveredExpressions - .filter(isDeclaredLicense) - .map(value => { return { value, version: get(definitions.original, 'coordinates.revision') } }) + let appendDeclared = discoveredExpressions.filter(isDeclaredLicense).map(value => { + return { value, version: get(definitions.original, 'coordinates.revision') } + }) let suggestedSoFar = get(suggestion, 'licensed.declared') || [] - hasSuggested |= setIfValue(suggestion, 'licensed.declared', appendDeclared - .concat(suggestedSoFar) - .filter((v, i, a) => a.indexOf(v) === i)) + hasSuggested |= setIfValue( + suggestion, + 'licensed.declared', + appendDeclared.concat(suggestedSoFar).filter((v, i, a) => a.indexOf(v) === i) + ) } } diff --git a/docs/architecture/go_components.md b/docs/architecture/go_components.md index 7994cb00c..0491a01bf 100644 --- a/docs/architecture/go_components.md +++ b/docs/architecture/go_components.md @@ -4,10 +4,10 @@ This drafts an architecture document for adding support for Go components to Cle ## TLDR; -* Add a new "go" type to ClearlyDefined -* Only support go modules as components (which were added in Go 1.11). [According to the Go documentation](https://blog.golang.org/using-go-modules), modules are a dependency management system that makes dependency version information explicit and easier to manage. There were other, more complicated ways of managing go dependencies prior to this, but we should only focus on modules in our first iteration. We can revisit other ways of managing go dependencies later if necessary. -* Use 'golang' as the provider for the component. -* Use URL encoding for slashes in go import paths and package names +- Add a new "go" type to ClearlyDefined +- Only support go modules as components (which were added in Go 1.11). [According to the Go documentation](https://blog.golang.org/using-go-modules), modules are a dependency management system that makes dependency version information explicit and easier to manage. There were other, more complicated ways of managing go dependencies prior to this, but we should only focus on modules in our first iteration. We can revisit other ways of managing go dependencies later if necessary. +- Use 'golang' as the provider for the component. +- Use URL encoding for slashes in go import paths and package names ## Prior work @@ -15,8 +15,8 @@ This drafts an architecture document for adding support for Go components to Cle I have also completed a few prior drafts of this architecture: -* [Go Architecture Draft 1](https://github.com/clearlydefined/service/pull/862) -* [Go Architecture Draft 2](https://github.com/clearlydefined/service/pull/864) +- [Go Architecture Draft 1](https://github.com/clearlydefined/service/pull/862) +- [Go Architecture Draft 2](https://github.com/clearlydefined/service/pull/864) ### No central Go repository @@ -71,11 +71,12 @@ curl -X GET https://clearlydefined.io/definitions/maven/mavencentral/com.apollog In this case, the coordinates are maven/mavencentral/com.apollographql.apollo3/apollo-runtime-jvm/3.0.0-dev14 Let's break this down: -* **maven** is the **type** -* **mavencentral** is the **provider** -* **com.apollographql.apollo3** is the **namespace** -* **apollo-runtime-jvm** is the **name** -* **3.0.0-dev14** is the **revision** + +- **maven** is the **type** +- **mavencentral** is the **provider** +- **com.apollographql.apollo3** is the **namespace** +- **apollo-runtime-jvm** is the **name** +- **3.0.0-dev14** is the **revision** When we run this API call: @@ -85,7 +86,7 @@ curl -X GET https://clearlydefined.io/definitions/maven/mavencentral/com.apollog It harvests the component from [here](https://repo1.maven.org/maven2/com/apollographql/apollo3/apollo-runtime-jvm/3.0.0-dev14/). -Notice something in the url - the namespace is "com/apollographql/apollo3" - there are a lot of slashes in there. +Notice something in the url - the namespace is "com/apollographql/apollo3" - there are a lot of slashes in there. The way we translate this namespace into coordinates is to replace the slashes in the namespace with periods. @@ -97,20 +98,20 @@ A Go component's coordinates will also need to consist of a type, provider, name Go's support of vanity package names makes this a little different than other components. While there are a few different approaches we could take, we should map the coordinates to what go developers know the package as. -* **type** should be go -* **provider** should be 'golang' -* **namespace** should be anything that appears before the package name in the import path (it should be "-" if nothing appears before the package name) -* **name** should be the name of the package -* **revision** should be the component revision (note - go components seem to have multiple ways of specifying revisions - sometimes version numbers, sometimes commit hashes) +- **type** should be go +- **provider** should be 'golang' +- **namespace** should be anything that appears before the package name in the import path (it should be "-" if nothing appears before the package name) +- **name** should be the name of the package +- **revision** should be the component revision (note - go components seem to have multiple ways of specifying revisions - sometimes version numbers, sometimes commit hashes) A challenge with go components is that import paths and package names can contain slashes and periods - which makes translating them into valid coordinates more difficult. In previous drafts, I considered replacing slashes with periods like with Maven components, but periods are also valid characters in Go import paths. Any character that can appear in a url can be used in an import path and package name. I considered using a different character to replace slashes in components...but this has the potential to become very confusing and inconsistent. In order to be as straightforward and consistent as possible, we need to use [URL encoding](https://www.tutorialspoint.com/html/html_url_encoding.htm) for slashes in go components (and potentially in other components as well). -### Examples +### Examples -* `collectd.org v0.5.0` maps to `go/golang/-/collectd.org/v0.5.0` -* `go.starlark.net v0.0.0-20210406145628-7a1108eaa012` maps to `go/golang/-/go.starlark.net/v0.0.0-20210406145628-7a1108eaa012` -* `cloud.google.com/go v0.56.0` maps to `go/golang/cloud.google.com/go/v0.56.0` -* `golang.org/x/net v0.0.0-20210226172049-e18ecbb05110` maps to `go/golang/golang.org%2fx/net/v0.0.0-20210226172049-e18ecbb05110` -* `github.com/Azure/azure-event-hubs-go/v3 v3.2.0` maps to `go/golang/github.com%2fAzure%2fazure-event-hubs-go/v3/v3.2.0` \ No newline at end of file +- `collectd.org v0.5.0` maps to `go/golang/-/collectd.org/v0.5.0` +- `go.starlark.net v0.0.0-20210406145628-7a1108eaa012` maps to `go/golang/-/go.starlark.net/v0.0.0-20210406145628-7a1108eaa012` +- `cloud.google.com/go v0.56.0` maps to `go/golang/cloud.google.com/go/v0.56.0` +- `golang.org/x/net v0.0.0-20210226172049-e18ecbb05110` maps to `go/golang/golang.org%2fx/net/v0.0.0-20210226172049-e18ecbb05110` +- `github.com/Azure/azure-event-hubs-go/v3 v3.2.0` maps to `go/golang/github.com%2fAzure%2fazure-event-hubs-go/v3/v3.2.0` diff --git a/docs/calculating-definition-scores.md b/docs/calculating-definition-scores.md index 3edd12ecd..1e245e0de 100644 --- a/docs/calculating-definition-scores.md +++ b/docs/calculating-definition-scores.md @@ -1,15 +1,16 @@ # How ClearlyDefined Scores are calculated If you look at a component on ClearlyDefined such as [this one](https://clearlydefined.io/definitions/maven/mavencentral/org.opendaylight.controller/sal-common-util/4.0.6), you will see two types of scores: -* Described -* Licensed + +- Described +- Licensed ## Described The Described Score is based on two factors: -* Whether the definition has a release date -* Whether the definition has a source location URL +- Whether the definition has a release date +- Whether the definition has a source location URL See below for more details @@ -17,17 +18,17 @@ See below for more details The license score is based on several factors: -* whether the definition has a declared license -* whether the definition has discovered licenses -* whether the declared and discovered licenses are consistent -* whether the declared license can be parsed as an SPDX expression -* whether all there is text available for all referenced licenses +- whether the definition has a declared license +- whether the definition has discovered licenses +- whether the declared and discovered licenses are consistent +- whether the declared license can be parsed as an SPDX expression +- whether all there is text available for all referenced licenses This document explores how these scores are calculated. ## Where it starts -Computing ClearlyDefined scores starts in +Computing ClearlyDefined scores starts in **service/business/definitionService.js** @@ -39,16 +40,18 @@ Computing ClearlyDefined scores starts in } } ``` -* this function returns a "Licensed Score" and "Declared Score" + +- this function returns a "Licensed Score" and "Declared Score" ## Calculating the Licensed Score There are several parts that go into computing the Licensed Score -* declared score -* discovered score -* consistency score -* spdx score -* texts score + +- declared score +- discovered score +- consistency score +- spdx score +- texts score ```javascript _computeLicensedScore(definition) { @@ -60,9 +63,9 @@ There are several parts that go into computing the Licensed Score const total = declared + discovered + consistency + spdx + texts return { total, declared, discovered, consistency, spdx, texts } } -```` +``` -* it then adds the scores together and returns the total along with the various scores +- it then adds the scores together and returns the total along with the various scores ### Declared Score @@ -107,12 +110,13 @@ const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts return Math.round((completeFiles.length / coreFiles.length) * weights.discovered) } ``` -* checks for files in the definition -* if there are no files, returns 0 -* filters out files in the core facet -* if there are no files in the core facet, returns 0 -* filters out files that have a licenses and attributions -* divides files in the core facet / files that have licenses and attributions, then multiplies that number by the weight for the discovered score + +- checks for files in the definition +- if there are no files, returns 0 +- filters out files in the core facet +- if there are no files in the core facet, returns 0 +- filters out files that have a licenses and attributions +- divides files in the core facet / files that have licenses and attributions, then multiplies that number by the weight for the discovered score ```javascript const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts: 15, date: 30, source: 70 } @@ -130,10 +134,11 @@ const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts return discovered.every(expression => SPDX.satisfies(expression, declared)) ? weights.consistency : 0 } ``` -* searches for declared and discovered licenses -* if there are no declared or discovered licenses, return 0 -* otherwise, it checks whether every discovered license is compatible with the declared license(s) -* if so, it returns the weight for consistency + +- searches for declared and discovered licenses +- if there are no declared or discovered licenses, return 0 +- otherwise, it checks whether every discovered license is compatible with the declared license(s) +- if so, it returns the weight for consistency ```javascript const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts: 15, date: 30, source: 70 } @@ -151,8 +156,9 @@ const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts } } ``` -* checks whether the declared license can be parsed -* if so, returns weight for spdx + +- checks whether the declared license can be parsed +- if so, returns weight for spdx ```javascript const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts: 15, date: 30, source: 70 } @@ -174,8 +180,8 @@ const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts } ``` -* checks for definition files -* collects license texts +- checks for definition files +- collects license texts ```javascript // Get the full set of license texts captured in the definition @@ -188,7 +194,7 @@ const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts } ``` -* collects referenced licenses +- collects referenced licenses ```javascript // get all the licenses that have been referenced anywhere in the definition (declared and core) @@ -202,8 +208,8 @@ const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts } ``` -* checks that all referenced licenses have texts -* if they do, returns texts weight +- checks that all referenced licenses have texts +- if they do, returns texts weight ```javascript const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts: 15, date: 30, source: 70 } @@ -221,12 +227,9 @@ const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts } ``` -* checks whether the definition has a release date. If so, applies the date weight. -* Also checks whether the definition has a source location url. If so, applies the source weight: +- checks whether the definition has a release date. If so, applies the date weight. +- Also checks whether the definition has a source location url. If so, applies the source weight: ```javascript const weights = { declared: 30, discovered: 25, consistency: 15, spdx: 15, texts: 15, date: 30, source: 70 } ``` - - - diff --git a/docs/determining-declared-license.md b/docs/determining-declared-license.md index 731d5de65..28f7b6fbe 100644 --- a/docs/determining-declared-license.md +++ b/docs/determining-declared-license.md @@ -1,111 +1,131 @@ # How ClearlyDefined determines the declared license ## Crawler -* OSS components are harvested by the [ClearlyDefined Crawler](https://github.com/clearlydefined/crawler) -* The Crawler uses 4 tools for harvest - ClearlyDefined itself, [Scancode](https://scancode-toolkit.readthedocs.io/en/latest/getting-started/home.html), [Licensee](https://github.com/licensee/licensee), and [Reuse](https://reuse.software/) -* See below for how it handles different types of components -* The Crawler then sends the harvest data to the ClearlyDefined Service + +- OSS components are harvested by the [ClearlyDefined Crawler](https://github.com/clearlydefined/crawler) +- The Crawler uses 4 tools for harvest - ClearlyDefined itself, [Scancode](https://scancode-toolkit.readthedocs.io/en/latest/getting-started/home.html), [Licensee](https://github.com/licensee/licensee), and [Reuse](https://reuse.software/) +- See below for how it handles different types of components +- The Crawler then sends the harvest data to the ClearlyDefined Service ## Service -* The harvests are processed into definitions by the [ClearlyDefined Service](https://github.com/clearlydefined/service/tree/9e0a677a74c36c6ea276c4548b520b7c91db05ce) -* The service summarizes the data using the ClearlyDefined summarizer, Scancode summarizer, Licensee summarizer, and Reuse summarizer -* The ClearlyDefined summarizer does different things based on the component type, see below for how it handles different types of components -* The Scancode summarizer pulls any declared license information detected by Scancode (for more information, see the [code here](https://github.com/clearlydefined/service/blob/2d1e52caf5c07c3b6ef2565b5b77f1b677c82033/providers/summary/scancode.js)) -* The Licensee summarizer pulls any declared license information detected by Licensee (for more information, see the [code here](https://github.com/clearlydefined/service/blob/master/providers/summary/licensee.js)) -* The Reuse summarizer pulls any declared license information detected by Reuse (for more information, see the [code here](https://github.com/clearlydefined/service/blob/master/providers/summary/reuse.js)) -* Then the ClearlyDefined service aggregates the information from the four tools - when there is conflicting information, the order of precedence is 'clearlydefined', 'reuse', 'licensee', 'scancode', 'cdsource' + +- The harvests are processed into definitions by the [ClearlyDefined Service](https://github.com/clearlydefined/service/tree/9e0a677a74c36c6ea276c4548b520b7c91db05ce) +- The service summarizes the data using the ClearlyDefined summarizer, Scancode summarizer, Licensee summarizer, and Reuse summarizer +- The ClearlyDefined summarizer does different things based on the component type, see below for how it handles different types of components +- The Scancode summarizer pulls any declared license information detected by Scancode (for more information, see the [code here](https://github.com/clearlydefined/service/blob/2d1e52caf5c07c3b6ef2565b5b77f1b677c82033/providers/summary/scancode.js)) +- The Licensee summarizer pulls any declared license information detected by Licensee (for more information, see the [code here](https://github.com/clearlydefined/service/blob/master/providers/summary/licensee.js)) +- The Reuse summarizer pulls any declared license information detected by Reuse (for more information, see the [code here](https://github.com/clearlydefined/service/blob/master/providers/summary/reuse.js)) +- Then the ClearlyDefined service aggregates the information from the four tools - when there is conflicting information, the order of precedence is 'clearlydefined', 'reuse', 'licensee', 'scancode', 'cdsource' ## Curations -* If the declared license is changed through [the human curation process](https://github.com/clearlydefined/clearlydefined/blob/master/docs/curation-guidelines.md), the declared license in the curation will take precedence. + +- If the declared license is changed through [the human curation process](https://github.com/clearlydefined/clearlydefined/blob/master/docs/curation-guidelines.md), the declared license in the curation will take precedence. ## Harvesting and Determining Declared License (by the ClearlyDefined Summarizer) ### npm -* source: https://www.npmjs.com -* The crawler pulls registry data for the component from https://registry.npmjs.com -* In the service, the ClearlyDefined summarizer parses license(s) from the registry data and sets them as the declared license + +- source: https://www.npmjs.com +- The crawler pulls registry data for the component from https://registry.npmjs.com +- In the service, the ClearlyDefined summarizer parses license(s) from the registry data and sets them as the declared license ### gem -* source: https://rubygems.org -* The crawler pulls registry data for the component from https://rubygems.org -* The ClearlyDefined summarizer determines the declared license based on the license in the registry data + +- source: https://rubygems.org +- The crawler pulls registry data for the component from https://rubygems.org +- The ClearlyDefined summarizer determines the declared license based on the license in the registry data ### pypi -* source: https://pypi.org -* First, the crawler pulls registry information from https://pypi.org [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/pypiFetch.js#L42) -* It then extracts the declared license from the registry data [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/pypiFetch.js#L71) -* The service uses the declared license set by the crawler + +- source: https://pypi.org +- First, the crawler pulls registry information from https://pypi.org [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/pypiFetch.js#L42) +- It then extracts the declared license from the registry data [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/pypiFetch.js#L71) +- The service uses the declared license set by the crawler ### maven -* sources https://mvnrepository.com/repos/central, https://maven.google.com/ and https://plugins.gradle.org/m2/ -**maven central** +- sources https://mvnrepository.com/repos/central, https://maven.google.com/ and https://plugins.gradle.org/m2/ -* The crawler downloads the maven artifact from maven.org -* The crawler then extracts all pom files from the artifact -* And then merges the poms (including all the licenses defined in the poms) -* The ClearlyDefined summarizer parses the merged poms and sets the declared license(s) based on that data +--maven central-- -**google maven** +- The crawler downloads the maven artifact from maven.org +- The crawler then extracts all pom files from the artifact +- And then merges the poms (including all the licenses defined in the poms) +- The ClearlyDefined summarizer parses the merged poms and sets the declared license(s) based on that data -* The crawler gets pom files for the component from https://dl.google.com/android/maven2/ -* It then merges the poms (including all the licenses defined in the poms) -* The ClearlyDefined summarizer parses the merged poms and sets the declared license(s) based on that data +--google maven-- -**gradle plugin** +- The crawler gets pom files for the component from https://dl.google.com/android/maven2/ +- It then merges the poms (including all the licenses defined in the poms) +- The ClearlyDefined summarizer parses the merged poms and sets the declared license(s) based on that data -* The crawler gets pom files for the component from https://plugins.gradle.org/m2/ -* It then merges the poms (including all the licenses defined in the poms) -* The ClearlyDefined summarizer parses the merged poms and sets the declared license(s) based on that data +--gradle plugin-- + +- The crawler gets pom files for the component from https://plugins.gradle.org/m2/ +- It then merges the poms (including all the licenses defined in the poms) +- The ClearlyDefined summarizer parses the merged poms and sets the declared license(s) based on that data ### nuget -* source: https://www.nuget.org/ -* The crawler gets registry information for the component from https://api.nuget.org -* If the registry information has a licenseExpression field, the ClearlyDefined summarizer sets the declared license to that license expression -* If the registry information has a licenseUrl field, the ClearlyDefined summarizer extracts the license from that license url and sets the declared license to the extracted license -* If the ClearlyDefined summarizer cannot extract the license from the license URL, it sets the declared license to NOASSERTION -**Checking for the packageEntries field** +- source: https://www.nuget.org/ +- The crawler gets registry information for the component from https://api.nuget.org +- If the registry information has a licenseExpression field, the ClearlyDefined summarizer sets the declared license to that license expression +- If the registry information has a licenseUrl field, the ClearlyDefined summarizer extracts the license from that license url and sets the declared license to the extracted license +- If the ClearlyDefined summarizer cannot extract the license from the license URL, it sets the declared license to NOASSERTION + +--Checking for the packageEntries field-- -* The ClearlyDefined summarizer then checks whether the registry information has a packageEntries field -* If it does not, it leaves the declared license as it is -* If it does have a packageEntries field, the ClearlyDefined summarizer creates a new definition with the files field set to those packageEntries +- The ClearlyDefined summarizer then checks whether the registry information has a packageEntries field +- If it does not, it leaves the declared license as it is +- If it does have a packageEntries field, the ClearlyDefined summarizer creates a new definition with the files field set to those packageEntries -**Merging definitions** +--Merging definitions-- -* It then merges the definitions and, in the process, merges the declared licenses -* If the original definition (prior to the merge) has a declared license of 'OTHER', it sets the declared license (on the merged definition) to the license on the new definition -* Otherwise, it combines the original definition license and the new definition license with AND +- It then merges the definitions and, in the process, merges the declared licenses +- If the original definition (prior to the merge) has a declared license of 'OTHER', it sets the declared license (on the merged definition) to the license on the new definition +- Otherwise, it combines the original definition license and the new definition license with AND ### git -* sources: https://github.com and https://gitlab.com -* The crawler clones the repo for the component from either https://gitlab.com or https://github.com -* TODO - how is the declared license decided? + +- sources: https://github.com and https://gitlab.com +- The crawler clones the repo for the component from either https://gitlab.com or https://github.com +- TODO - how is the declared license decided? ### crate -* source: https://crates.io/ -* The crawler gets registry information from https://crates.io/api/v1/crates/ -* The ClearlyDefined summarizer sets the declared license to the license(s) in the registry information + +- source: https://crates.io/ +- The crawler gets registry information from https://crates.io/api/v1/crates/ +- The ClearlyDefined summarizer sets the declared license to the license(s) in the registry information ### deb -* source: http://ftp.debian.org/ -* First, the crawler downloads a package file map from http://ftp.debian.org/debian/indices/package-file.map.bz2 and caches it (if there is not one already cached) for 8 hours [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L87) -* It then pulls the registry information for the particular component from that package map file [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L114) -* It then finds the relevant copyright URL from the registry information [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L295) [Example](https://metadata.ftp-master.debian.org/changelogs/main/0/0ad-data/0ad-data_0.0.17-1_copyright) -* It then pulls information from the copyright URL [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L306) -* And parses that information [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L320) to determine the declared license(s) -* The ClearlyDefined summarizer then parses the declared licenses and, if there is more than one, joins them with 'AND' + +- source: http://ftp.debian.org/ +- First, the crawler downloads a package file map from http://ftp.debian.org/debian/indices/package-file.map.bz2 and caches it (if there is not one already cached) for 8 hours [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L87) +- It then pulls the registry information for the particular component from that package map file [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L114) +- It then finds the relevant copyright URL from the registry information [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L295) [Example](https://metadata.ftp-master.debian.org/changelogs/main/0/0ad-data/0ad-data_0.0.17-1_copyright) +- It then pulls information from the copyright URL [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L306) +- And parses that information [Code](https://github.com/clearlydefined/crawler/blob/f461b2358fbde130bcc5d183de01a4212c4cd66d/providers/fetch/debianFetch.js#L320) to determine the declared license(s) +- The ClearlyDefined summarizer then parses the declared licenses and, if there is more than one, joins them with 'AND' ### debsrc -* source: http://ftp.debian.org/ -* Appears to be the same as `deb` + +- source: http://ftp.debian.org/ +- Appears to be the same as `deb` ### composer -* source: https://packagist.org/ -* The crawler pulls registry information from https://repo.packagist.org/ -* The ClearlyDefined summarizer then sets the declared license based on the registry information + +- source: https://packagist.org/ +- The crawler pulls registry information from https://repo.packagist.org/ +- The ClearlyDefined summarizer then sets the declared license based on the registry information ### pod -* source: https://cocoapods.org/ -* The service then sets the declared license based on the registry information -* The ClearlyDefined summarizer pulls registry information from 'https://raw.githubusercontent.com/CocoaPods/Specs/master + +- source: https://cocoapods.org/ +- The service then sets the declared license based on the registry information +- The ClearlyDefined summarizer pulls registry information from 'https://raw.githubusercontent.com/CocoaPods/Specs/master + +### conda + +- source: conda-forge anaconda-main, or anaconda-r (https://conda.anaconda.org) +- The crawler gets registry information from https://conda.anaconda.org/conda-forge +- The ClearlyDefined summarizer sets the declared license to the license(s) in the registry information diff --git a/docs/rampup.md b/docs/rampup.md index 5b51a4e49..7535e8f71 100644 --- a/docs/rampup.md +++ b/docs/rampup.md @@ -3,46 +3,53 @@ These are suggested steps / tips to get familiar with the codebase: 0. Clone repo, two branches: master, and prod. Correspond to dev and prod environment. -0. `npm install`, `npm test` to run tests -0. Take a look at the [README](/README.md) -0. take a look at the [package.json](/package.json) scripts section. - * Test for tests, dev/start to run -0. Try making a change (update a package), run tests again -0. If tests are good, open a PR - * Will run the clearlydefined.service pipeline in azdo - * https://dev.azure.com/clearlydefined/ClearlyDefined/_build - * The pipeline is defined in azure-pipelines.yaml -0. Can merge after approval and checks pass - * Upon merge, pipeline will kick off: service-master: graphical definition - * Runs npm test, build/push docker image to ACR - * Release will kick off: service-dev: deploys and restarts azure app service: clearlydefined-api-dev - * Note: need to address azdo release warning, needed arguments in release definition +1. `npm install`, `npm test` to run tests +2. Take a look at the [README](/README.md) +3. take a look at the [package.json](/package.json) scripts section. + - Test for tests, dev/start to run +4. Try making a change (update a package), run tests again +5. If tests are good, open a PR + - Will run the clearlydefined.service pipeline in azdo + - https://dev.azure.com/clearlydefined/ClearlyDefined/_build + - The pipeline is defined in azure-pipelines.yaml +6. Can merge after approval and checks pass + - Upon merge, pipeline will kick off: service-master: graphical definition + - Runs npm test, build/push docker image to ACR + - Release will kick off: service-dev: deploys and restarts azure app service: clearlydefined-api-dev + - Note: need to address azdo release warning, needed arguments in release definition ## Local dev + ### Minimal + 0. See quick start in [README](/README.md#quick-start), also [minimal.env.json](/minimal.env.json) -0. Can use [curated-data-dev](https://github.com/clearlydefined/curated-data-dev) as curation repo, file store location can be local directory - * Minimal env is not close to real service environment (no queues, blobs, etc) +1. Can use [curated-data-dev](https://github.com/clearlydefined/curated-data-dev) as curation repo, file store location can be local directory + - Minimal env is not close to real service environment (no queues, blobs, etc) ### Dev-like + Better to use a copy of the real dev environment, can change queue names to be your own, same with blob storage. -* (Haven’t used storage emulator yet because not using Windows.) + +- (Haven’t used storage emulator yet because not using Windows.) + 0. Rather than using [minimal.env.json](/minimal.env.json), use [full.env.json](/full.env.json) as your env file in your parent directory -0. Add your name to: - * "HARVEST_AZBLOB_CONTAINER_NAME": "develop-jlm-local", -0. Comment/remove: - * "APPINSIGHTS_INSTRUMENTATIONKEY" -0. Maybe remove: - * "CURATION_QUEUE_PROVIDER" - So we don’t pull any curations off queue -0. Add in the same values you would have were you using [minimal.env.json](/minimal.env.json) (you can learn more about those values [here](https://docs.clearlydefined.io/contributing-code)). These include: - * "FILE_STORE_LOCATION" - * "CURATION_GITHUB_REPO" - * "CURATION_GITHUB_TOKEN" - * "CRAWLER_GITHUB_TOKEN" - * "SCANCODE_HOME" -0. Any other environmental variable values you might need can be found in the Clearly Defined subscription in Azure Portal under App Services -> clearlydefined-api-dev -> Settings -> Configuration -0. Consider all the vars and what you need for testing what you will test. +1. Add your name to: + - "HARVEST_AZBLOB_CONTAINER_NAME": "develop-jlm-local", +2. Comment/remove: + - "APPINSIGHTS_INSTRUMENTATIONKEY" +3. Maybe remove: + - "CURATION_QUEUE_PROVIDER" + So we don’t pull any curations off queue +4. Add in the same values you would have were you using [minimal.env.json](/minimal.env.json) (you can learn more about those values [here](https://docs.clearlydefined.io/contributing-code)). These include: + - "FILE_STORE_LOCATION" + - "CURATION_GITHUB_REPO" + - "CURATION_GITHUB_TOKEN" + - "CRAWLER_GITHUB_TOKEN" + - "WEBHOOK_GITHUB_SECRET" + - "WEBHOOK_CRAWLER_SECRET" + - "SCANCODE_HOME" +5. Any other environmental variable values you might need can be found in the Clearly Defined subscription in Azure Portal under App Services -> clearlydefined-api-dev -> Settings -> Configuration +6. Consider all the vars and what you need for testing what you will test. ## Dependency Security Management @@ -50,25 +57,29 @@ This project uses two tools to monitor (and fix) vulnerabilities in this project ### Dependabot -* [Dependabot](https://docs.github.com/en/free-pro-team@latest/github/managing-security-vulnerabilities/about-dependabot-security-updates) is a GitHub Security Feature. It tracks vulnerabilities in several languages including JavaScript. -* When Dependabot detects any vulnerabilities in the [GitHub Advisory Database](https://docs.github.com/en/free-pro-team@latest/github/managing-security-vulnerabilities/browsing-security-vulnerabilities-in-the-github-advisory-database), it sends a notification and may also open a pull request to fix the vulnerability. -* Only project maintainers can see Dependabot alerts +- [Dependabot](https://docs.github.com/en/free-pro-team@latest/github/managing-security-vulnerabilities/about-dependabot-security-updates) is a GitHub Security Feature. It tracks vulnerabilities in several languages including JavaScript. +- When Dependabot detects any vulnerabilities in the [GitHub Advisory Database](https://docs.github.com/en/free-pro-team@latest/github/managing-security-vulnerabilities/browsing-security-vulnerabilities-in-the-github-advisory-database), it sends a notification and may also open a pull request to fix the vulnerability. +- Only project maintainers can see Dependabot alerts ### Snyk -* [Synk Open Source](https://solutions.snyk.io/snyk-academy/open-source) is similar to Dependabot, though not GitHub specific. It also tracks vulnerabilities in dependencies. -* When Synk detects a vulnerability in the [Synk Intel Vulnerability Database](https://snyk.io/product/vulnerability-database/), it also opens a pull request with a fix for the vulnerability. -* Everyone can see pull requests opened by Snyk, but only members of the Clearly Defined organization on Snyk can see details of the vulnerability. -* If you do not have access to the Clearly Defined Snyk organization, reach out to @nellshamrell + +- [Synk Open Source](https://solutions.snyk.io/snyk-academy/open-source) is similar to Dependabot, though not GitHub specific. It also tracks vulnerabilities in dependencies. +- When Synk detects a vulnerability in the [Synk Intel Vulnerability Database](https://snyk.io/product/vulnerability-database/), it also opens a pull request with a fix for the vulnerability. +- Everyone can see pull requests opened by Snyk, but only members of the Clearly Defined organization on Snyk can see details of the vulnerability. +- If you do not have access to the Clearly Defined Snyk organization, reach out to @nellshamrell ### Why both? We are using both Dependabot and Snyk partly for experimental purposes but also because they use different vulnerability databases. One may detect a vulnerability that the other does not. At some point we may settle on one, but currently lose nothing by having both. ## Misc info + ### Invalid curations? + Providers/curation/github.js: github PR’s check service to see if it is valid ### Queues + Harvest queue: crawler puts messages on queue when it is done with any tools Curations queue: logic app puts messages on queue when it is called by github webhook @@ -78,14 +89,17 @@ Providers/curation/process.js, code for pulling from curation queue GitHub webhook is set to put message on queue for any change in PR status, this allows service to take different actions on ‘opened’ vs ‘merged’ etc. ### Database + What do we put in mongo / Cosmos DB? ( I see config for curations and definitions) -* Curations: looks like pr info, coordinates. Guess: used for curation info in relation to a coordinate (in UI) -* Definitions: mapping between attachments and definitions, finding the attachment blobs in azure storage + +- Curations: looks like pr info, coordinates. Guess: used for curation info in relation to a coordinate (in UI) +- Definitions: mapping between attachments and definitions, finding the attachment blobs in azure storage ### Definitions + business/definitionservice.js: code to compute definition, recomputed after harvest or curation Website uses apis that are not listed in swagger ### Logging -Appinsights: clearlydefined-api-prod: 346 exceptions in last 24 hours, should look into them +Appinsights: clearlydefined-api-prod: 346 exceptions in last 24 hours, should look into them diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..c22296ebf --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,22 @@ +const js = require('@eslint/js') +const globals = require('globals') +const eslintConfigPrettier = require('eslint-config-prettier') + +module.exports = [ + js.configs.recommended, + { + languageOptions: { + globals: { + ...globals.node, + ...globals.mocha + }, + parserOptions: { + sourceType: 'module' + } + }, + rules: { + 'no-console': 'off' + } + }, + eslintConfigPrettier +] diff --git a/lib/coordinatesMapper.js b/lib/coordinatesMapper.js index 3d4464d65..3fb79e3b7 100644 --- a/lib/coordinatesMapper.js +++ b/lib/coordinatesMapper.js @@ -11,7 +11,6 @@ const defaultMappers = { } class CoordinatesMapper { - constructor(mappers = defaultMappers, cache = defaultcache) { this.mappers = mappers this.cache = cache @@ -28,4 +27,4 @@ class CoordinatesMapper { } } -module.exports = (mappers, cache) => new CoordinatesMapper(mappers, cache) \ No newline at end of file +module.exports = (mappers, cache) => new CoordinatesMapper(mappers, cache) diff --git a/lib/curation.js b/lib/curation.js index 7fd83c92c..262ff9715 100644 --- a/lib/curation.js +++ b/lib/curation.js @@ -55,10 +55,12 @@ class Curation { Object.keys(revisions) .filter(revision => revisions[revision].licensed) - .forEach(revision => sourceLicenseList.push({ - source: `${revision} licensed.declared`, - license: revisions[revision].licensed.declared - })) + .forEach(revision => + sourceLicenseList.push({ + source: `${revision} licensed.declared`, + license: revisions[revision].licensed.declared + }) + ) Object.keys(revisions) .filter(revision => revisions[revision].files) diff --git a/lib/entityCoordinates.js b/lib/entityCoordinates.js index 2fb925404..9cac0653d 100644 --- a/lib/entityCoordinates.js +++ b/lib/entityCoordinates.js @@ -24,7 +24,8 @@ class EntityCoordinates { } static fromString(path) { - if (!path) return null + if (!path || typeof path !== 'string') return null + path = path.startsWith('/') ? path.slice(1) : path const [type, provider, namespace, name, revision] = path.split('/') return new EntityCoordinates(type, provider, namespace, name, revision) diff --git a/lib/github.js b/lib/github.js index d649424e9..e4efdb8ee 100644 --- a/lib/github.js +++ b/lib/github.js @@ -4,7 +4,7 @@ const GitHubApi = require('@octokit/rest') module.exports = { - getClient: function(options) { + getClient: function (options) { const github = new GitHubApi({ headers: { 'user-agent': 'clearlydefined.io' } }) github.authenticate({ type: 'token', token: options.token }) return github diff --git a/lib/gitlab.js b/lib/gitlab.js index 08f56dbbf..399e702ec 100644 --- a/lib/gitlab.js +++ b/lib/gitlab.js @@ -8,4 +8,4 @@ module.exports = { }) return gitlab } -} \ No newline at end of file +} diff --git a/lib/gradleCoordinatesMapper.js b/lib/gradleCoordinatesMapper.js index e6f85139f..a8a8166b4 100644 --- a/lib/gradleCoordinatesMapper.js +++ b/lib/gradleCoordinatesMapper.js @@ -10,7 +10,6 @@ const EntityCoordinates = require('./entityCoordinates') const repoBaseUrl = 'https://plugins.gradle.org/m2' class GradleCoordinatesMapper { - async map(coordinates) { if (!this._shouldResolve(coordinates)) return null const resolved = await this._resolve(coordinates) @@ -22,37 +21,38 @@ class GradleCoordinatesMapper { } async _resolve(coordinates) { - const markerCoordinates = coordinates.revision ? - coordinates : - { ...coordinates, revision: await this._getLatestVersion(coordinates) } + const markerCoordinates = coordinates.revision + ? coordinates + : { ...coordinates, revision: await this._getLatestVersion(coordinates) } if (!markerCoordinates.revision) return const mappedGav = await this._getImplementation(markerCoordinates) - return mappedGav && { - namespace: get(mappedGav, 'groupId.0'), - name: get(mappedGav, 'artifactId.0'), - revision: coordinates.revision ? get(mappedGav, 'version.0') : undefined - } + return ( + mappedGav && { + namespace: get(mappedGav, 'groupId.0'), + name: get(mappedGav, 'artifactId.0'), + revision: coordinates.revision ? get(mappedGav, 'version.0') : undefined + } + ) } async _getLatestVersion({ name }) { const answer = await this.getMavenMetadata(name) - const meta = answer && await parseXml(answer) + const meta = answer && (await parseXml(answer)) return get(meta, 'metadata.versioning.0.release.0') } async _getImplementation(markerCoordinates) { - const answer = await this._request(this._buildPomUrl((markerCoordinates))) - const pluginMarker = answer && await parseXml(answer) + const answer = await this._request(this._buildPomUrl(markerCoordinates)) + const pluginMarker = answer && (await parseXml(answer)) return get(pluginMarker, 'project.dependencies.0.dependency.0') } async _request(url) { - return this._handleRequest(url) - .catch(error => { - if (error.statusCode === 404) return null - throw error - }) + return this._handleRequest(url).catch(error => { + if (error.statusCode === 404) return null + throw error + }) } _buildPomUrl(coordinates) { diff --git a/lib/licenseMatcher.js b/lib/licenseMatcher.js index a4316068c..787774e2f 100644 --- a/lib/licenseMatcher.js +++ b/lib/licenseMatcher.js @@ -14,7 +14,8 @@ class LicenseMatcher { * @return { isMatching: Boolean, match: [] | undefined, mismatch: [] | undefined } */ process(source, target) { - const compareResults = this._policies.map(policy => policy.compare(source, target)) + const compareResults = this._policies + .map(policy => policy.compare(source, target)) .reduce((acc, cur) => ({ match: acc.match.concat(cur.match), mismatch: acc.mismatch.concat(cur.mismatch) })) const allInconclusive = compareResults.mismatch.length === 0 && compareResults.match.length === 0 if (compareResults.mismatch.length || allInconclusive) { @@ -53,12 +54,13 @@ class DefinitionLicenseMatchPolicy { } _addFileToMap(fileMap, files, propName) { - files && files.forEach(f => { - if (!f.path) return - const current = fileMap.get(f.path) || {} - current[propName] = f - fileMap.set(f.path, current) - }) + files && + files.forEach(f => { + if (!f.path) return + const current = fileMap.get(f.path) || {} + current[propName] = f + fileMap.set(f.path, current) + }) } _getLicenseFile(definition) { @@ -100,7 +102,6 @@ class DefinitionLicenseMatchPolicy { } class HarvestLicenseMatchPolicy { - compare(source, target) { const type = source.definition.coordinates.type const strategy = this._getStrategy(type) @@ -111,6 +112,10 @@ class HarvestLicenseMatchPolicy { switch (type) { case 'maven': return new BaseHarvestLicenseMatchStrategy('maven', ['manifest.summary.licenses']) + case 'conda': + return new BaseHarvestLicenseMatchStrategy('conda', ['declaredLicenses']) + case 'condasrc': + return new BaseHarvestLicenseMatchStrategy('condasrc', ['declaredLicenses']) case 'crate': return new BaseHarvestLicenseMatchStrategy('crate', ['registryData.license']) case 'pod': @@ -212,4 +217,4 @@ module.exports = { LicenseMatcher, DefinitionLicenseMatchPolicy, HarvestLicenseMatchPolicy -} \ No newline at end of file +} diff --git a/lib/mockInsights.js b/lib/mockInsights.js index d3c7ef420..68e8c06ad 100644 --- a/lib/mockInsights.js +++ b/lib/mockInsights.js @@ -13,11 +13,7 @@ class MockInsights { if (appInsights.defaultClient instanceof MockInsights) return if (!key || key === 'mock') appInsights.defaultClient = new MockInsights() else { - appInsights - .setup(key) - .setAutoCollectPerformance(false) - .setAutoCollectDependencies(true) - .start() + appInsights.setup(key).setAutoCollectPerformance(false).setAutoCollectDependencies(true).start() if (echo) appInsights.defaultClient = new MockInsights(appInsights.defaultClient) } } diff --git a/lib/scancodeMap.js b/lib/scancodeMap.js index a1805572d..c3d3d4a34 100644 --- a/lib/scancodeMap.js +++ b/lib/scancodeMap.js @@ -1,396 +1,2320 @@ // Copyright (c) Microsoft Corporation and others. Licensed under the MIT license. // SPDX-License-Identifier: MIT -// This is a map from scancode key to spdx identifier -// see licenses in https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/ +// *** THIS FILE IS AUTO-GENERATED by service/.github/workflows/transform-scancode-licensedb.js *** +// *** DO NOT EDIT MANUALLY *** +// +// This is a mapping from scancode key to SPDX identifier based on https://scancode-licensedb.aboutcode.org/index.json +// See licenses in https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/ module.exports = new Map([ - ['abstyles', 'Abstyles'], ['389-exception', '389-exception'], + ['3com-microcode', 'LicenseRef-scancode-3com-microcode'], + ['3dslicer-1.0', 'LicenseRef-scancode-3dslicer-1.0'], + ['4suite-1.1', 'LicenseRef-scancode-4suite-1.1'], + ['996-icu-1.0', 'LicenseRef-scancode-996-icu-1.0'], + ['aardvark-py-2014', 'LicenseRef-scancode-aardvark-py-2014'], + ['abrms', 'LicenseRef-scancode-abrms'], + ['abstyles', 'Abstyles'], + ['ac3filter', 'LicenseRef-scancode-ac3filter'], + ['accellera-systemc', 'LicenseRef-scancode-accellera-systemc'], + ['acdl-1.0', 'CDL-1.0'], ['ace-tao', 'DOC'], + ['acm-sla', 'LicenseRef-scancode-acm-sla'], + ['acroname-bdk', 'LicenseRef-scancode-acroname-bdk'], + ['activestate-community', 'LicenseRef-scancode-activestate-community'], + ['activestate-community-2012', 'LicenseRef-scancode-activestate-community-2012'], + ['activestate-komodo-edit', 'LicenseRef-scancode-activestate-komodo-edit'], + ['actuate-birt-ihub-ftype-sla', 'LicenseRef-scancode-actuate-birt-ihub-ftype-sla'], + ['ada-linking-exception', 'GNAT-exception'], + ['adacore-doc', 'AdaCore-doc'], ['adapt-1.0', 'APL-1.0'], + ['adaptec-downloadable', 'LicenseRef-scancode-adaptec-downloadable'], + ['adaptec-eula', 'LicenseRef-scancode-adaptec-eula'], + ['adcolony-tos-2022', 'LicenseRef-scancode-adcolony-tos-2022'], + ['addthis-mobile-sdk-1.0', 'LicenseRef-scancode-addthis-mobile-sdk-1.0'], + ['adi-bsd', 'LicenseRef-scancode-adi-bsd'], + ['adobe-acrobat-reader-eula', 'LicenseRef-scancode-adobe-acrobat-reader-eula'], + ['adobe-air-sdk', 'LicenseRef-scancode-adobe-air-sdk'], + ['adobe-air-sdk-2014', 'LicenseRef-scancode-adobe-air-sdk-2014'], + ['adobe-color-profile-bundling', 'LicenseRef-scancode-adobe-color-profile-bundling'], + ['adobe-color-profile-license', 'LicenseRef-scancode-adobe-color-profile-license'], + ['adobe-dng-sdk', 'LicenseRef-scancode-adobe-dng-sdk'], + ['adobe-dng-spec-patent', 'LicenseRef-scancode-adobe-dng-spec-patent'], + ['adobe-eula', 'LicenseRef-scancode-adobe-eula'], + ['adobe-flash-player-eula-21.0', 'LicenseRef-scancode-adobe-flash-player-eula-21.0'], + ['adobe-flex-4-sdk', 'LicenseRef-scancode-adobe-flex-4-sdk'], + ['adobe-flex-sdk', 'LicenseRef-scancode-adobe-flex-sdk'], + ['adobe-general-tou', 'LicenseRef-scancode-adobe-general-tou'], ['adobe-glyph', 'Adobe-Glyph'], + ['adobe-indesign-sdk', 'LicenseRef-scancode-adobe-indesign-sdk'], + ['adobe-postscript', 'LicenseRef-scancode-adobe-postscript'], ['adobe-scl', 'Adobe-2006'], + ['adobe-utopia', 'Adobe-Utopia'], + ['adrian', 'LicenseRef-scancode-adrian'], ['adsl', 'ADSL'], - ['afl-1.2', 'AFL-1.2'], + ['aes-128-3.0', 'LicenseRef-scancode-aes-128-3.0'], ['afl-1.1', 'AFL-1.1'], + ['afl-1.2', 'AFL-1.2'], ['afl-2.0', 'AFL-2.0'], - ['afpl-8.0', 'Aladdin'], ['afl-2.1', 'AFL-2.1'], + ['afl-3.0', 'AFL-3.0'], ['afmparse', 'Afmparse'], + ['afpl-8.0', 'Aladdin'], + ['afpl-9.0', 'LicenseRef-scancode-afpl-9.0'], + ['agentxpp', 'LicenseRef-scancode-agentxpp'], + ['agere-bsd', 'LicenseRef-scancode-agere-bsd'], + ['agere-sla', 'LicenseRef-scancode-agere-sla'], + ['ago-private-1.0', 'LicenseRef-scancode-ago-private-1.0'], ['agpl-1.0', 'AGPL-1.0-only'], - ['afl-3.0', 'AFL-3.0'], - ['agpl-3.0-plus', 'AGPL-3.0-or-later'], ['agpl-1.0-plus', 'AGPL-1.0-or-later'], + ['agpl-2.0', 'LicenseRef-scancode-agpl-2.0'], ['agpl-3.0', 'AGPL-3.0-only'], + ['agpl-3.0-bacula', 'null'], + ['agpl-3.0-linking-exception', 'null'], + ['agpl-3.0-openssl', 'null'], + ['agpl-3.0-plus', 'AGPL-3.0-or-later'], + ['agpl-generic-additional-terms', 'LicenseRef-scancode-agpl-generic-additional-terms'], + ['agtpl', 'LicenseRef-scancode-agtpl'], + ['aladdin-md5', 'null'], + ['alasir', 'LicenseRef-scancode-alasir'], + ['aldor-public-2.0', 'LicenseRef-scancode-aldor-public-2.0'], + ['alexisisaac-freeware', 'LicenseRef-scancode-alexisisaac-freeware'], + ['alfresco-exception-0.5', 'LicenseRef-scancode-alfresco-exception-0.5'], ['allegro-4', 'Giftware'], + ['allen-institute-software-2018', 'LicenseRef-scancode-allen-institute-software-2018'], + ['alliance-open-media-patent-1.0', 'LicenseRef-scancode-alliance-open-media-patent-1.0'], + ['altermime', 'LicenseRef-scancode-altermime'], + ['altova-eula', 'LicenseRef-scancode-altova-eula'], + ['amazon-redshift-jdbc', 'LicenseRef-scancode-amazon-redshift-jdbc'], + ['amazon-sl', 'LicenseRef-.amazon.com.-AmznSL-1.0'], + ['amd-aspf-2023', 'LicenseRef-scancode-amd-aspf-2023'], + ['amd-historical', 'LicenseRef-scancode-amd-historical'], + ['amd-linux-firmware', 'LicenseRef-scancode-amd-linux-firmware'], + ['amd-linux-firmware-export', 'LicenseRef-scancode-amd-linux-firmware-export'], ['amdplpa', 'AMDPLPA'], ['aml', 'AML'], + ['amlogic-linux-firmware', 'LicenseRef-scancode-amlogic-linux-firmware'], ['ampas', 'AMPAS'], + ['ams-fonts', 'LicenseRef-scancode-ams-fonts'], + ['android-sdk-2009', 'LicenseRef-scancode-android-sdk-2009'], + ['android-sdk-2012', 'LicenseRef-scancode-android-sdk-2012'], + ['android-sdk-2021', 'LicenseRef-scancode-android-sdk-2021'], + ['android-sdk-license', 'LicenseRef-scancode-android-sdk-license'], + ['android-sdk-preview-2015', 'LicenseRef-scancode-android-sdk-preview-2015'], + ['anepokis-1.0', 'LicenseRef-scancode-anepokis-1.0'], + ['anti-capitalist-1.4', 'LicenseRef-scancode-anti-capitalist-1.4'], ['antlr-pd', 'ANTLR-PD'], - ['apache-1.1', 'Apache-1.1'], + ['antlr-pd-fallback', 'ANTLR-PD-fallback'], + ['anu-license', 'LicenseRef-scancode-anu-license'], + ['aop-pd', 'null'], ['apache-1.0', 'Apache-1.0'], + ['apache-1.1', 'Apache-1.1'], ['apache-2.0', 'Apache-2.0'], + ['apache-2.0-linking-exception', 'null'], + ['apache-2.0-runtime-library-exception', 'null'], + ['apache-due-credit', 'null'], + ['apache-exception-llvm', 'null'], + ['apache-patent-exception', 'LicenseRef-scancode-apache-patent-exception'], + ['apache-patent-provision-exception', 'null'], ['apafml', 'APAFML'], - ['apsl-1.2', 'APSL-1.2'], + ['apl-1.1', 'LicenseRef-scancode-apl-1.1'], + ['app-s2p', 'App-s2p'], + ['appfire-eula', 'LicenseRef-scancode-appfire-eula'], + ['apple-academic-lisa-os-3.1', 'LicenseRef-scancode-apple-academic-lisa-os-3.1'], + ['apple-attribution', 'LicenseRef-scancode-apple-attribution'], + ['apple-attribution-1997', 'LicenseRef-scancode-apple-attribution-1997'], + ['apple-excl', 'LicenseRef-scancode-apple-excl'], + ['apple-mfi-license', 'LicenseRef-scancode-apple-mfi-license'], + ['apple-ml-ferret-2023', 'LicenseRef-scancode-apple-ml-ferret-2023'], + ['apple-mpeg-4', 'LicenseRef-scancode-apple-mpeg-4'], + ['apple-runtime-library-exception', 'Swift-exception'], + ['apple-sscl', 'LicenseRef-scancode-apple-sscl'], + ['appsflyer-framework', 'LicenseRef-scancode-appsflyer-framework'], ['apsl-1.0', 'APSL-1.0'], - ['apsl-2.0', 'APSL-2.0'], ['apsl-1.1', 'APSL-1.1'], + ['apsl-1.2', 'APSL-1.2'], + ['apsl-2.0', 'APSL-2.0'], + ['aptana-1.0', 'LicenseRef-scancode-aptana-1.0'], + ['aptana-exception-3.0', 'LicenseRef-scancode-aptana-exception-3.0'], + ['arachni-psl-1.0', 'LicenseRef-scancode-arachni-psl-1.0'], + ['aravindan-premkumar', 'LicenseRef-scancode-aravindan-premkumar'], + ['argouml', 'LicenseRef-scancode-argouml'], + ['arm-cortex-mx', 'LicenseRef-scancode-arm-cortex-mx'], + ['arm-llvm-sga', 'LicenseRef-scancode-arm-llvm-sga'], + ['arphic-public', 'Arphic-1999'], + ['array-input-method-pl', 'LicenseRef-scancode-array-input-method-pl'], + ['artistic-1.0', 'Artistic-1.0'], ['artistic-1.0-cl8', 'Artistic-1.0-cl8'], ['artistic-2.0', 'Artistic-2.0'], - ['artistic-1.0', 'Artistic-1.0'], ['artistic-clarified', 'ClArtistic'], + ['artistic-dist-1.0', 'LicenseRef-scancode-artistic-1988-1.0'], ['artistic-perl-1.0', 'Artistic-1.0-Perl'], + ['asal-1.0', 'LicenseRef-scancode-asal-1.0'], + ['ascender-eula', 'LicenseRef-scancode-ascender-eula'], + ['ascender-web-fonts', 'LicenseRef-scancode-ascender-web-fonts'], + ['aslp', 'LicenseRef-scancode-aslp'], + ['aslr', 'LicenseRef-scancode-aslr'], + ['asmus', 'LicenseRef-scancode-asmus'], + ['asn1', 'LicenseRef-scancode-asn1'], + ['asterisk-exception', 'Asterisk-exception'], + ['aswf-digital-assets-1.0', 'ASWF-Digital-Assets-1.0'], + ['aswf-digital-assets-1.1', 'ASWF-Digital-Assets-1.1'], + ['ati-eula', 'LicenseRef-scancode-ati-eula'], + ['atkinson-hyperlegible-font', 'LicenseRef-scancode-atkinson-hyperlegible-font'], + ['atlassian-marketplace-tou', 'LicenseRef-scancode-atlassian-marketplace-tou'], + ['atmel-firmware', 'LicenseRef-scancode-atmel-firmware'], + ['atmel-linux-firmware', 'LicenseRef-scancode-atmel-linux-firmware'], + ['atmel-microcontroller', 'LicenseRef-scancode-atmel-microcontroller'], + ['atmosphere-0.4', 'LicenseRef-scancode-atmosphere-0.4'], ['attribution', 'AAL'], + ['authorizenet-sdk', 'LicenseRef-scancode-authorizenet-sdk'], ['autoconf-exception-2.0', 'Autoconf-exception-2.0'], ['autoconf-exception-3.0', 'Autoconf-exception-3.0'], + ['autoconf-macro-exception', 'Autoconf-exception-macro'], + ['autoconf-simple-exception', 'Autoconf-exception-generic-3.0'], + ['autoconf-simple-exception-2.0', 'Autoconf-exception-generic'], + ['autodesk-3d-sft-3.0', 'LicenseRef-scancode-autodesk-3d-sft-3.0'], + ['autoit-eula', 'LicenseRef-scancode-autoit-eula'], + ['autoopts-exception-2.0', 'LicenseRef-scancode-autoopts-exception-2.0'], + ['avisynth-c-interface-exception', 'LicenseRef-scancode-avisynth-c-exception'], + ['avisynth-linking-exception', 'LicenseRef-scancode-avisynth-linking-exception'], + ['avsystem-5-clause', 'LicenseRef-scancode-avsystem-5-clause'], + ['bacula-exception', 'LicenseRef-scancode-bacula-exception'], + ['baekmuk-fonts', 'Baekmuk'], ['bahyph', 'Bahyph'], + ['bakoma-fonts-1995', 'LicenseRef-scancode-bakoma-fonts-1995'], + ['bapl-1.0', 'LicenseRef-scancode-bapl-1.0'], ['barr-tex', 'Barr'], + ['bash-exception-gpl', 'LicenseRef-scancode-bash-exception-gpl-2.0'], + ['bcrypt-solar-designer', 'bcrypt-Solar-Designer'], + ['bea-2.1', 'LicenseRef-scancode-bea-2.1'], + ['beal-screamer', 'LicenseRef-scancode-beal-screamer'], ['beerware', 'Beerware'], + ['beri-hw-sw-1.0', 'LicenseRef-scancode-beri-hw-sw-1.0'], + ['bigcode-open-rail-m-v1', 'LicenseRef-scancode-bigcode-open-rail-m-v1'], + ['bigdigits', 'LicenseRef-scancode-bigdigits'], + ['bigelow-holmes', 'Lucida-Bitmap-Fonts'], + ['bigscience-open-rail-m', 'LicenseRef-scancode-bigscience-open-rail-m'], + ['bigscience-rail-1.0', 'LicenseRef-scancode-bigscience-rail-1.0'], + ['binary-linux-firmware', 'LicenseRef-scancode-binary-linux-firmware'], + ['binary-linux-firmware-patent', 'LicenseRef-scancode-binary-linux-firmware-patent'], + ['biopython', 'LicenseRef-scancode-biopython'], + ['biosl-4.0', 'LicenseRef-scancode-biosl-4.0'], + ['bison-exception-2.0', 'Bison-exception-1.24'], ['bison-exception-2.2', 'Bison-exception-2.2'], + ['bitstream', 'Bitstream-Vera'], ['bittorrent-1.0', 'BitTorrent-1.0'], ['bittorrent-1.1', 'BitTorrent-1.1'], + ['bittorrent-1.2', 'LicenseRef-scancode-bittorrent-1.2'], + ['bittorrent-eula', 'LicenseRef-scancode-bittorrent-eula'], + ['bitwarden-1.0', 'LicenseRef-scancode-bitwarden-1.0'], + ['bitzi-pd', 'LicenseRef-scancode-bitzi-pd'], + ['blas-2017', 'LicenseRef-scancode-blas-2017'], + ['blender-2010', 'LicenseRef-scancode-blender-2010'], + ['blessing', 'blessing'], + ['blitz-artistic', 'LicenseRef-scancode-blitz-artistic'], + ['bloomberg-blpapi', 'LicenseRef-scancode-bloomberg-blpapi'], + ['blueoak-1.0.0', 'BlueOak-1.0.0'], + ['bohl-0.2', 'LicenseRef-scancode-bohl-0.2'], ['boost-1.0', 'BSL-1.0'], + ['boost-original', 'LicenseRef-scancode-boost-original'], ['bootloader-exception', 'Bootloader-exception'], ['borceux', 'Borceux'], + ['boutell-libgd-2021', 'LicenseRef-scancode-boutell-libgd-2021'], + ['bpel4ws-spec', 'LicenseRef-scancode-bpel4ws-spec'], + ['bpmn-io', 'LicenseRef-scancode-bpmn-io'], + ['brad-martinez-vb-32', 'LicenseRef-scancode-brad-martinez-vb-32'], + ['brankas-open-license-1.0', 'LicenseRef-scancode-brankas-open-license-1.0'], + ['brent-corkum', 'LicenseRef-scancode-brent-corkum'], + ['brian-clapper', 'LicenseRef-scancode-brian-clapper'], + ['brian-gladman', 'Brian-Gladman-2-Clause'], + ['brian-gladman-3-clause', 'LicenseRef-scancode-brian-gladman-3-clause'], + ['brian-gladman-dual', 'Brian-Gladman-3-Clause'], + ['broadcom-cfe', 'LicenseRef-scancode-broadcom-cfe'], + ['broadcom-commercial', 'LicenseRef-scancode-broadcom-commercial'], + ['broadcom-confidential', 'LicenseRef-scancode-broadcom-confidential'], + ['broadcom-dual', 'null'], + ['broadcom-linking-exception-2.0', 'LicenseRef-scancode-bcm-linking-exception-2.0'], + ['broadcom-linking-unmodified', 'LicenseRef-scancode-broadcom-linking-unmodified'], + ['broadcom-linux-firmware', 'LicenseRef-scancode-broadcom-linux-firmware'], + ['broadcom-linux-timer', 'LicenseRef-scancode-broadcom-linux-timer'], + ['broadcom-opus-patent', 'LicenseRef-scancode-broadcom-opus-patent'], + ['broadcom-proprietary', 'LicenseRef-scancode-broadcom-proprietary'], + ['broadcom-raspberry-pi', 'LicenseRef-scancode-broadcom-raspberry-pi'], + ['broadcom-standard-terms', 'LicenseRef-scancode-broadcom-standard-terms'], + ['broadcom-unmodified-exception', 'LicenseRef-scancode-broadcom-unmodified-exception'], + ['broadcom-unpublished-source', 'null'], + ['broadcom-wiced', 'LicenseRef-scancode-broadcom-wiced'], + ['broadleaf-fair-use', 'LicenseRef-scancode-broadleaf-fair-use'], + ['brocade-firmware', 'LicenseRef-scancode-brocade-firmware'], + ['bruno-podetti', 'LicenseRef-scancode-bruno-podetti'], ['bsd-1-clause', 'BSD-1-Clause'], - ['bsd-2-clause-freebsd', 'BSD-2-Clause-FreeBSD'], - ['bsd-2-clause-netbsd', 'BSD-2-Clause-NetBSD'], + ['bsd-1-clause-build', 'LicenseRef-scancode-bsd-1-clause-build'], + ['bsd-1988', 'LicenseRef-scancode-bsd-1988'], + ['bsd-2-clause-freebsd', 'null'], + ['bsd-2-clause-netbsd', 'null'], + ['bsd-2-clause-plus-advertizing', 'LicenseRef-scancode-bsd-2-clause-plus-advertizing'], + ['bsd-2-clause-views', 'BSD-2-Clause-Views'], + ['bsd-3-clause-devine', 'LicenseRef-scancode-bsd-3-clause-devine'], + ['bsd-3-clause-fda', 'LicenseRef-scancode-bsd-3-clause-fda'], + ['bsd-3-clause-hp', 'BSD-3-Clause-HP'], + ['bsd-3-clause-jtag', 'LicenseRef-scancode-bsd-3-clause-jtag'], + ['bsd-3-clause-no-change', 'LicenseRef-scancode-bsd-3-clause-no-change'], + ['bsd-3-clause-no-military', 'BSD-3-Clause-No-Military-License'], ['bsd-3-clause-no-nuclear-warranty', 'BSD-3-Clause-No-Nuclear-Warranty'], + ['bsd-3-clause-no-trademark', 'LicenseRef-scancode-bsd-3-clause-no-trademark'], + ['bsd-3-clause-open-mpi', 'BSD-3-Clause-Open-MPI'], + ['bsd-3-clause-sun', 'BSD-3-Clause-Sun'], + ['bsd-4-clause-shortened', 'BSD-4-Clause-Shortened'], ['bsd-ack', 'BSD-3-Clause-Attribution'], + ['bsd-ack-carrot2', 'LicenseRef-scancode-bsd-ack-carrot2'], + ['bsd-advertising-acknowledgement', 'BSD-Advertising-Acknowledgement'], + ['bsd-artwork', 'LicenseRef-scancode-bsd-artwork'], + ['bsd-atmel', 'LicenseRef-scancode-bsd-atmel'], + ['bsd-axis', 'null'], + ['bsd-axis-nomod', 'LicenseRef-scancode-bsd-axis-nomod'], + ['bsd-credit', 'LicenseRef-scancode-bsd-credit'], + ['bsd-dpt', 'LicenseRef-scancode-bsd-dpt'], + ['bsd-export', 'LicenseRef-scancode-bsd-export'], + ['bsd-inferno-nettverk', 'BSD-Inferno-Nettverk'], + ['bsd-innosys', 'LicenseRef-scancode-bsd-innosys'], + ['bsd-intel', 'null'], + ['bsd-mylex', 'LicenseRef-scancode-bsd-mylex'], ['bsd-new', 'BSD-3-Clause'], + ['bsd-new-derivative', 'LicenseRef-scancode-bsd-new-derivative'], + ['bsd-new-far-manager', 'null'], + ['bsd-new-nomod', 'LicenseRef-scancode-bsd-new-nomod'], + ['bsd-new-tcpdump', 'LicenseRef-scancode-bsd-new-tcpdump'], + ['bsd-no-disclaimer', 'LicenseRef-scancode-bsd-no-disclaimer'], + ['bsd-no-disclaimer-unmodified', 'LicenseRef-scancode-bsd-no-disclaimer-unmodified'], + ['bsd-no-mod', 'LicenseRef-scancode-bsd-no-mod'], ['bsd-original', 'BSD-4-Clause'], + ['bsd-original-muscle', 'LicenseRef-scancode-bsd-original-muscle'], ['bsd-original-uc', 'BSD-4-Clause-UC'], - ['bsd-protection', 'BSD-Protection'], + ['bsd-original-uc-1986', 'BSD-4.3RENO'], + ['bsd-original-uc-1990', 'null'], + ['bsd-original-voices', 'LicenseRef-scancode-bsd-original-voices'], + ['bsd-plus-mod-notice', 'LicenseRef-scancode-bsd-plus-mod-notice'], ['bsd-plus-patent', 'BSD-2-Clause-Patent'], + ['bsd-protection', 'BSD-Protection'], ['bsd-simplified', 'BSD-2-Clause'], + ['bsd-simplified-darwin', 'BSD-2-Clause-Darwin'], + ['bsd-simplified-intel', 'LicenseRef-scancode-bsd-simplified-intel'], + ['bsd-simplified-source', 'LicenseRef-scancode-bsd-simplified-source'], ['bsd-source-code', 'BSD-Source-Code'], + ['bsd-systemics', 'BSD-Systemics'], + ['bsd-systemics-w3works', 'BSD-Systemics-W3Works'], + ['bsd-top', 'BSD-Source-beginning-file'], + ['bsd-top-gpl-addition', 'LicenseRef-scancode-bsd-top-gpl-addition'], + ['bsd-unchanged', 'LicenseRef-scancode-bsd-unchanged'], + ['bsd-unmodified', 'LicenseRef-scancode-bsd-unmodified'], + ['bsd-x11', 'LicenseRef-scancode-bsd-x11'], ['bsd-zero', '0BSD'], + ['bsl-1.0', 'LicenseRef-scancode-bsl-1.0'], + ['bsl-1.1', 'BUSL-1.1'], + ['bsla', 'BSD-4.3TAHOE'], + ['bsla-no-advert', 'LicenseRef-scancode-bsla-no-advert'], + ['bugsense-sdk', 'LicenseRef-scancode-bugsense-sdk'], + ['bytemark', 'LicenseRef-scancode-bytemark'], + ['bzip2-libbzip-1.0.5', 'null'], ['bzip2-libbzip-2010', 'bzip2-1.0.6'], - ['caldera', 'Caldera'], + ['c-fsl-1.1', 'LicenseRef-scancode-c-fsl-1.1'], + ['c-uda-1.0', 'C-UDA-1.0'], ['ca-tosl-1.1', 'CATOSL-1.1'], - ['bzip2-libbzip-1.0.5', 'bzip2-1.0.5'], + ['cadence-linux-firmware', 'LicenseRef-scancode-cadence-linux-firmware'], + ['cal-1.0', 'CAL-1.0'], + ['cal-1.0-combined-work-exception', 'CAL-1.0-Combined-Work-Exception'], + ['caldera', 'Caldera'], + ['caldera-no-preamble', 'Caldera-no-preamble'], + ['can-ogl-2.0-en', 'OGL-Canada-2.0'], + ['can-ogl-alberta-2.1', 'LicenseRef-scancode-can-ogl-alberta-2.1'], + ['can-ogl-british-columbia-2.0', 'LicenseRef-scancode-can-ogl-british-columbia-2.0'], + ['can-ogl-nova-scotia-1.0', 'LicenseRef-scancode-can-ogl-nova-scotia-1.0'], + ['can-ogl-ontario-1.0', 'LicenseRef-scancode-can-ogl-ontario-1.0'], + ['can-ogl-toronto-1.0', 'LicenseRef-scancode-can-ogl-toronto-1.0'], + ['canonical-ha-cla-any-e-v1.2', 'LicenseRef-scancode-canonical-ha-cla-any-e-v1.2'], + ['canonical-ha-cla-any-i-v1.2', 'LicenseRef-scancode-canonical-ha-cla-any-i-v1.2'], + ['capec-tou', 'LicenseRef-scancode-capec-tou'], + ['careware', 'LicenseRef-scancode-careware'], + ['carnegie-mellon', 'LicenseRef-scancode-carnegie-mellon'], + ['carnegie-mellon-contributors', 'CMU-Mach'], + ['catharon-osl', 'LicenseRef-scancode-catharon-osl'], + ['cavium-linux-firmware', 'LicenseRef-scancode-cavium-linux-firmware'], + ['cavium-malloc', 'LicenseRef-scancode-cavium-malloc'], + ['cavium-targeted-hardware', 'LicenseRef-scancode-cavium-targeted-hardware'], ['cc-by-1.0', 'CC-BY-1.0'], + ['cc-by-2.0', 'CC-BY-2.0'], + ['cc-by-2.0-uk', 'LicenseRef-scancode-cc-by-2.0-uk'], ['cc-by-2.5', 'CC-BY-2.5'], - ['cc-by-4.0', 'CC-BY-4.0'], + ['cc-by-2.5-au', 'CC-BY-2.5-AU'], ['cc-by-3.0', 'CC-BY-3.0'], - ['cc-by-2.0', 'CC-BY-2.0'], + ['cc-by-3.0-at', 'CC-BY-3.0-AT'], + ['cc-by-3.0-au', 'CC-BY-3.0-AU'], + ['cc-by-3.0-de', 'CC-BY-3.0-DE'], + ['cc-by-3.0-igo', 'CC-BY-3.0-IGO'], + ['cc-by-3.0-nl', 'CC-BY-3.0-NL'], + ['cc-by-3.0-us', 'CC-BY-3.0-US'], + ['cc-by-4.0', 'CC-BY-4.0'], ['cc-by-nc-1.0', 'CC-BY-NC-1.0'], - ['cc-by-nc-3.0', 'CC-BY-NC-3.0'], + ['cc-by-nc-2.0', 'CC-BY-NC-2.0'], ['cc-by-nc-2.5', 'CC-BY-NC-2.5'], + ['cc-by-nc-3.0', 'CC-BY-NC-3.0'], + ['cc-by-nc-3.0-de', 'CC-BY-NC-3.0-DE'], ['cc-by-nc-4.0', 'CC-BY-NC-4.0'], ['cc-by-nc-nd-1.0', 'CC-BY-NC-ND-1.0'], - ['cc-by-nc-2.0', 'CC-BY-NC-2.0'], ['cc-by-nc-nd-2.0', 'CC-BY-NC-ND-2.0'], - ['cc-by-nc-nd-3.0', 'CC-BY-NC-ND-3.0'], + ['cc-by-nc-nd-2.0-at', 'LicenseRef-scancode-cc-by-nc-nd-2.0-at'], + ['cc-by-nc-nd-2.0-au', 'LicenseRef-scancode-cc-by-nc-nd-2.0-au'], ['cc-by-nc-nd-2.5', 'CC-BY-NC-ND-2.5'], + ['cc-by-nc-nd-3.0', 'CC-BY-NC-ND-3.0'], + ['cc-by-nc-nd-3.0-de', 'CC-BY-NC-ND-3.0-DE'], + ['cc-by-nc-nd-3.0-igo', 'CC-BY-NC-ND-3.0-IGO'], ['cc-by-nc-nd-4.0', 'CC-BY-NC-ND-4.0'], - ['cc-by-nc-sa-3.0', 'CC-BY-NC-SA-3.0'], + ['cc-by-nc-sa-1.0', 'CC-BY-NC-SA-1.0'], + ['cc-by-nc-sa-2.0', 'CC-BY-NC-SA-2.0'], + ['cc-by-nc-sa-2.0-de', 'CC-BY-NC-SA-2.0-DE'], + ['cc-by-nc-sa-2.0-fr', 'CC-BY-NC-SA-2.0-FR'], + ['cc-by-nc-sa-2.0-uk', 'CC-BY-NC-SA-2.0-UK'], ['cc-by-nc-sa-2.5', 'CC-BY-NC-SA-2.5'], + ['cc-by-nc-sa-3.0', 'CC-BY-NC-SA-3.0'], + ['cc-by-nc-sa-3.0-de', 'CC-BY-NC-SA-3.0-DE'], + ['cc-by-nc-sa-3.0-igo', 'CC-BY-NC-SA-3.0-IGO'], + ['cc-by-nc-sa-3.0-us', 'LicenseRef-scancode-cc-by-nc-sa-3.0-us'], ['cc-by-nc-sa-4.0', 'CC-BY-NC-SA-4.0'], ['cc-by-nd-1.0', 'CC-BY-ND-1.0'], - ['cc-by-nd-3.0', 'CC-BY-ND-3.0'], - ['cc-by-nc-sa-1.0', 'CC-BY-NC-SA-1.0'], - ['cc-by-nc-sa-2.0', 'CC-BY-NC-SA-2.0'], ['cc-by-nd-2.0', 'CC-BY-ND-2.0'], ['cc-by-nd-2.5', 'CC-BY-ND-2.5'], + ['cc-by-nd-3.0', 'CC-BY-ND-3.0'], + ['cc-by-nd-3.0-de', 'CC-BY-ND-3.0-DE'], ['cc-by-nd-4.0', 'CC-BY-ND-4.0'], ['cc-by-sa-1.0', 'CC-BY-SA-1.0'], ['cc-by-sa-2.0', 'CC-BY-SA-2.0'], + ['cc-by-sa-2.0-uk', 'CC-BY-SA-2.0-UK'], + ['cc-by-sa-2.1-jp', 'CC-BY-SA-2.1-JP'], ['cc-by-sa-2.5', 'CC-BY-SA-2.5'], ['cc-by-sa-3.0', 'CC-BY-SA-3.0'], + ['cc-by-sa-3.0-at', 'CC-BY-SA-3.0-AT'], + ['cc-by-sa-3.0-de', 'CC-BY-SA-3.0-DE'], + ['cc-by-sa-3.0-igo', 'CC-BY-SA-3.0-IGO'], ['cc-by-sa-4.0', 'CC-BY-SA-4.0'], + ['cc-devnations-2.0', 'LicenseRef-scancode-cc-devnations-2.0'], + ['cc-gpl-2.0-pt', 'LicenseRef-scancode-cc-gpl-2.0-pt'], + ['cc-lgpl-2.1-pt', 'LicenseRef-scancode-cc-lgpl-2.1-pt'], + ['cc-nc-1.0', 'LicenseRef-scancode-cc-nc-1.0'], + ['cc-nc-sampling-plus-1.0', 'LicenseRef-scancode-cc-nc-sampling-plus-1.0'], + ['cc-nd-1.0', 'LicenseRef-scancode-cc-nd-1.0'], + ['cc-pd', 'CC-PDDC'], + ['cc-pdm-1.0', 'LicenseRef-scancode-cc-pdm-1.0'], + ['cc-sa-1.0', 'LicenseRef-scancode-cc-sa-1.0'], + ['cc-sampling-1.0', 'LicenseRef-scancode-cc-sampling-1.0'], + ['cc-sampling-plus-1.0', 'LicenseRef-scancode-cc-sampling-plus-1.0'], ['cc0-1.0', 'CC0-1.0'], + ['cclrc', 'LicenseRef-scancode-cclrc'], + ['ccrc-1.0', 'null'], ['cddl-1.0', 'CDDL-1.0'], - ['cdla-sharing-1.0', 'CDLA-Sharing-1.0'], - ['cdla-permissive-1.0', 'CDLA-Permissive-1.0'], ['cddl-1.1', 'CDDL-1.1'], + ['cdla-permissive-1.0', 'CDLA-Permissive-1.0'], + ['cdla-permissive-2.0', 'CDLA-Permissive-2.0'], + ['cdla-sharing-1.0', 'CDLA-Sharing-1.0'], ['cecill-1.0', 'CECILL-1.0'], - ['cecill-b', 'CECILL-B'], - ['cecill-2.0', 'CECILL-2.0'], + ['cecill-1.0-en', 'LicenseRef-scancode-cecill-1.0-en'], ['cecill-1.1', 'CECILL-1.1'], + ['cecill-2.0', 'CECILL-2.0'], + ['cecill-2.0-fr', 'LicenseRef-scancode-cecill-2.0-fr'], ['cecill-2.1', 'CECILL-2.1'], + ['cecill-2.1-fr', 'LicenseRef-scancode-cecill-2.1-fr'], + ['cecill-b', 'CECILL-B'], + ['cecill-b-en', 'LicenseRef-scancode-cecill-b-en'], ['cecill-c', 'CECILL-C'], - ['classworlds', 'Plexus'], - ['clisp-exception-2.0', 'CLISP-exception-2.0'], - ['clear-bsd', 'BSD-3-Clause-Clear'], + ['cecill-c-en', 'LicenseRef-scancode-cecill-c-en'], + ['cern-attribution-1995', 'LicenseRef-scancode-cern-attribution-1995'], + ['cern-ohl-1.1', 'CERN-OHL-1.1'], + ['cern-ohl-1.2', 'CERN-OHL-1.2'], + ['cern-ohl-p-2.0', 'CERN-OHL-P-2.0'], + ['cern-ohl-s-2.0', 'CERN-OHL-S-2.0'], + ['cern-ohl-w-2.0', 'CERN-OHL-W-2.0'], + ['cfitsio', 'CFITSIO'], + ['cgic', 'LicenseRef-scancode-cgic'], + ['chartdirector-6.0', 'LicenseRef-scancode-chartdirector-6.0'], + ['check-cvs', 'check-cvs'], + ['checkmk', 'checkmk'], + ['chelsio-linux-firmware', 'LicenseRef-scancode-chelsio-linux-firmware'], + ['chicken-dl-0.2', 'LicenseRef-scancode-chicken-dl-0.2'], + ['chris-maunder', 'LicenseRef-scancode-chris-maunder'], + ['chris-stoy', 'LicenseRef-scancode-chris-stoy'], + ['christopher-velazquez', 'LicenseRef-scancode-christopher-velazquez'], + ['cisco-avch264-patent', 'LicenseRef-scancode-cisco-avch264-patent'], + ['civicrm-exception-to-agpl-3.0', 'LicenseRef-scancode-civicrm-exception-to-agpl-3.0'], + ['classic-vb', 'LicenseRef-scancode-classic-vb'], ['classpath-exception-2.0', 'Classpath-exception-2.0'], - ['cnri-jython', 'CNRI-Jython'], + ['classworlds', 'null'], + ['clause-6-exception-lgpl-2.1', 'LicenseRef-scancode-clause-6-exception-lgpl-2.1'], + ['clear-bsd', 'BSD-3-Clause-Clear'], + ['clear-bsd-1-clause', 'LicenseRef-scancode-clear-bsd-1-clause'], + ['click-license', 'LicenseRef-scancode-click-license'], + ['clips-2017', 'Clips'], + ['clisp-exception-2.0', 'CLISP-exception-2.0'], + ['clojure-exception-to-gpl-3.0', 'LicenseRef-scancode-clojure-exception-to-gpl-3.0'], + ['cloudera-express', 'LicenseRef-scancode-cloudera-express'], + ['cmigemo', 'LicenseRef-scancode-cmigemo'], + ['cmr-no', 'null'], + ['cmu-computing-services', 'BSD-Attribution-HPND-disclaimer'], + ['cmu-flite', 'LicenseRef-scancode-cmu-flite'], + ['cmu-mit', 'LicenseRef-scancode-cmu-mit'], + ['cmu-nara-nagoya', 'LicenseRef-scancode-cmu-nara-nagoya'], + ['cmu-simple', 'LicenseRef-scancode-cmu-simple'], + ['cmu-template', 'LicenseRef-scancode-cmu-template'], ['cmu-uc', 'MIT-CMU'], + ['cncf-corporate-cla-1.0', 'LicenseRef-scancode-cncf-corporate-cla-1.0'], + ['cncf-individual-cla-1.0', 'LicenseRef-scancode-cncf-individual-cla-1.0'], + ['cnri-jython', 'CNRI-Jython'], ['cnri-python-1.6', 'CNRI-Python'], ['cnri-python-1.6.1', 'CNRI-Python-GPL-Compatible'], - ['copyleft-next-0.3.1', 'copyleft-next-0.3.1'], + ['cockroach', 'LicenseRef-scancode-cockroach'], + ['cockroachdb-use-grant-for-bsl-1.1', 'LicenseRef-scancode-cockroachdb-use-grant-bsl-1.1'], + ['code-credit-license-1.0-0', 'LicenseRef-scancode-code-credit-license-1.0.0'], + ['code-credit-license-1.0.1', 'LicenseRef-scancode-code-credit-license-1.0.1'], + ['code-credit-license-1.1.0', 'LicenseRef-scancode-code-credit-license-1.1.0'], + ['codeguru-permissions', 'LicenseRef-scancode-codeguru-permissions'], + ['codelite-exception-to-gpl', 'LicenseRef-scancode-codelite-exception-to-gpl'], + ['codesourcery-2004', 'LicenseRef-scancode-codesourcery-2004'], + ['codexia', 'LicenseRef-scancode-codexia'], + ['cognitive-web-osl-1.1', 'LicenseRef-scancode-cognitive-web-osl-1.1'], + ['coil-1.0', 'COIL-1.0'], + ['colt', 'LicenseRef-scancode-colt'], + ['com-oreilly-servlet', 'LicenseRef-scancode-com-oreilly-servlet'], + ['commercial-license', 'LicenseRef-scancode-commercial-license'], + ['commercial-option', 'null'], + ['commonj-timer', 'LicenseRef-scancode-commonj-timer'], + ['commons-clause', 'LicenseRef-scancode-commons-clause'], + ['compass', 'LicenseRef-scancode-compass'], + ['componentace-jcraft', 'LicenseRef-scancode-componentace-jcraft'], + ['compuphase-linking-exception', 'LicenseRef-scancode-compuphase-linking-exception'], + ['concursive-pl-1.0', 'LicenseRef-scancode-concursive-pl-1.0'], ['condor-1.1', 'Condor-1.1'], + ['confluent-community-1.0', 'LicenseRef-scancode-confluent-community-1.0'], + ['cooperative-non-violent-4.0', 'LicenseRef-scancode-cooperative-non-violent-4.0'], + ['cooperative-non-violent-6.0', 'LicenseRef-scancode-cooperative-non-violent-6.0'], + ['cooperative-non-violent-7.0', 'LicenseRef-scancode-cooperative-non-violent-7.0'], + ['copyheart', 'LicenseRef-scancode-copyheart'], + ['copyleft-next-0.3.0', 'copyleft-next-0.3.0'], + ['copyleft-next-0.3.1', 'copyleft-next-0.3.1'], + ['cornell-lossless-jpeg', 'Cornell-Lossless-JPEG'], + ['corporate-accountability-1.1', 'LicenseRef-scancode-corporate-accountability-1.1'], + ['corporate-accountability-commercial-1.1', 'LicenseRef-scancode-accountability-commercial-1.1'], + ['cosl', 'LicenseRef-scancode-cosl'], + ['cosli', 'LicenseRef-scancode-cosli'], + ['couchbase-community', 'LicenseRef-scancode-couchbase-community'], + ['couchbase-enterprise', 'LicenseRef-scancode-couchbase-enterprise'], ['cpal-1.0', 'CPAL-1.0'], + ['cpl-0.5', 'LicenseRef-scancode-cpl-0.5'], ['cpl-1.0', 'CPL-1.0'], + ['cpm-2022', 'LicenseRef-scancode-cpm-2022'], + ['cpol-1.0', 'LicenseRef-scancode-cpol-1.0'], ['cpol-1.02', 'CPOL-1.02'], - ['crystal-stacker', 'CrystalStacker'], + ['cpp-core-guidelines', 'LicenseRef-scancode-cpp-core-guidelines'], + ['crapl-0.1', 'LicenseRef-scancode-crapl-0.1'], + ['crashlytics-agreement-2018', 'LicenseRef-scancode-crashlytics-agreement-2018'], + ['crcalc', 'LicenseRef-scancode-crcalc'], + ['cronyx', 'Cronyx'], ['crossword', 'Crossword'], + ['crunchbase-data-2019-12-17', 'LicenseRef-scancode-crunchbase-data-2019-12-17'], + ['crypto-keys-redistribution', 'LicenseRef-scancode-crypto-keys-redistribution'], + ['cryptopp', 'LicenseRef-scancode-cryptopp'], + ['crystal-stacker', 'CrystalStacker'], + ['csl-1.0', 'Community-Spec-1.0'], + ['csla', 'LicenseRef-scancode-csla'], + ['csprng', 'LicenseRef-scancode-csprng'], + ['ctl-linux-firmware', 'LicenseRef-scancode-ctl-linux-firmware'], ['cua-opl-1.0', 'CUA-OPL-1.0'], ['cube', 'Cube'], + ['cubiware-software-1.0', 'LicenseRef-scancode-cubiware-software-1.0'], + ['cups', 'LicenseRef-scancode-cups'], + ['cups-apple-os-exception', 'LicenseRef-scancode-cups-apple-os-exception'], ['curl', 'curl'], + ['cve-tou', 'LicenseRef-scancode-cve-tou'], + ['cvwl', 'LicenseRef-scancode-cvwl'], + ['cwe-tou', 'LicenseRef-scancode-cwe-tou'], + ['cximage', 'LicenseRef-scancode-cximage'], + ['cygwin-exception-2.0', 'LicenseRef-scancode-cygwin-exception-2.0'], + ['cygwin-exception-3.0', 'LicenseRef-scancode-cygwin-exception-3.0'], + ['cygwin-exception-lgpl-3.0-plus', 'LicenseRef-scancode-cygwin-exception-lgpl-3.0-plus'], + ['cypress-linux-firmware', 'LicenseRef-scancode-cypress-linux-firmware'], ['d-fsl-1.0-de', 'D-FSL-1.0'], + ['d-fsl-1.0-en', 'LicenseRef-scancode-d-fsl-1.0-en'], + ['d-zlib', 'LicenseRef-scancode-d-zlib'], + ['damail', 'LicenseRef-scancode-damail'], + ['dante-treglia', 'LicenseRef-scancode-dante-treglia'], + ['datamekanix-license', 'LicenseRef-scancode-datamekanix-license'], + ['day-spec', 'LicenseRef-scancode-day-spec'], + ['dbad', 'LicenseRef-scancode-dbad'], + ['dbad-1.1', 'LicenseRef-scancode-dbad-1.1'], + ['dbcl-1.0', 'LicenseRef-scancode-dbcl-1.0'], + ['dbmx-foss-exception-1.0.9', 'LicenseRef-scancode-dbmx-foss-exception-1.0.9'], + ['dbmx-linking-exception-1.0', 'LicenseRef-scancode-dbmx-linking-exception-1.0'], + ['dco-1.1', 'LicenseRef-scancode-dco-1.1'], + ['dec-3-clause', 'DEC-3-Clause'], + ['defensive-patent-1.1', 'LicenseRef-scancode-defensive-patent-1.1'], + ['dejavu-font', 'LicenseRef-scancode-dejavu-font'], + ['delorie-historical', 'LicenseRef-scancode-delorie-historical'], + ['dennis-ferguson', 'LicenseRef-scancode-dennis-ferguson'], + ['devblocks-1.0', 'LicenseRef-scancode-devblocks-1.0'], + ['dgraph-cla', 'LicenseRef-scancode-dgraph-cla'], + ['dhb-lbnl-bsd-2007', 'LicenseRef-scancode-dhb-lbnl-bsd-2007'], + ['dhb-limited-bsd-2015', 'LicenseRef-scancode-dhb-limited-bsd-2015'], + ['dhtmlab-public', 'LicenseRef-scancode-dhtmlab-public'], ['diffmark', 'diffmark'], + ['digia-qt-commercial', 'LicenseRef-scancode-digia-qt-commercial'], + ['digia-qt-exception-lgpl-2.1', 'null'], + ['digia-qt-preview', 'LicenseRef-scancode-digia-qt-preview'], ['digirule-foss-exception', 'DigiRule-FOSS-exception'], + ['divx-open-1.0', 'LicenseRef-scancode-divx-open-1.0'], + ['divx-open-2.1', 'LicenseRef-scancode-divx-open-2.1'], + ['dl-de-by-1-0-de', 'LicenseRef-scancode-dl-de-by-1-0-de'], + ['dl-de-by-1-0-en', 'LicenseRef-scancode-dl-de-by-1-0-en'], + ['dl-de-by-2-0-de', 'DL-DE-BY-2.0'], + ['dl-de-by-2-0-en', 'LicenseRef-scancode-dl-de-by-2-0-en'], + ['dl-de-by-nc-1-0-de', 'LicenseRef-scancode-dl-de-by-nc-1-0-de'], + ['dl-de-by-nc-1-0-en', 'LicenseRef-scancode-dl-de-by-nc-1-0-en'], + ['dl-de-zero-2.0', 'DL-DE-ZERO-2.0'], + ['dmalloc', 'LicenseRef-scancode-dmalloc'], + ['dmtf-2017', 'LicenseRef-scancode-dmtf-2017'], + ['do-no-harm-0.1', 'LicenseRef-scancode-do-no-harm-0.1'], + ['docbook', 'LicenseRef-scancode-docbook'], + ['dom4j', 'Plexus'], + ['dos32a-extender', 'LicenseRef-scancode-dos32a-extender'], ['dotseqn', 'Dotseqn'], + ['doug-lea', 'null'], + ['douglas-young', 'LicenseRef-scancode-douglas-young'], + ['dpl-1.1', 'LicenseRef-scancode-dpl-1.1'], + ['dr-john-maddock', 'null'], + ['drl-1.0', 'DRL-1.0'], + ['drl-1.1', 'DRL-1.1'], + ['dropbear', 'LicenseRef-scancode-dropbear'], + ['dropbear-2016', 'LicenseRef-scancode-dropbear-2016'], ['dsdp', 'DSDP'], + ['dtree', 'LicenseRef-scancode-dtree'], + ['dual-bsd-gpl', 'null'], + ['dual-commercial-gpl', 'LicenseRef-scancode-dual-commercial-gpl'], + ['duende-sla-2022', 'LicenseRef-scancode-duende-sla-2022'], + ['dune-exception', 'LicenseRef-scancode-dune-exception'], ['dvipdfm', 'dvipdfm'], + ['dwtfnmfpl-3.0', 'LicenseRef-scancode-dwtfnmfpl-3.0'], + ['dynamic-drive-tou', 'LicenseRef-scancode-dynamic-drive-tou'], + ['dynarch-developer', 'LicenseRef-scancode-dynarch-developer'], + ['dynarch-linkware', 'LicenseRef-scancode-dynarch-linkware'], + ['ecfonts-1.0', 'LicenseRef-scancode-ecfonts-1.0'], ['ecl-1.0', 'ECL-1.0'], - ['ecos-exception-2.0', 'eCos-exception-2.0'], ['ecl-2.0', 'ECL-2.0'], + ['eclipse-sua-2001', 'LicenseRef-scancode-eclipse-sua-2001'], + ['eclipse-sua-2002', 'LicenseRef-scancode-eclipse-sua-2002'], + ['eclipse-sua-2003', 'LicenseRef-scancode-eclipse-sua-2003'], + ['eclipse-sua-2004', 'LicenseRef-scancode-eclipse-sua-2004'], + ['eclipse-sua-2005', 'LicenseRef-scancode-eclipse-sua-2005'], + ['eclipse-sua-2010', 'LicenseRef-scancode-eclipse-sua-2010'], + ['eclipse-sua-2011', 'LicenseRef-scancode-eclipse-sua-2011'], + ['eclipse-sua-2014', 'LicenseRef-scancode-eclipse-sua-2014'], + ['eclipse-sua-2014-11', 'LicenseRef-scancode-eclipse-sua-2014-11'], + ['eclipse-sua-2017', 'LicenseRef-scancode-eclipse-sua-2017'], + ['ecma-documentation', 'LicenseRef-scancode-ecma-documentation'], + ['ecma-no-patent', 'LicenseRef-scancode-ecma-no-patent'], + ['ecma-patent-coc-0', 'LicenseRef-scancode-ecma-patent-coc-0'], + ['ecma-patent-coc-1', 'LicenseRef-scancode-ecma-patent-coc-1'], + ['ecma-patent-coc-2', 'LicenseRef-scancode-ecma-patent-coc-2'], + ['ecos', 'eCos-2.0'], + ['ecos-exception-2.0', 'eCos-exception-2.0'], + ['ecosrh-1.0', 'LicenseRef-scancode-ecosrh-1.0'], ['ecosrh-1.1', 'RHeCos-1.1'], + ['edrdg-2000', 'LicenseRef-scancode-edrdg-2000'], + ['efl-1.0', 'EFL-1.0'], ['efl-2.0', 'EFL-2.0'], + ['efsl-1.0', 'LicenseRef-scancode-efsl-1.0'], + ['egenix-1.0.0', 'LicenseRef-scancode-egenix-1.0.0'], ['egenix-1.1.0', 'eGenix'], - ['efl-1.0', 'EFL-1.0'], - ['enna', 'MIT-enna'], + ['egrappler', 'LicenseRef-scancode-egrappler'], + ['ej-technologies-eula', 'LicenseRef-scancode-ej-technologies-eula'], + ['ekiga-exception-2.0-plus', 'LicenseRef-scancode-ekiga-exception-2.0-plus'], + ['ekioh', 'null'], + ['elastic-license-2018', 'LicenseRef-scancode-elastic-license-2018'], + ['elastic-license-v2', 'Elastic-2.0'], + ['elib-gpl', 'LicenseRef-scancode-elib-gpl'], + ['ellis-lab', 'LicenseRef-scancode-ellis-lab'], + ['embedthis-evaluation', 'LicenseRef-scancode-embedthis-evaluation'], + ['embedthis-extension', 'LicenseRef-scancode-embedthis-extension'], + ['embedthis-tou-2022', 'LicenseRef-scancode-embedthis-tou-2022'], + ['emit', 'LicenseRef-scancode-emit'], + ['emx-library', 'LicenseRef-scancode-emx-library'], + ['energyplus', 'LicenseRef-scancode-energyplus-2023'], + ['energyplus-bsd', 'LicenseRef-scancode-energyplus-bsd'], + ['enhydra-1.1', 'LicenseRef-scancode-enhydra-1.1'], ['enlightenment', 'MIT-advertising'], + ['enna', 'MIT-enna'], ['entessa-1.0', 'Entessa'], - ['epl-2.0', 'EPL-2.0'], + ['epaperpress', 'LicenseRef-scancode-epaperpress'], + ['epics', 'EPICS'], ['epl-1.0', 'EPL-1.0'], - ['eu-datagrid', 'EUDatagrid'], + ['epl-2.0', 'EPL-2.0'], + ['epo-osl-2005.1', 'LicenseRef-scancode-epo-osl-2005.1'], + ['eric-glass', 'LicenseRef-scancode-eric-glass'], ['erlangpl-1.1', 'ErlPL-1.1'], - ['eupl-1.1', 'EUPL-1.1'], + ['errbot-exception', 'LicenseRef-scancode-errbot-exception'], + ['esri', 'LicenseRef-scancode-esri'], + ['esri-devkit', 'LicenseRef-scancode-esri-devkit'], + ['etalab-2.0', 'etalab-2.0'], + ['etalab-2.0-en', 'LicenseRef-scancode-etalab-2.0-en'], + ['etalab-2.0-fr', 'null'], + ['eu-datagrid', 'EUDatagrid'], ['eupl-1.0', 'EUPL-1.0'], + ['eupl-1.1', 'EUPL-1.1'], ['eupl-1.2', 'EUPL-1.2'], ['eurosym', 'Eurosym'], + ['examdiff', 'LicenseRef-scancode-examdiff'], + ['excelsior-jet-runtime', 'LicenseRef-scancode-excelsior-jet-runtime'], + ['fabien-tassin', 'LicenseRef-scancode-fabien-tassin'], + ['fabric-agreement-2017', 'LicenseRef-scancode-fabric-agreement-2017'], + ['facebook-nuclide', 'LicenseRef-scancode-facebook-nuclide'], + ['facebook-patent-rights-2', 'LicenseRef-scancode-facebook-patent-rights-2'], + ['facebook-software-license', 'LicenseRef-scancode-facebook-software-license'], ['fair', 'Fair'], + ['fair-source-0.9', 'LicenseRef-scancode-fair-source-0.9'], + ['fancyzoom', 'LicenseRef-scancode-fancyzoom'], + ['far-manager-exception', 'LicenseRef-scancode-far-manager-exception'], + ['fastbuild-2012-2020', 'LicenseRef-scancode-fastbuild-2012-2020'], ['fastcgi-devkit', 'OML'], + ['fatfs', 'LicenseRef-scancode-fatfs'], ['fawkes-runtime-exception', 'Fawkes-Runtime-exception'], + ['fbm', 'FBM'], + ['ferguson-twofish', 'Ferguson-Twofish'], + ['fftpack-2004', 'LicenseRef-scancode-fftpack-2004'], + ['filament-group-mit', 'LicenseRef-scancode-filament-group-mit'], + ['first-works-appreciative-1.2', 'LicenseRef-scancode-first-works-appreciative-1.2'], + ['flex-2.5', 'BSD-3-Clause-flex'], + ['flex2sdk', 'LicenseRef-scancode-flex2sdk'], + ['flora-1.1', 'LicenseRef-scancode-flora-1.1'], + ['flowplayer-gpl-3.0', 'LicenseRef-scancode-flowplayer-gpl-3.0'], ['fltk-exception-lgpl-2.0', 'FLTK-exception'], + ['font-alias', 'LicenseRef-scancode-font-alias'], ['font-exception-gpl', 'Font-exception-2.0'], + ['foobar2000', 'LicenseRef-scancode-foobar2000'], + ['fpdf', 'LicenseRef-scancode-fpdf'], + ['fpl', 'LicenseRef-scancode-fpl'], + ['fplot', 'LicenseRef-scancode-fplot'], ['frameworx-1.0', 'Frameworx-1.0'], + ['fraunhofer-fdk-aac-codec', 'FDK-AAC'], + ['fraunhofer-iso-14496-10', 'LicenseRef-scancode-fraunhofer-iso-14496-10'], + ['free-art-1.3', 'LicenseRef-scancode-free-art-1.3'], + ['free-fork', 'LicenseRef-scancode-free-fork'], + ['free-surfer-1.0', 'LicenseRef-scancode-free-surfer-1.0'], + ['free-unknown', 'LicenseRef-scancode-free-unknown'], + ['freebsd-boot', 'LicenseRef-scancode-freebsd-boot'], + ['freebsd-doc', 'FreeBSD-DOC'], + ['freebsd-first', 'LicenseRef-scancode-freebsd-first'], ['freeimage-1.0', 'FreeImage'], + ['freemarker', 'LicenseRef-scancode-freemarker'], + ['freertos-exception-2.0', 'freertos-exception-2.0'], + ['freetts', 'MIT-Festival'], ['freetype', 'FTL'], + ['freetype-patent', 'LicenseRef-scancode-freetype-patent'], + ['froala-owdl-1.0', 'LicenseRef-scancode-froala-owdl-1.0'], + ['frontier-1.0', 'LicenseRef-scancode-frontier-1.0'], ['fsf-ap', 'FSFAP'], - ['freertos-exception-2.0', 'freertos-exception-2.0'], ['fsf-free', 'FSFUL'], + ['fsf-notice', 'LicenseRef-scancode-fsf-notice'], ['fsf-unlimited', 'FSFULLR'], - ['gcc-linking-exception-2.0', 'GCC-exception-2.0'], + ['fsf-unlimited-no-warranty', 'FSFULLRWD'], + ['fsfap-no-warranty-disclaimer', 'FSFAP-no-warranty-disclaimer'], + ['fsl-1.0-apache-2.0', 'LicenseRef-scancode-fsl-1.0-apache-2.0'], + ['fsl-1.0-mit', 'LicenseRef-scancode-fsl-1.0-mit'], + ['ftdi', 'LicenseRef-scancode-ftdi'], + ['ftpbean', 'LicenseRef-scancode-ftpbean'], + ['fujion-exception-to-apache-2.0', 'LicenseRef-scancode-fujion-exception-to-apache-2.0'], + ['furuseth', 'Furuseth'], + ['fwlw', 'fwlw'], + ['g10-permissive', 'LicenseRef-scancode-g10-permissive'], + ['gareth-mccaughan', 'LicenseRef-scancode-gareth-mccaughan'], + ['gary-s-brown', 'LicenseRef-scancode-gary-s-brown'], + ['gatling-highcharts', 'LicenseRef-scancode-gatling-highcharts'], + ['gcc-compiler-exception-2.0', 'LicenseRef-scancode-gcc-compiler-exception-2.0'], + ['gcc-exception-2.0-note', 'GCC-exception-2.0-note'], + ['gcc-exception-3.0', 'LicenseRef-scancode-gcc-exception-3.0'], ['gcc-exception-3.1', 'GCC-exception-3.1'], + ['gcc-linking-exception-2.0', 'GCC-exception-2.0'], + ['gcel-2022', 'LicenseRef-scancode-gcel-2022'], + ['gco-v3.0', 'LicenseRef-scancode-gco-v3.0'], + ['gcr-docs', 'GCR-docs'], + ['gdcl', 'LicenseRef-scancode-gdcl'], + ['generic-cla', 'LicenseRef-scancode-generic-cla'], + ['generic-exception', 'LicenseRef-scancode-generic-exception'], + ['generic-export-compliance', 'LicenseRef-scancode-generic-export-compliance'], + ['generic-loop', 'LicenseRef-scancode-generic-loop'], + ['generic-tos', 'LicenseRef-scancode-generic-tos'], + ['generic-trademark', 'LicenseRef-scancode-generic-trademark'], + ['genivia-gsoap', 'LicenseRef-scancode-genivia-gsoap'], + ['genode-agpl-3.0-exception', 'LicenseRef-scancode-genode-agpl-3.0-exception'], + ['geoff-kuenning-1993', 'LicenseRef-scancode-geoff-kuenning-1993'], + ['geoserver-exception-2.0-plus', 'LicenseRef-scancode-geoserver-exception-2.0-plus'], ['gfdl-1.1', 'GFDL-1.1-only'], + ['gfdl-1.1-invariants-only', 'GFDL-1.1-invariants-only'], + ['gfdl-1.1-invariants-or-later', 'GFDL-1.1-invariants-or-later'], + ['gfdl-1.1-no-invariants-only', 'GFDL-1.1-no-invariants-only'], + ['gfdl-1.1-no-invariants-or-later', 'GFDL-1.1-no-invariants-or-later'], ['gfdl-1.1-plus', 'GFDL-1.1-or-later'], - ['gfdl-1.3-plus', 'GFDL-1.3-or-later'], ['gfdl-1.2', 'GFDL-1.2-only'], + ['gfdl-1.2-invariants-only', 'GFDL-1.2-invariants-only'], + ['gfdl-1.2-invariants-or-later', 'GFDL-1.2-invariants-or-later'], + ['gfdl-1.2-no-invariants-only', 'GFDL-1.2-no-invariants-only'], + ['gfdl-1.2-no-invariants-or-later', 'GFDL-1.2-no-invariants-or-later'], ['gfdl-1.2-plus', 'GFDL-1.2-or-later'], ['gfdl-1.3', 'GFDL-1.3-only'], + ['gfdl-1.3-invariants-only', 'GFDL-1.3-invariants-only'], + ['gfdl-1.3-invariants-or-later', 'GFDL-1.3-invariants-or-later'], + ['gfdl-1.3-no-invariants-only', 'GFDL-1.3-no-invariants-only'], + ['gfdl-1.3-no-invariants-or-later', 'GFDL-1.3-no-invariants-or-later'], + ['gfdl-1.3-plus', 'GFDL-1.3-or-later'], + ['ghostpdl-permissive', 'LicenseRef-scancode-ghostpdl-permissive'], + ['ghostscript-1988', 'LicenseRef-scancode-ghostscript-1988'], + ['github-codeql-terms-2020', 'LicenseRef-scancode-github-codeql-terms-2020'], + ['gitlab-ee', 'LicenseRef-scancode-gitlab-ee'], + ['gitpod-self-hosted-free-2020', 'LicenseRef-scancode-gitpod-self-hosted-free-2020'], + ['gl2ps', 'GL2PS'], + ['gladman-older-rijndael-code-use', 'LicenseRef-scancode-gladman-older-rijndael-code'], ['glide', 'Glide'], ['glulxe', 'Glulxe'], - ['gl2ps', 'GL2PS'], + ['glut', 'LicenseRef-scancode-glut'], + ['glwtpl', 'GLWTPL'], + ['gmsh-exception', 'Gmsh-exception'], + ['gnome-examples-exception', 'GNOME-examples-exception'], + ['gnu-emacs-gpl-1988', 'LicenseRef-scancode-gnu-emacs-gpl-1988'], ['gnu-javamail-exception', 'gnu-javamail-exception'], ['gnuplot', 'gnuplot'], + ['goahead', 'LicenseRef-scancode-goahead'], + ['good-boy', 'LicenseRef-scancode-good-boy'], + ['google-analytics-tos', 'LicenseRef-scancode-google-analytics-tos'], + ['google-analytics-tos-2015', 'LicenseRef-scancode-google-analytics-tos-2015'], + ['google-analytics-tos-2016', 'LicenseRef-scancode-google-analytics-tos-2016'], + ['google-analytics-tos-2019', 'LicenseRef-scancode-google-analytics-tos-2019'], + ['google-apis-tos-2021', 'LicenseRef-scancode-google-apis-tos-2021'], + ['google-cla', 'LicenseRef-scancode-google-cla'], + ['google-corporate-cla', 'LicenseRef-scancode-google-corporate-cla'], + ['google-maps-tos-2018-02-07', 'LicenseRef-scancode-google-maps-tos-2018-02-07'], + ['google-maps-tos-2018-05-01', 'LicenseRef-scancode-google-maps-tos-2018-05-01'], + ['google-maps-tos-2018-06-07', 'LicenseRef-scancode-google-maps-tos-2018-06-07'], + ['google-maps-tos-2018-07-09', 'LicenseRef-scancode-google-maps-tos-2018-07-09'], + ['google-maps-tos-2018-07-19', 'LicenseRef-scancode-google-maps-tos-2018-07-19'], + ['google-maps-tos-2018-10-01', 'LicenseRef-scancode-google-maps-tos-2018-10-01'], + ['google-maps-tos-2018-10-31', 'LicenseRef-scancode-google-maps-tos-2018-10-31'], + ['google-maps-tos-2019-05-02', 'LicenseRef-scancode-google-maps-tos-2019-05-02'], + ['google-maps-tos-2019-11-21', 'LicenseRef-scancode-google-maps-tos-2019-11-21'], + ['google-maps-tos-2020-04-02', 'LicenseRef-scancode-google-maps-tos-2020-04-02'], + ['google-maps-tos-2020-04-27', 'LicenseRef-scancode-google-maps-tos-2020-04-27'], + ['google-maps-tos-2020-05-06', 'LicenseRef-scancode-google-maps-tos-2020-05-06'], + ['google-ml-kit-tos-2022', 'LicenseRef-scancode-google-ml-kit-tos-2022'], + ['google-patent-license', 'LicenseRef-scancode-google-patent-license'], + ['google-patent-license-fuchsia', 'LicenseRef-scancode-google-patent-license-fuchsia'], + ['google-patent-license-fuschia', 'null'], + ['google-patent-license-golang', 'LicenseRef-scancode-google-patent-license-golang'], + ['google-patent-license-webm', 'LicenseRef-scancode-google-patent-license-webm'], + ['google-patent-license-webrtc', 'LicenseRef-scancode-google-patent-license-webrtc'], + ['google-playcore-sdk-tos-2020', 'LicenseRef-scancode-google-playcore-sdk-tos-2020'], + ['google-tos-2013', 'LicenseRef-scancode-google-tos-2013'], + ['google-tos-2014', 'LicenseRef-scancode-google-tos-2014'], + ['google-tos-2017', 'LicenseRef-scancode-google-tos-2017'], + ['google-tos-2019', 'LicenseRef-scancode-google-tos-2019'], + ['google-tos-2020', 'LicenseRef-scancode-google-tos-2020'], + ['gpl-1.0', 'GPL-1.0-only'], ['gpl-1.0-plus', 'GPL-1.0-or-later'], + ['gpl-2.0', 'GPL-2.0-only'], + ['gpl-2.0-adaptec', 'LicenseRef-scancode-gpl-2.0-adaptec'], ['gpl-2.0-autoconf', 'GPL-2.0-with-autoconf-exception'], - ['gpl-1.0', 'GPL-1.0-only'], + ['gpl-2.0-autoopts', 'null'], + ['gpl-2.0-bison', 'null'], + ['gpl-2.0-bison-2.2', 'null'], + ['gpl-2.0-broadcom-linking', 'null'], ['gpl-2.0-classpath', 'GPL-2.0-with-classpath-exception'], - ['gpl-2.0-gcc', 'GPL-2.0-with-GCC-exception'], + ['gpl-2.0-cygwin', 'null'], + ['gpl-2.0-djvu', 'LicenseRef-scancode-gpl-2.0-djvu'], ['gpl-2.0-font', 'GPL-2.0-with-font-exception'], + ['gpl-2.0-freertos', 'null'], + ['gpl-2.0-gcc', 'GPL-2.0-with-GCC-exception'], + ['gpl-2.0-gcc-compiler-exception', 'null'], + ['gpl-2.0-glibc', 'null'], + ['gpl-2.0-guile', 'null'], + ['gpl-2.0-ice', 'null'], + ['gpl-2.0-independent-module-linking', 'null'], + ['gpl-2.0-iolib', 'null'], + ['gpl-2.0-iso-cpp', 'null'], + ['gpl-2.0-javascript', 'null'], + ['gpl-2.0-kernel', 'null'], + ['gpl-2.0-koterov', 'LicenseRef-scancode-gpl-2.0-koterov'], + ['gpl-2.0-libgit2', 'null'], + ['gpl-2.0-library', 'null'], + ['gpl-2.0-libtool', 'null'], + ['gpl-2.0-lmbench', 'null'], + ['gpl-2.0-mysql-connector-odbc', 'null'], + ['gpl-2.0-mysql-floss', 'null'], + ['gpl-2.0-openjdk', 'null'], + ['gpl-2.0-openssl', 'null'], + ['gpl-2.0-oracle-mysql-foss', 'null'], + ['gpl-2.0-oracle-openjdk', 'null'], ['gpl-2.0-plus', 'GPL-2.0-or-later'], - ['gpl-2.0', 'GPL-2.0-only'], + ['gpl-2.0-plus-ada', 'null'], + ['gpl-2.0-plus-ekiga', 'null'], + ['gpl-2.0-plus-gcc', 'null'], + ['gpl-2.0-plus-geoserver', 'null'], + ['gpl-2.0-plus-linking', 'null'], + ['gpl-2.0-plus-nant', 'null'], + ['gpl-2.0-plus-openmotif', 'null'], + ['gpl-2.0-plus-openssl', 'null'], + ['gpl-2.0-plus-sane', 'null'], + ['gpl-2.0-plus-subcommander', 'null'], + ['gpl-2.0-plus-syntext', 'null'], + ['gpl-2.0-plus-upx', 'null'], + ['gpl-2.0-proguard', 'null'], + ['gpl-2.0-qt-qca', 'null'], + ['gpl-2.0-redhat', 'null'], + ['gpl-2.0-rrdtool-floss', 'null'], + ['gpl-2.0-uboot', 'null'], + ['gpl-3.0', 'GPL-3.0-only'], + ['gpl-3.0-aptana', 'null'], ['gpl-3.0-autoconf', 'GPL-3.0-with-autoconf-exception'], + ['gpl-3.0-bison', 'null'], + ['gpl-3.0-cygwin', 'null'], + ['gpl-3.0-font', 'null'], ['gpl-3.0-gcc', 'GPL-3.0-with-GCC-exception'], + ['gpl-3.0-interface-exception', 'GPL-3.0-interface-exception'], + ['gpl-3.0-linking-exception', 'GPL-3.0-linking-exception'], + ['gpl-3.0-linking-source-exception', 'GPL-3.0-linking-source-exception'], + ['gpl-3.0-openbd', 'null'], ['gpl-3.0-plus', 'GPL-3.0-or-later'], - ['gpl-3.0', 'GPL-3.0-only'], + ['gpl-3.0-plus-openssl', 'null'], + ['gpl-generic-additional-terms', 'LicenseRef-scancode-gpl-generic-additional-terms'], + ['gplcc-1.0', 'GPL-CC-1.0'], + ['gradle-enterprise-sla-2022-11-08', 'LicenseRef-scancode-gradle-enterprise-sla-2022-11-'], + ['gradle-tou-2022-01-13', 'LicenseRef-scancode-gradle-tou-2022-01-13'], + ['graphics-gems', 'Graphics-Gems'], + ['greg-roelofs', 'LicenseRef-scancode-greg-roelofs'], + ['gregory-pietsch', 'LicenseRef-scancode-gregory-pietsch'], + ['gsoap-1.3a', 'LicenseRef-scancode-gsoap-1.3a'], ['gsoap-1.3b', 'gSOAP-1.3b'], + ['gstreamer-exception-2.0', 'LicenseRef-scancode-gstreamer-exception-2.0'], + ['gstreamer-exception-2005', 'GStreamer-exception-2005'], + ['gstreamer-exception-2008', 'GStreamer-exception-2008'], + ['gtkbook', 'gtkbook'], + ['gtpl-v1', 'LicenseRef-scancode-gtpl-v1'], + ['gtpl-v2', 'LicenseRef-scancode-gtpl-v2'], + ['gtpl-v3', 'LicenseRef-scancode-gtpl-v3'], + ['guile-exception-2.0', 'LicenseRef-scancode-guile-exception-2.0'], + ['gust-font-1.0', 'LicenseRef-scancode-gust-font-1.0'], + ['gust-font-2006-09-30', 'LicenseRef-scancode-gust-font-2006-09-30'], + ['gutenberg-2020', 'LicenseRef-scancode-gutenberg-2020'], + ['h2-1.0', 'LicenseRef-scancode-h2-1.0'], + ['hacking-license', 'LicenseRef-scancode-hacking-license'], + ['hacos-1.2', 'LicenseRef-scancode-hacos-1.2'], + ['happy-bunny', 'LicenseRef-scancode-happy-bunny'], ['haskell-report', 'HaskellReport'], + ['hauppauge-firmware-eula', 'LicenseRef-scancode-hauppauge-firmware-eula'], + ['hauppauge-firmware-oem', 'LicenseRef-scancode-hauppauge-firmware-oem'], + ['hazelcast-community-1.0', 'LicenseRef-scancode-hazelcast-community-1.0'], + ['hdf4', 'LicenseRef-scancode-hdf4'], + ['hdf5', 'LicenseRef-scancode-hdf5'], + ['hdparm', 'hdparm'], + ['helios-eula', 'LicenseRef-scancode-helios-eula'], + ['helix', 'LicenseRef-scancode-helix'], ['henry-spencer-1999', 'Spencer-99'], - ['here-proprietary', 'LicenseRef-Proprietary-HERE'], + ['here-disclaimer', 'LicenseRef-scancode-here-disclaimer'], + ['here-proprietary', 'LicenseRef-scancode-here-proprietary'], + ['hessla', 'LicenseRef-scancode-hessla'], + ['hfoil-1.0', 'LicenseRef-scancode-hfoil-1.0'], + ['hidapi', 'LicenseRef-scancode-hidapi'], + ['hippocratic-1.0', 'LicenseRef-scancode-hippocratic-1.0'], + ['hippocratic-1.1', 'LicenseRef-scancode-hippocratic-1.1'], + ['hippocratic-1.2', 'LicenseRef-scancode-hippocratic-1.2'], + ['hippocratic-2.0', 'LicenseRef-scancode-hippocratic-2.0'], + ['hippocratic-2.1', 'Hippocratic-2.1'], + ['hippocratic-3.0', 'LicenseRef-scancode-Hippocratic-3.0'], ['historical', 'HPND'], - ['i2p-gpl-java-exception', 'i2p-gpl-java-exception'], + ['historical-ntp', 'LicenseRef-scancode-historical-ntp'], + ['historical-sell-variant', 'null'], + ['homebrewed', 'LicenseRef-scancode-homebrewed'], + ['hot-potato', 'LicenseRef-scancode-hot-potato'], + ['houdini-project', 'LicenseRef-scancode-houdini'], + ['hp', 'LicenseRef-scancode-hp'], + ['hp-1986', 'HP-1986'], + ['hp-enterprise-eula', 'LicenseRef-scancode-hp-enterprise-eula'], + ['hp-netperf', 'LicenseRef-scancode-hp-netperf'], + ['hp-proliant-essentials', 'LicenseRef-scancode-hp-proliant-essentials'], + ['hp-snmp-pp', 'LicenseRef-scancode-hp-snmp-pp'], + ['hp-software-eula', 'LicenseRef-scancode-hp-software-eula'], + ['hp-ux-java', 'LicenseRef-scancode-hp-ux-java'], + ['hp-ux-jre', 'LicenseRef-scancode-hp-ux-jre'], + ['hpnd-doc', 'HPND-doc'], + ['hpnd-doc-sell', 'HPND-doc-sell'], + ['hpnd-export-us', 'HPND-export-US'], + ['hpnd-fenneberg-livingston', 'HPND-Fenneberg-Livingston'], + ['hpnd-inria-imag', 'HPND-INRIA-IMAG'], + ['hpnd-mit-disclaimer', 'HPND-MIT-disclaimer'], + ['hpnd-pbmplus', 'HPND-Pbmplus'], + ['hpnd-sell-mit-disclaimer-xserver', 'HPND-sell-MIT-disclaimer-xserver'], + ['hpnd-sell-regexpr', 'HPND-sell-regexpr'], + ['hpnd-sell-variant-mit-disclaimer', 'HPND-sell-variant-MIT-disclaimer'], + ['hpnd-uc', 'HPND-UC'], ['hs-regexp', 'Spencer-94'], + ['hs-regexp-orig', 'null'], + ['html5', 'LicenseRef-scancode-html5'], + ['httpget', 'LicenseRef-scancode-httpget'], + ['huggingface-tos-20220915', 'LicenseRef-scancode-huggingface-tos-20220915'], + ['hugo', 'LicenseRef-scancode-hugo'], + ['hxd', 'LicenseRef-scancode-hxd'], + ['i2p-gpl-java-exception', 'i2p-gpl-java-exception'], + ['ian-kaplan', 'LicenseRef-scancode-ian-kaplan'], + ['ian-piumarta', 'LicenseRef-scancode-ian-piumarta'], + ['ibm-as-is', 'LicenseRef-scancode-ibm-as-is'], + ['ibm-data-server-2011', 'LicenseRef-scancode-ibm-data-server-2011'], + ['ibm-developerworks-community-download', 'LicenseRef-scancode-ibm-developerworks-community'], + ['ibm-dhcp', 'LicenseRef-scancode-ibm-dhcp'], + ['ibm-employee-written', 'LicenseRef-scancode-ibm-employee-written'], + ['ibm-glextrusion', 'LicenseRef-scancode-ibm-glextrusion'], + ['ibm-icu', 'LicenseRef-scancode-ibm-icu'], + ['ibm-java-portlet-spec-2.0', 'LicenseRef-scancode-ibm-java-portlet-spec-2.0'], + ['ibm-jre', 'LicenseRef-scancode-ibm-jre'], + ['ibm-nwsc', 'LicenseRef-scancode-ibm-nwsc'], ['ibm-pibs', 'IBM-pibs'], + ['ibm-sample', 'LicenseRef-scancode-ibm-sample'], ['ibmpl-1.0', 'IPL-1.0'], + ['ibpp', 'LicenseRef-scancode-ibpp'], + ['ic-1.0', 'LicenseRef-scancode-ic-1.0'], + ['ic-shared-1.0', 'LicenseRef-scancode-ic-shared-1.0'], + ['icann-public', 'LicenseRef-scancode-icann-public'], + ['ice-exception-2.0', 'LicenseRef-scancode-ice-exception-2.0'], + ['icot-free', 'LicenseRef-scancode-icot-free'], + ['idt-notice', 'LicenseRef-scancode-idt-notice'], + ['iec-code-components-eula', 'IEC-Code-Components-EULA'], + ['ietf', 'LicenseRef-scancode-ietf'], + ['ietf-trust', 'LicenseRef-scancode-ietf-trust'], ['ijg', 'IJG'], + ['ijg-short', 'IJG-short'], + ['ilmid', 'LicenseRef-scancode-ilmid'], ['imagemagick', 'ImageMagick'], - ['indiana-extreme-1.2', 'xpp'], + ['imagen', 'LicenseRef-scancode-imagen'], ['imlib2', 'Imlib2'], + ['independent-module-linking-exception', 'LicenseRef-scancode-indie-module-linking-exception'], + ['indiana-extreme', 'LicenseRef-scancode-indiana-extreme'], + ['indiana-extreme-1.2', 'xpp'], + ['infineon-free', 'LicenseRef-scancode-infineon-free'], ['info-zip', 'Info-ZIP'], + ['info-zip-1997-10', 'LicenseRef-scancode-info-zip-1997-10'], + ['info-zip-2001-01', 'LicenseRef-scancode-info-zip-2001-01'], + ['info-zip-2002-02', 'LicenseRef-scancode-info-zip-2002-02'], + ['info-zip-2003-05', 'LicenseRef-scancode-info-zip-2003-05'], + ['info-zip-2004-05', 'LicenseRef-scancode-info-zip-2004-05'], + ['info-zip-2005-02', 'LicenseRef-scancode-info-zip-2005-02'], + ['info-zip-2007-03', 'LicenseRef-scancode-info-zip-2007-03'], + ['info-zip-2009-01', 'LicenseRef-scancode-info-zip-2009-01'], + ['infonode-1.1', 'LicenseRef-scancode-infonode-1.1'], + ['initial-developer-public', 'LicenseRef-scancode-initial-developer-public'], + ['inner-net-2.0', 'Inner-Net-2.0'], + ['inno-setup', 'LicenseRef-scancode-inno-setup'], + ['inria-linking-exception', 'QPL-1.0-INRIA-2004-exception'], + ['installsite', 'LicenseRef-scancode-installsite'], + ['intel', 'LicenseRef-scancode-intel'], ['intel-acpi', 'Intel-ACPI'], + ['intel-bcl', 'LicenseRef-scancode-intel-bcl'], + ['intel-bsd', 'BSD-3-Clause-acpica'], + ['intel-bsd-2-clause', 'LicenseRef-scancode-intel-bsd-2-clause'], ['intel-bsd-export-control', 'Intel'], + ['intel-code-samples', 'LicenseRef-scancode-intel-code-samples'], + ['intel-confidential', 'LicenseRef-scancode-intel-confidential'], + ['intel-firmware', 'LicenseRef-scancode-intel-firmware'], + ['intel-master-eula-sw-dev-2016', 'LicenseRef-scancode-intel-master-eula-sw-dev-2016'], + ['intel-material', 'LicenseRef-scancode-intel-material'], + ['intel-mcu-2018', 'LicenseRef-scancode-intel-mcu-2018'], + ['intel-microcode', 'LicenseRef-scancode-intel-microcode'], + ['intel-osl-1989', 'LicenseRef-scancode-intel-osl-1989'], + ['intel-osl-1993', 'LicenseRef-scancode-intel-osl-1993'], + ['intel-royalty-free', 'LicenseRef-scancode-intel-royalty-free'], + ['intel-sample-source-code-2015', 'LicenseRef-scancode-intel-sample-source-code-2015'], + ['intel-scl', 'LicenseRef-scancode-intel-scl'], ['interbase-1.0', 'Interbase-1.0'], + ['iolib-exception-2.0', 'GNU-compiler-exception'], + ['iozone', 'LicenseRef-scancode-iozone'], ['ipa-font', 'IPA'], + ['ipca', 'LicenseRef-scancode-ipca'], + ['iptc-2006', 'LicenseRef-scancode-iptc-2006'], + ['irfanview-eula', 'LicenseRef-scancode-irfanview-eula'], ['isc', 'ISC'], + ['iso-14496-10', 'LicenseRef-scancode-iso-14496-10'], + ['iso-8879', 'LicenseRef-scancode-iso-8879'], + ['iso-recorder', 'LicenseRef-scancode-iso-recorder'], + ['isotope-cla', 'LicenseRef-scancode-isotope-cla'], + ['issl-2018', 'LicenseRef-scancode-issl-2018'], + ['issl-2022', 'LicenseRef-scancode-issl-2022'], + ['itc-eula', 'LicenseRef-scancode-itc-eula'], + ['itu', 'LicenseRef-scancode-itu'], + ['itu-t', 'LicenseRef-scancode-itu-t'], + ['itu-t-gpl', 'LicenseRef-scancode-itu-t-gpl'], + ['itunes', 'LicenseRef-scancode-itunes'], + ['ja-sig', 'LicenseRef-scancode-ja-sig'], + ['jahia-1.3.1', 'LicenseRef-scancode-jahia-1.3.1'], + ['jam', 'Jam'], + ['jam-stapl', 'LicenseRef-scancode-jam-stapl'], + ['jamon', 'LicenseRef-scancode-jamon'], + ['jason-mayes', 'LicenseRef-scancode-jason-mayes'], + ['jasper-1.0', 'LicenseRef-scancode-jasper-1.0'], ['jasper-2.0', 'JasPer-2.0'], + ['java-app-stub', 'LicenseRef-scancode-java-app-stub'], + ['java-research-1.5', 'LicenseRef-scancode-java-research-1.5'], + ['java-research-1.6', 'LicenseRef-scancode-java-research-1.6'], + ['javascript-exception-2.0', 'LicenseRef-scancode-javascript-exception-2.0'], + ['jboss-eula', 'LicenseRef-scancode-jboss-eula'], + ['jdbm-1.00', 'LicenseRef-scancode-jdbm-1.00'], + ['jdom', 'LicenseRef-scancode-jdom'], + ['jelurida-public-1.1', 'LicenseRef-scancode-jelurida-public-1.1'], + ['jetbrains-purchase-terms', 'LicenseRef-scancode-jetbrains-purchase-terms'], + ['jetbrains-toolbox-open-source-3', 'LicenseRef-scancode-jetbrains-toolbox-oss-3'], + ['jetty', 'LicenseRef-scancode-jetty'], + ['jetty-ccla-1.1', 'LicenseRef-scancode-jetty-ccla-1.1'], + ['jgraph', 'LicenseRef-scancode-jgraph'], + ['jgraph-general', 'LicenseRef-scancode-jgraph-general'], + ['jide-sla', 'LicenseRef-scancode-jide-sla'], + ['jj2000', 'LicenseRef-scancode-jj2000'], + ['jmagnetic', 'LicenseRef-scancode-jmagnetic'], + ['josl-1.0', 'LicenseRef-scancode-josl-1.0'], + ['jpegxr', 'LicenseRef-scancode-jpegxr'], + ['jpl-image', 'JPL-image'], + ['jpnic-idnkit', 'JPNIC'], + ['jpnic-mdnkit', 'LicenseRef-scancode-jpnic-mdnkit'], + ['jprs-oscl-1.1', 'LicenseRef-scancode-jprs-oscl-1.1'], + ['jpython-1.1', 'LicenseRef-scancode-jpython-1.1'], + ['jquery-pd', 'LicenseRef-scancode-jquery-pd'], + ['jrunner', 'LicenseRef-scancode-jrunner'], + ['jscheme', 'LicenseRef-scancode-jscheme'], + ['jsel-2.0', 'LicenseRef-scancode-jsel-2.0'], + ['jsfromhell', 'LicenseRef-scancode-jsfromhell'], ['json', 'JSON'], + ['json-js-pd', 'LicenseRef-scancode-json-js-pd'], + ['json-pd', 'LicenseRef-scancode-json-pd'], + ['jsr-107-jcache-spec', 'LicenseRef-scancode-jsr-107-jcache-spec'], + ['jsr-107-jcache-spec-2013', 'LicenseRef-scancode-jsr-107-jcache-spec-2013'], + ['jython', 'LicenseRef-scancode-jython'], + ['kalle-kaukonen', 'LicenseRef-scancode-kalle-kaukonen'], + ['karl-peterson', 'LicenseRef-scancode-karl-peterson'], + ['kastrup', 'Kastrup'], + ['katharos-0.1.0', 'LicenseRef-scancode-katharos-0.1.0'], + ['katharos-0.2.0', 'LicenseRef-scancode-katharos-0.2.0'], + ['kazlib', 'Kazlib'], + ['kde-accepted-gpl', 'LicenseRef-scancode-kde-accepted-gpl'], + ['kde-accepted-lgpl', 'LicenseRef-scancode-kde-accepted-lgpl'], + ['keith-rule', 'LicenseRef-scancode-keith-rule'], + ['kerberos', 'LicenseRef-scancode-kerberos'], + ['kevan-stannard', 'LicenseRef-scancode-kevan-stannard'], + ['kevlin-henney', 'HPND-Kevlin-Henney'], + ['keypirinha', 'LicenseRef-scancode-keypirinha'], + ['kfgqpc-uthmanic-script-hafs', 'LicenseRef-scancode-kfgqpc-uthmanic-script-hafs'], + ['kfqf-accepted-gpl', 'LicenseRef-scancode-kfqf-accepted-gpl'], + ['khronos', 'LicenseRef-scancode-khronos'], + ['kicad-libraries-exception', 'KiCad-libraries-exception'], + ['knuth-ctan', 'Knuth-CTAN'], + ['ko-man-page', 'LicenseRef-scancode-ko-man-page'], + ['kreative-relay-fonts-free-use-1.2f', 'LicenseRef-scancode-kreative-relay-fonts-free-1.2f'], + ['kumar-robotics', 'LicenseRef-scancode-kumar-robotics'], + ['lal-1.2', 'LAL-1.2'], + ['lal-1.3', 'LAL-1.3'], + ['lance-norskog-license', 'LicenseRef-scancode-lance-norskog-license'], + ['larabie', 'LicenseRef-scancode-larabie'], ['latex2e', 'Latex2e'], + ['latex2e-translated-notice', 'Latex2e-translated-notice'], + ['lattice-osl-2017', 'LicenseRef-scancode-lattice-osl-2017'], + ['lavantech', 'LicenseRef-scancode-lavantech'], ['lbnl-bsd', 'BSD-3-Clause-LBNL'], - ['lgpl-2.0-plus', 'LGPL-2.0-or-later'], + ['lcs-telegraphics', 'LicenseRef-scancode-lcs-telegraphics'], + ['ldap-sdk-free-use', 'LicenseRef-scancode-ldap-sdk-free-use'], + ['ldpc-1994', 'LicenseRef-scancode-ldpc-1994'], + ['ldpc-1997', 'LicenseRef-scancode-ldpc-1997'], + ['ldpc-1999', 'LicenseRef-scancode-ldpc-1999'], + ['ldpgpl-1', 'LicenseRef-scancode-ldpgpl-1'], + ['ldpgpl-1a', 'LicenseRef-scancode-ldpgpl-1a'], + ['ldpl-2.0', 'LicenseRef-scancode-ldpl-2.0'], + ['ldpm-1998', 'LicenseRef-scancode-ldpm-1998'], + ['leap-motion-sdk-2019', 'LicenseRef-scancode-leap-motion-sdk-2019'], ['leptonica', 'Leptonica'], ['lgpl-2.0', 'LGPL-2.0-only'], - ['lgpl-2.1-plus', 'LGPL-2.1-or-later'], + ['lgpl-2.0-fltk', 'null'], + ['lgpl-2.0-plus', 'LGPL-2.0-or-later'], + ['lgpl-2.0-plus-gcc', 'null'], ['lgpl-2.1', 'LGPL-2.1-only'], + ['lgpl-2.1-digia-qt', 'null'], + ['lgpl-2.1-nokia-qt', 'null'], + ['lgpl-2.1-nokia-qt-1.0', 'null'], + ['lgpl-2.1-nokia-qt-1.1', 'null'], + ['lgpl-2.1-plus', 'LGPL-2.1-or-later'], + ['lgpl-2.1-plus-linking', 'null'], + ['lgpl-2.1-plus-unlimited-linking', 'null'], + ['lgpl-2.1-qt-company', 'null'], + ['lgpl-2.1-qt-company-2017', 'null'], + ['lgpl-2.1-rxtx', 'null'], + ['lgpl-2.1-spell-checker', 'null'], + ['lgpl-3-plus-linking', 'null'], ['lgpl-3.0', 'LGPL-3.0-only'], + ['lgpl-3.0-cygwin', 'null'], + ['lgpl-3.0-linking-exception', 'LGPL-3.0-linking-exception'], ['lgpl-3.0-plus', 'LGPL-3.0-or-later'], + ['lgpl-3.0-plus-openssl', 'null'], + ['lgpl-3.0-zeromq', 'null'], ['lgpllr', 'LGPLLR'], - ['libtool-exception-2.0', 'Libtool-exception'], + ['lha', 'LicenseRef-scancode-lha'], + ['libcap', 'null'], + ['liberation-font-exception', 'LicenseRef-scancode-liberation-font-exception'], + ['libgd-2018', 'GD'], + ['libgeotiff', 'LicenseRef-scancode-libgeotiff'], + ['libmib', 'LicenseRef-scancode-libmib'], + ['libmng-2007', 'LicenseRef-scancode-libmng-2007'], + ['libpbm', 'xlock'], ['libpng', 'Libpng'], - ['linux-syscall-exception-gpl', 'Linux-syscall-note'], + ['libpng-v2', 'libpng-2.0'], + ['libpri-openh323-exception', 'libpri-OpenH323-exception'], + ['librato-exception', 'LicenseRef-scancode-librato-exception'], + ['libselinux-pd', 'LicenseRef-scancode-libselinux-pd'], + ['libsrv-1.0.2', 'LicenseRef-scancode-libsrv-1.0.2'], + ['libtool-exception', 'null'], + ['libtool-exception-2.0', 'Libtool-exception'], + ['libtool-exception-lgpl', 'LicenseRef-scancode-libtool-exception-lgpl'], + ['libutil-david-nugent', 'libutil-David-Nugent'], + ['libwebsockets-exception', 'LicenseRef-scancode-libwebsockets-exception'], + ['libzip', 'null'], + ['license-file-reference', 'null'], + ['liferay-dxp-eula-2.0.0-2023-06', 'LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06'], + ['liferay-ee', 'LicenseRef-scancode-liferay-ee'], + ['liferay-marketplace-tos', 'LicenseRef-scancode-liferay-marketplace-tos'], + ['lil-1', 'LicenseRef-scancode-lil-1'], + ['liliq-p-1.1', 'LiLiQ-P-1.1'], + ['liliq-r-1.1', 'LiLiQ-R-1.1'], + ['liliq-rplus-1.1', 'LiLiQ-Rplus-1.1'], + ['lilo', 'LicenseRef-scancode-lilo'], + ['linking-exception-2.0-plus', 'LicenseRef-scancode-linking-exception-2.0-plus'], + ['linking-exception-2.1-plus', 'LicenseRef-scancode-linking-exception-2.1-plus'], + ['linking-exception-agpl-3.0', 'LicenseRef-scancode-linking-exception-agpl-3.0'], + ['linking-exception-lgpl-2.0-plus', 'LicenseRef-scancode-linking-exception-lgpl-2.0plus'], + ['linking-exception-lgpl-3.0', 'null'], + ['linotype-eula', 'LicenseRef-scancode-linotype-eula'], + ['linum', 'null'], + ['linux-device-drivers', 'LicenseRef-scancode-linux-device-drivers'], + ['linux-man-pages-1-para', 'Linux-man-pages-1-para'], + ['linux-man-pages-2-para', 'Linux-man-pages-copyleft-2-para'], + ['linux-man-pages-copyleft-var', 'Linux-man-pages-copyleft-var'], ['linux-openib', 'Linux-OpenIB'], + ['linux-syscall-exception-gpl', 'Linux-syscall-note'], + ['linuxbios', 'LicenseRef-scancode-linuxbios'], + ['linuxhowtos', 'LicenseRef-scancode-linuxhowtos'], + ['llama-2-license-2023', 'LicenseRef-scancode-llama-2-license-2023'], + ['llama-license-2023', 'LicenseRef-scancode-llama-license-2023'], + ['llgpl', 'LLGPL'], + ['llnl', 'LicenseRef-scancode-llnl'], ['llvm-exception', 'LLVM-exception'], - ['lppl-1.1', 'LPPL-1.1'], + ['lmbench-exception-2.0', 'LicenseRef-scancode-lmbench-exception-2.0'], + ['logica-1.0', 'LicenseRef-scancode-logica-1.0'], + ['lontium-linux-firmware', 'LicenseRef-scancode-lontium-linux-firmware'], + ['loop', 'LOOP'], + ['losla', 'LicenseRef-scancode-losla'], ['lppl-1.0', 'LPPL-1.0'], + ['lppl-1.1', 'LPPL-1.1'], ['lppl-1.2', 'LPPL-1.2'], - ['lppl-1.3c', 'LPPL-1.3c'], ['lppl-1.3a', 'LPPL-1.3a'], + ['lppl-1.3c', 'LPPL-1.3c'], + ['lsi-proprietary-eula', 'LicenseRef-scancode-lsi-proprietary-eula'], ['lucent-pl-1.0', 'LPL-1.0'], ['lucent-pl-1.02', 'LPL-1.02'], + ['lucre', 'LicenseRef-scancode-lucre'], + ['lumisoft-mail-server', 'LicenseRef-scancode-lumisoft-mail-server'], + ['luxi', 'LicenseRef-scancode-luxi'], + ['lyubinskiy-dropdown', 'LicenseRef-scancode-lyubinskiy-dropdown'], + ['lyubinskiy-popup-window', 'LicenseRef-scancode-lyubinskiy-popup-window'], ['lzma-cpl-exception', 'LZMA-exception'], + ['lzma-sdk-2006', 'LicenseRef-scancode-lzma-sdk-2006'], + ['lzma-sdk-2006-exception', 'LicenseRef-scancode-lzma-sdk-2006-exception'], + ['lzma-sdk-2008', 'LicenseRef-scancode-lzma-sdk-2008'], + ['lzma-sdk-9.11-to-9.20', 'LZMA-SDK-9.11-to-9.20'], + ['lzma-sdk-9.22', 'LZMA-SDK-9.22'], + ['lzma-sdk-original', 'LicenseRef-scancode-lzma-sdk-original'], + ['lzma-sdk-pd', 'LicenseRef-scancode-lzma-sdk-pd'], + ['m-plus', 'mplus'], + ['madwifi-dual', 'null'], + ['magaz', 'magaz'], + ['magpie-exception-1.0', 'LicenseRef-scancode-magpie-exception-1.0'], + ['mailprio', 'mailprio'], + ['make-human-exception', 'LicenseRef-scancode-make-human-exception'], ['makeindex', 'MakeIndex'], + ['mame', 'LicenseRef-scancode-mame'], + ['manfred-klein-fonts-tos', 'LicenseRef-scancode-manfred-klein-fonts-tos'], + ['mapbox-tos-2021', 'LicenseRef-scancode-mapbox-tos-2021'], + ['markus-kuhn-license', 'HPND-Markus-Kuhn'], + ['markus-mummert-permissive', 'LicenseRef-scancode-markus-mummert-permissive'], + ['martin-birgmeier', 'Martin-Birgmeier'], + ['marvell-firmware', 'LicenseRef-scancode-marvell-firmware'], + ['marvell-firmware-2019', 'LicenseRef-scancode-marvell-firmware-2019'], + ['matt-gallagher-attribution', 'LicenseRef-scancode-matt-gallagher-attribution'], + ['matthew-kwan', 'LicenseRef-scancode-matthew-kwan'], + ['matthew-welch-font-license', 'LicenseRef-scancode-matthew-welch-font-license'], + ['mattkruse', 'LicenseRef-scancode-mattkruse'], + ['maxmind-geolite2-eula-2019', 'LicenseRef-scancode-maxmind-geolite2-eula-2019'], + ['maxmind-odl', 'LicenseRef-scancode-maxmind-odl'], + ['mcafee-tou', 'LicenseRef-scancode-mcafee-tou'], + ['mcphee-slideshow', 'McPhee-slideshow'], + ['mcrae-pl-4-r53', 'LicenseRef-scancode-mcrae-pl-4-r53'], + ['mediainfo-lib', 'LicenseRef-scancode-mediainfo-lib'], + ['mediatek-firmware', 'LicenseRef-scancode-mediatek-firmware'], + ['mediatek-no-warranty', 'LicenseRef-scancode-mediatek-no-warranty'], + ['mediatek-proprietary-2008', 'LicenseRef-scancode-mediatek-proprietary-2008'], + ['melange', 'LicenseRef-scancode-melange'], + ['mentalis', 'null'], + ['merit-network-derivative', 'LicenseRef-scancode-merit-network-derivative'], + ['metageek-inssider-eula', 'LicenseRef-scancode-metageek-inssider-eula'], + ['metamail', 'metamail'], + ['metrolink-1.0', 'LicenseRef-scancode-metrolink-1.0'], + ['mgopen-font-license', 'LicenseRef-scancode-mgopen-font-license'], + ['michael-barr', 'LicenseRef-scancode-michael-barr'], + ['michigan-disclaimer', 'LicenseRef-scancode-michigan-disclaimer'], + ['microchip-linux-firmware', 'LicenseRef-scancode-microchip-linux-firmware'], + ['microchip-products-2018', 'LicenseRef-scancode-microchip-products-2018'], + ['microsoft-enterprise-library-eula', 'LicenseRef-scancode-ms-enterprise-library-eula'], + ['microsoft-windows-rally-devkit', 'LicenseRef-scancode-microsoft-windows-rally-devkit'], ['mif-exception', 'mif-exception'], - ['mit-ack', 'MIT-feh'], - ['mit-0', 'MIT-0'], + ['mike95', 'LicenseRef-scancode-mike95'], + ['minecraft-mod', 'LicenseRef-scancode-minecraft-mod'], + ['mini-xml', 'null'], + ['mini-xml-exception-lgpl-2.0', 'LicenseRef-scancode-mini-xml-exception-lgpl-2.0'], + ['minpack', 'Minpack'], ['mir-os', 'MirOS'], + ['mit', 'MIT'], + ['mit-0', 'MIT-0'], + ['mit-1995', 'LicenseRef-scancode-mit-1995'], + ['mit-ack', 'MIT-feh'], + ['mit-addition', 'MIT-Wu'], ['mit-export-control', 'Xerox'], + ['mit-kyle-restrictions', 'LicenseRef-scancode-mit-kyle-restrictions'], + ['mit-license-1998', 'LicenseRef-scancode-mit-license-1998'], + ['mit-modern', 'MIT-Modern-Variant'], + ['mit-nagy', 'LicenseRef-scancode-mit-nagy'], + ['mit-no-advert-export-control', 'LicenseRef-scancode-mit-no-advert-export-control'], ['mit-no-false-attribs', 'MITNFA'], - ['mit', 'MIT'], + ['mit-no-trademarks', 'LicenseRef-scancode-mit-no-trademarks'], + ['mit-old-style', 'LicenseRef-scancode-mit-old-style'], + ['mit-old-style-no-advert', 'NTP'], + ['mit-old-style-sparse', 'LicenseRef-scancode-mit-old-style-sparse'], + ['mit-readme', 'LicenseRef-scancode-mit-readme'], + ['mit-specification-disclaimer', 'LicenseRef-scancode-mit-specification-disclaimer'], + ['mit-synopsys', 'LicenseRef-scancode-mit-synopsys'], + ['mit-taylor-variant', 'LicenseRef-scancode-mit-taylor-variant'], + ['mit-testregex', 'MIT-testregex'], + ['mit-veillard-variant', 'ISC-Veillard'], + ['mit-with-modification-obligations', 'HPND-export-US-modify'], + ['mit-xfig', 'Xfig'], + ['mmixware', 'MMIXware'], + ['mod-dav-1.0', 'LicenseRef-scancode-mod-dav-1.0'], + ['monetdb-1.1', 'LicenseRef-scancode-monetdb-1.1'], + ['mongodb-sspl-1.0', 'SSPL-1.0'], + ['monkeysaudio', 'LicenseRef-scancode-monkeysaudio'], + ['morbig-ieee-std-usage', 'LicenseRef-scancode-morbig-ieee-std-usage'], + ['motorola', 'LicenseRef-scancode-motorola'], ['motosoto-0.9.1', 'Motosoto'], + ['moxa-linux-firmware', 'LicenseRef-scancode-moxa-linux-firmware'], + ['mozilla-gc', 'Boehm-GC'], + ['mozilla-ospl-1.0', 'LicenseRef-scancode-mozilla-ospl-1.0'], + ['mpeg-7', 'LicenseRef-scancode-mpeg-7'], + ['mpeg-iso', 'LicenseRef-scancode-mpeg-iso'], + ['mpeg-ssg', 'MPEG-SSG'], + ['mpi-permissive', 'mpi-permissive'], ['mpich', 'mpich2'], ['mpl-1.0', 'MPL-1.0'], - ['mpl-2.0-no-copyleft-exception', 'MPL-2.0-no-copyleft-exception'], ['mpl-1.1', 'MPL-1.1'], ['mpl-2.0', 'MPL-2.0'], + ['mpl-2.0-no-copyleft-exception', 'MPL-2.0-no-copyleft-exception'], + ['ms-api-code-pack-net', 'LicenseRef-scancode-ms-api-code-pack-net'], + ['ms-asp-net-ajax-supplemental-terms', 'LicenseRef-scancode-ms-asp-net-ajax-supp-terms'], + ['ms-asp-net-mvc3', 'LicenseRef-scancode-ms-asp-net-mvc3'], + ['ms-asp-net-mvc4', 'LicenseRef-scancode-ms-asp-net-mvc4'], + ['ms-asp-net-mvc4-extensions', 'LicenseRef-scancode-ms-asp-net-mvc4-extensions'], + ['ms-asp-net-software', 'LicenseRef-scancode-ms-asp-net-software'], + ['ms-asp-net-tools-pre-release', 'LicenseRef-scancode-ms-asp-net-tools-pre-release'], + ['ms-asp-net-web-optimization-framework', 'LicenseRef-scancode-ms-asp-net-web-optimization'], + ['ms-asp-net-web-pages-2', 'LicenseRef-scancode-ms-asp-net-web-pages-2'], + ['ms-asp-net-web-pages-templates', 'LicenseRef-scancode-ms-asp-net-web-pages-templates'], + ['ms-azure-data-studio', 'LicenseRef-scancode-ms-azure-data-studio'], + ['ms-azure-spatialanchors-2.9.0', 'LicenseRef-scancode-ms-azure-spatialanchors-2.9.0'], + ['ms-capicom', 'LicenseRef-scancode-ms-capicom'], + ['ms-cl', 'LicenseRef-scancode-ms-cl'], + ['ms-cla', 'LicenseRef-scancode-ms-cla'], + ['ms-control-spy-2.0', 'LicenseRef-scancode-ms-control-spy-2.0'], + ['ms-data-tier-af-2022', 'LicenseRef-scancode-ms-data-tier-af-2022'], + ['ms-developer-services-agreement', 'LicenseRef-scancode-ms-dev-services-agreement'], + ['ms-developer-services-agreement-2018-06', 'LicenseRef-scancode-ms-dev-services-2018-06'], + ['ms-device-emulator-3.0', 'LicenseRef-scancode-ms-device-emulator-3.0'], + ['ms-direct3d-d3d120n7-1.1.0', 'LicenseRef-scancode-ms-direct3d-d3d120n7-1.1.0'], + ['ms-directx-sdk-eula', 'LicenseRef-scancode-ms-directx-sdk-eula'], + ['ms-directx-sdk-eula-2020', 'LicenseRef-scancode-ms-directx-sdk-eula-2020'], + ['ms-dxsdk-d3dx-9.29.952.3', 'LicenseRef-scancode-ms-dxsdk-d3dx-9.29.952.3'], + ['ms-edge-devtools-2022', 'LicenseRef-scancode-ms-edge-devtools-2022'], + ['ms-edge-webview2', 'LicenseRef-scancode-ms-edge-webview2'], + ['ms-edge-webview2-fixed', 'LicenseRef-scancode-ms-edge-webview2-fixed'], + ['ms-entity-framework-4.1', 'LicenseRef-scancode-ms-entity-framework-4.1'], + ['ms-entity-framework-5', 'LicenseRef-scancode-ms-entity-framework-5'], + ['ms-eula-win-script-host', 'LicenseRef-scancode-ms-eula-win-script-host'], + ['ms-exchange-server-2010-sp2-sdk', 'LicenseRef-scancode-ms-exchange-srv-2010-sp2-sdk'], + ['ms-iis-container-images-eula-2020', 'LicenseRef-scancode-ms-iis-container-eula-2020'], + ['ms-ilmerge', 'LicenseRef-scancode-ms-ilmerge'], + ['ms-invisible-eula-1.0', 'LicenseRef-scancode-ms-invisible-eula-1.0'], + ['ms-jdbc-driver-40-sql-server', 'LicenseRef-scancode-ms-jdbc-driver-40-sql-server'], + ['ms-jdbc-driver-41-sql-server', 'LicenseRef-scancode-ms-jdbc-driver-41-sql-server'], + ['ms-jdbc-driver-60-sql-server', 'LicenseRef-scancode-ms-jdbc-driver-60-sql-server'], + ['ms-kinext-win-sdk', 'LicenseRef-scancode-ms-kinext-win-sdk'], + ['ms-limited-community', 'LicenseRef-scancode-ms-limited-community'], + ['ms-limited-public', 'null'], + ['ms-lpl', 'MS-LPL'], + ['ms-msn-webgrease', 'LicenseRef-scancode-ms-msn-webgrease'], + ['ms-net-framework-4-supplemental-terms', 'LicenseRef-scancode-ms-net-framework-4-supp-terms'], + ['ms-net-framework-deployment', 'LicenseRef-scancode-ms-net-framework-deployment'], + ['ms-net-library', 'LicenseRef-scancode-ms-net-library'], + ['ms-net-library-2016-05', 'LicenseRef-scancode-ms-net-library-2016-05'], + ['ms-net-library-2018-11', 'LicenseRef-scancode-ms-net-library-2018-11'], + ['ms-net-library-2019-06', 'LicenseRef-scancode-ms-net-library-2019-06'], + ['ms-net-library-2020-09', 'LicenseRef-scancode-ms-net-library-2020-09'], + ['ms-nt-resource-kit', 'LicenseRef-scancode-ms-nt-resource-kit'], + ['ms-nuget', 'LicenseRef-scancode-ms-nuget'], + ['ms-nuget-package-manager', 'LicenseRef-scancode-ms-nuget-package-manager'], + ['ms-office-extensible-file', 'LicenseRef-scancode-ms-office-extensible-file'], + ['ms-office-system-programs-eula', 'LicenseRef-scancode-ms-office-system-programs-eula'], + ['ms-opus-patent-2012', 'LicenseRef-scancode-ms-opus-patent-2012'], + ['ms-patent-promise', 'LicenseRef-scancode-ms-patent-promise'], + ['ms-patent-promise-mono', 'LicenseRef-scancode-ms-patent-promise-mono'], + ['ms-permissive-1.1', 'null'], ['ms-pl', 'MS-PL'], + ['ms-platform-sdk', 'LicenseRef-scancode-ms-platform-sdk'], + ['ms-pre-release-sla-2023', 'LicenseRef-scancode-ms-pre-release-sla-2023'], + ['ms-programsynthesis-7.22.0', 'LicenseRef-scancode-ms-programsynthesis-7.22.0'], + ['ms-python-vscode-pylance-2021', 'LicenseRef-scancode-ms-python-vscode-pylance-2021'], + ['ms-reactive-extensions-eula', 'LicenseRef-scancode-ms-reactive-extensions-eula'], + ['ms-refl', 'null'], + ['ms-remote-ndis-usb-kit', 'LicenseRef-scancode-ms-remote-ndis-usb-kit'], + ['ms-research-shared-source', 'LicenseRef-scancode-ms-research-shared-source'], ['ms-rl', 'MS-RL'], + ['ms-rsl', 'LicenseRef-scancode-ms-rsl'], + ['ms-silverlight-3', 'LicenseRef-scancode-ms-silverlight-3'], + ['ms-specification', 'LicenseRef-scancode-ms-specification'], + ['ms-sql-server-compact-4.0', 'LicenseRef-scancode-ms-sql-server-compact-4.0'], + ['ms-sql-server-data-tools', 'LicenseRef-scancode-ms-sql-server-data-tools'], + ['ms-sspl', 'LicenseRef-scancode-ms-sspl'], + ['ms-sysinternals-sla', 'LicenseRef-scancode-ms-sysinternals-sla'], + ['ms-testplatform-17.0.0', 'LicenseRef-scancode-ms-testplatform-17.0.0'], + ['ms-ttf-eula', 'LicenseRef-scancode-ms-ttf-eula'], + ['ms-typescript-msbuild-4.1.4', 'LicenseRef-scancode-ms-typescript-msbuild-4.1.4'], + ['ms-visual-2008-runtime', 'LicenseRef-scancode-ms-visual-2008-runtime'], + ['ms-visual-2010-runtime', 'LicenseRef-scancode-ms-visual-2010-runtime'], + ['ms-visual-2015-sdk', 'LicenseRef-scancode-ms-visual-2015-sdk'], + ['ms-visual-cpp-2015-runtime', 'LicenseRef-scancode-ms-visual-cpp-2015-runtime'], + ['ms-visual-studio-2017', 'LicenseRef-scancode-ms-visual-studio-2017'], + ['ms-visual-studio-2017-tools', 'LicenseRef-scancode-ms-visual-studio-2017-tools'], + ['ms-visual-studio-code', 'LicenseRef-scancode-ms-visual-studio-code'], + ['ms-visual-studio-code-2018', 'LicenseRef-scancode-ms-visual-studio-code-2018'], + ['ms-visual-studio-code-2022', 'LicenseRef-scancode-ms-visual-studio-code-2022'], + ['ms-vs-addons-ext-17.2.0', 'LicenseRef-scancode-ms-vs-addons-ext-17.2.0'], + ['ms-web-developer-tools-1.0', 'LicenseRef-scancode-ms-web-developer-tools-1.0'], + ['ms-windows-container-base-image-eula-2020', 'LicenseRef-scancode-ms-win-container-eula-2020'], + ['ms-windows-driver-kit', 'LicenseRef-scancode-ms-windows-driver-kit'], + ['ms-windows-identity-foundation', 'LicenseRef-scancode-ms-windows-identity-foundation'], + ['ms-windows-os-2018', 'LicenseRef-scancode-ms-windows-os-2018'], + ['ms-windows-sdk-server-2008-net-3.5', 'LicenseRef-scancode-ms-win-sdk-server-2008-net-3.5'], + ['ms-windows-sdk-win10', 'LicenseRef-scancode-ms-windows-sdk-win10'], + ['ms-windows-sdk-win10-net-6', 'LicenseRef-scancode-ms-windows-sdk-win10-net-6'], + ['ms-windows-sdk-win7-net-4', 'LicenseRef-scancode-ms-windows-sdk-win7-net-4'], + ['ms-windows-server-2003-ddk', 'LicenseRef-scancode-ms-windows-server-2003-ddk'], + ['ms-windows-server-2003-sdk', 'LicenseRef-scancode-ms-windows-server-2003-sdk'], + ['ms-ws-routing-spec', 'LicenseRef-scancode-ms-ws-routing-spec'], + ['ms-xamarin-uitest3.2.0', 'LicenseRef-scancode-ms-xamarin-uitest3.2.0'], + ['ms-xml-core-4.0', 'LicenseRef-scancode-ms-xml-core-4.0'], + ['msdn-magazine-sample-code-2007', 'LicenseRef-scancode-msdn-magazine-sample-code-2007'], + ['msj-sample-code', 'LicenseRef-scancode-msj-sample-code'], + ['msntp', 'LicenseRef-scancode-msntp'], + ['msppl', 'LicenseRef-scancode-msppl'], ['mtll', 'MTLL'], - ['mup', 'Mup'], + ['mtx-licensing-statement', 'LicenseRef-scancode-mtx-licensing-statement'], + ['mulanpsl-1.0', 'MulanPSL-1.0'], + ['mulanpsl-1.0-en', 'LicenseRef-scancode-mulanpsl-1.0-en'], + ['mulanpsl-2.0', 'MulanPSL-2.0'], + ['mulanpsl-2.0-en', 'LicenseRef-scancode-mulanpsl-2.0-en'], + ['mulanpubl-1.0', 'LicenseRef-scancode-mulanpubl-1.0'], + ['mulanpubl-2.0', 'LicenseRef-scancode-mulanpubl-2.0'], + ['mule-source-1.1.3', 'LicenseRef-scancode-mule-source-1.1.3'], + ['mule-source-1.1.4', 'LicenseRef-scancode-mule-source-1.1.4'], + ['mulle-kybernetik', 'LicenseRef-scancode-mulle-kybernetik'], ['multics', 'Multics'], + ['mup', 'Mup'], + ['musl-exception', 'LicenseRef-scancode-musl-exception'], + ['mut-license', 'LicenseRef-scancode-mut-license'], + ['mvt-1.1', 'LicenseRef-scancode-mvt-1.1'], + ['mx4j', 'LicenseRef-scancode-mx4j'], + ['mysql-connector-odbc-exception-2.0', 'LicenseRef-scancode-mysql-con-odbc-exception-2.0'], + ['mysql-floss-exception-2.0', 'LicenseRef-scancode-mysql-floss-exception-2.0'], + ['mysql-linking-exception-2018', 'LicenseRef-scancode-mysql-linking-exception-2018'], + ['n8n-ee-2022', 'LicenseRef-scancode-n8n-ee-2022'], + ['naist-2003', 'NAIST-2003'], + ['nant-exception-2.0-plus', 'LicenseRef-scancode-nant-exception-2.0-plus'], ['nasa-1.3', 'NASA-1.3'], + ['naughter', 'LicenseRef-scancode-naughter'], ['naumen', 'Naumen'], ['nbpl-1.0', 'NBPL-1.0'], + ['ncbi', 'LicenseRef-scancode-ncbi'], + ['ncgl-uk-2.0', 'NCGL-UK-2.0'], + ['ncsa-httpd-1995', 'LicenseRef-scancode-ncsa-httpd-1995'], + ['nero-eula', 'LicenseRef-scancode-nero-eula'], ['net-snmp', 'Net-SNMP'], + ['netapp-sdk-aug2020', 'LicenseRef-scancode-netapp-sdk-aug2020'], + ['netcat', 'LicenseRef-scancode-netcat'], ['netcdf', 'NetCDF'], + ['netcomponents', 'LicenseRef-scancode-netcomponents'], + ['netdata-ncul1', 'LicenseRef-scancode-netdata-ncul1'], + ['netron', 'LicenseRef-scancode-netron'], + ['netronome-firmware', 'LicenseRef-scancode-netronome-firmware'], + ['network-time-protocol', 'null'], + ['new-relic', 'LicenseRef-scancode-new-relic'], + ['newlib-historical', 'LicenseRef-scancode-newlib-historical'], + ['newran', 'LicenseRef-scancode-newran'], ['newsletr', 'Newsletr'], + ['newton-king-cla', 'LicenseRef-scancode-newton-king-cla'], + ['nexb-eula-saas-1.1.0', 'LicenseRef-scancode-nexb-eula-saas-1.1.0'], + ['nexb-ssla-1.1.0', 'LicenseRef-scancode-nexb-ssla-1.1.0'], ['ngpl', 'NGPL'], + ['nice', 'LicenseRef-scancode-nice'], + ['nicta-exception', 'LicenseRef-scancode-nicta-exception'], + ['nicta-psl', 'NICTA-1.0'], + ['niels-ferguson', 'LicenseRef-scancode-niels-ferguson'], + ['nilsson-historical', 'LicenseRef-scancode-nilsson-historical'], + ['nist-pd', 'NIST-PD'], + ['nist-pd-fallback', 'NIST-PD-fallback'], + ['nist-software', 'NIST-Software'], + ['nist-srd', 'LicenseRef-scancode-nist-srd'], ['nlod-1.0', 'NLOD-1.0'], + ['nlod-2.0', 'NLOD-2.0'], ['nlpl', 'NLPL'], + ['no-license', 'LicenseRef-scancode-no-license'], + ['node-js', 'LicenseRef-scancode-node-js'], + ['nokia-qt-exception-1.1', 'null'], ['nokos-1.0a', 'Nokia'], + ['non-violent-4.0', 'LicenseRef-scancode-non-violent-4.0'], + ['non-violent-7.0', 'LicenseRef-scancode-non-violent-7.0'], + ['nonexclusive', 'LicenseRef-scancode-nonexclusive'], + ['nortel-dasa', 'LicenseRef-scancode-nortel-dasa'], + ['northwoods-sla-2021', 'LicenseRef-scancode-northwoods-sla-2021'], ['nosl-1.0', 'NOSL'], + ['nosl-3.0', 'NPOSL-3.0'], + ['notre-dame', 'LicenseRef-scancode-notre-dame'], ['noweb', 'Noweb'], ['npl-1.0', 'NPL-1.0'], ['npl-1.1', 'NPL-1.1'], + ['npsl-exception-0.92', 'LicenseRef-scancode-npsl-exception-0.92'], + ['npsl-exception-0.93', 'LicenseRef-scancode-npsl-exception-0.93'], + ['npsl-exception-0.94', 'LicenseRef-scancode-npsl-exception-0.94'], + ['npsl-exception-0.95', 'LicenseRef-scancode-npsl-exception-0.95'], ['nrl', 'NRL'], - ['nosl-3.0', 'NPOSL-3.0'], - ['ntpl', 'NTP'], + ['nrl-permission', 'CMU-Mach-nodoc'], + ['ntlm', 'LicenseRef-scancode-ntlm'], + ['ntp-0', 'NTP-0'], + ['ntpl', 'null'], + ['ntpl-origin', 'LicenseRef-scancode-ntpl-origin'], + ['nucleusicons-eula', 'LicenseRef-scancode-nucleusicons-eula'], + ['numerical-recipes-notice', 'LicenseRef-scancode-numerical-recipes-notice'], + ['nunit-v2', 'null'], + ['nvidia', 'LicenseRef-scancode-nvidia'], + ['nvidia-2002', 'AML-glslang'], + ['nvidia-apex-sdk-eula-2011', 'LicenseRef-scancode-nvidia-apex-sdk-eula-2011'], + ['nvidia-cuda-supplement-2020', 'LicenseRef-scancode-nvidia-cuda-supplement-2020'], + ['nvidia-gov', 'LicenseRef-scancode-nvidia-gov'], + ['nvidia-isaac-eula-2019.1', 'LicenseRef-scancode-nvidia-isaac-eula-2019.1'], + ['nvidia-ngx-eula-2019', 'LicenseRef-scancode-nvidia-ngx-eula-2019'], + ['nvidia-sdk-eula-v0.11', 'LicenseRef-scancode-nvidia-sdk-eula-v0.11'], + ['nvidia-video-codec-agreement', 'LicenseRef-scancode-nvidia-video-codec-agreement'], + ['nwhm', 'LicenseRef-scancode-nwhm'], + ['nxp-firmware-patent', 'LicenseRef-scancode-nxp-firmware-patent'], + ['nxp-linux-firmware', 'LicenseRef-scancode-nxp-linux-firmware'], + ['nxp-mc-firmware', 'LicenseRef-scancode-nxp-mc-firmware'], + ['nxp-microcontroller-proprietary', 'LicenseRef-scancode-nxp-microctl-proprietary'], + ['nxp-warranty-disclaimer', 'LicenseRef-scancode-nxp-warranty-disclaimer'], + ['nysl-0.9982', 'LicenseRef-scancode-nysl-0.9982'], + ['nysl-0.9982-jp', 'LicenseRef-scancode-nysl-0.9982-jp'], + ['o-uda-1.0', 'O-UDA-1.0'], + ['o-young-jong', 'LicenseRef-scancode-o-young-jong'], + ['oasis-ipr-2013', 'LicenseRef-scancode-oasis-ipr-2013'], + ['oasis-ipr-policy-2014', 'LicenseRef-scancode-oasis-ipr-policy-2014'], + ['oasis-ws-security-spec', 'LicenseRef-scancode-oasis-ws-security-spec'], + ['object-form-exception-to-mit', 'fmt-exception'], ['ocaml-lgpl-linking-exception', 'OCaml-LGPL-linking-exception'], + ['ocb-non-military-2013', 'LicenseRef-scancode-ocb-non-military-2013'], + ['ocb-open-source-2013', 'LicenseRef-scancode-ocb-open-source-2013'], + ['ocb-patent-openssl-2013', 'LicenseRef-scancode-ocb-patent-openssl-2013'], + ['occt-exception-1.0', 'OCCT-exception-1.0'], ['occt-pl', 'OCCT-PL'], + ['oclc-1.0', 'LicenseRef-scancode-oclc-1.0'], ['oclc-2.0', 'OCLC-2.0'], + ['ocsl-1.0', 'LicenseRef-scancode-ocsl-1.0'], + ['oculus-sdk', 'LicenseRef-scancode-oculus-sdk'], + ['oculus-sdk-2020', 'LicenseRef-scancode-oculus-sdk-2020'], + ['oculus-sdk-3.5', 'LicenseRef-scancode-oculus-sdk-3.5'], + ['odb-cpl', 'LicenseRef-scancode-odb-cpl'], + ['odb-fpl', 'LicenseRef-scancode-odb-fpl'], + ['odb-ncuel', 'LicenseRef-scancode-odb-ncuel'], ['odbl-1.0', 'ODbL-1.0'], - ['occt-exception-1.0', 'OCCT-exception-1.0'], + ['odc-1.0', 'null'], ['odc-by-1.0', 'ODC-By-1.0'], - ['ofl-1.1', 'OFL-1.1'], + ['odl', 'LicenseRef-scancode-odl'], + ['odmg', 'LicenseRef-scancode-odmg'], + ['offis', 'OFFIS'], ['ofl-1.0', 'OFL-1.0'], - ['ogl-uk-2.0', 'OGL-UK-2.0'], + ['ofl-1.0-no-rfn', 'OFL-1.0-no-RFN'], + ['ofl-1.0-rfn', 'OFL-1.0-RFN'], + ['ofl-1.1', 'OFL-1.1'], + ['ofl-1.1-no-rfn', 'OFL-1.1-no-RFN'], + ['ofl-1.1-rfn', 'OFL-1.1-RFN'], + ['ofrak-community-1.0', 'LicenseRef-scancode-ofrak-community-1.0'], + ['ogc', 'LicenseRef-scancode-ogc'], + ['ogc-1.0', 'OGC-1.0'], + ['ogc-2006', 'null'], + ['ogc-document-2020', 'LicenseRef-scancode-ogc-document-2020'], + ['ogdl-taiwan-1.0', 'OGDL-Taiwan-1.0'], + ['ogl-1.0a', 'LicenseRef-scancode-ogl-1.0a'], + ['ogl-canada-2.0-fr', 'LicenseRef-scancode-ogl-canada-2.0-fr'], ['ogl-uk-1.0', 'OGL-UK-1.0'], + ['ogl-uk-2.0', 'OGL-UK-2.0'], ['ogl-uk-3.0', 'OGL-UK-3.0'], - ['opengroup', 'OGTSL'], + ['ogl-wpd-3.0', 'LicenseRef-scancode-ogl-wpd-3.0'], + ['ohdl-1.0', 'LicenseRef-scancode-ohdl-1.0'], + ['okl', 'LicenseRef-scancode-okl'], + ['olf-ccla-1.0', 'LicenseRef-scancode-olf-ccla-1.0'], + ['olfl-1.3', 'OLFL-1.3'], + ['oll-1.0', 'LicenseRef-scancode-oll-1.0'], + ['on2-patent', 'LicenseRef-scancode-on2-patent'], + ['ooura-2001', 'LicenseRef-scancode-ooura-2001'], + ['open-diameter', 'LicenseRef-scancode-open-diameter'], ['open-public', 'OPL-1.0'], + ['open-weights-permissive-1.0.0', 'LicenseRef-scancode-open-weights-permissive-1.0.0'], + ['openai-tou-20230314', 'LicenseRef-scancode-openai-tou-20230314'], + ['openbd-exception-3.0', 'LicenseRef-scancode-openbd-exception-3.0'], + ['opencarp-1.0', 'LicenseRef-scancode-opencarp-1.0'], + ['opengroup', 'OGTSL'], + ['opengroup-pl', 'LicenseRef-scancode-opengroup-pl'], + ['openi-pl-1.0', 'LicenseRef-scancode-openi-pl-1.0'], ['openjdk-assembly-exception-1.0', 'OpenJDK-assembly-exception-1.0'], + ['openjdk-classpath-exception-2.0', 'LicenseRef-scancode-openjdk-classpath-exception2.0'], + ['openjdk-exception', 'LicenseRef-scancode-openjdk-exception'], + ['openldap-1.1', 'OLDAP-1.1'], ['openldap-1.2', 'OLDAP-1.2'], - ['openldap-1.4', 'OLDAP-1.4'], ['openldap-1.3', 'OLDAP-1.3'], - ['openldap-1.1', 'OLDAP-1.1'], + ['openldap-1.4', 'OLDAP-1.4'], ['openldap-2.0', 'OLDAP-2.0'], ['openldap-2.0.1', 'OLDAP-2.0.1'], ['openldap-2.1', 'OLDAP-2.1'], - ['openldap-2.2.2', 'OLDAP-2.2.2'], ['openldap-2.2', 'OLDAP-2.2'], - ['openldap-2.3', 'OLDAP-2.3'], ['openldap-2.2.1', 'OLDAP-2.2.1'], + ['openldap-2.2.2', 'OLDAP-2.2.2'], + ['openldap-2.3', 'OLDAP-2.3'], ['openldap-2.4', 'OLDAP-2.4'], ['openldap-2.5', 'OLDAP-2.5'], - ['openldap-2.7', 'OLDAP-2.7'], ['openldap-2.6', 'OLDAP-2.6'], + ['openldap-2.7', 'OLDAP-2.7'], ['openldap-2.8', 'OLDAP-2.8'], + ['openmap', 'LicenseRef-scancode-openmap'], + ['openmarket-fastcgi', 'LicenseRef-scancode-openmarket-fastcgi'], + ['openmotif-exception-2.0-plus', 'LicenseRef-scancode-openmotif-exception-2.0-plus'], + ['openmrs-exception-to-mpl-2.0', 'LicenseRef-scancode-openmrs-exception-to-mpl-2.0'], + ['opennetcf-shared-source', 'LicenseRef-scancode-opennetcf-shared-source'], + ['openorb-1.0', 'LicenseRef-scancode-openorb-1.0'], + ['openpbs-2.3', 'OpenPBS-2.3'], + ['openpub', 'OPUBL-1.0'], + ['opensaml-1.0', 'LicenseRef-scancode-opensaml-1.0'], + ['opensc-openssl-openpace-exception-gpl', 'LicenseRef-scancode-openpace-exception-gpl'], + ['openssh', 'SSH-OpenSSH'], + ['openssl', 'OpenSSL-standalone'], + ['openssl-exception-agpl-3.0', 'LicenseRef-scancode-openssl-exception-agpl-3.0'], + ['openssl-exception-agpl-3.0-monit', 'LicenseRef-scancode-openssl-exception-agpl3.0monit'], + ['openssl-exception-agpl-3.0-plus', 'LicenseRef-scancode-openssl-exception-agpl3.0plus'], + ['openssl-exception-gpl-2.0', 'x11vnc-openssl-exception'], + ['openssl-exception-gpl-2.0-plus', 'LicenseRef-scancode-openssl-exception-gpl-2.0-plus'], + ['openssl-exception-gpl-3.0-plus', 'cryptsetup-OpenSSL-exception'], + ['openssl-exception-lgpl', 'LicenseRef-scancode-openssl-exception-lgpl'], + ['openssl-exception-lgpl-2.0-plus', 'LicenseRef-scancode-openssl-exception-lgpl2.0plus'], + ['openssl-exception-lgpl-3.0-plus', 'LicenseRef-scancode-openssl-exception-lgpl3.0plus'], + ['openssl-exception-mongodb-sspl', 'LicenseRef-scancode-openssl-exception-mongodb-sspl'], + ['openssl-nokia-psk-contribution', 'LicenseRef-scancode-openssl-nokia-psk-contribution'], ['openssl-ssleay', 'OpenSSL'], + ['openvision', 'OpenVision'], + ['openvpn-as-eula', 'LicenseRef-scancode-openvpn-as-eula'], ['openvpn-openssl-exception', 'openvpn-openssl-exception'], + ['openwall-md5-permissive', 'LicenseRef-scancode-openwall-md5-permissive'], + ['opera-eula-2018', 'LicenseRef-scancode-opera-eula-2018'], + ['opera-eula-eea-2018', 'LicenseRef-scancode-opera-eula-eea-2018'], + ['opera-widget-1.0', 'LicenseRef-scancode-opera-widget-1.0'], + ['opl-1.0', 'LicenseRef-scancode-opl-1.0'], + ['opl-uk-3.0', 'OPL-UK-3.0'], + ['opml-1.0', 'LicenseRef-scancode-opml-1.0'], + ['opnl-1.0', 'LicenseRef-scancode-opnl-1.0'], + ['opnl-2.0', 'LicenseRef-scancode-opnl-2.0'], + ['oracle-bcl-javaee', 'LicenseRef-scancode-oracle-bcl-javaee'], + ['oracle-bcl-javase-javafx-2012', 'LicenseRef-scancode-oracle-bcl-javase-javafx-2012'], + ['oracle-bcl-javase-javafx-2013', 'LicenseRef-scancode-oracle-bcl-javase-javafx-2013'], + ['oracle-bcl-javase-platform-javafx-2013', 'LicenseRef-scancode-oracle-bcl-java-platform-2013'], + ['oracle-bcl-javase-platform-javafx-2017', 'LicenseRef-scancode-oracle-bcl-java-platform-2017'], + ['oracle-bcl-jsse-1.0.3', 'LicenseRef-scancode-oracle-bcl-jsse-1.0.3'], ['oracle-bsd-no-nuclear', 'BSD-3-Clause-No-Nuclear-License-2014'], + ['oracle-code-samples-bsd', 'LicenseRef-scancode-oracle-code-samples-bsd'], + ['oracle-commercial-database-11g2', 'LicenseRef-scancode-oracle-commercial-db-11g2'], + ['oracle-devtools-vsnet-dev', 'LicenseRef-scancode-oracle-devtools-vsnet-dev'], + ['oracle-entitlement-05-15', 'LicenseRef-scancode-oracle-entitlement-05-15'], + ['oracle-free-2018', 'LicenseRef-scancode-oracle-free-2018'], + ['oracle-gftc-2023-06-12', 'LicenseRef-scancode-oracle-gftc-2023-06-12'], + ['oracle-java-ee-sdk-2010', 'LicenseRef-scancode-oracle-java-ee-sdk-2010'], + ['oracle-master-agreement', 'LicenseRef-scancode-oracle-master-agreement'], + ['oracle-mysql-foss-exception-2.0', 'LicenseRef-scancode-oracle-mysql-foss-exception2.0'], + ['oracle-nftc-2021', 'LicenseRef-scancode-oracle-nftc-2021'], + ['oracle-openjdk-classpath-exception-2.0', 'LicenseRef-scancode-oracle-openjdk-exception-2.0'], + ['oracle-otn-javase-2019', 'LicenseRef-scancode-oracle-otn-javase-2019'], + ['oracle-sql-developer', 'LicenseRef-scancode-oracle-sql-developer'], + ['oracle-web-sites-tou', 'LicenseRef-scancode-oracle-web-sites-tou'], + ['oreilly-notice', 'LicenseRef-scancode-oreilly-notice'], ['oset-pl-2.1', 'OSET-PL-2.1'], + ['osetpl-2.1', 'null'], + ['osf-1990', 'HP-1989'], + ['osgi-spec-2.0', 'LicenseRef-scancode-osgi-spec-2.0'], ['osl-1.0', 'OSL-1.0'], - ['osl-2.0', 'OSL-2.0'], - ['osl-3.0', 'OSL-3.0'], ['osl-1.1', 'OSL-1.1'], + ['osl-2.0', 'OSL-2.0'], ['osl-2.1', 'OSL-2.1'], + ['osl-3.0', 'OSL-3.0'], + ['ossn-3.0', 'LicenseRef-scancode-ossn-3.0'], + ['oswego-concurrent', 'LicenseRef-scancode-oswego-concurrent'], + ['other-copyleft', 'LicenseRef-scancode-other-copyleft'], + ['other-permissive', 'LicenseRef-scancode-other-permissive'], + ['otn-dev-dist', 'LicenseRef-scancode-otn-dev-dist'], + ['otn-dev-dist-2009', 'LicenseRef-scancode-otn-dev-dist-2009'], + ['otn-dev-dist-2014', 'LicenseRef-scancode-otn-dev-dist-2014'], + ['otn-dev-dist-2016', 'LicenseRef-scancode-otn-dev-dist-2016'], + ['otn-early-adopter-2018', 'LicenseRef-scancode-otn-early-adopter-2018'], + ['otn-early-adopter-development', 'LicenseRef-scancode-otn-early-adopter-development'], + ['otn-standard-2014-09', 'LicenseRef-scancode-otn-standard-2014-09'], + ['owal-1.0', 'LicenseRef-scancode-owal-1.0'], + ['owf-cla-1.0-copyright', 'LicenseRef-scancode-owf-cla-1.0-copyright'], + ['owf-cla-1.0-copyright-patent', 'LicenseRef-scancode-owf-cla-1.0-copyright-patent'], + ['owfa-1-0-patent-only', 'LicenseRef-scancode-owfa-1.0-patent-only'], + ['owfa-1.0', 'LicenseRef-scancode-owfa-1.0'], + ['owl-0.9.4', 'LicenseRef-scancode-owl-0.9.4'], + ['owtchart', 'LicenseRef-scancode-owtchart'], + ['oxygen-xml-webhelp-eula', 'LicenseRef-scancode-oxygen-xml-webhelp-eula'], + ['ozplb-1.0', 'LicenseRef-scancode-ozplb-1.0'], + ['ozplb-1.1', 'LicenseRef-scancode-ozplb-1.1'], + ['padl', 'PADL'], + ['paint-net', 'LicenseRef-scancode-paint-net'], + ['paolo-messina-2000', 'LicenseRef-scancode-paolo-messina-2000'], + ['paraview-1.2', 'LicenseRef-scancode-paraview-1.2'], + ['parity-6.0.0', 'Parity-6.0.0'], + ['parity-7.0.0', 'Parity-7.0.0'], + ['passive-aggressive', 'LicenseRef-scancode-passive-aggressive'], + ['patent-disclaimer', 'LicenseRef-scancode-patent-disclaimer'], + ['paul-hsieh-derivative', 'LicenseRef-scancode-paul-hsieh-derivative'], + ['paul-hsieh-exposition', 'LicenseRef-scancode-paul-hsieh-exposition'], + ['paul-mackerras', 'Mackerras-3-Clause-acknowledgment'], + ['paul-mackerras-binary', 'LicenseRef-scancode-paul-mackerras-binary'], + ['paul-mackerras-new', 'Mackerras-3-Clause'], + ['paul-mackerras-simplified', 'LicenseRef-scancode-paul-mackerras-simplified'], + ['paulo-soares', 'LicenseRef-scancode-paulo-soares'], + ['paypal-sdk-2013-2016', 'LicenseRef-scancode-paypal-sdk-2013-2016'], + ['pbl-1.0', 'LicenseRef-scancode-pbl-1.0'], + ['pcre', 'LicenseRef-scancode-pcre'], + ['pd-mit', 'LicenseRef-scancode-pd-mit'], + ['pd-programming', 'LicenseRef-scancode-pd-programming'], ['pddl-1.0', 'PDDL-1.0'], - ['php-3.01', 'PHP-3.01'], + ['pdf-creator-pilot', 'LicenseRef-scancode-pdf-creator-pilot'], + ['pdl-1.0', 'LicenseRef-scancode-pdl-1.0'], + ['perl-1.0', 'LicenseRef-scancode-perl-1.0'], + ['peter-deutsch-document', 'LPD-document'], + ['pfe-proprietary-notice', 'LicenseRef-scancode-pfe-proprietary-notice'], + ['pftijah-1.1', 'LicenseRef-scancode-pftijah-1.1'], + ['pftus-1.1', 'LicenseRef-scancode-pftus-1.1'], + ['phaser-academic', 'LicenseRef-scancode-phaser-academic'], + ['phaser-ccp4', 'LicenseRef-scancode-phaser-ccp4'], + ['phaser-phenix', 'LicenseRef-scancode-phaser-phenix'], + ['phil-bunce', 'LicenseRef-scancode-phil-bunce'], + ['philippe-de-muyter', 'LicenseRef-scancode-philippe-de-muyter'], + ['philips-proprietary-notice-2000', 'LicenseRef-scancode-philips-proprietary-notice2000'], + ['phorum-2.0', 'LicenseRef-scancode-phorum-2.0'], + ['php-2.0.2', 'LicenseRef-scancode-php-2.0.2'], ['php-3.0', 'PHP-3.0'], + ['php-3.01', 'PHP-3.01'], + ['pine', 'LicenseRef-scancode-pine'], + ['pivotal-tou', 'LicenseRef-scancode-pivotal-tou'], + ['pixabay-content', 'LicenseRef-scancode-pixabay-content'], + ['pixar', 'Pixar'], + ['planet-source-code', 'LicenseRef-scancode-planet-source-code'], + ['plural-20211124', 'LicenseRef-scancode-plural-20211124'], + ['pml-2020', 'LicenseRef-scancode-pml-2020'], + ['pngsuite', 'LicenseRef-scancode-pngsuite'], + ['pnmstitch', 'pnmstitch'], + ['politepix-pl-1.0', 'LicenseRef-scancode-politepix-pl-1.0'], + ['polyform-defensive-1.0.0', 'null'], + ['polyform-free-trial-1.0.0', 'LicenseRef-scancode-polyform-free-trial-1.0.0'], + ['polyform-internal-use-1.0.0', 'LicenseRef-scancode-polyform-internal-use-1.0.0'], + ['polyform-noncommercial-1.0.0', 'PolyForm-Noncommercial-1.0.0'], + ['polyform-perimeter-1.0.0', 'LicenseRef-scancode-polyform-perimeter-1.0.0'], + ['polyform-shield-1.0.0', 'LicenseRef-scancode-polyform-shield-1.0.0'], + ['polyform-small-business-1.0.0', 'PolyForm-Small-Business-1.0.0'], + ['polyform-strict-1.0.0', 'LicenseRef-scancode-polyform-strict-1.0.0'], ['postgresql', 'PostgreSQL'], + ['powervr-tools-software-eula', 'LicenseRef-scancode-powervr-tools-software-eula'], + ['ppp', 'LicenseRef-scancode-ppp'], + ['proconx-modbus-rev4', 'LicenseRef-scancode-proconx-modbus-rev4'], + ['proguard-exception-2.0', 'LicenseRef-scancode-proguard-exception-2.0'], + ['proprietary', 'null'], + ['proprietary-license', 'LicenseRef-scancode-proprietary-license'], + ['prosperity-1.0.1', 'LicenseRef-scancode-prosperity-1.0.1'], + ['prosperity-2.0', 'LicenseRef-scancode-prosperity-2.0'], + ['prosperity-3.0', 'LicenseRef-scancode-prosperity-3.0'], + ['protobuf', 'LicenseRef-scancode-protobuf'], ['ps-or-pdf-font-exception-20170817', 'PS-or-PDF-font-exception-20170817'], + ['psf-2.0', 'PSF-2.0'], + ['psf-3.7.2', 'LicenseRef-scancode-psf-3.7.2'], ['psfrag', 'psfrag'], ['psutils', 'psutils'], + ['psytec-freesoft', 'LicenseRef-scancode-psytec-freesoft'], + ['public-domain', 'LicenseRef-scancode-public-domain'], + ['public-domain-disclaimer', 'LicenseRef-scancode-public-domain-disclaimer'], + ['punycode', 'LicenseRef-scancode-punycode'], + ['purdue-bsd', 'lsof'], + ['pybench', 'LicenseRef-scancode-pybench'], + ['pycrypto', 'LicenseRef-scancode-pycrypto'], + ['pygres-2.2', 'LicenseRef-scancode-pygres-2.2'], ['python', 'Python-2.0'], - ['qpl-1.0', 'QPL-1.0'], + ['python-2.0.1', 'Python-2.0.1'], + ['python-cwi', 'LicenseRef-scancode-python-cwi'], + ['python-ldap', 'python-ldap'], + ['qaplug', 'LicenseRef-scancode-qaplug'], + ['qca-linux-firmware', 'LicenseRef-scancode-qca-linux-firmware'], + ['qca-technology', 'LicenseRef-scancode-qca-technology'], + ['qcad-exception-gpl', 'LicenseRef-scancode-qcad-exception-gpl'], ['qhull', 'Qhull'], + ['qlogic-firmware', 'LicenseRef-scancode-qlogic-firmware'], + ['qlogic-microcode', 'LicenseRef-scancode-qlogic-microcode'], + ['qpl-1.0', 'QPL-1.0'], + ['qpl-1.0-inria-2004', 'QPL-1.0-INRIA-2004'], + ['qpopper', 'LicenseRef-scancode-qpopper'], + ['qskinny-exception-lgpl-2.1', 'LicenseRef-scancode-qskinny-exception-lgpl-2.1'], + ['qt-commercial-1.1', 'LicenseRef-scancode-qt-commercial-1.1'], + ['qt-commercial-agreement-4.4.1', 'LicenseRef-scancode-qt-commercial-agreement-4.4.1'], + ['qt-company-exception-2017-lgpl-2.1', 'null'], + ['qt-company-exception-lgpl-2.1', 'LicenseRef-scancode-qt-company-exception-lgpl-2.1'], ['qt-gpl-exception-1.0', 'Qt-GPL-exception-1.0'], + ['qt-kde-linking-exception', 'LicenseRef-scancode-qt-kde-linking-exception'], ['qt-lgpl-exception-1.1', 'Qt-LGPL-exception-1.1'], + ['qt-qca-exception-2.0', 'LicenseRef-scancode-qt-qca-exception-2.0'], + ['qti-linux-firmware', 'LicenseRef-scancode-qti-linux-firmware'], + ['qualcomm-iso', 'LicenseRef-scancode-qualcomm-iso'], + ['qualcomm-turing', 'LicenseRef-scancode-qualcomm-turing'], + ['quickfix-1.0', 'LicenseRef-scancode-quickfix-1.0'], + ['quicktime', 'LicenseRef-scancode-quicktime'], + ['quin-street', 'LicenseRef-scancode-quin-street'], + ['quirksmode', 'LicenseRef-scancode-quirksmode'], + ['qwt-1.0', 'null'], ['qwt-exception-1.0', 'Qwt-exception-1.0'], + ['rackspace', 'LicenseRef-scancode-rackspace'], + ['radvd', 'radvd'], + ['ralf-corsepius', 'null'], + ['ralink-firmware', 'LicenseRef-scancode-ralink-firmware'], + ['rar-winrar-eula', 'LicenseRef-scancode-rar-winrar-eula'], + ['rcsl-2.0', 'LicenseRef-scancode-rcsl-2.0'], + ['rcsl-3.0', 'LicenseRef-scancode-rcsl-3.0'], ['rdisc', 'Rdisc'], - ['ricoh-1.0', 'RSCPL'], + ['reading-godiva-2010', 'LicenseRef-scancode-reading-godiva-2010'], + ['realm-platform-extension-2017', 'LicenseRef-scancode-realm-platform-extension-2017'], + ['red-hat-attribution', 'LicenseRef-scancode-red-hat-attribution'], + ['red-hat-bsd-simplified', 'LicenseRef-scancode-red-hat-bsd-simplified'], + ['red-hat-logos', 'LicenseRef-scancode-red-hat-logos'], + ['red-hat-trademarks', 'LicenseRef-scancode-red-hat-trademarks'], + ['redis-source-available-1.0', 'LicenseRef-scancode-redis-source-available-1.0'], ['regexp', 'Spencer-86'], + ['reportbug', 'LicenseRef-scancode-reportbug'], + ['repoze', 'BSD-3-Clause-Modification'], + ['research-disclaimer', 'LicenseRef-scancode-research-disclaimer'], + ['responsible-ai-source-1.0', 'LicenseRef-scancode-responsible-ai-source-1.0'], + ['responsible-ai-source-1.1', 'LicenseRef-scancode-responsible-ai-source-1.1'], + ['rh-eula', 'LicenseRef-scancode-rh-eula'], + ['rh-eula-lgpl', 'LicenseRef-scancode-rh-eula-lgpl'], + ['ricebsd', 'LicenseRef-scancode-ricebsd'], + ['richard-black', 'LicenseRef-scancode-richard-black'], + ['ricoh-1.0', 'RSCPL'], + ['riverbank-sip', 'LicenseRef-scancode-riverbank-sip'], + ['robert-hubley', 'LicenseRef-scancode-robert-hubley'], + ['rockchip-proprietary-2022', 'LicenseRef-scancode-rockchip-proprietary-2022'], + ['rogue-wave', 'LicenseRef-scancode-rogue-wave'], ['rpl-1.1', 'RPL-1.1'], ['rpl-1.5', 'RPL-1.5'], ['rpsl-1.0', 'RPSL-1.0'], + ['rrdtool-floss-exception-2.0', 'LicenseRef-scancode-rrdtool-floss-exception-2.0'], + ['rsa-1990', 'LicenseRef-scancode-rsa-1990'], + ['rsa-cryptoki', 'LicenseRef-scancode-rsa-cryptoki'], + ['rsa-demo', 'LicenseRef-scancode-rsa-demo'], + ['rsa-md2', 'LicenseRef-scancode-rsa-md2'], + ['rsa-md4', 'LicenseRef-scancode-rsa-md4'], ['rsa-md5', 'RSA-MD'], + ['rsa-proprietary', 'LicenseRef-scancode-rsa-proprietary'], + ['rsalv2', 'LicenseRef-scancode-rsalv2'], + ['rtools-util', 'LicenseRef-scancode-rtools-util'], ['ruby', 'Ruby'], + ['rubyencoder-commercial', 'LicenseRef-scancode-rubyencoder-commercial'], + ['rubyencoder-loader', 'LicenseRef-scancode-rubyencoder-loader'], + ['rute', 'LicenseRef-scancode-rute'], + ['rxtx-exception-lgpl-2.1', 'LicenseRef-scancode-rxtx-exception-lgpl-2.1'], + ['ryszard-szopa', 'LicenseRef-scancode-ryszard-szopa'], + ['saas-mit', 'LicenseRef-scancode-saas-mit'], + ['saf', 'LicenseRef-scancode-saf'], + ['safecopy-eula', 'LicenseRef-scancode-safecopy-eula'], + ['san-francisco-font', 'LicenseRef-scancode-san-francisco-font'], + ['sandeep', 'LicenseRef-scancode-sandeep'], + ['sane-exception-2.0-plus', 'SANE-exception'], + ['sash', 'LicenseRef-scancode-sash'], + ['sata', 'LicenseRef-scancode-sata'], ['sax-pd', 'SAX-PD'], + ['sax-pd-2.0', 'SAX-PD-2.0'], + ['saxix-mit', 'LicenseRef-scancode-saxix-mit'], ['saxpath', 'Saxpath'], + ['sbia-b', 'LicenseRef-scancode-sbia-b'], + ['scancode-acknowledgment', 'LicenseRef-scancode-scancode-acknowledgment'], + ['scanlogd-license', 'LicenseRef-scancode-scanlogd-license'], + ['scansoft-1.2', 'LicenseRef-scancode-scansoft-1.2'], ['scea-1.0', 'SCEA'], - ['sendmail-8.23', 'Sendmail-8.23'], + ['schemereport', 'SchemeReport'], + ['scilab-en-2005', 'LicenseRef-scancode-scilab-en'], + ['scilab-fr', 'LicenseRef-scancode-scilab-fr'], + ['scintilla', 'LicenseRef-scancode-scintilla'], + ['scola-en', 'LicenseRef-scancode-scola-en'], + ['scola-fr', 'LicenseRef-scancode-scola-fr'], + ['scribbles', 'LicenseRef-scancode-scribbles'], + ['script-asylum', 'LicenseRef-scancode-script-asylum'], + ['script-nikhilk', 'LicenseRef-scancode-script-nikhilk'], + ['scrub', 'LicenseRef-scancode-scrub'], + ['scsl-3.0', 'LicenseRef-scancode-scsl-3.0'], + ['secret-labs-2011', 'LicenseRef-scancode-secret-labs-2011'], + ['see-license', 'null'], + ['selinux-nsa-declaration-1.0', 'libselinux-1.0'], + ['semgrep-registry', 'LicenseRef-scancode-semgrep-registry'], + ['sencha-app-floss-exception', 'LicenseRef-scancode-sencha-app-floss-exception'], + ['sencha-commercial', 'LicenseRef-scancode-sencha-commercial'], + ['sencha-commercial-3.17', 'LicenseRef-scancode-sencha-commercial-3.17'], + ['sencha-commercial-3.9', 'LicenseRef-scancode-sencha-commercial-3.9'], + ['sencha-dev-floss-exception', 'LicenseRef-scancode-sencha-dev-floss-exception'], ['sendmail', 'Sendmail'], + ['sendmail-8.23', 'Sendmail-8.23'], + ['service-comp-arch', 'LicenseRef-scancode-service-comp-arch'], ['sfl-license', 'iMatix'], + ['sgi-cid-1.0', 'LicenseRef-scancode-sgi-cid-1.0'], ['sgi-freeb-1.1', 'SGI-B-1.1'], ['sgi-freeb-2.0', 'SGI-B-2.0'], ['sgi-fslb-1.0', 'SGI-B-1.0'], + ['sgi-glx-1.0', 'LicenseRef-scancode-sgi-glx-1.0'], + ['sglib', 'LicenseRef-scancode-sglib'], + ['sgp4', 'SGP4'], + ['sh-cla-1.1', 'LicenseRef-scancode-sh-cla-1.1'], + ['shavlik-eula', 'LicenseRef-scancode-shavlik-eula'], + ['shital-shah', 'LicenseRef-scancode-shital-shah'], + ['shl-0.5', 'SHL-0.5'], + ['shl-0.51', 'SHL-0.51'], + ['shl-2.0', 'SHL-2.0'], + ['shl-2.1', 'SHL-2.1'], + ['signal-gpl-3.0-exception', 'LicenseRef-scancode-signal-gpl-3.0-exception'], + ['silicon-image-2007', 'LicenseRef-scancode-silicon-image-2007'], + ['simpl-1.1', 'LicenseRef-scancode-simpl-1.1'], ['simpl-2.0', 'SimPL-2.0'], + ['six-labors-split-1.0', 'LicenseRef-scancode-six-labors-split-1.0'], + ['skip-2014', 'LicenseRef-scancode-skip-2014'], + ['sl', 'SL'], ['sleepycat', 'Sleepycat'], - ['snia', 'SNIA'], + ['slf4j-2005', 'null'], + ['slf4j-2008', 'null'], + ['slint-commercial-2.0', 'LicenseRef-scancode-slint-commercial-2.0'], + ['slint-royalty-free-1.0', 'LicenseRef-scancode-slint-royalty-free-1.0'], + ['slysoft-eula', 'LicenseRef-scancode-slysoft-eula'], + ['smail-gpl', 'LicenseRef-scancode-smail-gpl'], + ['smartlabs-freeware', 'LicenseRef-scancode-smartlabs-freeware'], ['smppl', 'SMPPL'], + ['smsc-non-commercial-2012', 'LicenseRef-scancode-smsc-non-commercial-2012'], + ['snapeda-design-exception-1.0', 'LicenseRef-scancode-snapeda-design-exception-1.0'], + ['snia', 'SNIA'], + ['snmp4j-smi', 'LicenseRef-scancode-snmp4j-smi'], + ['snprintf', 'snprintf'], + ['softerra-ldap-browser-eula', 'LicenseRef-scancode-softerra-ldap-browser-eula'], + ['softfloat', 'LicenseRef-scancode-softfloat'], + ['softfloat-2.0', 'LicenseRef-scancode-softfloat-2.0'], + ['softfloat-2c', 'LicenseRef-scancode-softfloat-2c'], + ['softsurfer', 'softSurfer'], + ['solace-software-eula-2020', 'LicenseRef-scancode-solace-software-eula-2020'], + ['soundex', 'Soundex'], + ['sourcegraph-enterprise-2018', 'LicenseRef-scancode-sourcegraph-enterprise-2018'], + ['spark-jive', 'LicenseRef-scancode-spark-jive'], + ['sparky', 'LicenseRef-scancode-sparky'], + ['speechworks-1.1', 'LicenseRef-scancode-speechworks-1.1'], + ['spell-checker-exception-lgpl-2.1-plus', 'LicenseRef-scancode-spell-exception-lgpl-2.1-plus'], ['spl-1.0', 'SPL-1.0'], + ['splunk-3pp-eula', 'LicenseRef-scancode-splunk-3pp-eula'], + ['splunk-mint-tos-2018', 'LicenseRef-scancode-splunk-mint-tos-2018'], + ['splunk-sla', 'LicenseRef-scancode-splunk-sla'], + ['square-cla', 'LicenseRef-scancode-square-cla'], + ['squeak', 'LicenseRef-scancode-squeak'], + ['srgb', 'LicenseRef-scancode-srgb'], + ['ssh-keyscan', 'ssh-keyscan'], + ['ssleay', 'LicenseRef-scancode-ssleay'], + ['ssleay-windows', 'SSLeay-standalone'], + ['st-bsd-restricted', 'LicenseRef-scancode-st-bsd-restricted'], + ['st-mcd-2.0', 'LicenseRef-scancode-st-mcd-2.0'], + ['stable-diffusion-2022-08-22', 'LicenseRef-scancode-stable-diffusion-2022-08-22'], ['standard-ml-nj', 'SMLNJ'], + ['stanford-mrouted', 'LicenseRef-scancode-stanford-mrouted'], + ['stanford-pvrg', 'LicenseRef-scancode-stanford-pvrg'], + ['statewizard', 'LicenseRef-scancode-statewizard'], + ['stax', 'LicenseRef-scancode-stax'], + ['stlport-2000', 'LicenseRef-scancode-stlport-2000'], + ['stlport-4.5', 'LicenseRef-scancode-stlport-4.5'], + ['stmicroelectronics-centrallabs', 'LicenseRef-scancode-stmicroelectronics-centrallabs'], + ['stmicroelectronics-linux-firmware', 'LicenseRef-scancode-stmicro-linux-firmware'], + ['stream-benchmark', 'LicenseRef-scancode-stream-benchmark'], + ['strongswan-exception', 'LicenseRef-scancode-strongswan-exception'], + ['stu-nicholls', 'LicenseRef-scancode-stu-nicholls'], + ['stunnel-exception', 'stunnel-exception'], + ['subcommander-exception-2.0-plus', 'LicenseRef-scancode-subcommander-exception-2.0plus'], ['sugarcrm-1.1.3', 'SugarCRM-1.1.3'], + ['sun-bcl-11-06', 'LicenseRef-scancode-sun-bcl-11-06'], + ['sun-bcl-11-07', 'LicenseRef-scancode-sun-bcl-11-07'], + ['sun-bcl-11-08', 'LicenseRef-scancode-sun-bcl-11-08'], + ['sun-bcl-j2re-1.2.x', 'LicenseRef-scancode-sun-bcl-j2re-1.2.x'], + ['sun-bcl-j2re-1.4.2', 'LicenseRef-scancode-sun-bcl-j2re-1.4.2'], + ['sun-bcl-j2re-1.4.x', 'LicenseRef-scancode-sun-bcl-j2re-1.4.x'], + ['sun-bcl-j2re-5.0', 'LicenseRef-scancode-sun-bcl-j2re-5.0'], + ['sun-bcl-java-servlet-imp-2.1.1', 'LicenseRef-scancode-sun-bcl-java-servlet-imp-2.1.1'], + ['sun-bcl-javahelp', 'LicenseRef-scancode-sun-bcl-javahelp'], + ['sun-bcl-jimi-sdk', 'LicenseRef-scancode-sun-bcl-jimi-sdk'], + ['sun-bcl-jre6', 'LicenseRef-scancode-sun-bcl-jre6'], + ['sun-bcl-jsmq', 'LicenseRef-scancode-sun-bcl-jsmq'], + ['sun-bcl-opendmk', 'LicenseRef-scancode-sun-bcl-opendmk'], + ['sun-bcl-openjdk', 'LicenseRef-scancode-sun-bcl-openjdk'], + ['sun-bcl-sdk-1.3', 'LicenseRef-scancode-sun-bcl-sdk-1.3'], + ['sun-bcl-sdk-1.4.2', 'LicenseRef-scancode-sun-bcl-sdk-1.4.2'], + ['sun-bcl-sdk-5.0', 'LicenseRef-scancode-sun-bcl-sdk-5.0'], + ['sun-bcl-sdk-6.0', 'LicenseRef-scancode-sun-bcl-sdk-6.0'], + ['sun-bcl-web-start', 'LicenseRef-scancode-sun-bcl-web-start'], + ['sun-bsd-extra', 'LicenseRef-scancode-sun-bsd-extra'], ['sun-bsd-no-nuclear', 'BSD-3-Clause-No-Nuclear-License'], + ['sun-cc-pp-1.0', 'LicenseRef-scancode-sun-cc-pp-1.0'], + ['sun-communications-api', 'LicenseRef-scancode-sun-communications-api'], + ['sun-ejb-spec-2.1', 'LicenseRef-scancode-sun-ejb-spec-2.1'], + ['sun-ejb-spec-3.0', 'LicenseRef-scancode-sun-ejb-spec-3.0'], + ['sun-entitlement-03-15', 'LicenseRef-scancode-sun-entitlement-03-15'], + ['sun-entitlement-jaf', 'LicenseRef-scancode-sun-entitlement-jaf'], + ['sun-glassfish', 'LicenseRef-scancode-sun-glassfish'], + ['sun-iiop', 'LicenseRef-scancode-sun-iiop'], + ['sun-java-transaction-api', 'LicenseRef-scancode-sun-java-transaction-api'], + ['sun-java-web-services-dev-pack-1.6', 'LicenseRef-scancode-sun-java-web-services-dev-1.6'], + ['sun-javamail', 'LicenseRef-scancode-sun-javamail'], + ['sun-jsr-spec-04-2006', 'LicenseRef-scancode-sun-jsr-spec-04-2006'], + ['sun-jta-spec-1.0.1', 'LicenseRef-scancode-sun-jta-spec-1.0.1'], + ['sun-jta-spec-1.0.1b', 'LicenseRef-scancode-sun-jta-spec-1.0.1b'], + ['sun-no-high-risk-activities', 'LicenseRef-scancode-sun-no-high-risk-activities'], + ['sun-ppp', 'Sun-PPP'], + ['sun-project-x', 'LicenseRef-scancode-sun-project-x'], + ['sun-prop-non-commercial', 'LicenseRef-scancode-sun-prop-non-commercial'], + ['sun-proprietary-jdk', 'null'], + ['sun-rpc', 'LicenseRef-scancode-sun-rpc'], + ['sun-sdk-spec-1.1', 'LicenseRef-scancode-sun-sdk-spec-1.1'], + ['sun-sissl-1.0', 'LicenseRef-scancode-sun-sissl-1.0'], ['sun-sissl-1.1', 'SISSL'], ['sun-sissl-1.2', 'SISSL-1.2'], - ['sybase', 'Watcom-1.0'], + ['sun-source', 'LicenseRef-scancode-sun-source'], + ['sun-ssscfr-1.1', 'LicenseRef-scancode-sun-ssscfr-1.1'], + ['sunpro', 'SunPro'], + ['sunsoft', 'LicenseRef-scancode-sunsoft'], + ['supervisor', 'LicenseRef-scancode-supervisor'], + ['sustainable-use-1.0', 'LicenseRef-scancode-sustainable-use-1.0'], + ['svndiff', 'LicenseRef-scancode-svndiff'], + ['swi-exception', 'SWI-exception'], + ['swig', 'LicenseRef-scancode-swig'], ['swl', 'SWL'], + ['swrule', 'swrule'], + ['sybase', 'Watcom-1.0'], + ['symlinks', 'Symlinks'], + ['symphonysoft', 'LicenseRef-scancode-symphonysoft'], + ['synopsys-attribution', 'LicenseRef-scancode-synopsys-attribution'], + ['synopsys-mit', 'LicenseRef-scancode-synopsys-mit'], + ['syntext-serna-exception-1.0', 'LicenseRef-scancode-syntext-serna-exception-1.0'], + ['synthesis-toolkit', 'LicenseRef-scancode-synthesis-toolkit'], + ['t-engine-public', 'LicenseRef-scancode-t-engine-public'], + ['t-license-1.0', 'LicenseRef-scancode-t-license-1.0'], + ['t-license-2.0', 'LicenseRef-scancode-t-license-2.0'], + ['t-license-2.1', 'LicenseRef-scancode-t-license-2.1'], + ['t-license-2.2', 'LicenseRef-scancode-t-license-2.2'], + ['t-license-amp-t-kernel', 'LicenseRef-scancode-t-license-amp-t-kernel'], + ['t-license-amp-tkse', 'LicenseRef-scancode-t-license-amp-tkse'], + ['t-license-smp-t-kernel', 'LicenseRef-scancode-t-license-smp-t-kernel'], + ['t-license-smp-tkse', 'LicenseRef-scancode-t-license-smp-tkse'], + ['t-license-tkse', 'LicenseRef-scancode-t-license-tkse'], + ['takao-abe', 'LicenseRef-scancode-takao-abe'], + ['takuya-ooura', 'LicenseRef-scancode-takuya-ooura'], + ['taligent-jdk', 'LicenseRef-scancode-taligent-jdk'], + ['tanuki-community-sla-1.0', 'LicenseRef-scancode-tanuki-community-sla-1.0'], + ['tanuki-community-sla-1.1', 'LicenseRef-scancode-tanuki-community-sla-1.1'], + ['tanuki-community-sla-1.2', 'LicenseRef-scancode-tanuki-community-sla-1.2'], + ['tanuki-community-sla-1.3', 'LicenseRef-scancode-tanuki-community-sla-1.3'], + ['tanuki-development', 'LicenseRef-scancode-tanuki-development'], + ['tanuki-maintenance', 'LicenseRef-scancode-tanuki-maintenance'], + ['tapr-ohl-1.0', 'TAPR-OHL-1.0'], + ['tatu-ylonen', 'SSH-short'], + ['tcg-spec-license-v1', 'LicenseRef-scancode-tcg-spec-license-v1'], ['tcl', 'TCL'], ['tcp-wrappers', 'TCP-wrappers'], + ['teamdev-services', 'LicenseRef-scancode-teamdev-services'], + ['tekhvc', 'LicenseRef-scancode-tekhvc'], + ['telerik-eula', 'LicenseRef-scancode-telerik-eula'], + ['tenable-nessus', 'LicenseRef-scancode-tenable-nessus'], + ['term-readkey', 'TermReadKey'], + ['tested-software', 'LicenseRef-scancode-tested-software'], + ['tex-exception', 'Texinfo-exception'], + ['tex-live', 'LicenseRef-scancode-tex-live'], + ['tfl', 'LicenseRef-scancode-tfl'], + ['tgc-spec-license-v2', 'LicenseRef-scancode-tcg-spec-license-v2'], + ['tgppl-1.0', 'TGPPL-1.0'], + ['the-stack-tos-2023-07', 'LicenseRef-scancode-the-stack-tos-2023-07'], + ['things-i-made-public-license', 'LicenseRef-scancode-things-i-made-public-license'], + ['thomas-bandt', 'LicenseRef-scancode-thomas-bandt'], + ['thor-pl', 'TPL-1.0'], + ['ti-broadband-apps', 'LicenseRef-scancode-ti-broadband-apps'], + ['ti-linux-firmware', 'LicenseRef-scancode-ti-linux-firmware'], + ['ti-restricted', 'LicenseRef-scancode-ti-restricted'], + ['tidy', 'HTMLTIDY'], + ['tiger-crypto', 'LicenseRef-scancode-tiger-crypto'], + ['tigra-calendar-3.2', 'LicenseRef-scancode-tigra-calendar-3.2'], + ['tigra-calendar-4.0', 'LicenseRef-scancode-tigra-calendar-4.0'], + ['tim-janik-2003', 'LicenseRef-scancode-tim-janik-2003'], + ['timestamp-picker', 'LicenseRef-scancode-timestamp-picker'], + ['tizen-sdk', 'LicenseRef-scancode-tizen-sdk'], ['tmate', 'TMate'], + ['toppers-educational', 'LicenseRef-scancode-toppers-educational'], + ['toppers-license', 'LicenseRef-scancode-toppers-license'], ['torque-1.1', 'TORQUE-1.1'], ['tosl', 'TOSL'], + ['tpdl', 'TPDL'], + ['tpl-1.0', 'LicenseRef-scancode-tpl-1.0'], + ['tpl-2.0', 'LicenseRef-scancode-tpl-2.0'], + ['trademark-notice', 'null'], + ['trca-odl-1.0', 'LicenseRef-scancode-trca-odl-1.0'], + ['treeview-developer', 'LicenseRef-scancode-treeview-developer'], + ['treeview-distributor', 'LicenseRef-scancode-treeview-distributor'], + ['triptracker', 'LicenseRef-scancode-triptracker'], + ['trolltech-gpl-exception-1.0', 'LicenseRef-scancode-trolltech-gpl-exception-1.0'], + ['trolltech-gpl-exception-1.1', 'LicenseRef-scancode-trolltech-gpl-exception-1.1'], + ['trolltech-gpl-exception-1.2', 'LicenseRef-scancode-trolltech-gpl-exception-1.2'], + ['truecrypt-3.1', 'LicenseRef-scancode-truecrypt-3.1'], + ['trustonic-proprietary-2013', 'LicenseRef-scancode-trustonic-proprietary-2013'], + ['tsl-2018', 'LicenseRef-scancode-tsl-2018'], + ['tsl-2020', 'LicenseRef-scancode-tsl-2020'], + ['tso-license', 'LicenseRef-scancode-tso-license'], + ['ttcl', 'LicenseRef-scancode-ttcl'], + ['ttf2pt1', 'null'], + ['ttwl', 'TTWL'], + ['ttyp0', 'TTYP0'], + ['tu-berlin', 'TU-Berlin-1.0'], ['tu-berlin-2.0', 'TU-Berlin-2.0'], + ['tumbolia', 'LicenseRef-scancode-tumbolia'], + ['twisted-snmp', 'LicenseRef-scancode-twisted-snmp'], + ['txl-10.5', 'LicenseRef-scancode-txl-10.5'], ['u-boot-exception-2.0', 'u-boot-exception-2.0'], - ['tu-berlin', 'TU-Berlin-1.0'], + ['ubc', 'LicenseRef-scancode-ubc'], + ['ubdl', 'UBDL-exception'], + ['ubuntu-font-1.0', 'LicenseRef-scancode-ubuntu-font-1.0'], + ['ucar', 'UCAR'], + ['ucl-1.0', 'UCL-1.0'], + ['ugui', 'LicenseRef-scancode-ugui'], + ['ulem', 'ulem'], + ['umich-merit', 'UMich-Merit'], + ['unbuntu-font-1.0', 'null'], + ['unicode', 'LicenseRef-scancode-unicode'], + ['unicode-data-software', 'null'], + ['unicode-dfs-2015', 'Unicode-DFS-2015'], ['unicode-dfs-2016', 'Unicode-DFS-2016'], + ['unicode-icu-58', 'LicenseRef-scancode-unicode-icu-58'], + ['unicode-mappings', 'LicenseRef-scancode-unicode-mappings'], ['unicode-tou', 'Unicode-TOU'], - ['unicode-dfs-2015', 'Unicode-DFS-2015'], + ['unicode-v3', 'Unicode-3.0'], + ['universal-foss-exception-1.0', 'Universal-FOSS-exception-1.0'], + ['unixcrypt', 'UnixCrypt'], + ['unknown', 'LicenseRef-scancode-unknown'], + ['unknown-license-reference', 'LicenseRef-scancode-unknown-license-reference'], + ['unknown-spdx', 'LicenseRef-scancode-unknown-spdx'], ['unlicense', 'Unlicense'], + ['unlimited-binary-linking', 'LicenseRef-scancode-unlimited-binary-linking'], + ['unlimited-binary-use-exception', 'LicenseRef-scancode-unlimited-binary-use-exception'], + ['unlimited-linking-exception-gpl', 'LicenseRef-scancode-unlimited-link-exception-gpl'], + ['unlimited-linking-exception-lgpl', 'LicenseRef-scancode-unlimited-link-exception-lgpl'], + ['unpbook', 'LicenseRef-scancode-unpbook'], + ['unpublished-source', 'LicenseRef-scancode-unpublished-source'], + ['unrar', 'LicenseRef-scancode-unrar'], + ['unrar-v3', 'LicenseRef-scancode-unrar-v3'], + ['unsplash', 'LicenseRef-scancode-unsplash'], + ['uofu-rfpl', 'LicenseRef-scancode-uofu-rfpl'], ['uoi-ncsa', 'NCSA'], ['upl-1.0', 'UPL-1.0'], + ['upx-exception-2.0-plus', 'LicenseRef-scancode-upx-exception-2.0-plus'], + ['urt-rle', 'URT-RLE'], + ['us-govt-geotranform', 'LicenseRef-scancode-us-govt-geotranform'], + ['us-govt-public-domain', 'LicenseRef-scancode-us-govt-public-domain'], + ['us-govt-unlimited-rights', 'LicenseRef-scancode-us-govt-unlimited-rights'], + ['usrobotics-permissive', 'LicenseRef-scancode-usrobotics-permissive'], + ['utopia', 'LicenseRef-scancode-utopia'], + ['vaadin-cvdl-4.0', 'LicenseRef-scancode-vaadin-cvdl-4.0'], + ['vbaccelerator', 'LicenseRef-scancode-vbaccelerator'], + ['vcalendar', 'LicenseRef-scancode-vcalendar'], + ['vcvrack-exception-to-gpl-3.0', 'LicenseRef-scancode-vcvrack-exception-to-gpl-3.0'], + ['verbatim-manual', 'Linux-man-pages-copyleft'], + ['verisign', 'LicenseRef-scancode-verisign'], + ['vhfpl-1.1', 'LicenseRef-scancode-vhfpl-1.1'], + ['vic-metcalfe-pd', 'LicenseRef-scancode-vic-metcalfe-pd'], + ['vicomsoft-software', 'LicenseRef-scancode-vicomsoft-software'], + ['viewflow-agpl-3.0-exception', 'LicenseRef-scancode-viewflow-agpl-3.0-exception'], ['vim', 'Vim'], - ['vsl-1.0', 'VSL-1.0'], + ['vince', 'LicenseRef-scancode-vince'], + ['visual-idiot', 'LicenseRef-scancode-visual-idiot'], + ['visual-numerics', 'LicenseRef-scancode-visual-numerics'], + ['vita-nuova-liberal', 'LicenseRef-scancode-vita-nuova-liberal'], + ['vitesse-prop', 'LicenseRef-scancode-vitesse-prop'], + ['vixie-cron', 'LicenseRef-scancode-vixie-cron'], + ['vnc-viewer-ios', 'LicenseRef-scancode-vnc-viewer-ios'], + ['volatility-vsl-v1.0', 'LicenseRef-scancode-volatility-vsl-v1.0'], ['vostrom', 'VOSTROM'], + ['vpl-1.1', 'LicenseRef-scancode-vpl-1.1'], + ['vpl-1.2', 'LicenseRef-scancode-vpl-1.2'], + ['vs10x-code-map', 'LicenseRef-scancode-vs10x-code-map'], + ['vsftpd-openssl-exception', 'vsftpd-openssl-exception'], + ['vsl-1.0', 'VSL-1.0'], + ['vuforia-2013-07-29', 'LicenseRef-scancode-vuforia-2013-07-29'], + ['vvvvvv-scl-1.0', 'LicenseRef-scancode-vvvvvv-scl-1.0'], ['w3c', 'W3C'], + ['w3c-03-bsd-license', 'LicenseRef-scancode-w3c-03-bsd-license'], + ['w3c-community-cla', 'LicenseRef-scancode-w3c-community-cla'], + ['w3c-docs-19990405', 'LicenseRef-scancode-w3c-docs-19990405'], + ['w3c-docs-20021231', 'LicenseRef-scancode-w3c-docs-20021231'], + ['w3c-documentation', 'LicenseRef-scancode-w3c-documentation'], ['w3c-software-19980720', 'W3C-19980720'], + ['w3c-software-20021231', 'null'], + ['w3c-software-2023', 'LicenseRef-scancode-w3c-software-2023'], ['w3c-software-doc-20150513', 'W3C-20150513'], + ['w3c-test-suite', 'LicenseRef-scancode-w3c-test-suite'], + ['w3m', 'w3m'], + ['warranty-disclaimer', 'LicenseRef-scancode-warranty-disclaimer'], + ['waterfall-feed-parser', 'LicenseRef-scancode-waterfall-feed-parser'], + ['westhawk', 'LicenseRef-scancode-westhawk'], + ['whistle', 'LicenseRef-scancode-whistle'], + ['whitecat', 'LicenseRef-scancode-whitecat'], + ['wide-license', 'LicenseRef-scancode-wide-license'], + ['widget-workshop', 'Widget-Workshop'], + ['wifi-alliance', 'LicenseRef-scancode-wifi-alliance'], + ['william-alexander', 'LicenseRef-scancode-william-alexander'], + ['wince-50-shared-source', 'LicenseRef-scancode-wince-50-shared-source'], + ['windriver-commercial', 'LicenseRef-scancode-windriver-commercial'], + ['wingo', 'LicenseRef-scancode-wingo'], + ['wink', 'LicenseRef-scancode-wink'], + ['winzip-eula', 'LicenseRef-scancode-winzip-eula'], + ['winzip-self-extractor', 'LicenseRef-scancode-winzip-self-extractor'], + ['wol', 'LicenseRef-scancode-wol'], + ['woodruff-2002', 'LicenseRef-scancode-woodruff-2002'], + ['wordnet', 'LicenseRef-scancode-wordnet'], + ['wrox', 'LicenseRef-scancode-wrox'], + ['wrox-download', 'LicenseRef-scancode-wrox-download'], + ['ws-addressing-spec', 'LicenseRef-scancode-ws-addressing-spec'], + ['ws-policy-specification', 'LicenseRef-scancode-ws-policy-specification'], + ['ws-trust-specification', 'LicenseRef-scancode-ws-trust-specification'], ['wsuipa', 'Wsuipa'], + ['wtfnmfpl-1.0', 'LicenseRef-scancode-wtfnmfpl-1.0'], + ['wtfpl-1.0', 'LicenseRef-scancode-wtfpl-1.0'], ['wtfpl-2.0', 'WTFPL'], - ['wxwindows-exception-3.1', 'WxWindows-exception-3.1'], + ['wthpl-1.0', 'LicenseRef-scancode-wthpl-1.0'], + ['wxwidgets', 'LicenseRef-scancode-wxwidgets'], ['wxwindows', 'wxWindows'], + ['wxwindows-exception-3.1', 'WxWindows-exception-3.1'], + ['wxwindows-r-3.0', 'LicenseRef-scancode-wxwindows-r-3.0'], + ['wxwindows-u-3.0', 'LicenseRef-scancode-wxwindows-u-3.0'], ['x11', 'ICU'], - ['x11-xconsortium', 'X11'], + ['x11-acer', 'LicenseRef-scancode-x11-acer'], + ['x11-adobe', 'Adobe-Display-PostScript'], + ['x11-adobe-dec', 'LicenseRef-scancode-x11-adobe-dec'], + ['x11-bitstream', 'Bitstream-Charter'], + ['x11-dec1', 'LicenseRef-scancode-x11-dec1'], + ['x11-dec2', 'HPND-DEC'], + ['x11-doc', 'LicenseRef-scancode-x11-doc'], + ['x11-dsc', 'LicenseRef-scancode-x11-dsc'], + ['x11-fsf', 'X11-distribute-modifications-variant'], + ['x11-hanson', 'LicenseRef-scancode-x11-hanson'], + ['x11-ibm', 'LicenseRef-scancode-x11-ibm'], + ['x11-keith-packard', 'HPND-sell-variant'], + ['x11-lucent', 'dtoa'], + ['x11-lucent-variant', 'LicenseRef-scancode-x11-lucent-variant'], + ['x11-oar', 'LicenseRef-scancode-x11-oar'], + ['x11-opengl', 'SGI-OpenGL'], + ['x11-opengroup', 'MIT-open-group'], + ['x11-quarterdeck', 'LicenseRef-scancode-x11-quarterdeck'], + ['x11-r75', 'null'], + ['x11-realmode', 'LicenseRef-scancode-x11-realmode'], + ['x11-sg', 'LicenseRef-scancode-x11-sg'], + ['x11-stanford', 'LicenseRef-scancode-x11-stanford'], + ['x11-tektronix', 'LicenseRef-scancode-x11-tektronix'], ['x11-tiff', 'libtiff'], + ['x11-x11r5', 'LicenseRef-scancode-x11-x11r5'], + ['x11-xconsortium', 'X11'], + ['x11-xconsortium-veillard', 'LicenseRef-scancode-x11-xconsortium-veillard'], + ['x11-xconsortium_veillard', 'null'], + ['x11r5-authors', 'null'], + ['xceed-community-2021', 'LicenseRef-scancode-xceed-community-2021'], + ['xdebug-1.03', 'Xdebug-1.03'], + ['xenomai-gpl-exception', 'LicenseRef-scancode-xenomai-gpl-exception'], + ['xfree86-1.0', 'LicenseRef-scancode-xfree86-1.0'], ['xfree86-1.1', 'XFree86-1.1'], + ['xilinx-2016', 'LicenseRef-scancode-xilinx-2016'], ['xinetd', 'xinetd'], - ['xskat', 'XSkat'], + ['xiph-patent', 'LicenseRef-scancode-xiph-patent'], + ['xkeyboard-config-zinoviev', 'xkeyboard-config-Zinoviev'], + ['xming', 'LicenseRef-scancode-xming'], + ['xmldb-1.0', 'LicenseRef-scancode-xmldb-1.0'], ['xnet', 'Xnet'], + ['xskat', 'XSkat'], + ['xxd', 'LicenseRef-scancode-xxd'], + ['yahoo-browserplus-eula', 'LicenseRef-scancode-yahoo-browserplus-eula'], + ['yahoo-messenger-eula', 'LicenseRef-scancode-yahoo-messenger-eula'], + ['yale-cas', 'LicenseRef-scancode-yale-cas'], + ['yensdesign', 'LicenseRef-scancode-yensdesign'], + ['yolo-1.0', 'LicenseRef-scancode-yolo-1.0'], + ['yolo-2.0', 'LicenseRef-scancode-yolo-2.0'], ['ypl-1.0', 'YPL-1.0'], - ['zed', 'Zed'], ['ypl-1.1', 'YPL-1.1'], + ['zapatec-calendar', 'LicenseRef-scancode-zapatec-calendar'], + ['zed', 'Zed'], + ['zeeff', 'Zeeff'], ['zend-2.0', 'Zend-2.0'], + ['zendesk-appdev-api-2022', 'LicenseRef-scancode-zendesk-appdev-api-2022'], + ['zeromq-exception-lgpl-3.0', 'LicenseRef-scancode-zeromq-exception-lgpl-3.0'], + ['zeusbench', 'LicenseRef-scancode-zeusbench'], + ['zhorn-stickies', 'LicenseRef-scancode-zhorn-stickies'], ['zimbra-1.3', 'Zimbra-1.3'], ['zimbra-1.4', 'Zimbra-1.4'], - ['zlib-acknowledgement', 'zlib-acknowledgement'], + ['zipeg', 'LicenseRef-scancode-zipeg'], + ['ziplist5-geocode-duplication-addendum', 'LicenseRef-scancode-ziplist5-geocode-dup-addendum'], + ['ziplist5-geocode-end-user-enterprise', 'LicenseRef-scancode-ziplist5-geocode-enterprise'], + ['ziplist5-geocode-end-user-workstation', 'LicenseRef-scancode-ziplist5-geocode-workstation'], ['zlib', 'Zlib'], - ['zpl-2.0', 'ZPL-2.0'], + ['zlib-acknowledgement', 'zlib-acknowledgement'], + ['zpl-1.0', 'LicenseRef-scancode-zpl-1.0'], ['zpl-1.1', 'ZPL-1.1'], + ['zpl-2.0', 'ZPL-2.0'], ['zpl-2.1', 'ZPL-2.1'], - ['google-patent-license-golang', 'OTHER'] + ['zrythm-exception-agpl-3.0', 'LicenseRef-scancode-zrythm-exception-agpl-3.0'], + ['zsh', 'LicenseRef-scancode-zsh'], + ['zuora-software', 'LicenseRef-scancode-zuora-software'], + ['zveno-research', 'LicenseRef-scancode-zveno-research'] ]) diff --git a/lib/utils.js b/lib/utils.js index 4c95404d0..1a6ba5c72 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -11,7 +11,6 @@ const extend = require('extend') const SPDX = require('@clearlydefined/spdx') const coordinatesMapper = require('./coordinatesMapper')() - async function toResultCoordinatesFromRequest(request) { const coordinates = await toNormalizedEntityCoordinates(request.params) return new ResultCoordinates( @@ -137,7 +136,7 @@ function extractDate(dateAndTime) { } function compareDates(dateA, dateB) { - if (!dateA || !dateB) return dateA ? 1 : (dateB ? -1 : 0) + if (!dateA || !dateB) return dateA ? 1 : dateB ? -1 : 0 return DateTime.fromISO(dateA).toJSDate() - DateTime.fromISO(dateB).toJSDate() } @@ -207,11 +206,31 @@ function _mergeFile(base, proposed, override) { if (!base) return proposed const result = _mergeExcept(base, proposed, ['license', 'attributions', 'facets', 'hashes', 'natures']) const overrideStrategy = override ? proposed => proposed : (proposed, mergeStrategy) => mergeStrategy(proposed) - setIfValue(result, 'license', overrideStrategy(proposed.license, p => SPDX.merge(p, base.license, 'AND'))) - setIfValue(result, 'attributions', overrideStrategy(proposed.attributions, p => _mergeArray(base.attributions, p))) - setIfValue(result, 'facets', overrideStrategy(proposed.facets, p => _mergeArray(base.facets, p))) - setIfValue(result, 'hashes', overrideStrategy(proposed.hashes, p => _mergeObject(base.hashes, p))) - setIfValue(result, 'natures', overrideStrategy(proposed.natures, p => _mergeArray(base.natures, p))) + setIfValue( + result, + 'license', + overrideStrategy(proposed.license, p => SPDX.merge(p, base.license, 'AND')) + ) + setIfValue( + result, + 'attributions', + overrideStrategy(proposed.attributions, p => _mergeArray(base.attributions, p)) + ) + setIfValue( + result, + 'facets', + overrideStrategy(proposed.facets, p => _mergeArray(base.facets, p)) + ) + setIfValue( + result, + 'hashes', + overrideStrategy(proposed.hashes, p => _mergeObject(base.hashes, p)) + ) + setIfValue( + result, + 'natures', + overrideStrategy(proposed.natures, p => _mergeArray(base.natures, p)) + ) return result } @@ -284,7 +303,7 @@ function buildSourceUrl(spec) { } function deCodeSlashes(namespace) { - return `${namespace.replace(/%2f/ig, '/')}` + return `${namespace.replace(/%2f/gi, '/')}` } // migrate the format of the source location to the current norm diff --git a/middleware/github.js b/middleware/github.js index 9493c358e..bbfa79490 100644 --- a/middleware/github.js +++ b/middleware/github.js @@ -108,7 +108,7 @@ async function getTeams(client, org) { if (err.code === 404) { console.error( 'GitHub returned a 404 when trying to read team data. ' + - 'You probably need to re-configure your CURATION_GITHUB_TOKEN token with the `read:org` scope. (This only affects local development.)' + 'You probably need to re-configure your CURATION_GITHUB_TOKEN token with the `read:org` scope. (This only affects local development.)' ) } else if (err.code === 401 && err.message === 'Bad credentials') { // the token was bad. trickle up the problem so the user can fix @@ -123,10 +123,7 @@ async function getTeams(client, org) { } async function getCacheKey(prefix, token) { - const hashedToken = await crypto - .createHash('sha256') - .update(token) - .digest('hex') + const hashedToken = await crypto.createHash('sha256').update(token).digest('hex') return `${prefix}.${hashedToken}` } diff --git a/minimal.env.json b/minimal.env.json index 8f7daa935..9f6916c91 100644 --- a/minimal.env.json +++ b/minimal.env.json @@ -2,6 +2,10 @@ "========== Service Harvest settings ==========": "", "FILE_STORE_LOCATION": "< path to cloned harvested-data repo, other local store location, or omit for default >", + "========== Service Webhooks settings ==========": "", + "WEBHOOK_CRAWLER_SECRET": "", + "WEBHOOK_GITHUB_SECRET": "", + "========== Service Curation settings ==========": "", "CURATION_GITHUB_REPO": "sample-curated-data", "CURATION_GITHUB_TOKEN": "" diff --git a/package-lock.json b/package-lock.json index 39e8ff598..2ae2b5c2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "service", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "service", - "version": "1.2.0", + "version": "1.3.0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -71,17 +71,28 @@ "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "deep-equal-in-any-order": "^1.0.10", - "eslint": "^7.5", + "eslint": "8.56.0", + "eslint-config-prettier": "9.1.0", "mocha": "^8.2.1", "mongodb-memory-server": "^8.11.2", "node-mocks-http": "^1.6.7", "nodemon": "^2.0.3", "nyc": "^15.0.0", + "prettier": "3.2.5", "proxyquire": "^2.0.1", "sinon": "^5.0.0", "typescript": "5.0.4" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@aws-crypto/ie11-detection": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", @@ -1611,46 +1622,63 @@ "spdx-satisfies": "github:clearlydefined/spdx-satisfies.js#parse-override" } }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", - "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1665,9 +1693,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -1679,6 +1707,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/eslintrc/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1709,6 +1761,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@gitbeaker/core": { "version": "29.2.4", "resolved": "https://registry.npmjs.org/@gitbeaker/core/-/core-29.2.4.tgz", @@ -1946,23 +2007,23 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", - "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.0", - "debug": "^4.1.1", - "minimatch": "^3.0.4" + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, "node_modules/@humanwhocodes/config-array/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1976,16 +2037,41 @@ } } }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/config-array/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -2070,6 +2156,41 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@octokit/rest": { "version": "14.0.9", "resolved": "http://registry.npmjs.org/@octokit/rest/-/rest-14.0.9.tgz", @@ -2312,6 +2433,12 @@ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -2344,9 +2471,9 @@ } }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2413,9 +2540,9 @@ } }, "node_modules/ajv": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", - "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2642,15 +2769,6 @@ "node": ">=0.10.0" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/async": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz", @@ -4165,18 +4283,6 @@ "once": "^1.4.0" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/err-code": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", @@ -4222,106 +4328,98 @@ } }, "node_modules/eslint": { - "version": "7.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", - "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.3", - "@humanwhocodes/config-array": "^0.5.0", - "ajv": "^6.10.0", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", - "enquirer": "^2.3.5", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, - "engines": { - "node": ">=8.0.0" + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ansi-styles": { @@ -4339,6 +4437,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -4402,10 +4506,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/eslint/node_modules/globals": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", - "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4417,25 +4549,79 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "node_modules/eslint/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "yocto-queue": "^0.1.0" }, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint/node_modules/strip-ansi": { @@ -4450,18 +4636,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -4475,26 +4649,20 @@ } }, "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -4510,9 +4678,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -4521,15 +4689,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -4542,7 +4701,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -4551,15 +4710,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -4957,7 +5107,7 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fast-xml-parser": { @@ -4977,6 +5127,15 @@ "url": "https://paypal.me/naturalintelligence" } }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -5485,6 +5644,12 @@ "node": ">=0.4.0" } }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -5890,9 +6055,9 @@ } }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -6111,9 +6276,9 @@ } }, "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" @@ -6185,9 +6350,9 @@ "dev": true }, "node_modules/is-path-inside": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", - "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "engines": { "node": ">=8" @@ -6686,12 +6851,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, "node_modules/log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", @@ -8138,17 +8297,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -8528,6 +8687,21 @@ "node": ">=4" } }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", @@ -8545,15 +8719,6 @@ "node": ">=8" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/promise-retry": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", @@ -8656,6 +8821,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -8857,18 +9042,6 @@ "node": ">=0.10.0" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/registry-auth-token": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz", @@ -9059,15 +9232,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -9128,6 +9292,16 @@ "node": "*" } }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -9139,6 +9313,29 @@ "rimraf": "bin.js" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -9420,65 +9617,6 @@ "node": ">=6" } }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/slice-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -10082,85 +10220,6 @@ "node": ">= v0.10.32" } }, - "node_modules/table": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", - "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz", - "integrity": "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/table/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/table/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/tar-stream": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", @@ -10800,12 +10859,6 @@ "uuid": "bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/validator": { "version": "9.4.1", "resolved": "http://registry.npmjs.org/validator/-/validator-9.4.1.tgz", @@ -10994,15 +11047,6 @@ "node": ">=0.1.90" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -11330,6 +11374,18 @@ "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 54702fd98..7b40795d4 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,16 @@ { "name": "service", - "version": "1.2.0", + "version": "1.3.0", "description": "Service side of clearlydefined.io.", "scripts": { - "test": "nyc mocha --exit \"test/**/*.js\" && eslint .", + "test": "npm run mocha && npm run lint", + "mocha": "nyc mocha --exit \"test/**/*.js\"", + "lint": "npm run prettier:check && npm run eslint", + "lint:fix": "npm run prettier:write && npm run eslint:fix", + "eslint": "eslint .", + "eslint:fix": "eslint . --fix", + "prettier:check": "prettier . --check", + "prettier:write": "prettier . --write", "dev": "nodemon ./bin/www", "start": "node ./bin/www", "postinstall": "patch-package" @@ -75,12 +82,14 @@ "chai": "^4.1.2", "chai-as-promised": "^7.1.1", "deep-equal-in-any-order": "^1.0.10", - "eslint": "^7.5", + "eslint": "8.56.0", + "eslint-config-prettier": "9.1.0", "mocha": "^8.2.1", "mongodb-memory-server": "^8.11.2", "node-mocks-http": "^1.6.7", "nodemon": "^2.0.3", "nyc": "^15.0.0", + "prettier": "3.2.5", "proxyquire": "^2.0.1", "sinon": "^5.0.0", "typescript": "5.0.4" diff --git a/providers/curation/github.js b/providers/curation/github.js index 8a7ff6390..29ef971be 100644 --- a/providers/curation/github.js +++ b/providers/curation/github.js @@ -1,7 +1,21 @@ // Copyright (c) Microsoft Corporation and others. Licensed under the MIT license. // SPDX-License-Identifier: MIT -const { concat, get, forIn, merge, isEqual, uniq, pick, flatten, flatMap, first, union, unset, uniqWith } = require('lodash') +const { + concat, + get, + forIn, + merge, + isEqual, + uniq, + pick, + flatten, + flatMap, + first, + union, + unset, + uniqWith +} = require('lodash') const { DateTime } = require('luxon') const geit = require('geit') const yaml = require('js-yaml') @@ -114,9 +128,7 @@ class GitHubCurationService { // Should also delete revision less coordinate curation cache toBeCleaned = uniqWith(toBeCleaned.concat(toBeCleaned.map(c => c.asRevisionless())), isEqual) await Promise.all( - toBeCleaned.map( - throat(10, async coordinates => this.cache.delete(this._getCacheKey(coordinates))) - ) + toBeCleaned.map(throat(10, async coordinates => this.cache.delete(this._getCacheKey(coordinates)))) ) if (data.merged_at) await this._prMerged(curations) } @@ -173,27 +185,29 @@ class GitHubCurationService { const harvest = await this.harvestStore.getAll(coordinates) const matches = [] - await Promise.all(otherCoordinatesList.map(async (otherCoordinates) => { - const otherDefinition = await this.definitionService.getStored(otherCoordinates) - const otherHarvest = await this.harvestStore.getAll(otherCoordinates) - const result = this.licenseMatcher.process( - { definition, harvest }, - { definition: otherDefinition, harvest: otherHarvest } - ) + await Promise.all( + otherCoordinatesList.map(async otherCoordinates => { + const otherDefinition = await this.definitionService.getStored(otherCoordinates) + const otherHarvest = await this.harvestStore.getAll(otherCoordinates) + const result = this.licenseMatcher.process( + { definition, harvest }, + { definition: otherDefinition, harvest: otherHarvest } + ) - if (result.isMatching) { - matches.push({ - version: otherCoordinates.revision, - matchingProperties: result.match.map(reason => { - if (reason.file) { - return { file: reason.file } - } else { - return { propPath: reason.propPath, value: reason.value } - } + if (result.isMatching) { + matches.push({ + version: otherCoordinates.revision, + matchingProperties: result.match.map(reason => { + if (reason.file) { + return { file: reason.file } + } else { + return { propPath: reason.propPath, value: reason.value } + } + }) }) - }) - } - })) + } + }) + ) return matches } @@ -221,13 +235,20 @@ class GitHubCurationService { const coordinatesList = await this.definitionService.list(revisionlessCoords) const filteredCoordinatesList = coordinatesList .map(stringCoords => EntityCoordinates.fromString(stringCoords)) - .filter(coords => coordinates.name === coords.name && coordinates.revision !== coords.revision && coords.revision !== 'undefined') + .filter( + coords => + coordinates.name === coords.name && + coordinates.revision !== coords.revision && + coords.revision !== 'undefined' + ) const matchingRevisionsAndReasons = await this._startMatching(coordinates, filteredCoordinatesList) const curations = await this.list(revisionlessCoords) const existingRevisions = this._getRevisionsFromCurations(curations) - const uncuratedMatchingRevisions = matchingRevisionsAndReasons.filter(versionAndReason => existingRevisions.indexOf(versionAndReason.version) == -1) + const uncuratedMatchingRevisions = matchingRevisionsAndReasons.filter( + versionAndReason => existingRevisions.indexOf(versionAndReason.version) == -1 + ) return uncuratedMatchingRevisions } @@ -242,12 +263,15 @@ class GitHubCurationService { filtered.push(revisionAndReason) } else { if (existingDeclaredLicense !== get(curation, 'licensed.declared')) { - this.logger.info('GitHubCurationService._filterRevisionWithDeclaredLicense.ExistingLicenseNotEqualToCuratedLicense', { - coordinates: coordinates.toString(), - revisionAndReason, - curation, - existingLicense: existingDeclaredLicense - }) + this.logger.info( + 'GitHubCurationService._filterRevisionWithDeclaredLicense.ExistingLicenseNotEqualToCuratedLicense', + { + coordinates: coordinates.toString(), + revisionAndReason, + curation, + existingLicense: existingDeclaredLicense + } + ) } } } @@ -339,7 +363,9 @@ class GitHubCurationService { const curationAndContributions = await this.list(revisionLessCoordinates) if (!this._canBeAutoCurated(definition, curationAndContributions)) { - this.logger.info('GitHubCurationService.autoCurate.notApplicable', { coordinates: definition.coordinates.toString() }) + this.logger.info('GitHubCurationService.autoCurate.notApplicable', { + coordinates: definition.coordinates.toString() + }) return } @@ -374,7 +400,10 @@ class GitHubCurationService { } const otherHarvest = await this.harvestStore.getAll(otherCoordinates) - const result = this.licenseMatcher.process({ definition, harvest }, { definition: otherDefinition, harvest: otherHarvest }) + const result = this.licenseMatcher.process( + { definition, harvest }, + { definition: otherDefinition, harvest: otherHarvest } + ) if (result.isMatching) { const info = await this._getUserInfo(this.github) const resolution = `Auto-generated curation. Newly harvested version ${definition.coordinates.revision} matches existing version ${otherCoordinates.revision}. ${this._generateMatchingDescription(result.match)}` @@ -383,24 +412,29 @@ class GitHubCurationService { type: 'auto', summary: definition.coordinates.toString(), details: `Add ${declaredLicense} license`, - resolution, + resolution }, - patches: [{ - coordinates: revisionLessCoordinates, - revisions: { - [definition.coordinates.revision]: curation + patches: [ + { + coordinates: revisionLessCoordinates, + revisions: { + [definition.coordinates.revision]: curation + } } - }] + ] } const contribution = await this._addOrUpdate(null, this.github, info, patch) this.logger.info('GitHubCurationService.autoCurate.match', { - ...logProps, pr: contribution.data.number, match: result.match + ...logProps, + pr: contribution.data.number, + match: result.match }) return } else { this.logger.info('GitHubCurationService.autoCurate.mismatch', { - ...logProps, mismatch: result.mismatch + ...logProps, + mismatch: result.mismatch }) } } @@ -413,7 +447,8 @@ class GitHubCurationService { _canBeAutoCurated(definition, curationAndContributions) { const tools = get(definition, 'described.tools') || [] const hasClearlyDefinedInTools = tools.some(tool => tool.startsWith('clearlydefined')) - const hasCurations = curationAndContributions.curations && Object.keys(curationAndContributions.curations).length !== 0 + const hasCurations = + curationAndContributions.curations && Object.keys(curationAndContributions.curations).length !== 0 return hasClearlyDefinedInTools && !this._hasExistingCurations(definition, curationAndContributions) && hasCurations } @@ -450,7 +485,11 @@ class GitHubCurationService { } this.logger.info('eligible component for multiversion curation', { coordinates: curatedCoordinates.toString() }) let matchingRevisionAndReason = await this._calculateMatchingRevisionAndReason(curatedCoordinates) - matchingRevisionAndReason = await this._filterRevisionWithDeclaredLicense(curatedCoordinates, get(curationRevisions, [revision]), matchingRevisionAndReason) + matchingRevisionAndReason = await this._filterRevisionWithDeclaredLicense( + curatedCoordinates, + get(curationRevisions, [revision]), + matchingRevisionAndReason + ) if (matchingRevisionAndReason.length === 0) { return } @@ -462,9 +501,14 @@ class GitHubCurationService { type: 'auto', summary: curatedCoordinates.toString(), details: `Add ${get(curationRevisions, [revision, 'licensed', 'declared'])} license`, - resolution: `Automatically added versions based on ${pr.html_url}\n ${this._formatMultiversionCuratedRevisions(matchingRevisionAndReason)}`, + resolution: `Automatically added versions based on ${pr.html_url}\n ${this._formatMultiversionCuratedRevisions(matchingRevisionAndReason)}` } - return this._addCurationWithMatchingRevisions(curatedCoordinates, curationRevisions[revision], info, matchingRevisionAndReason) + return this._addCurationWithMatchingRevisions( + curatedCoordinates, + curationRevisions[revision], + info, + matchingRevisionAndReason + ) } catch (err) { this.logger.error('GitHubCurationService.addByMergedCuration.addFailed', { error: err, pr: pr.html_url }) } @@ -539,8 +583,10 @@ ${this._formatDefinitions(patch.patches)}` _formatDefinitions(definitions) { return definitions.map( def => - `- [${def.coordinates.name} ${Object.keys(def.revisions)[0] - }](https://clearlydefined.io/definitions/${EntityCoordinates.fromObject(def.coordinates)}/${Object.keys(def.revisions)[0] + `- [${def.coordinates.name} ${ + Object.keys(def.revisions)[0] + }](https://clearlydefined.io/definitions/${EntityCoordinates.fromObject(def.coordinates)}/${ + Object.keys(def.revisions)[0] })` ) } @@ -555,7 +601,7 @@ ${this._formatDefinitions(patch.patches)}` } return 0 }) - .forEach(version => output += `- ${version}\n`) + .forEach(version => (output += `- ${version}\n`)) const allMatchingProps = union(...multiversionSearchResults.map(m => m.matchingProperties)) output += this._generateMatchingDescription(allMatchingProps) @@ -581,9 +627,14 @@ ${this._formatDefinitions(patch.patches)}` } if (Object.keys(matchingMetadata).length > 0) { - const metadataText = Object.keys(matchingMetadata).length == 1 - ? Object.keys(matchingMetadata).map(metadataProp => `${metadataProp}: ${JSON.stringify(matchingMetadata[metadataProp])}`) - : Object.keys(matchingMetadata).map(metadataProp => `\n- ${metadataProp}: ${JSON.stringify(matchingMetadata[metadataProp])}`) + const metadataText = + Object.keys(matchingMetadata).length == 1 + ? Object.keys(matchingMetadata).map( + metadataProp => `${metadataProp}: ${JSON.stringify(matchingMetadata[metadataProp])}` + ) + : Object.keys(matchingMetadata).map( + metadataProp => `\n- ${metadataProp}: ${JSON.stringify(matchingMetadata[metadataProp])}` + ) output += `\nMatching metadata: ${metadataText}` } return output @@ -601,7 +652,10 @@ ${this._formatDefinitions(patch.patches)}` * @returns {Object} The requested curation and corresponding revision identifier (e.g., commit sha) if relevant */ async get(coordinates, curation = null) { - if (!coordinates.revision) throw new Error(`Coordinates ${coordinates.toString()} appear to be malformed. Are they missing a namespace or revision?`) + if (!coordinates.revision) + throw new Error( + `Coordinates ${coordinates.toString()} appear to be malformed. Are they missing a namespace or revision?` + ) if (curation && typeof curation !== 'number' && typeof curation !== 'string') return curation const all = await this._getCurations(coordinates, curation) if (!all || !all.revisions) return null @@ -624,17 +678,29 @@ ${this._formatDefinitions(patch.patches)}` */ async _getCurations(coordinates, pr = null) { const path = this._getCurationPath(coordinates) - this.logger.info('7:compute:curation_source:start', { ts: new Date().toISOString(), coordinates: coordinates.toString() }) + this.logger.info('7:compute:curation_source:start', { + ts: new Date().toISOString(), + coordinates: coordinates.toString() + }) const tree = await this._getCurationTree(pr) - this.logger.info('7:compute:curation_source:end', { ts: new Date().toISOString(), coordinates: coordinates.toString() }) + this.logger.info('7:compute:curation_source:end', { + ts: new Date().toISOString(), + coordinates: coordinates.toString() + }) const treePath = flatMap(deCodeSlashes(path).split('/'), (current, i, original) => original.length - 1 != i ? [current, 'children'] : current ) const blob = get(tree, treePath) if (!blob) return null - this.logger.info('8:compute:curation_blob:start', { ts: new Date().toISOString(), coordinates: coordinates.toString() }) + this.logger.info('8:compute:curation_blob:start', { + ts: new Date().toISOString(), + coordinates: coordinates.toString() + }) const data = await this.smartGit.blob(blob.object) - this.logger.info('8:compute:curation_blob:end', { ts: new Date().toISOString(), coordinates: coordinates.toString() }) + this.logger.info('8:compute:curation_blob:end', { + ts: new Date().toISOString(), + coordinates: coordinates.toString() + }) const content = yaml.safeLoad(data.toString()) // Stash the sha of the content as a NON-enumerable prop so it does not get merged into the patch Object.defineProperty(content, '_origin', { value: { sha: blob.object }, enumerable: false }) @@ -824,9 +890,7 @@ ${this._formatDefinitions(patch.patches)}` } _getCacheKey(coordinates) { - return `cur_${EntityCoordinates.fromObject(coordinates) - .toString() - .toLowerCase()}` + return `cur_${EntityCoordinates.fromObject(coordinates).toString().toLowerCase()}` } async _addCurationWithMatchingRevisions(coordinates, curation, info, matchingRevisionAndReason) { @@ -835,14 +899,18 @@ ${this._formatDefinitions(patch.patches)}` return } const newRevisions = {} - matchingRevisionAndReason.forEach(versionAndReason => { newRevisions[versionAndReason.version] = { 'licensed': { 'declared': license } } }) + matchingRevisionAndReason.forEach(versionAndReason => { + newRevisions[versionAndReason.version] = { licensed: { declared: license } } + }) const userInfo = await this._getUserInfo(this.github) const patch = { contributionInfo: info, - patches: [{ - coordinates: coordinates.asRevisionless(), - revisions: newRevisions - }] + patches: [ + { + coordinates: coordinates.asRevisionless(), + revisions: newRevisions + } + ] } return this._addOrUpdate(null, this.github, userInfo, patch) } @@ -856,12 +924,19 @@ ${this._formatDefinitions(patch.patches)}` for (const coordinates of uniqueCoordinatesList) { const result = { coordinates: coordinates.toString() } try { - this.logger.info('GitHubCurationService.reprocessMergedCurations.reprocessMergedCurationStart', { coordinate: coordinates.toString() }) + this.logger.info('GitHubCurationService.reprocessMergedCurations.reprocessMergedCurationStart', { + coordinate: coordinates.toString() + }) result.contributions = await this._reprocessMergedCuration(coordinates) - this.logger.info('GitHubCurationService.reprocessMergedCurations.reprocessMergedCurationSuccess', { coordinate: coordinates.toString() }) + this.logger.info('GitHubCurationService.reprocessMergedCurations.reprocessMergedCurationSuccess', { + coordinate: coordinates.toString() + }) } catch (err) { result.error = err.message - this.logger.info('GitHubCurationService.reprocessMergedCurations.reprocessMergedCurationFailed', { err, coordinate: coordinates.toString() }) + this.logger.info('GitHubCurationService.reprocessMergedCurations.reprocessMergedCurationFailed', { + err, + coordinate: coordinates.toString() + }) } results.push(result) } @@ -878,7 +953,11 @@ ${this._formatDefinitions(patch.patches)}` const curatedCoordinates = EntityCoordinates.fromString(curatedCoordinatesStr) let matchingRevisionAndReason = await this._calculateMatchingRevisionAndReason(curatedCoordinates) matchingRevisionAndReason = matchingRevisionAndReason.filter(r => !processedRevisions.has(r.version)) - matchingRevisionAndReason = await this._filterRevisionWithDeclaredLicense(curatedCoordinates, curation, matchingRevisionAndReason) + matchingRevisionAndReason = await this._filterRevisionWithDeclaredLicense( + curatedCoordinates, + curation, + matchingRevisionAndReason + ) if (matchingRevisionAndReason.length === 0) { contributions.push({ coordinates: curatedCoordinates.toString() }) continue @@ -891,9 +970,14 @@ ${this._formatDefinitions(patch.patches)}` type: 'auto', summary: `Reprocess merged curation for ${EntityCoordinates.fromObject(curatedCoordinates).toString()}`, details: `Curated ${get(curation, ['licensed.declared'])} license`, - resolution: `Automatically added versions based on merged curation:\n ${this._formatMultiversionCuratedRevisions(matchingRevisionAndReason)}`, + resolution: `Automatically added versions based on merged curation:\n ${this._formatMultiversionCuratedRevisions(matchingRevisionAndReason)}` } - const contribution = await this._addCurationWithMatchingRevisions(curatedCoordinates, curation, info, matchingRevisionAndReason) + const contribution = await this._addCurationWithMatchingRevisions( + curatedCoordinates, + curation, + info, + matchingRevisionAndReason + ) matchingRevisionAndReason.forEach(r => processedRevisions.add(r.version)) contributions.push({ coordinates: curatedCoordinates.toString(), diff --git a/providers/curation/memoryStore.js b/providers/curation/memoryStore.js index a57eaffcd..4739f509a 100644 --- a/providers/curation/memoryStore.js +++ b/providers/curation/memoryStore.js @@ -57,9 +57,7 @@ class MemoryStore { _getCurationId(coordinates) { if (!coordinates) return '' - return EntityCoordinates.fromObject(coordinates) - .toString() - .toLowerCase() + return EntityCoordinates.fromObject(coordinates).toString().toLowerCase() } } diff --git a/providers/curation/mongoCurationStore.js b/providers/curation/mongoCurationStore.js index 0f3ea049b..8e5c8a1d5 100644 --- a/providers/curation/mongoCurationStore.js +++ b/providers/curation/mongoCurationStore.js @@ -106,9 +106,7 @@ class MongoCurationStore { _getCurationId(coordinates) { if (!coordinates) return '' - return EntityCoordinates.fromObject(coordinates) - .toString() - .toLowerCase() + return EntityCoordinates.fromObject(coordinates).toString().toLowerCase() } _buildContributionQuery(coordinates) { @@ -132,11 +130,7 @@ class MongoCurationStore { } _lowercaseCoordinates(input) { - return EntityCoordinates.fromString( - EntityCoordinates.fromObject(input) - .toString() - .toLowerCase() - ) + return EntityCoordinates.fromString(EntityCoordinates.fromObject(input).toString().toLowerCase()) } } diff --git a/providers/harvest/azureQueueConfig.js b/providers/harvest/azureQueueConfig.js index 3e11593de..eb713ad44 100644 --- a/providers/harvest/azureQueueConfig.js +++ b/providers/harvest/azureQueueConfig.js @@ -10,7 +10,7 @@ function azure(options) { queueName: config.get('HARVEST_QUEUE_NAME') || 'harvests', dequeueOptions: { numOfMessages: 32, - visibilityTimeout: 10 * 60, // 10 min. The default value is 30 seconds. + visibilityTimeout: 10 * 60 // 10 min. The default value is 30 seconds. } } return new AzureStorageQueue(realOptions) diff --git a/providers/harvest/process.js b/providers/harvest/process.js index 01514a6b6..54f21cf96 100644 --- a/providers/harvest/process.js +++ b/providers/harvest/process.js @@ -10,9 +10,7 @@ async function work(once) { try { const messages = await queue.dequeueMultiple() if (messages && messages.length > 0) isQueueEmpty = false - await Promise.all( - messages.map(message => processMessage(message)) - ) + await Promise.all(messages.map(message => processMessage(message))) } catch (error) { logger.error(error) } finally { diff --git a/providers/queueing/azureStorageQueue.js b/providers/queueing/azureStorageQueue.js index 44deb7d1d..7f1523f76 100644 --- a/providers/queueing/azureStorageQueue.js +++ b/providers/queueing/azureStorageQueue.js @@ -47,11 +47,17 @@ class AzureStorageQueue { /** Similar to dequeue() but returns multiple messages to improve performance */ async dequeueMultiple() { - const messages = await promisify(this.queueService.getMessages).bind(this.queueService)(this.options.queueName, this.options.dequeueOptions) + const messages = await promisify(this.queueService.getMessages).bind(this.queueService)( + this.options.queueName, + this.options.dequeueOptions + ) if (!messages || messages.length === 0) return [] for (const i in messages) { if (messages[i].dequeueCount <= 5) { - messages[i] = { original: messages[i], data: JSON.parse(Buffer.from(messages[i].messageText, 'base64').toString('utf8')) } + messages[i] = { + original: messages[i], + data: JSON.parse(Buffer.from(messages[i].messageText, 'base64').toString('utf8')) + } } else { await this.delete({ original: messages[i] }) } diff --git a/providers/stores/abstractFileStore.js b/providers/stores/abstractFileStore.js index 8c02fad3a..d616e3c25 100644 --- a/providers/stores/abstractFileStore.js +++ b/providers/stores/abstractFileStore.js @@ -13,7 +13,7 @@ class AbstractFileStore { this.options = options } - async initialize() { } + async initialize() {} /** * Visit all of the files associated with the given coordinates. @@ -24,13 +24,15 @@ class AbstractFileStore { async list(coordinates, visitor) { try { const paths = await recursive(this._toStoragePathFromCoordinates(coordinates), ['.DS_Store']) - return (await Promise.all( - paths.map(async path => { - if (!this._isValidPath(path)) return null - const data = await promisify(fs.readFile)(path) - return data ? visitor(JSON.parse(data)) : null - }) - )).filter(x => x) + return ( + await Promise.all( + paths.map(async path => { + if (!this._isValidPath(path)) return null + const data = await promisify(fs.readFile)(path) + return data ? visitor(JSON.parse(data)) : null + }) + ) + ).filter(x => x) } catch (error) { // If there is just no entry, that's fine, there is no content. if (error.code === 'ENOENT') return [] @@ -63,21 +65,23 @@ class AbstractFileStore { */ async find(query) { const paths = await recursive(this.options.location, ['.DS_Store']) - return (await Promise.all( - paths.map(async path => { - try { - if (!this._isValidPath(path)) return null - const data = await promisify(fs.readFile)(path) - if (!data) return null - const definition = JSON.parse(data) - return definition - } catch (error) { - // If there is just no entry, that's fine, there is no content. - if (error.code === 'ENOENT') return null - throw error - } - }) - )).filter(definition => { + return ( + await Promise.all( + paths.map(async path => { + try { + if (!this._isValidPath(path)) return null + const data = await promisify(fs.readFile)(path) + if (!data) return null + const definition = JSON.parse(data) + return definition + } catch (error) { + // If there is just no entry, that's fine, there is no content. + if (error.code === 'ENOENT') return null + throw error + } + }) + ) + ).filter(definition => { if (!definition) return false if (query.type && definition.coordinates.type !== query.type) return false if (query.provider && definition.coordinates.provider !== query.provider) return false diff --git a/providers/stores/abstractMongoDefinitionStore.js b/providers/stores/abstractMongoDefinitionStore.js index 47d1c4f3d..a9d3e27cf 100644 --- a/providers/stores/abstractMongoDefinitionStore.js +++ b/providers/stores/abstractMongoDefinitionStore.js @@ -23,10 +23,10 @@ const sortOptions = { } const valueTransformers = { - 'licensed.score.total': (value) => value && parseInt(value), - 'described.score.total': (value) => value && parseInt(value), - 'scores.effective': (value) => value && parseInt(value), - 'scores.tool': (value) => value && parseInt(value) + 'licensed.score.total': value => value && parseInt(value), + 'described.score.total': value => value && parseInt(value), + 'scores.effective': value => value && parseInt(value), + 'scores.tool': value => value && parseInt(value) } const SEPARATOR = '&' @@ -38,7 +38,7 @@ class AbstractMongoDefinitionStore { } initialize() { - return promiseRetry(async (retry) => { + return promiseRetry(async retry => { try { this.client = await MongoClient.connect(this.options.connectionString, { useNewUrlParser: true }) this.db = this.client.db(this.options.dbName) @@ -173,7 +173,7 @@ class AbstractMongoDefinitionStore { const sort = sortOptions[parameters.sort] || [] const clause = {} const sortDirection = parameters.sortDesc ? -1 : 1 - sort.forEach((item) => (clause[item] = sortDirection)) + sort.forEach(item => (clause[item] = sortDirection)) //Always sort on coordinatesKey(_id or partitionKey) for continuation token const coordinateKey = this.getCoordinatesKey() clause[coordinateKey] = sortDirection @@ -194,7 +194,7 @@ class AbstractMongoDefinitionStore { _buildQueryExpressions(continuationToken, sort) { const lastValues = base64.decode(continuationToken) - const sortValues = lastValues.split(SEPARATOR).map((value) => (value.length ? value : null)) + const sortValues = lastValues.split(SEPARATOR).map(value => (value.length ? value : null)) const queryExpressions = [] const sortConditions = Object.entries(sort) @@ -240,7 +240,7 @@ class AbstractMongoDefinitionStore { if (data.length !== pageSize) return '' const lastItem = data[data.length - 1] const lastValues = Object.keys(sortClause) - .map((key) => get(lastItem, key)) + .map(key => get(lastItem, key)) .join(SEPARATOR) return base64.encode(lastValues) } diff --git a/providers/stores/fileHarvestStore.js b/providers/stores/fileHarvestStore.js index 45170c54e..f4917302e 100644 --- a/providers/stores/fileHarvestStore.js +++ b/providers/stores/fileHarvestStore.js @@ -61,9 +61,8 @@ class FileHarvestStore extends AbstractFileStore { const contents = await Promise.all( files.map(file => { return new Promise((resolve, reject) => - fs.readFile( - file, - (error, data) => (error ? reject(error) : resolve({ name: file, content: JSON.parse(data) })) + fs.readFile(file, (error, data) => + error ? reject(error) : resolve({ name: file, content: JSON.parse(data) }) ) ) }) diff --git a/providers/stores/mongo.js b/providers/stores/mongo.js index fa611ea36..5c6ca290e 100644 --- a/providers/stores/mongo.js +++ b/providers/stores/mongo.js @@ -5,7 +5,6 @@ const { clone, get, range } = require('lodash') const AbstractMongoDefinitionStore = require('./abstractMongoDefinitionStore') class MongoStore extends AbstractMongoDefinitionStore { - /** * List all of the matching components for the given coordinates. * Accepts partial coordinates. @@ -88,15 +87,14 @@ class MongoStore extends AbstractMongoDefinitionStore { await this.collection.deleteMany({ '_mongo.partitionKey': this.getId(coordinates) }) return null } - + getCoordinatesKey() { return '_mongo.partitionKey' } - + buildQuery(parameters) { const filter = super.buildQuery(parameters) return { ...filter, '_mongo.page': 1 } // only get page 1 of each definition } - } module.exports = options => new MongoStore(options) diff --git a/providers/stores/mongoConfig.js b/providers/stores/mongoConfig.js index 0ac1bcc29..f3db88a80 100644 --- a/providers/stores/mongoConfig.js +++ b/providers/stores/mongoConfig.js @@ -10,21 +10,27 @@ const dbOptions = { } function definitionPaged(options) { - return mongo(options || { - ...dbOptions, - collectionName: config.get('DEFINITION_MONGO_COLLECTION_NAME') || 'definitions-paged' - }) + return mongo( + options || { + ...dbOptions, + collectionName: config.get('DEFINITION_MONGO_COLLECTION_NAME') || 'definitions-paged' + } + ) } function definitionTrimmed(options) { const oldConfig = config.get('TRIMMED_DEFINITION_MONGO_COLLECTION_NAME') if (oldConfig) { - console.warn('The TRIMMED_DEFINITION_MONGO_COLLECTION_NAME environment variable is deprecated. Use DEFINITION_MONGO_TRIMMED_COLLECTION_NAME instead.') + console.warn( + 'The TRIMMED_DEFINITION_MONGO_COLLECTION_NAME environment variable is deprecated. Use DEFINITION_MONGO_TRIMMED_COLLECTION_NAME instead.' + ) } - return TrimmedMongoDefinitionStore(options || { - ...dbOptions, - collectionName: config.get('DEFINITION_MONGO_TRIMMED_COLLECTION_NAME') || oldConfig || 'definitions-trimmed' - }) + return TrimmedMongoDefinitionStore( + options || { + ...dbOptions, + collectionName: config.get('DEFINITION_MONGO_TRIMMED_COLLECTION_NAME') || oldConfig || 'definitions-trimmed' + } + ) } module.exports = { definitionPaged, definitionTrimmed } diff --git a/providers/stores/trimmedMongoDefinitionStore.js b/providers/stores/trimmedMongoDefinitionStore.js index 8320d8d5e..404f0e196 100644 --- a/providers/stores/trimmedMongoDefinitionStore.js +++ b/providers/stores/trimmedMongoDefinitionStore.js @@ -19,7 +19,7 @@ class TrimmedMongoDefinitionStore extends AbstractMongoDefinitionStore { async find(query, continuationToken = '', pageSize) { const result = await super.find(query, continuationToken, pageSize) - result.data.forEach((def) => delete def._id) + result.data.forEach(def => delete def._id) return result } diff --git a/providers/summary/clearlydefined.js b/providers/summary/clearlydefined.js index 13278b551..0908d7fc9 100644 --- a/providers/summary/clearlydefined.js +++ b/providers/summary/clearlydefined.js @@ -20,6 +20,12 @@ const mavenBasedUrls = { gradleplugin: 'https://plugins.gradle.org/m2' } +const condaChannels = { + 'anaconda-main': 'https://repo.anaconda.com/pkgs/main', + 'anaconda-r': 'https://repo.anaconda.com/pkgs/r', + 'conda-forge': 'https://conda.anaconda.org/conda-forge' +} + class ClearlyDescribedSummarizer { constructor(options) { this.options = options @@ -44,6 +50,12 @@ class ClearlyDescribedSummarizer { case 'npm': this.addNpmData(result, data, coordinates) break + case 'conda': + this.addCondaData(result, data, coordinates) + break + case 'condasrc': + this.addCondaSrcData(result, data, coordinates) + break case 'crate': this.addCrateData(result, data, coordinates) break @@ -166,17 +178,9 @@ class ClearlyDescribedSummarizer { const urls = this.getMavenUrls(coordinates) setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) - setIfValue( - result, - 'described.urls.registry', - urls.registry - ) + setIfValue(result, 'described.urls.registry', urls.registry) setIfValue(result, 'described.urls.version', `${get(result, 'described.urls.registry')}/${coordinates.revision}`) - setIfValue( - result, - 'described.urls.download', - urls.download - ) + setIfValue(result, 'described.urls.download', urls.download) const projectSummaryLicenses = get(data, 'manifest.summary.licenses') || get(data, 'manifest.summary.project.licenses') // the project layer was removed in 1.2.0 if (!projectSummaryLicenses) return @@ -191,6 +195,22 @@ class ClearlyDescribedSummarizer { if (licenses.length) setIfValue(result, 'licensed.declared', SPDX.normalize(licenses.join(' OR '))) } + addCondaData(result, data, coordinates) { + setIfValue(result, 'described.releaseDate', extractDate(get(data, 'releaseDate'))) + setIfValue(result, 'described.urls.download', get(data, 'registryData.downloadUrl')) + setIfValue(result, 'described.urls.registry', new URL(`${condaChannels[coordinates.provider]}`).href) + setIfValue(result, 'described.projectWebsite', get(data, 'registryData.channelData.home')) + setIfValue(result, 'licensed.declared', SPDX.normalize(data.declaredLicenses)) + } + + addCondaSrcData(result, data, coordinates) { + setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) + setIfValue(result, 'described.urls.download', get(data, 'registryData.channelData.source_url')) + setIfValue(result, 'described.urls.registry', new URL(`${condaChannels[coordinates.provider]}`).href) + setIfValue(result, 'described.projectWebsite', get(data, 'registryData.channelData.home')) + setIfValue(result, 'licensed.declared', SPDX.normalize(data.declaredLicenses)) + } + addCrateData(result, data, coordinates) { setIfValue(result, 'described.releaseDate', extractDate(get(data, 'registryData.created_at'))) setIfValue(result, 'described.projectWebsite', get(data, 'manifest.homepage')) @@ -206,7 +226,6 @@ class ClearlyDescribedSummarizer { } addSourceArchiveData(result, data, coordinates) { - setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) const namespaceAsFolders = coordinates.namespace ? coordinates.namespace.replace(/\./g, '/') : coordinates.namespace setIfValue( @@ -275,14 +294,16 @@ class ClearlyDescribedSummarizer { setIfValue( result, 'described.urls.registry', - `https://npmjs.com/package/${coordinates.namespace ? coordinates.namespace + '/' + coordinates.name : coordinates.name + `https://npmjs.com/package/${ + coordinates.namespace ? coordinates.namespace + '/' + coordinates.name : coordinates.name }` ) setIfValue(result, 'described.urls.version', `${get(result, 'described.urls.registry')}/v/${coordinates.revision}`) setIfValue( result, 'described.urls.download', - `https://registry.npmjs.com/${coordinates.namespace ? coordinates.namespace + '/' + coordinates.name : coordinates.name + `https://registry.npmjs.com/${ + coordinates.namespace ? coordinates.namespace + '/' + coordinates.name : coordinates.name }/-/${coordinates.name}-${coordinates.revision}.tgz` ) const manifest = get(data, 'registryData.manifest') @@ -407,16 +428,8 @@ class ClearlyDescribedSummarizer { setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) setIfValue(result, 'described.urls.registry', urls.registry) - setIfValue( - result, - 'described.urls.version', - urls.version - ) - setIfValue( - result, - 'described.urls.download', - urls.download - ) + setIfValue(result, 'described.urls.version', urls.version) + setIfValue(result, 'described.urls.download', urls.download) } addDebData(result, data, coordinates) { @@ -461,10 +474,7 @@ class ClearlyDescribedSummarizer { const registryPath = registryData[0].Path if (registryPath) { // Example: ./pool/main/0/0ad/0ad_0.0.17-1.debian.tar.xz -> http://ftp.debian.org/debian/pool/main/0/0ad - const pathName = registryPath - .split('/') - .slice(1, 5) - .join('/') + const pathName = registryPath.split('/').slice(1, 5).join('/') return 'http://ftp.debian.org/debian/' + pathName } return null @@ -482,17 +492,9 @@ class ClearlyDescribedSummarizer { setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) setIfValue(result, 'described.releaseDate', extractDate(data.releaseDate)) - setIfValue( - result, - 'described.urls.registry', - urls.registry - ) + setIfValue(result, 'described.urls.registry', urls.registry) setIfValue(result, 'described.urls.version', urls.version) - setIfValue( - result, - 'described.urls.download', - urls.download - ) + setIfValue(result, 'described.urls.download', urls.download) const licenses = get(data, 'registryData.licenses') || [] // Based on the https://pkg.go.dev/license-policy and github.com/google/licensecheck, // ',' means use AND logic. diff --git a/providers/summary/reuse.js b/providers/summary/reuse.js index fb2c2dc67..fdadce353 100644 --- a/providers/summary/reuse.js +++ b/providers/summary/reuse.js @@ -66,11 +66,10 @@ class FsfeReuseSummarizer { _addLicenseDeclaration(harvested, result) { if (!harvested.reuse.licenses) return const declaredLicenses = harvested.reuse.licenses - .map(license => isDeclaredLicense(SPDX.normalize(license.spdxId)) ? license.spdxId : null) + .map(license => (isDeclaredLicense(SPDX.normalize(license.spdxId)) ? license.spdxId : null)) .filter(x => x) setIfValue(result, 'licensed.declared', uniq(declaredLicenses).join(' AND ')) } - } module.exports = options => new FsfeReuseSummarizer(options) diff --git a/providers/summary/scancode.js b/providers/summary/scancode.js index a51e49e63..520643df9 100644 --- a/providers/summary/scancode.js +++ b/providers/summary/scancode.js @@ -70,7 +70,7 @@ class ScanCodeSummarizer { // Some Maven packages have this value as an object rather than a string // Example: for maven/mavencentral/redis.clients/jedis/4.1.1 // declared_license would be { "name": "MIT", "url": "http://github.com/redis/jedis/raw/master/LICENSE.txt", "comments": null, "distribution": "repo" }' - // Some pypi packages have this value as an object with a license field + // Some pypi packages have this value as an object with a license field // Example: for pypi/pypi/abseil/absl-py/0.9.0 // declared_license would be { "license": "Apache 2.0", "classifiers": ["License :: OSI Approved :: Apache Software License"] } if (typeof declared_license != 'string' && declared_license != undefined) { @@ -210,9 +210,18 @@ class ScanCodeSummarizer { } _normalizeLicenseExpression(licenseExpression) { - const parsed = SPDX.parse(licenseExpression, (key) => SPDX.normalizeSingle(scancodeMap.get(key) || key)) + const licenseVisitor = rawLicenseExpression => { + const mappedLicenseExpression = scancodeMap.get(rawLicenseExpression) + const licenseExpression = mappedLicenseExpression ? mappedLicenseExpression : rawLicenseExpression + + return SPDX.normalizeSingle(licenseExpression) + } + + const parsed = SPDX.parse(licenseExpression, licenseVisitor) const result = SPDX.stringify(parsed) + if (result === 'NOASSERTION') this.logger.info(`ScanCode NOASSERTION from ${licenseExpression}`) + return result } } diff --git a/routes/auth.js b/routes/auth.js index dff033d81..222318519 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -99,7 +99,7 @@ async function getUserDetails(token, org) { if (error.code === 404) console.error( 'GitHub returned a 404 when trying to read team data. ' + - 'You probably need to re-configure your CURATION_GITHUB_TOKEN token with the `read:org` scope. (This only affects local development.)' + 'You probably need to re-configure your CURATION_GITHUB_TOKEN token with the `read:org` scope. (This only affects local development.)' ) else if (error.code === 401 && error.message === 'Bad credentials') // the token was bad. trickle up the problem so the user can fix diff --git a/routes/curations.js b/routes/curations.js index c2002c73b..8b5c187fe 100644 --- a/routes/curations.js +++ b/routes/curations.js @@ -85,9 +85,11 @@ async function updateCurations(request, response) { return response.status(400).send(errorData) } - const normalizedPatches = await Promise.all(request.body.patches.map(async entry => { - return { ...entry, coordinates: await utils.toNormalizedEntityCoordinates(entry.coordinates) } - })) + const normalizedPatches = await Promise.all( + request.body.patches.map(async entry => { + return { ...entry, coordinates: await utils.toNormalizedEntityCoordinates(entry.coordinates) } + }) + ) const normalizedBody = { ...request.body, patches: normalizedPatches } const result = await curationService.addOrUpdate(userGithub, serviceGithub, info, normalizedBody) response.status(200).send({ diff --git a/routes/definitions-1.0.0.js b/routes/definitions-1.0.0.js index 34237f3a1..8e4ac414b 100644 --- a/routes/definitions-1.0.0.js +++ b/routes/definitions-1.0.0.js @@ -11,9 +11,7 @@ const validator = require('../schemas/validator') router.get('/', asyncMiddleware(getDefinition)) async function getDefinition(req, resp) { - const { - coordinates, pr, expand - } = req.query + const { coordinates, pr, expand } = req.query const force = req.query.force === true || req.query.force === 'true' let coordinatesEntity = EntityCoordinates.fromString(coordinates) const isValid = validator.validate('definitions-get-dto', { @@ -28,7 +26,7 @@ async function getDefinition(req, resp) { try { coordinatesEntity = await utils.toNormalizedEntityCoordinates(coordinatesEntity) } catch (err) { - return resp.status(404).send(`The ${coordinates} is not public.`) + return resp.status(404).send(`The ${encodeURIComponent(coordinates)} is not public.`) } const result = await definitionService.get(coordinatesEntity, pr, force, expand) @@ -46,4 +44,4 @@ function setup(definition, testFlag = false) { return router } -module.exports = setup \ No newline at end of file +module.exports = setup diff --git a/routes/definitions.js b/routes/definitions.js index 9b5bf404a..8f9fb37b6 100644 --- a/routes/definitions.js +++ b/routes/definitions.js @@ -44,15 +44,13 @@ async function getDefinition(request, response) { // Join the rest of the string as the namespace const nameSpace = splitString.join('/') - coordinates = utils.toEntityCoordinatesFromArgs( - { - 'type': request.params.type, - 'provider': request.params.provider, - 'namespace': nameSpace, - 'name': name, - 'revision': revision - } - ) + coordinates = utils.toEntityCoordinatesFromArgs({ + type: request.params.type, + provider: request.params.provider, + namespace: nameSpace, + name: name, + revision: revision + }) } else { coordinates = await utils.toEntityCoordinatesFromRequest(request) } @@ -122,7 +120,8 @@ async function listDefinitions(request, response) { try { // Tempoarily adding this verbose logging to find perf issues log.info('POSTing to /definitions', { - ts: new Date().toISOString(), requestParams: request.params, + ts: new Date().toISOString(), + requestParams: request.params, normalizedCoordinates, coordinateCount: coordinatesList.length, force, diff --git a/routes/harvest.js b/routes/harvest.js index f5dcfbd43..ac7993721 100644 --- a/routes/harvest.js +++ b/routes/harvest.js @@ -88,13 +88,14 @@ async function queue(request, response) { } async function normalizeCoordinates(requests) { - const normalizedBody = await Promise.all(requests - .map(async (entry) => { + const normalizedBody = await Promise.all( + requests.map(async entry => { const coordinates = EntityCoordinates.fromString(entry?.coordinates) if (!coordinates) return null const mapped = await utils.toNormalizedEntityCoordinates(coordinates) return { ...entry, coordinates: mapped.toString() } - })) + }) + ) return normalizedBody.filter(entry => entry && entry.coordinates) } diff --git a/routes/index.js b/routes/index.js index c8103207e..72c7e6253 100644 --- a/routes/index.js +++ b/routes/index.js @@ -3,15 +3,17 @@ const express = require('express') const router = express.Router() -router.get('/', function(req, res) { - const msg = `{ "status": "OK", "sha": "${sha}" }` +router.get('/', function (req, res) { + const msg = `{ "status": "OK", "version": "${version}", "sha": "${sha}"` res.status(200).send(msg) }) module.exports = router +let version let sha -function setup(buildsha) { +function setup(buildsha, appVersion) { + version = appVersion sha = buildsha return router } diff --git a/routes/originConda.js b/routes/originConda.js new file mode 100644 index 000000000..2764bb4cf --- /dev/null +++ b/routes/originConda.js @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation and others. Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +const asyncMiddleware = require('../middleware/asyncMiddleware') +const router = require('express').Router() +const requestPromise = require('request-promise-native') +const { uniq } = require('lodash') +const { Cache } = require('memory-cache') +const condaChannels = { + 'anaconda-main': 'https://repo.anaconda.com/pkgs/main', + 'anaconda-r': 'https://repo.anaconda.com/pkgs/r', + 'conda-forge': 'https://conda.anaconda.org/conda-forge' +} + +async function fetchCondaChannelData(channel) { + const key = `${channel}-channelData` + let channelData = condaCache.get(key) + if (!channelData) { + const url = `${condaChannels[channel]}/channeldata.json` + channelData = await requestPromise({ url, method: 'GET', json: true }) + condaCache.put(key, channelData, 8 * 60 * 60 * 1000) // 8 hours + } + return channelData +} + +async function fetchCondaRepoData(channel, subdir) { + const key = `${channel}-${subdir}-repoData` + let repoData = condaCache.get(key) + if (!repoData) { + const url = `${condaChannels[channel]}/${subdir}/repodata.json` + repoData = await requestPromise({ url, method: 'GET', json: true }) + condaCache.put(key, repoData, 8 * 60 * 60 * 1000) // 8 hours + } + return repoData +} + +router.get('/:channel/:subdir/:name/revisions', asyncMiddleware(getOriginCondaRevisions)) + +async function getOriginCondaRevisions(request, response) { + let { channel, subdir, name } = request.params + channel = encodeURIComponent(channel) + subdir = encodeURIComponent(subdir) + name = encodeURIComponent(name) + if (!condaChannels[channel]) { + return response.status(404).send(`Unrecognized Conda channel ${channel}`) + } + let channelData = await fetchCondaChannelData(channel) + if (!channelData.packages[name]) { + return response.status(404).send(`Package ${name} not found in Conda channel ${channel}`) + } + if (subdir !== '-' && !channelData.subdirs.find(x => x == subdir)) { + return response + .status(404) + .send(`Subdir ${subdir} is non-existent in Conda channel ${channel}, subdirs: ${channelData.subdirs}`) + } + let revisions = [] + let subdirs = subdir === '-' ? channelData.packages[name].subdirs : [subdir] + for (let subdir of subdirs) { + const repoData = await fetchCondaRepoData(channel, subdir) + if (repoData['packages']) { + Object.entries(repoData['packages']).forEach(([, packageData]) => { + if (packageData.name === name) { + revisions.push(`${subdir}:${packageData.version}-${packageData.build}`) + } + }) + } + if (repoData['packages.conda']) { + Object.entries(repoData['packages.conda']).forEach(([, packageData]) => { + if (packageData.name === name) { + revisions.push(`${subdir}:${packageData.version}-${packageData.build}`) + } + }) + } + } + return response.status(200).send(uniq(revisions)) +} + +router.get('/:channel/:name', asyncMiddleware(getOriginConda)) + +async function getOriginConda(request, response) { + let { channel, name } = request.params + channel = encodeURIComponent(channel) + name = encodeURIComponent(name) + if (!condaChannels[channel]) { + return response.status(404).send(`Unrecognized Conda channel ${channel}`) + } + let channelData = await fetchCondaChannelData(channel) + let matches = Object.entries(channelData.packages) + .filter(([packageName]) => packageName.includes(name)) + .map(([packageName]) => { + return { id: packageName } + }) + return response.status(200).send(matches) +} + +let condaCache + +function setup(cache = new Cache(), testFlag = false) { + condaCache = cache + + if (testFlag) { + router._getOriginConda = getOriginConda + router._getOriginCondaRevisions = getOriginCondaRevisions + } + + return router +} + +module.exports = setup diff --git a/routes/originGitLab.js b/routes/originGitLab.js index e5145f42f..455a2d26c 100644 --- a/routes/originGitLab.js +++ b/routes/originGitLab.js @@ -15,7 +15,6 @@ router.get( '/:namespace/:project/:revisions', asyncMiddleware(async (request, response) => { try { - const { namespace, project } = request.params const project_info = await gitlab.Projects.search(project) @@ -24,10 +23,10 @@ router.get( const tags = await gitlab.Tags.all(project_match.id) const unsorted = tags.map(tag => { - return ({ + return { tag: tag.name, sha: tag.commit.id - }) + } }) const result = unsorted.filter(x => x).sort((a, b) => (a.tag < b.tag ? 1 : a.tag > b.tag ? -1 : 0)) @@ -82,7 +81,7 @@ function setup() { function getExactProjectMatch(namespace, project, projects) { let exact_match - projects.filter((item) => { + projects.filter(item => { if (item.path_with_namespace == `${namespace}/${project}`) { exact_match = item } @@ -95,9 +94,9 @@ async function projectsByProjectName(namespace, project) { const projects = await gitlab.Projects.search(project) let project_names = projects.map(project => { - return ({ + return { id: project.path_with_namespace - }) + } }) return project_names @@ -109,9 +108,7 @@ async function getUserProjects(username) { const user_projects = await gitlab.Users.projects(user_response[0].id) const user_project_names = user_projects.map(project => { - return ( - project.name - ) + return project.name }) return user_project_names @@ -121,10 +118,10 @@ async function getUsers(userName) { const users = await gitlab.Users.search(userName) let user_names = users.map(user => { - return ({ + return { id: user.id, username: user.username - }) + } }) return user_names @@ -137,9 +134,7 @@ async function getGroupProjects(groupName) { const group_projects = await gitlab.Groups.projects(group_response[0]) let group_project_names = group_projects.map(project => { - return ( - project.name - ) + return project.name }) return group_project_names @@ -154,12 +149,10 @@ async function getGroups(groupName) { const groups = await gitlab.Groups.search(groupName) let group_names = groups.map(group => { - return ( - group.id - ) + return group.id }) return group_names } -module.exports = setup \ No newline at end of file +module.exports = setup diff --git a/routes/originGo.js b/routes/originGo.js index 17d3c250c..a136a72f6 100644 --- a/routes/originGo.js +++ b/routes/originGo.js @@ -42,4 +42,4 @@ function setup() { return router } -module.exports = setup \ No newline at end of file +module.exports = setup diff --git a/routes/originGradlePlugin.js b/routes/originGradlePlugin.js index c59d09bcc..e3ede2b25 100644 --- a/routes/originGradlePlugin.js +++ b/routes/originGradlePlugin.js @@ -17,7 +17,7 @@ router.get( asyncMiddleware(async (request, response) => { const { pluginId } = request.params const answer = await gradleHelper.getMavenMetadata(pluginId) - const meta = answer && await parseXml(answer) + const meta = answer && (await parseXml(answer)) const result = get(meta, 'metadata.versioning.0.versions.0.version') || [] result.reverse() return response.status(200).send(uniq(result)) diff --git a/routes/webhook.js b/routes/webhook.js index daed72592..5b0bffdc9 100644 --- a/routes/webhook.js +++ b/routes/webhook.js @@ -74,12 +74,7 @@ function validateGitHubSignature(request, response) { if (!isGithubEvent || !signature) return info(request, response, 400, 'Missing signature or event type on GitHub webhook') - const computedSignature = - 'sha1=' + - crypto - .createHmac('sha1', githubSecret) - .update(request.body) - .digest('hex') + const computedSignature = 'sha1=' + crypto.createHmac('sha1', githubSecret).update(request.body).digest('hex') if (!test && !crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computedSignature))) return info(request, response, 400, 'X-Hub-Signature does not match blob signature') return true diff --git a/schemas/coordinates-1.0.json b/schemas/coordinates-1.0.json index 023ca4012..ffb996b85 100644 --- a/schemas/coordinates-1.0.json +++ b/schemas/coordinates-1.0.json @@ -13,6 +13,8 @@ "type": { "enum": [ "npm", + "conda", + "condasrc", "crate", "git", "maven", @@ -32,8 +34,11 @@ }, "provider": { "enum": [ + "anaconda-main", + "anaconda-r", "npmjs", "cocoapods", + "conda-forge", "cratesio", "github", "gitlab", diff --git a/schemas/curation-1.0.json b/schemas/curation-1.0.json index 2bd32a9b1..eeda81552 100644 --- a/schemas/curation-1.0.json +++ b/schemas/curation-1.0.json @@ -24,6 +24,8 @@ "type": "string", "enum": [ "npm", + "conda", + "condasrc", "crate", "git", "maven", @@ -45,8 +47,11 @@ "provider": { "type": "string", "enum": [ + "anaconda-main", + "anaconda-r", "npmjs", "cocoapods", + "conda-forge", "cratesio", "github", "gitlab", diff --git a/schemas/curations-1.0.json b/schemas/curations-1.0.json index d520d53f4..fec1f048c 100644 --- a/schemas/curations-1.0.json +++ b/schemas/curations-1.0.json @@ -26,6 +26,8 @@ "type": "string", "enum": [ "npm", + "conda", + "condasrc", "crate", "git", "go", @@ -47,8 +49,11 @@ "provider": { "type": "string", "enum": [ + "anaconda-main", + "anaconda-r", "npmjs", "cocoapods", + "conda-forge", "cratesio", "github", "gitlab", diff --git a/schemas/definition-1.0.json b/schemas/definition-1.0.json index f492f2cd6..4383b13df 100644 --- a/schemas/definition-1.0.json +++ b/schemas/definition-1.0.json @@ -32,6 +32,8 @@ "type": { "enum": [ "npm", + "conda", + "condasrc", "crate", "git", "maven", @@ -48,8 +50,11 @@ }, "provider": { "enum": [ + "anaconda-main", + "anaconda-r", "npmjs", "cocoapods", + "conda-forge", "cratesio", "github", "gitlab", @@ -471,4 +476,4 @@ } } } -} \ No newline at end of file +} diff --git a/schemas/swagger.yaml b/schemas/swagger.yaml index 441ac4566..a0d031c28 100644 --- a/schemas/swagger.yaml +++ b/schemas/swagger.yaml @@ -423,6 +423,7 @@ components: example: - git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca - npm/npmjs/-/redie/0.3.0 + - conda/conda-forge/linux-64/21cmfast/3.1.1-py36 noticeFile: type: object @@ -531,6 +532,8 @@ components: type: string enum: - composer + - conda + - condasrc - crate - deb - debsrc @@ -551,7 +554,10 @@ components: schema: type: string enum: + - anaconda-main + - anaconda-r - cocoapods + - conda-forge - cratesio - debian - github @@ -568,7 +574,7 @@ components: name: namespace in: path required: true - description: many component systems have namespaces. GitHub orgs, NPM namespace, Maven group id, ... This segment must be supplied. If your component does not have a namespace, use '-' (ASCII hyphen). + description: many component systems have namespaces. GitHub orgs, NPM namespace, Maven group id, Conda Subdir/Architecture ... This segment must be supplied. If your component does not have a namespace, use '-' (ASCII hyphen). schema: type: string name: diff --git a/test/app.js b/test/app.js index 9de648522..1dcff89c1 100644 --- a/test/app.js +++ b/test/app.js @@ -8,12 +8,19 @@ const init = require('express-init') const Application = require('../app') const config = proxyquire('../bin/config', { ['painless-config']: { - get: () => null + get: name => { + return ( + { + WEBHOOK_GITHUB_SECRET: 'secret', + WEBHOOK_CRAWLER_SECRET: 'secret' + }[name] || null + ) + } } }) describe('Application', () => { - it('should initialize', (done) => { + it('should initialize', done => { const app = Application(config) init(app, error => { if (error) { diff --git a/test/business/aggregatorTest.js b/test/business/aggregatorTest.js new file mode 100644 index 000000000..49dbdfbb5 --- /dev/null +++ b/test/business/aggregatorTest.js @@ -0,0 +1,191 @@ +// (c) Copyright 2024, SAP SE and ClearlyDefined contributors. Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +const AggregatorService = require('../../business/aggregator') +const SummaryService = require('../../business/summarizer') +const EntityCoordinates = require('../../lib/entityCoordinates') +const { setIfValue } = require('../../lib/utils') +const deepEqualInAnyOrder = require('deep-equal-in-any-order') +const chai = require('chai') +chai.use(deepEqualInAnyOrder) +const expect = chai.expect + +describe('Aggregation service', () => { + it('handles no tool data', async () => { + const { service } = setupAggregator() + const aggregated = service.process({}) + expect(aggregated).to.be.null + }) + + it('handles one tool one version data', async () => { + const summaries = { tool2: { '1.0.0': { files: [buildFile('foo.txt', 'MIT')] } } } + const { service } = setupAggregator() + const aggregated = service.process(summaries) + expect(aggregated.files.length).to.eq(1) + }) + + it('handles one tool multiple version data', async () => { + const summaries = { + tool2: { + '1.0.0': { files: [buildFile('foo.txt', 'MIT'), buildFile('bar.txt', 'MIT')] }, + '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } + } + } + const { service } = setupAggregator() + const aggregated = service.process(summaries) + expect(aggregated.files.length).to.eq(1) + expect(aggregated.files[0].path).to.eq('foo.txt') + expect(aggregated.files[0].license).to.eq('GPL-2.0') + }) + + it('handles multiple tools and one file data', async () => { + const summaries = { + tool2: { + '1.0.0': { files: [buildFile('foo.txt', 'MIT')] }, + '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } + }, + tool1: { '3.0.0': { files: [buildFile('foo.txt', 'BSD-3-Clause')] } } + } + const { service } = setupAggregator() + const aggregated = service.process(summaries) + expect(aggregated.files.length).to.eq(1) + expect(aggregated.files[0].license).to.equal('BSD-3-Clause AND GPL-2.0') + }) + + it('handles multiple tools and multiple file data with extras ignored', async () => { + const summaries = { + tool2: { + '1.0.0': { files: [buildFile('foo.txt', 'MIT')] }, + '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } + }, + tool1: { + '3.0.0': { files: [buildFile('foo.txt', 'BSD-3-Clause')] }, + '2.0.0': { files: [buildFile('bar.txt', 'GPL-2.0')] } + } + } + const { service } = setupAggregator() + const aggregated = service.process(summaries) + expect(aggregated.files.length).to.eq(1) + expect(aggregated.files[0].license).to.equal('BSD-3-Clause AND GPL-2.0') + }) + + it('handles multiple tools and multiple file data with extras included', async () => { + const summaries = { + tool2: { + '1.0.0': { files: [buildFile('foo.txt', 'MIT')] }, + '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } + }, + tool1: { + '3.0.0': { files: [buildFile('foo.txt', 'BSD-3-Clause'), buildFile('bar.txt', 'GPL-2.0')] }, + '2.0.0': { files: [buildFile('bar.txt', 'GPL-2.0')] } + } + } + const { service } = setupAggregator() + const aggregated = service.process(summaries) + expect(aggregated.files.length).to.eq(2) + expect(aggregated.files[0].path).to.eq('foo.txt') + expect(aggregated.files[0].license).to.equal('BSD-3-Clause AND GPL-2.0') + expect(aggregated.files[1].path).to.eq('bar.txt') + expect(aggregated.files[1].license).to.eq('GPL-2.0') + }) + + it('handles Rust crates with license choices', async () => { + const testcases = [ + { + name: 'slog', + version: '2.7.0', + tools: [['clearlydefined', 'licensee', 'scancode']], + // Ideally this would be declared without any parentheses, but currently + // the SPDX normalization adds them. + expected: 'MPL-2.0 OR (MIT OR Apache-2.0)' + }, + { + name: 'quote', + version: '0.6.4', + tools: [['clearlydefined', 'fossology', 'licensee', 'scancode']], + expected: 'MIT OR Apache-2.0' + }, + { + name: 'quote', + version: '1.0.9', + tools: [['clearlydefined', 'licensee', 'scancode']], + expected: 'MIT OR Apache-2.0' + }, + { + name: 'rand', + version: '0.8.2', + tools: [['clearlydefined', 'licensee', 'scancode']], + expected: 'MIT OR Apache-2.0' + }, + { + name: 'regex', + version: '1.5.3', + tools: [['clearlydefined', 'licensee', 'scancode']], + expected: 'MIT OR Apache-2.0' + }, + { + name: 'serde', + version: '1.0.123', + tools: [['clearlydefined', 'licensee', 'scancode']], + expected: 'MIT OR Apache-2.0' + }, + { + name: 'mpmc', + version: '0.1.6', + tools: [['clearlydefined', 'licensee', 'scancode']], + expected: 'BSD-2-Clause-Views' + } + ] + + const summary_options = {} + const summaryService = SummaryService(summary_options) + + for (const testcase of testcases) { + const coordSpec = `crate/cratesio/-/${testcase.name}/${testcase.version}` + const coords = EntityCoordinates.fromString(coordSpec) + const raw = require(`./evidence/crate-${testcase.name}-${testcase.version}.json`) + const tools = testcase.tools + const summaries = summaryService.summarizeAll(coords, raw) + const { service } = setupAggregatorWithParams(coordSpec, tools) + const aggregated = service.process(summaries, coords) + expect(aggregated.licensed.declared, `${testcase.name}-${testcase.version}`).to.eq(testcase.expected) + } + }) + + it('should handle composer/packagist components', () => { + const tools = [['clearlydefined', 'licensee', 'scancode', 'reuse']] + const coordSpec = 'composer/packagist/mmucklo/krumo/0.7.0' + const coords = EntityCoordinates.fromString(coordSpec) + const raw = require(`./evidence/${coordSpec.replace(/\//g, '-')}.json`) + + const summary_options = {} + const summaryService = SummaryService(summary_options) + const summaries = summaryService.summarizeAll(coords, raw) + const { service } = setupAggregatorWithParams(coordSpec, tools) + const aggregated = service.process(summaries, coords) + expect(aggregated.licensed.declared).to.be.ok + // package manifest: LGPL-2.0-or-later, license: LGPL-2.1-only + expect(aggregated.licensed.declared).to.be.not.equal('NOASSERTION') + }) +}) + +function buildFile(path, license, holders) { + const result = { path } + setIfValue(result, 'license', license) + setIfValue(result, 'attributions', holders ? holders.map(entry => `Copyright ${entry}`) : null) + return result +} + +function setupAggregator() { + const coordinates = EntityCoordinates.fromString('npm/npmjs/-/test/1.0') + const config = { precedence: [['tool1', 'tool2', 'tool3']] } + const service = AggregatorService(config) + return { service, coordinates } +} + +function setupAggregatorWithParams(coordSpec, tool_precedence) { + const coordinates = EntityCoordinates.fromString(coordSpec) + const config = { precedence: tool_precedence } + const service = AggregatorService(config) + return { service, coordinates } +} diff --git a/test/business/definitionServiceTest.js b/test/business/definitionServiceTest.js index b350b86ca..7facac009 100644 --- a/test/business/definitionServiceTest.js +++ b/test/business/definitionServiceTest.js @@ -4,8 +4,6 @@ const sinon = require('sinon') const validator = require('../../schemas/validator') const DefinitionService = require('../../business/definitionService') -const AggregatorService = require('../../business/aggregator') -const SummaryService = require('../../business/summarizer') const EntityCoordinates = require('../../lib/entityCoordinates') const { setIfValue } = require('../../lib/utils') const Curation = require('../../lib/curation') @@ -15,7 +13,6 @@ const chai = require('chai') chai.use(deepEqualInAnyOrder) const expect = chai.expect - describe('Definition Service', () => { it('invalidates single coordinate', async () => { const { service, coordinates } = setup() @@ -116,6 +113,73 @@ describe('Definition Service', () => { expect(result.length).to.eq(3) expect(result.map(x => x.name)).to.have.members(['test0', 'test1', 'testUpperCase']) }) + + describe('Build source location', () => { + const data = new Map([ + [ + 'pypi/pypi/-/platformdirs/4.2.0', + { + type: 'pypi', + provider: 'pypi', + name: 'platformdirs', + revision: '4.2.0', + url: 'https://pypi.org/project/platformdirs/4.2.0/' + } + ], + [ + 'go/golang/rsc.io/quote/v1.3.0', + { + type: 'go', + provider: 'golang', + namespace: 'rsc.io', + name: 'quote', + revision: 'v1.3.0', + url: 'https://pkg.go.dev/rsc.io/quote@v1.3.0' + } + ], + [ + 'git/github/ratatui-org/ratatui/bcf43688ec4a13825307aef88f3cdcd007b32641', + { + type: 'git', + provider: 'github', + namespace: 'ratatui-org', + name: 'ratatui', + revision: 'bcf43688ec4a13825307aef88f3cdcd007b32641', + url: 'https://github.com/ratatui-org/ratatui/tree/bcf43688ec4a13825307aef88f3cdcd007b32641' + } + ], + [ + 'git/gitlab/cznic/sqlite/282bdb12f8ce48a34b4b768863c4e44c310c4bd8', + { + type: 'git', + provider: 'gitlab', + namespace: 'cznic', + name: 'sqlite', + revision: '282bdb12f8ce48a34b4b768863c4e44c310c4bd8', + url: 'https://gitlab.com/cznic/sqlite/-/tree/282bdb12f8ce48a34b4b768863c4e44c310c4bd8' + } + ], + [ + 'sourcearchive/mavencentral/com.azure/azure-storage-blob/12.20.0', + { + type: 'sourcearchive', + provider: 'mavencentral', + namespace: 'com.azure', + name: 'azure-storage-blob', + revision: '12.20.0', + url: 'https://search.maven.org/remotecontent?filepath=com/azure/azure-storage-blob/12.20.0/azure-storage-blob-12.20.0-sources.jar' + } + ] + ]) + + data.forEach((expected, coordinatesString) => { + it(`should have source location for ${coordinatesString} package`, async () => { + const { service, coordinates } = setup(createDefinition(null, null, []), coordinatesString) + const definition = await service.compute(coordinates) + expect(definition.described.sourceLocation).to.be.deep.equal(expected) + }) + }) + }) }) describe('Definition Service Facet management', () => { @@ -246,166 +310,6 @@ describe('Definition Service Facet management', () => { }) }) -describe('Aggregation service', () => { - it('handles no tool data', async () => { - const { service } = setupAggregator() - const aggregated = service.process({}) - expect(aggregated).to.be.null - }) - - it('handles one tool one version data', async () => { - const summaries = { tool2: { '1.0.0': { files: [buildFile('foo.txt', 'MIT')] } } } - const { service } = setupAggregator() - const aggregated = service.process(summaries) - expect(aggregated.files.length).to.eq(1) - }) - - it('handles one tool multiple version data', async () => { - const summaries = { - tool2: { - '1.0.0': { files: [buildFile('foo.txt', 'MIT'), buildFile('bar.txt', 'MIT')] }, - '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } - } - } - const { service } = setupAggregator() - const aggregated = service.process(summaries) - expect(aggregated.files.length).to.eq(1) - expect(aggregated.files[0].path).to.eq('foo.txt') - expect(aggregated.files[0].license).to.eq('GPL-2.0') - }) - - it('handles multiple tools and one file data', async () => { - const summaries = { - tool2: { - '1.0.0': { files: [buildFile('foo.txt', 'MIT')] }, - '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } - }, - tool1: { '3.0.0': { files: [buildFile('foo.txt', 'BSD-3-Clause')] } } - } - const { service } = setupAggregator() - const aggregated = service.process(summaries) - expect(aggregated.files.length).to.eq(1) - expect(aggregated.files[0].license).to.equal('BSD-3-Clause AND GPL-2.0') - }) - - it('handles multiple tools and multiple file data with extras ignored', async () => { - const summaries = { - tool2: { - '1.0.0': { files: [buildFile('foo.txt', 'MIT')] }, - '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } - }, - tool1: { - '3.0.0': { files: [buildFile('foo.txt', 'BSD-3-Clause')] }, - '2.0.0': { files: [buildFile('bar.txt', 'GPL-2.0')] } - } - } - const { service } = setupAggregator() - const aggregated = service.process(summaries) - expect(aggregated.files.length).to.eq(1) - expect(aggregated.files[0].license).to.equal('BSD-3-Clause AND GPL-2.0') - }) - - it('handles multiple tools and multiple file data with extras included', async () => { - const summaries = { - tool2: { - '1.0.0': { files: [buildFile('foo.txt', 'MIT')] }, - '2.0.0': { files: [buildFile('foo.txt', 'GPL-2.0')] } - }, - tool1: { - '3.0.0': { files: [buildFile('foo.txt', 'BSD-3-Clause'), buildFile('bar.txt', 'GPL-2.0')] }, - '2.0.0': { files: [buildFile('bar.txt', 'GPL-2.0')] } - } - } - const { service } = setupAggregator() - const aggregated = service.process(summaries) - expect(aggregated.files.length).to.eq(2) - expect(aggregated.files[0].path).to.eq('foo.txt') - expect(aggregated.files[0].license).to.equal('BSD-3-Clause AND GPL-2.0') - expect(aggregated.files[1].path).to.eq('bar.txt') - expect(aggregated.files[1].license).to.eq('GPL-2.0') - }) - - it('handles Rust crates with license choices', async () => { - const testcases = [ - { - name: 'slog', - version: '2.7.0', - tools: [['clearlydefined', 'licensee', 'scancode']], - // Ideally this would be declared without any parentheses, but currently - // the SPDX normalization adds them. - expected: 'MPL-2.0 OR (MIT OR Apache-2.0)', - }, - { - name: 'quote', - version: '0.6.4', - tools: [['clearlydefined', 'fossology', 'licensee', 'scancode']], - expected: 'MIT OR Apache-2.0', - }, - { - name: 'quote', - version: '1.0.9', - tools: [['clearlydefined', 'licensee', 'scancode']], - expected: 'MIT OR Apache-2.0', - }, - { - name: 'rand', - version: '0.8.2', - tools: [['clearlydefined', 'licensee', 'scancode']], - expected: 'MIT OR Apache-2.0', - }, - { - name: 'regex', - version: '1.5.3', - tools: [['clearlydefined', 'licensee', 'scancode']], - expected: 'MIT OR Apache-2.0', - }, - { - name: 'serde', - version: '1.0.123', - tools: [['clearlydefined', 'licensee', 'scancode']], - expected: 'MIT OR Apache-2.0', - }, - { - name: 'mpmc', - version: '0.1.6', - tools: [['clearlydefined', 'licensee', 'scancode']], - expected: 'BSD-2-Clause-Views', - } - ] - - const summary_options = {} - const summaryService = SummaryService(summary_options) - - for (let i = 0; i < testcases.length; i++) { - let testcase = testcases[i] - const coordSpec = `crate/cratesio/-/${testcase.name}/${testcase.version}` - const coords = EntityCoordinates.fromString(coordSpec) - const raw = require(`./evidence/crate-${testcase.name}-${testcase.version}.json`) - const tools = testcase.tools - const summaries = summaryService.summarizeAll(coords, raw) - const { service } = setupAggregatorWithParams(coordSpec, tools) - const aggregated = service.process(summaries, coords) - expect(aggregated.licensed.declared, `${testcase.name}-${testcase.version}`).to.eq(testcase.expected) - } - }) - - it('should handle composer/packagist components', () => { - const tools = [['clearlydefined', 'licensee', 'scancode', 'reuse']] - const coordSpec = 'composer/packagist/mmucklo/krumo/0.7.0' - const coords = EntityCoordinates.fromString(coordSpec) - const raw = require(`./evidence/${coordSpec.replace(/\//g, '-')}.json`) - - const summary_options = {} - const summaryService = SummaryService(summary_options) - const summaries = summaryService.summarizeAll(coords, raw) - const { service } = setupAggregatorWithParams(coordSpec, tools) - const aggregated = service.process(summaries, coords) - expect(aggregated.licensed.declared).to.be.ok - // package manifest: LGPL-2.0-or-later, license: LGPL-2.1-only - expect(aggregated.licensed.declared).to.be.not.equal('NOASSERTION') - }) -}) - function validate(definition) { // Tack on a dummy coordinates to keep the schema happy. Tool summarizations do not have to include coordinates definition.coordinates = { type: 'npm', provider: 'npmjs', namespace: null, name: 'foo', revision: '1.0' } @@ -434,7 +338,9 @@ function setup(definition, coordinateSpec, curation) { const curator = { get: () => Promise.resolve(curation), apply: (_coordinates, _curationSpec, definition) => Promise.resolve(Curation.apply(definition, curation)), - autoCurate: () => { return } + autoCurate: () => { + return + } } const harvestStore = { getAll: () => Promise.resolve(null) } const harvestService = { harvest: () => sinon.stub() } @@ -446,17 +352,3 @@ function setup(definition, coordinateSpec, curation) { const coordinates = EntityCoordinates.fromString(coordinateSpec || 'npm/npmjs/-/test/1.0') return { coordinates, service } } - -function setupAggregator() { - const coordinates = EntityCoordinates.fromString('npm/npmjs/-/test/1.0') - const config = { precedence: [['tool1', 'tool2', 'tool3']] } - const service = AggregatorService(config) - return { service, coordinates } -} - -function setupAggregatorWithParams(coordSpec, tool_precedence) { - const coordinates = EntityCoordinates.fromString(coordSpec) - const config = { precedence: tool_precedence } - const service = AggregatorService(config) - return { service, coordinates } -} diff --git a/test/business/noticeServiceTest.js b/test/business/noticeServiceTest.js index 7b4e0f276..b2fb3f866 100644 --- a/test/business/noticeServiceTest.js +++ b/test/business/noticeServiceTest.js @@ -59,7 +59,6 @@ describe('Notice Service', () => { licensed: { declared: 'MIT' }, files: [{ path: 'LICENSE', token: 'abcd', natures: ['license'] }], described: { tools: ['clearlydefined/1.0.0'] } - }, 'npm/npmjs/-/tested/2.0.0': { coordinates: { name: 'tested', revision: '2.0.0' }, @@ -69,16 +68,18 @@ describe('Notice Service', () => { { path: 'LICENSE', token: 'ijkl', natures: ['license'] } ], described: { tools: ['clearlydefined/1.0.0'] } - }, + } }, { abcd: '%%%This is the attachment%%%', efgh: '%%%This should not be included!%%%', - ijkl: '%%%This should be included!%%%', + ijkl: '%%%This should be included!%%%' } ) const notice = await service.generate(coordinates) - expect(notice.content).to.eq('** tested; version 2.0.0 -- \n\n%%%This should be included!%%%\n\n------\n\n** tested; version 1.0.0 -- \n\n%%%This is the attachment%%%') + expect(notice.content).to.eq( + '** tested; version 2.0.0 -- \n\n%%%This should be included!%%%\n\n------\n\n** tested; version 1.0.0 -- \n\n%%%This is the attachment%%%' + ) }) it('renders with custom template', async () => { diff --git a/test/business/suggestionServiceTest.js b/test/business/suggestionServiceTest.js index e133327d6..2b269c0c9 100644 --- a/test/business/suggestionServiceTest.js +++ b/test/business/suggestionServiceTest.js @@ -103,16 +103,14 @@ describe('Suggestion Service', () => { }) }) - it('will include \'discovered\' licenses for declared license suggestions', async () => { + it("will include 'discovered' licenses for declared license suggestions", async () => { const t2 = EntityCoordinates.fromString('gem/rubygems/-/autobuild/1.6.2.b8') const sample_definition = require('./evidence/issue-453-sample-1.json') const service = setup(sample_definition, []) const suggestions = await service.get(t2) expect(suggestions).to.not.be.null const declared = get(suggestions, 'licensed.declared') - expect(declared).to.equalInAnyOrder([ - { value: 'GPL-2.0', version: '1.6.2.b8' } - ]) + expect(declared).to.equalInAnyOrder([{ value: 'GPL-2.0', version: '1.6.2.b8' }]) }) }) @@ -140,7 +138,7 @@ function createDefinition(coordinates, releaseDate, license, files) { } function setup(definition, others) { - const definitionService = { find: () => { } } + const definitionService = { find: () => {} } sinon.stub(definitionService, 'find').resolves({ data: [...others, definition] }) return SuggestionService(definitionService) } diff --git a/test/lib/coordinatesMapper.js b/test/lib/coordinatesMapper.js index 9802cca1e..8b9a756d7 100644 --- a/test/lib/coordinatesMapper.js +++ b/test/lib/coordinatesMapper.js @@ -13,13 +13,12 @@ function pypiCoordinates(name) { function fakeCache(cache) { return { get: key => cache[key], - set: (key, value) => cache[key] = value, + set: (key, value) => (cache[key] = value), size: () => Object.keys(cache).length } } describe('CoordinatesMapper', () => { - it('return coordinate when no mapper', async () => { const coordinates = pypiCoordinates('0_core_client') const mapped = await coordinatesMapper({}).map(coordinates) @@ -59,4 +58,4 @@ describe('CoordinatesMapper', () => { const mapped = await coordinatesMapper().map() expect(mapped).to.be.undefined }) -}) \ No newline at end of file +}) diff --git a/test/lib/curation.js b/test/lib/curation.js index b08fcc3d3..dc75ecfd4 100644 --- a/test/lib/curation.js +++ b/test/lib/curation.js @@ -100,7 +100,9 @@ describe('Curations', () => { const content = getFixture('curation-invalid.11.yaml') const curation = new Curation(content) expect(curation.isValid).to.be.false - expect(curation.errors[0].error).to.equal('/foo in 4.17.4 files with value "mit and apache-2.0" is not SPDX compliant') + expect(curation.errors[0].error).to.equal( + '/foo in 4.17.4 files with value "mit and apache-2.0" is not SPDX compliant' + ) }) it('should identify valid curations', () => { diff --git a/test/lib/entityCoordinates.js b/test/lib/entityCoordinates.js index d0bde38f3..fa0b7614f 100644 --- a/test/lib/entityCoordinates.js +++ b/test/lib/entityCoordinates.js @@ -27,5 +27,4 @@ describe('EntityCoordinates', () => { const coordinates = new EntityCoordinates('pypi', 'pypi', '-', 'NAME', 'REVISION') expect(coordinates.name).to.be.eq('name') }) - -}) \ No newline at end of file +}) diff --git a/test/lib/gradleCoordinatesMapper.js b/test/lib/gradleCoordinatesMapper.js index fceef55ed..ccd5ed194 100644 --- a/test/lib/gradleCoordinatesMapper.js +++ b/test/lib/gradleCoordinatesMapper.js @@ -1,7 +1,6 @@ // (c) Copyright 2021, SAP SE and ClearlyDefined contributors. Licensed under the MIT license. // SPDX-License-Identifier: MIT - const { expect } = require('chai') const sinon = require('sinon') const fs = require('fs') @@ -9,7 +8,6 @@ const EntityCoordinates = require('../../lib/entityCoordinates') const GradleCoordinatesMapper = require('../../lib/gradleCoordinatesMapper') describe('GradleCoordinatesMapper', () => { - let coordinatesMapper beforeEach(() => { coordinatesMapper = new GradleCoordinatesMapper() @@ -23,11 +21,15 @@ describe('GradleCoordinatesMapper', () => { }) it('spec without namespace', async () => { - const stub = sinon.stub(coordinatesMapper, '_handleRequest').resolves(fs.readFileSync('test/fixtures/maven/pom.xml')) + const stub = sinon + .stub(coordinatesMapper, '_handleRequest') + .resolves(fs.readFileSync('test/fixtures/maven/pom.xml')) const specWithoutNameSpace = 'maven/gradleplugin/-/org.springframework.boot/1.4.2.RELEASE' const mapped = await coordinatesMapper.map(EntityCoordinates.fromString(specWithoutNameSpace)) - stub.calledOn('https://plugins.gradle.org/m2/org/springframework/boot/org.springframework.boot.gradle.plugin/1.4.2.RELEASE/org.springframework.boot.gradle.plugin-1.4.2.RELEASE.pom') + stub.calledOn( + 'https://plugins.gradle.org/m2/org/springframework/boot/org.springframework.boot.gradle.plugin/1.4.2.RELEASE/org.springframework.boot.gradle.plugin-1.4.2.RELEASE.pom' + ) expect(mapped.namespace).to.be.eq('org.springframework.boot') expect(mapped.name).to.be.eq('spring-boot-gradle-plugin') expect(mapped.revision).to.be.eq('1.4.2.RELEASE') @@ -40,10 +42,13 @@ describe('GradleCoordinatesMapper', () => { }) it('spec without revision', async () => { - sinon.stub(coordinatesMapper, '_handleRequest') + sinon + .stub(coordinatesMapper, '_handleRequest') .withArgs('https://plugins.gradle.org/m2/pluginId/pluginId.gradle.plugin/maven-metadata.xml') .resolves(fs.readFileSync('test/fixtures/maven/maven-metadata.xml')) - .withArgs('https://plugins.gradle.org/m2/pluginId/pluginId.gradle.plugin/4.5.10/pluginId.gradle.plugin-4.5.10.pom') + .withArgs( + 'https://plugins.gradle.org/m2/pluginId/pluginId.gradle.plugin/4.5.10/pluginId.gradle.plugin-4.5.10.pom' + ) .resolves(fs.readFileSync('test/fixtures/maven/pom.xml')) const mapped = await coordinatesMapper.map(EntityCoordinates.fromString('maven/gradleplugin/-/pluginId')) expect(mapped.revision).not.to.be.ok @@ -52,7 +57,9 @@ describe('GradleCoordinatesMapper', () => { }) it('_getLatestVersion', async () => { - const stub = sinon.stub(coordinatesMapper, '_handleRequest').resolves(fs.readFileSync('test/fixtures/maven/maven-metadata.xml')) + const stub = sinon + .stub(coordinatesMapper, '_handleRequest') + .resolves(fs.readFileSync('test/fixtures/maven/maven-metadata.xml')) const latest = await coordinatesMapper._getLatestVersion({ name: 'pluginId' }) stub.calledOn('https://plugins.gradle.org/m2/pluginId/pluginId.gradle.plugin/maven-metadata.xml') expect(latest).to.be.equal('4.5.10') @@ -65,4 +72,4 @@ describe('GradleCoordinatesMapper', () => { stub.calledOn('https://plugins.gradle.org/m2/pluginId/pluginId.gradle.plugin/maven-metadata.xml') expect(retrieved).to.be.equal(metadata) }) -}) \ No newline at end of file +}) diff --git a/test/lib/licenseMatcher.js b/test/lib/licenseMatcher.js index 58a64d45b..8a3312943 100644 --- a/test/lib/licenseMatcher.js +++ b/test/lib/licenseMatcher.js @@ -1,6 +1,4 @@ -const { - LicenseMatcher, DefinitionLicenseMatchPolicy, HarvestLicenseMatchPolicy -} = require('../../lib/licenseMatcher') +const { LicenseMatcher, DefinitionLicenseMatchPolicy, HarvestLicenseMatchPolicy } = require('../../lib/licenseMatcher') const EntityCoordinates = require('../../lib/entityCoordinates') const { expect } = require('chai') @@ -10,10 +8,10 @@ describe('licenseMatcher.js', () => { const mismatch = { propPath: 'path.to.license.prop', source: 'license1', target: 'license2' } const matcher = new LicenseMatcher([ { - compare: () => ({ match: [{}], mismatch: [mismatch] }), + compare: () => ({ match: [{}], mismatch: [mismatch] }) }, { - compare: () => ({ match: [{}], mismatch: [] }), + compare: () => ({ match: [{}], mismatch: [] }) } ]) const result = matcher.process({}, {}) @@ -24,10 +22,10 @@ describe('licenseMatcher.js', () => { it('Should return NOT match if all policy returns empty mismatch and empty match', () => { const matcher = new LicenseMatcher([ { - compare: () => ({ match: [], mismatch: [] }), + compare: () => ({ match: [], mismatch: [] }) }, { - compare: () => ({ match: [], mismatch: [] }), + compare: () => ({ match: [], mismatch: [] }) } ]) const result = matcher.process({}, {}) @@ -40,10 +38,10 @@ describe('licenseMatcher.js', () => { const secondMatch = { policy: '2', propPath: 'path.to.license.prop2', value: 'license2' } const matcher = new LicenseMatcher([ { - compare: () => ({ match: [firstMatch], mismatch: [] }), + compare: () => ({ match: [firstMatch], mismatch: [] }) }, { - compare: () => ({ match: [secondMatch], mismatch: [] }), + compare: () => ({ match: [secondMatch], mismatch: [] }) } ]) const result = matcher.process({}, {}) @@ -57,21 +55,25 @@ describe('licenseMatcher.js', () => { it('Should return match array includes the same hashes.sha1', () => { const coordinates = { type: 'npm' } const sourceDefinition = { - 'files': [{ - 'path': 'package/LICENSE', - 'hashes': { - 'sha1': 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26', + files: [ + { + path: 'package/LICENSE', + hashes: { + sha1: 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26' + } } - }] + ] } const targetDefinition = { - 'files': [{ - 'path': 'package/LICENSE', - 'hashes': { - 'sha1': 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26', + files: [ + { + path: 'package/LICENSE', + hashes: { + sha1: 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26' + } } - }] + ] } const result = definitionLicenseMatchPolicy.compare( @@ -90,21 +92,25 @@ describe('licenseMatcher.js', () => { it('Should return match array includes the same hashes.sha256', () => { const coordinates = { type: 'pypi', name: 'foo', revision: '1.0.0' } const sourceDefinition = { - 'files': [{ - 'path': 'foo-1.0.0/LICENSE', - 'hashes': { - 'sha256': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d', + files: [ + { + path: 'foo-1.0.0/LICENSE', + hashes: { + sha256: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } } - }] + ] } const targetDefinition = { - 'files': [{ - 'path': 'foo-1.0.0/LICENSE', - 'hashes': { - 'sha256': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d', + files: [ + { + path: 'foo-1.0.0/LICENSE', + hashes: { + sha256: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } } - }] + ] } const result = definitionLicenseMatchPolicy.compare( @@ -123,17 +129,21 @@ describe('licenseMatcher.js', () => { it('Should return match array includes the same token', () => { const coordinates = { type: 'maven' } const sourceDefinition = { - 'files': [{ - 'path': 'meta-inf/LICENSE', - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }] + files: [ + { + path: 'meta-inf/LICENSE', + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } + ] } const targetDefinition = { - 'files': [{ - 'path': 'meta-inf/LICENSE', - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }] + files: [ + { + path: 'meta-inf/LICENSE', + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } + ] } const result = definitionLicenseMatchPolicy.compare( @@ -151,17 +161,21 @@ describe('licenseMatcher.js', () => { it('Should return empty match and mismatch array when no license files found', () => { const sourceDefinition = { - 'path': 'NOT-A-License-File', - 'files': [{ - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }] + path: 'NOT-A-License-File', + files: [ + { + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } + ] } const targetDefinition = { - 'path': 'NOT-A-License-File', - 'files': [{ - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }] + path: 'NOT-A-License-File', + files: [ + { + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } + ] } const result = definitionLicenseMatchPolicy.compare( @@ -174,21 +188,25 @@ describe('licenseMatcher.js', () => { it('Should return mismatch array when file license hashes.sha1 are different', () => { const sourceDefinition = { - 'files': [{ - 'path': 'license.md', - 'hashes': { - 'sha1': 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26', + files: [ + { + path: 'license.md', + hashes: { + sha1: 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26' + } } - }] + ] } const targetDefinition = { - 'files': [{ - 'path': 'license.md', - 'hashes': { - 'sha1': 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26-Diff', + files: [ + { + path: 'license.md', + hashes: { + sha1: 'dbf8c7e394791d3de9a9fff305d8ee7b59196f26-Diff' + } } - }] + ] } const result = definitionLicenseMatchPolicy.compare( @@ -208,24 +226,29 @@ describe('licenseMatcher.js', () => { it('Should return match array when all license file matched', () => { const coordinates = { type: 'maven' } const sourceDefinition = { - 'files': [{ - 'path': 'meta-inf/LICENSE', - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }, - { - 'path': 'LICENSE', - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }] + files: [ + { + path: 'meta-inf/LICENSE', + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + }, + { + path: 'LICENSE', + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } + ] } const targetDefinition = { - 'files': [{ - 'path': 'LICENSE', - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }, { - 'path': 'meta-inf/LICENSE', - 'token': 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }] + files: [ + { + path: 'LICENSE', + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + }, + { + path: 'meta-inf/LICENSE', + token: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } + ] } const result = definitionLicenseMatchPolicy.compare( @@ -233,17 +256,22 @@ describe('licenseMatcher.js', () => { { definition: { ...targetDefinition, coordinates } } ) - expect(result.match).to.have.lengthOf(2).and.have.deep.members([{ - policy: definitionLicenseMatchPolicy.name, - file: 'meta-inf/LICENSE', - propPath: 'token', - value: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d', - }, { - policy: definitionLicenseMatchPolicy.name, - file: 'LICENSE', - propPath: 'token', - value: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' - }]) + expect(result.match) + .to.have.lengthOf(2) + .and.have.deep.members([ + { + policy: definitionLicenseMatchPolicy.name, + file: 'meta-inf/LICENSE', + propPath: 'token', + value: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + }, + { + policy: definitionLicenseMatchPolicy.name, + file: 'LICENSE', + propPath: 'token', + value: 'd9fccda7d1daaec4c1a84d46b48d808e56ee8979c1b62ccc1492b7c27ab7010d' + } + ]) expect(result.mismatch).to.have.lengthOf(0) }) }) @@ -255,14 +283,10 @@ describe('licenseMatcher.js', () => { describe('Match maven package', () => { const sourceLicenses = [ { - 'license': [ + license: [ { - 'name': [ - 'The Apache License, Version 2.0' - ], - 'url': [ - 'http://www.apache.org/licenses/LICENSE-2.0.txt' - ] + name: ['The Apache License, Version 2.0'], + url: ['http://www.apache.org/licenses/LICENSE-2.0.txt'] } ] } @@ -270,14 +294,16 @@ describe('licenseMatcher.js', () => { function generateMavenDefinitionAndHarvest(revision, licenses) { return { definition: { - coordinates: EntityCoordinates.fromString(`maven/mavencentral/io.opentelemetry/opentelemetry-sdk-common/${revision}`) + coordinates: EntityCoordinates.fromString( + `maven/mavencentral/io.opentelemetry/opentelemetry-sdk-common/${revision}` + ) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.5.0': { - 'manifest': { - 'summary': { - 'licenses': licenses + manifest: { + summary: { + licenses: licenses } } }, @@ -302,14 +328,10 @@ describe('licenseMatcher.js', () => { it('Should return mismatch array includes harvest manifest.summary.licenses when they are NOT deep equal', () => { const targetLicenses = [ { - 'license': [ + license: [ { - 'name': [ - 'MIT' - ], - 'url': [ - 'https://opensource.org/licenses/MIT' - ] + name: ['MIT'], + url: ['https://opensource.org/licenses/MIT'] } ] } @@ -344,10 +366,10 @@ describe('licenseMatcher.js', () => { coordinates: EntityCoordinates.fromString(`crate/cratesio/-/libc/${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.2.0': { - 'registryData': { - 'license': license + registryData: { + license: license } } } @@ -401,11 +423,11 @@ describe('licenseMatcher.js', () => { coordinates: EntityCoordinates.fromString(`nuget/nuget/-/Microsoft.Identity.Web.MicrosoftGraph/${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.4.2': { - 'manifest': { - 'licenseUrl': licenseUrl, - 'licenseExpression': license + manifest: { + licenseUrl: licenseUrl, + licenseExpression: license } } } @@ -417,15 +439,20 @@ describe('licenseMatcher.js', () => { const source = generateNugetDefinitionAndHarvest('1.4.0', sourceLicense, sourceLicenseUrl) const target = generateNugetDefinitionAndHarvest('1.4.6', sourceLicense, sourceLicenseUrl) const result = harvestLicenseMatchPolicy.compare(source, target) - expect(result.match).to.have.lengthOf(2).and.have.deep.members([{ - policy: 'harvest', - propPath: 'manifest.licenseExpression', - value: sourceLicense - }, { - policy: 'harvest', - propPath: 'manifest.licenseUrl', - value: sourceLicenseUrl - }]) + expect(result.match) + .to.have.lengthOf(2) + .and.have.deep.members([ + { + policy: 'harvest', + propPath: 'manifest.licenseExpression', + value: sourceLicense + }, + { + policy: 'harvest', + propPath: 'manifest.licenseUrl', + value: sourceLicenseUrl + } + ]) expect(result.mismatch).to.have.lengthOf(0) }) @@ -434,12 +461,16 @@ describe('licenseMatcher.js', () => { const source = generateNugetDefinitionAndHarvest('1.4.0', sourceLicense) const target = generateNugetDefinitionAndHarvest('1.4.6', targetLicense) const result = harvestLicenseMatchPolicy.compare(source, target) - expect(result.mismatch).to.have.lengthOf(1).and.have.deep.members([{ - policy: 'harvest', - propPath: 'manifest.licenseExpression', - source: sourceLicense, - target: targetLicense - }]) + expect(result.mismatch) + .to.have.lengthOf(1) + .and.have.deep.members([ + { + policy: 'harvest', + propPath: 'manifest.licenseExpression', + source: sourceLicense, + target: targetLicense + } + ]) }) it('Should return mismatch array includes harvest manifest.licenseUrl when they are NOT deep equal', () => { @@ -447,12 +478,16 @@ describe('licenseMatcher.js', () => { const source = generateNugetDefinitionAndHarvest('1.4.0', undefined, sourceLicenseUrl) const target = generateNugetDefinitionAndHarvest('1.4.6', undefined, targetLicenseUrl) const result = harvestLicenseMatchPolicy.compare(source, target) - expect(result.mismatch).to.have.lengthOf(1).and.have.deep.members([{ - policy: 'harvest', - propPath: 'manifest.licenseUrl', - source: sourceLicenseUrl, - target: targetLicenseUrl - }]) + expect(result.mismatch) + .to.have.lengthOf(1) + .and.have.deep.members([ + { + policy: 'harvest', + propPath: 'manifest.licenseUrl', + source: sourceLicenseUrl, + target: targetLicenseUrl + } + ]) }) it('Should return empty match and mismatch array when harvest manifest.licenseExpression and manifest.licenseUrl are both undefined/null', () => { @@ -490,11 +525,11 @@ describe('licenseMatcher.js', () => { coordinates: EntityCoordinates.fromString(`npm/npmjs/-/mongoose/${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.1.2': { - 'registryData': { - 'manifest': { - 'license': license + registryData: { + manifest: { + license: license } } } @@ -539,20 +574,18 @@ describe('licenseMatcher.js', () => { }) describe('Match composer package', () => { - const sourceLicenses = [ - 'GPL-2.0+' - ] + const sourceLicenses = ['GPL-2.0+'] function generateComposerDefinitionAndHarvest(revision, licenses) { return { definition: { coordinates: EntityCoordinates.fromString(`composer/packagist/codeinwp/themeisle-sdk/$${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.2.0': { - 'registryData': { - 'manifest': { - 'license': licenses + registryData: { + manifest: { + license: licenses } } } @@ -574,9 +607,7 @@ describe('licenseMatcher.js', () => { }) it('Should return mismatch array includes harvest registryData.manifest.license when they are NOT deep equal', () => { - const targetLicenses = [ - 'GPL-2.0' - ] + const targetLicenses = ['GPL-2.0'] const source = generateComposerDefinitionAndHarvest('3.2.9', sourceLicenses) const target = generateComposerDefinitionAndHarvest('3.1.9', targetLicenses) const result = harvestLicenseMatchPolicy.compare(source, target) @@ -599,19 +630,17 @@ describe('licenseMatcher.js', () => { }) describe('Match gem package', () => { - const sourceLicenses = [ - 'Ruby' - ] + const sourceLicenses = ['Ruby'] function generateGemDefinitionAndHarvest(revision, licenses) { return { definition: { coordinates: EntityCoordinates.fromString(`gem/rubygems/-/reline/${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.3.3': { - 'registryData': { - 'licenses': licenses + registryData: { + licenses: licenses } } } @@ -632,9 +661,7 @@ describe('licenseMatcher.js', () => { }) it('Should return mismatch array includes harvest registryData.licenses when they are NOT deep equal', () => { - const targetLicenses = [ - 'Ruby License' - ] + const targetLicenses = ['Ruby License'] const source = generateGemDefinitionAndHarvest('0.2.1', sourceLicenses) const target = generateGemDefinitionAndHarvest('0.1.1', targetLicenses) const result = harvestLicenseMatchPolicy.compare(source, target) @@ -665,14 +692,14 @@ describe('licenseMatcher.js', () => { coordinates: EntityCoordinates.fromString(`pypi/pypi/-/distributed/${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.3.1': { - 'registryData': { - 'info': { - 'license': licenseInfo + registryData: { + info: { + license: licenseInfo } }, - 'declaredLicense': declaredLicense + declaredLicense: declaredLicense } } } @@ -683,15 +710,20 @@ describe('licenseMatcher.js', () => { const source = generatePypiDefinitionAndHarvest('2021.1.0', sourceLicenseInfo, sourceDeclaredLicense) const target = generatePypiDefinitionAndHarvest('1.25.3', sourceLicenseInfo, sourceDeclaredLicense) const result = harvestLicenseMatchPolicy.compare(source, target) - expect(result.match).to.have.lengthOf(2).and.have.deep.members([{ - policy: 'harvest', - propPath: 'registryData.info.license', - value: sourceLicenseInfo - }, { - policy: 'harvest', - propPath: 'declaredLicense', - value: sourceDeclaredLicense - }]) + expect(result.match) + .to.have.lengthOf(2) + .and.have.deep.members([ + { + policy: 'harvest', + propPath: 'registryData.info.license', + value: sourceLicenseInfo + }, + { + policy: 'harvest', + propPath: 'declaredLicense', + value: sourceDeclaredLicense + } + ]) expect(result.mismatch).to.have.lengthOf(0) }) @@ -700,12 +732,16 @@ describe('licenseMatcher.js', () => { const source = generatePypiDefinitionAndHarvest('2021.1.0', undefined, sourceDeclaredLicense) const target = generatePypiDefinitionAndHarvest('1.25.3', undefined, targetDeclaredLicense) const result = harvestLicenseMatchPolicy.compare(source, target) - expect(result.mismatch).to.have.lengthOf(1).and.have.deep.members([{ - policy: 'harvest', - propPath: 'declaredLicense', - source: sourceDeclaredLicense, - target: targetDeclaredLicense - }]) + expect(result.mismatch) + .to.have.lengthOf(1) + .and.have.deep.members([ + { + policy: 'harvest', + propPath: 'declaredLicense', + source: sourceDeclaredLicense, + target: targetDeclaredLicense + } + ]) }) it('Should return mismatch array includes harvest registryData.info.license when they are NOT deep equal', () => { @@ -713,12 +749,16 @@ describe('licenseMatcher.js', () => { const source = generatePypiDefinitionAndHarvest('2021.1.0', sourceLicenseInfo) const target = generatePypiDefinitionAndHarvest('1.25.3', targetLicenseInfo) const result = harvestLicenseMatchPolicy.compare(source, target) - expect(result.mismatch).to.have.lengthOf(1).and.have.deep.members([{ - policy: 'harvest', - propPath: 'registryData.info.license', - source: sourceLicenseInfo, - target: targetLicenseInfo - }]) + expect(result.mismatch) + .to.have.lengthOf(1) + .and.have.deep.members([ + { + policy: 'harvest', + propPath: 'registryData.info.license', + source: sourceLicenseInfo, + target: targetLicenseInfo + } + ]) }) it('Should return empty match and mismatch array when harvest declaredLicense and registryData.info.license are both undefined/null', () => { @@ -731,23 +771,16 @@ describe('licenseMatcher.js', () => { }) describe('Match deb package', () => { - const sourceLicenses = [ - 'AGPL-3', - 'MIT', - 'BSD-3-clause', - '(GPL-3 OR AGPL-3)', - 'PSF-2', - 'GPL-3' - ] + const sourceLicenses = ['AGPL-3', 'MIT', 'BSD-3-clause', '(GPL-3 OR AGPL-3)', 'PSF-2', 'GPL-3'] function generateDebDefinitionAndHarvest(revision, licenses) { return { definition: { coordinates: EntityCoordinates.fromString(`deb/debian/-/kopano-contacts/${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.2.1': { - 'declaredLicenses': licenses + declaredLicenses: licenses } } } @@ -767,13 +800,7 @@ describe('licenseMatcher.js', () => { }) it('Should return mismatch array includes harvest declaredLicense when they are NOT deep equal', () => { - const targetLicenses = [ - 'MIT', - 'BSD-3-clause', - '(GPL-3 OR AGPL-3)', - 'PSF-2', - 'GPL-3' - ] + const targetLicenses = ['MIT', 'BSD-3-clause', '(GPL-3 OR AGPL-3)', 'PSF-2', 'GPL-3'] const source = generateDebDefinitionAndHarvest('8.7.0-4_s390x', sourceLicenses) const target = generateDebDefinitionAndHarvest('8.7.0-3_amd64', targetLicenses) const result = harvestLicenseMatchPolicy.compare(source, target) @@ -796,22 +823,16 @@ describe('licenseMatcher.js', () => { }) describe('Match debsrc package', () => { - const sourceLicenses = [ - 'GPL-3.0+', - 'MIT', - 'GPL-2.0+', - 'AGPL-3.0', - 'BSD-3-clause' - ] + const sourceLicenses = ['GPL-3.0+', 'MIT', 'GPL-2.0+', 'AGPL-3.0', 'BSD-3-clause'] function generateDebDefinitionAndHarvest(revision, licenses) { return { definition: { coordinates: EntityCoordinates.fromString(`debsrc/debian/-/lava/${revision}`) }, harvest: { - 'clearlydefined': { + clearlydefined: { '1.3.1': { - 'declaredLicenses': licenses + declaredLicenses: licenses } } } @@ -831,12 +852,7 @@ describe('licenseMatcher.js', () => { }) it('Should return mismatch array includes harvest declaredLicense when they are NOT deep equal', () => { - const targetLicenses = [ - 'MIT', - 'GPL-2.0+', - 'AGPL-3.0', - 'BSD-3-clause' - ] + const targetLicenses = ['MIT', 'GPL-2.0+', 'AGPL-3.0', 'BSD-3-clause'] const source = generateDebDefinitionAndHarvest('2019.10-1', sourceLicenses) const target = generateDebDefinitionAndHarvest('2019.10-2', targetLicenses) const result = harvestLicenseMatchPolicy.compare(source, target) @@ -858,4 +874,4 @@ describe('licenseMatcher.js', () => { }) }) }) -}) \ No newline at end of file +}) diff --git a/test/lib/spdx.js b/test/lib/spdx.js index ee6038102..8b54d8f48 100644 --- a/test/lib/spdx.js +++ b/test/lib/spdx.js @@ -176,8 +176,20 @@ describe('SPDX utility functions', () => { ['MIT', [['MIT']]], ['MIT AND GPL-3.0', [['GPL-3.0', 'MIT']]], ['MIT OR GPL-3.0', [['MIT'], ['GPL-3.0']]], - ['MIT AND (GPL-3.0 OR BSD-3-Clause)', [['GPL-3.0', 'MIT'], ['BSD-3-Clause', 'MIT']]], - ['(MIT OR GPL-3.0) AND ISC', [['ISC', 'MIT'], ['GPL-3.0', 'ISC']]] + [ + 'MIT AND (GPL-3.0 OR BSD-3-Clause)', + [ + ['GPL-3.0', 'MIT'], + ['BSD-3-Clause', 'MIT'] + ] + ], + [ + '(MIT OR GPL-3.0) AND ISC', + [ + ['ISC', 'MIT'], + ['GPL-3.0', 'ISC'] + ] + ] ] data.forEach(input => { const results = SPDX.expand(input[0]) diff --git a/test/lib/util.js b/test/lib/util.js index 011b4c598..808b05784 100644 --- a/test/lib/util.js +++ b/test/lib/util.js @@ -10,7 +10,7 @@ const EntityCoordinates = require('../../lib/entityCoordinates') describe('Utils latest version', () => { it('should get the latest version', () => { const inputs = { - '1': ['1'], // https://github.com/clearlydefined/crawler/issues/124 + 1: ['1'], // https://github.com/clearlydefined/crawler/issues/124 '1.1.0': ['1', '1.0.1', '1.1.0'], // special handling for version = '1' '1.2.0': ['1', '1.2.0'], '2.0.0': ['2.0.0'], @@ -165,7 +165,10 @@ describe('Utils mergeDefinitions', () => { it('does not mess with existing entries', () => { const base = { described: { releaseDate: '2018-6-3' }, - files: [{ path: '1.txt', license: 'MIT' }, { path: '2.txt', license: 'GPL' }] + files: [ + { path: '1.txt', license: 'MIT' }, + { path: '2.txt', license: 'GPL' } + ] } const newDefinition = { described: { issueTracker: 'http://bugs' }, files: [{ path: '1.txt', token: '13' }] } utils.mergeDefinitions(base, newDefinition) @@ -269,8 +272,16 @@ describe('Copyright simplification', () => { describe('Utils isLicenseFile', () => { it('should detect root level license files', () => { const inputs = [ - 'LICENSE', 'license', 'License.txt', 'LICENSE.md', 'LICENSE.HTML', - 'COPYING', 'copying', 'copying.txt', 'COPYING.md', 'copying.html' + 'LICENSE', + 'license', + 'License.txt', + 'LICENSE.md', + 'LICENSE.HTML', + 'COPYING', + 'copying', + 'copying.txt', + 'COPYING.md', + 'copying.html' ] for (const input of inputs) { @@ -279,10 +290,7 @@ describe('Utils isLicenseFile', () => { }) it('should not detect nested license files without coordinates', () => { - const inputs = [ - 'package/LICENSE', 'licenses/license', - 'package/COPYING', 'licenses/copying' - ] + const inputs = ['package/LICENSE', 'licenses/license', 'package/COPYING', 'licenses/copying'] for (const input of inputs) { expect(utils.isLicenseFile(input), `input: ${input}`).to.be.false @@ -376,7 +384,7 @@ describe('Utils isLicenseFile', () => { 'package/copying', 'package/Copying.txt', 'package/COPYING.md', - 'package/COPYING.HTML', + 'package/COPYING.HTML' ] const coordinate = EntityCoordinates.fromString('nuget/nuget/-/redis/3.1') for (const input of inputs) { @@ -482,7 +490,7 @@ describe('Utils compareDates', () => { }) it('reverse sort non null dates', () => { - const sorted = ['2010-01-01', '1990-01-01', '2000-01-01'].sort((x, y) => (-utils.compareDates(x, y))) + const sorted = ['2010-01-01', '1990-01-01', '2000-01-01'].sort((x, y) => -utils.compareDates(x, y)) expect(sorted).to.deep.eq(['2010-01-01', '2000-01-01', '1990-01-01']) }) @@ -492,7 +500,7 @@ describe('Utils compareDates', () => { }) it('reverse sort null and non null: null last', () => { - const sorted = [null, '1990-01-01', null].sort((x, y) => (-utils.compareDates(x, y))) + const sorted = [null, '1990-01-01', null].sort((x, y) => -utils.compareDates(x, y)) expect(sorted).to.deep.eq(['1990-01-01', null, null]) }) }) @@ -509,7 +517,7 @@ describe('Utils toEntityCoordinatesFromRequest', () => { } before(function () { - sinon.replace(utils, 'toNormalizedEntityCoordinates', (entry) => Promise.resolve(entry)) + sinon.replace(utils, 'toNormalizedEntityCoordinates', entry => Promise.resolve(entry)) }) after(function () { @@ -570,7 +578,7 @@ describe('Utils parseNamespaceNameRevision', () => { revision: 'foo', extra1: 'bar', extra2: 'bah', - extra3: 'v3.1.0', + extra3: 'v3.1.0' } } @@ -592,7 +600,7 @@ describe('Utils getLicenseLocations', () => { } before(function () { - sinon.replace(utils, 'toNormalizedEntityCoordinates', (entry) => Promise.resolve(entry)) + sinon.replace(utils, 'toNormalizedEntityCoordinates', entry => Promise.resolve(entry)) }) after(function () { @@ -700,7 +708,9 @@ describe('Utils buildSourceUrl', () => { const coordinates = utils.toEntityCoordinatesFromArgs(args) const result = utils.buildSourceUrl(coordinates) - expect(result).to.eq('https://search.maven.org/remotecontent?filepath=clearlydefined/service/1.2.3/service-1.2.3-sources.jar') + expect(result).to.eq( + 'https://search.maven.org/remotecontent?filepath=clearlydefined/service/1.2.3/service-1.2.3-sources.jar' + ) }) it('returns the correct mavencentral source url with dots in the namespace', () => { @@ -715,8 +725,9 @@ describe('Utils buildSourceUrl', () => { const coordinates = utils.toEntityCoordinatesFromArgs(args) const result = utils.buildSourceUrl(coordinates) - expect(result).to.eq('https://search.maven.org/remotecontent?filepath=clearlydefined/foo/service/1.2.3/service-1.2.3-sources.jar') - + expect(result).to.eq( + 'https://search.maven.org/remotecontent?filepath=clearlydefined/foo/service/1.2.3/service-1.2.3-sources.jar' + ) }) it('returns the correct mavengoogle source url', () => { @@ -781,4 +792,4 @@ describe('Utils buildSourceUrl', () => { expect(result).to.eq('https://pypi.org/project/zuul/3.3.0/') }) -}) \ No newline at end of file +}) diff --git a/test/providers/caching/redis.js b/test/providers/caching/redis.js index 7ff44b65c..ab23c1e63 100644 --- a/test/providers/caching/redis.js +++ b/test/providers/caching/redis.js @@ -9,7 +9,7 @@ const redisCache = require('../../../providers/caching/redis') describe('get a tool result', () => { const store = {} - beforeEach(function() { + beforeEach(function () { sandbox.stub(redis, 'createClient').callsFake(() => { return { get: (key, callback) => callback(null, store[key]), @@ -25,7 +25,7 @@ describe('get a tool result', () => { }) }) - afterEach(function() { + afterEach(function () { sandbox.restore() }) diff --git a/test/providers/curation/github.js b/test/providers/curation/github.js index 113a60d91..8defc11b3 100644 --- a/test/providers/curation/github.js +++ b/test/providers/curation/github.js @@ -55,8 +55,9 @@ describe('Github Curation Service', () => { }) const curations = await service.getContributedCurations(42, 'testBranch') - service.logger = { // intercept and verify invalid contribution - error: (description) => { + service.logger = { + // intercept and verify invalid contribution + error: description => { expect(description).to.be.eq('Invalid curations: curations/sdfdsf/npmjs/test.yaml') } } @@ -65,7 +66,9 @@ describe('Github Curation Service', () => { expect(service._postCommitStatus.getCall(0).args[2]).to.be.eq('pending') expect(service._postCommitStatus.getCall(1).args[2]).to.be.eq('error') expect(service._postErrorsComment.calledOnce).to.be.true - expect(service._postErrorsComment.getCall(0).args[1]).to.be.eq('We discovered some errors in this curation when validating it:\n\nThis is an error\n') + expect(service._postErrorsComment.getCall(0).args[1]).to.be.eq( + 'We discovered some errors in this curation when validating it:\n\nThis is an error\n' + ) }) it('merges simple changes', async () => { @@ -259,7 +262,9 @@ describe('Github Curation Service', () => { const { service, harvestStore } = setup() sinon .stub(service, 'listAll') - .callsFake(() => [EntityCoordinates.fromObject({ type: 'npm', provider: 'npmjs', name: 'test', revision: '1.0' })]) + .callsFake(() => [ + EntityCoordinates.fromObject({ type: 'npm', provider: 'npmjs', name: 'test', revision: '1.0' }) + ]) sinon.stub(service, 'list').callsFake(() => [ 'npm/npmjs/-/test/1.0', // curated revision 'npm/npmjs/-/test/1.1', // license match on file @@ -282,12 +287,17 @@ describe('Github Curation Service', () => { const expectedResults = [ { version: '1.1', matchingProperties: [{ file: 'LICENSE.txt' }] }, { - version: '1.2', matchingProperties: [{ - propPath: 'registryData.manifest.license', - value: ['LICENSE METADATA'] - }] - }] - const expectedDescription = '- 1.1\n- 1.2\n\nMatching license file(s): LICENSE.txt\nMatching metadata: registryData.manifest.license: ["LICENSE METADATA"]' + version: '1.2', + matchingProperties: [ + { + propPath: 'registryData.manifest.license', + value: ['LICENSE METADATA'] + } + ] + } + ] + const expectedDescription = + '- 1.1\n- 1.2\n\nMatching license file(s): LICENSE.txt\nMatching metadata: registryData.manifest.license: ["LICENSE METADATA"]' const description = gitHubService._formatMultiversionCuratedRevisions(expectedResults) expect(description).to.be.deep.equal(expectedDescription) @@ -302,14 +312,14 @@ describe('Github Curation Service', () => { '(http://localhost:3000/curations/143)' ) - assert(startMatchingSpy.calledWith( - EntityCoordinates.fromObject(definitionCoordinates), - [ + assert( + startMatchingSpy.calledWith(EntityCoordinates.fromObject(definitionCoordinates), [ EntityCoordinates.fromString('npm/npmjs/-/test/1.1'), EntityCoordinates.fromString('npm/npmjs/-/test/1.2'), EntityCoordinates.fromString('npm/npmjs/-/test/1.3'), - EntityCoordinates.fromString('npm/npmjs/-/test/1.4'), - ])) + EntityCoordinates.fromString('npm/npmjs/-/test/1.4') + ]) + ) assert(calculateMatchingRevisionAndReasonSpy.calledWith(curatedCoordinates)) assert(formatRevisionsSpy.calledWith(expectedResults)) }) @@ -341,7 +351,7 @@ describe('Github Curation Service', () => { gitHubService = createService(service, licenseMatcher, harvestStore, {}, store) // TODO: Should not stub private functions and private properties sinon.stub(gitHubService, 'github').value({ - users: { get: sinon.stub() }, + users: { get: sinon.stub() } }) sinon.stub(gitHubService, '_addOrUpdate').resolves({ data: { number: 1 } @@ -389,10 +399,7 @@ describe('Github Curation Service', () => { beforeEach(() => { const definitionService = { - list: sinon.stub().resolves([ - 'npm/npmjs/-/express/5.0.0', - 'npm/npmjs/-/express/4.0.0' - ]), + list: sinon.stub().resolves(['npm/npmjs/-/express/5.0.0', 'npm/npmjs/-/express/4.0.0']), getStored: sinon.stub().resolves({ coordinates: EntityCoordinates.fromString('npm/npmjs/-/express/5.0.0') }) @@ -431,30 +438,40 @@ describe('Github Curation Service', () => { } matcherResult = { isMatching: true, - match: [{ - file: 'LICENSE.txt' - }, { - propPath: 'registryData.manifest.license', - value: 'LICENSE METADATA' - }] + match: [ + { + file: 'LICENSE.txt' + }, + { + propPath: 'registryData.manifest.license', + value: 'LICENSE METADATA' + } + ] } const coordinatesList = [EntityCoordinates.fromString('npm/npmjs/-/express')] const result = await gitHubService.reprocessMergedCurations(coordinatesList) expect(result).to.have.lengthOf(1) - expect(result).to.be.deep.includes.members([{ - coordinates: 'npm/npmjs/-/express', - contributions: [{ - coordinates: 'npm/npmjs/-/express/5.0.0', - contribution: 'www.curation.pr.com' - }] - }]) + expect(result).to.be.deep.includes.members([ + { + coordinates: 'npm/npmjs/-/express', + contributions: [ + { + coordinates: 'npm/npmjs/-/express/5.0.0', + contribution: 'www.curation.pr.com' + } + ] + } + ]) }) }) describe('verify _getBranchName', () => { before(function () { - sinon.replace(DateTime, 'now', sinon.stub().callsFake() - .returns(DateTime.fromFormat('211203_140949.712', 'yyMMdd_HHmmss.SSS'))) + sinon.replace( + DateTime, + 'now', + sinon.stub().callsFake().returns(DateTime.fromFormat('211203_140949.712', 'yyMMdd_HHmmss.SSS')) + ) }) after(function () { @@ -494,15 +511,24 @@ const complexCuration = { '1.0': { described: { releaseDate: '2018-10-19', projectWebsite: 'http://foo.com' }, licensed: { declared: 'Apache-2.0' }, - files: [{ path: '1.txt', license: 'MIT' }, { path: '2.txt', license: 'GPL' }] + files: [ + { path: '1.txt', license: 'MIT' }, + { path: '2.txt', license: 'GPL' } + ] } } } -function createService(definitionService = null, licenseMatcher = null, harvestStore = null, endpoints = { website: 'http://localhost:3000' }, store = CurationStore({})) { +function createService( + definitionService = null, + licenseMatcher = null, + harvestStore = null, + endpoints = { website: 'http://localhost:3000' }, + store = CurationStore({}) +) { const mockCache = { get: sinon.stub().resolves(undefined), - set: sinon.stub(), + set: sinon.stub() } require('../../../providers/logging/logger')({ error: sinon.stub(), @@ -555,7 +581,10 @@ const simpleHarvested = { const complexHarvested = { coordinates: definitionCoordinates, described: { releaseDate: '2018-08-09' }, - files: [{ path: '2.txt', token: '2 token' }, { path: '1.txt', token: '1 token' }] + files: [ + { path: '2.txt', token: '2 token' }, + { path: '1.txt', token: '1 token' } + ] } const complexHarvestedWithLicenses = { diff --git a/test/providers/curation/githubPRs.js b/test/providers/curation/githubPRs.js index abc549fed..d331374cc 100644 --- a/test/providers/curation/githubPRs.js +++ b/test/providers/curation/githubPRs.js @@ -21,7 +21,10 @@ function complexCuration(name = 'foo') { revisions: { '1.0': { described: { releaseDate: '2018-10-19', projectWebsite: `http://${name}.com` }, - files: [{ path: `${name}.1.txt`, license: 'MIT' }, { path: `${name}.2.txt`, license: 'GPL' }] + files: [ + { path: `${name}.1.txt`, license: 'MIT' }, + { path: `${name}.2.txt`, license: 'GPL' } + ] } } } @@ -71,8 +74,10 @@ describe('Curation service pr events', () => { expect(data).to.be.deep.equalInAnyOrder([complexCuration()]) const cacheDeleteSpy = service.cache.delete expect(cacheDeleteSpy.calledTwice).to.be.true - expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]) - .to.equalInAnyOrder(['cur_npm/npmjs/-/foo/1.0', 'cur_npm/npmjs/-/foo']) + expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]).to.equalInAnyOrder([ + 'cur_npm/npmjs/-/foo/1.0', + 'cur_npm/npmjs/-/foo' + ]) }).timeout(8000) // First time loading proxyquire('../../../providers/curation/github') is very slow. it('handles update', async () => { @@ -85,8 +90,10 @@ describe('Curation service pr events', () => { expect(data).to.be.deep.equalInAnyOrder([complexCuration()]) const cacheDeleteSpy = service.cache.delete expect(cacheDeleteSpy.calledTwice).to.be.true - expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]) - .to.equalInAnyOrder(['cur_npm/npmjs/-/foo/1.0', 'cur_npm/npmjs/-/foo']) + expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]).to.equalInAnyOrder([ + 'cur_npm/npmjs/-/foo/1.0', + 'cur_npm/npmjs/-/foo' + ]) }) it('handles merge', async () => { @@ -110,8 +117,10 @@ describe('Curation service pr events', () => { const cacheDeleteSpy = service.cache.delete expect(cacheDeleteSpy.calledTwice).to.be.true - expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]) - .to.equalInAnyOrder(['cur_npm/npmjs/-/foo/1.0', 'cur_npm/npmjs/-/foo']) + expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]).to.equalInAnyOrder([ + 'cur_npm/npmjs/-/foo/1.0', + 'cur_npm/npmjs/-/foo' + ]) const computeSpy = service.definitionService.computeAndStore expect(computeSpy.calledOnce).to.be.true @@ -126,8 +135,10 @@ describe('Curation service pr events', () => { expect(updateSpy.args[0][0].number).to.be.equal(12) const cacheDeleteSpy = service.cache.delete expect(cacheDeleteSpy.calledTwice).to.be.true - expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]) - .to.equalInAnyOrder(['cur_npm/npmjs/-/foo/1.0', 'cur_npm/npmjs/-/foo']) + expect([cacheDeleteSpy.args[0][0], cacheDeleteSpy.args[1][0]]).to.equalInAnyOrder([ + 'cur_npm/npmjs/-/foo/1.0', + 'cur_npm/npmjs/-/foo' + ]) }) it('handles list', async () => { diff --git a/test/providers/harvest/processTest.js b/test/providers/harvest/processTest.js index aa08fe4b0..8c9f1953b 100644 --- a/test/providers/harvest/processTest.js +++ b/test/providers/harvest/processTest.js @@ -29,7 +29,9 @@ describe('Harvest queue processing', () => { it('handles new message from non-clearlydefined tool', async () => { const { queue, definitionService, logger } = setup({ - _metadata: { links: { self: { href: 'urn:pypi:pypi:-:backports.ssl_match_hostname:revision:3.2a3:tool:scancode:3.2.2' } } } + _metadata: { + links: { self: { href: 'urn:pypi:pypi:-:backports.ssl_match_hostname:revision:3.2a3:tool:scancode:3.2.2' } } + } }) await process(queue, definitionService, logger, true) diff --git a/test/providers/search/memoryTest.js b/test/providers/search/memoryTest.js index a2e02caa6..325390108 100644 --- a/test/providers/search/memoryTest.js +++ b/test/providers/search/memoryTest.js @@ -20,7 +20,7 @@ describe('memory search tests', () => { } let memorySearch - before(() =>{ + before(() => { const definitions = Object.values(searches) .map(EntityCoordinates.fromString) .map(coordinates => ({ coordinates })) @@ -35,4 +35,4 @@ describe('memory search tests', () => { expect(result[0]).to.be.equal(value) }) }) -}) \ No newline at end of file +}) diff --git a/test/providers/store/abstractFileStore.js b/test/providers/store/abstractFileStore.js index 577f80c63..3a6987572 100644 --- a/test/providers/store/abstractFileStore.js +++ b/test/providers/store/abstractFileStore.js @@ -16,7 +16,7 @@ describe('AbstractFileStore lists entries ', () => { '/foo/npm/npmjs/-/test/revision/2.0/tool/testtool2/3.0.json': {} } - beforeEach(function() { + beforeEach(function () { const recursiveStub = async path => { path = path.replace(/\\/g, '/') if (path.includes('error')) throw new Error('test error') @@ -39,7 +39,7 @@ describe('AbstractFileStore lists entries ', () => { }) }) - afterEach(function() { + afterEach(function () { sandbox.restore() }) diff --git a/test/providers/store/dispatchDefinitionStore.js b/test/providers/store/dispatchDefinitionStore.js index ba128b2fe..ec98373a3 100644 --- a/test/providers/store/dispatchDefinitionStore.js +++ b/test/providers/store/dispatchDefinitionStore.js @@ -12,7 +12,7 @@ describe('Dispatch Definition store', () => { store1 = createStore() store2 = createStore() logger = { error: sinon.stub() } - dispatchDefinitionStore = DispatchDefinitionStore({ + dispatchDefinitionStore = DispatchDefinitionStore({ stores: [store1, store2], logger }) diff --git a/test/providers/store/mongoDefinition.js b/test/providers/store/mongoDefinition.js index a64ecb161..b37f7ed70 100644 --- a/test/providers/store/mongoDefinition.js +++ b/test/providers/store/mongoDefinition.js @@ -132,16 +132,19 @@ describe('Mongo Definition store', () => { it('builds a mongo query with continuationToken', () => { const store = createStore() const parameters = { namespace: '@owner', name: 'package' } - const sort = {'_mongo.partitionKey': 1} + const sort = { '_mongo.partitionKey': 1 } const continuationToken = 'bnBtL25wbWpzLy0vdmVycm9yLzEuMTAuMA' const expected = { - '$and': [{ - '_mongo.page': 1, - 'coordinates.name': 'package', - 'coordinates.namespace': '@owner' - }, { - '_mongo.partitionKey': { '$gt': 'npm/npmjs/-/verror/1.10.0' } - }] + $and: [ + { + '_mongo.page': 1, + 'coordinates.name': 'package', + 'coordinates.namespace': '@owner' + }, + { + '_mongo.partitionKey': { $gt: 'npm/npmjs/-/verror/1.10.0' } + } + ] } expect(store._buildQueryWithPaging(parameters, continuationToken, sort)).to.deep.equal(expected) @@ -153,11 +156,23 @@ describe('Mongo Definition store', () => { [{}, { '_mongo.partitionKey': 1 }], [{ sort: 'type' }, { 'coordinates.type': 1, '_mongo.partitionKey': 1 }], [{ sort: 'provider' }, { 'coordinates.provider': 1, '_mongo.partitionKey': 1 }], - [{ sort: 'name', sortDesc: true }, { 'coordinates.name': -1, 'coordinates.revision': -1, '_mongo.partitionKey': -1 }], - [{ sort: 'namespace' }, { 'coordinates.namespace': 1, 'coordinates.name': 1, 'coordinates.revision': 1, '_mongo.partitionKey': 1 }], - [{ sort: 'license', sortDesc: true }, { 'licensed.declared': -1, '_mongo.partitionKey': -1 }], + [ + { sort: 'name', sortDesc: true }, + { 'coordinates.name': -1, 'coordinates.revision': -1, '_mongo.partitionKey': -1 } + ], + [ + { sort: 'namespace' }, + { 'coordinates.namespace': 1, 'coordinates.name': 1, 'coordinates.revision': 1, '_mongo.partitionKey': 1 } + ], + [ + { sort: 'license', sortDesc: true }, + { 'licensed.declared': -1, '_mongo.partitionKey': -1 } + ], [{ sort: 'releaseDate' }, { 'described.releaseDate': 1, '_mongo.partitionKey': 1 }], - [{ sort: 'licensedScore', sortDesc: false }, { 'licensed.score.total': 1, '_mongo.partitionKey': 1 }], + [ + { sort: 'licensedScore', sortDesc: false }, + { 'licensed.score.total': 1, '_mongo.partitionKey': 1 } + ], [{ sort: 'describedScore' }, { 'described.score.total': 1, '_mongo.partitionKey': 1 }], [{ sort: 'effectiveScore' }, { 'scores.effective': 1, '_mongo.partitionKey': 1 }], [{ sort: 'toolScore' }, { 'scores.tool': 1, '_mongo.partitionKey': 1 }], @@ -172,14 +187,18 @@ describe('Mongo Definition store', () => { it('gets a continuationToken', () => { const store = createStore() - const sortClause = {'_mongo.partitionKey': 1} - const token = store._getContinuationToken(5, [ - { _mongo: { partitionKey: 'npm/npmjs/-/a/1.0.0' } }, - { _mongo: { partitionKey: 'npm/npmjs/-/b/1.0.0' } }, - { _mongo: { partitionKey: 'npm/npmjs/-/c/1.0.0' } }, - { _mongo: { partitionKey: 'npm/npmjs/-/d/1.0.0' } }, - { _mongo: { partitionKey: 'npm/npmjs/-/e/1.0.0' } } - ], sortClause) + const sortClause = { '_mongo.partitionKey': 1 } + const token = store._getContinuationToken( + 5, + [ + { _mongo: { partitionKey: 'npm/npmjs/-/a/1.0.0' } }, + { _mongo: { partitionKey: 'npm/npmjs/-/b/1.0.0' } }, + { _mongo: { partitionKey: 'npm/npmjs/-/c/1.0.0' } }, + { _mongo: { partitionKey: 'npm/npmjs/-/d/1.0.0' } }, + { _mongo: { partitionKey: 'npm/npmjs/-/e/1.0.0' } } + ], + sortClause + ) expect(token).to.eq('bnBtL25wbWpzLy0vZS8xLjAuMA==') }) @@ -192,16 +211,17 @@ describe('Mongo Definition store', () => { ]) expect(token).to.eq('') }) - + it('should call find with right arguments', async () => { const store = createStore() - store.collection.find = sinon.fake.returns({ toArray: () => Promise.resolve([])}) + store.collection.find = sinon.fake.returns({ toArray: () => Promise.resolve([]) }) await store.find({ type: 'npm' }) - const filter = { 'coordinates.type': 'npm','_mongo.page': 1 } + const filter = { 'coordinates.type': 'npm', '_mongo.page': 1 } const opts = { - 'projection': { '_id': 0, 'files': 0 }, - 'sort': { '_mongo.partitionKey': 1 }, - 'limit': 100 } + projection: { _id: 0, files: 0 }, + sort: { '_mongo.partitionKey': 1 }, + limit: 100 + } const findArgs = store.collection.find.firstCall.args expect(findArgs[0]).to.be.deep.equal(filter) expect(findArgs[1]).to.be.deep.equal(opts) @@ -238,7 +258,7 @@ function createStore(data) { insertMany: sinon.stub(), deleteMany: sinon.stub() } - const opts = { logger: { debug: () => {} }} + const opts = { logger: { debug: () => {} } } const store = Store(opts) store.collection = collectionStub return store diff --git a/test/providers/store/mongoDefinitionPagination.js b/test/providers/store/mongoDefinitionPagination.js index 5b28b1318..a3fb570b7 100644 --- a/test/providers/store/mongoDefinitionPagination.js +++ b/test/providers/store/mongoDefinitionPagination.js @@ -15,13 +15,12 @@ const dbOptions = { } } -const shouldPaginateSearchCorrectly = function() { - - describe('Mongo Definition Store: search pagination', function() { +const shouldPaginateSearchCorrectly = function () { + describe('Mongo Definition Store: search pagination', function () { const mongoServer = new MongoMemoryServer() let mongoStore - - before('setup database', async function() { + + before('setup database', async function () { await mongoServer.start() const uri = await mongoServer.getUri() const options = { @@ -32,16 +31,16 @@ const shouldPaginateSearchCorrectly = function() { mongoStore = await this.createStore(options, defs) }) - after('cleanup database', async function() { + after('cleanup database', async function () { await mongoStore.collection.drop() await mongoStore.close() await mongoServer.stop() }) - it('should fetch records without sort continuously', async function() { + it('should fetch records without sort continuously', async function () { const expected = [ - 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', - 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', + 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', + 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', 'maven/mavencentral/io.jenetics/jenetics/7.1.1', 'maven/mavencentral/io.quarkiverse.cxf/quarkus-cxf/1.5.4', 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-alpha5' @@ -52,8 +51,8 @@ const shouldPaginateSearchCorrectly = function() { const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - - it('should sort ascending on releaseDate and find 1 page of records', async function() { + + it('should sort ascending on releaseDate and find 1 page of records', async function () { const expected = ['maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-alpha5'] const query = { sort: 'releaseDate', @@ -64,15 +63,16 @@ const shouldPaginateSearchCorrectly = function() { const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - - it('should sort ascending on releaseDate and handle null and non null values in continuation', async function() { + + it('should sort ascending on releaseDate and handle null and non null values in continuation', async function () { const expected = [ - 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-alpha5', - 'maven/mavencentral/org.flywaydb/flyway-maven-plugin/5.0.7', - 'npm/npmjs/@sinclair/typebox/0.24.45', + 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-alpha5', + 'maven/mavencentral/org.flywaydb/flyway-maven-plugin/5.0.7', + 'npm/npmjs/@sinclair/typebox/0.24.45', 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-beta2', - 'pypi/pypi/-/backports.ssl_match_hostname/3.5.0.1'] - + 'pypi/pypi/-/backports.ssl_match_hostname/3.5.0.1' + ] + const query = { sort: 'releaseDate', sortDesc: false @@ -80,13 +80,13 @@ const shouldPaginateSearchCorrectly = function() { const defs = await fetchAll(mongoStore, query) expect(defs[0].described.releaseDate).not.to.be.ok expect(defs[3].described.releaseDate).to.be.ok - + expect(defs.length).to.be.equal(12) const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - - it('should sort descending on releaseDate and handle null and non null values in continuation', async function() { + + it('should sort descending on releaseDate and handle null and non null values in continuation', async function () { const query = { sort: 'releaseDate', sortDesc: true @@ -95,15 +95,16 @@ const shouldPaginateSearchCorrectly = function() { expect(defs.length).to.be.equal(12) verifyUniqueCoordinates(defs) }) - - it('should sort ascending on license and handle null and non null values in continuation ', async function() { + + it('should sort ascending on license and handle null and non null values in continuation ', async function () { const expected = [ - 'npm/npmjs/@sinclair/typebox/0.24.45', - 'maven/mavencentral/io.jenetics/jenetics/7.1.1', - 'maven/mavencentral/io.quarkiverse.cxf/quarkus-cxf/1.5.4', - 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-alpha5', - 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-beta2'] - + 'npm/npmjs/@sinclair/typebox/0.24.45', + 'maven/mavencentral/io.jenetics/jenetics/7.1.1', + 'maven/mavencentral/io.quarkiverse.cxf/quarkus-cxf/1.5.4', + 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-alpha5', + 'maven/mavencentral/org.apache.httpcomponents/httpcore/4.0-beta2' + ] + const query = { sort: 'license', sortDesc: false @@ -115,8 +116,8 @@ const shouldPaginateSearchCorrectly = function() { const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - - it('should sort descending on license and handle null and non null values in continuation ', async function() { + + it('should sort descending on license and handle null and non null values in continuation ', async function () { const query = { sort: 'license', sortDesc: true @@ -125,14 +126,15 @@ const shouldPaginateSearchCorrectly = function() { expect(defs.length).to.be.equal(12) verifyUniqueCoordinates(defs) }) - - it('should filter and sort ascending on multiple keys and handle null and non null namespace in continuation', async function() { + + it('should filter and sort ascending on multiple keys and handle null and non null namespace in continuation', async function () { const expected = [ - 'npm/npmjs/-/angular/1.6.9', - 'npm/npmjs/-/redie/0.3.0', - 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', - 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca'] - + 'npm/npmjs/-/angular/1.6.9', + 'npm/npmjs/-/redie/0.3.0', + 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', + 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca' + ] + const query = { license: 'MIT', sort: 'namespace', @@ -145,14 +147,15 @@ const shouldPaginateSearchCorrectly = function() { const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - - it('should filter and sort descending on multiple keys in continuation', async function() { + + it('should filter and sort descending on multiple keys in continuation', async function () { const expected = [ 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', - 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', - 'npm/npmjs/-/redie/0.3.0', - 'npm/npmjs/-/angular/1.6.9'] - + 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', + 'npm/npmjs/-/redie/0.3.0', + 'npm/npmjs/-/angular/1.6.9' + ] + const query = { license: 'MIT', sort: 'namespace', @@ -163,14 +166,15 @@ const shouldPaginateSearchCorrectly = function() { const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - - it('should filter and sort on numerical scores and fetch continuously', async function() { + + it('should filter and sort on numerical scores and fetch continuously', async function () { const expected = [ - 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', - 'npm/npmjs/-/angular/1.6.9', - 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', - 'npm/npmjs/-/redie/0.3.0'] - + 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0', + 'npm/npmjs/-/angular/1.6.9', + 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', + 'npm/npmjs/-/redie/0.3.0' + ] + const query = { license: 'MIT', sort: 'toolScore', @@ -185,15 +189,15 @@ const shouldPaginateSearchCorrectly = function() { const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - - it('should filter and sort descending on numerical scores and fetch continuously', async function() { + + it('should filter and sort descending on numerical scores and fetch continuously', async function () { const expected = [ 'npm/npmjs/-/redie/0.3.0', - 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', - 'npm/npmjs/-/angular/1.6.9', + 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', + 'npm/npmjs/-/angular/1.6.9', 'maven/mavencentral/com.azure/azure-storage-blob/12.20.0' ] - + const query = { license: 'MIT', sort: 'toolScore', @@ -204,7 +208,6 @@ const shouldPaginateSearchCorrectly = function() { const coordinates = verifyUniqueCoordinates(defs) verifyExpectedCoordinates(coordinates, expected) }) - }) } @@ -233,7 +236,7 @@ async function fetchAll(mongoStore, query, pageSize) { //Default pageSize set to 1 to verify null value handling async function fetchUpToNTimes(mongoStore, query, nTimes, pageSize = 1) { const allData = [] - const fetchOperation = async (params) => { + const fetchOperation = async params => { const { continuationToken, ...query } = params const result = await mongoStore.find(query, continuationToken, pageSize) allData.push(...result.data) @@ -265,16 +268,18 @@ class ContinousFetch { } async fetchUpToNtimes(params, nTime) { - let dispatchCounter = 0, fetchedCounter = 0 + let dispatchCounter = 0, + fetchedCounter = 0 let retrieved = {} while (dispatchCounter < nTime) { retrieved = await this._delayedFetch({ ...params, - continuationToken: retrieved.continuationToken }) + continuationToken: retrieved.continuationToken + }) fetchedCounter += retrieved.count - dispatchCounter ++ + dispatchCounter++ if (!retrieved.continuationToken) break } @@ -282,4 +287,4 @@ class ContinousFetch { } } -module.exports = shouldPaginateSearchCorrectly \ No newline at end of file +module.exports = shouldPaginateSearchCorrectly diff --git a/test/providers/store/pagedDefinitionPagination.js b/test/providers/store/pagedDefinitionPagination.js index f0c409d79..a446923b3 100644 --- a/test/providers/store/pagedDefinitionPagination.js +++ b/test/providers/store/pagedDefinitionPagination.js @@ -5,12 +5,11 @@ const Store = require('../../../providers/stores/mongo') const shouldPaginateSearchCorrectly = require('./mongoDefinitionPagination') const dbOptions = { - collectionName: 'definitions-paged', + collectionName: 'definitions-paged' } -describe('Mongo Definition Store: Paged', function() { - - before('setup store factory', async function() { +describe('Mongo Definition Store: Paged', function () { + before('setup store factory', async function () { this.createStore = createStore }) diff --git a/test/providers/store/trimmedDefinitionPagination.js b/test/providers/store/trimmedDefinitionPagination.js index 95af5d9cf..9de88d87f 100644 --- a/test/providers/store/trimmedDefinitionPagination.js +++ b/test/providers/store/trimmedDefinitionPagination.js @@ -8,9 +8,8 @@ const dbOptions = { collectionName: 'definitions-trimmed' } -describe('Mongo Definition Store: Trimmed', function() { - - before('setup store factory', async function() { +describe('Mongo Definition Store: Trimmed', function () { + before('setup store factory', async function () { this.createStore = createStore }) diff --git a/test/providers/store/trimmedMongoDefinitionStore.js b/test/providers/store/trimmedMongoDefinitionStore.js index 0bef101b2..700fbd604 100644 --- a/test/providers/store/trimmedMongoDefinitionStore.js +++ b/test/providers/store/trimmedMongoDefinitionStore.js @@ -15,8 +15,8 @@ const dbOptions = { dbName: 'clearlydefined', collectionName: 'definitions-trimmed', logger: { - debug: () => {}, - }, + debug: () => {} + } } describe('Trimmed Mongo Definition store', () => { @@ -28,7 +28,7 @@ describe('Trimmed Mongo Definition store', () => { const uri = await mongoServer.getUri() const options = { ...dbOptions, - connectionString: uri, + connectionString: uri } mongoStore = TrimmedMongoDefinitionStore(options) await mongoStore.initialize() @@ -97,7 +97,7 @@ describe('Trimmed Mongo Definition store', () => { expect(defs.data.length).to.be.eq(0) }) }) - + describe('find', () => { it('should call find with right arguments', async () => { mongoStore.collection.find = sinon.fake.returns({ toArray: () => Promise.resolve([]) }) @@ -107,13 +107,13 @@ describe('Trimmed Mongo Definition store', () => { const opts = { projection: undefined, sort: { _id: 1 }, - limit: 100, + limit: 100 } const findArgs = mongoStore.collection.find.firstCall.args expect(findArgs[0]).to.be.deep.equal(filter) expect(findArgs[1]).to.be.deep.equal(opts) }) - + it('should find one page of records', async () => { const expected = [ 'git/github/microsoft/redie/194269b5b7010ad6f8dc4ef608c88128615031ca', @@ -136,7 +136,7 @@ describe('Trimmed Mongo Definition store', () => { expect(defs1.continuationToken).to.be.ok const defs2 = await mongoStore.find(query, defs1.continuationToken, 7) expect(defs2.continuationToken).to.be.not.ok - const allDefs = [ ...defs1.data, ...defs2.data] + const allDefs = [...defs1.data, ...defs2.data] const coordinates = verifyUniqueCoordinates(allDefs) expect(coordinates.length).to.be.equal(12) }) @@ -171,34 +171,49 @@ describe('Trimmed Mongo Definition store', () => { it('builds a mongo query with continuationToken', () => { const parameters = { namespace: '@owner', name: 'package' } - const sort = {'_id': 1} + const sort = { _id: 1 } const continuationToken = 'bnBtL25wbWpzLy0vdmVycm9yLzEuMTAuMA' const expected = { - '$and': [{ - 'coordinates.name': 'package', - 'coordinates.namespace': '@owner' - }, { - '_id': { '$gt': 'npm/npmjs/-/verror/1.10.0' } - }] + $and: [ + { + 'coordinates.name': 'package', + 'coordinates.namespace': '@owner' + }, + { + _id: { $gt: 'npm/npmjs/-/verror/1.10.0' } + } + ] } - + expect(mongoStore._buildQueryWithPaging(parameters, continuationToken, sort)).to.deep.equal(expected) }) it('builds a mongo sort', () => { const data = new Map([ - [{}, { '_id': 1 }], - [{ sort: 'type' }, { 'coordinates.type': 1, '_id': 1 }], - [{ sort: 'provider' }, { 'coordinates.provider': 1, '_id': 1 }], - [{ sort: 'name', sortDesc: true }, { 'coordinates.name': -1, 'coordinates.revision': -1, '_id': -1 }], - [{ sort: 'namespace' }, { 'coordinates.namespace': 1, 'coordinates.name': 1, 'coordinates.revision': 1, '_id': 1 }], - [{ sort: 'license', sortDesc: true }, { 'licensed.declared': -1, '_id': -1 }], - [{ sort: 'releaseDate' }, { 'described.releaseDate': 1, '_id': 1 }], - [{ sort: 'licensedScore', sortDesc: false }, { 'licensed.score.total': 1, '_id': 1 }], - [{ sort: 'describedScore' }, { 'described.score.total': 1, '_id': 1 }], - [{ sort: 'effectiveScore' }, { 'scores.effective': 1, '_id': 1 }], - [{ sort: 'toolScore' }, { 'scores.tool': 1, '_id': 1 }], - [{ sort: 'revision' }, { 'coordinates.revision': 1, '_id': 1 }] + [{}, { _id: 1 }], + [{ sort: 'type' }, { 'coordinates.type': 1, _id: 1 }], + [{ sort: 'provider' }, { 'coordinates.provider': 1, _id: 1 }], + [ + { sort: 'name', sortDesc: true }, + { 'coordinates.name': -1, 'coordinates.revision': -1, _id: -1 } + ], + [ + { sort: 'namespace' }, + { 'coordinates.namespace': 1, 'coordinates.name': 1, 'coordinates.revision': 1, _id: 1 } + ], + [ + { sort: 'license', sortDesc: true }, + { 'licensed.declared': -1, _id: -1 } + ], + [{ sort: 'releaseDate' }, { 'described.releaseDate': 1, _id: 1 }], + [ + { sort: 'licensedScore', sortDesc: false }, + { 'licensed.score.total': 1, _id: 1 } + ], + [{ sort: 'describedScore' }, { 'described.score.total': 1, _id: 1 }], + [{ sort: 'effectiveScore' }, { 'scores.effective': 1, _id: 1 }], + [{ sort: 'toolScore' }, { 'scores.tool': 1, _id: 1 }], + [{ sort: 'revision' }, { 'coordinates.revision': 1, _id: 1 }] ]) data.forEach((expected, input) => { const result = mongoStore._buildSort(input) @@ -242,14 +257,18 @@ describe('Trimmed Mongo Definition store', () => { }) it('gets a continuationToken', () => { - const sortClause = {'_id': 1} - const token = mongoStore._getContinuationToken(5, [ - { _id: 'npm/npmjs/-/a/1.0.0' }, - { _id: 'npm/npmjs/-/b/1.0.0' }, - { _id: 'npm/npmjs/-/c/1.0.0' }, - { _id: 'npm/npmjs/-/d/1.0.0' }, - { _id: 'npm/npmjs/-/e/1.0.0' } - ], sortClause) + const sortClause = { _id: 1 } + const token = mongoStore._getContinuationToken( + 5, + [ + { _id: 'npm/npmjs/-/a/1.0.0' }, + { _id: 'npm/npmjs/-/b/1.0.0' }, + { _id: 'npm/npmjs/-/c/1.0.0' }, + { _id: 'npm/npmjs/-/d/1.0.0' }, + { _id: 'npm/npmjs/-/e/1.0.0' } + ], + sortClause + ) expect(token).to.eq('bnBtL25wbWpzLy0vZS8xLjAuMA==') }) @@ -266,18 +285,18 @@ describe('Trimmed Mongo Definition store', () => { describe('trimmed vs. paged definition', () => { let pagedMongoStore - + beforeEach('setup database', async () => { const uri = await mongoServer.getUri() const options = { ...dbOptions, connectionString: uri, - collectionName: 'definitions-paged', + collectionName: 'definitions-paged' } pagedMongoStore = PagedMongoDefinitionStore(options) await pagedMongoStore.initialize() }) - + afterEach('cleanup database', async () => { await pagedMongoStore.close() }) @@ -298,7 +317,7 @@ describe('Trimmed Mongo Definition store', () => { async function setupStore(mongoStore) { const fileName = path.join(__dirname, '../../fixtures/store/definitions-paged-no-files') const content = await fsPromise.readFile(fileName) - const defDump = JSON.parse(content.toString()).map((def) => { + const defDump = JSON.parse(content.toString()).map(def => { delete def._mongo return def }) @@ -311,7 +330,7 @@ function verifyExpectedCoordinates(allCoordinates, expected) { } function verifyUniqueCoordinates(defs) { - const allCoordinates = defs.map((e) => EntityCoordinates.fromObject(e.coordinates).toString()) + const allCoordinates = defs.map(e => EntityCoordinates.fromObject(e.coordinates).toString()) const uniqTokens = uniq(allCoordinates) expect(uniqTokens.length).to.be.equal(allCoordinates.length) return allCoordinates @@ -319,7 +338,7 @@ function verifyUniqueCoordinates(defs) { function createDefinition(coordinates) { coordinates = EntityCoordinates.fromString(coordinates) - return { + return { coordinates, described: {}, licensed: {}, @@ -327,4 +346,4 @@ function createDefinition(coordinates) { _meta: {}, files: [{ path: '1' }, { path: '2' }] } -} \ No newline at end of file +} diff --git a/test/providers/summary/scancode.js b/test/providers/summary/scancode.js index e1adceaa1..055b7ce6f 100644 --- a/test/providers/summary/scancode.js +++ b/test/providers/summary/scancode.js @@ -20,9 +20,9 @@ describe('ScancodeSummarizer basic compatability', () => { const result = summarizer.summarize(coordinates, harvestData) assert.equal(result.licensed.declared, 'ISC', `Declared license mismatch for version ${version}`) assert.equal(result.described.releaseDate, '2017-05-19', `releaseDate mismatch for version ${version}`) - assert.deepEqual(uniq(flatten(result.files.map((x) => x.attributions))).filter((x) => x).length, 1) - assert.deepEqual(result.files.find((x) => x.path === 'package/LICENSE').natures, ['license']) - assert.equal(flatten(result.files.map((x) => x.natures)).filter((x) => x).length, 1) + assert.deepEqual(uniq(flatten(result.files.map(x => x.attributions))).filter(x => x).length, 1) + assert.deepEqual(result.files.find(x => x.path === 'package/LICENSE').natures, ['license']) + assert.equal(flatten(result.files.map(x => x.natures)).filter(x => x).length, 1) } }) @@ -46,9 +46,9 @@ describe('ScancodeSummarizer basic compatability', () => { `Declared license mismatch for version ${version}` ) assert.equal(result.described.releaseDate, '2018-03-31', `releaseDate mismatch for version ${version}`) - assert.deepEqual(uniq(flatten(result.files.map((x) => x.attributions))).filter((x) => x).length, 33) - assert.deepEqual(result.files.find((x) => x.path === 'package/LICENSE').natures, ['license']) - assert.equal(flatten(result.files.map((x) => x.natures)).filter((x) => x).length, 1) + assert.deepEqual(uniq(flatten(result.files.map(x => x.attributions))).filter(x => x).length, 33) + assert.deepEqual(result.files.find(x => x.path === 'package/LICENSE').natures, ['license']) + assert.equal(flatten(result.files.map(x => x.natures)).filter(x => x).length, 1) } }) @@ -134,9 +134,9 @@ describe('ScancodeSummarizer basic compatability', () => { undefinedOverrides.indexOf(version) > -1 ? undefined : 'MIT', `Declared license mismatch for version ${version}` ) - assert.equal(result.files.find((x) => x.path === 'MIT-LICENSE.md').license, 'MIT') + assert.equal(result.files.find(x => x.path === 'MIT-LICENSE.md').license, 'MIT') assert.equal(result.described.releaseDate, '2018-08-09', `releaseDate mismatch for version ${version}`) - assert.deepEqual(uniq(flatten(result.files.map((x) => x.attributions))).filter((x) => x).length, 3) + assert.deepEqual(uniq(flatten(result.files.map(x => x.attributions))).filter(x => x).length, 3) } }) @@ -148,9 +148,9 @@ describe('ScancodeSummarizer basic compatability', () => { const result = summarizer.summarize(coordinates, harvestData) assert.equal(result.licensed.declared, 'ISC', `Declared license mismatch for version ${version}`) assert.equal(result.described.releaseDate, '2017-02-24', `releaseDate mismatch for version ${version}`) - assert.deepEqual(uniq(flatten(result.files.map((x) => x.attributions))).filter((x) => x).length, 1) - assert.deepEqual(result.files.find((x) => x.path === 'LICENSE').natures, ['license']) - assert.equal(flatten(result.files.map((x) => x.natures)).filter((x) => x).length, 1) + assert.deepEqual(uniq(flatten(result.files.map(x => x.attributions))).filter(x => x).length, 1) + assert.deepEqual(result.files.find(x => x.path === 'LICENSE').natures, ['license']) + assert.equal(flatten(result.files.map(x => x.natures)).filter(x => x).length, 1) } }) @@ -162,9 +162,9 @@ describe('ScancodeSummarizer basic compatability', () => { const result = summarizer.summarize(coordinates, harvestData) assert.equal(result.licensed.declared, 'MIT', `Declared license mismatch for version ${version}`) assert.equal(result.described.releaseDate, '2018-11-15', `releaseDate mismatch for version ${version}`) - assert.deepEqual(uniq(flatten(result.files.map((x) => x.attributions))).filter((x) => x).length, 1) - assert.deepEqual(result.files.find((x) => x.path === 'redis-3.0.1/LICENSE').natures, ['license']) - assert.equal(flatten(result.files.map((x) => x.natures)).filter((x) => x).length, 1) + assert.deepEqual(uniq(flatten(result.files.map(x => x.attributions))).filter(x => x).length, 1) + assert.deepEqual(result.files.find(x => x.path === 'redis-3.0.1/LICENSE').natures, ['license']) + assert.equal(flatten(result.files.map(x => x.natures)).filter(x => x).length, 1) } }) }) @@ -234,9 +234,9 @@ describe('ScancodeSummarizer fixtures', () => { assert.deepEqual(result.described, { releaseDate: '2019-01-31' }) assert.deepEqual(result.licensed, { declared: 'NOASSERTION' }) assert.deepEqual(result.files.length, 576) - assert.deepEqual(uniq(flatten(result.files.map((x) => x.attributions))).filter((x) => x).length, 21) + assert.deepEqual(uniq(flatten(result.files.map(x => x.attributions))).filter(x => x).length, 21) assert.deepEqual( - result.files.filter((x) => x.natures), + result.files.filter(x => x.natures), [ { path: 'LICENSE', diff --git a/test/routes/definitions-1.0.0.js b/test/routes/definitions-1.0.0.js index f339845e0..936199db5 100644 --- a/test/routes/definitions-1.0.0.js +++ b/test/routes/definitions-1.0.0.js @@ -58,4 +58,3 @@ function createDefinitionService() { get: sinon.stub() } } - diff --git a/test/routes/definitions.js b/test/routes/definitions.js index 79b9cbd22..de7a17daf 100644 --- a/test/routes/definitions.js +++ b/test/routes/definitions.js @@ -38,7 +38,7 @@ function createGetRequest() { type: 'crate', provider: 'cratesio', namespace: '-', - revision: '1.0.14', + revision: '1.0.14' } }) } @@ -52,7 +52,7 @@ function createGetForceComputeRequest() { type: 'crate', provider: 'cratesio', namespace: '-', - revision: '1.0.14', + revision: '1.0.14' }, query: { force: true diff --git a/test/routes/harvest.js b/test/routes/harvest.js index dbdfc97f3..87f05724b 100644 --- a/test/routes/harvest.js +++ b/test/routes/harvest.js @@ -98,4 +98,4 @@ function createGetRequest(entries) { url: '/', params: entries }) -} \ No newline at end of file +} diff --git a/test/routes/origins.js b/test/routes/origins.js new file mode 100644 index 000000000..367f6726f --- /dev/null +++ b/test/routes/origins.js @@ -0,0 +1,66 @@ +// Copyright (c) The Linux Foundation and others. Licensed under the MIT license. +// SPDX-License-Identifier: MIT + +const { expect } = require('chai') +const httpMocks = require('node-mocks-http') +const sinon = require('sinon') +const originCondaRoutes = require('../../routes/originConda') + +describe('Conda origin routes', () => { + it('accepts a good revisions GET request', async () => { + const request = createGetOriginCondaRevisionsRequest() + const response = httpMocks.createResponse() + const stubCondaCache = createStubCondaCache({ + 'conda-forge-linux-64-repoData': { + packages: [ + { + name: 'tensorflow', + version: '2.15.0', + build: 'cuda120py39hb94c71b_3' + } + ], + subdirs: ['linux-64'] + }, + 'conda-forge-channelData': { + packages: { + tensorflow: {} + }, + subdirs: ['linux-64'] + } + }) + const router = createRoutes(stubCondaCache) + await router._getOriginCondaRevisions(request, response) + expect(response.statusCode).to.be.eq(200) + expect(response._getData()).to.be.deep.equal(['linux-64:2.15.0-cuda120py39hb94c71b_3']) + expect(stubCondaCache.get.calledTwice).to.be.true + }) +}) + +function createGetOriginCondaRevisionsRequest() { + return httpMocks.createRequest({ + method: 'GET', + url: 'origins/conda/conda-forge/linux-64/tensorflow/revisions', + baseUrl: 'https://dev.clearlydefined.io', + params: { + channel: 'conda-forge', + subdir: 'linux-64', + name: 'tensorflow' + } + }) +} + +function createRoutes(condaCache) { + return originCondaRoutes(condaCache, true) +} + +function createStubCondaCache(cacheData) { + let getStub = sinon.stub() + + for (const [key, value] of Object.entries(cacheData)) { + getStub.withArgs(key).returns(value) + } + + return { + get: getStub + } +} diff --git a/test/summary/clearlyDefined.js b/test/summary/clearlyDefined.js index 3b0c99e60..e8ff76acb 100644 --- a/test/summary/clearlyDefined.js +++ b/test/summary/clearlyDefined.js @@ -446,7 +446,12 @@ describe('ClearlyDefined PHP composer summarizer', () => { }) it('handles with all the data and a disjunctive license array', () => { - const { coordinates, harvested } = setupComposer('2018-03-06T11:38:10.284Z', 'v1.0.0', ['MIT', 'Apache-2.0'], 'http://homepage') + const { coordinates, harvested } = setupComposer( + '2018-03-06T11:38:10.284Z', + 'v1.0.0', + ['MIT', 'Apache-2.0'], + 'http://homepage' + ) const summary = Summarizer().summarize(coordinates, harvested) validate(summary) @@ -574,7 +579,9 @@ describe('ClearlyDefined Debian summarizer', () => { expect(summary.described.urls.version).to.eq(registryUrl) expect(summary.described.urls.download).to.eq('http://ftp.debian.org/debian/pool/main/0/0ad/0ad_0.0.17-1_i386.deb') expect(summary.described.sourceLocation.url).to.eq(registryUrl) - expect(summary.licensed.declared).to.eq('GPL-2.0+ AND (CPL-1.0 OR MIT) AND (BSD-3-Clause OR GPL-3.0 AND LGPL-2.1+) AND NOASSERTION') + expect(summary.licensed.declared).to.eq( + 'GPL-2.0+ AND (CPL-1.0 OR MIT) AND (BSD-3-Clause OR GPL-3.0 AND LGPL-2.1+) AND NOASSERTION' + ) }) it('handles no data', () => { diff --git a/test/summary/clearlydefinedTests.js b/test/summary/clearlydefinedTests.js index 1bf1a50fb..7ead8081b 100644 --- a/test/summary/clearlydefinedTests.js +++ b/test/summary/clearlydefinedTests.js @@ -64,7 +64,12 @@ describe('ClearlyDescribedSummarizer add files', () => { it('adds tokens for multiple files', () => { const result = { files: [{ path: 'foo' }, { path: 'bar' }] } - const files = { attachments: [{ path: 'foo', token: 'abcd' }, { path: 'bar', token: 'dcba' }] } + const files = { + attachments: [ + { path: 'foo', token: 'abcd' }, + { path: 'bar', token: 'dcba' } + ] + } summarizer.addAttachedFiles(result, files) assert.strictEqual(result.files.length, 2) assert.strictEqual(result.files[0].path, 'foo') @@ -75,7 +80,12 @@ describe('ClearlyDescribedSummarizer add files', () => { it('adds license nature for attachments named license', () => { const result = { files: [{ path: 'foo' }, { path: 'LICENSE' }] } - const files = { attachments: [{ path: 'foo', token: 'abcd' }, { path: 'LICENSE', token: 'dcba' }] } + const files = { + attachments: [ + { path: 'foo', token: 'abcd' }, + { path: 'LICENSE', token: 'dcba' } + ] + } summarizer.addAttachedFiles(result, files) assert.strictEqual(result.files.length, 2) assert.strictEqual(result.files[0].path, 'foo') @@ -87,6 +97,52 @@ describe('ClearlyDescribedSummarizer add files', () => { }) }) +describe('ClearlyDescribedSummarizer addCondaData', () => { + const condaTestCoordinates = EntityCoordinates.fromString('conda/conda-forge/-/test/1.0') + it('declares license from registryData', () => { + let result = {} + summarizer.addCondaData(result, { declaredLicenses: 'MIT' }, condaTestCoordinates) + assert.strictEqual(get(result, 'licensed.declared'), 'MIT') + }) + + it('declares dual license from registryData with SPDX expression', () => { + let result = {} + let data = setup([ + { path: 'LICENSE-MIT', license: 'MIT' }, + { path: 'LICENSE-APACHE', license: 'Apache-2.0' } + ]) + data.declaredLicenses = 'MIT OR Apache-2.0' + summarizer.addCondaData(result, data, condaTestCoordinates) + assert.strictEqual(get(result, 'licensed.declared'), 'MIT OR Apache-2.0') + }) + + it('normalizes to spdx only', () => { + let result = {} + summarizer.addCondaData(result, { declaredLicenses: 'Garbage' }, condaTestCoordinates) + assert.strictEqual(get(result, 'licensed.declared'), 'NOASSERTION') + }) + + it('describes projectWebsite from registryData', () => { + let result = {} + summarizer.addCondaData( + result, + { + registryData: { + channelData: { home: 'https://github.com/owner/repo' } + } + }, + condaTestCoordinates + ) + assert.strictEqual(result.described.projectWebsite, 'https://github.com/owner/repo') + }) + + it('describes releaseDate from registryData', () => { + let result = {} + summarizer.addCondaData(result, { releaseDate: 'Wed, 14 Jun 2017 07:00:00 GMT' }, condaTestCoordinates) + assert.strictEqual(result.described.releaseDate, '2017-06-14') + }) +}) + describe('ClearlyDescribedSummarizer addCrateData', () => { const crateTestCoordinates = EntityCoordinates.fromString('crate/cratesio/-/test/1.0') it('declares license from registryData', () => { @@ -97,7 +153,10 @@ describe('ClearlyDescribedSummarizer addCrateData', () => { it('declares dual license from registryData with SPDX expression', () => { let result = {} - let data = setup([{ path: 'LICENSE-MIT', license: 'MIT' }, { path: 'LICENSE-APACHE', license: 'Apache-2.0' }]) + let data = setup([ + { path: 'LICENSE-MIT', license: 'MIT' }, + { path: 'LICENSE-APACHE', license: 'Apache-2.0' } + ]) data.registryData = { license: 'MIT OR Apache-2.0' } summarizer.addCrateData(result, data, crateTestCoordinates) assert.strictEqual(get(result, 'licensed.declared'), 'MIT OR Apache-2.0') @@ -105,7 +164,10 @@ describe('ClearlyDescribedSummarizer addCrateData', () => { it('declares dual license from registryData with slash-separated licenses', () => { let result = {} - let data = setup([{ path: 'LICENSE-MIT', license: 'MIT' }, { path: 'LICENSE-APACHE', license: 'Apache-2.0' }]) + let data = setup([ + { path: 'LICENSE-MIT', license: 'MIT' }, + { path: 'LICENSE-APACHE', license: 'Apache-2.0' } + ]) data.registryData = { license: 'MIT/Apache-2.0' } summarizer.addCrateData(result, data, crateTestCoordinates) assert.strictEqual(get(result, 'licensed.declared'), 'MIT OR Apache-2.0') @@ -275,8 +337,7 @@ describe('ClearlyDescribedSummarizer addNpmData', () => { ...expectedResult, licensed: { declared: data[license] } }) - } - else assert.deepEqual(result, expectedResult) + } else assert.deepEqual(result, expectedResult) } for (let license of Object.keys(data)) { @@ -287,8 +348,7 @@ describe('ClearlyDescribedSummarizer addNpmData', () => { ...expectedResult, licensed: { declared: data[license] } }) - } - else assert.deepEqual(result, expectedResult) + } else assert.deepEqual(result, expectedResult) } const licenseArray = ['MIT'] @@ -302,7 +362,11 @@ describe('ClearlyDescribedSummarizer addNpmData', () => { assert.deepEqual(result2, { ...expectedResult, licensed: { declared: 'MIT AND Apache-2.0' } }) let result3 = {} - summarizer.addNpmData(result3, { registryData: { manifest: { license: { type: licenseArray2 } } } }, npmTestCoordinates) + summarizer.addNpmData( + result3, + { registryData: { manifest: { license: { type: licenseArray2 } } } }, + npmTestCoordinates + ) assert.deepEqual(result3, { ...expectedResult, licensed: { declared: 'MIT AND Apache-2.0' } }) let result4 = {} @@ -408,7 +472,7 @@ describe('ClearlyDescribedSummarizer addNpmData', () => { }) }) - it('should not set issueTracker if it is not http', () => { }) + it('should not set issueTracker if it is not http', () => {}) it('should return if no registry data', () => { let result = {} @@ -484,7 +548,7 @@ describe('ClearlyDescribedSummarizer addMavenData', () => { const expectedUrls = { download: 'https://repo1.maven.org/maven2/io/clearlydefined/test/1.0/test-1.0.jar', registry: 'https://repo1.maven.org/maven2/io/clearlydefined/test', - version: 'https://repo1.maven.org/maven2/io/clearlydefined/test/1.0', + version: 'https://repo1.maven.org/maven2/io/clearlydefined/test/1.0' } const expectedResult = { described: { urls: expectedUrls } } it('should set declared license from manifest licenseUrl', () => { @@ -547,7 +611,7 @@ describe('ClearlyDescribedSummarizer addMavenData', () => { const expectedUrls = { download: 'https://maven.google.com/web/index.html#io.clearlydefined:test:1.0', registry: 'https://maven.google.com/web/index.html#io.clearlydefined:test:1.0', - version: 'https://maven.google.com/web/index.html#io.clearlydefined:test:1.0/1.0', + version: 'https://maven.google.com/web/index.html#io.clearlydefined:test:1.0/1.0' } const expectedResult = { described: { urls: expectedUrls } } it('should set declared license from manifest licenseUrl', () => { @@ -609,13 +673,13 @@ describe('ClearlyDescribedSummarizer addSourceArchiveData', () => { const expectedUrls = { download: 'https://repo1.maven.org/maven2/io/clearlydefined/test/1.0/test-1.0.jar', registry: 'https://repo1.maven.org/maven2/io/clearlydefined/test', - version: 'https://repo1.maven.org/maven2/io/clearlydefined/test/1.0', + version: 'https://repo1.maven.org/maven2/io/clearlydefined/test/1.0' } const expectedResult = { described: { urls: expectedUrls } } it('should set the correct urls', () => { const data = { - 'https://opensource.org/licenses/MIT': 'MIT', + 'https://opensource.org/licenses/MIT': 'MIT' } for (let url of Object.keys(data)) { @@ -627,7 +691,7 @@ describe('ClearlyDescribedSummarizer addSourceArchiveData', () => { ) if (data[url]) assert.deepEqual(result, { - ...expectedResult, + ...expectedResult }) else assert.deepEqual(result, expectedResult) } @@ -664,7 +728,7 @@ describe('ClearlyDescribedSummarizer addGitData', () => { it('should set the correct urls', () => { const data = { - 'https://opensource.org/licenses/MIT': 'MIT', + 'https://opensource.org/licenses/MIT': 'MIT' } for (let url of Object.keys(data)) { @@ -676,7 +740,7 @@ describe('ClearlyDescribedSummarizer addGitData', () => { ) if (data[url]) assert.deepEqual(result, { - ...expectedResult, + ...expectedResult }) else assert.deepEqual(result, expectedResult) } @@ -702,7 +766,7 @@ describe('ClearlyDescribedSummarizer addGitData', () => { it('should set the correct urls', () => { const data = { - 'https://opensource.org/licenses/MIT': 'MIT', + 'https://opensource.org/licenses/MIT': 'MIT' } for (let url of Object.keys(data)) { @@ -714,7 +778,7 @@ describe('ClearlyDescribedSummarizer addGitData', () => { ) if (data[url]) assert.deepEqual(result, { - ...expectedResult, + ...expectedResult }) else assert.deepEqual(result, expectedResult) } @@ -732,7 +796,6 @@ function setup(files, attachments) { return { licensee: { version: '1.2.3', output: { content: { matched_files } } }, attachments } } - describe('ClearlyDescribedSummarizer addGoData', () => { const testCoordinatesGo = EntityCoordinates.fromString('go/golang/rsc.io/quote/v1.3.0') @@ -746,7 +809,7 @@ describe('ClearlyDescribedSummarizer addGoData', () => { it('should set the correct urls', () => { const data = { - 'https://opensource.org/licenses/MIT': 'MIT', + 'https://opensource.org/licenses/MIT': 'MIT' } for (let url of Object.keys(data)) { @@ -758,14 +821,16 @@ describe('ClearlyDescribedSummarizer addGoData', () => { ) if (data[url]) assert.deepEqual(result, { - ...expectedResult, + ...expectedResult }) else assert.deepEqual(result, expectedResult) } }) it('should handle url encoding in the coordinates', () => { - const testEncodedCoordinatesGo = EntityCoordinates.fromString('go/golang/golang.org%2fx/net/v0.0.0-20210226172049-e18ecbb05110') + const testEncodedCoordinatesGo = EntityCoordinates.fromString( + 'go/golang/golang.org%2fx/net/v0.0.0-20210226172049-e18ecbb05110' + ) const expectedDecodedUrls = { download: 'https://proxy.golang.org/golang.org/x/net/@v/v0.0.0-20210226172049-e18ecbb05110.zip', @@ -776,7 +841,7 @@ describe('ClearlyDescribedSummarizer addGoData', () => { const expectedDecodedResult = { described: { urls: expectedDecodedUrls } } const testData = { - 'https://opensource.org/licenses/MIT': 'MIT', + 'https://opensource.org/licenses/MIT': 'MIT' } for (let url of Object.keys(testData)) { @@ -788,7 +853,7 @@ describe('ClearlyDescribedSummarizer addGoData', () => { ) if (testData[url]) assert.deepEqual(result, { - ...expectedDecodedResult, + ...expectedDecodedResult }) else assert.deepEqual(result, expectedDecodedResult) } @@ -802,7 +867,11 @@ describe('ClearlyDescribedSummarizer addGoData', () => { it('gets license from data', () => { let result = {} - summarizer.addGoData(result, { registryData: { licenses: ['Apache-2.0', 'BSD-2-Clause, BSD-3-Clause, HPND'] } }, testCoordinatesGo) + summarizer.addGoData( + result, + { registryData: { licenses: ['Apache-2.0', 'BSD-2-Clause, BSD-3-Clause, HPND'] } }, + testCoordinatesGo + ) assert.strictEqual(result.licensed.declared, 'Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND HPND') }) }) diff --git a/test/summary/licensee.js b/test/summary/licensee.js index 3ed015ca1..055431a66 100644 --- a/test/summary/licensee.js +++ b/test/summary/licensee.js @@ -30,7 +30,10 @@ describe('LicenseeSummarizer', () => { }) it('should AND together matched declared licenses', () => { - const data = setup([{ path: 'LICENSE-MIT', license: 'MIT' }, { path: 'LICENSE-APACHE', license: 'Apache-2.0' }]) + const data = setup([ + { path: 'LICENSE-MIT', license: 'MIT' }, + { path: 'LICENSE-APACHE', license: 'Apache-2.0' } + ]) const result = summarizer.summarize(null, data) assert.deepEqual(result, { files: [ @@ -42,7 +45,10 @@ describe('LicenseeSummarizer', () => { }) it('should filter NOASSERTION for matched declared licenses', () => { - const data = setup([{ path: 'LICENSE-MIT', license: 'MIT' }, { path: 'LICENSE', license: 'NOASSERTION' }]) + const data = setup([ + { path: 'LICENSE-MIT', license: 'MIT' }, + { path: 'LICENSE', license: 'NOASSERTION' } + ]) const result = summarizer.summarize(null, data) assert.deepEqual(result, { files: [{ path: 'LICENSE-MIT', license: 'MIT', natures: ['license'] }], diff --git a/test/summary/reuse.js b/test/summary/reuse.js index 09aa7f125..1bc600f18 100644 --- a/test/summary/reuse.js +++ b/test/summary/reuse.js @@ -5,11 +5,22 @@ const assert = require('assert') const summarizer = require('../../providers/summary/reuse')() describe('FsfeReuseSummarizer', () => { - it('should include populate all available attributes', () => { const files = [ - { fileName: 'README.md', licenseConcluded: 'MIT', licenseInfoFile: 'NOASSERTION', fileCopyrightText: 'Somebody', checksumSha1: '42' }, - { fileName: 'SECURITY.md', licenseConcluded: 'NOASSERTION', licenseInfoFile: 'Apache-2.0', fileCopyrightText: 'Somebody else', checksumSha1: '23' } + { + fileName: 'README.md', + licenseConcluded: 'MIT', + licenseInfoFile: 'NOASSERTION', + fileCopyrightText: 'Somebody', + checksumSha1: '42' + }, + { + fileName: 'SECURITY.md', + licenseConcluded: 'NOASSERTION', + licenseInfoFile: 'Apache-2.0', + fileCopyrightText: 'Somebody else', + checksumSha1: '23' + } ] const licenses = ['MIT', 'Apache-2.0'] const data = setup(files, licenses) @@ -19,7 +30,7 @@ describe('FsfeReuseSummarizer', () => { { path: 'README.md', license: 'MIT', hashes: { sha1: '42' }, attributions: ['Somebody'] }, { path: 'SECURITY.md', license: 'Apache-2.0', hashes: { sha1: '23' }, attributions: ['Somebody else'] }, { path: 'LICENSES/MIT.txt', license: 'MIT', natures: ['license'] }, - { path: 'LICENSES/Apache-2.0.txt', license: 'Apache-2.0', natures: ['license'] }, + { path: 'LICENSES/Apache-2.0.txt', license: 'Apache-2.0', natures: ['license'] } ], licensed: { declared: 'MIT AND Apache-2.0' } }) @@ -28,7 +39,13 @@ describe('FsfeReuseSummarizer', () => { it('should ignore missing or irrelevant attributes', () => { const files = [ { fileName: 'README.md', licenseConcluded: 'MIT', fileCopyrightText: 'Somebody', checksumSha1: '42' }, - { fileName: 'SECURITY.md', licenseConcluded: 'NOASSERTION', licenseInfoFile: 'Apache-2.0', fileCopyrightText: 'NONE', checksumSha1: '23' } + { + fileName: 'SECURITY.md', + licenseConcluded: 'NOASSERTION', + licenseInfoFile: 'Apache-2.0', + fileCopyrightText: 'NONE', + checksumSha1: '23' + } ] const licenses = ['MIT', 'Apache-2.0'] const data = setup(files, licenses) @@ -38,7 +55,7 @@ describe('FsfeReuseSummarizer', () => { { path: 'README.md', license: 'MIT', hashes: { sha1: '42' }, attributions: ['Somebody'] }, { path: 'SECURITY.md', license: 'Apache-2.0', hashes: { sha1: '23' } }, { path: 'LICENSES/MIT.txt', license: 'MIT', natures: ['license'] }, - { path: 'LICENSES/Apache-2.0.txt', license: 'Apache-2.0', natures: ['license'] }, + { path: 'LICENSES/Apache-2.0.txt', license: 'Apache-2.0', natures: ['license'] } ], licensed: { declared: 'MIT AND Apache-2.0' } }) @@ -46,7 +63,13 @@ describe('FsfeReuseSummarizer', () => { it('should ignore missing license information', () => { const files = [ - { fileName: 'README.md', licenseConcluded: 'MIT', licenseInfoFile: 'NOASSERTION', fileCopyrightText: 'Somebody', checksumSha1: '42' }, + { + fileName: 'README.md', + licenseConcluded: 'MIT', + licenseInfoFile: 'NOASSERTION', + fileCopyrightText: 'Somebody', + checksumSha1: '42' + }, { fileName: 'SECURITY.md', licenseConcluded: 'NOASSERTION', fileCopyrightText: 'NONE', checksumSha1: '23' } ] const licenses = ['MIT'] @@ -81,18 +104,24 @@ describe('FsfeReuseSummarizer', () => { function setup(files, licenses) { const matchedFiles = files.map(file => { return { - 'FileName': file.fileName, - 'LicenseConcluded': file.licenseConcluded, - 'LicenseInfoInFile': file.licenseInfoFile, - 'FileCopyrightText': file.fileCopyrightText, - 'FileChecksumSHA1': file.checksumSha1 + FileName: file.fileName, + LicenseConcluded: file.licenseConcluded, + LicenseInfoInFile: file.licenseInfoFile, + FileCopyrightText: file.fileCopyrightText, + FileChecksumSHA1: file.checksumSha1 } }) const matchedLicenses = licenses.map(license => { return { - 'filePath': ('LICENSES/' + license + '.txt'), - 'spdxId': license + filePath: 'LICENSES/' + license + '.txt', + spdxId: license } }) - return { reuse: { metadata: { 'DocumentName': 'ospo-reuse', 'CreatorTool': 'reuse-0.13.0' }, files: matchedFiles, licenses: matchedLicenses } } + return { + reuse: { + metadata: { DocumentName: 'ospo-reuse', CreatorTool: 'reuse-0.13.0' }, + files: matchedFiles, + licenses: matchedLicenses + } + } } diff --git a/test/summary/scancode.js b/test/summary/scancode.js index a3e228c4e..c69d8b46d 100644 --- a/test/summary/scancode.js +++ b/test/summary/scancode.js @@ -186,7 +186,15 @@ describe('ScanCode summarizer', () => { [buildRule('mit OR apache-2.0', ['mit', 'apache-2.0']), 'MIT OR Apache-2.0'], [buildRule('mit AND apache-2.0', ['mit', 'apache-2.0']), 'MIT AND Apache-2.0'], [buildRule('mit OR junk', ['mit', 'junk']), 'MIT OR NOASSERTION'], - [buildRule('junk OR mit', ['mit', 'junk']), 'NOASSERTION OR MIT'] + [buildRule('junk OR mit', ['mit', 'junk']), 'NOASSERTION OR MIT'], + [ + buildRule('mit AND apache-2.0 AND agpl-generic-additional-terms', [ + 'mit', + 'apache-2.0', + 'agpl-generic-additional-terms' + ]), + 'MIT AND Apache-2.0 AND NOASSERTION' + ] ]) examples.forEach((expected, input) => { const result = Summarizer()._createExpressionFromLicense(input)