state: caldav-mcp-beta is running an image that predates the RFC 8252 loopback fix #9

Closed
opened 2026-08-26 04:54:56 +00:00 by jlxq0 · 3 comments
Owner

State, verified 2026-08-26

caldav-mcp-beta is running an image built before the RFC 8252 §7.3 loopback
fix (#2, merged as 33bd20d). Production is not.

namespace image pod imageID
caldav-mcp v0.1.2 sha256:3d37a2ebe89851ae457f67e7fbb637d1f5d2948b177fa11da24f4d0b0f43c70c
caldav-mcp-beta v0.1.1-beta.e1ad86b sha256:ab8e6b38b5533b18edb01c59c716dd31372ca537ecd8f52748b38b803dcce85a

e1ad86b is the v0.1.1 commit, so beta predates both 33bd20d (the loopback
fix) and 4a6cf39 (the test that pins both halves of the scheme guard).

Both ArgoCD applications read Synced and Healthy, which is why the digests
above 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 by
exact string equality, so DCR answers unregistered redirect_uri. Production
accepts 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.

## State, verified 2026-08-26 `caldav-mcp-beta` is running an image built before the RFC 8252 §7.3 loopback fix (#2, merged as `33bd20d`). Production is not. | namespace | image | pod imageID | |---|---|---| | `caldav-mcp` | `v0.1.2` | `sha256:3d37a2ebe89851ae457f67e7fbb637d1f5d2948b177fa11da24f4d0b0f43c70c` | | `caldav-mcp-beta` | `v0.1.1-beta.e1ad86b` | `sha256:ab8e6b38b5533b18edb01c59c716dd31372ca537ecd8f52748b38b803dcce85a` | `e1ad86b` is the `v0.1.1` commit, so beta predates both `33bd20d` (the loopback fix) and `4a6cf39` (the test that pins both halves of the scheme guard). Both ArgoCD applications read `Synced` and `Healthy`, which is why the digests above 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 by exact string equality, so DCR answers `unregistered redirect_uri`. Production accepts 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.
Author
Owner

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.yml triggers on
push to main, push of v* tags, and pull_request. The image is pushed
only on a v* tag. There is no beta branch 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.e1ad86b was cut by hand.

2. Renovate cannot move the current pin even if a new tag appears. The
platform's clusters/fondue/*-beta/** rule takes:

"allowedVersions": "/^v?\\d+\\.\\d+\\.\\d+-(beta|alpha)\\.\\d+$/"

The suffix must be digits. v0.1.1-beta.e1ad86b is a sha, so it does not match
the rule that is supposed to maintain it. Every other *-beta app in fondue
uses a timestamp and matches:

app tag
a-grand-tour-beta v0.9.0-beta.20260822192015
hanso-beta v3.4.4-beta.20260821152014
miru-beta v0.1.0-beta.20260823015035
caldav-mcp-beta v0.1.1-beta.e1ad86b

caldav-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 current main by hand. It matches the
Renovate 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.toml version or be a prerelease of it, and this repo's convention is to
bump Cargo.toml at release time (chore(release): prepare v0.1.2), so
Cargo.toml reads 0.1.2 between releases and v0.1.3-beta.* would fail the
guard.

The oddity that leaves: 0.1.2-beta.<ts> sorts below the released 0.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.yml so beta stops being hand-cut, which also settles
whether Cargo.toml should carry the next version between releases the way the
Elixir apps do.

No :latest tag is produced — the workflow only adds it when the version has
no - in it — so production is untouched by this.

## 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.yml` triggers on `push` to `main`, `push` of `v*` tags, and `pull_request`. The image is pushed only on a `v*` tag. There is no `beta` branch 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.e1ad86b` was cut by hand. **2. Renovate cannot move the current pin even if a new tag appears.** The platform's `clusters/fondue/*-beta/**` rule takes: ```json "allowedVersions": "/^v?\\d+\\.\\d+\\.\\d+-(beta|alpha)\\.\\d+$/" ``` The suffix must be digits. `v0.1.1-beta.e1ad86b` is a sha, so it does not match the rule that is supposed to maintain it. Every other `*-beta` app in `fondue` uses a timestamp and matches: | app | tag | |---|---| | `a-grand-tour-beta` | `v0.9.0-beta.20260822192015` | | `hanso-beta` | `v3.4.4-beta.20260821152014` | | `miru-beta` | `v0.1.0-beta.20260823015035` | | `caldav-mcp-beta` | `v0.1.1-beta.e1ad86b` | caldav-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 current `main` by hand. It matches the Renovate 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.toml` version or be a prerelease of it, and this repo's convention is to bump `Cargo.toml` at release time (`chore(release): prepare v0.1.2`), so `Cargo.toml` reads `0.1.2` between releases and `v0.1.3-beta.*` would fail the guard. The oddity that leaves: `0.1.2-beta.<ts>` sorts *below* the released `0.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.yml` so beta stops being hand-cut, which also settles whether `Cargo.toml` should carry the next version between releases the way the Elixir apps do. No `:latest` tag is produced — the workflow only adds it when the version has no `-` in it — so production is untouched by this.
Author
Owner

A third layer, in oddie-apps/platform, and the reason this could never have self-corrected

The tag v0.1.2-beta.20260826052605 built and Renovate opened
oddie-apps/platform#538 with exactly the right diff. It fails CI, and the
failure is in that repository's own test suite.

tests/test_caldav_mcp.py::test_image_is_immutable_semver_prerelease asserts:

r"image: forge\.oddie\.app/jlxq0/caldav-mcp:"
r"v0\.1\.1-beta\.[0-9a-f]+@sha256:[0-9a-f]{64}"

That pins the current value rather than the shape, and it does the damage
twice:

  • v0\.1\.1 literally, so every future beta bump turns the test red. The
    pin could not move by automation.
  • [0-9a-f]+ for the prerelease suffix, which is what admitted the hand-cut
    v0.1.1-beta.e1ad86b. A sha cannot match the clusters/fondue/*-beta/**
    Renovate rule, allowedVersions: /^v?\d+\.\d+\.\d+-(beta|alpha)\.\d+$/, so
    the tag the test permitted was one the automation could never maintain.

Together those two facts mean caldav-mcp-beta has been unmaintainable since
it 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:33v[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 cannot
both be correct in separate commits, because the new regex rejects the tag on
main and the new tag fails the regex on main. The new regex was run against
the 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-config gets.

## A third layer, in `oddie-apps/platform`, and the reason this could never have self-corrected The tag `v0.1.2-beta.20260826052605` built and Renovate opened `oddie-apps/platform#538` with exactly the right diff. It fails CI, and the failure is in that repository's own test suite. `tests/test_caldav_mcp.py::test_image_is_immutable_semver_prerelease` asserts: ```python r"image: forge\.oddie\.app/jlxq0/caldav-mcp:" r"v0\.1\.1-beta\.[0-9a-f]+@sha256:[0-9a-f]{64}" ``` That pins the current **value** rather than the shape, and it does the damage twice: - `v0\.1\.1` literally, so **every** future beta bump turns the test red. The pin could not move by automation. - `[0-9a-f]+` for the prerelease suffix, which is what admitted the hand-cut `v0.1.1-beta.e1ad86b`. A sha cannot match the `clusters/fondue/*-beta/**` Renovate rule, `allowedVersions: /^v?\d+\.\d+\.\d+-(beta|alpha)\.\d+$/`, so the tag the test permitted was one the automation could never maintain. Together those two facts mean `caldav-mcp-beta` has been unmaintainable since it 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 cannot both be correct in separate commits, because the new regex rejects the tag on `main` and the new tag fails the regex on `main`. The new regex was run against the 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-config` gets.
Author
Owner

Closing state, and two corrections to what is written above

Beta is deployed. caldav-mcp-beta-6fb6fdcff7-45rls, container app, is
running sha256:3f0104a208dbb420c48e6d1ba7ee250fb512c43bf932f776667b3eae84d88707
— the digest the registry serves for v0.1.2-beta.20260826052605. Read off the
pod, after .status.sync.revision reached the merge commit; the ArgoCD
application read Synced/Healthy at 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.py and tests/test_typst_mcp.py
were correct examples sitting next to a broken one. That is true of main
today 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:

r"image: forge\.oddie\.app/jlxq0/carddav-mcp:v0\.1\.2@sha256:[0-9a-f]{64}"
r"^forge\.oddie\.app/jlxq0/typst-mcp:v0\.2\.0@sha256:[0-9a-f]{64}$"

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-mcp is
deployed at v0.1.3 and typst-mcp at v0.2.1 right now, both past the
versions their tests used to pin. Those bumps landed because 04fa38a2 had
already 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

assertRegex searches rather than matches, so [0-9a-f]{64} was satisfied by
the 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/platform at 69a0f7b by 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 test
does not) and 1.2.3-beta.4 (the rule's v is optional, the test's is not).
Recorded on oddie-apps/platform#539.

## Closing state, and two corrections to what is written above **Beta is deployed.** `caldav-mcp-beta-6fb6fdcff7-45rls`, container `app`, is running `sha256:3f0104a208dbb420c48e6d1ba7ee250fb512c43bf932f776667b3eae84d88707` — the digest the registry serves for `v0.1.2-beta.20260826052605`. Read off the pod, after `.status.sync.revision` reached the merge commit; the ArgoCD application read `Synced`/`Healthy` at 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.py` and `tests/test_typst_mcp.py` were correct examples sitting next to a broken one. That is true of `main` today 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: ```python r"image: forge\.oddie\.app/jlxq0/carddav-mcp:v0\.1\.2@sha256:[0-9a-f]{64}" r"^forge\.oddie\.app/jlxq0/typst-mcp:v0\.2\.0@sha256:[0-9a-f]{64}$" ``` 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-mcp` is deployed at `v0.1.3` and `typst-mcp` at `v0.2.1` right now, both past the versions their tests used to pin. Those bumps landed *because* `04fa38a2` had already 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 `assertRegex` searches rather than matches, so `[0-9a-f]{64}` was satisfied by the 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/platform` at `69a0f7b` by 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 test does not) and `1.2.3-beta.4` (the rule's `v` is optional, the test's is not). Recorded on `oddie-apps/platform#539`.
jlxq0 closed this issue 2026-08-26 06:40:52 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
jlxq0/caldav-mcp#9
No description provided.