diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfe68a6..ad6a700 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -517,7 +517,7 @@ jobs: if: github.ref == 'refs/heads/main' env: FORGE: https://git.dodotech.cloud - REPO: DodoTech/DodoSSH + REPO: DodoTech-Public/DodoSSH TOKEN: ${{ secrets.GITHUB_TOKEN }} STAGED: ${{ steps.nightly.outputs.staged }} VERSION: ${{ steps.nightly.outputs.version }} diff --git a/README.md b/README.md index 7715182..1109369 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ not go. If the repository is private, every check answers `404`, and the honest about that is say so. It is one line to check: ```bash -curl -so /dev/null -w '%{http_code}\n' https://git.dodotech.cloud/api/v1/repos/DodoTech/DodoSSH +curl -so /dev/null -w '%{http_code}\n' https://git.dodotech.cloud/api/v1/repos/DodoTech-Public/DodoSSH ``` `200` and updates work. `404` and they cannot. `/api/v1/version` answering `200` proves only that the forge diff --git a/docs/adr/0013-desktop-distribution-and-updates.md b/docs/adr/0013-desktop-distribution-and-updates.md index ed77c73..2f90ddc 100644 --- a/docs/adr/0013-desktop-distribution-and-updates.md +++ b/docs/adr/0013-desktop-distribution-and-updates.md @@ -118,7 +118,7 @@ than assumed: - **The feed repository must be readable with no credentials, and that is a deployment precondition** rather than a property of the code. It is checkable in one line, which is the only reason it is worth stating: - `curl -so /dev/null -w '%{http_code}' https://git.dodotech.cloud/api/v1/repos/DodoTech/DodoSSH` answers + `curl -so /dev/null -w '%{http_code}' https://git.dodotech.cloud/api/v1/repos/DodoTech-Public/DodoSSH` answers `200` when the design holds and `404` when it does not. `/api/v1/version` answering `200` proves only that the forge is reachable, which is what made this look like nothing was wrong. - **An unreachable channel must be distinguishable from a current build.** `IUpdateChannel.CheckAsync` used diff --git a/docs/manual-checks.md b/docs/manual-checks.md index ce5b60a..9672a93 100644 --- a/docs/manual-checks.md +++ b/docs/manual-checks.md @@ -1802,7 +1802,7 @@ Nothing else in this phase or the next means anything until this passes. Run it nothing: ```bash -curl -so /dev/null -w '%{http_code}\n' https://git.dodotech.cloud/api/v1/repos/DodoTech/DodoSSH +curl -so /dev/null -w '%{http_code}\n' https://git.dodotech.cloud/api/v1/repos/DodoTech-Public/DodoSSH ``` **Pass:** `200`. diff --git a/scripts/release-android.ps1 b/scripts/release-android.ps1 index 33ab73f..77b366e 100644 --- a/scripts/release-android.ps1 +++ b/scripts/release-android.ps1 @@ -50,7 +50,7 @@ $RepoRoot = Split-Path -Parent $PSScriptRoot $Project = Join-Path $RepoRoot 'src/DodoSSH.Client.Android/DodoSSH.Client.Android.csproj' $Staging = Join-Path $RepoRoot 'artifacts/android' $Forge = 'https://git.dodotech.cloud' -$Repo = 'DodoTech/DodoSSH' +$Repo = 'DodoTech-Public/DodoSSH' $Api = "$Forge/api/v1/repos/$Repo" function Write-Step([string] $Message) { diff --git a/scripts/release-windows.ps1 b/scripts/release-windows.ps1 index 3035328..38f3073 100644 --- a/scripts/release-windows.ps1 +++ b/scripts/release-windows.ps1 @@ -62,7 +62,11 @@ $PackAuthors = 'DodoTech' # The project's own forge. Never a DodoSSH deployment — ADR 0011 rule 2. The same URL is a constant in # VelopackUpdateChannel, and the two have to agree or the client polls somewhere nothing is published. -$RepoUrl = 'https://git.dodotech.cloud/DodoTech/DodoSSH' +# +# The owner is part of it. When the repository moved organisations Gitea left a 301 at the old path, which +# a GET follows and an upload does not — so a stale URL here fails at the one step that matters rather than +# redirecting quietly. +$RepoUrl = 'https://git.dodotech.cloud/DodoTech-Public/DodoSSH' # A contract with VelopackUpdateChannel.ReleaseChannel. It is Velopack's Windows default, so leaving it # unsaid on both sides would work too — but unsaid here and stated there is how a feed goes quiet with no diff --git a/src/DodoSSH.Api/Dockerfile b/src/DodoSSH.Api/Dockerfile index 4a583af..4118a0c 100644 --- a/src/DodoSSH.Api/Dockerfile +++ b/src/DodoSSH.Api/Dockerfile @@ -111,7 +111,7 @@ LABEL org.opencontainers.image.title="DodoSSH API" \ org.opencontainers.image.description="DodoSSH server: sync, identity, teams and relay authorization." \ org.opencontainers.image.vendor="DodoTech" \ org.opencontainers.image.licenses="MIT" \ - org.opencontainers.image.source="https://git.dodotech.cloud/DodoTech/DodoSSH" \ + org.opencontainers.image.source="https://git.dodotech.cloud/DodoTech-Public/DodoSSH" \ org.opencontainers.image.version="${VERSION}" \ org.opencontainers.image.revision="${REVISION}" \ org.opencontainers.image.created="${CREATED}" diff --git a/src/DodoSSH.Client.Android/Platform/AndroidUpdateChannel.cs b/src/DodoSSH.Client.Android/Platform/AndroidUpdateChannel.cs index cc4941e..32b8381 100644 --- a/src/DodoSSH.Client.Android/Platform/AndroidUpdateChannel.cs +++ b/src/DodoSSH.Client.Android/Platform/AndroidUpdateChannel.cs @@ -76,7 +76,14 @@ internal sealed partial class ForgeJsonContext : JsonSerializerContext; internal sealed class AndroidUpdateChannel : IUpdateChannel { /// The project's own forge, and the one address in this file. - private const string RepositoryApi = "https://git.dodotech.cloud/api/v1/repos/DodoTech/DodoSSH"; + /// + /// ◆ The owner is DodoTech-Public and that half of the path matters. The repository was moved + /// between organisations, and Gitea leaves a 301 at the old one — so a client still naming it looks + /// fine, because HttpClient follows a redirect on a GET. What it buys is a dependency on a + /// redirect somebody can delete, and it does not extend to the release scripts, whose uploads are + /// POSTs. The live path is named here, in VelopackUpdateChannel and in both scripts. + /// + private const string RepositoryApi = "https://git.dodotech.cloud/api/v1/repos/DodoTech-Public/DodoSSH"; /// /// The session name the installer writes under, and it is reused rather than made unique. diff --git a/src/DodoSSH.Client.App/Platform/VelopackUpdateChannel.cs b/src/DodoSSH.Client.App/Platform/VelopackUpdateChannel.cs index 723306a..71d5ead 100644 --- a/src/DodoSSH.Client.App/Platform/VelopackUpdateChannel.cs +++ b/src/DodoSSH.Client.App/Platform/VelopackUpdateChannel.cs @@ -75,14 +75,24 @@ internal sealed class VelopackUpdateChannel : IUpdateChannel /// /// /// This must never become a setting. ADR 0011 rule 2 says the deployment a client signs in to + /// /// is never where the client comes from, and it says the same about the update check: an operator who /// can answer "is there a newer version" can answer "no" forever, and pin a chosen user to a build /// with a known hole without holding any key. A configurable feed URL is exactly the knob that would /// hand them that, whether through a settings screen or through somebody editing the plaintext /// settings.json by hand. A constant is that rule expressed structurally rather than as a convention /// somebody has to keep. + /// + /// + /// ◆ DodoTech-Public, and the owner is part of the address rather than incidental. The + /// repository was moved between organisations, and Gitea leaves a 301 behind at the old path — which is + /// why a client pointing at the old one appears to work: HttpClient follows a redirect on a GET. + /// It does not follow one on a POST, so vpk upload against the stale URL fails rather than + /// redirecting, and a redirect is a thing an operator can remove. Both heads and both release scripts + /// name the live path. + /// /// - private const string RepositoryUrl = "https://git.dodotech.cloud/DodoTech/DodoSSH"; + private const string RepositoryUrl = "https://git.dodotech.cloud/DodoTech-Public/DodoSSH"; /// /// The release channel to read, and it is stated rather than left to the default.