Decouple token refresh from liquid tests: read-only CONFIG_JSON in run_tests.yml - #40
Draft
michieldegezelle wants to merge 1 commit into
Draft
Decouple token refresh from liquid tests: read-only CONFIG_JSON in run_tests.yml#40michieldegezelle wants to merge 1 commit into
michieldegezelle wants to merge 1 commit into
Conversation
Drops the check-auth job and loads CONFIG_JSON with every firm's refreshToken blanked, making this workflow a read-only consumer that can never rotate or write the shared token. Token refreshing moves to a scheduled refresh_token.yml in each market repo, which becomes that repo's sole CONFIG_JSON writer. Removes the poisoning class behind the 2026-07-14 invalid_grant incident on firm 400583: silverfin-cli refreshes on any 401 and Silverfin rotates the refresh token server-side, but the rotated pair dies with the runner, so the secret keeps a consumed token until a human re-authorizes the firm. Validated in be_market since 2026-07-24 (forked inline there in #3047); same strip mechanism as push_to_review_firm.yml (#29). README documents the pattern and the per-repo adopter checklist. PREREQUISITE, do not merge before: every caller repo needs its cron live first (nl#933, uk#1552, lu#820), or its tokens stop being refreshed and every firm's access token lapses within its 2h TTL. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueComment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
⛔ Do not merge yet — prerequisite PRs must land and be verified first
This makes the shared
run_tests.ymlstop refreshing tokens. If it merges before a caller repo hasits own scheduled refresher live, nothing refreshes that repo's
CONFIG_JSONand every firm'saccess token lapses within its 2h TTL, failing all of its liquid tests. Opened as a draft for that
reason.
Prerequisites, one per caller of this workflow:
schedule-triggeredrefresh_token.ymlrun confirmed greenuses:ref to@main); it forksrun_tests.ymlinline and is unaffected by this PR either wayWhat changes
.github/workflows/run_tests.ymlbecomes a read-only consumer ofCONFIG_JSON:check-authjob (andtest-templates'needs:on it) is removed — this workflow no longerrefreshes tokens or writes the secret;
refreshTokenviajqbefore the CLI runs, and passes thesecret through
env:rather than interpolating it into the script text;README.mdgains a "Token refresh (refresh_token.ymlin each market repo)" section underAuthentication: why the split exists, the per-repo adopter checklist, and the two known
limitations. This also closes out the "
push_to_review_firmadopter checklist" action item, sincethe checklist is the same for either consumer.
Why
silverfin-clirefreshes an access token transparently on any 401, for any command, andSilverfin rotates the refresh token server-side when it does. The rotated pair is written only to
the runner's local
~/.silverfin/config.json— there is no path back to the secret — soCONFIG_JSONis left holding an already-consumed refresh token. The next explicit refresh failswith
invalid_grantand that firm needs a manual re-authorization before its CI works again.That is the 2026-07-14 incident on firm 400583. Two decoupled writers racing over one rotating
credential cannot be made safe by ordering them; the fix is one scheduled writer plus consumers
that are structurally incapable of rotating anything. With
refreshTokenblanked, a stale accesstoken fails its 401 cleanly instead of poisoning the secret.
Validation
Not new logic — this ports what has been running in production:
be_market#3047forked this exact design inline on 2026-07-24 and has run it since. Over themost recent ~2.5 day window: 199/200
refresh_token.ymlruns green (the one failure self-healedon the next tick and did fire its Slack alert), with
run_tests.ymlgreen on live PR trafficthroughout.
jqstrip has been live inpush_to_review_firm.ymlsince push_to_review_firm.yml: strip refreshToken to stop silent CONFIG_JSON poisoning #29 (2026-07-23), includinga forced-401 drill that confirmed a stripped run fails cleanly and leaves the firm's real refresh
token untouched.
proving a held access token stays valid across an external refresh, and 5 concurrent read-only
runs passing in parallel) is in
silverfin-cli/CI_AUTH_SAMPLER_PLAN.md§1.Post-merge verification
run-tests / test-templatesruns green, and its log shows the"(read-only, no-poison)" load step. There should no longer be a
check-authjob in the run.refresh_token.ymlin each repo keeps ticking green andCONFIG_JSON's timestamp keeps moving.invalid_grantin any repo's refresh logs over the following days — the same check run forbe_market's weekend window on 2026-07-27, which was clean across 116 runs and all 8 firms.
Deliberately not in scope
check_auth.yml. Underbash -e, one firm's failed refreshaborts the step and skips the write-back, so no firm's refreshed token persists for that tick.
It self-heals on the next tick and only bites on a genuinely dead token, which the Slack alert
surfaces — fail-safe, not fail-dangerous. Changing the shared secret-writer in the same change
as a four-repo rollout is the wrong trade; separate PR.
#267/#268, both closed unmerged). A stale token still makessilverfin-cliexit the whole process, losing the verdict for every handle batched in the samerun-test --statuscall. CI-reliability only — this job has no write-back path, so it can neverpoison a token. Documented in the workflow header.
npm install …/silverfin-cli.gitunpinned, matching everyother production workflow; be_market has run floating
mainfor a month.update_templates_*andadd_shared_parts_*are unchanged andout of scope here.