From fc91f9141194e5f239ab1c5a5d88f6f32a3c2391 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 31 Oct 2026 05:26:56 +0000 Subject: [PATCH 1/2] Release workflow on GitHub, with code signing prepared (off until set up) Until now NVENCForgeGUI.exe was not built by GitHub Actions. The new release workflow builds it from a tag vX.Y.Z (equal to guiVersion): tests, window checks, wails build with the version written into the file properties, then publishes NVENCForgeGUI.exe, the asset name the window's update button looks for. The release text is .github/release-notes/vX.Y.Z.md or the annotated tag message. Code signing with SignPath is prepared in the same workflow but only runs once the repository has the variable SIGNPATH_ORGANIZATION_ID and the secret SIGNPATH_API_TOKEN; without them the exe is released unsigned. - Dry run: by hand (tick "dry run") and for pull requests that change the release workflow, wails.json, build/windows/ or .signpath/. - CODE_SIGNING.md: code signing policy with roles, privacy policy and uninstalling, linked from the README and from every release text. - .signpath/: artifact configuration, file check, setup and removal. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GvUq7HnA5ggbuHBogzS2rV --- .github/workflows/release.yml | 243 +++++++++++++++++++++++++++ .signpath/README.md | 65 +++++++ .signpath/artifact-configuration.xml | 21 +++ .signpath/check-files.ps1 | 61 +++++++ CODE_SIGNING.md | 77 +++++++++ README.md | 12 +- 6 files changed, 477 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 .signpath/README.md create mode 100644 .signpath/artifact-configuration.xml create mode 100644 .signpath/check-files.ps1 create mode 100644 CODE_SIGNING.md diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c5b34b3 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,243 @@ +# Turns a pushed version tag into a finished release, built on GitHub and +# nowhere else: tests, builds NVENCForgeGUI.exe with "wails build" and +# publishes it as the release asset. The asset name stays NVENCForgeGUI.exe, +# because the window's own update button looks for exactly that file. +# +# Two ways in: +# - push a tag vX.Y.Z (equal to guiVersion in main.go), or +# - Actions > Release > Run workflow with an existing tag. +# The release text is .github/release-notes/vX.Y.Z.md if that file exists, +# otherwise the message of the annotated tag (git tag -a). +# +# Dry run: tick "dry run" when starting it by hand. The exe is built and +# checked and stays on the run page as a workflow artifact; nothing is +# signed or published. Pull requests that change this workflow, wails.json, +# build/windows/ or .signpath/ get a dry run by themselves. +# +# Code signing (SignPath Foundation) is prepared but off until the +# repository has the variable SIGNPATH_ORGANIZATION_ID and the secret +# SIGNPATH_API_TOKEN; see .signpath/README.md. Without them the exe is +# released unsigned. +name: Release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + tag: + description: 'Existing tag to release (for example v2.2.0)' + required: true + dry_run: + description: 'Dry run: build and check only, sign and publish nothing' + type: boolean + default: false + pull_request: + paths: + - '.github/workflows/release.yml' + - '.signpath/**' + - 'wails.json' + - 'build/windows/**' + +# Publishing needs write access to the repository contents; actions: read +# lets SignPath fetch the unsigned exe from this run. +permissions: + contents: write + actions: read + +env: + DRY_RUN: ${{ github.event_name == 'pull_request' || inputs.dry_run == true }} + +jobs: + release: + runs-on: windows-latest + # Includes up to one hour of waiting for the signing approval. + timeout-minutes: 120 + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.tag || github.ref }} + # The annotated tag message can be the release text, and it only + # exists in a clone that carries the tag objects. + fetch-depth: 0 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + # Node only runs the window checks; the interface itself has no build step. + - uses: actions/setup-node@v4 + with: + node-version: '22' + + # A tag that disagrees with guiVersion would publish an exe that keeps + # offering itself as an update. A pull request has no tag: it builds + # the version in main.go. + - name: Tag matches guiVersion + run: | + $match = Select-String -Path main.go -Pattern '^const guiVersion = "(.+)"' | Select-Object -First 1 + if (-not $match) { + Write-Host "::error::Could not find guiVersion in main.go" + exit 1 + } + $inCode = $match.Matches[0].Groups[1].Value + $tag = "${{ inputs.tag || github.ref_name }}" + if ($env:GITHUB_EVENT_NAME -eq 'pull_request') { $tag = "v$inCode" } + if ("v$inCode" -ne $tag) { + Write-Host "::error::Tag $tag does not match guiVersion $inCode in main.go" + exit 1 + } + Write-Host "Tag $tag matches guiVersion $inCode." + "TAG=$tag" | Out-File $env:GITHUB_ENV -Append -Encoding utf8 + "VERSION=$inCode" | Out-File $env:GITHUB_ENV -Append -Encoding utf8 + + - name: go test + run: go test ./... + + - name: window checks + run: | + $checks = Get-ChildItem -Path frontend\*_check.js | Sort-Object Name + if (-not $checks) { + Write-Host "::error::No frontend\*_check.js found - nothing was checked." + exit 1 + } + $failed = @() + foreach ($check in $checks) { + node $check.FullName + if ($LASTEXITCODE -ne 0) { $failed += $check.Name } + } + if ($failed) { + Write-Host "::error::These window checks failed: $($failed -join ', ')" + exit 1 + } + + # wails.json feeds the file properties (right-click > Properties > + # Details); SignPath only signs an exe whose properties name + # NVENCForgeGUI and the version of the release. + - name: Version into wails.json + run: | + $text = [IO.File]::ReadAllText("$PWD\wails.json") + $text = [regex]::Replace($text, '"productVersion": "[^"]*"', "`"productVersion`": `"$env:VERSION`"") + [IO.File]::WriteAllText("$PWD\wails.json", $text, [Text.UTF8Encoding]::new($false)) + + # The Wails CLI of the same version as in go.mod; "go run" needs no + # global install. + - name: Build + run: | + go run github.com/wailsapp/wails/v2/cmd/wails@v2.14.0 build -trimpath + if ($LASTEXITCODE -ne 0) { exit 1 } + Copy-Item build/bin/NVENCForgeGUI.exe NVENCForgeGUI.exe + + - name: Check the file properties + run: ./.signpath/check-files.ps1 -ProductName NVENCForgeGUI -ProductVersion $env:VERSION -Path NVENCForgeGUI.exe + + # --- code signing ------------------------------------------------------ + - name: 'code signing: on or off?' + id: signing + env: + ORGANIZATION_ID: ${{ vars.SIGNPATH_ORGANIZATION_ID }} + HAS_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN != '' }} + run: | + $hasOrganization = -not [string]::IsNullOrWhiteSpace($env:ORGANIZATION_ID) + $hasToken = $env:HAS_TOKEN -eq 'true' + if ($env:DRY_RUN -eq 'true') { + $on = $false + Write-Host 'Dry run: nothing is signed.' + } elseif ($hasOrganization -ne $hasToken) { + Write-Host '::error::Code signing is half set up: SIGNPATH_ORGANIZATION_ID and SIGNPATH_API_TOKEN must both be set, or neither (see .signpath/README.md).' + exit 1 + } else { + $on = $hasOrganization -and $hasToken + Write-Host ($(if ($on) { 'Code signing is on.' } else { 'Code signing is off: this release is unsigned.' })) + } + "enabled=$($on.ToString().ToLower())" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8 + + - name: 'code signing: collect the exe' + if: steps.signing.outputs.enabled == 'true' + run: | + New-Item -ItemType Directory sign/unsigned -Force | Out-Null + Copy-Item NVENCForgeGUI.exe sign/unsigned/ + + - name: 'code signing: upload the exe' + id: unsigned + if: steps.signing.outputs.enabled == 'true' + uses: actions/upload-artifact@v7 + with: + name: unsigned + path: sign/unsigned + if-no-files-found: error + + - name: 'code signing: sign (approve the request in SignPath)' + if: steps.signing.outputs.enabled == 'true' + uses: signpath/github-action-submit-signing-request@v3 + with: + api-token: ${{ secrets.SIGNPATH_API_TOKEN }} + organization-id: ${{ vars.SIGNPATH_ORGANIZATION_ID }} + project-slug: ${{ vars.SIGNPATH_PROJECT_SLUG || 'NVENCForgeGUI' }} + signing-policy-slug: ${{ vars.SIGNPATH_SIGNING_POLICY_SLUG || 'release-signing' }} + artifact-configuration-slug: ${{ vars.SIGNPATH_ARTIFACT_CONFIGURATION_SLUG }} + github-artifact-id: ${{ steps.unsigned.outputs.artifact-id }} + wait-for-completion: true + wait-for-completion-timeout-in-seconds: 3600 + output-artifact-directory: sign/signed + parameters: | + version: "${{ env.VERSION }}" + + - name: 'code signing: take over the signed exe' + if: steps.signing.outputs.enabled == 'true' + run: | + Copy-Item sign/signed/NVENCForgeGUI.exe NVENCForgeGUI.exe -Force + ./.signpath/check-files.ps1 -ProductName NVENCForgeGUI -ProductVersion $env:VERSION -Path NVENCForgeGUI.exe -Signed + + - name: 'dry run: keep the exe on the run page' + if: env.DRY_RUN == 'true' + uses: actions/upload-artifact@v7 + with: + name: release-dry-run + path: NVENCForgeGUI.exe + retention-days: 7 + + # gh is preinstalled on GitHub runners and signs in with the token this + # workflow already holds, so no personal access token is involved. + - name: Publish release + if: env.DRY_RUN != 'true' + env: + GH_TOKEN: ${{ github.token }} + SIGNED: ${{ steps.signing.outputs.enabled }} + run: | + $tag = $env:TAG + $title = "NVENCForgeGUI $tag" + $file = ".github/release-notes/$tag.md" + if (Test-Path $file) { + $notes = [IO.File]::ReadAllText("$PWD/$file") + } else { + $notes = (git tag -l --format='%(contents)' $tag) -join "`n" + } + if ([string]::IsNullOrWhiteSpace($notes)) { + Write-Host "::error::No release text: add $file or create the tag with 'git tag -a'." + exit 1 + } + # The release page is the download page, so it links the code + # signing policy and says whether this exe is signed. + $policy = "https://github.com/$env:GITHUB_REPOSITORY/blob/main/CODE_SIGNING.md" + if ($env:SIGNED -eq 'true') { + $footer = "NVENCForgeGUI.exe is signed. Free code signing provided by [SignPath.io](https://about.signpath.io), certificate by [SignPath Foundation](https://signpath.org). [Code signing policy]($policy)" + } else { + $footer = "NVENCForgeGUI.exe is not code signed, so Windows SmartScreen may warn. [Code signing policy]($policy)" + } + [IO.File]::WriteAllText("$PWD/release-notes.md", $notes.TrimEnd() + "`n`n---`n`n$footer`n", [Text.UTF8Encoding]::new($false)) + + Write-Host "Publishing $tag with NVENCForgeGUI.exe ($((Get-Item NVENCForgeGUI.exe).Length) bytes)." + # A rerun (a corrected workflow, a retried build) refreshes the + # release that is there instead of failing on the second attempt. + gh release view $tag *> $null + if ($LASTEXITCODE -eq 0) { + Write-Host "Release $tag already exists - refreshing its notes and asset." + gh release edit $tag --title $title --notes-file release-notes.md --draft=false + gh release upload $tag NVENCForgeGUI.exe --clobber + } else { + gh release create $tag NVENCForgeGUI.exe --title $title --notes-file release-notes.md + } diff --git a/.signpath/README.md b/.signpath/README.md new file mode 100644 index 0000000..bfe450e --- /dev/null +++ b/.signpath/README.md @@ -0,0 +1,65 @@ +# Code signing with SignPath: prepared, off until switched on + +NVENCForgeGUI has applied to the [SignPath Foundation](https://signpath.org) for free +code signing of its Windows files. Everything for it is prepared here and in +[`release.yml`](../.github/workflows/release.yml), but **it stays off** until it is +switched on below. Until then every release is built and published exactly as before, +unsigned, and its release text says so. + +| File | What it is | +| ---- | ---------- | +| [`../CODE_SIGNING.md`](../CODE_SIGNING.md) | The public code signing policy (required by SignPath Foundation): roles, what is signed, privacy | +| [`artifact-configuration.xml`](artifact-configuration.xml) | The SignPath artifact configuration (the project's default): signs NVENCForgeGUI.exe only | +| [`check-files.ps1`](check-files.ps1) | Run by every release build: checks product name and version of every file to be signed (SignPath enforces both), and with `-Signed` that the signatures are valid | + +## How the release workflow decides + +| Repository settings | What a release does | +| ------------------- | ------------------- | +| Neither `SIGNPATH_ORGANIZATION_ID` nor `SIGNPATH_API_TOKEN` set | Builds and publishes unsigned, as before | +| Both set | Uploads the files, sends a signing request to SignPath, **waits up to one hour for the approval**, downloads the signed files, checks their signatures and publishes them | +| Only one of them set | Stops with an error, so a half finished setup never ships unsigned files by surprise | + +**Dry run:** *Actions > Release > Run workflow* with "dry run" ticked builds and checks +everything, keeps the files on the run page as a workflow artifact, never signs and +publishes nothing. It also runs by itself for every pull request that changes the +release workflow or this folder. + +## Switching it on (after SignPath Foundation said yes) + +1. **Two-factor authentication** on GitHub and on SignPath for everybody in the team + (a condition of SignPath Foundation). +2. **In SignPath** (the Foundation sets up most of it with you): + - the project, slug `NVENCForgeGUI` (another slug: set the variable `SIGNPATH_PROJECT_SLUG`), + - the trusted build system *GitHub.com* linked to the project, and the SignPath + GitHub App installed on this repository (SignPath shows the link), + - the artifact configuration from [`artifact-configuration.xml`](artifact-configuration.xml), set as the project's default, + - the signing policy `release-signing` with manual approval by the approver + (another slug: set `SIGNPATH_SIGNING_POLICY_SLUG`), + - a CI user with the *Submitter* role on that policy, and an API token for it. +3. **On GitHub:** *Settings > Secrets and variables > Actions* + - secret `SIGNPATH_API_TOKEN`: the API token of the CI user, + - variable `SIGNPATH_ORGANIZATION_ID`: the organization ID from SignPath. +4. **Recommended:** a ruleset that protects `main` and the `v*` tags from force pushes + and deletion (*Settings > Rules > Rulesets*). SignPath can require this in its + policies. +5. **Update the texts:** the status line at the top of + [`CODE_SIGNING.md`](../CODE_SIGNING.md) and the SmartScreen note in the README. +6. **Release as usual.** Approve the signing request in SignPath within one hour (the + link is in the run log and in the e-mail from SignPath), then the release is published + with signed files. + +| Variable / secret | Required | Default | +| ----------------- | -------- | ------- | +| `SIGNPATH_API_TOKEN` (secret) | yes | | +| `SIGNPATH_ORGANIZATION_ID` | yes | | +| `SIGNPATH_PROJECT_SLUG` | no | `NVENCForgeGUI` | +| `SIGNPATH_SIGNING_POLICY_SLUG` | no | `release-signing` | +| `SIGNPATH_ARTIFACT_CONFIGURATION_SLUG` | no | the project's default artifact configuration | + +## Taking it out again + +Never setting the secret and the variable is enough: nothing is signed then. To remove +it completely: delete this folder and `CODE_SIGNING.md`, remove the steps marked +`code signing` in `release.yml` (the file check step uses `check-files.ps1` from this +folder) and the links to `CODE_SIGNING.md` in the README. diff --git a/.signpath/artifact-configuration.xml b/.signpath/artifact-configuration.xml new file mode 100644 index 0000000..04de42d --- /dev/null +++ b/.signpath/artifact-configuration.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/.signpath/check-files.ps1 b/.signpath/check-files.ps1 new file mode 100644 index 0000000..d448886 --- /dev/null +++ b/.signpath/check-files.ps1 @@ -0,0 +1,61 @@ +# NVENCForgeGUI (https://github.com/burnersen/NVENCForgeGUI) +# Copyright (C) 2026 burnersen +# SPDX-License-Identifier: GPL-3.0-only +# +# Checks the Windows files a release is about to sign or publish: +# +# - every file exists, +# - its file properties carry exactly the product name and product version +# that the SignPath artifact configuration enforces (product-name, +# product-version). SignPath refuses a signing request whose files do not +# match, so this check runs on every release build, signed or not: a +# mismatch shows up long before the first signed release. +# - with -Signed: every file carries a valid Authenticode signature. +# +# Usage (from the release workflow): +# ./.signpath/check-files.ps1 -ProductName X -ProductVersion 1.2.3 -Path a.exe, b.exe [-Signed] + +param( + [Parameter(Mandatory)] [string[]] $Path, + [Parameter(Mandatory)] [string] $ProductName, + [Parameter(Mandatory)] [string] $ProductVersion, + [switch] $Signed +) + +$ErrorActionPreference = 'Stop' +$failed = 0 + +foreach ($file in $Path) { + if (-not (Test-Path -LiteralPath $file -PathType Leaf)) { + Write-Host "::error::$file is missing" + $failed++ + continue + } + $info = (Get-Item -LiteralPath $file).VersionInfo + $name = "$($info.ProductName)".Trim() + $version = "$($info.ProductVersion)".Trim() + if ($name -ne $ProductName) { + Write-Host "::error::$file has product name '$name', expected '$ProductName'" + $failed++ + } + if ($version -ne $ProductVersion) { + Write-Host "::error::$file has product version '$version', expected '$ProductVersion'" + $failed++ + } + $line = "{0}: {1} {2}" -f $file, $name, $version + if ($Signed) { + $signature = Get-AuthenticodeSignature -LiteralPath $file + if ($signature.Status -ne 'Valid') { + Write-Host "::error::$file is not validly signed ($($signature.Status): $($signature.StatusMessage))" + $failed++ + } else { + $line += ", signed by $($signature.SignerCertificate.Subject)" + } + } + Write-Host $line +} + +if ($failed -gt 0) { + Write-Host "::error::$failed problem(s) with the release files" + exit 1 +} diff --git a/CODE_SIGNING.md b/CODE_SIGNING.md new file mode 100644 index 0000000..c4c52cf --- /dev/null +++ b/CODE_SIGNING.md @@ -0,0 +1,77 @@ +# Code signing policy + +Free code signing provided by [SignPath.io](https://about.signpath.io), +certificate by [SignPath Foundation](https://signpath.org). + +> **Status:** NVENCForgeGUI has applied to the SignPath Foundation. Until +> the signing is active, `NVENCForgeGUI.exe` is not signed. Every release +> says in its text whether its exe is signed. + +## What is signed + +Only `NVENCForgeGUI.exe`, built from the source code in this repository by +the [release workflow](.github/workflows/release.yml) on GitHub-hosted +runners. Nothing that was built elsewhere is signed with this certificate. +Every signing request is approved by hand, release by release. + +Not part of this project's releases: the converter `NVENCForge.exe`, which +the window fetches from the releases of +[NVENCForge](https://github.com/burnersen/NVENCForge) (a project of its own +with its own [code signing policy](https://github.com/burnersen/NVENCForge/blob/main/CODE_SIGNING.md)), +and FFmpeg, which the converter downloads on its first run. + +The file properties of the signed exe name the product `NVENCForgeGUI` and +the version of the release; SignPath refuses to sign a file that does not +match. + +## Team roles + +| Role | Who | +| ---- | --- | +| Committers and reviewers | [burnersen](https://github.com/burnersen) | +| Approvers | [burnersen](https://github.com/burnersen) | + +Changes from anybody else (pull requests) are reviewed by a committer before +they are merged. All team members use multi-factor authentication for GitHub +and for SignPath. + +## Privacy policy + +This program will not transfer any information to other networked systems +unless specifically requested by the user or the person installing or +operating it. + +What NVENCForgeGUI does on the network, and only when you click for it: + +- **Fetching the converter:** if `NVENCForge.exe` is missing, or when you + update it, the window asks the GitHub API for the newest NVENCForge + release and downloads `NVENCForge.exe` from GitHub. The converter then + fetches FFmpeg itself (see its + [privacy policy](https://github.com/burnersen/NVENCForge/blob/main/CODE_SIGNING.md#privacy-policy)). +- **Updating the window:** on the About page, and only when you press the + button, it asks the GitHub API for the newest NVENCForgeGUI release and, + on a second click, downloads it from GitHub. + +Like any network request, these reveal your IP address to GitHub. Your +videos are converted on your own PC and never leave it. There is no +telemetry, no automatic update check, no account and no advertising. + +## Installing and uninstalling + +There is no installer. NVENCForgeGUI keeps everything (the converter, +FFmpeg, its settings, profiles and window position) in the `tools` folder +next to the exe and writes nothing to the registry. To uninstall, delete the +folder. + +## Verifying a download + +- **Signature:** right-click `NVENCForgeGUI.exe` > *Properties* > *Digital + Signatures*. A signed release shows *SignPath Foundation*. +- **Build it yourself:** see [Building it yourself](README.md#building-it-yourself). + +## Reporting a problem + +If you think a signed file of this project does something it should not, +please open an [issue](https://github.com/burnersen/NVENCForgeGUI/issues). +Signed files that break these rules can also be reported to the +[SignPath Foundation](https://signpath.org). diff --git a/README.md b/README.md index e20da09..bf06f64 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Same converter, same results, same settings file — just visible. [![License: GPLv3](https://img.shields.io/badge/License-GPLv3-blue)](#-license) [![Ko-fi](https://img.shields.io/badge/Ko--fi-Support%20me-FF5E5B?logo=kofi&logoColor=white)](https://ko-fi.com/burnersen) -**[⬇️ Download the latest release](https://github.com/burnersen/NVENCForgeGUI/releases/latest)** · **[⌨️ Prefer the command line?](https://github.com/burnersen/NVENCForge)** · **[🌐 Website](https://tech.burnersen.de/en/tools/nvencforge-en/)** · **[☕ Buy me a coffee](https://ko-fi.com/burnersen)** +**[⬇️ Download the latest release](https://github.com/burnersen/NVENCForgeGUI/releases/latest)** · **[⌨️ Prefer the command line?](https://github.com/burnersen/NVENCForge)** · **[🌐 Website](https://tech.burnersen.de/en/tools/nvencforge-en/)** · **[🔏 Code signing policy](CODE_SIGNING.md)** · **[☕ Buy me a coffee](https://ko-fi.com/burnersen)** 🇩🇪 Auf Deutsch: [tech.burnersen.de/tools/nvencforge](https://tech.burnersen.de/tools/nvencforge/) @@ -141,7 +141,9 @@ The tool modes (Split, Join, DaVinci) always run one at a time. They copy instea ## 🛡️ Windows SmartScreen / antivirus warnings -Windows or your antivirus may warn you the first time you run `NVENCForgeGUI.exe`. The honest reason: **the EXE is not code-signed.** Signing certificates cost several hundred euros *per year*, and this is a free hobby project with zero income. Unsigned Go binaries are frequent false-positive targets; there is nothing I can do about it except be transparent. +Windows or your antivirus may warn you the first time you run `NVENCForgeGUI.exe`. The honest reason: **the EXE is not code-signed yet.** Signing certificates cost several hundred euros *per year*, and this is a free hobby project with zero income. Free code signing through the [SignPath Foundation](https://signpath.org) is applied for and already prepared; see the [code signing policy](CODE_SIGNING.md). Until then, unsigned Go binaries are frequent false-positive targets, and all I can do is be transparent. + +Every release is built by GitHub Actions from this repository ([release workflow](.github/workflows/release.yml)), never on a private PC. You don't have to trust me blindly: **scan it** on [VirusTotal](https://www.virustotal.com), **read it** — the complete source is in this repository — or **[build it yourself](#building-it-yourself)**. @@ -162,6 +164,8 @@ wails build **Without `-clean`** — that would delete `build\bin\tools\` and with it the converter sitting next to the window. +Releases are built by the [release workflow](.github/workflows/release.yml) on GitHub: push a tag `vX.Y.Z` equal to `guiVersion` in `main.go`. It runs the tests and the window checks, writes the version into the file properties and, once code signing is switched on, has the exe signed ([`.signpath/README.md`](.signpath/README.md)). "Run workflow" with "dry run" ticked builds and checks everything without publishing. + The interface is a single HTML file with no build step: no npm, no bundler, no node_modules. @@ -193,6 +197,10 @@ NVENCForgeGUI is free software under the [GNU General Public License, version 3] - **Free of charge:** NVENCForgeGUI is and stays free. The official source is [github.com/burnersen/NVENCForgeGUI](https://github.com/burnersen/NVENCForgeGUI) — anyone asking money for NVENCForgeGUI is selling you what you can get here for free. - **A separate license for companies:** Want to build NVENCForgeGUI into a product that is not meant to be under the GPLv3? You can ask the author for a separate license — just [open an issue](https://github.com/burnersen/NVENCForgeGUI/issues). +### Code signing and privacy + +What is signed, who approves it and what the window fetches from GitHub (only when you click for it): [code signing policy](CODE_SIGNING.md). + ### What it is built on From 298b88d59f3c8542539199215f5748498a7c9a3d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 31 Oct 2026 05:29:52 +0000 Subject: [PATCH 2/2] README: drop the offer of a separate license for companies NVENCForgeGUI is GPL-3.0-only and nothing else. SignPath Foundation signs only projects under an OSI license without commercial dual-licensing, and the project is not meant to earn money anyway. Donations via Ko-fi stay. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GvUq7HnA5ggbuHBogzS2rV --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index bf06f64..1d0d244 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,6 @@ NVENCForgeGUI is free software under the [GNU General Public License, version 3] - **Use it:** Anyone may use NVENCForgeGUI free of charge, at home or at work, and read, change and share its source code. - **The one condition:** Whoever passes on NVENCForgeGUI or parts of it — unchanged, changed or built into a program of their own — must include the complete source code and pass everything on under the same license. A closed, paid product with NVENCForgeGUI inside is therefore not possible. - **Free of charge:** NVENCForgeGUI is and stays free. The official source is [github.com/burnersen/NVENCForgeGUI](https://github.com/burnersen/NVENCForgeGUI) — anyone asking money for NVENCForgeGUI is selling you what you can get here for free. -- **A separate license for companies:** Want to build NVENCForgeGUI into a product that is not meant to be under the GPLv3? You can ask the author for a separate license — just [open an issue](https://github.com/burnersen/NVENCForgeGUI/issues). ### Code signing and privacy