fix(ploeg): tie per-Run forge tokens to a live Lease and always revoke them #174

Merged
ryangr0 merged 1 commit from ryangr0/ploeg-forge-token-lifecycle into development 2026-10-03 11:55:16 +00:00 AGit
Owner

A writing claim minted a push token, then recorded its id on the Lease while
ignoring the affected-row count. If the Run had been withdrawn or its Lease
had expired while the mint was in flight, or the database write failed, the
error was only logged and the worker still got a token that nothing was
recorded to revoke. The forge orphan sweep read the live Lease ids before it
listed the forge's tokens, so a token minted or not yet recorded during a
sweep looked orphaned and a running worker lost its push rights. The sweep
also read only the first page of the token list and stopped at the first
failed revoke. MintRequest.TTL promised a time limit that Forgejo's token API
does not support, and the broker never sent one.

RecordForgeToken now returns ErrLeaseLost unless the Run is running and its
Lease is unexpired. On any record failure the claim answers 204, revokes the
token with a context that is not cancelled and is limited to 30 seconds, and
releases the Run when the Lease is still there. Report and withdraw revokes
use the same kind of context. The forge sweep lists every page of the bot's
tokens first, then reads which runs hold a Lease. It keeps every token whose
name carries a leased run, revokes the rest, and keeps going after a failed
revoke. Because the token name carries the run, the forge itself records
every token: after a restart, a token that was minted but not recorded, or
whose revoke failed, is revoked once its Run holds no Lease. The TTL field is
removed. The package documentation and the Push Credential glossary entry
now say that the token does not expire and revocation is its only limit.

No migration: the forge's own token list (names carry ploeg-run-) is the record, so the sweep revokes any ploeg-run token whose Run holds no Lease; other tokens on the bot account are never touched. The sweep now lists tokens before reading Leases (the old order could revoke a running worker's token) and reads every page. Forgejo tokens have no expiry (MintRequest.TTL removed; docs say revocation is the only bound). Rebased onto current development; landscape regenerated.

Verified with mise run verify on the pinned toolchain (all gates passed).

Ticket: https://vikunja.webgrip.dev/tasks/1739

🤖 Generated with Claude Code

A writing claim minted a push token, then recorded its id on the Lease while ignoring the affected-row count. If the Run had been withdrawn or its Lease had expired while the mint was in flight, or the database write failed, the error was only logged and the worker still got a token that nothing was recorded to revoke. The forge orphan sweep read the live Lease ids before it listed the forge's tokens, so a token minted or not yet recorded during a sweep looked orphaned and a running worker lost its push rights. The sweep also read only the first page of the token list and stopped at the first failed revoke. MintRequest.TTL promised a time limit that Forgejo's token API does not support, and the broker never sent one. RecordForgeToken now returns ErrLeaseLost unless the Run is running and its Lease is unexpired. On any record failure the claim answers 204, revokes the token with a context that is not cancelled and is limited to 30 seconds, and releases the Run when the Lease is still there. Report and withdraw revokes use the same kind of context. The forge sweep lists every page of the bot's tokens first, then reads which runs hold a Lease. It keeps every token whose name carries a leased run, revokes the rest, and keeps going after a failed revoke. Because the token name carries the run, the forge itself records every token: after a restart, a token that was minted but not recorded, or whose revoke failed, is revoked once its Run holds no Lease. The TTL field is removed. The package documentation and the Push Credential glossary entry now say that the token does not expire and revocation is its only limit. No migration: the forge's own token list (names carry ploeg-run-<run prefix>) is the record, so the sweep revokes any ploeg-run token whose Run holds no Lease; other tokens on the bot account are never touched. The sweep now lists tokens before reading Leases (the old order could revoke a running worker's token) and reads every page. Forgejo tokens have no expiry (MintRequest.TTL removed; docs say revocation is the only bound). Rebased onto current development; landscape regenerated. Verified with `mise run verify` on the pinned toolchain (all gates passed). Ticket: https://vikunja.webgrip.dev/tasks/1739 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(ploeg): tie per-Run forge tokens to a live Lease and always revoke them
All checks were successful
[Workflow] On Pull Request / checks (pull_request) Successful in 7m1s
[Workflow] On Pull Request / release-policy (pull_request) Successful in 18s
[Workflow] On Pull Request / warnings (pull_request) Successful in 1s
da2f3a2240
A writing claim minted a push token, then recorded its id on the Lease while
ignoring the affected-row count. If the Run had been withdrawn or its Lease
had expired while the mint was in flight, or the database write failed, the
error was only logged and the worker still got a token that nothing was
recorded to revoke. The forge orphan sweep read the live Lease ids before it
listed the forge's tokens, so a token minted or not yet recorded during a
sweep looked orphaned and a running worker lost its push rights. The sweep
also read only the first page of the token list and stopped at the first
failed revoke. MintRequest.TTL promised a time limit that Forgejo's token API
does not support, and the broker never sent one.

RecordForgeToken now returns ErrLeaseLost unless the Run is running and its
Lease is unexpired. On any record failure the claim answers 204, revokes the
token with a context that is not cancelled and is limited to 30 seconds, and
releases the Run when the Lease is still there. Report and withdraw revokes
use the same kind of context. The forge sweep lists every page of the bot's
tokens first, then reads which runs hold a Lease. It keeps every token whose
name carries a leased run, revokes the rest, and keeps going after a failed
revoke. Because the token name carries the run, the forge itself records
every token: after a restart, a token that was minted but not recorded, or
whose revoke failed, is revoked once its Run holds no Lease. The TTL field is
removed. The package documentation and the Push Credential glossary entry
now say that the token does not expire and revocation is its only limit.

VIK-1739

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ryangr0 merged commit 77f2bdaee0 into development 2026-10-03 11:55:16 +00:00
Sign in to join this conversation.
No reviewers
No labels
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
webgrip/unfold!174
No description provided.