From 9762ac79fd36055a9b523978d1bc5c1332aef24f Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 31 Oct 2026 05:20:53 +0000 Subject: [PATCH 1/2] Prepare code signing with SignPath Foundation (off until set up) The release workflow can now sign NVENCForge.exe with SignPath, but only once the repository has the variable SIGNPATH_ORGANIZATION_ID and the secret SIGNPATH_API_TOKEN. Without them it builds unsigned exactly as before. - NVENCForge.exe now carries name and version in its file properties (winres/winres.json, written by the release workflow); every release build checks them, because SignPath only signs matching files. - Dry run: by hand (tick "dry run") and for pull requests that change the release workflow, winres/ 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 | 125 +++++++++++++++++++++++++-- .gitignore | 4 + .signpath/README.md | 65 ++++++++++++++ .signpath/artifact-configuration.xml | 22 +++++ .signpath/check-files.ps1 | 61 +++++++++++++ CODE_SIGNING.md | 72 +++++++++++++++ README.md | 10 ++- TECHNICAL.md | 6 ++ winres/winres.json | 22 +++++ 9 files changed, 380 insertions(+), 7 deletions(-) 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 create mode 100644 winres/winres.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ed45fde..8b27495 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,16 @@ # release asset. Runs on Windows for the same reason CI does - every source # file carries //go:build windows && amd64, so a Linux runner finds no # packages at all and would report success without building anything. +# +# 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, winres/ 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, exactly as before. name: Release on: @@ -16,15 +26,31 @@ on: tag: description: 'Existing tag to release (for example v1.25.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/**' + - 'winres/**' # The default token is read-only; publishing a release and uploading its asset -# both need write access to the repository contents. +# both need 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 @@ -46,38 +72,119 @@ jobs: # A tag that disagrees with appVersion would ship an exe announcing the # wrong version in its own startup header. Cheaper to catch here than to - # replace a published asset afterwards. + # replace a published asset afterwards. A pull request has no tag: it + # builds the version in main.go. - name: Tag matches appVersion run: | - $tag = "${{ inputs.tag || github.ref_name }}" $match = Select-String -Path main.go -Pattern '^const appVersion = "(.+)"' | Select-Object -First 1 if (-not $match) { Write-Host "::error::Could not find appVersion 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 appVersion $inCode in main.go" exit 1 } Write-Host "Tag $tag matches appVersion $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 and version in the exe's file properties (right-click > + # Properties > Details). SignPath only signs an exe whose properties + # name NVENCForge and the version of the release. + - name: File properties + run: go run github.com/tc-hib/go-winres@v0.3.3 make --in winres/winres.json --out rsrc --arch amd64 --product-version $env:VERSION --file-version $env:VERSION + # -ldflags="-s -w" drops the debug and symbol tables: the same flags # every released exe so far was built with, so the asset stays the size # users are used to. - name: Build run: go build -ldflags="-s -w" -o NVENCForge.exe . + - name: Check the file properties + run: ./.signpath/check-files.ps1 -ProductName NVENCForge -ProductVersion $env:VERSION -Path NVENCForge.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 NVENCForge.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 || 'NVENCForge' }} + 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/NVENCForge.exe NVENCForge.exe -Force + ./.signpath/check-files.ps1 -ProductName NVENCForge -ProductVersion $env:VERSION -Path NVENCForge.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: NVENCForge.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 = "${{ inputs.tag || github.ref_name }}" + $tag = $env:TAG $title = "NVENCForge $tag" Write-Host "Publishing $tag with NVENCForge.exe ($((Get-Item NVENCForge.exe).Length) bytes)." @@ -90,7 +197,15 @@ jobs: Write-Host "::error::Tag $tag has no annotation - the release notes come from it. Create it with 'git tag -a'." exit 1 } - $notes | Out-File -FilePath release-notes.md -Encoding utf8 + # 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 = "NVENCForge.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 = "NVENCForge.exe is not code signed, so Windows SmartScreen may warn. [Code signing policy]($policy)" + } + "$notes`n`n---`n`n$footer" | Out-File -FilePath release-notes.md -Encoding utf8 # gh release view exits non-zero when the release does not exist yet. # Re-running a release (a corrected workflow, a retried build) has to diff --git a/.gitignore b/.gitignore index 6ba31bd..d8643bb 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ SRTCleaner_config.txt output/ NVENCForge_Config.ini.bak NVENCForge_Config.ini.bak-* + +# Windows resources (version info), generated by the release workflow +# from winres/winres.json. +*.syso diff --git a/.signpath/README.md b/.signpath/README.md new file mode 100644 index 0000000..3bb3afb --- /dev/null +++ b/.signpath/README.md @@ -0,0 +1,65 @@ +# Code signing with SignPath: prepared, off until switched on + +NVENCForge 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 NVENCForge.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 `NVENCForge` (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 | `NVENCForge` | +| `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..d28a79e --- /dev/null +++ b/.signpath/artifact-configuration.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + diff --git a/.signpath/check-files.ps1 b/.signpath/check-files.ps1 new file mode 100644 index 0000000..9cad969 --- /dev/null +++ b/.signpath/check-files.ps1 @@ -0,0 +1,61 @@ +# NVENCForge (https://github.com/burnersen/NVENCForge) +# 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..93dc41e --- /dev/null +++ b/CODE_SIGNING.md @@ -0,0 +1,72 @@ +# Code signing policy + +Free code signing provided by [SignPath.io](https://about.signpath.io), +certificate by [SignPath Foundation](https://signpath.org). + +> **Status:** NVENCForge has applied to the SignPath Foundation. Until the +> signing is active, `NVENCForge.exe` is not signed. Every release says in +> its text whether its exe is signed. + +## What is signed + +Only `NVENCForge.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. + +FFmpeg is not part of NVENCForge and is never signed by this project: on +first run NVENCForge downloads an official build of the +[BtbN FFmpeg-Builds](https://github.com/BtbN/FFmpeg-Builds) project, or uses +the `ffmpeg.exe` you put next to it. + +The file properties of the signed exe name the product `NVENCForge` 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 NVENCForge does on the network, and only for that: + +- **FFmpeg download:** only if there is no `ffmpeg.exe` / `ffprobe.exe` next + to the exe, NVENCForge asks the GitHub API for the newest release of + [BtbN/FFmpeg-Builds](https://github.com/BtbN/FFmpeg-Builds) and downloads + it from GitHub. Nothing else is sent. + +Like any network request, this reveals your IP address to GitHub. Your +videos are converted on your own PC and never leave it. There is no +telemetry, no update check, no account and no advertising. + +## Installing and uninstalling + +There is no installer: NVENCForge is one exe. It keeps its settings +(`NVENCForge_Config.ini`), the downloaded FFmpeg and its log next to that exe +and writes nothing to the registry. To uninstall, delete the folder. If you +added NVENCForge to the "Send to" menu, also delete that shortcut +(`Win+R`, `shell:sendto`). + +## Verifying a download + +- **Signature:** right-click `NVENCForge.exe` > *Properties* > *Digital + Signatures*. A signed release shows *SignPath Foundation*. +- **Build it yourself:** see [TECHNICAL.md](TECHNICAL.md#building). + +## 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/NVENCForge/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 b06af97..de2a593 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ HDR-aware. Resilient. DaVinci-Resolve-ready. One EXE. [![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/NVENCForge/releases/latest)** ยท **[๐ŸŒ 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/NVENCForge/releases/latest)** ยท **[๐ŸŒ 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/) @@ -315,7 +315,9 @@ The five worth knowing about: ## ๐Ÿ›ก๏ธ Windows SmartScreen / antivirus warnings -Windows or your antivirus may warn you the first time you run `NVENCForge.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 `NVENCForge.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](TECHNICAL.md#building)**. @@ -338,6 +340,10 @@ NVENCForge is free software under the [GNU General Public License, version 3](LI - **Free of charge:** NVENCForge is and stays free. The official source is [github.com/burnersen/NVENCForge](https://github.com/burnersen/NVENCForge) โ€” anyone asking money for NVENCForge is selling you what you can get here for free. - **A separate license for companies:** Want to build NVENCForge 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/NVENCForge/issues). +### Code signing and privacy + +What is signed, who approves it and what NVENCForge sends over the network (only the FFmpeg download): [code signing policy](CODE_SIGNING.md). To uninstall, delete the folder; nothing is written to the registry. + ### FFmpeg NVENCForge does **not** bundle FFmpeg. On first run it downloads an official static build from the [BtbN FFmpeg-Builds](https://github.com/BtbN/FFmpeg-Builds) project (GPL-licensed) onto your machine, or you provide your own copy. FFmpeg is a separate work by the [FFmpeg project](https://ffmpeg.org) under its own license; NVENCForge invokes it as an external program. This software uses libraries from the FFmpeg project under the GPL. diff --git a/TECHNICAL.md b/TECHNICAL.md index d388812..258b04c 100644 --- a/TECHNICAL.md +++ b/TECHNICAL.md @@ -393,6 +393,12 @@ build.bat That's it. `build.bat` resolves the dependencies and compiles `NVENCForge.exe` (Go 1.21+). +Released exes are built by the [release workflow](.github/workflows/release.yml) on GitHub, which also writes name and version into the file properties (from [`winres/winres.json`](winres/winres.json)) and, once code signing is switched on, has the exe signed: see [`.signpath/README.md`](.signpath/README.md). To get the same file properties locally, run this before `build.bat`: + +``` +go run github.com/tc-hib/go-winres@v0.3.3 make --in winres/winres.json --out rsrc --arch amd64 --product-version 2.2.1 --file-version 2.2.1 +``` + --- **[โ† Back to the README](README.md)** diff --git a/winres/winres.json b/winres/winres.json new file mode 100644 index 0000000..0b7f797 --- /dev/null +++ b/winres/winres.json @@ -0,0 +1,22 @@ +{ + "RT_VERSION": { + "#1": { + "0000": { + "fixed": { + "file_version": "0.0.0.0", + "product_version": "0.0.0.0" + }, + "info": { + "0409": { + "CompanyName": "burnersen", + "FileDescription": "NVENCForge - H.265 / AV1 NVENC batch encoder", + "InternalName": "NVENCForge", + "LegalCopyright": "Copyright (C) 2026 burnersen, GPL-3.0-only", + "OriginalFilename": "NVENCForge.exe", + "ProductName": "NVENCForge" + } + } + } + } + } +} From 6f31fb52772a8c6d8885a76cd7dc254d75fffd37 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 31 Oct 2026 05:29:50 +0000 Subject: [PATCH 2/2] README: drop the offer of a separate license for companies NVENCForge 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 de2a593..404ba4e 100644 --- a/README.md +++ b/README.md @@ -338,7 +338,6 @@ NVENCForge is free software under the [GNU General Public License, version 3](LI - **Use it:** Anyone may use NVENCForge free of charge, at home or at work, and read, change and share its source code. - **The one condition:** Whoever passes on NVENCForge 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 NVENCForge inside is therefore not possible. - **Free of charge:** NVENCForge is and stays free. The official source is [github.com/burnersen/NVENCForge](https://github.com/burnersen/NVENCForge) โ€” anyone asking money for NVENCForge is selling you what you can get here for free. -- **A separate license for companies:** Want to build NVENCForge 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/NVENCForge/issues). ### Code signing and privacy