diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index ed89fe6..dfbc0ef 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -1,7 +1,6 @@ paths: - src - tests - - frontend - tools - .github diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23df3ab..31f301e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ permissions: jobs: format: name: Verify Code Format - runs-on: self-hosted + runs-on: [self-hosted, Linux] timeout-minutes: 15 steps: - name: Checkout Source @@ -26,6 +26,15 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v6 + # actions/setup-dotnet's install script defaults to a system-wide + # location (e.g. C:\Program Files\dotnet) that self-hosted runner + # service accounts often can't write to. Redirect installs into the + # per-step runner temp directory, which is always writable + # regardless of runner OS or account. (The `runner` context is + # only available inside a step, not at the job- or workflow-level + # `env:` -- confirmed via GitHub's own workflow validation error.) + env: + DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet with: dotnet-version: '10.0.x' cache: true @@ -34,30 +43,99 @@ jobs: NuGet.config - name: Restore Dependencies + shell: bash run: dotnet restore Trackdub.slnx -m:1 - name: Verify Format Style Limits + shell: bash run: dotnet format Trackdub.slnx --verify-no-changes - build: - name: Build & Test (${{ matrix.name }}) + repository-boundary: + name: Verify Repository Boundary + runs-on: [self-hosted, Linux] + timeout-minutes: 5 + steps: + - name: Checkout Source + uses: actions/checkout@v7 + + - name: Scan for stale license/desktop-boundary claims + shell: bash + run: python3 scripts/ci/check-repository-boundary.py + + build-windows: + name: Build & Test (Windows) + timeout-minutes: 45 + runs-on: [self-hosted, Windows] + steps: + - name: Checkout Source + uses: actions/checkout@v7 + + - name: Setup .NET + uses: actions/setup-dotnet@v6 + env: + DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet + with: + dotnet-version: '10.0.x' + cache: true + cache-dependency-path: | + **/packages.lock.json + NuGet.config + + - name: Restore Dependencies + shell: bash + run: dotnet restore Trackdub.slnx -m:1 + + - name: Compile + shell: bash + run: dotnet build Trackdub.slnx -c Release --no-restore -m:1 + + - name: Test + shell: bash + run: dotnet test Trackdub.slnx -c Release --no-build -m:1 + + build-linux: + name: Build & Test (Linux) timeout-minutes: 45 - runs-on: ${{ matrix.runner }} - strategy: - fail-fast: false - matrix: - include: - - name: Windows - runner: self-hosted - - name: Linux - runner: self-hosted + runs-on: [self-hosted, Linux] + steps: + - name: Checkout Source + uses: actions/checkout@v7 + - name: Setup .NET + uses: actions/setup-dotnet@v6 + env: + DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet + with: + dotnet-version: '10.0.x' + cache: true + cache-dependency-path: | + **/packages.lock.json + NuGet.config + + - name: Restore Dependencies + shell: bash + run: dotnet restore Trackdub.slnx -m:1 + + - name: Compile + shell: bash + run: dotnet build Trackdub.slnx -c Release --no-restore -m:1 + + - name: Test + shell: bash + run: dotnet test Trackdub.slnx -c Release --no-build -m:1 + + build-macos: + name: Build & Test (macOS) + timeout-minutes: 45 + runs-on: [self-hosted, macOS] steps: - name: Checkout Source uses: actions/checkout@v7 - name: Setup .NET uses: actions/setup-dotnet@v6 + env: + DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet with: dotnet-version: '10.0.x' cache: true @@ -66,10 +144,13 @@ jobs: NuGet.config - name: Restore Dependencies + shell: bash run: dotnet restore Trackdub.slnx -m:1 - name: Compile + shell: bash run: dotnet build Trackdub.slnx -c Release --no-restore -m:1 - name: Test + shell: bash run: dotnet test Trackdub.slnx -c Release --no-build -m:1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6ab2b58 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,28 @@ +# Contributing + +Trackdub (this repository) is the Apache-2.0 public core: the SDK, CLI, +pipeline, inference, media processing, infrastructure, and neutral licensing +mechanisms. See [docs/repository-policy.md](docs/repository-policy.md) and +[AGENTS.md](AGENTS.md) for organization, dependency-direction rules, and +build/test commands before opening a change. + +## Inbound contribution terms + +- Contributions to this repository are submitted under the + [Apache License, Version 2.0](LICENSE). +- By submitting a contribution, you certify that you have the right to submit + it under that license (for example, it is your own original work, or you + otherwise hold the necessary rights). +- No separate Contributor License Agreement (CLA) is currently required to + contribute here. +- This forward-looking contribution policy is separate from, and does not + affect, any historical intellectual-property ownership review of code + already in the repository. + +## Before submitting a change + +- Run `dotnet build Trackdub.slnx -m:1` and `dotnet test Trackdub.slnx -m:1`. +- Run `dotnet format Trackdub.slnx --verify-no-changes`. +- Follow the coding style and dependency-direction rules in + [AGENTS.md](AGENTS.md). +- Use imperative commit titles: `Add ...`, `Fix ...`, `Remove ...`. diff --git a/LICENSE b/LICENSE index 261061c..0a97c85 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2026 tonythethompson + Copyright 2024-2026 Trackdub LLC Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/docs/legal/CONTRIBUTOR-LICENSE-AGREEMENT.md b/docs/legal/CONTRIBUTOR-LICENSE-AGREEMENT.md deleted file mode 100644 index 9a6f12d..0000000 --- a/docs/legal/CONTRIBUTOR-LICENSE-AGREEMENT.md +++ /dev/null @@ -1,15 +0,0 @@ -# Contributor License Agreement Placeholder - -This project is intended to support GPLv3 + commercial dual licensing. - -To preserve that option, outside contributors should sign a contributor agreement before their code is merged. - -At minimum, the agreement should grant the project owner the right to: - -- use the contribution in the GPL community edition -- relicense the contribution under commercial terms -- sublicense as needed for commercial customers -- modify, distribute, and maintain the contribution -- include the contribution in future versions - -This is a placeholder. Use a lawyer-reviewed CLA or copyright assignment before accepting external contributions if dual licensing matters. diff --git a/docs/legal/LICENSE-HISTORY.md b/docs/legal/LICENSE-HISTORY.md new file mode 100644 index 0000000..5acc0de --- /dev/null +++ b/docs/legal/LICENSE-HISTORY.md @@ -0,0 +1,19 @@ +# License History + +Trackdub is split into two repositories with different licenses: + +- **`trackdubllc/Trackdub`** (this repository) — the public core: SDK, CLI, + pipeline, inference, media processing, infrastructure, and neutral + licensing mechanisms. Licensed under [Apache License, Version 2.0](../../LICENSE) + (see the root [NOTICE](../../NOTICE)). +- **The Trackdub desktop product** — a separate, private repository that + depends on this public core. It owns the desktop application shell, + product policy (export tiers, watermarking, entitlements), activation, + packaging, and release signing. It is proprietary and is not covered by + the Apache-2.0 license in this repository. + +This repository was established with a fresh root history as the public +core. It carries only Apache-2.0-compatible source and does not contain +desktop product code, activation-server code, or proprietary packaging +logic. Detailed historical ownership evidence for code predating this split +is retained privately and is out of scope for this public document. diff --git a/docs/legal/THIRD_PARTY_NOTICES.md b/docs/legal/THIRD_PARTY_NOTICES.md index 05fbf86..2775cde 100644 --- a/docs/legal/THIRD_PARTY_NOTICES.md +++ b/docs/legal/THIRD_PARTY_NOTICES.md @@ -28,17 +28,6 @@ Each entry should include: - attribution required? - notes -## Inter - -- name: Inter -- version / revision: 4.1 -- source URL: https://github.com/rsms/inter/releases/download/v4.1/Inter-4.1.zip -- license: SIL Open Font License 1.1 -- commercial use allowed? yes -- redistribution allowed? yes -- attribution required? license notice retained in `src/Trackdub.App/Assets/Fonts/Inter-LICENSE.txt` -- notes: Packaged as `InterVariable.ttf` and `InterVariable-Italic.ttf` for Trackdub UI typography. - ## FFmpeg / ffprobe Windows x64 binaries - name: FFmpeg / ffprobe Windows x64 binaries (BtbN FFmpeg-Builds, `lgpl-shared`) @@ -70,40 +59,7 @@ Each entry should include: - commercial use allowed? yes - redistribution allowed? yes, provided LGPL-2.1 obligations are met (dynamic linking, no source modifications) - attribution required? yes -- notes: .NET bindings for the LibVLC media framework. The application links to LibVLC dynamically (LGPL compliance). No modifications are made to the LibVLC or LibVLCSharp source. Used in `Trackdub.Media.Playback` and `Trackdub.App.Avalonia`. - -## LibVLCSharp.Avalonia - -- name: LibVLCSharp.Avalonia -- version / revision: centrally pinned in Directory.Packages.props -- source URL: https://www.nuget.org/packages/LibVLCSharp.Avalonia -- license: LGPL-2.1-or-later -- commercial use allowed? yes -- redistribution allowed? yes, same terms as LibVLCSharp -- attribution required? yes -- notes: Avalonia-specific VideoView control for rendering LibVLC video output. Used in `Trackdub.App.Avalonia` only. - -## VideoLAN.LibVLC.Windows (LibVLC native runtime — Windows) - -- name: VideoLAN.LibVLC.Windows -- version / revision: centrally pinned in Directory.Packages.props -- source URL: https://www.nuget.org/packages/VideoLAN.LibVLC.Windows -- license: LGPL-2.1-or-later -- commercial use allowed? yes -- redistribution allowed? yes, provided LGPL-2.1 notice and dynamic-linking obligations are met -- attribution required? yes -- notes: Bundled LibVLC native runtime for Windows (~100 MB). Extracted at build time into the application output directory. The application links dynamically — no static linking or source modification. Scoped to the Avalonia app project. - -## VideoLAN.LibVLC.Mac (LibVLC native runtime — macOS) - -- name: VideoLAN.LibVLC.Mac -- version / revision: centrally pinned in Directory.Packages.props -- source URL: https://www.nuget.org/packages/VideoLAN.LibVLC.Mac -- license: LGPL-2.1-or-later -- commercial use allowed? yes -- redistribution allowed? yes, same terms as the Windows runtime package -- attribution required? yes -- notes: Bundled LibVLC native runtime for macOS. Extracted at build time into the application output directory. The application links dynamically — no static linking or source modification. Scoped to the Avalonia app project. +- notes: .NET bindings for the LibVLC media framework. Trackdub links to LibVLC dynamically (LGPL compliance). No modifications are made to the LibVLC or LibVLCSharp source. Used in `Trackdub.Media.Playback` as one of two composited playback backends (libmpv is the primary compositor; LibVLC is the fallback). Bundling the native LibVLC runtime and any Avalonia-specific video-rendering control is a packaging concern of the consuming desktop product, not the public core, and is documented in that product's own third-party notices. ## LibVLC on Linux (system-installed) @@ -114,7 +70,7 @@ Each entry should include: - commercial use allowed? yes - redistribution allowed? n/a — not bundled; users install via their system package manager - attribution required? yes (license notice in documentation) -- notes: On Linux, no NuGet runtime package is available. The application uses the system-installed `libvlc.so` located by `LibVlcRuntimeLocator`. Users must install VLC (e.g., `sudo apt install vlc` or equivalent) for playback to function. +- notes: On Linux, no NuGet runtime package is available. `Trackdub.Media.Playback`'s `LibVlcRuntimeLocator` falls back to the system-installed `libvlc.so`. End users must install VLC (e.g., `sudo apt install vlc` or equivalent) for the LibVLC playback backend to function. ## Trackdub.OnnxRuntime.Dnnl.Native (generated package) diff --git a/scripts/ci/check-repository-boundary.py b/scripts/ci/check-repository-boundary.py new file mode 100644 index 0000000..d85fc82 --- /dev/null +++ b/scripts/ci/check-repository-boundary.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +"""Scan the public-core legal/policy surface for stale monorepo-era claims. + +Guards against regressions like the GPLv3/dual-license CLA wording and the +false "Implemented in Application layer" IExportTierGate claim found during +the open-core split: license text that contradicts the Apache-2.0 LICENSE, +and desktop/cloud project names bleeding into files a public consumer of +this core would read as authoritative. + +This intentionally does not scan docs/architecture, docs/specs, +docs/operations, docs/development, docs/decisions, docs/audits, docs/plans, +or tools/**: those contain legitimate historical/internal-engineering +references to pre-split monorepo projects (Trackdub.App.Avalonia, +Trackdub.Api, Trackdub.Worker, Trackdub.WebhookDelivery, the activation +service) that are a separate, larger documentation cleanup — not part of +this check. +""" + +from __future__ import annotations + +import re +import subprocess +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[2] + +# License-claim patterns: must never appear anywhere in the tracked tree +# (excluding historical planning/audit records and third-party notices, +# which may legitimately discuss or quote other licenses). +LICENSE_CLAIM_PATTERNS = [ + # Matches GPL/GPLv3/GPL-3.0-only/"GPL 3.0" etc., case-insensitively, + # while excluding LGPL/AGPL (a letter immediately before "GPL"). + re.compile(r"(? list[Path]: + output = subprocess.run( + ["git", "ls-files"], + cwd=REPO_ROOT, + check=True, + capture_output=True, + text=True, + ).stdout + return [REPO_ROOT / line for line in output.splitlines() if line] + + +def matches_any(rel_posix: str, prefixes: list[str]) -> bool: + return any(rel_posix == p.rstrip("/") or rel_posix.startswith(p) for p in prefixes) + + +def scan(files: list[Path], patterns: list[re.Pattern[str]]) -> list[str]: + violations: list[str] = [] + for path in files: + try: + text = path.read_text(encoding="utf-8") + except (UnicodeDecodeError, OSError): + continue + for lineno, line in enumerate(text.splitlines(), start=1): + for pattern in patterns: + if pattern.search(line): + rel = path.relative_to(REPO_ROOT) + violations.append(f"{rel}:{lineno}: matched /{pattern.pattern}/: {line.strip()}") + return violations + + +def main() -> int: + all_files = tracked_files() + violations: list[str] = [] + + license_files = [ + f + for f in all_files + if not matches_any(f.relative_to(REPO_ROOT).as_posix(), LICENSE_CLAIM_EXCLUDE_DIRS) + and f.relative_to(REPO_ROOT).as_posix() not in LICENSE_CLAIM_EXCLUDE_FILES + ] + violations += scan(license_files, LICENSE_CLAIM_PATTERNS) + + boundary_files = [ + f + for f in all_files + if matches_any(f.relative_to(REPO_ROOT).as_posix(), BOUNDARY_SCAN_PATHS) + ] + violations += scan(boundary_files, BOUNDARY_PATTERNS) + + if violations: + print("Repository-boundary scan failed:") + for v in violations: + print(f" {v}") + print() + print( + "Stale license or desktop/cloud-boundary wording found in the public-core " + "legal/policy surface. See docs/legal/LICENSE-HISTORY.md and " + "docs/repository-policy.md." + ) + return 1 + + print("Repository-boundary scan passed.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/Trackdub.Cli/Trackdub.Cli.csproj b/src/Trackdub.Cli/Trackdub.Cli.csproj index dae9e1f..8595969 100644 --- a/src/Trackdub.Cli/Trackdub.Cli.csproj +++ b/src/Trackdub.Cli/Trackdub.Cli.csproj @@ -6,6 +6,11 @@ true trackdub Trackdub.Cli + Trackdub + Trackdub command-line interface for the local-first AI dubbing pipeline. + Apache-2.0 + https://github.com/trackdubllc/Trackdub + https://github.com/trackdubllc/Trackdub diff --git a/src/Trackdub.Contracts/IExportTierGate.cs b/src/Trackdub.Contracts/IExportTierGate.cs index f4ed061..5b7b4e5 100644 --- a/src/Trackdub.Contracts/IExportTierGate.cs +++ b/src/Trackdub.Contracts/IExportTierGate.cs @@ -1,7 +1,8 @@ namespace Trackdub.Contracts; /// -/// Checks tier gates before export begins. Implemented in Application layer. +/// Checks tier gates before export begins. The public core ships no concrete +/// implementation; a consuming product supplies its own tier policy. /// public interface IExportTierGate { diff --git a/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj b/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj index 31ae1c1..5b19bb4 100644 --- a/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj +++ b/src/Trackdub.OnnxRuntime.Dnnl.Native/Trackdub.OnnxRuntime.Dnnl.Native.csproj @@ -8,6 +8,8 @@ Trackdub DNNL-enabled ONNX Runtime native assets for Trackdub. MIT + https://github.com/trackdubllc/Trackdub + https://github.com/trackdubllc/Trackdub false $(NoWarn);NU5128 diff --git a/tests/Trackdub.Media.Tests/WavePcm16Tests.cs b/tests/Trackdub.Media.Tests/WavePcm16Tests.cs index a19116e..28246de 100644 --- a/tests/Trackdub.Media.Tests/WavePcm16Tests.cs +++ b/tests/Trackdub.Media.Tests/WavePcm16Tests.cs @@ -399,7 +399,7 @@ await WavePcm16.WriteSamplesAsync( using (var destinationLock = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.None)) { - Exception ex = await Assert.ThrowsAsync(() => + Exception ex = await Assert.ThrowsAnyAsync(() => WavePcm16.WriteSamplesAsync( path, [0.9f, -0.9f, 0.9f, -0.9f],