diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25da803..1e02f83 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,8 +30,17 @@ dotnet build gclo.slnx -p:Platform=x64 # Verify this still works before opening a PR. dotnet build gclo.slnx -p:Platform=x64 -p:WindowsPackageType=None -# Run the engine test suite +# Run the unit/integration test suites (engine + view models, and the CLI) dotnet test gclo.Engine.Tests +dotnet test gclo.Cli.Tests + +# Coverage as CI measures it (must be 100% for gclo.Engine, gclo.ViewModels, gclo) +dotnet test gclo.Engine.Tests --settings coverage.runsettings --collect:"XPlat Code Coverage" +dotnet test gclo.Cli.Tests --settings coverage.runsettings --collect:"XPlat Code Coverage" + +# UI end-to-end tests (build the app first, then drive the real exe) +dotnet build gclo/gclo.csproj -p:Platform=x64 -p:WindowsPackageType=None +dotnet test gclo.UiTests/gclo.UiTests.csproj # Formatting/style gate — must report no changes needed dotnet format gclo.slnx --verify-no-changes --severity error @@ -63,7 +72,8 @@ Every pull request must pass: | Check | What it gates | | --- | --- | -| **Build and test (x64)** | `dotnet build gclo.slnx -p:Platform=x64 -warnaserror` — zero warnings, including NuGetAudit vulnerability warnings; then `dotnet test gclo.Engine.Tests` with coverage, and `gclo.Engine` line coverage must stay **≥ 60%** | +| **Build and test (x64)** | `dotnet build gclo.slnx -p:Platform=x64 -warnaserror` — zero warnings, including NuGetAudit vulnerability warnings; then the test suites with coverage. **Line coverage must be 100%** on each of `gclo.Engine`, `gclo.ViewModels`, and `gclo` (the CLI), measured via `coverage.runsettings` (source-generated code and the `[ExcludeFromCodeCoverage]` native/network adapters are excluded — see that file) | +| **UI end-to-end tests (x64)** | FlaUI/UIA smoke tests drive the real `gclo.exe` (`gclo.UiTests`) | | **Format (style gate)** | `dotnet format gclo.slnx --verify-no-changes --severity error` | | **Dependency review** | New/changed dependencies must have no known vulnerabilities (any severity fails) and a license on the repo's allowlist | | **CodeQL** | Static security analysis (runs on PRs targeting `main` and weekly) | diff --git a/Directory.Build.props b/Directory.Build.props index 9da913d..e14ba8f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -10,13 +10,14 @@ true - + version output surface as the short hash. Prefix tracks the next expected + release after the last stable tag (v1.0.0). --> - 0.1.0 + 1.0.1 dev diff --git a/README.md b/README.md index 2b39d2b..41f9325 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,9 @@ All builds are published on the [**GitHub Releases** page](https://github.com/Ko Plain version tags (`v1.2.3`) are **stable** releases; pre-release tags (`v1.2.3-beta.1`) publish to the **dev** channel, and an installed app only ever updates within its own channel. -Installation via `winget` is coming soon. +> **Upgrading from a beta?** Channels don't cross: a dev/beta install never auto-updates to a stable release (its **Check for updates** only looks at the dev channel). To move to stable, install `gclo-stable-Setup.exe` once — it takes over the existing install and self-updates within the stable channel from then on. + +`winget` support is planned (tracked in [#7](https://github.com/KofTwentyTwo/gclo/issues/7)); until then, install from the Releases page above. ## Getting a token @@ -37,7 +39,7 @@ gclo authenticates to GitHub with a personal access token — it is used for bot | Classic PAT | `repo` scope (read access to the org's repositories); optionally `read:org` so the organization dropdown / `gclo orgs` can list your orgs | | Fine-grained PAT | Repository read access for the organization | -The token is used in memory for the duration of a sync and is never stored on disk. +**Token storage.** In **Quick Sync**, the token is held in memory for the session only and never written anywhere. A **saved account's** token and the optional **default token** (Settings) are kept in the **Windows Credential Manager** (per-user, DPAPI-protected) — never in `settings.json`, `accounts.json`, or any log. See [SECURITY.md](SECURITY.md). ## Using the GUI @@ -168,6 +170,10 @@ To F5-debug the packaged app in Visual Studio, open `gclo.slnx`, set `gclo` as t | `gclo.Engine` | Core sync engine: `OrgSyncEngine`, Octokit-based listers, LibGit2Sharp git client, Windows path validation | | `gclo.ViewModels` | UI-framework-free view models and settings persistence, shared presentation logic | | `gclo.Engine.Tests` | xunit tests: engine (with fakes), real-git integration suite, and view-model tests | +| `gclo.Cli.Tests` | xunit tests for the CLI, driving injectable command cores over fakes | +| `gclo.UiTests` | FlaUI/UIA end-to-end tests that drive the real `gclo.exe` | + +Line coverage is held at **100%** for `gclo.Engine`, `gclo.ViewModels`, and `gclo` (the CLI), enforced in CI. ## Contributing diff --git a/SECURITY.md b/SECURITY.md index e8fd0f9..d5b2705 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -35,7 +35,8 @@ gclo is maintained by a single person in their spare time, so response times are gclo works with GitHub Personal Access Tokens, so token safety is part of the design: -- **The PAT is kept in memory only.** It is used for the GitHub API and as the git HTTPS credential for the duration of a run, and is never written to disk, settings, or logs. The app's persisted settings (`%LOCALAPPDATA%\gclo\settings.json`) contain only preferences such as the default folder, parallelism, and theme — never the token. +- **Quick Sync tokens are kept in memory only.** A token pasted into Quick Sync is used for the GitHub API and as the git HTTPS credential for the duration of the session, and is never written to disk, settings, or logs. +- **Saved-account tokens and the default token live in the Windows Credential Manager.** When you save an account, or set a default token in Settings, the token is stored in the per-user Windows Credential Manager (DPAPI-protected), under a `gclo:account:` target, and removed when the account or token is deleted. It is **never** written to `settings.json`, `accounts.json`, or any log — those files hold only non-secret metadata (organization, target folder, parallelism, theme, last-sync summary). This is why accounts are Windows-only. - **The CLI refuses tokens on the command line.** There is deliberately no `--token ` option; tokens are accepted only via environment variable (`--token-env`, default `GITHUB_TOKEN`), a file (`--token-file`), or standard input (`--token-stdin`). See [docs/CLI.md](docs/CLI.md). - **Secret-scanning push protection is enabled** on this repository, so credentials cannot be accidentally committed and pushed. diff --git a/TODO.md b/TODO.md index 9983a21..e1a8b67 100644 --- a/TODO.md +++ b/TODO.md @@ -2,8 +2,7 @@ **Development is tracked in [GitHub Issues](https://github.com/KofTwentyTwo/gclo/issues).** -- Roadmap / execution order: [#11 — Development roadmap](https://github.com/KofTwentyTwo/gclo/issues/11) -- Current priority: [#2 — Windows-invalid path clone failures](https://github.com/KofTwentyTwo/gclo/issues/2) +- Roadmap / current status: [#11 — Development roadmap](https://github.com/KofTwentyTwo/gclo/issues/11) (v1.0.0 shipped; post-1.0 backlog there) - Owner action items: [#7 — Owner setup checklist](https://github.com/KofTwentyTwo/gclo/issues/7) Labels: `priority` (work first), `needs-owner` (blocked on the owner), `deferred` diff --git a/docs/CLI.md b/docs/CLI.md index ea4e467..5ed1ead 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -319,5 +319,7 @@ done ```console $ gclo --version -0.1.0-beta.6 (9ac6c2bde) +1.0.0 (a893741d2) ``` + +Released builds print the semantic version and the short commit hash; local builds print the next-release version with a `-dev` suffix (e.g. `1.0.1-dev ()`). diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 33d1662..45baf79 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -163,3 +163,7 @@ published release: its assets cannot be swapped in place. gh release delete v1.2.3 --yes git push origin :refs/tags/v1.2.3 ``` + +> The repository's **tag protection ruleset** blocks tag deletion by default. To +> delete a bad tag, temporarily disable (or add a bypass to) the tag ruleset in +> **Settings → Rules → Rulesets**, delete the tag, then re-enable it. diff --git a/docs/plans/accounts-mode.md b/docs/plans/accounts-mode.md index fb49f33..f4ef30a 100644 --- a/docs/plans/accounts-mode.md +++ b/docs/plans/accounts-mode.md @@ -1,5 +1,9 @@ # Implementation plan: Accounts mode + workspace redesign +> **Status: shipped.** Delivered across the v0.1.0 betas and released in +> **v1.0.0** (issues #16 and #22 closed). This document is kept as the historical +> execution plan; the tracker of record is GitHub Issues. + Delivers issue #16 (Accounts mode) built directly into the layout redesign direction recorded on that issue, with issue #22's findings reconciled along the way. Tracker of record: GitHub Issues; this document is the executable plan.