feat(cli,api,store): binding CRUD, multi-destination cred add, cred update#24
Merged
nnemirovsky merged 10 commits intomainfrom Apr 11, 2026
Merged
feat(cli,api,store): binding CRUD, multi-destination cred add, cred update#24nnemirovsky merged 10 commits intomainfrom
nnemirovsky merged 10 commits intomainfrom
Conversation
Squashed fixes from review phases 1 through 4 and codex iterations 1-10: - preserve OAuth refresh_token when not supplied (CLI + API) - sync paired allow rule when binding destination, ports, or protocols change - add EnvVar field to BindingUpdateOpts; --env-var and --protocols on update - reject duplicate binding add via case-insensitive UNIQUE index (migrations 000005, 000007) - migration aborts on conflicting binding dedup so data loss is surfaced to operators - classify API errors: 409 Conflict on duplicates, 400 only for ErrBindingValidation, 500 otherwise - wrap validation errors (port range, destination glob, protocols, env_var) with ErrBindingValidation sentinel - close TOCTOUs: AddBinding env_var check transactional; RemoveBindingWithRuleCleanup in one tx; UpdateBindingWithRuleSync transactional; PostApiCredentials/PatchApiCredentialsName acquire reloadMu - CAS-protect credential rollback against concurrent writers (vault.RollbackAdd, store.RemoveCredentialMetaCAS) - PatchApiCredentialsName and handleCredUpdate use credential_meta as authoritative type source - updatePairedRuleTx walks both cred-add and binding-add source prefixes - recompileEngine/rebuildResolver failures now return 500 to callers instead of WARN+success - return 500 on rebuildResolver failures in PostApiCredentials/DeleteApiCredentialsName - consolidated source-prefix constants into store package - deleted dead UpdateBinding/UpdateRuleDestinationBySource/SyncPairedAllowRule code - extracted parsePortsList helper into flagutil.go - updated CLAUDE.md and openapi.yaml to match new behavior
The binding-cli branch added 000005, 000006, and 000007 across separate review iterations. None have shipped to production, so they should be one atomic schema change. The consolidated 000005 drops idx_bindings_env_var, detects conflicting (credential, LOWER(destination)) bindings, dedups exact duplicates with their paired allow rules, and creates the case-insensitive unique index in a single migration.
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.
Summary
sluice binding add|list|update|removeCLI subcommands andPATCH /api/bindings/{id}API endpoint for managing bindings without needing to delete and recreate themsluice cred updateCLI subcommand andPATCH /api/credentials/{name}API endpoint for replacing a credential value (static or OAuth) without losing bindingssluice cred add --destinationis now repeatable so a single credential can ship with multiple bindings sharing the same optionsBindingUpdateOptsstore API and a transactionalUpdateBindingWithRuleSyncthat keeps the auto-created paired allow rule (ports/protocols/destination) in lockstep with binding edits, plusRemoveBindingWithRuleCleanupfor atomic delete000005_binding_unique_cred_dest: dropsidx_bindings_env_var, conflict-detects duplicate(credential, LOWER(destination))rows with an operator-actionable abort, dedups exact duplicates with their paired allow rules, and creates a case-insensitive UNIQUE index. Bindings of the same credential can now share anenv_varbecause they resolve to the same phantom valueErrBindingDuplicate,ErrBindingNotFound,ErrBindingValidationso API handlers map store failures to the right HTTP status (409/404/400/500) instead of blanket400recompileEngineandrebuildResolverfailures now propagate as500on binding/credential mutation paths instead of silently logging and returning success, so a failed reload no longer leaves the live engine stale while reporting201/204vault.RollbackAdd,store.RemoveCredentialMetaCAS) so a transient DB failure duringcred addcannot wipe a concurrent writer's credentialPatchApiCredentialsNameandhandleCredUpdatenow readcredential_metato authoritatively decide static vs OAuth, instead of inferring from payload shape (which misclassified static credentials whose values happened to be JSON containingaccess_token+token_url)(credential, LOWER(destination))to match the new unique index, so re-importing a config that changesheader/template/portsfor an existing pair no longer aborts onUNIQUEviolationTest plan
go build ./...go test ./... -timeout 120s(12 packages, all green)gofumpt -l cmd/sluice/ internal/cleancred updatepreserves bindings, verify migration aborts loudly on conflicting upgrade data