diff --git a/lib/checkLicense.js b/lib/checkLicense.js new file mode 100644 index 000000000..6f7ba1c2e --- /dev/null +++ b/lib/checkLicense.js @@ -0,0 +1,56 @@ +/******************************************************************************** + * Copyright (c) 2022 TypeFox and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + ********************************************************************************/ + +// @ts-check +const checkLicense = require("osi-license-checker"); +const fs = require('fs'); +const octokit = require('octokit'); + +/** + * Check if the extension has an OSI-approved open-source license + * @param {URL} url + * @param {string} owner + * @param {string} repo + * @param {octokit.Octokit} octokit a preauthenthicated octokit client + * @param {string} packagePath + */ +exports.checkLicense = async function(url, owner, repo, octokit, packagePath) { + try { + const manifest = JSON.parse( + await fs.promises.readFile(packagePath, "utf-8") + ); + const license = manifest.license; + if (!license) { + if (!checkLicense.checkShorthand(license)) { + console.error(`Not an OSS license: ${license}`); + return false; + } + + if (url.hostname !== "github.com") { + console.error("Can' check license on non-github repositories "); + return false; + } + + const ghLicenseResponse = ( + await octokit.rest.licenses.getForRepo({ owner, repo }) + ).data.license; + if (!checkLicense.checkShorthand(ghLicenseResponse.spdx_id)) { + console.error( + `Not an OSS license: ${ghLicenseResponse.name} (${ghLicenseResponse.spdx_id})` + ); + return false; + } + return true; + } + } catch (e) { + console.error("Can't get license", e); + return false; + } +} diff --git a/lib/resolveExtension.js b/lib/resolveExtension.js index 8d1f0d3be..e73bc88fb 100644 --- a/lib/resolveExtension.js +++ b/lib/resolveExtension.js @@ -6,6 +6,7 @@ const Octokit = require('octokit').Octokit; const readVSIXPackage = require('vsce/out/zip').readVSIXPackage; const download = require('download'); const exec = require('./exec'); +const { checkLicense } = require('./checkLicense'); const token = process.env.GITHUB_TOKEN; if (!token) { @@ -53,6 +54,7 @@ exports.resolveExtension = async function ({ id, repository, location }, ms) { await exec(`git clone --filter=blob:none --recurse-submodules ${repository} ${repoPath}`, { quiet: true }); const packagePath = [repoPath, location, 'package.json'].filter(p => !!p).join('/'); + /** * @param {string} ref * @returns {Promise} diff --git a/package.json b/package.json index 4e497c461..dad25a124 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "download": "^8.0.0", "minimist": "^1.2.5", "octokit": "^1.7.0", + "osi-license-checker": "latest", "ovsx": "latest", "semver": "^7.1.3", "vsce": "^2.3.0" diff --git a/publish-extension.js b/publish-extension.js index 6feeb56aa..8aab75dc4 100644 --- a/publish-extension.js +++ b/publish-extension.js @@ -16,6 +16,14 @@ const path = require('path'); const semver = require('semver'); const exec = require('./lib/exec'); const { createVSIX } = require('vsce'); +const { checkLicense } = require('./lib/checkLicense'); +const { Octokit } = require('octokit'); + +const token = process.env.GITHUB_TOKEN; +if (!token) { + throw new Error("GITHUB_TOKEN env var is not set"); +} +const octokit = new Octokit({ auth: token }); (async () => { /** @@ -32,6 +40,11 @@ const { createVSIX } = require('vsce'); packagePath = path.join(packagePath, extension.location); } + const [owner, repo] = extension.repository.slice(1).split("/"); + if (!(await checkLicense(new URL(extension.repository), owner, repo, octokit, packagePath+'/package.json'))) { + process.exit(1); + } + /** @type {import('ovsx').PublishOptions} */ let options; if (context.file) {