Fix: sandbox resource version is not advanced for every policy revision #4109
jayasri-88
started this conversation in
Vouch Request
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Hi, I'm jayasri-88 and this would be my first contribution to OpenShell. I hit this while integrating a policy reconciliation controller that drives sandboxes through the Go SDK, and I want to fix the underlying bug rather than work around it.
What I found
put_policy_revision_atomicin the gateway persistence layer only bumped the sandbox'sresource_versionwhen the revision actually changed something on the sandbox. If a revision left annotations alone, had no backfill policy, or re-submitted the exact policy the sandbox was already running, the revision was still committed but the version stayed where it was.Why it matters to me
My controller reads a sandbox, computes policy changes, then writes. It uses the resource version it read as the optimistic concurrency precondition, on the understanding that any other policy writer will have moved it. That assumption does not hold here. My controller can read a sandbox, another writer commits a revision that happens to be a no-op projection, and my controller's write still gets accepted even though the policy it derived from is stale. Policy revision numbers do not save me, because I select the next revision number while submitting content computed from the earlier read.
Re-reading immediately before the write narrows the window but does not close it, and a process-local lock in my controller cannot coordinate against a separate controller instance or a second gateway replica.
What I am proposing
Make the sandbox update unconditional in both backends, so every committed per-sandbox policy revision advances the resource version and refreshes
updated_at_ms. The projection logic itself is unchanged, so backfill and annotation semantics stay exactly as they are.expected_resource_version = 0remains unconditional but now also advances the version. I am leaving the non-atomicput_policy_revisionand the global policy-revision path alone.In other words: if a revision commits, the version moves. That makes the precondition meaningful.
How I verified it
On SQLite with the gateway server test suite. I added regression tests covering each case: no-op projection, identical backfilled policy, unconditional write with version zero, a stale nonzero version correctly conflicting, a retry succeeding after re-reading, and the rollback path leaving the sandbox version untouched when the policy insert fails. I confirmed the five version-related tests fail against the unpatched code and pass with the change. Full crate suite is green (1871 passed, 0 failed), fmt is clean, and clippy reports nothing new.
PostgreSQL is changed to match but I have not run it against a live instance, only the in-memory SQLite tests.
PR
PR #4108 has the change. It was auto-closed because I was not vouched yet. I am happy to rebase, split anything up, or rework the approach if you would rather it went in differently.
Thanks for taking a look.
All reactions