state: caldav-mcp-beta is running an image that predates the RFC 8252 loopback fix #9
Labels
No labels
blocked
waiting-on-julian
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jlxq0/caldav-mcp#9
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
State, verified 2026-08-26
caldav-mcp-betais running an image built before the RFC 8252 §7.3 loopbackfix (#2, merged as
33bd20d). Production is not.caldav-mcpv0.1.2sha256:3d37a2ebe89851ae457f67e7fbb637d1f5d2948b177fa11da24f4d0b0f43c70ccaldav-mcp-betav0.1.1-beta.e1ad86bsha256:ab8e6b38b5533b18edb01c59c716dd31372ca537ecd8f52748b38b803dcce85ae1ad86bis thev0.1.1commit, so beta predates both33bd20d(the loopbackfix) and
4a6cf39(the test that pins both halves of the scheme guard).Both ArgoCD applications read
SyncedandHealthy, which is why the digestsabove were read off the running pods rather than off the tiles.
What this means in practice
A native or command-line OAuth client cannot complete Dynamic Client
Registration against beta: it binds an ephemeral loopback port, the allowlist
entry is
http://localhost:8787/callback, and the pre-fix matcher compares byexact string equality, so DCR answers
unregistered redirect_uri. Productionaccepts it.
Beta therefore reproduces a defect that no longer exists in the code, which is
the failure mode worth recording: someone testing a CLI client against beta
next month will rediscover #2 and have no way to tell it is a stale image
rather than a regression.
Not urgent
Beta serves no production traffic. This issue exists so the discrepancy is
written somewhere with a state, rather than living in a message.
Why beta is stale is not "nobody pushed a tag"
Two findings from looking at how it would be bumped, both verified 2026-08-26.
1. This repo has no beta path in CI.
.forgejo/workflows/ci.ymltriggers onpushtomain,pushofv*tags, andpull_request. The image is pushedonly on a
v*tag. There is nobetabranch trigger and nothing that mints a-beta.{timestamp}tag, so the loop the platform's Renovate rule describes —"push main:beta -> CI tags v{BASE}-beta.{ts} -> Renovate PR auto-merges -> Argo
syncs" — does not exist here.
v0.1.1-beta.e1ad86bwas cut by hand.2. Renovate cannot move the current pin even if a new tag appears. The
platform's
clusters/fondue/*-beta/**rule takes:The suffix must be digits.
v0.1.1-beta.e1ad86bis a sha, so it does not matchthe rule that is supposed to maintain it. Every other
*-betaapp infondueuses a timestamp and matches:
a-grand-tour-betav0.9.0-beta.20260822192015hanso-betav3.4.4-beta.20260821152014miru-betav0.1.0-beta.20260823015035caldav-mcp-betav0.1.1-beta.e1ad86bcaldav-mcp is the exception. That is why the pin has not moved on its own.
What I am doing about it now, and what I am not
Cutting
v0.1.2-beta.<timestamp>off currentmainby hand. It matches theRenovate rule, so the existing automation can take it from there, and it is the
tag CI accepts today: the workflow requires the tag version to equal the
Cargo.tomlversion or be a prerelease of it, and this repo's convention is tobump
Cargo.tomlat release time (chore(release): prepare v0.1.2), soCargo.tomlreads0.1.2between releases andv0.1.3-beta.*would fail theguard.
The oddity that leaves:
0.1.2-beta.<ts>sorts below the released0.1.2,so beta will show a lower version than production while running newer code.
That is the same "confident wrong answer from a real page" shape this issue and
#10 are about, and it is the reason the sha-suffixed tag is not simply repeated.
Not doing, and worth a separate decision: wiring an actual beta loop into
.forgejo/workflows/ci.ymlso beta stops being hand-cut, which also settleswhether
Cargo.tomlshould carry the next version between releases the way theElixir apps do.
No
:latesttag is produced — the workflow only adds it when the version hasno
-in it — so production is untouched by this.A third layer, in
oddie-apps/platform, and the reason this could never have self-correctedThe tag
v0.1.2-beta.20260826052605built and Renovate openedoddie-apps/platform#538with exactly the right diff. It fails CI, and thefailure is in that repository's own test suite.
tests/test_caldav_mcp.py::test_image_is_immutable_semver_prereleaseasserts:That pins the current value rather than the shape, and it does the damage
twice:
v0\.1\.1literally, so every future beta bump turns the test red. Thepin could not move by automation.
[0-9a-f]+for the prerelease suffix, which is what admitted the hand-cutv0.1.1-beta.e1ad86b. A sha cannot match theclusters/fondue/*-beta/**Renovate rule,
allowedVersions: /^v?\d+\.\d+\.\d+-(beta|alpha)\.\d+$/, sothe tag the test permitted was one the automation could never maintain.
Together those two facts mean
caldav-mcp-betahas been unmaintainable sinceit was created: not a stalled automation, one structurally unable to match, with
a test that would have rejected the fix if it had ever been attempted.
A correct example sat three files away
Two sibling tests in the same directory get this right:
tests/test_carddav_mcp.py:33—v[0-9]+\.[0-9]+\.[0-9]+@sha256:[0-9a-f]{64}tests/test_typst_mcp.py:16—^forge\.oddie\.app/jlxq0/typst-mcp:v[0-9]+\.[0-9]+\.[0-9]+@sha256:[0-9a-f]{64}$Run the comparison rather than taking my word for it. The pattern being present
and correct next door is what makes the broken one easy to read past: the eye
takes the shape as established and does not re-derive it.
Fix
oddie-apps/platform#539, one commit, test and manifest together — they cannotboth be correct in separate commits, because the new regex rejects the tag on
mainand the new tag fails the regex onmain. The new regex was run againstthe old sha form, a hex-lettered suffix and a digest-less line and rejected all
three before being trusted; a green case alone would not have shown which
strings it refuses.
Merging it is not mine — that repository reaches the cluster within minutes of a
merge, so it is handed to the session that owns it, with the cross-engine review
edge-configgets.Closing state, and two corrections to what is written above
Beta is deployed.
caldav-mcp-beta-6fb6fdcff7-45rls, containerapp, isrunning
sha256:3f0104a208dbb420c48e6d1ba7ee250fb512c43bf932f776667b3eae84d88707— the digest the registry serves for
v0.1.2-beta.20260826052605. Read off thepod, after
.status.sync.revisionreached the merge commit; the ArgoCDapplication read
Synced/Healthyat the pre-merge revision before that.Correction 1: the defect was the directory's convention, and it was already half-fixed
My earlier comment said
tests/test_carddav_mcp.pyandtests/test_typst_mcp.pywere correct examples sitting next to a broken one. That is true of
maintoday and false of how it got there. Before
04fa38a2(2026-08-25 13:14,"test: assert the image is digest-pinned, not that it is one version") they read:
All three files carried the same defect. Someone diagnosed it a day before I
did, fixed the two files their commit touched, and did not touch caldav's —
plausibly because caldav's is the beta assertion with a different regex shape
and did not match whatever they were grepping for. So this was the convention of
the directory, not one file's slip, and the surviving instance was the one the
fix did not reach.
The correction cuts the other way too, and the check is cheap:
carddav-mcpisdeployed at
v0.1.3andtypst-mcpatv0.2.1right now, both past theversions their tests used to pin. Those bumps landed because
04fa38a2hadalready gone in. Any issue claiming those two tests still pin a literal and
that their bumps are waiting is describing 2026-08-25, and would have someone
fix what is fixed.
Correction 2: my own fix had the same fault one layer down
assertRegexsearches rather than matches, so[0-9a-f]{64}was satisfied bythe first 64 characters of a 65-hex digest. A malformed digest would have
passed the test that exists to reject malformed digests. Fixed in
oddie-apps/platformat69a0f7bby anchoring the trailing newline.I ran four controls against that regex — the old sha form, a hex-lettered
suffix, a missing digest, and the good case — and all four passed. The fifth I
did not think of is the one that mattered. A regex accepting what it should
reject is exactly the defect being removed here, and it survived into the
removal.
Cross-engine review found two more divergences from Renovate's rule, both
failing closed on a red PR:
v1.2.3-alpha.4(the rule takes alpha, the testdoes not) and
1.2.3-beta.4(the rule'svis optional, the test's is not).Recorded on
oddie-apps/platform#539.