From 21cdcd25af82e5495bcfb004e09549fe97ed6c5e Mon Sep 17 00:00:00 2001
From: JSONbored <49853598+JSONbored@users.noreply.github.com>
Date: Mon, 13 Jul 2026 04:01:04 -0700
Subject: [PATCH 1/2] ci(selfhost): stop publishing the legacy
gittensory-selfhost image tag
The self-host container image release workflow published every orb-v
tag under both the renamed "loopover-selfhost" name and the pre-rename
"gittensory-selfhost" name as a dual-publish alias. Stop publishing
under the old name going forward -- only "loopover-selfhost" ships
from here on.
Already-published tags and digests under the old name are untouched;
GHCR has no server-side alias, so an existing exact-version or digest
pin keeps resolving forever regardless. Only a ":latest"-style pin
stops advancing, which is the accepted tradeoff of retiring the
dual-publish, not something this change works around.
Updates the release workflow's image metadata step and release-notes
template, trims the now-stale dual-publish/alias commentary from the
deploy script, release-automation scripts, and .env.example, and
brings the self-hosting docs and unit tests in line with the new
single-name publish.
Part of #4777
---
.env.example | 5 +---
.github/workflows/orb-beta-release.yml | 4 +---
.github/workflows/orb-stable-release-pr.yml | 4 +---
.github/workflows/release-selfhost.yml | 23 +++++--------------
.../routes/docs.self-hosting-operations.tsx | 5 ++--
.../routes/docs.self-hosting-quickstart.tsx | 5 ++--
.../docs.self-hosting-release-checklist.tsx | 8 +++----
.../src/routes/docs.self-hosting-releases.tsx | 8 +++----
orb-manifest.json | 2 +-
scripts/deploy-selfhost-image.sh | 5 ----
scripts/orb-release-core.mjs | 4 +---
test/unit/release-selfhost-notes.test.ts | 5 +---
test/unit/selfhost-image-deploy.test.ts | 14 ++++++-----
test/unit/selfhost-sentry-release.test.ts | 12 +++-------
14 files changed, 35 insertions(+), 69 deletions(-)
diff --git a/.env.example b/.env.example
index 2b72ef2c7c..0fcfc3b2a1 100644
--- a/.env.example
+++ b/.env.example
@@ -262,10 +262,7 @@ REDIS_URL=redis://redis:6379 # REQUIRED for the self-host review
# # starts Redis automatically; override for an external Redis.
# GITTENSORY_IMAGE=ghcr.io/jsonbored/loopover-selfhost:latest # image used by scripts/deploy-selfhost-image.sh;
# # pin production rollouts to a release tag such as :orb-v0.1.0
-# # or to an immutable @sha256 digest. #4770: the pre-rename
-# # ghcr.io/jsonbored/gittensory-selfhost name is a deprecated
-# # alias of the same image during the deprecation window (#4777)
-# # -- an existing pin to it keeps working unmodified.
+# # or to an immutable @sha256 digest.
# GITHUB_CACHE_TTL_SECONDS=20 # Enables the Redis-backed GitHub GET-response cache when >0; set 0
# # to disable. NOT a per-entry TTL duration — each cached class
# # resolves its own TTL below (GITHUB_BRANCH_PROTECTION_CACHE_TTL_SECONDS
diff --git a/.github/workflows/orb-beta-release.yml b/.github/workflows/orb-beta-release.yml
index 6537b463c0..11e5da97c9 100644
--- a/.github/workflows/orb-beta-release.yml
+++ b/.github/workflows/orb-beta-release.yml
@@ -1,6 +1,4 @@
-# Automated ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost -- #4770: the pre-rename
-# ghcr.io/jsonbored/gittensory-selfhost name remains a deprecated alias of the same build during the
-# deprecation window tracked by #4777) beta channel.
+# Automated ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost) beta channel.
# Daily (or on demand via workflow_dispatch), checks whether any image-relevant commit has landed
# since the last orb-v tag (scripts/check-orb-release-due.mjs / scripts/orb-release-core.mjs) and,
# if so, cuts the next `orb-vX.Y.Z-beta.N` tag and dispatches release-selfhost.yml to build + publish
diff --git a/.github/workflows/orb-stable-release-pr.yml b/.github/workflows/orb-stable-release-pr.yml
index 99a948d0f8..ab90a4301e 100644
--- a/.github/workflows/orb-stable-release-pr.yml
+++ b/.github/workflows/orb-stable-release-pr.yml
@@ -1,6 +1,4 @@
-# Automated ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost -- #4770: the pre-rename
-# ghcr.io/jsonbored/gittensory-selfhost name remains a deprecated alias of the same build during the
-# deprecation window tracked by #4777) STABLE-channel Release PR --
+# Automated ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost) STABLE-channel Release PR --
# the release-please-equivalent for ORB, whose cross-cutting image-relevant scoping (src/** shared with
# UI/MCP-only subtrees it must exclude -- see orb-release-core.mjs's IMAGE_RELEVANT_PREFIXES/EXCLUDED_PREFIXES)
# doesn't fit release-please's directory-component model the way packages/gittensory-mcp and
diff --git a/.github/workflows/release-selfhost.yml b/.github/workflows/release-selfhost.yml
index 2cb8eb44b5..ab86d925dd 100644
--- a/.github/workflows/release-selfhost.yml
+++ b/.github/workflows/release-selfhost.yml
@@ -5,10 +5,9 @@
#
# Pull: docker pull ghcr.io//loopover-selfhost:orb-v0.1.0
#
-# #4770: `ghcr.io//gittensory-selfhost` is a deprecated alias of the SAME image, published from this
-# same build/push so both names resolve to the byte-identical digest -- see the "Image metadata" step below.
-# Self-hosters pinned to the old name keep working unmodified during the deprecation window; do not remove
-# that alias without the sign-off tracked by #4777.
+# #4777: publishing under the pre-rename "gittensory-selfhost" name stopped -- see the "Image metadata"
+# step below. Already-published tags/digests under that name are untouched and keep resolving forever
+# (GHCR has no server-side alias); only new pushes moved to "loopover-selfhost" exclusively.
#
# Prerelease tags (#1937): orb-v0.1.0-rc.1 / orb-v0.1.0-beta.1 run the identical pipeline but never move
# `latest` and are marked prerelease on the GitHub Release -- for beta-testing an image before it becomes
@@ -222,21 +221,15 @@ jobs:
echo "GTORBTAGS"
} >> "$GITHUB_OUTPUT"
- # #4770: publish under BOTH the new "loopover-selfhost" name (primary going forward, listed first) and
- # the legacy "gittensory-selfhost" name (deprecated alias) from this SAME buildx build/push below --
- # docker/metadata-action applies the identical `tags:` set to every entry in a multi-line `images:`
- # list, so both names resolve to the byte-identical multi-arch manifest with no second build and no
- # extra registry round-trip. Self-hosters who pinned the old image reference in their own deployment
- # config must keep working unmodified until the deprecation window closes. Removal of the alias is
- # tracked by #4777 ("retire every deprecation shim") and requires an explicit, separately-announced
- # window before it's dropped -- do not remove the second `images:` line without that sign-off.
+ # #4777: publishes only under the "loopover-selfhost" name now. The pre-rename "gittensory-selfhost"
+ # name is no longer pushed to; GHCR has no server-side alias, so its already-published exact-version
+ # and digest pins keep resolving forever regardless -- this only stops new tags from landing there.
- name: Image metadata
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
with:
images: |
ghcr.io/${{ github.repository_owner }}/loopover-selfhost
- ghcr.io/${{ github.repository_owner }}/gittensory-selfhost
tags: ${{ steps.tags.outputs.list }}
labels: |
org.opencontainers.image.title=gittensory-orb
@@ -354,10 +347,6 @@ jobs:
Multi-arch (linux/amd64 + linux/arm64). See https://loopover.ai/docs/maintainer-self-hosting for setup.
Includes the Claude Code / Codex subscription CLIs by default; credentials stay runtime-only.
Sentry release id baked into the image: \`${RELEASE_ID}\`.
-
- #4770: \`ghcr.io/${REPOSITORY_OWNER_LOWER}/gittensory-selfhost:${RELEASE_TAG}\` (the pre-rename name)
- still resolves to this identical build/digest during the deprecation window -- no action needed if
- you're already pinned to it. Track eventual removal via #4777.
EOF
)"
# #1937: a prerelease tag never becomes the repo's "Latest release" and is visibly marked as such
diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx
index e7862a0b0e..6174571eed 100644
--- a/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx
+++ b/apps/gittensory-ui/src/routes/docs.self-hosting-operations.tsx
@@ -982,9 +982,8 @@ SENTRY_ORG_SLUG=
GITTENSORY_IMAGE=ghcr.io/jsonbored/loopover-selfhost@sha256:... ./scripts/deploy-selfhost-image.sh`}
/>
- ghcr.io/jsonbored/gittensory-selfhost (the pre-rename name) remains a
- deprecated alias of the identical image during the deprecation window — an existing pin to
- it keeps resolving unmodified.
+ ghcr.io/jsonbored/gittensory-selfhost (the pre-rename name) is no longer
+ published to, but an existing pin to a specific tag or digest under it keeps resolving.
The pull always runs with --policy always, so re-running the script against an
diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-quickstart.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-quickstart.tsx
index 87df53eeb0..b0b3c4e409 100644
--- a/apps/gittensory-ui/src/routes/docs.self-hosting-quickstart.tsx
+++ b/apps/gittensory-ui/src/routes/docs.self-hosting-quickstart.tsx
@@ -120,9 +120,8 @@ curl http://localhost:8787/ready`}
GITTENSORY_IMAGE=ghcr.io/jsonbored/loopover-selfhost@sha256:... ./scripts/deploy-selfhost-image.sh`}
/>
- ghcr.io/jsonbored/gittensory-selfhost (the pre-rename name) remains available
- as a deprecated alias of the identical image during the deprecation window — existing pins
- keep working unmodified.
+ ghcr.io/jsonbored/gittensory-selfhost (the pre-rename name) is no longer
+ published to, but an existing pin to a specific tag or digest under it keeps resolving.
Contributors and anyone customizing the Dockerfile can still build locally —{" "}
diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-release-checklist.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-release-checklist.tsx
index a79e3c99e5..a57542f2db 100644
--- a/apps/gittensory-ui/src/routes/docs.self-hosting-release-checklist.tsx
+++ b/apps/gittensory-ui/src/routes/docs.self-hosting-release-checklist.tsx
@@ -233,7 +233,7 @@ git push origin orb-v0.1.0`}
scripts/deploy-selfhost-prebuilt.sh, run{" "}
scripts/deploy-selfhost-image.sh
- ghcr.io/<owner>/gittensory-selfhost:orb-v0.1.0
+ ghcr.io/<owner>/loopover-selfhost:orb-v0.1.0
.
@@ -570,8 +570,8 @@ docker rm -f gt-qdrant && docker network rm gt-rag-smoke`}
This audit is Dockerfile-derived, not a runtime scan. If a future dependency bump adds a
@@ -635,7 +635,7 @@ docker images ghcr.io/jsonbored/gittensory-selfhost:orb-v0.1.0 --format '{{.Size
code={`Gittensory Orb container image:
\`\`\`bash
-docker pull ghcr.io/jsonbored/gittensory-selfhost:orb-v0.1.0
+docker pull ghcr.io/jsonbored/loopover-selfhost:orb-v0.1.0
\`\`\`
Multi-arch (linux/amd64 + linux/arm64). See https://gittensory.aethereal.dev/docs/maintainer-self-hosting for setup.
diff --git a/apps/gittensory-ui/src/routes/docs.self-hosting-releases.tsx b/apps/gittensory-ui/src/routes/docs.self-hosting-releases.tsx
index 3fd61a3ca3..7ed8fd6eb0 100644
--- a/apps/gittensory-ui/src/routes/docs.self-hosting-releases.tsx
+++ b/apps/gittensory-ui/src/routes/docs.self-hosting-releases.tsx
@@ -56,10 +56,10 @@ function SelfHostingReleases() {
docker pull ghcr.io/jsonbored/loopover-selfhost:latest`}
/>
- ghcr.io/jsonbored/loopover-selfhost is the current name. The pre-rename{" "}
- ghcr.io/jsonbored/gittensory-selfhost remains available as a deprecated alias
- of the byte-identical image during the deprecation window — existing pins keep working
- unmodified.
+ ghcr.io/jsonbored/loopover-selfhost is the only name new releases publish
+ under. The pre-rename ghcr.io/jsonbored/gittensory-selfhost is no longer
+ published to, but an existing pin to a specific tag or digest under that name keeps
+ resolving — pull it and switch to the new name at your convenience.
Prerelease (beta/rc) images
diff --git a/orb-manifest.json b/orb-manifest.json
index 862db6df11..8d2ce1c419 100644
--- a/orb-manifest.json
+++ b/orb-manifest.json
@@ -1,4 +1,4 @@
{
"version": "1.0.0",
- "description": "Source of truth for the self-hostable gittensory-orb container image's target release version (ghcr.io/jsonbored/loopover-selfhost -- #4770: ghcr.io/jsonbored/gittensory-selfhost is a deprecated alias of the same build/digest during the deprecation window tracked by #4777). Bumped by a maintainer when a feat/fix/breaking change since the last stable orb-v tag warrants moving to a new target version -- scripts/orb-release-core.mjs and .github/workflows/orb-beta-release.yml read this file to decide what version the next automated beta snapshot targets. Promoting a beta to a stable orb-vX.Y.Z release is still a manual `git tag` -- this manifest only drives the automated beta channel."
+ "description": "Source of truth for the self-hostable gittensory-orb container image's target release version (ghcr.io/jsonbored/loopover-selfhost). Bumped by a maintainer when a feat/fix/breaking change since the last stable orb-v tag warrants moving to a new target version -- scripts/orb-release-core.mjs and .github/workflows/orb-beta-release.yml read this file to decide what version the next automated beta snapshot targets. Promoting a beta to a stable orb-vX.Y.Z release is still a manual `git tag` -- this manifest only drives the automated beta channel."
}
diff --git a/scripts/deploy-selfhost-image.sh b/scripts/deploy-selfhost-image.sh
index 4e1972d4da..6214eb63cf 100755
--- a/scripts/deploy-selfhost-image.sh
+++ b/scripts/deploy-selfhost-image.sh
@@ -10,11 +10,6 @@
# ./scripts/deploy-selfhost-image.sh ghcr.io/jsonbored/loopover-selfhost:orb-v0.1.0
# GITTENSORY_IMAGE=ghcr.io/jsonbored/loopover-selfhost@sha256:... ./scripts/deploy-selfhost-image.sh
#
-# #4770: ghcr.io/jsonbored/gittensory-selfhost (the pre-rename name) is a deprecated alias of the SAME
-# build/digest during the deprecation window -- an existing GITTENSORY_IMAGE override or CLI argument
-# pinned to that old name keeps resolving unmodified; only DEFAULT_IMAGE below moves to the new name.
-# Removal of the alias is tracked by #4777.
-#
# The image itself carries official release metadata. Set SENTRY_RELEASE only for custom images whose
# source maps were uploaded under that exact id.
set -euo pipefail
diff --git a/scripts/orb-release-core.mjs b/scripts/orb-release-core.mjs
index a5c45ca7aa..b0effed457 100644
--- a/scripts/orb-release-core.mjs
+++ b/scripts/orb-release-core.mjs
@@ -1,6 +1,4 @@
-// Pure logic for the ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost -- #4770: the
-// pre-rename ghcr.io/jsonbored/gittensory-selfhost name remains a deprecated alias of the same build
-// during the deprecation window tracked by #4777) automated beta
+// Pure logic for the ORB (self-host container image, ghcr.io/jsonbored/loopover-selfhost) automated beta
// channel. Deliberately independent of scripts/mcp-release-core.mjs (no shared imports/state) even though the
// shape mirrors it closely -- ORB and the MCP package are versioned, tagged, and published on separate
// schedules by separate automation, and keeping them decoupled means neither can accidentally regress the
diff --git a/test/unit/release-selfhost-notes.test.ts b/test/unit/release-selfhost-notes.test.ts
index cb451c2989..06150f3659 100644
--- a/test/unit/release-selfhost-notes.test.ts
+++ b/test/unit/release-selfhost-notes.test.ts
@@ -138,10 +138,7 @@ describe('release-selfhost.yml "GitHub Release" step changelog generation', () =
const r = harness.run();
expect(r.status).toBe(0);
expect(r.notesPassed).toContain("docker pull ghcr.io/jsonbored/loopover-selfhost:orb-v0.2.0");
- // #4770: the notes must also tell an operator that the pre-rename image name still resolves to
- // this identical build during the deprecation window, and point at #4777 for eventual removal.
- expect(r.notesPassed).toContain("ghcr.io/jsonbored/gittensory-selfhost:orb-v0.2.0");
- expect(r.notesPassed).toContain("#4777");
+ expect(r.notesPassed).not.toContain("gittensory-selfhost");
expect(r.notesPassed).toContain("## What's Changed");
expect(r.notesPassed).toContain("feat: something");
// The tag being released must never be diffed against itself.
diff --git a/test/unit/selfhost-image-deploy.test.ts b/test/unit/selfhost-image-deploy.test.ts
index 15061b797e..8e04e5e813 100644
--- a/test/unit/selfhost-image-deploy.test.ts
+++ b/test/unit/selfhost-image-deploy.test.ts
@@ -13,9 +13,10 @@ import { describe, expect, it } from "vitest";
const scriptPath = resolve("scripts/deploy-selfhost-image.sh");
const defaultImage = "ghcr.io/jsonbored/loopover-selfhost:latest";
-// #4770: the pre-rename name is a deprecated alias of the identical image during the deprecation
-// window -- an operator who pinned it explicitly (CLI arg, env var, or .env value) must keep
-// resolving to that exact string unmodified, even though DEFAULT_IMAGE above now points at the new name.
+// #4777: publishing under the pre-rename name has stopped, but GHCR has no server-side alias, so its
+// already-published tags/digests keep resolving forever -- an operator who pinned it explicitly (CLI
+// arg, env var, or .env value) must keep resolving to that exact string unmodified, even though
+// DEFAULT_IMAGE above now points at the new name.
const legacyPinnedImage = "ghcr.io/jsonbored/gittensory-selfhost:orb-v0.1.0";
interface RunOptions {
@@ -167,10 +168,11 @@ describe("self-host image deploy script", () => {
}
});
- // REGRESSION (#4770): DEFAULT_IMAGE moved to the new "loopover-selfhost" name, but a self-hoster who
+ // REGRESSION (#4777): DEFAULT_IMAGE moved to the new "loopover-selfhost" name, but a self-hoster who
// explicitly pinned the pre-rename "gittensory-selfhost" image (as a CLI argument, GITTENSORY_IMAGE env
- // var, or .env value) must keep resolving to that exact string, unmodified -- the deprecation alias is
- // guaranteed by the release workflow's dual-tag push, not by rewriting an operator's existing pin here.
+ // var, or .env value) must keep resolving to that exact string, unmodified -- GHCR keeps already-published
+ // tags/digests resolving forever with no server-side alias needed, and this script must not rewrite an
+ // operator's existing pin either way.
it("passes an explicit pre-rename image reference through unchanged despite the new default", () => {
const { harness, result } = runHarness({ args: [legacyPinnedImage] });
try {
diff --git a/test/unit/selfhost-sentry-release.test.ts b/test/unit/selfhost-sentry-release.test.ts
index b295bf1ae0..ff520ca48d 100644
--- a/test/unit/selfhost-sentry-release.test.ts
+++ b/test/unit/selfhost-sentry-release.test.ts
@@ -42,18 +42,12 @@ describe("self-host Sentry release wiring", () => {
expect(releaseWorkflow).toContain(
"docker pull ghcr.io/${REPOSITORY_OWNER_LOWER}/loopover-selfhost:${RELEASE_TAG}",
);
- // #4770: the release notes must also point out that the pre-rename image name still resolves to
- // the identical build during the deprecation window (tracked for eventual removal by #4777).
- expect(releaseWorkflow).toContain(
- "ghcr.io/${REPOSITORY_OWNER_LOWER}/gittensory-selfhost:${RELEASE_TAG}",
- );
- expect(releaseWorkflow).toContain("#4777");
- // The "Image metadata" step must push BOTH names from the same buildx build so the two tags share
- // a byte-identical digest -- no second build, no drift between them.
+ // #4777: the "Image metadata" step must only push the renamed image now -- publishing under the
+ // pre-rename "gittensory-selfhost" name has stopped.
expect(releaseWorkflow).toContain(
"ghcr.io/${{ github.repository_owner }}/loopover-selfhost",
);
- expect(releaseWorkflow).toContain(
+ expect(releaseWorkflow).not.toContain(
"ghcr.io/${{ github.repository_owner }}/gittensory-selfhost",
);
expect(releaseWorkflow).not.toContain('"selfhost-v*"');
From f768cc58291cc7fa88aea9059e7ff1dc04f031a8 Mon Sep 17 00:00:00 2001
From: JSONbored <49853598+JSONbored@users.noreply.github.com>
Date: Mon, 13 Jul 2026 13:32:05 -0700
Subject: [PATCH 2/2] ci: retrigger Workers Builds (Cloudflare
build-concurrency contention from #5648 merge)