Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
# Let git handle line endings for other files
* text=auto


# Generated, and compared byte for byte in CI
THIRD-PARTY-NOTICES.txt text eol=lf
67 changes: 67 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,72 @@ jobs:
- name: App doc links
run: node scripts/check-app-doc-links.mjs

# Third-party licenses. Two checks, both on the dependency tree rather
# than on compiled code, so this job builds nothing but the two tools.
#
# `cargo deny check licenses` fails on a crate whose license deny.toml
# does not allow, which is where a copyleft dependency would otherwise
# arrive unnoticed. The notices check fails when THIRD-PARTY-NOTICES.txt
# no longer matches Cargo.lock and package-lock.json, the way the
# TypeScript bindings check in the lint job does. A dependency bump has
# to regenerate the notices in the same PR, or the release ships stale
# ones.
licenses:
name: Licenses
needs: changes
if: needs.changes.outputs.code == 'true'
runs-on: ubuntu-latest
# A cold cache compiles both tools first, which is most of this.
timeout-minutes: 30
env:
# The latest releases on crates.io when these were set (2026-10-08).
# Bump them here; the cache keys below follow.
CARGO_ABOUT_VERSION: 0.9.2
CARGO_DENY_VERSION: 0.20.2
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Install Rust
# See the pin note on the lint job below.
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
with:
toolchain: "1.96.0"
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: .nvmrc
cache: npm
cache-dependency-path: apps/netscli-gui/package-lock.json
# Keyed on the pinned versions, for the reason audit.yml gives.
- name: Cache cargo-about and cargo-deny
id: cache-license-tools
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.cargo/bin/cargo-about
~/.cargo/bin/cargo-deny
key: license-tools-about-${{ env.CARGO_ABOUT_VERSION }}-deny-${{ env.CARGO_DENY_VERSION }}
# cargo-about builds its binary only with the `cli` feature.
- name: Install cargo-about and cargo-deny
if: steps.cache-license-tools.outputs.cache-hit != 'true'
run: |
cargo install cargo-about --version "$CARGO_ABOUT_VERSION" --features cli --locked
cargo install cargo-deny --version "$CARGO_DENY_VERSION" --locked
# Both read each crate's license file from its source, and the notices
# are generated offline so a crate's repository cannot change them.
- name: Fetch crates
run: cargo fetch --locked
- name: cargo deny check licenses
run: cargo deny check licenses
- name: npm ci
run: npm ci --ignore-scripts
working-directory: apps/netscli-gui
- name: Third-party notices match the lockfiles
run: |
node scripts/third-party-notices.mjs
git diff --exit-code -- THIRD-PARTY-NOTICES.txt apps/netscli-cli/THIRD-PARTY-NOTICES.txt \
|| { echo "::error::Regenerate with: node scripts/third-party-notices.mjs"; exit 1; }

# Installer scripts aren't exercised by any other job, so lint them
# directly. shellcheck and PSScriptAnalyzer are both preinstalled on
# ubuntu-latest/GitHub-hosted runners.
Expand Down Expand Up @@ -569,6 +635,7 @@ jobs:
needs:
- changes
- maintainability
- licenses
- script-lint
- lint
- test
Expand Down
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,31 @@ jobs:
ASSET: ${{ matrix.asset_name }}
run: gh release upload "$TAG" "$ASSET" "$ASSET.sha256" "$ASSET.sig" "$ASSET.pem" --clobber

# ─── Third-party notices ──────────────────────────────────────────────
# The licenses of everything built into the CLI and the desktop app, from
# the tag. The raw CLI binaries have no archive to carry it in, so it ships
# beside them, and publish-npm.sh puts this copy into the npm packages.
# It is committed and checked against the lockfiles in CI, so there is
# nothing to build here and no signature beyond the release's own.
notices:
name: Attach third-party notices
needs: guard
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
ref: ${{ env.TAG }}
# `gh`, for the reasons given at the CLI job's upload.
- name: Upload Release Asset
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
run: gh release upload "$TAG" THIRD-PARTY-NOTICES.txt --clobber

# ─── Desktop GUI installers ───────────────────────────────────────────
# Builds the Tauri 2 desktop app on each native runner. .msi/.dmg/.deb/
# .AppImage outputs from `tauri.conf.json:bundle.targets = "all"` get
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ keeps a bare heading and collects entries.
stops the scan, instead of it running to the end and holding one of the
server's sixteen request slots.

- **Every download now carries the licenses of the open source code inside
it.** `netscli licenses` prints them, and the desktop app shows them from a
Third-party licenses button in its About dialog. The same notices are a
file on each GitHub release and in the npm packages. The Linux AppImage
bundles GTK, WebKitGTK and other system libraries, so it now includes their
licenses too and says where Ubuntu publishes their source. CI rebuilds the
notices and checks the license of every dependency, so a new one cannot
arrive under a license nobody has looked at.

### Changed

- **History is off unless you set `NETSCLI_HISTORY=1`.** Every `discover`,
Expand Down
Loading
Loading