From 275e733607f2e57701c90eb5f7e2c8dccb3e010a Mon Sep 17 00:00:00 2001 From: Michelangelo Mori Date: Wed, 8 Jan 2025 15:50:11 +0100 Subject: [PATCH 1/2] Add `license-is-osi-or-fsf-approved` rule type. This rule type checks that the license detected by GitHub is approved by either OSI or FSF. It uses two data sources, one to call GitHub API to get the SPDX identifier of the license, and another one to get the updated list of licenses approved by from SPDX repository. This rule can be used to implement `OSPS-LE-02`. --- data-sources/{osi.yaml => spdx.yaml} | 2 +- rule-types/github/permissive_license.yaml | 53 +++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) rename data-sources/{osi.yaml => spdx.yaml} (95%) create mode 100644 rule-types/github/permissive_license.yaml diff --git a/data-sources/osi.yaml b/data-sources/spdx.yaml similarity index 95% rename from data-sources/osi.yaml rename to data-sources/spdx.yaml index 63e05b7..4e6e6ea 100644 --- a/data-sources/osi.yaml +++ b/data-sources/spdx.yaml @@ -1,6 +1,6 @@ version: v1 type: data-source -name: osi +name: spdx context: {} rest: def: diff --git a/rule-types/github/permissive_license.yaml b/rule-types/github/permissive_license.yaml new file mode 100644 index 0000000..e91ba57 --- /dev/null +++ b/rule-types/github/permissive_license.yaml @@ -0,0 +1,53 @@ +version: v1 +release_phase: alpha +type: rule-type +name: permissive_license +display_name: License meets the OSI or the FSF definition +short_failure_message: License does not meet OSI or FSF definition +severity: + value: info +context: + provider: github +description: | + Ensure that the project’s source code is distributed under a + recognized and legally enforceable open source software license. +guidance: | + Ensure that the project’s source code is distributed under a + recognized and legally enforceable open source software license, + providing clarity on how the code can be used and shared by others. +def: + in_entity: repository + rule_schema: {} + ingest: + type: git + eval: + type: rego + data_sources: + - name: ghapi + - name: spdx + rego: + type: constraints + def: | + package minder + + import future.keywords.every + import future.keywords.if + + violations[{"msg": msg}] { + owner := input.properties["github/repo_owner"] + repo := input.properties["github/repo_name"] + + resp := minder.datasource.ghapi.license({"owner": owner, "repo": repo}) + license := resp.body.license.spdx_id + + resp2 := minder.datasource.spdx.licenses({}) + licenses := resp2.body.licenses + osi := { l.licenseId | l := licenses[_]; l.isOsiApproved } + fsf := { l.licenseId | l := licenses[_]; l.isFsfLibre } + approved_licenses := osi | fsf + + count(approved_licenses) != 0 + license != null + not license in approved_licenses + msg := sprintf("License %s of repo %s/%s is not OSI/FSF approved", [license, owner, repo]) + } From aceda9ac4f76b71fb0a0fd3c71010c5914fe005a Mon Sep 17 00:00:00 2001 From: Michelangelo Mori Date: Thu, 9 Jan 2025 12:47:47 +0100 Subject: [PATCH 2/2] Replace ingest, remove usage of ghapi data source. --- rule-types/github/permissive_license.yaml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/rule-types/github/permissive_license.yaml b/rule-types/github/permissive_license.yaml index e91ba57..190ccdc 100644 --- a/rule-types/github/permissive_license.yaml +++ b/rule-types/github/permissive_license.yaml @@ -19,11 +19,22 @@ def: in_entity: repository rule_schema: {} ingest: - type: git + type: rest + rest: + # This is the path to the data source. Given that this will evaluate + # for each repository in the organization, we use a template that + # will be evaluated for each repository. The structure to use is the + # protobuf structure for the entity that is being evaluated. + endpoint: '/repos/{{.Entity.Owner}}/{{.Entity.Name}}/license' + # This is the method to use to retrieve the data. It should already default to JSON + parse: json + fallback: + - http_code: 404 + body: | + {"http_status": 404, "message": "License details not found} eval: type: rego data_sources: - - name: ghapi - name: spdx rego: type: constraints @@ -34,11 +45,7 @@ def: import future.keywords.if violations[{"msg": msg}] { - owner := input.properties["github/repo_owner"] - repo := input.properties["github/repo_name"] - - resp := minder.datasource.ghapi.license({"owner": owner, "repo": repo}) - license := resp.body.license.spdx_id + license := input.ingested.license.spdx_id resp2 := minder.datasource.spdx.licenses({}) licenses := resp2.body.licenses @@ -49,5 +56,5 @@ def: count(approved_licenses) != 0 license != null not license in approved_licenses - msg := sprintf("License %s of repo %s/%s is not OSI/FSF approved", [license, owner, repo]) + msg := sprintf("License %s is not OSI/FSF approved", [license]) }