diff --git a/README.md b/README.md index 6c448d5..f9ebb6b 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ The SCANOSS scan engine supports [scan tuning parameters](https://github.com/sca The SCANOSS Code Scan Action includes three configurable policies: 1. **Copyleft** (`copyleft or cpl`): This policy checks if any component or code snippet is associated with a copyleft license. If such a - license is detected, the pull request (PR) is rejected. The default list of Copyleft licenses is defined in the following [file](https://github.com/scanoss/gha-code-scan/blob/main/src/utils/license.utils.ts). + license is detected, the pull request (PR) is rejected. The copyleft determination is performed by [scanoss.py](https://github.com/scanoss/scanoss.py) (`scanoss-py inspect copyleft`), which uses the [OSADL copyleft checklist](https://www.osadl.org/fileadmin/checklists/copyleft.json) as the default list. Both strong (`Yes`) and weak/restricted (`Yes (restricted)`) copyleft entries are treated as copyleft, and this includes `-or-later` variants (e.g. `GPL-2.0-or-later`, `AGPL-3.0-or-later`). The default list can be customized with the `licenses.copyleft.include`, `licenses.copyleft.exclude`, and `licenses.copyleft.explicit` inputs. 2. **Undeclared** (`undeclared or und`): This policy compares the components detected in the repository against those declared in scanoss.json file (customizable through the settingsFilepath parameter). If there are undeclared components, the PR is rejected. diff --git a/__tests__/license.utils.test.ts b/__tests__/license.utils.test.ts index d66d6c2..a5247fe 100644 --- a/__tests__/license.utils.test.ts +++ b/__tests__/license.utils.test.ts @@ -23,91 +23,9 @@ import { LicenseUtil } from '../src/utils/license.utils'; -// Mock external dependencies -jest.mock('@actions/core'); - describe('License Utils', () => { - beforeEach(() => { - jest.clearAllMocks(); - // Clear module cache to ensure fresh imports - jest.resetModules(); - }); - - describe('LicenseUtil class initialization', () => { - it('should use explicit licenses when COPYLEFT_LICENSE_EXPLICIT is set', () => { - jest.doMock('../src/app.input', () => ({ - COPYLEFT_LICENSE_EXPLICIT: 'GPL-2.0-only,LGPL-3.0-only', - COPYLEFT_LICENSE_INCLUDE: '', - COPYLEFT_LICENSE_EXCLUDE: '' - })); - - const { LicenseUtil: MockedLicenseUtil } = require('../src/utils/license.utils'); - const util = new MockedLicenseUtil(); - - // Test that the utility is instantiated correctly with explicit configuration - expect(util).toBeDefined(); - expect(util).toBeInstanceOf(MockedLicenseUtil); - }); - - it('should use default licenses with include when COPYLEFT_LICENSE_INCLUDE is set', () => { - jest.doMock('../src/app.input', () => ({ - COPYLEFT_LICENSE_EXPLICIT: '', - COPYLEFT_LICENSE_INCLUDE: 'Custom-License-1.0', - COPYLEFT_LICENSE_EXCLUDE: '' - })); - - const { LicenseUtil: MockedLicenseUtil } = require('../src/utils/license.utils'); - const util = new MockedLicenseUtil(); - - // Test that the utility is instantiated correctly with include configuration - expect(util).toBeDefined(); - expect(util).toBeInstanceOf(MockedLicenseUtil); - }); - - it('should use default licenses with exclude when COPYLEFT_LICENSE_EXCLUDE is set', () => { - jest.doMock('../src/app.input', () => ({ - COPYLEFT_LICENSE_EXPLICIT: '', - COPYLEFT_LICENSE_INCLUDE: '', - COPYLEFT_LICENSE_EXCLUDE: 'GPL-2.0-only' - })); - - const { LicenseUtil: MockedLicenseUtil } = require('../src/utils/license.utils'); - const util = new MockedLicenseUtil(); - - // Test that the utility is instantiated correctly with exclude configuration - expect(util).toBeDefined(); - expect(util).toBeInstanceOf(MockedLicenseUtil); - }); - - it('should be instantiated correctly with default configuration', () => { - jest.doMock('../src/app.input', () => ({ - COPYLEFT_LICENSE_EXPLICIT: '', - COPYLEFT_LICENSE_INCLUDE: '', - COPYLEFT_LICENSE_EXCLUDE: '' - })); - - const { LicenseUtil: MockedLicenseUtil } = require('../src/utils/license.utils'); - const util = new MockedLicenseUtil(); - - // Test that the utility is instantiated correctly with default configuration - expect(util).toBeDefined(); - expect(util).toBeInstanceOf(MockedLicenseUtil); - }); - }); - describe('LicenseUtil.getOSADL', () => { - let util: LicenseUtil; - - beforeEach(() => { - // Create fresh instance with default configuration for each test - jest.doMock('../src/app.input', () => ({ - COPYLEFT_LICENSE_EXPLICIT: '', - COPYLEFT_LICENSE_INCLUDE: '', - COPYLEFT_LICENSE_EXCLUDE: '' - })); - const { LicenseUtil: MockedLicenseUtil } = require('../src/utils/license.utils'); - util = new MockedLicenseUtil(); - }); + const util = new LicenseUtil(); it('should return SPDX URL for valid SPDX licenses', () => { const result = util.getOSADL('MIT'); diff --git a/dist/index.js b/dist/index.js index ec77412..67fdd49 100644 --- a/dist/index.js +++ b/dist/index.js @@ -132464,61 +132464,6 @@ var import_github8 = __toESM(require_github()); var LicenseUtil = class { BASE_OSADL_URL = "https://spdx.org/licenses"; HTML = "html"; - /** - * Initializes the license utility with copyleft license configurations. - */ - constructor() { - this.init(); - } - defaultCopyleftLicenses = new Set( - [ - "GPL-1.0-only", - "GPL-2.0-only", - "GPL-3.0-only", - "AGPL-3.0-only", - "Sleepycat", - "Watcom-1.0", - "GFDL-1.1-only", - "GFDL-1.2-only", - "GFDL-1.3-only", - "LGPL-2.1-only", - "LGPL-3.0-only", - "MPL-1.1", - "MPL-2.0", - "EPL-1.0", - "EPL-2.0", - "CDDL-1.0", - "CDDL-1.1", - "CECILL-2.1", - "Artistic-1.0", - "Artistic-2.0", - "CC-BY-SA-4.0" - ].map((l) => l.toLowerCase()) - ); - copyLeftLicenses = /* @__PURE__ */ new Set(); - /** - * Initializes copyleft license sets based on configuration. - */ - init() { - if (COPYLEFT_LICENSE_EXPLICIT) { - const explicitCopyleftLicenses = COPYLEFT_LICENSE_EXPLICIT.split(",").map((pn) => pn.trim().toLowerCase()); - debug(`Explicit licenses: ${explicitCopyleftLicenses}`); - this.copyLeftLicenses = new Set(explicitCopyleftLicenses); - return; - } - debug(`Explicit licenses not defined, setting default licenses...`); - this.copyLeftLicenses = this.defaultCopyleftLicenses; - if (COPYLEFT_LICENSE_INCLUDE) { - const includedCopyleftLicenses = COPYLEFT_LICENSE_INCLUDE.split(",").map((pn) => pn.trim()); - debug(`Included copyleft licenses: ${includedCopyleftLicenses}`); - includedCopyleftLicenses.forEach((l) => this.copyLeftLicenses.add(l.toLowerCase())); - } - if (COPYLEFT_LICENSE_EXCLUDE) { - const excludedCopyleftLicenses = COPYLEFT_LICENSE_EXCLUDE.split(",").map((pn) => pn.trim()); - debug(`Excluded copyleft licenses: ${excludedCopyleftLicenses}`); - excludedCopyleftLicenses.forEach((l) => this.copyLeftLicenses.delete(l.toLowerCase())); - } - } /** * Generates SPDX license URL for the given license identifier. */ diff --git a/src/utils/license.utils.ts b/src/utils/license.utils.ts index 9849f11..87e3ce0 100644 --- a/src/utils/license.utils.ts +++ b/src/utils/license.utils.ts @@ -21,76 +21,16 @@ THE SOFTWARE. */ -import * as inputs from '../app.input'; -import * as core from '@actions/core'; - /** - * Utility class for handling license operations and copyleft license detection. + * Utility class for handling license operations. + * + * Note: copyleft determination is NOT performed here. It is delegated to + * scanoss.py (`scanoss-py inspect copyleft`), which uses the OSADL copyleft + * checklist. This class only builds SPDX license reference URLs for reporting. */ export class LicenseUtil { private BASE_OSADL_URL = 'https://spdx.org/licenses'; private HTML = 'html'; - /** - * Initializes the license utility with copyleft license configurations. - */ - constructor() { - this.init(); - } - - private defaultCopyleftLicenses = new Set( - [ - 'GPL-1.0-only', - 'GPL-2.0-only', - 'GPL-3.0-only', - 'AGPL-3.0-only', - 'Sleepycat', - 'Watcom-1.0', - 'GFDL-1.1-only', - 'GFDL-1.2-only', - 'GFDL-1.3-only', - 'LGPL-2.1-only', - 'LGPL-3.0-only', - 'MPL-1.1', - 'MPL-2.0', - 'EPL-1.0', - 'EPL-2.0', - 'CDDL-1.0', - 'CDDL-1.1', - 'CECILL-2.1', - 'Artistic-1.0', - 'Artistic-2.0', - 'CC-BY-SA-4.0' - ].map(l => l.toLowerCase()) - ); - - private copyLeftLicenses = new Set(); - - /** - * Initializes copyleft license sets based on configuration. - */ - private init(): void { - if (inputs.COPYLEFT_LICENSE_EXPLICIT) { - const explicitCopyleftLicenses = inputs.COPYLEFT_LICENSE_EXPLICIT.split(',').map(pn => pn.trim().toLowerCase()); - core.debug(`Explicit licenses: ${explicitCopyleftLicenses}`); - this.copyLeftLicenses = new Set(explicitCopyleftLicenses); - return; - } - - core.debug(`Explicit licenses not defined, setting default licenses...`); - this.copyLeftLicenses = this.defaultCopyleftLicenses; - - if (inputs.COPYLEFT_LICENSE_INCLUDE) { - const includedCopyleftLicenses = inputs.COPYLEFT_LICENSE_INCLUDE.split(',').map(pn => pn.trim()); - core.debug(`Included copyleft licenses: ${includedCopyleftLicenses}`); - includedCopyleftLicenses.forEach(l => this.copyLeftLicenses.add(l.toLowerCase())); - } - - if (inputs.COPYLEFT_LICENSE_EXCLUDE) { - const excludedCopyleftLicenses = inputs.COPYLEFT_LICENSE_EXCLUDE.split(',').map(pn => pn.trim()); - core.debug(`Excluded copyleft licenses: ${excludedCopyleftLicenses}`); - excludedCopyleftLicenses.forEach(l => this.copyLeftLicenses.delete(l.toLowerCase())); - } - } /** * Generates SPDX license URL for the given license identifier.