Dependency review on the dev -> main PR failed on licenses only (no
vulnerabilities): LibGit2Sharp, Microsoft.WindowsAppSDK and
Microsoft.Windows.SDK.BuildTools declare their license as a file in the
nuspec, so the dependency graph reports "unknown"/NOASSERTION and any version
bump fails the gate. All three have been dependencies since the first commit;
their licenses (MIT, Microsoft Software License Terms, Windows SDK license)
are recorded next to the exemption. Vulnerability scanning is unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The rebuilt release chain called ci.yml wholesale, which made the FlaUI UI
end-to-end job a hard release gate while it is deliberately NOT a required
check on main (hosted-runner UI automation is still proving itself). A flaky
UI run that would never block a merge could therefore block an immutable tag.
ci.yml gains a workflow_call input, ui-tests-advisory (default false), and
the ui-tests job sets continue-on-error from it; push/PR runs are unchanged.
The release workflow passes true, so build, coverage and format still block
publishing and a red UI job is visible but not fatal. Documented in
release.yml and docs/RELEASING.md as the explicit exception #44 allows; flip
the input (and add the job to main's required checks) once the suite has
earned it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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>
Save and Delete touched two stores (accounts.json and the Credential Manager
vault) with no defined order or compensation: a vault failure after the
metadata write left an account with no usable credential, and a vault failure
after a metadata delete orphaned the PAT.
Both operations now have a fixed order and a compensating step:
- Save with a token: vault write FIRST, then metadata. A vault failure changes
nothing (Store either replaces the entry or leaves the previous one intact,
so an update keeps the credential that worked). A metadata failure restores
the previous token, or deletes the new entry for a brand-new account.
- Delete: vault delete first, then metadata. A vault failure changes nothing.
A metadata failure stores the removed token again, so a listed account never
silently loses its credential and no token is left without its account.
- In-memory state changes only after both stores succeeded.
- When compensation itself fails, the new AccountConsistencyException states
the exact leftover state and how a plain retry reconciles it (Save overwrites
the vault entry and rewrites the file; Delete tolerates an absent entry), and
the activity log records the same. Neither ever contains a token.
ITokenVault.Store's contract now states the leave-unchanged-on-failure rule the
store relies on; CredentialManagerVault already behaves that way (CredWriteW is
an atomic replace) and InMemoryVault trivially does.
Tests (AccountsStoreConsistencyTests, with a faultable vault and a recording
log): vault-write failure for new and updated accounts, metadata-write failure
with and without a token, compensation failure for save and delete, vault-delete
failure, idempotent retry after every leftover state, and no token in any
exception or log message. Coverage gate stays 100%.
Closes#43
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A clone that failed or was killed after its fetch but before/during checkout
could leave a libgit-valid .git with a partial working tree whenever the
best-effort cleanup could not delete the directory (open handle, antivirus,
permissions). The next run treated it as an existing repository, saw equal
commit tips, and returned "already up to date".
The existing gclo.checkoutpending local-config marker (previously set only for
Windows-invalid-path clones) is now set the moment the fetch lands, before
anything is checked out, and cleared only after checkout completes. It is
therefore durable evidence of an incomplete clone regardless of what
interrupted it or whether cleanup succeeded. FetchAndPull already routes
marked repositories through CompletePendingCheckout, which re-validates the
tip's paths on Windows and force-checks-out the whole tree, so a marked repo is
repaired rather than trusted. Empty-origin clones clear the marker so the
unborn-HEAD path keeps handling them. Recovery metadata (.git/gclo-recovery.json)
is checked first and is unaffected.
Tests: a finished clone and an empty-origin clone leave the marker cleared; a
marked repo with a partial tree and EQUAL tips is checked out instead of
reported up to date; the same with the remote ahead materializes the new tip;
a marked repo whose tip gained a Windows-invalid path fails with the typed
exception and keeps the marker.
Closes#46
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The public list overload of OrgSyncEngine.SyncAsync combined caller-supplied
RepoDescriptor.Name values with TargetRoot via Path.Combine and went straight to
clone/pull. A rooted name, a traversal (../x), or a name with separators could
operate outside the root the caller asked for. GitHub's own names are safe, but
gclo.Engine ships on NuGet.
New public RepositoryPathResolver:
- TryValidateName: rejects blank, '.', '..', any directory separator (covers
slash-rooted and UNC), ':' on every platform (drive-relative forms such as
'C:' and 'C:repo'), and file-system-invalid or control characters.
- Resolve: normalizes root and candidate with Path.GetFullPath and requires the
candidate to sit strictly inside the root, catching anything the textual
checks miss (e.g. '...' which Windows normalization trims onto the root).
The engine resolves every target before it creates TargetRoot, reports Queued,
or calls the git client, so a bad name fails the whole call with an
ArgumentException naming the repository and nothing on disk is touched. The
git client now receives the normalized absolute folder.
Tests: resolver unit tests (valid GitHub-style names, every rejection class,
both separator styles, drive-rooted, UNC, containment backstop, relative and
messy roots) and engine tests proving rejection happens before any side
effect, for both the list and the lister overloads. Coverage gate stays 100%.
Closes#47
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The tag-triggered release accepted any v* tag and ran only a build plus the
Engine tests, so an immutable public release could be cut from a commit that
never passed main's gates. The workflow is now three jobs, each needing the
previous:
- verify: strict-semver tag check (unchanged) plus `git merge-base
--is-ancestor <tag> origin/main`; a tag off main fails here and nothing
downstream runs (push a v* tag on an unmerged commit to see it).
- gates: calls ci.yml (new workflow_call trigger) so a release passes exactly
what a PR does: zero-warning x64 build, 100% line coverage on
Engine/ViewModels/Cli, the FlaUI UI smoke suite, and the format gate. The
UI suite is not yet a required check on main PRs; it is required here.
- release: the existing publish steps, reading version/channel from the
verify job's outputs. contents: write is now scoped to this job only.
Verified: all three workflows parse; the ancestry check was run locally and
passes for v1.0.0 and origin/main and fails for the unmerged dev head.
docs/RELEASING.md describes the three stages.
Closes#44
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Feature PRs target dev, but CodeQL only watched main, so code reached the
integration branch unanalyzed. Scan pushes and PRs on both branches; the
weekly scheduled scan is unchanged. CONTRIBUTING's check table now says so.
Closes#45
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Three minor WinUI releases. Verified locally with a clean x64 unpackaged build
(warning-free) and the full FlaUI end-to-end suite (8/8 passing) against the
new runtime. Note for anyone bumping WinUI again: wipe gclo/obj first, the XAML
compiler's incremental pass-1 output from the previous SDK can mix with pass-2
from the new one and fail with CS0759 on _XamlGeneratedCreateApplicationInstance.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Dependabot has been closing its own PRs and failing weekly on actions/setup-dotnet
("no longer updatable") since the v6 release in July, so nothing has landed since.
Bump everything it should have delivered:
- actions/setup-dotnet v5 -> v6 in all five workflow usages (ESM migration only)
- LibGit2Sharp 0.31.0 -> 0.32.0 (security release, bundles libgit2 1.8.6)
- Velopack 1.2.0 -> 1.2.161
- Microsoft.Windows.SDK.BuildTools 10.0.28000.2270 -> .2705
- Microsoft.NET.Test.Sdk 18.7.0 -> 18.10.1, coverlet.collector 10.0.1 -> 10.1.0,
xunit.runner.visualstudio 3.1.5 -> 4.0.0 (all three test projects)
Verified locally: solution builds warning-free, 267 Engine + 65 CLI tests pass,
coverage gate still reports 100% on gclo.Engine / gclo.ViewModels / gclo,
dotnet format verify clean.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>