Third-party notices and the license policy

September 21, 2026 ยท View on GitHub

THIRD-PARTY-NOTICES and NOTICE at the repository root are generated by tools/src/MacroDeck.LicenseTool from what Macro Deck actually ships. MacroDeckHost.csproj copies both, with LICENSE, next to the host in every build and publish, so every installer carries them. The host serves them to Settings > About in the configuration UI and to the web client's settings.

  • THIRD-PARTY-NOTICES: every shipped third-party component with its license and the license and notice texts. It carries no versions, so a version-only dependency bump leaves it unchanged unless the package's license text or copyright line changed with it.
  • NOTICE: the Apache-2.0 NOTICE. Only a fixed header, notices an override or attribution declares, and the NOTICE files of Apache-2.0 components, which the Apache License requires to be passed on. It is not a dependency list.

Regenerating

Run this after adding, removing or updating a dependency, and commit both files:

npm ci --prefix ui
dotnet restore host/src/MacroDeckHost/MacroDeckHost.csproj '-p:RuntimeIdentifiers="win-x64;linux-x64;osx-arm64"'
dotnet run --project tools/src/MacroDeck.LicenseTool

The tool also needs cargo on the PATH (it runs cargo metadata). --check reports whether the committed files are current without writing them. The CI job Third-party notices & license policy in ci.yml runs the same steps and fails when the files differ or the policy is violated, so Renovate pull requests that add or remove packages need a regeneration commit.

What counts as shipped

The sources are configured in third-party/config.yml.

  • NuGet: the host's project.assets.json, one target per shipped runtime identifier. A package counts when it has a runtime, native or resource asset for that runtime; placeholder-only packages, analyzers and source generators do not. Packages that ship for only some platforms are listed with those platforms.
  • npm: the shipped bundles' entry points are listed in third-party/config.yml, mirroring angular.json (browser, styles) and the web client's build scripts; add an entry there when a bundle gains one. They are followed through relative imports, dynamic imports, tsconfig path aliases and stylesheet loads. Every package they import, plus each shipped workspace's declared dependencies, is resolved in ui/package-lock.json with its dependencies. The list is a deliberate superset: declared dependencies are included even when the bundler drops them. Packages restricted by os or cpu are native build tools and never counted. Build scripts and tests next to shipped code are not reachable from an entry point, so they do not count. CSS url() references are not followed.
  • Cargo: cargo metadata --filter-platform for each release target of the bootstrapper. Only normal dependencies count; build and dev dependencies and proc-macro crates are compile-time only.

A bare import that does not resolve, a missing restore graph, or missing node_modules is an error rather than a silent omission.

Policy

third-party/config.yml lists the allowed SPDX licenses in order of preference. For a choice such as MIT OR Apache-2.0 the first allowed one is attributed, and only its license files are reproduced. A component fails the run when it has no license metadata, when no branch of its expression is allowed, or when it declares a custom (LicenseRef-*) license that has not been reviewed.

Overrides and attributions

third-party/overrides.yml corrects a package by ecosystem and name, for all versions:

FieldEffect
licenseReplaces the declared SPDX expression.
reviewedAccepts the (custom) licenses in license; say who reviewed what and why.
licenseFileReplaces the package's license files with a repository file.
noticeText that belongs in NOTICE.
additionalLicensesFurther licenses for code the package vendors (title, license, copyright, licenseFile).
excludeTreats the package as not shipped; give the reason.
url, copyrightReplace the metadata values.

An override that matches no shipped component fails the run, so overrides cannot go stale.

Package metadata does not describe vendored native code. Packages that bundle third-party binaries (Skia, HarfBuzz, SQLite, libsodium, the WebView2 loader in webview2-com-sys) need their extra licenses reproduced, either from the package's own notice files or through additionalLicenses. Check this when adding a -sys crate or a native-assets package.

third-party/attributions.yml lists third-party files in the repository that no package graph describes, such as icons. Each entry's paths globs must match at least one file.

Standard license texts used when a package ships none are in third-party/licenses/; the component's declared authors are printed above them.

Not covered

  • System libraries that linuxdeploy bundles into the Linux AppImage (GTK, WebKitGTK, GLib and others under the LGPL) are not in THIRD-PARTY-NOTICES. The AppImage carries its own generated file, usr/share/doc/macro-deck/THIRD-PARTY-NOTICES-LINUX-LIBRARIES, written at package time on the Ubuntu 22.04 runner by appimage-library-notices.mjs, which strip-appimage-wayland.sh runs before it repacks the AppImage. It maps every file linuxdeploy copied to the Ubuntu package that owns it (dpkg) and lists, per package, the files, the package and source package versions, a Launchpad source link and the package's copyright file verbatim. It also covers the AppImage runtime, which is pinned to a reviewed type2-runtime release, and the AppRun start-up files. The build fails when a file has no owning package, when the pinned runtime's checksum or reported commit differs, or when the repacked AppImage lacks the file. A new runtime release means reviewing its LICENSE and build files and updating the pinned values and components in the script.
  • The NSIS runtime and plugins in the Windows installer, and helper code that esbuild and Babel inject into the web bundles.
  • The macrodeck-plugin CLI package, a separate distribution that bundles its own dependencies.