main
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1915ce2f94
|
docs(release): the documents say what 1.1.1 does, and the package manifests verify the file they name (#199)
Statements the release reviews of 1.1.1 found untrue at this commit, and two gaps in the release tooling. - Threat model: the version reviewed; an installed build contacts git.kof22.com for updates; the binaries are signed (the accepted risks named them unsigned) and T1 with the Scoop part of T2 is what is accepted; T2 and T11 say what ADR 0009 changed, and T11 is not marked mitigated as a whole while the copy to the release server is manual. - SECURITY.md names 1.1.x as the supported line. - README: the beta is a separate app with its own accounts; parallelism is under Sync options, after loading; the buttons have the names on screen; the app is built unpackaged, with no Developer Mode. CONTRIBUTING the same. docs/CLI.md shows a current version. - RELEASING.md: the check that the server answers from outside comes before anything is tagged; a version that moves the updater is rehearsed with two prereleases read from that server; the copy to git.kof22.com is a numbered step; the packaging change is committed on Gitea; winget is updated by hand while the job would submit the GitHub URL; the engine package is numbered by its own public surface. - Update-PackageManifests.ps1 downloads the file the manifests will name and compares its SHA-256 with that of the built file it is given, instead of asking only whether the URL answers; it writes the Scoop manifest with the repository's line endings. - One vault test stored an entry in the credential namespace the installed app uses. It uses two test scopes now (#161). Closes #183 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Signed-off-by: James Maes <james@kof22.com> |
||
|
|
6696e37049
|
feat(update): updates and release downloads come from git.kof22.com (#171)
The in-app updater reads the project's releases on its own Gitea server through Velopack's GiteaSource, anonymously over HTTPS. The Scoop manifest (homepage, download, version check, auto-update), the Chocolatey package and the script that regenerates both for a release name the same server. - ADR 0009 amends ADR 0001. The threat model records where that trust is now placed: the updater checks hashes from the same feed and no signature, so whoever can publish on the server can deliver an update. T1 is accepted for 1.1.1, not mitigated. - Update-PackageManifests.ps1 refuses to write a manifest whose download does not answer, so a package cannot be pushed before its release is on the server. - RELEASING.md: what a release on git.kof22.com must contain, the prerelease flag, the ten-release window, and where a broken release is withdrawn. - PackagingManifestTests pin the auto-update URL, the hash URL, the release notes link and the version check exactly. Versions up to 1.1.0 look for updates on GitHub and are updated once by hand. Closes #170 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Signed-off-by: James Maes <james@kof22.com> |
||
|
|
2c4726e30e |
feat(release): Authenticode-sign releases with Azure Artifact Signing over OIDC (#96)
## What
Releases are now Authenticode-signed (K22-REL-05) through the standards'
shared workflow, which already carries the signing steps behind `sign`
(`azure/login` v3.1.0 and `azure/artifact-signing-action` v2.0.0, both
SHA-pinned and current; `vpk pack --azureTrustedSignFile`). ADR 0008.
- `release.yml`: `sign: true`; new `verify-signatures` job after
`release` downloads the published Setup.exe, portable zip and CLI zip
and runs `signtool verify /pa /all` + `Get-AuthenticodeSignature` on
every gclo executable, failing on an invalid, untimestamped or
foreign-publisher signature (`TRUSTED_SIGNING_SUBJECT`).
- Authentication is GitHub OIDC: an Entra application
`gclo-release-signing` with a federated credential for
`repo:KofTwentyTwo/gclo:environment:release` and only *Artifact Signing
Certificate Profile Signer* on the certificate profile. No secret, key
or PFX anywhere. The identity is `release`-environment **variables**:
`AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_SUBSCRIPTION_ID`,
`TRUSTED_SIGNING_ENDPOINT`, `TRUSTED_SIGNING_ACCOUNT`,
`TRUSTED_SIGNING_PROFILE`, `TRUSTED_SIGNING_SUBJECT`.
- `.github/scripts/Set-ReleaseSigning.ps1`: idempotent Azure
configuration (reads the existing account and Active profile through
ARM, ensures app + service principal + federated credential +
profile-scoped role, prints the `gh variable set` lines). Run
interactively by the owner; never creates secrets or touches the
account, validation or profile.
- Docs: RELEASING.md ("Code signing", local signing with SignTool + the
`Microsoft.ArtifactSigning.Client` dlib, the verify job), SECURITY.md,
README verify step 4, threat-model revision row.
Closes #57 (part of #62). After the first signed release verifies,
EX-0002 closes for gclo in the standards register.
## Azure configuration status
Pending the owner's interactive sign-in; the script output and `signtool
verify` results of the first signed prerelease will be posted here
before merge.
## How it was tested
- `actionlint` clean; PSScriptAnalyzer 0 findings.
- Verification of a real signed build: pending the Azure configuration
(recorded here when done).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Signed-off-by: James Maes <james@kof22.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
987762295d |
ci: release through the standards' shared Velopack workflow; publishers fail instead of skip (#77)
## What Releases now build through the standards' shared `release-velopack.yml` (standards#5, pinned to `e8ab30f`), which gives SLSA Build L3 provenance and lets exception EX-0004 close after the first successful run. `release.yml` keeps only what is gclo's, and every publisher **fails instead of skipping** when it cannot publish, so a green run means every channel shipped (#76, part of #62; blocks #67). - `release.yml`: `verify` (tag on `main`) → `gates` (the full `ci` workflow, now including the FlaUI suite as a blocking gate since it is a required check on `main`; the `ui-tests-advisory` input is removed, closes #54) → `release` (shared workflow: locked restore, Release build, tests + 100% coverage gate, publish, vpk pack, Syft SBOMs, `SHA256SUMS`, provenance, draft-then-publish) → caller-side `packages` (Scoop/Chocolatey manifests PR + `choco push`), `winget`, and opt-in `nuget`. Publishers run in the `release` environment (created; deployment rule: tags `v*`) and fail on a missing `DEPS_PAT`, `CHOCO_API_KEY`, `WINGET_TOKEN`/`WINGET_PACKAGE_ID`, or `NUGET_API_KEY` when `NUGET_PUBLISH` is `true`. Separate jobs, so a failed publisher re-runs alone after its token is added. - **Lock files:** the locked release publish had never run (`-p:RestoreLockedMode=true` arrived in #68 after the last tag) and failed locally: `-r win-x64 --self-contained -p:PublishSingleFile=true` changes every project's restore graph (RID graph; `Microsoft.NET.ILLink.Tasks` via the single-file analyzer). `gclo.Engine`, `gclo.ViewModels` and `gclo.Cli` now declare `RuntimeIdentifiers=win-x64` and `EnableSingleFileAnalyzer=true`, and the lock files carry both graphs, so the plain locked restore and the publish agree. - Asset names follow the shared workflow: `gclo-cli-win-x64-<version>.zip`, `gclo-<version>.cdx.json`, `gclo-cli-<version>.cdx.json`; generated release notes replace `New-ReleaseNotes.ps1` (deleted). `Update-PackageManifests.ps1`, `bucket/gclo.json` (autoupdate URL) and `PackagingManifestTests` follow; the tests accept both names because 1.0.0's manifests still point at the unversioned asset. - LICENSE ships inside the published app and CLI through the project files (the shared workflow does not add it). - Docs: `docs/RELEASING.md` rewritten (required tokens table, rehearsal prerelease step, per-job recovery), ADR 0007, README "Verifying a release" (`--signer-repo KofTwentyTwo/standards`), SECURITY.md, CONTRIBUTING gate table, ADR 0003, threat model T11 + revision row. #7 lists the tokens to add. ## How it was tested - `dotnet restore gclo.slnx -p:Platform=x64 --locked-mode` passes; `dotnet build … -warnaserror` 0 warnings; `gclo.Engine.Tests` 422/422 and `gclo.Cli.Tests` 129/129 with 100% line coverage on all three packages; `dotnet format --verify-no-changes --severity warn` clean; PSScriptAnalyzer 0 findings; `actionlint` clean on both workflows. - The shared workflow's exact publish commands pass locked mode locally and include `LICENSE`: ```powershell dotnet publish gclo.Cli/gclo.Cli.csproj -c Release -r win-x64 --self-contained -p:RestoreLockedMode=true -p:PublishSingleFile=true dotnet publish gclo/gclo.csproj -c Release -p:Platform=x64 -r win-x64 --self-contained -p:RestoreLockedMode=true -p:WindowsPackageType=None -p:WindowsAppSDKSelfContained=true -p:PublishTrimmed=false ``` - Not yet exercised on a real tag: the shared workflow has never run (its author asked for gclo's next prerelease to be its first). Per #67 the rehearsal is `v1.0.1-beta.2`, after the `release` environment holds the tokens listed on #7. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: James Maes <james@kof22.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
50b3c134eb |
style: adopt the Kingsrook C# layout and the standard .NET quality gate (#70)
* style: adopt the Kingsrook C# layout and the standard .NET quality gate The standard .editorconfig and Directory.Build.props from KofTwentyTwo/standards (3-space indent, Allman braces, `if(` without a space, file-scoped namespaces, var only when apparent, `s_` static fields, IDE0055 and the Meziantou analyzers as build errors, NuGetAudit on the whole graph, CI-conditional locked restore), central package management in Directory.Packages.props, LF line endings via .gitattributes, and the SPDX header on every C# file. Members are separated by three blank lines, one top-level type per file (24 types moved into their own files), ArgumentException parameter names, bounded regex match times, the announcement event in the EventHandler<AnnouncementEventArgs> shape, and the CLI sync command split into option parsing, the run, and summary reporting. Repository-specific adjustments, each justified in .editorconfig: namespaces keep the product name `gclo`; MA0051 flags only extremes (160 lines / 100 statements); the app project keeps CA1822, IDE0051/52 (XAML-referenced handlers; dotnet format's fixer would delete them) and IDE0060 (handler signatures) off; XAML stays at 4 spaces. PowerShell scripts use the standard PSScriptAnalyzer settings: strict mode, comment-based help, Allman and 3-space layout, no Write-Host; the NuGet update script now edits Directory.Packages.props. The CI format gate runs at --severity warn and PSScriptAnalyzer. Behavior is unchanged: Engine 422, CLI 129 and FlaUI 11 tests pass, line coverage stays at 100%. Closes #65 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: James Maes <james@kof22.com> * ci: analyze PowerShell scripts one file at a time PSScriptAnalyzer 1.25.0 intermittently fails with "Object reference not set to an instance of an object" when Invoke-ScriptAnalyzer is handed a directory (it passed on the same scripts an hour earlier, and locally the same call crashes on some runs and not others). Handing it one script per call never crashed in repeated local runs, so the format job now loops over the scripts. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: James Maes <james@kof22.com> --------- Signed-off-by: James Maes <james@kof22.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
a562acd55c |
ci: adopt the standards' pull-request, security, CodeQL and Scorecard gates (#68)
* ci: adopt the standards' pull-request, security, CodeQL and Scorecard gates
Call the KofTwentyTwo/standards reusable workflows (pinned to 855cf44):
pr-gates (Conventional Commit title, DCO, dependency review), security
(gitleaks over history, Trivy + OSV-Scanner on the lock files, zizmor +
actionlint), codeql (security-extended for csharp and actions, gated at
high), plus the Scorecard workflow. Root scanner configs, global.json,
.pre-commit-config.yaml with the dotnet-format hook, and the standard
PSScriptAnalyzer settings come with them.
Harden the existing workflows: persist-credentials false on every checkout,
no restore cache in the release job, verify-job outputs and inputs read from
environment variables instead of ${{ }} inside run:, concurrency on release,
locked restores for publish and pack (the CLI now declares win-x64 so its
lock file carries that runtime graph).
Release assets: a CycloneDX 1.6 SBOM per artifact (attached and attested),
SHA256SUMS (renamed; the channel feed is listed too), LICENSE inside the CLI
zip and the app payload, and release notes generated from Conventional
Commit subjects by .github/scripts/New-ReleaseNotes.ps1 with breaking and
security changes first. Generated pull requests use Conventional Commit
titles; Dependabot gets the 7-day cooldown and the ci prefix; the NuGet
update script holds back versions younger than the cooldown.
The old job names and dependency-review.yml stay until protect-main lists
the new required contexts (#66).
Closes #63
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
* ci: pin the standards workflows to the commit that exempts file-licensed packages
standards#4 (merged as ae174f5) adds the `allow-dependencies-licenses` input to
the reusable pull-request workflow, fixes the DCO check for commits whose author
has no GitHub login, and accepts `security` titles. The three callers move to
that commit, and pr-gates.yml exempts LibGit2Sharp, Microsoft.WindowsAppSDK and
Microsoft.Windows.SDK.BuildTools from the license check (standards EX-0003):
their nuspecs name a license file, so the dependency graph reports NOASSERTION.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
---------
Signed-off-by: James Maes <james@kof22.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
|
||
|
|
2d64ac475a |
Packaging: Scoop bucket, Chocolatey package, SHA256SUMS.txt (#9)
- bucket/gclo.json: this repo is its own Scoop bucket; checkver github, autoupdate keyed on SHA256SUMS.txt. Verified locally with scoop install. - packaging/chocolatey: nuspec + Install-ChocolateyZipPackage script for the same gclo-cli-win-x64.zip asset. - .github/scripts/Update-PackageManifests.ps1: single source of truth that re-points both manifests at a stable release (refuses prereleases). - release.yml: write + attest + attach SHA256SUMS.txt on every release; on stable tags update the manifests, choco pack, choco push when CHOCO_API_KEY is set, and open a PR against dev with the updated manifests. - gclo.Cli.Tests/PackagingManifestTests.cs: both manifests valid, stable, and describing the same asset. - docs/RELEASING.md + README: install and secret docs. Closes #9 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
c37e411c0e |
CI: replace Dependabot's NuGet updates with a workflow that can see WinUI TFMs
Dependabot's NuGet updater cannot evaluate Windows-versioned target frameworks (dependabot/dependabot-core#13923, open since January). On this repo it logged every newer package as "not compatible. Incompatible project frameworks: net10.0-windows10.0.19041", and because it updates a package consistently across projects, the same packages were blocked in the plain net10.0 test projects too. Net effect: WindowsAppSDK, Velopack, xunit.runner.visualstudio and Microsoft.NET.Test.Sdk were never offered, and the one PR it did open was closed by the bot itself. - .github/scripts/Update-NuGetPackages.ps1 drives the bump from `dotnet list package --outdated --format json` (real MSBuild/NuGet evaluation): applies minor/patch bumps by exact textual edit of each PackageReference (encoding and line endings preserved), holds major bumps and prereleases for review, and writes a Markdown report. Verified on a copy of the repo with four packages downgraded: three minor/patch bumps applied, the major held, and the edited csproj byte-identical to HEAD. - .github/workflows/nuget-updates.yml runs it weekly (Mondays 06:00 ET) or on demand (with an include-major switch), runs the build/test/format gates against the bumped tree, and opens or refreshes one PR on deps/nuget-weekly against dev with the report and gate results in the body. The third-party create-pull-request action is pinned to a commit SHA. With GITHUB_TOKEN the PR gets no checks of its own (GitHub does not chain workflows from it); an optional DEPS_PAT secret enables that. - dependabot.yml keeps only the github-actions ecosystem and explains why. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |