fix(forge): one process renews the git sign-in at a time, so renewals at once no longer lose it #140

Merged
HumanBean merged 1 commit from HumanBean/Longshot:fix/forge-session-lock into main 2026-11-13 06:22:33 +00:00
Owner

Why

Twice today the git.magicbean.dev sign-in was lost mid-work ("token was already used"): git's credential helper and forge.py, or two agents, renewed the expired token at the same moment, Forgejo takes each refresh token once, and the second renewal threw the sign-in away. Everyone then had to sign in again.

What changed

  • scripts/magicbean_login.py: forge_session() renews under a lock (forge.json.lock, flock on Linux, msvcrt.locking on Windows) and reads the saved sign-in again once it holds it, so a process that waited uses the token the first one saved instead of renewing with a spent refresh token. A token still good returns at once, without the lock. forge_expire() takes the lock too.
  • write_private() writes to a temporary file named with the process id, so two writers never share one.
  • New tests/test_forge_session_lock.py: 4 processes renew an expired sign-in together against a stand-in for Forgejo that refuses a reused refresh token.

Flags and settings

None

Measurements

main: a7aa850b (2026-11-13)
this PR: fix/forge-session-lock @ 795d16b3

4 renewals at once (tests/test_forge_session_lock.py) main @ a7aa850b this PR @ 795d16b3
processes left with a token 1 of 4 (3 lose the sign-in) 4 of 4
renewals Forgejo sees 4 (3 refused) 1

Testing

Tested: the new test on Linux (fails on main's code, passes here); tests/test_forge_pr.py.

Not tested: the Windows lock (msvcrt.locking) on Windows.

Needs other testers: Windows: run python -I scripts/forge.py whoami twice at once after the token expired (an hour after sign-in); both should answer (request to open).

Screenshots

Nothing on screen

Risk and rollback

A process holding the lock while Forgejo is slow makes others wait for it (the request has a timeout). Reverting the commit is enough.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.
## Why Twice today the git.magicbean.dev sign-in was lost mid-work ("token was already used"): git's credential helper and forge.py, or two agents, renewed the expired token at the same moment, Forgejo takes each refresh token once, and the second renewal threw the sign-in away. Everyone then had to sign in again. ## What changed - `scripts/magicbean_login.py`: `forge_session()` renews under a lock (`forge.json.lock`, `flock` on Linux, `msvcrt.locking` on Windows) and reads the saved sign-in again once it holds it, so a process that waited uses the token the first one saved instead of renewing with a spent refresh token. A token still good returns at once, without the lock. `forge_expire()` takes the lock too. - `write_private()` writes to a temporary file named with the process id, so two writers never share one. - New `tests/test_forge_session_lock.py`: 4 processes renew an expired sign-in together against a stand-in for Forgejo that refuses a reused refresh token. ## Flags and settings None ## Measurements main: a7aa850b (2026-11-13) this PR: fix/forge-session-lock @ 795d16b3 | 4 renewals at once (tests/test_forge_session_lock.py) | main @ a7aa850b | this PR @ 795d16b3 | |---|---|---| | processes left with a token | 1 of 4 (3 lose the sign-in) | 4 of 4 | | renewals Forgejo sees | 4 (3 refused) | 1 | ## Testing **Tested:** the new test on Linux (fails on main's code, passes here); `tests/test_forge_pr.py`. **Not tested:** the Windows lock (`msvcrt.locking`) on Windows. **Needs other testers:** Windows: run `python -I scripts/forge.py whoami` twice at once after the token expired (an hour after sign-in); both should answer (request to open). ## Screenshots Nothing on screen ## Risk and rollback A process holding the lock while Forgejo is slow makes others wait for it (the request has a timeout). Reverting the commit is enough. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.
fix(forge): one process renews the git sign-in at a time, so renewals at once no longer lose it
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Successful in 6s
CI / Workflow lint (actionlint) (pull_request) Failing after 6s
Third-party parts / As their notes say (pull_request) Successful in 13s
795d16b3b1
HumanBean deleted branch fix/forge-session-lock 2026-11-13 06:22:34 +00:00
Sign in to join this conversation.
No reviewers
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
MagicBeanDev/Longshot!140
No description provided.