|
| 1 | +# 00009. Create New Field in License |
| 2 | + |
| 3 | +Date: 2025-07-27 |
| 4 | + |
| 5 | +## Status |
| 6 | + |
| 7 | +DRAFT |
| 8 | + |
| 9 | +## Context |
| 10 | + |
| 11 | +In the new license search requirements, there is a section called license summary, which requires collecting usage statistics for all licenses that appear, including how many packages and SBOMs use each license. |
| 12 | + |
| 13 | +## The Current Status of Licenses in Trustify |
| 14 | + |
| 15 | +Currently, Trustify's support for licenses is as follows: |
| 16 | + |
| 17 | +In SPDX, there are two types of licenses: licenseDeclared and licenseConcluded, and the representation is mainly in the form of license expressions, which can include custom license references (licenseRef). |
| 18 | + |
| 19 | +CycloneDX uses only one type, licenseDeclared, but offers three ways to represent it: |
| 20 | + |
| 21 | +- ID: This is a standard SPDX license ID. |
| 22 | +- License expression: Similar to SPDX, it supports license expressions. |
| 23 | +- Name: This is similar to a custom license reference, allowing for user-defined license names. |
| 24 | + |
| 25 | +In Trustify, the handling is as follows: |
| 26 | + |
| 27 | +When processing SPDX, Trustify parses the license expression into standard SPDX license IDs and exceptions, and stores them in spdx_licenses and spdx_license_exceptions. All custom license references (LicenseRef) are filtered out, while the original expression is preserved in the text field. |
| 28 | + |
| 29 | +When processing CycloneDX, there are three scenarios: |
| 30 | + |
| 31 | +- If the license is an ID, the value is saved directly in the text field and spdx_licenses. |
| 32 | +- If the license is a name: The value is saved directly in the text field, stores them in spdx_licenses. |
| 33 | +- If the license is an expression: Trustify parses it into standard SPDX license IDs and exceptions, stores them in spdx_licenses and spdx_license_exceptions, and also preserves the original expression in the text field. |
| 34 | + |
| 35 | +## The Current Issue |
| 36 | + |
| 37 | +- In SPDX, when a license expression contains a custom license ID, Trustify also saves it only in a text field, and filters out the custom license ID during the process of parsing it into standard SPDX license IDs and exceptions. |
| 38 | +- In SPDX, when a license expression includes a custom license ID, the custom license ID itself is meaningless and only has significance within the current SBOM, so it cannot be used for statistics or searches. |
| 39 | + |
| 40 | +## Decision |
| 41 | + |
| 42 | +Add a new field named `custom_license_refs` to the license table. Its type is a list, which includes licenses of type name appearing in CycloneDX, as well as license expressions that contain custom licenses in SPDX. |
| 43 | + |
| 44 | +```sql |
| 45 | +ALTER TABLE license ADD COLUMN custom_license_refs text[]; |
| 46 | +ALTER TABLE license ADD COLUMN custom_document_license_refs text[]; |
| 47 | +``` |
| 48 | +### The current table structure vs. the changed table structure |
| 49 | + |
| 50 | +- Current table structure |
| 51 | +```rust |
| 52 | +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, serde::Serialize)] |
| 53 | +#[sea_orm(table_name = "license")] |
| 54 | +pub struct Model { |
| 55 | + #[sea_orm(primary_key)] |
| 56 | + pub id: Uuid, |
| 57 | + pub text: String, |
| 58 | + pub spdx_licenses: Option<Vec<String>>, |
| 59 | + pub spdx_license_exceptions: Option<Vec<String>>, |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +- Changed table structure |
| 64 | + |
| 65 | +```rust |
| 66 | +#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, serde::Serialize)] |
| 67 | +#[sea_orm(table_name = "license")] |
| 68 | +pub struct Model { |
| 69 | + #[sea_orm(primary_key)] |
| 70 | + pub id: Uuid, |
| 71 | + pub text: String, |
| 72 | + pub spdx_licenses: Option<Vec<String>>, |
| 73 | + pub spdx_license_exceptions: Option<Vec<String>>, |
| 74 | + pub custom_license_refs: Option<Vec<String>>, |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +### SPDX |
| 79 | + |
| 80 | +License expression: |
| 81 | + |
| 82 | +```json |
| 83 | +{ |
| 84 | + "SPDXID": "SPDXRef-2a02a923-8a04-489d-9cbc-80f2d23de5ea", |
| 85 | + "copyrightText": "NOASSERTION", |
| 86 | + "downloadLocation": "https://access.redhat.com/downloads/content/package-browser", |
| 87 | + "externalRefs": [ |
| 88 | + { |
| 89 | + "referenceCategory": "PACKAGE_MANAGER", |
| 90 | + "referenceLocator": "pkg:rpm/redhat/[email protected]?arch=src", |
| 91 | + "referenceType": "purl" |
| 92 | + } |
| 93 | + ], |
| 94 | + "filesAnalyzed": false, |
| 95 | + "licenseConcluded": "NOASSERTION", |
| 96 | + "licenseDeclared": "LicenseRef-2 AND LicenseRef-11 AND LicenseRef-BSD", |
| 97 | + "name": "foreman-bootloaders-redhat", |
| 98 | + "originator": "NOASSERTION", |
| 99 | + "packageFileName": "foreman-bootloaders-redhat-202102220000-1.el8sat.src.rpm", |
| 100 | + "supplier": "Organization: Red Hat", |
| 101 | + "versionInfo": "202102220000-1.el8sat" |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +Custom licenses: |
| 106 | + |
| 107 | +```json |
| 108 | +[ |
| 109 | + { |
| 110 | + "comment": "External License Info is obtained from a build system which predates the SPDX specification and is not strict in accepting valid SPDX licenses.", |
| 111 | + "extractedText": "The license info found in the package meta data is: GPLv2+. See the specific package info in this SPDX document or the package itself for more details.", |
| 112 | + "licenseId": "LicenseRef-2", |
| 113 | + "name": "GPLv2+" |
| 114 | + }, |
| 115 | + { |
| 116 | + "comment": "External License Info is obtained from a build system which predates the SPDX specification and is not strict in accepting valid SPDX licenses.", |
| 117 | + "extractedText": "The license info found in the package meta data is: GPLv3+. See the specific package info in this SPDX document or the package itself for more details.", |
| 118 | + "licenseId": "LicenseRef-11", |
| 119 | + "name": "GPLv3+" |
| 120 | + }, |
| 121 | + { |
| 122 | + "comment": "External License Info is obtained from a build system which predates the SPDX specification and is not strict in accepting valid SPDX licenses.", |
| 123 | + "extractedText": "The license info found in the package meta data is: BSD. See the specific package info in this SPDX document or the package itself for more details.", |
| 124 | + "licenseId": "LicenseRef-BSD", |
| 125 | + "name": "BSD" |
| 126 | + } |
| 127 | +] |
| 128 | +``` |
| 129 | + |
| 130 | +`custom_license_refs`: should be a JSONB mapping all custom license identifiers to their descriptions or SPDX expressions. |
| 131 | + |
| 132 | +```json |
| 133 | +{ |
| 134 | + "LicenseRef-2": "GPLv2+", |
| 135 | + "LicenseRef-11": "GPLv3+", |
| 136 | + "LicenseRef-BSD": "BSD" |
| 137 | +} |
| 138 | +``` |
| 139 | + |
| 140 | +## Consequences |
| 141 | +- Positive: Enables complete license statistics and search functionality |
| 142 | +- Negative: Increases storage overhead and requires data migration handling |
| 143 | + |
| 144 | +## Alternatives Considered |
| 145 | +- Using JSONB to store complete license mappings (rejected: high query complexity) |
| 146 | +- Maintaining status quo without handling custom licenses (rejected: fails business requirements) |
| 147 | + |
| 148 | +## Success Metrics |
| 149 | +- Ability to count packages containing custom licenses |
| 150 | +- Support for searching by custom license ID |
| 151 | + |
| 152 | + |
| 153 | +## Known Issues |
| 154 | + |
| 155 | +There are two types of custom licenses: |
| 156 | + |
| 157 | +- Ones that are defined within the current SBOM, for example those with the "LicenseRef" prefix. |
| 158 | +- Ones that reference other SBOM documents, for example those with the "DocumentRef" prefix. |
| 159 | + |
| 160 | +Previously, we only handled the first type of custom license. The second type cannot be processed currently. |
| 161 | +If we want to handle the second type, we need to add a new field, `custom_document_license_refs`, to store the complete reference, such as "DocumentRef-spdx-tool-1.2:LicenseRef-BSD"[1], in this field. |
| 162 | + |
| 163 | +[1] Where "DocumentRef" is the prefix and "spdx-tool-1.2" refers to another SPDX SBOM, "LicenseRef-BSD" is the custom license reference within that SBOM. |
0 commit comments