Repository navigation
feat(cliproxy): restrict Kamino credentials by model family - #3241
Conversation
|
Warning This organization's free trial has ended, so Indent couldn't continue this review. Manage billing to resume reviews on this repository.
All required CI checks passed on
Select any unchecked box below to run or rerun that agent. Full resultsIndent Review Agent
|
|
Caution Review failedThe pull request is closed. Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
ℹ️ No critical issues — minor suggestions inline.
Reviewed changes Restricts Kamino tunnel OAuth credentials by model family so each credential can only register and route to its approved Claude family.
home-manager/programs/kamino/default.nix— readskamino-tunnels.json, validatesmodel_familyagainst an allow-list (fail-closed at Nix eval), and writesmodel_familyintokamino-fleet.jsonper machine.home-manager/services/cliproxyapi/scripts/start.sh— addsmodel_policy_exclusions()andapply_model_policies(); writesexcluded_modelsplusfleet_model_*markers to matching OAuth auth files; rollback removes only generated exclusions on policy removal. Invoked atstart.sh:239.kamino-tunnels.json— setsmodel_family: "haiku"for the jangly-bears6h Claude credential.home-manager/services/cliproxyapi/README.md— documentsmodel_familyconfiguration.spec/cliproxyapi_spec.sh— tests exclusions definition and apply-to-auth-file behavior.
Implementation is sound: fail-closed Nix validation, marker-based rollback that preserves operator-authored exclusions, and lock coordination matching the existing assign_proxy_urls pattern.
free | 𝕏
| if @jq@ -e 'has("fleet_model_policy") and has("fleet_model_excluded_models")' "$f" >/dev/null 2>&1; then | ||
| # shellcheck disable=SC2016 | ||
| @jq@ 'if has("fleet_model_previous_excluded_models") then .excluded_models = .fleet_model_previous_excluded_models elif .excluded_models == .fleet_model_excluded_models then del(.excluded_models) else . end | del(.fleet_model_policy, .fleet_model_excluded_models, .fleet_model_previous_excluded_models)' "$f" >"$f.tmp" && mv "$f.tmp" "$f" | ||
| fi |
There was a problem hiding this comment.
The removal/rollback path keys on fleet_model_policy and fleet_model_excluded_models markers written into each auth file. CLIProxyAPI rewrites auth files on every token refresh (README.md:74); if it strips unknown JSON fields when re-serializing, these markers—and excluded_models itself—lapse between start.sh runs. The restriction would then only be enforced until the next refresh, and the rollback path wouldn't fire on CLIProxy-rewritten files. This is an external-behavior question, not a confirmed bug.
Technical details
# Marker survival across CLIProxy auth-file rewrites
## Affected sites
- home-manager/services/cliproxyapi/scripts/start.sh:182-185 — removal logic keys on fleet_model_* markers
- home-manager/services/cliproxyapi/scripts/start.sh:175-177 — markers written alongside excluded_models
## Required outcome
- Confirm whether CLIProxy preserves unknown JSON fields (excluded_models, fleet_model_*) when rewriting auth files on token refresh, or document the restriction lapses between start.sh runs.
## Suggested approach (optional)
- Empirically diff an auth file before and after a CLIProxy token refresh to see whether excluded_models survives.
- If CLIProxy strips unknown fields, either re-apply policies on a schedule or note the window in the README.
## Open questions for the human
- Does CLIProxyAPI preserve custom JSON fields in auth files across token refreshes?| if matches == [ ] then { } else { model_family = (builtins.head matches).model_family; }; | ||
| inventory = pkgs.writeText "kamino-fleet.json" ( | ||
| builtins.toJSON ( | ||
| fleet |
There was a problem hiding this comment.
Nix validation of model_family is case-sensitive (allowedModelFamilies is lowercase), but the shell model_policy_exclusions lowercases its input (${1,,}). A value like "Haiku" would fail Nix evaluation yet pass the shell function in isolation. Not a bug with the current all-lowercase data, but worth aligning for consistency.
Technical details
# Case-sensitivity mismatch between Nix and shell
## Affected sites
- home-manager/programs/kamino/default.nix:26 — case-sensitive elem check against lowercase allowedModelFamilies
- home-manager/services/cliproxyapi/scripts/start.sh:128 — model_policy_exclusions lowercases via ${1,,}
## Required outcome
- Align case handling so Nix and shell agree on accepted model_family values.
## Suggested approach (optional)
- Either lowercase in Nix before the elem check, or drop the lowercase in shell to match Nix (and update the spec test that uses "Haiku").
Changes
model_familypolicies to Kamino credential mappings.kamino-fleet.jsonand document the configuration.Technical details
A
model_family: haikumapping excludes Claude model IDs containingopus,sonnet, orfable, so that credential can only register and route to Haiku models. Unknown families fail closed during Nix evaluation or proxy rendering.Testing
shellspec spec/cliproxyapi_spec.sh spec/kamino_fleet_spec.sh(99 examples, 0 failures)bash -n, ShellCheck,nixfmt --check, andgit diff --checkGenerated with Codex.
Summary by cubic
Restricts Kamino tunnel credentials to a declared model family so OAuth credentials can only route to the models they are approved for.
model_familyfield tokamino-tunnels.json; the CLIProxy start script renders it intoexcluded_modelsrules on the matching auth file before starting.kamino-fleet.jsonwith the samemodel_familyfield and strips previously generated exclusions when a policy is removed.claude-2738f2fb-jangly-bears6h@icloud.comcredential tohaiku, so it can no longer serve Opus, Sonnet, or Fable models.Migration
model_familyentry inkamino-tunnels.json. Credentials without one keep their current behavior.Written for commit 0497b5f. Summary will update on new commits.