|
| 1 | +--- |
| 2 | +name: semaphore-ui-third-party-licenses |
| 3 | +description: > |
| 4 | + Generate or update the THIRD-PARTY-LICENSES.md file for the Semaphore UI repository. Use this skill whenever the user |
| 5 | + asks to create, update, regenerate, audit, or refresh third-party license attributions, OSS notices, SBOM-style |
| 6 | + license inventories, or NOTICE files for Semaphore UI. Trigger on phrases like "third-party licenses", "OSS notices", |
| 7 | + "license attribution file", "SBOM for licenses", "NOTICE file", "audit dependencies", |
| 8 | + "licenses for go.mod / package.json", or any request that mentions compliance with customer agreements requiring an |
| 9 | + OSS components list. Also trigger when the user says "we added a new dependency, regenerate licenses". This skill |
| 10 | + knows the Semaphore UI layout (Go backend + Vue.js frontend), the project's license policy (allowlist/denylist), |
| 11 | + and the canonical output format. |
| 12 | +--- |
| 13 | + |
| 14 | +# Semaphore UI — Third-Party License Generator |
| 15 | + |
| 16 | +This skill produces `THIRD-PARTY-LICENSES.md` for the Semaphore UI repository. The file lists every open-source |
| 17 | +dependency shipped with Semaphore UI by **name**, **version**, **license**, and **source URL**, grouped by component. It |
| 18 | +exists to satisfy contractual obligations toward customers (identification of OSS components by name, version, |
| 19 | +and license type) and to preserve attribution required by permissive licenses (MIT/BSD/Apache-2.0). |
| 20 | + |
| 21 | +## Repository layout you can expect |
| 22 | + |
| 23 | +Semaphore UI is a self-hosted product. The repository ships: |
| 24 | + |
| 25 | +- **Go backend** — module file at `go.mod`, source under `pkg/`, `services/`, `db/`, etc. |
| 26 | +- **Vue.js frontend** — `web/package.json` (or `web2/package.json` in some branches), built into static assets and |
| 27 | + embedded in the Go binary. |
| 28 | + |
| 29 | +External CLI tools (Ansible, Terraform, OpenTofu, Pulumi, Bash) are invoked at runtime as separate operating-system |
| 30 | +processes. They are NOT linked into the binary and NOT redistributed with Semaphore UI, so they are intentionally |
| 31 | +**not listed** in `THIRD-PARTY-LICENSES.md` — their license terms apply to the user who installs them on the host, |
| 32 | +not to Semaphore UI's distribution. The license policy still discusses why this is contractually safe (see |
| 33 | +`references/license_policy.md`, "Subprocess exception"). |
| 34 | + |
| 35 | +If the layout differs (monorepo restructure, new submodule, etc.), inspect the repo first with |
| 36 | +`find . -name "go.mod" -o -name "package.json" -not -path "*/node_modules/*"` and adapt. |
| 37 | + |
| 38 | +## Workflow |
| 39 | + |
| 40 | +Follow these steps in order. Don't skip the policy check — it's the part that actually protects the project from |
| 41 | +accidentally shipping a GPL'd dependency. |
| 42 | + |
| 43 | +### 1. Confirm scope with the user |
| 44 | + |
| 45 | +Before generating anything, ask (briefly) which targets to include if it's not obvious from context: |
| 46 | + |
| 47 | +- Backend only? Frontend only? Both? |
| 48 | +- Production dependencies only, or also dev dependencies? |
| 49 | + |
| 50 | +**Default**: both backend and frontend, **production-only** (dev dependencies are not distributed to customers and don't |
| 51 | +need attribution). Override only if the user explicitly asks for dev deps too. |
| 52 | + |
| 53 | +### 2. Collect raw license data |
| 54 | + |
| 55 | +Run `scripts/collect_licenses.sh` from the repo root. It does the following: |
| 56 | + |
| 57 | +- Sets `GOWORK=off` and runs `go-licenses report ./... --template scripts/go_template.tpl` for the Go backend, so |
| 58 | + workspace siblings (e.g. `pro_impl`) are not pulled in. |
| 59 | +- Rolls sub-package rows up to their parent module (uses `go list -m all` for the module → version map) and drops |
| 60 | + any module path that belongs to the root module's namespace (first-party packages, including `replace … => ./pro` |
| 61 | + targets). |
| 62 | +- Applies a small `OVERRIDES` table in the script for modules where `go-licenses` can't auto-detect a license |
| 63 | + (e.g. `modernc.org/mathutil` → BSD-3-Clause). Extend the table when new "Unknown" entries appear. |
| 64 | +- Runs `license-checker --production --json --excludePrivatePackages` in the frontend directory and strips the |
| 65 | + low-confidence `*` suffix from license strings so `MIT*` collapses into `MIT`. |
| 66 | +- Writes raw output to `.licenses-cache/go.tsv` and `.licenses-cache/npm.json`. |
| 67 | + |
| 68 | +If the tools aren't installed, the script prints the install commands. Don't try to install them silently — show the |
| 69 | +user what needs to be added so they can decide whether to add them to CI. |
| 70 | + |
| 71 | +### 3. Run the policy check |
| 72 | + |
| 73 | +Run `scripts/check_policy.py .licenses-cache/`. This compares every detected license against the project policy in |
| 74 | +`references/license_policy.md`: |
| 75 | + |
| 76 | +- **Allowed** (green): MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, Zlib, Unlicense, CC0-1.0, MPL-2.0 — proceed. |
| 77 | +- **Review** (yellow): LGPL-2.1, LGPL-3.0, EPL-2.0, CDDL-1.0, custom/unknown — pause and ask the user. LGPL is fine for |
| 78 | + dynamic linking but Go statically links, so flag it for review. |
| 79 | +- **Forbidden** (red): GPL-2.0, GPL-3.0, AGPL-3.0, SSPL-1.0, BUSL-1.1, Commons Clause, "non-commercial" clauses — STOP. |
| 80 | + Do not proceed with file generation. Report the offending package and ask the user how to handle it (replace, vendor, |
| 81 | + or accept and document the consequence). |
| 82 | + |
| 83 | +**This step is non-negotiable.** A forbidden license slipping into THIRD-PARTY-LICENSES.md isn't just a documentation |
| 84 | +problem — it's a contract breach with every customer. If `check_policy.py` returns a non-zero exit code, surface the |
| 85 | +failures prominently and stop. |
| 86 | + |
| 87 | +### 4. Generate the markdown |
| 88 | + |
| 89 | +Run `scripts/generate_md.py .licenses-cache/ > THIRD-PARTY-LICENSES.md`. This produces the file using the structure |
| 90 | +described in `references/template.md`. Key points the generator handles: |
| 91 | + |
| 92 | +- Sorts entries alphabetically within each section. |
| 93 | +- Groups by component category (Go backend / npm frontend). |
| 94 | +- Deduplicates packages that appear at multiple versions (lists all versions on one line). |
| 95 | +- Renders a summary table at the top with license counts. |
| 96 | +- Adds a generation timestamp and a note pointing to `scripts/collect_licenses.sh` so the file is reproducible. |
| 97 | + |
| 98 | +### 5. Verify and commit |
| 99 | + |
| 100 | +After generation: |
| 101 | + |
| 102 | +1. Diff against the previous `THIRD-PARTY-LICENSES.md` (if it exists). New rows = new dependencies — confirm with the |
| 103 | + user that they're expected. |
| 104 | +2. Verify the file isn't truncated and ends with the closing footer (`<!-- end of generated file -->`). |
| 105 | +3. Suggest the commit message: `chore(licenses): regenerate THIRD-PARTY-LICENSES.md for vX.Y.Z`. |
| 106 | +4. If a CI pipeline exists (`.github/workflows/`), suggest adding a job that runs `scripts/check_policy.py` on every |
| 107 | + PR — that's how the project prevents regressions, not by re-checking manually each release. |
| 108 | + |
| 109 | +## Notes on edge cases |
| 110 | + |
| 111 | +**Vendored dependencies.** If the repo has a `vendor/` directory, `go-licenses` will read from it. That's fine — |
| 112 | +vendored code still ships and still needs attribution. |
| 113 | + |
| 114 | +**Dual-licensed packages.** Some packages are offered under "MIT OR Apache-2.0". Pick MIT (the simpler one) and note the |
| 115 | +choice in the entry: `License: MIT (also available under Apache-2.0)`. |
| 116 | + |
| 117 | +**Packages with no detectable license.** `go-licenses` flags these as "Unknown". Don't ship the file with Unknowns — |
| 118 | +manually inspect the repo, fill in the SPDX identifier, and if there's truly no license, treat the package as |
| 119 | +forbidden (no license = "all rights reserved", which is incompatible with redistribution). |
| 120 | + |
| 121 | +**Ansible / Terraform / OpenTofu / Pulumi / Bash.** Do NOT list them in `THIRD-PARTY-LICENSES.md`. They are invoked |
| 122 | +as separate OS processes (`os/exec`), not linked, not redistributed. Their licenses bind the user who installs them |
| 123 | +on the host, not Semaphore UI's distribution. Listing them would imply otherwise and is an unnecessary signal to a |
| 124 | +reviewing customer's legal team. The "Subprocess exception" section in `references/license_policy.md` explains the |
| 125 | +reasoning if a reviewer asks. |
| 126 | + |
| 127 | +**First-party packages with no LICENSE.** The root module and any `replace … => ./<dir>` target (e.g. `./pro`) live |
| 128 | +inside this repo and don't need to be self-attributed. The collection script filters them out by the root module |
| 129 | +prefix from `go.mod`. If you see "Unknown license" rows for `github.com/<this-org>/<this-repo>/…`, the filter is |
| 130 | +working correctly — those rows shouldn't appear in the final cache. |
| 131 | + |
| 132 | +**Embedded license texts.** For packages under MIT/BSD/ISC, the license requires preserving the copyright notice. The |
| 133 | +generator embeds the full LICENSE file text from each package's source. For Apache-2.0 packages, it embeds the NOTICE |
| 134 | +file if one exists. |
| 135 | + |
| 136 | +## What this skill does NOT do |
| 137 | + |
| 138 | +- It does not generate a CycloneDX or SPDX SBOM. If the user wants a machine-readable SBOM (for compliance scanners, |
| 139 | + customer attestations, etc.), point them at `syft packages dir:. -o cyclonedx-json` as a separate step. |
| 140 | + THIRD-PARTY-LICENSES.md is the human-readable artifact. |
| 141 | +- It does not check for CVEs. That's a security concern, not a licensing one — use `govulncheck` and `npm audit` for |
| 142 | + that. |
| 143 | +- It does not modify go.mod or package.json. The skill is read-only with respect to the dependency manifests; it only |
| 144 | + generates the attribution document. |
| 145 | + |
| 146 | +See `references/license_policy.md` for the full policy and `references/template.md` for the output format. |
0 commit comments