Repository navigation
feat(svo-adapter): token keeper for model tasks the Workflows engine starts late - #377
Merged
Merged
Conversation
…starts late
Tapis Workflows wedged two composite runs for 4.6 h and 29 h before launching
the model task; by then the 4 h per-run token in the run args had expired and
the task died on its first call with MODEL_PROVIDER_AUTH_FAILED. The task's
own renewal cannot help because it needs a live token.
The adapter now keeps the current per-run token on adapter.workflow_run,
Fernet-encrypted and bound to the run id, and serves a live one at
POST /runs/{id}/token. The endpoint authenticates with a per-run HMAC in its
own domain (run-token:v1:, derived from the signal secrets), rate-limits per
run, serves only running/submitting runs inside a 72 h deadline, mints a
successor on the way out when the stored token is near expiry, and revokes
predecessors. Stored tokens are revoked and cleared on terminal status,
cancel, failed dispatch, deadline, and decrypt failure. An optional poller
sweep renews ahead of time for waits longer than one TTL.
The generated model task fetches a live token before its first Tapis call
when the baked token is expired or near expiry, and once on a 401 (never on
403); on a 401 from /v3/jobs/submit it re-checks for an existing job by name
before submitting again. A task that cannot recover fails with
RUN_TOKEN_EXPIRED_BEFORE_START instead of a misleading rejection message.
Off by default (SVO_ADAPTER_RUN_TOKEN_KEEPER_ENABLED); a keeper enabled
without a usable key, run signals, or an https public URL fails at startup.
Deploy wiring applies run-token values only when set and refuses to enable
the keeper without a key. Migration 1771300000035 adds the four columns.
Design: docs/design/2026-10-28-svo-adapter-workflow-token-lifecycle.md (rev 2,
security-reviewer, skeptic and QA revisions recorded).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This branch was successfully deployed
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.
Why
On 2026-11-03 two composite runs were held by the Tapis Workflows engine for 4.6 h and 29 h before their model task launched. By then the 4 h per-run token in the run args had expired, and the task died on its first Tapis call with
MODEL_PROVIDER_AUTH_FAILED. The task's own renewal (_renew_if_due) cannot help: it runs inside the task and needs a live token. Design:docs/design/2026-10-28-svo-adapter-workflow-token-lifecycle.md, rev 2 (security-reviewer, skeptic and QA revisions recorded in the spec).What
adapter.workflow_run(run_token_enc, Fernet viaMultiFernetfor rotation, ciphertext bound to the run id), plusrun_token_expires_at,run_token_deadline_at,run_token_renewals. Migration1771300000035_adapter_workflow_run_token_keeper.POST /runs/{run_id}/token: hands the model task the current token. Authenticated by a per-run HMAC credential in its own domain (run-token:v1:, derived fromSVO_ADAPTER_RUN_SIGNAL_SECRETS; a signal token cannot fetch and vice versa). Uniform 401 for bad credential / unknown run, 404RUN_TOKEN_UNAVAILABLEoutsiderunning/submittingor past the 72 h deadline, per-run rate limit,Cache-Control: no-store. Mints a successor on the way out when the stored token is within the renewal margin and revokes the predecessor (POST /v3/tokens/revoke, verified on portals).cancellingare also cleared. Optional background sweep (SVO_ADAPTER_RUN_TOKEN_KEEPER_SWEEP_ENABLED) for waits longer than one TTL./v3/jobs/submitit re-checks_existing_job()by name before resubmitting, so a late start never duplicates a job. Fails withRUN_TOKEN_EXPIRED_BEFORE_STARTwhen it cannot recover.register_mint_stack.py --sync-svo-runtimemanagesSVO_ADAPTER_RUN_TOKEN_*only when the variable/secret is set, and refuses to enable the keeper without a key.Verified live before coding
GET /healthfrom a canary task, 0.11 s).POST /v3/tokens;POST /v3/tokens/revokeworks.runningfrom dispatch, so the keeper's status filter covers the engine-wedge case.Tests
svo-adapter-service: 233 passed. Newtests/test_run_token_keeper.pycovers crypto round trip and key rotation, config fail-closed, credential domains, endpoint auth / 404 / 429 / renew / cap / CAS loss, sweep, release, and runs the generated model task against a stubbed Tapis for late start, no-keeper failure code, and a mid-run 401 without a duplicate job.test_run_signal.pycovers submit-time storage, arming, and failed-dispatch release. The 5 failures intest_demo_api.pyandtest_register_existing_etl_pieces.pypre-exist ondevelop.Rollout
SVO_ADAPTER_RUN_TOKEN_ENCRYPTION_KEYS(Fernet key) and env varSVO_ADAPTER_RUN_TOKEN_KEEPER_ENABLED=trueinTapis Dev Deploy, re-run the dev-pod deploy.run.token.fetchedrecorded. Then lowerSVO_ADAPTER_RUN_TOKEN_TTL_SECONDSback from the interim 48 h.🤖 Generated with Claude Code