Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

plaidcloud-github-actions

Shared GitHub Actions for PlaidCloud repositories.

license-check

Fails a build on a Python dependency whose license the organisation has not approved. Replaces liccheck, which imports pkg_resources — removed in setuptools 82 — and was last released in September 2023 (sc-24172).

license:
name: Check Dependency Licensesruns-on: ubuntu-lateststeps:
- uses: actions/checkout@v7
- uses: PlaidCloud/plaidcloud-github-actions/license-check@v1with:
extras: full,tracing

Inputs

InputDefaultNotes
package.What to install and scan. Ignored when requirements is set.
requirements''Install a requirements file instead of package, for a repo that ships an image and has nothing pip-installable of its own.
extras''Comma-separated, e.g. full,tracing. Empty installs base dependencies.
policy''Repo-local policy file, applied in addition tolicense-policy.txt, not instead of it.
python-version3.12
uv-version0.11.10
trivy-versionv0.70.0Pinned deliberately — see below.
diagnosticsfalsePrint what each Trivy scan surface saw. Run once when onboarding a repo.

How it decides

Trivy is the license extractor; the policy is applied by check_licenses.py in this repo. That split is not stylistic:

  • Trivy's license findings are not dependable. On 0.73.0 the findings block — the surface --exit-code and license.ignored act on — came back empty for a 53-package venv, while Results[].Packages[].Licenses resolved every package on every version and platform tried. A findings-based gate would have kept passing, green, enforcing nothing, after a routine action bump. trivy-version is pinned for the same reason.
  • trivy rootfs, never trivy fs. On the same venv, fs returns no result blocks at all.
  • Completeness is checked, not just violations. A scanner that cannot read the venv reports nothing and exits 0 — a pass for a tree it never looked at. Every .dist-info in the venv must appear in Trivy's package list, so the check self-calibrates as dependencies change rather than resting on a hardcoded floor.

The policy file

license-check/license-policy.txt is the organisation allow-list. There is no deny-list: anything not named fails, as does a package declaring no license at all. That reproduces liccheck's level: cautious.

Entries are matched case-insensitively, and both SPDX identifiers and free-text names are listed on purpose — Trivy normalises many packages to SPDX but passes the declared text through verbatim when it cannot, so Apache-2.0 and Apache Software License both reach the policy. A license's whole declared string is matched first; only an unmatched one is treated as an SPDX expression and split on AND/OR/WITH. Compound expressions are evaluated conservatively — both sides of an OR must be approved, so a package we could legally take under the permitted half asks for a human rather than passing quietly.

Changing this file changes the gate for every repository on the same tag. Review it as policy, not as configuration.

Per-package waivers

A line of the form package: license[, license…] forgives one package a license the organisation otherwise refuses. It replaces liccheck's [Authorized Packages], and unlike that section it names what it forgives:

# PyInstaller is GPLv2-or-later with the bootloader exception, which permits
# distributing non-free programs built with it. That exception is prose — PyPI
# declares the bare GPLv2 classifier and no License-Expression, so no scanner
# reading metadata can see it. Permanent, not a migration convenience.
pyinstaller: GPL-2.0-or-later, GPL-2.0-only, GNU General Public License v2 (GPLv2)

Put repo-specific waivers in a repo-local file and pass it as policy:. Naming the license matters: if the package relicenses, the waiver stops covering it and the build fails, where a bare package name would keep waving it through.

Waivers that match no scanned package are reported on every run. An exemption list rots silently otherwise — liccheck's accumulated 22 entries across the org, most of them for packages whose licenses Trivy now reads without help.

Assertions

A waiver forgives a license the scanner read. When the scanner cannot read one at all, assert what it is with =:

# Declares no license of any kind. Google's, Apache-2.0 upstream.
google-crc32c = Apache-2.0
# Puts its whole license text in the `license` field, so Trivy passes it
# through as `text://MIT License Copyright (c) 2022 OpenAI…`.
tiktoken = MIT

The asserted license replaces what was scanned and is then checked like any other, so nobody can assert their way to something the policy refuses.

It applies only where the scanner produced nothing usable: no license, a text:// blob, or a literal UNKNOWN. Asserting over a license Trivy read correctly is an error, not an override — that is how a GPL package would get laundered into MIT, and it is what a waiver is for. This is the capability liccheck's [Authorized Packages] provided, except that it names the license rather than just the package, so it can be reviewed and can go stale loudly.

Versioning

  • @v1 — moving, and what consumers should normally pin. A policy change reaches every repository on the next run, which is the entire point of putting the policy in one place; pinning exact versions everywhere would mean ten pull requests to disallow one license.
  • @v1.0.0 — frozen. Use it to hold a repository back deliberately, and say why in the workflow.

v1 is moved only for a change we intend to propagate, and only from a green main. A change to an input's name or meaning is a v2, not a v1 move — the gate failing everywhere at once is acceptable, a gate silently doing nothing everywhere at once is not.

About

Shared Github Actions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages