Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions docs/security/sbom.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,171 @@ Key fields worth reading:
| `metadata.component.version` | The value from `.release-please-manifest.json` at the time of generation. Pre-release: `0.0.0`. |
| `metadata.component.purl` | Package URL keyed to the exact commit SHA — unambiguous pointer back to the source. |
| `metadata.component.supplier.name` | `Cozens Software Solutions Limited (COSOSO)`. |
| `metadata.component.externalReferences[type=license]` | One per PolyForm term, so a scanner resolves each to its canonical text instead of leaving it unknown. The commercial term has no licence document to point at and carries an `other` reference to the enquiry route instead. See [reading the licence expression](#reading-the-licence-expression). |
| `metadata.component.licenses[0].expression` | `PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial` — an SPDX expression, because the library is offered under three alternative licences and the recipient chooses. Only the Noncommercial identifier is on the SPDX License List; the other two are `LicenseRef-`. |
| `metadata.properties[solidsyslog:source-tree-sha256]` | Content-tree hash: SHA-256 of a sorted list of `<content-sha256> <path>` lines for every tracked file in `Core/` + `Platform/` plus the root-level `CMakeLists.txt`, `CMakePresets.json`, `LICENSE.md`, and `LICENSES/`, at the commit. Reproducible byte-for-byte from any clone, with no dependency on `git archive` output format or git version. |

## Reading the licence expression

Written for a compliance reviewer holding SolidSyslog as an item in a review
queue. If you are choosing a licence rather than reviewing one,
[`LICENSE.md`](../../LICENSE.md) is the document you want instead.

`metadata.component.licenses[0].expression` reads:

```text
PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial
```

**`OR` is a choice, not an accumulation.** SPDX defines the operator as
alternatives: a recipient relies on one term and complies with that one. The
component is not encumbered by all three at once, and nothing obliges a
recipient to satisfy the noncommercial term if they hold a different one.

This expression is the whole licence question for the component. SolidSyslog
vendors no third-party source, so the `components` array is empty and there is
no transitive licence graph underneath it — see
[why the platform backends are not components](#why-the-platform-backends-are-not-components).

### Why two of the three are `LicenseRef-`

Only `PolyForm-Noncommercial-1.0.0` appears on the
[SPDX License List](https://spdx.org/licenses/). The other two do not, for
different reasons:

| Term | Why it is a `LicenseRef-` |
|---|---|
| `LicenseRef-PolyForm-Internal-Use-1.0.0` | A published, unmodified PolyForm licence that SPDX has not listed. The verbatim text ships in the repository and is linked from [`LICENSE.md`](../../LICENSE.md). |
| `LicenseRef-COSOSO-Commercial` | A negotiated agreement between COSOSO and the licensee. It has no single public text, so no published identifier could describe it. |

If your scanner reports these identifiers as unknown or custom, that result is
expected. A `LicenseRef-` is how SPDX names a licence its list does not cover,
so there is no template in any scanner's corpus for it to match — and for the
PolyForm term the verbatim text ships in the repository, for a reviewer who
needs to read it.

An unknown identifier is not, by itself, evidence of a licence defect. Neither
is it a resolution: the item stays open until you have confirmed which of the
three terms your organisation relies on, and hold the evidence for it.

So that the terms resolve to documents rather than to nothing, the SBOM carries
an `externalReferences` entry of type `license` for each PolyForm licence,
pointing at its canonical URL. An SPDX expression has nowhere to put a URL,
which is why they are attached to the component instead.

`LicenseRef-COSOSO-Commercial` has no such entry. There is no public document to
point at, and type `license` means the URL of a licence file — labelling an
enquiry form as one would resolve the identifier to something that is not a
licence. The enquiry route is carried as an `other` reference instead, with a
comment saying what it is.

### Which term applies

| If your organisation is | The term you rely on |
|---|---|
| Using SolidSyslog in the internal business operations of you and your company — which covers evaluation, porting, integration and testing, and internal deployment, commercial organisations included | `LicenseRef-PolyForm-Internal-Use-1.0.0` |
| Distributing it for a noncommercial purpose | `PolyForm-Noncommercial-1.0.0` |
| Supplying, selling or otherwise making available a commercial product, device, firmware or service containing it | `LicenseRef-COSOSO-Commercial` |

This table says only which term to read. The conditions each one attaches are
in [`LICENSE.md`](../../LICENSE.md), which is the authoritative statement.

### What to record in your own SBOM

The expression above is SolidSyslog's **declared** licence — what COSOSO offers
to any recipient. It is not a statement about your organisation's position.

Once you have taken one of the three, record **that single term** as the
concluded licence for this component in your own product SBOM. Carrying the
disjunction forward re-raises the same review item on every rebuild, and
misstates your position to anyone reading your SBOM downstream.

`PolyForm-Noncommercial-1.0.0` is on the SPDX list, so an expression carries
everything a tool needs to identify it:

```json
"licenses": [
{ "expression": "PolyForm-Noncommercial-1.0.0" }
]
```

The other two are `LicenseRef-` terms, and an expression has nowhere to put a
name or a URL for them — which is the whole reason they resolve as unknown. Use
CycloneDX's named-licence form instead. PolyForm Internal Use is a published
document, so its canonical URL is enough:

```json
"licenses": [
{
"license": {
"name": "PolyForm Internal Use License 1.0.0",
"url": "https://polyformproject.org/licenses/internal-use/1.0.0"
}
}
]
```

`LicenseRef-COSOSO-Commercial` needs more again. It names a class of negotiated
agreement rather than your particular contract, so on its own it tells a
downstream reader of your SBOM nothing about what was granted. CycloneDX has
fields for exactly this — use the named-licence form:

```json
"licenses": [
{
"license": {
"name": "COSOSO Commercial Licence",
"url": "https://www.cososo.co.uk/#contact",
"licensing": {
"licensor": {
"organization": { "name": "Cozens Software Solutions Limited" }
},
"licensee": {
"organization": { "name": "<your organisation>" }
},
"purchaseOrder": "<your agreement or PO reference>",
"licenseTypes": ["oem"],
"expiration": "<RFC 3339 timestamp, if your agreement has a term>"
}
}
}
]
```

`licenseTypes` takes values from CycloneDX's own enumeration — `oem`,
`appliance`, `perpetual`, `subscription` and others — so pick whichever
describes your agreement. A `licenses` array is *either* a list of named
licences *or* exactly one expression; the two forms cannot be mixed.

**Do not put the agreement itself in `license.text`.** A negotiated commercial
agreement is confidential between the parties, and an SBOM is a document you
distribute. The reference is what belongs here; the terms are not.

The same question applies to `purchaseOrder` and `licensee`. They are exactly
right in an internal compliance record, but if you pass this SBOM on to your
own customers, your commercial arrangements travel with it. Decide which of
these fields belong in the copy you distribute and which stay in the copy you
keep — `name` and `url` alone are enough to resolve the identifier.

Whichever term applies, keep the evidence for it — the agreement reference for
a commercial licence, or a record of the permitted purpose relied on for a
PolyForm one — in your compliance record alongside the SBOM entry. That is what
lets the next reviewer resolve this without repeating your work.

### A policy rule you can adopt

Stated in prose rather than a vendor syntax, because the encoding differs
across scanning platforms:

> SolidSyslog is a disjunctively multi-licensed component. Resolve it to the
> single term this organisation holds, record that as the concluded licence
> together with the evidence supporting it, and close the item on that basis.
> Do not assess the component against the noncommercial term unless that is the
> term being relied on.

If your review turns up a question this page does not answer, ask before
escalating it internally: <https://www.cososo.co.uk/#contact>.

## How to generate one (rehearsal)

Each run produces a CycloneDX 1.5 JSON file, validated against the spec by
Expand Down
15 changes: 15 additions & 0 deletions sbom/sbom.cdx.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@
}
],
"externalReferences": [
{
"type": "license",
"url": "https://polyformproject.org/licenses/noncommercial/1.0.0",
"comment": "Full text for PolyForm-Noncommercial-1.0.0. A verbatim copy also ships at LICENSES/PolyForm-Noncommercial-1.0.0.md and is covered by solidsyslog:source-tree-sha256."
},
{
"type": "license",
"url": "https://polyformproject.org/licenses/internal-use/1.0.0",
"comment": "Full text for LicenseRef-PolyForm-Internal-Use-1.0.0, which SPDX does not list. A verbatim copy also ships at LICENSES/PolyForm-Internal-Use-1.0.0.md and is covered by solidsyslog:source-tree-sha256."
},
{
"type": "other",
"url": "https://www.cososo.co.uk/#contact",
"comment": "How to obtain LicenseRef-COSOSO-Commercial. Deliberately not type=license: that type means the URL of a licence file, and this agreement is negotiated per licensee with no public document to link. Labelling an enquiry form as a licence would resolve the identifier to something that is not one."
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
{
"type": "vcs",
"url": "https://github.com/cososo-ltd/solid-syslog"
Expand Down
Loading