Skip to content

feat(cli,api,store): binding CRUD, multi-destination cred add, cred update#24

Merged
nnemirovsky merged 10 commits intomainfrom
binding-cli
Apr 11, 2026
Merged

feat(cli,api,store): binding CRUD, multi-destination cred add, cred update#24
nnemirovsky merged 10 commits intomainfrom
binding-cli

Conversation

@nnemirovsky
Copy link
Copy Markdown
Owner

Summary

  • New sluice binding add|list|update|remove CLI subcommands and PATCH /api/bindings/{id} API endpoint for managing bindings without needing to delete and recreate them
  • New sluice cred update CLI subcommand and PATCH /api/credentials/{name} API endpoint for replacing a credential value (static or OAuth) without losing bindings
  • sluice cred add --destination is now repeatable so a single credential can ship with multiple bindings sharing the same options
  • Adds the BindingUpdateOpts store API and a transactional UpdateBindingWithRuleSync that keeps the auto-created paired allow rule (ports/protocols/destination) in lockstep with binding edits, plus RemoveBindingWithRuleCleanup for atomic delete
  • New migration 000005_binding_unique_cred_dest: drops idx_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 an env_var because they resolve to the same phantom value
  • Sentinel errors ErrBindingDuplicate, ErrBindingNotFound, ErrBindingValidation so API handlers map store failures to the right HTTP status (409/404/400/500) instead of blanket 400
  • API recompileEngine and rebuildResolver failures now propagate as 500 on binding/credential mutation paths instead of silently logging and returning success, so a failed reload no longer leaves the live engine stale while reporting 201/204
  • CAS-protected vault and credential_meta rollback (vault.RollbackAdd, store.RemoveCredentialMetaCAS) so a transient DB failure during cred add cannot wipe a concurrent writer's credential
  • PatchApiCredentialsName and handleCredUpdate now read credential_meta to authoritatively decide static vs OAuth, instead of inferring from payload shape (which misclassified static credentials whose values happened to be JSON containing access_token+token_url)
  • Destination glob, port range, and protocol name validation pushed into the store boundary so bad input fails at the API/CLI surface, not later at policy/resolver recompile time
  • TOML import deduplicates bindings on (credential, LOWER(destination)) to match the new unique index, so re-importing a config that changes header/template/ports for an existing pair no longer aborts on UNIQUE violation

Test plan

  • go build ./...
  • go test ./... -timeout 120s (12 packages, all green)
  • gofumpt -l cmd/sluice/ internal/ clean
  • Manual: create credential with multiple destinations, verify cred update preserves bindings, verify migration aborts loudly on conflicting upgrade data

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.
@nnemirovsky nnemirovsky merged commit 32eaa23 into main Apr 11, 2026
6 checks passed
@nnemirovsky nnemirovsky deleted the binding-cli branch April 11, 2026 10:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant