feat(app): the Add account wizard asks where the repositories are, and can add an account on a Gitea server #207

Merged
james.maes merged 3 commits from feat/206-gitea-wizard into main 2026-11-11 22:24:40 +00:00
Owner

What

Step 3 of #201, stacked on #205: the desktop app's Add account wizard can add an account on a Gitea server.

  • Step 1 asks, for a new account, where the repositories are: GitHub (default) or a Gitea server and its address. The address is checked by the rule the command line uses (ForgeEndpoint.TryCreate) and shown as it was normalized.
  • Step 2 checks the token with the chosen place. The wizard holds the lister of one place at a time: the shell gives it a lister per place, and step 1 takes the one of the place that was chosen.
  • Nothing is carried to another place: when step 1 is left with another place than before, the typed token, the organization and the organization list are emptied. The default token (a GitHub token) is neither offered nor preselected for a Gitea server.
  • An edit, and a Quick Sync connection saved as an account, offer no choice and say where the account is.
  • Texts follow the place: the token box, the "How to create a token" page, the note of step 2, the connect card of an account's page.
  • UI fixture: answers for a Gitea server with an organization of its own; the wizard's listers are wrapped by it like a workspace's.
  • README, ADR 0010, threat model T16.

Why

Closes #206. The rules, each pinned by a test in AccountWizardPlaceTests:

  • a token is sent to the chosen place and to no other;
  • a token typed for one place is not kept when another place is chosen (GitHub to a server, and one server to another);
  • an address that cannot be used keeps the wizard on step 1, nothing is sent, and the address is not repeated in the message;
  • the default token is never sent to a Gitea server;
  • a wizard that was given one lister stays on the place of that lister, whatever is set on it.

How it was tested

  • AccountWizardPlaceTests (view model), one new test in the UI suite that walks the wizard for a Gitea server against the offline fixture.
  • Gates, started from PowerShell: numbers in the comment below.
  • Looked at on screen: step 1 with and without the server box, step 2 for a Gitea server.

Not in this change

  • Quick Sync stays GitHub only.
  • The screenshot of the wizard in the README shows step 1 as it was.
  • The Share invitation still says "GitHub organization".

Not merged until

1.1.1 is tagged (#200), and #203 and #205 are merged. The base of this pull request is the branch of #205.

Checklist

  • Commits are signed and signed off (git commit -S -s)
  • Zero build warnings; format and lint are clean
  • Tests added or updated; the 100% coverage gate still passes
  • Docs updated for user-visible changes; threat model updated if the attack surface changed (README, ADR 0010, T16)
  • No secrets, credentials, or personal data
  • New dependencies are justified below, or none were added (none)
  • Substantial AI assistance, if any, is noted here: written with Claude Code.

🤖 Generated with Claude Code

## What Step 3 of #201, stacked on #205: the desktop app's Add account wizard can add an account on a Gitea server. - **Step 1** asks, for a new account, where the repositories are: GitHub (default) or a Gitea server and its address. The address is checked by the rule the command line uses (`ForgeEndpoint.TryCreate`) and shown as it was normalized. - **Step 2** checks the token with the chosen place. The wizard holds the lister of one place at a time: the shell gives it a lister per place, and step 1 takes the one of the place that was chosen. - **Nothing is carried to another place:** when step 1 is left with another place than before, the typed token, the organization and the organization list are emptied. The default token (a GitHub token) is neither offered nor preselected for a Gitea server. - **An edit, and a Quick Sync connection saved as an account,** offer no choice and say where the account is. - **Texts follow the place:** the token box, the "How to create a token" page, the note of step 2, the connect card of an account's page. - **UI fixture:** answers for a Gitea server with an organization of its own; the wizard's listers are wrapped by it like a workspace's. - README, ADR 0010, threat model T16. ## Why Closes #206. The rules, each pinned by a test in `AccountWizardPlaceTests`: - a token is sent to the chosen place and to no other; - a token typed for one place is not kept when another place is chosen (GitHub to a server, and one server to another); - an address that cannot be used keeps the wizard on step 1, nothing is sent, and the address is not repeated in the message; - the default token is never sent to a Gitea server; - a wizard that was given one lister stays on the place of that lister, whatever is set on it. ## How it was tested - `AccountWizardPlaceTests` (view model), one new test in the UI suite that walks the wizard for a Gitea server against the offline fixture. - Gates, started from PowerShell: numbers in the comment below. - Looked at on screen: step 1 with and without the server box, step 2 for a Gitea server. ## Not in this change - Quick Sync stays GitHub only. - The screenshot of the wizard in the README shows step 1 as it was. - The Share invitation still says "GitHub organization". ## Not merged until 1.1.1 is tagged (#200), and #203 and #205 are merged. The base of this pull request is the branch of #205. ## Checklist - [x] Commits are signed and signed off (`git commit -S -s`) - [x] Zero build warnings; format and lint are clean - [x] Tests added or updated; the 100% coverage gate still passes - [x] Docs updated for user-visible changes; threat model updated if the attack surface changed (README, ADR 0010, T16) - [x] No secrets, credentials, or personal data - [x] New dependencies are justified below, or none were added (none) - [x] Substantial AI assistance, if any, is noted here: written with Claude Code. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Author
Owner

Gates on 191c7da, started from PowerShell: build 0 warnings; engine and view-model tests 1,397; CLI tests 247; 100% line coverage on the three assemblies; format clean; UI suite 14/14 (one new test walks the wizard for a Gitea server against the offline fixture). Eight single-rule mutations of the wizard's place rules: six caught, two do not compile (the rule cannot be broken that way). An independent review follows.

Gates on `191c7da`, started from PowerShell: build 0 warnings; engine and view-model tests 1,397; CLI tests 247; 100% line coverage on the three assemblies; format clean; UI suite 14/14 (one new test walks the wizard for a Gitea server against the offline fixture). Eight single-rule mutations of the wizard's place rules: six caught, two do not compile (the rule cannot be broken that way). An independent review follows.
Author
Owner

Independent review: merge after fixes; no path was found that sends a token to another place than the chosen one. Fixed in 1729cfd (the branch was rebased onto the second round of fixes of #205).

Finding What was done
Step 2 named the host alone; the normalized address was visible only after Back Step 2 gives the whole address as it was normalized
The place was taken before its lister (a failing lister factory would leave the new place with the old lister and token) The lister is made first; pinned by a test
A token check in flight was applied to whatever place was current when it returned (view model only; the dialog held its buttons) Next and Back do nothing while a token is checked
An edit copied the stored address into the hidden address box Removed
Tests missed several rules Added: what step 2 is told when the place changes, the account is saved at the place step 1 accepted, the two rules above. 11 single-rule mutations: all caught
The server message stayed while the address was corrected; an account's page headed its token box "Personal access token" for Gitea Both fixed
ADR 0010 consequences stale; README picture predates the choice Corrected; new picture

Not done here, noted on #192: ForgeTexts words an unknown forge like Gitea; the fixture's Gitea clone addresses are used by no UI test; the Share invitation still says "GitHub organization".

Gates, from PowerShell: build 0 warnings; engine 1,409; CLI 248; 100% line coverage; format clean; UI 14/14. One run of the engine suite failed once on VaultTests.CredentialManager_RoundTrips_AgainstTheRealStore (the known flake, #190) and passed on the rerun.

Independent review: **merge after fixes**; no path was found that sends a token to another place than the chosen one. Fixed in `1729cfd` (the branch was rebased onto the second round of fixes of #205). | Finding | What was done | | --- | --- | | Step 2 named the host alone; the normalized address was visible only after Back | Step 2 gives the whole address as it was normalized | | The place was taken before its lister (a failing lister factory would leave the new place with the old lister and token) | The lister is made first; pinned by a test | | A token check in flight was applied to whatever place was current when it returned (view model only; the dialog held its buttons) | Next and Back do nothing while a token is checked | | An edit copied the stored address into the hidden address box | Removed | | Tests missed several rules | Added: what step 2 is told when the place changes, the account is saved at the place step 1 accepted, the two rules above. 11 single-rule mutations: all caught | | The server message stayed while the address was corrected; an account's page headed its token box "Personal access token" for Gitea | Both fixed | | ADR 0010 consequences stale; README picture predates the choice | Corrected; new picture | Not done here, noted on #192: `ForgeTexts` words an unknown forge like Gitea; the fixture's Gitea clone addresses are used by no UI test; the Share invitation still says "GitHub organization". Gates, from PowerShell: build 0 warnings; engine 1,409; CLI 248; 100% line coverage; format clean; UI 14/14. One run of the engine suite failed once on `VaultTests.CredentialManager_RoundTrips_AgainstTheRealStore` (the known flake, #190) and passed on the rerun.
Author
Owner

Rebased onto 04b458d of #205 (a documentation correction and one test assertion there; no code). Tip is now 6deda64. After the rebase: build 0 warnings, engine 1,409, CLI 248. The UI suite was not run again: nothing the app or the UI tests use changed since the 14/14 run on 1729cfd.

Rebased onto `04b458d` of #205 (a documentation correction and one test assertion there; no code). Tip is now `6deda64`. After the rebase: build 0 warnings, engine 1,409, CLI 248. The UI suite was not run again: nothing the app or the UI tests use changed since the 14/14 run on `1729cfd`.
james.maes changed target branch from feat/204-gitea-accounts-and-cli to main 2026-11-11 22:24:36 +00:00
james.maes added 3 commits 2026-11-11 22:24:36 +00:00
Step 3 of Gitea support (#201): the desktop app adds, loads and syncs an
account on a Gitea server.

- Step 1 of the wizard asks, for a new account, where the repositories are:
  GitHub (the default) or a Gitea server and its address. The address is
  checked by the rule the command line uses and shown as it was normalized,
  which is the address the token goes to.
- The wizard holds the lister of one place at a time. The shell gives it a
  lister per place, step 1 takes the one of the chosen place, and step 2 has
  no other to send the token to. A wizard that was given one lister (an edit,
  a Quick Sync connection saved as an account) offers no choice and says
  where the account is.
- What was entered for one place is not carried to another: when step 1 is
  left with another place than before, the typed token, the organization and
  the organization list are emptied. The default token is a GitHub token and
  is neither offered nor preselected for a Gitea server.
- Texts that named GitHub follow the place: the token box, the page a token
  is made on, the note of step 2, and the connect card of an account's page.
- The offline UI fixture answers for a Gitea server with an organization of
  its own, and the UI suite walks the wizard for one. The wizard's listers
  are wrapped by the fixture like a workspace's.
- README, ADR 0010, threat model T16.

Closes #206

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
From the review of #207.

- Step 2 named the host alone, and the normalized address was visible only
  after going back: two servers on one host read the same. The note of step
  2 now gives the address in full, as it was normalized.
- The place was taken before its lister: had the lister of the new place
  failed to be made, the wizard would have been on the new place with the
  lister and the token of the old one. The lister is made first.
- While step 2 checks a token, Next and Back do nothing: the answer that is
  on its way is the answer for the place and the token the wizard still
  holds. The dialog already held its buttons; the view model now holds too.
- An edit no longer puts the stored address into the (hidden) address box.
- The message about the server goes away when the address is corrected.
- An account's page heads its token box with what the forge calls a token.
- Tests state what was missing: what step 2 is told when the place changes,
  that the account is saved at the place step 1 accepted whatever the choice
  is set to afterwards, the two rules above. 11 single-rule mutations of the
  change: all caught.
- ADR 0010 and T16 corrected; the README's picture of the wizard shows the
  choice.

Refs #206

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
"A Gitea server" stood beside a bare "GitHub": an article and the word
server on one side only. The two options are now named alike; the server
address box that appears under Gitea says the rest. README sentence and
picture follow.

Refs #206

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Signed-off-by: James Maes <james@kof22.com>
james.maes merged commit 6764af9ff5 into main 2026-11-11 22:24:40 +00:00
Sign in to join this conversation.