Refresh on expiry, and push to providers that hold the value - #39
Merged
Conversation
czpython
force-pushed
the
dru-461-refresh-on-expiry
branch
from
September 6, 2026 16:15
79000b9 to
e787d85
Compare
czpython
force-pushed
the
dru-460-docker-sbx-secrets
branch
from
September 7, 2026 05:27
082831d to
c51e946
Compare
czpython
force-pushed
the
dru-461-refresh-on-expiry
branch
3 times, most recently
from
September 7, 2026 05:49
3bf8602 to
0cd8887
Compare
The exchange refreshes an issuer-backed secret when a request asks for it. On docker-sbx no request ever asks, since sbx does the swap, so the boot value expired after an hour and the box started to fail. The exchange now runs a timer. Every five seconds it looks at the active hosts on providers that hold the value. For each issuer-backed entry it fetches a fresh value when less than a minute of the pushed one remains, and hands it to the seam's push_secret. A push that fails is logged with the host and the service, and waits like a fetch that fails. The same value goes again after the wait. On restart the timer starts from the database, and nothing is written back. Proxy providers are not visited. push_secret takes the box, the service name, and the value. It takes no placeholder, since the host row keeps only a fingerprint of it. On docker-sbx a push is a rewritten value file: sbx runs the cat command at each use, for a service secret once registered with --refresh on-demand. Without that flag sbx caches the output for 55 minutes. Each host gets its own error boundary in a pass, and the hosts go side by side, so one host in trouble or one slow issuer costs no other host its value. A value file is replaced whole through a staged 0600 file, so sbx never reads a half-written one. Only put_secret makes the sandbox's directory, so a push that races a teardown brings nothing back. The exchange process logs at INFO, so its log shows each push.
czpython
force-pushed
the
dru-461-refresh-on-expiry
branch
from
September 7, 2026 05:52
0cd8887 to
10404df
Compare
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.
What changes
The exchange refreshes an issuer-backed secret on expiry for a provider that holds the value, and pushes it.
push_secret. The first push happens at first sight of the host, since the boot value came from the API process.RefreshableSecretkeeps its margin and its retry wait. A push that fails is logged with the host and the service, and waits like a fetch that fails. The same value goes again after the wait, without a new fetch.catcommand at each use: for a custom secret by default, and for a service secret when registered with--refresh on-demand, whichsbx secret setnow passes. Without that flag sbx caches the output for 55 minutes.Where this differs from the ticket
push_secret, notput_secretagain.put_secrettakes the placeholder, and the host row keeps only a fingerprint of it, by design. A provider that holds the value knows its own registration, so the push takes the box, the service name, and the value.Names
New names, open to change:
push_secreton the seam,Secrets.push,RefreshableSecret.pushed,RefreshableSecret.unpushed,RefreshableSecret.retry_later,push_on_expiry,push_held,TICK,SbxInjection.write_value.Gates
uv run ruff check,uv run ruff format --check,uv run pyright, anduv run pytestare green.Acceptance
docker-sbx on the KVM bed, with an anthropic secret from an issuer stub at a 70 second lifetime and a static github secret:
claude -pansweredokfour times across three lifetimes, over 224 seconds, with no manual step.DELETE /hosts, the sandbox scope listed no secret.11 of 11 checks passed on this commit.
Review
The adversarial review reported four findings. All four are applied, in their smallest form:
put_secretcreates the directory now. A push into a removed one fails as a provider error, which the timer logs and drops once the row is gone. The review suggested the host row lock for this. It is not needed once a push cannot recreate the directory.