You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
CredentialOps, ServiceOps and LoginOps have the same queued-closure cancellation race as #85 #87
The #85 defect exists in sibling ops too. Each passes a cancellable context to Queue.Do (via runQueued) and then reads or relies on the closure's outputs:
CredentialOps.Mint (cmd/relay/credential_ops.go): the same bug as RotateToken. The mint commits and its issuance is recorded, but a cancelled caller gets ctx.Err(), so the plaintext credential is lost. cred and plaintext also race with the worker.
Race on their outputs:CredentialOps.Revoke (removed), and ServiceOpsRegister, Create, Update and SaveConfigFile. Register's closure writes the named err directly.
Misreport but don't race:LoginOps.MintBootstrap and passkey revoke report a committed mint or revoke as failed.
Root cause
These use runQueued (Queue.Do) where runCommitted (Queue.DoCommitted) exists for this case.
Fix
Switch them to runCommitted, with -race tests first in the style of project_ops_commit_race_test.go.
Approved by the coordinator. This is the same fix as #85.
Change. Add runCommitted to CredentialOps (cmd/relay/credential_ops.go) and ServiceOps (cmd/relay/service_ops.go), shaped exactly like ProjectOps.runCommitted / LoginOps.runCommitted: nil Queue means run directly, otherwise Queue.DoCommitted. Then switch o.runQueued(ctx, …) to o.runCommitted(ctx, …) in exactly these eight methods:
CredentialOps.Mint: the one that matters, since a cancelled mint loses the plaintext;
LoginOps.MintBootstrap and LoginOps.RevokePasskey (they misreport; LoginOps.runCommitted already exists).
The calls that already pass context.Background() are unchanged, as are all signatures, return tuples, gates, audit and wire shapes. The queue structural test already accepts runCommitted. A step cancelled while still queued now runs; that is accepted, and #88 covers it.
Invariant for Mint and MintBootstrap: outside a deliberate audit-failure withhold path, a successful call returns the secret that was stored. After a cancellation the caller either receives it or nothing was stored. There must never be a stored credential or code whose plaintext the caller lost.
Tests (red first, -race). New file cmd/relay/ops_commit_race_test.go, one table-driven test in the style of project_ops_commit_race_test.go (hook store, real config.NewCommandQueue(1), cancel after the step is queued, then release). One row per method: it returns the committed result and the store agrees. Rows that race only need to be red or flagged by the race detector on the current code.
Files. Dev: credential_ops.go, service_ops.go, login_ops.go. Test writer: cmd/relay/ops_commit_race_test.go (new).
Activity
barelyworkingcode commentedon Sep 26, 2026
Contract
Approved by the coordinator. This is the same fix as #85.
Change. Add
runCommittedtoCredentialOps(cmd/relay/credential_ops.go) andServiceOps(cmd/relay/service_ops.go), shaped exactly likeProjectOps.runCommitted/LoginOps.runCommitted: nilQueuemeans run directly, otherwiseQueue.DoCommitted. Then switcho.runQueued(ctx, …)too.runCommitted(ctx, …)in exactly these eight methods:CredentialOps.Mint: the one that matters, since a cancelled mint loses the plaintext;CredentialOps.Revoke;ServiceOps.Register,Create,Update,SaveConfigFile;LoginOps.MintBootstrapandLoginOps.RevokePasskey(they misreport;LoginOps.runCommittedalready exists).The calls that already pass
context.Background()are unchanged, as are all signatures, return tuples, gates, audit and wire shapes. The queue structural test already acceptsrunCommitted. A step cancelled while still queued now runs; that is accepted, and #88 covers it.Invariant for
MintandMintBootstrap: outside a deliberate audit-failure withhold path, a successful call returns the secret that was stored. After a cancellation the caller either receives it or nothing was stored. There must never be a stored credential or code whose plaintext the caller lost.Tests (red first,
-race). New filecmd/relay/ops_commit_race_test.go, one table-driven test in the style ofproject_ops_commit_race_test.go(hook store, realconfig.NewCommandQueue(1), cancel after the step is queued, then release). One row per method: it returns the committed result and the store agrees. Rows that race only need to be red or flagged by the race detector on the current code.Files. Dev:
credential_ops.go,service_ops.go,login_ops.go. Test writer:cmd/relay/ops_commit_race_test.go(new).