feat(llamaswap): add llama-swaps (TLS) DSN scheme #4
Reference in New Issue
Block a user
Delete Branch "feat/llama-swaps-tls"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to #3. llama-swap was reachable by DSN only over http (
llama-swap://), which pushed TLS-fronted instances onto theopenai://scheme — losing the management methods and image generation that live on the concrete*llamaswap.Provider.This adds a
llama-swaps://scheme that builds anhttps://base URL, alongsidellama-swap://(http, local-first). Mirrors theredis/redissconvention.builtin.go;llama-swapsis scheme-only (no default built-in provider name).TestLlamaSwapsSchemeasserts the https base URL; existingllama-swaphttp test unchanged.Gates green (
build,vet,test -race,mod tidy). No new dependencies.🤖 Generated with Claude Code
🪰 Gadfly review —
m5/qwen3.6:35b-mlx(m5)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
VERDICT: No material issues found
Findings:
I traced the full input path for the
llama-swaps://DSN scheme and confirmed through reading:No new injection vectors introduced. The
llamaSwapScheme(urlScheme)factory inbuiltin.go:89-97constructs base URLs asurlScheme+"://"+dsn.Host. This mirrors the existingllama-swap(http) path exactly. Both schemes share identical code paths throughParseDSN()→WithBaseURL()→doJSON()→http.NewRequestWithContext().Existing host validation gap is pre-existing, not introduced by this PR.
ParseDSN()atenv.go:46-64performs zero validation on theHostfield — no character whitelist, no length limit, no internal IP blocking. An attacker who controlsLLM_LScould setllama-swaps://internal-service.local/pathfor SSRF. But this is true for all providers (openai, ollama, anthropic, etc.) which all useDSN.Hostidentically without validation. The PR does not make this worse.Token leakage to upstream server via HTTPS. The
llama-swapsscheme explicitly sends the bearer token over TLS (https://), which is the correct and intended behavior. Contrast withllama-swap(http://) where the token would be sent in cleartext — a pre-existing design consideration noted in comments, not changed by this PR.Scheme name collision unlikely.
ProviderLlamaSwapTLS = "llama-swaps"is registered as a new key inr.schemes. No other registration uses this string (confirmed via grep). The scheme-only registration (no no-DSN built-in) follows the same pattern as documented.Verified by:
builtin.go:89-100— confirmedllamaSwapSchemefactory logic for both http/https entriesenv.go:46-64— confirmedParseDSN()performs no host validationprovider/llamaswap/llamaswap.go:64,85-97— confirmedWithBaseURLand provider constructionRegisterScheme,schemes[ProviderLlamaSwapTLS]— confirmed unique registrationbuiltin.go:20-29— confirmed constant definitionConclusion: The PR is a straightforward scheme addition with no new security properties. It does not introduce injection, SSRF, credential leakage, or any other vulnerability beyond what already existed in the
llama-swap://scheme (and all other schemes). Both schemes share identical code paths through unvalidated input — but that's pre-existing and shared across all provider factories, not introduced by this change.🎯 Correctness — No material issues found
No material issues found.
Findings:
README.md:170-173): Both example DSN lines useLLM_LS, which in practice would conflict — the second would overwrite the first. The TLS example should use a distinct var name likeLLM_LSTto match the test and make sense as parallel examples. This is a documentation correctness issue: readers copying both lines into the same env will get unexpected behavior. Suggested fix: change line 172's prefix fromLLM_LS=toLLM_LST=(or another distinct name).🧯 Error handling & edge cases — No material issues found
No material issues found
llamaSwapSchemeconsistently returns(llm.Provider, nil), mirroring the existingllama-swapscheme and matching the pre-existing contract thatllamaswap.New()never errors on construction (errors surface at request time). No new unhappy paths or swallowed failures were introduced. (builtin.go:89-97)llamaSwapOpts(extra ...Option)closure safely handles variadic expansion and the optionalhttpClientappend. The backing slice is fresh per call, eliminating any risk of shared-slice aliasing bugs across concurrent factory invocations. (builtin.go:83-88)dsn.Hostor missing token produce"https://"+ empty host via string concat. This matches the pre-existing behavior forllama-swap://(which produces"http://"+ empty host) and defers validation to request time, avoiding early panics. (env.go:36,provider/llamaswap/llamaswap.go:65)deferor rollback. Registry map insertion is atomic and safe.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 11m 45s
🪰 Gadfly review —
glm-5.2:cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
Verdict: No material issues found
llama-swapsfactory reuses the samedsn.Host/dsn.Tokenhandling as every other built-in scheme (e.g.openaiusesdsn.BaseURL()="https://"+dsn.Host), so it introduces no new input-validation or injection surface. The base URL is composed asurlScheme+"://"+dsn.Hostand consumed viahttp.NewRequestWithContext(ctx, method, p.baseURL+path, ...)inprovider/llamaswap/llamaswap.go:200;dsn.Hostis operator-supplied env config (not untrusted request input), so this is not an SSRF vector."https"prefix passed intollamaSwapScheme("https")(builtin.go:100); there is no path by which allama-swaps://DSN can degrade to a plaintexthttp://base URL. The bearer token is forwarded identically to the existingllama-swappath (WithToken(dsn.Token)→Authorization: Bearer …atllamaswap.go:207-209), so credentials are not leaked over an unencrypted transport when the TLS scheme is selected.ProviderLlamaSwapTLSis intentionally scheme-only (nor.providers[ProviderLlamaSwapTLS]registration), so a barellama-swapsprovider name won't resolve to a no-URL built-in that could silently hit a default host — this is the safer choice and is consistent with the PR's stated design. Verified by readingbuiltin.go:98-100.Nothing in the security lens is materially wrong with this change.
🎯 Correctness — No material issues found
VERDICT: No material issues found
builtin.go:89-100: the sharedllamaSwapScheme(urlScheme)factory buildsurlScheme+"://"+dsn.Hostcorrectly for both schemes. Forllama-swaps://tok@swap.example.com,ParseDSNyieldsHost="swap.example.com"(verified inenv.go:46-64), so the base URL ishttps://swap.example.com— matching the test assertion and the documented TLS behavior.WithBaseURL(provider/llamaswap/llamaswap.go:64-66) trims only trailing slashes and preserves any/path, sodsn.Hostpath handling is identical to the existingllama-swaphttp path. No divergence introduced by the https twin.ProviderLlamaSwapTLS = "llama-swaps"is registered only as a scheme factory (r.schemes), not as ar.providersentry (builtin.go:98-100), so it correctly has no no-DSN built-in — consistent with the PR intent and ADR-0015 wording.DSN.BaseURL()https-always helper (env.go:41) is intentionally bypassed for both llama-swap schemes via the expliciturlSchemeparameter, so there is no double-prefix or scheme mismatch risk.registry.go:254-283) handlesllama-swapsidentically to other schemes viaproviderFromDSN→r.schemes[dsn.Scheme]; no special-casing needed and none missing.Nothing in the correctness lens is materially wrong.
🧯 Error handling & edge cases — No material issues found
VERDICT: No material issues found
llama-swapsscheme factory that mirrors the existingllama-swapone, differing only by the URL scheme string ("https"vs"http"). I verifiedbuiltin.go:89-100— the factory closure correctly threadsurlSchemeintoWithBaseURL(urlScheme+"://"+dsn.Host), and both schemes route tollamaswap.New, which never fails at construction (confirmed atprovider/llamaswap/llamaswap.go:82-91), so the factory'serrorreturn is alwaysnilhere, consistent with the existingllama-swappath.llama-swapsis scheme-only (nor.providers[ProviderLlamaSwapTLS]registration — verified via grep, onlyr.schemes[ProviderLlamaSwapTLS]exists atbuiltin.go:100). The provider is only ever built from a DSN, andParseDSN(env.go:46-63) already rejects an empty host withErrInvalidDSNbefore the factory is reached, so the factory never seesdsn.Host == ""to produce a malformedhttps://base URL. If someone constructs viallamaswap.Newdirectly with no base URL, the existing request-time guard atllamaswap.go:103-105/189-191returns a clear error — unchanged behavior, no new unhandled path introduced.llamaswap.New(...)result directly (which is non-nil and error-free here), andproviderFromDSN(env.go:104-120) already wraps any factory error via thescheme %q: %wpath. The diff adds nodefer, cleanup, or rollback concern (factory returns a stateless provider).r.schemes, a simple map assignment, with no iteration or length-dependent logic.Outside my lens: the package doc comment at
provider/llamaswap/llamaswap.go:20-22still describes only the singlellama-swapscheme and says "a TLS-fronted instance can use the openai:// scheme for chat instead" — now stale givenllama-swapsexists — but that's a docs-consistency issue, not an error-handling one.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 49s
🪰 Gadfly review —
glm-5.1:cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
VERDICT: No material issues found
The change is narrow and security-sound:
llamaSwapScheme("http")andllamaSwapScheme("https")hard-code the scheme string;dsn.Hostis appended after://with no interpolation of user-controlled scheme data, so there is no scheme-injection or SSRF risk.llama-swapsbuilds anhttps://base URL with the defaulthttp.Client{}(noInsecureSkipVerify, no customTLSClientConfig), so certificate verification follows the standard, secure path — consistent with every other scheme inbuiltin.go.dsn.Tokenflows toWithToken, which sets theAuthorization: Bearerheader (line 208 ofllamaswap.go). Underllama-swaps://this is sent over TLS; underllama-swap://it remains plaintext HTTP, but that is pre-existing behavior the PR improves by offering the TLS twin.BaseURL()returns the host URL only.llama-swapsregisters only a scheme factory (no default built-in provider), so it cannot be used without an explicitLLM_*DSN — no risk of silently falling back to an unconfigured provider.🎯 Correctness — No material issues found
VERDICT: No material issues found
The change is a narrow, well-structured addition of a
llama-swapsDSN scheme that mirrors thellama-swaphttp scheme with an https base URL. I verified the following:Scheme factory correctness:
llamaSwapScheme("https")producesurlScheme+"://"+dsn.Host→"https://swap.example.com"for the test DSN, confirmed by theTestLlamaSwapsSchemetest. Thellama-swapscheme still correctly produces"http://"URLs. No off-by-one or scheme-construction bug.No accidental default provider:
llama-swapsis intentionally registered only as a scheme (r.schemes), not as a default built-in (r.providers). This matches the documented design ("scheme-only, no default built-in provider name") and the ADR. A user who referencesllama-swapswithout a DSN will get a provider-not-found, same as any unregistered name — not a silent wrong-behavior bug.DSN parsing:
ParseDSN("llama-swaps://tok@swap.example.com")correctly splits on://to yield{Scheme: "llama-swaps", Token: "tok", Host: "swap.example.com"}, whichproviderFromDSNthen routes to the"llama-swaps"scheme factory. Verified by readingenv.go.No stale references: The package doc comment in
llamaswap/llamaswap.go:20-22still mentions onlyllama-swap://and suggests usingopenai://for TLS instances. This is now slightly stale (sincellama-swaps://exists as an alternative), but this is a documentation clarity issue, not a correctness bug — the old advice still works.No logic bugs, incorrect conversions, or semantic errors found.
🧯 Error handling & edge cases — No material issues found
VERDICT: No material issues found
llamaSwapSchemereturns the(llm.Provider, error)tuple fromllamaswap.New, which per its docs never errors at construction time — missing base URL surfaces at request time viaProvider.Model'sp.baseURL == ""guard (verified atprovider/llamaswap/llamaswap.go:102-104). Thenilerror return from the factory is therefore correct, not swallowed.ParseDSN(atenv.go:60) already rejectshost == ""withErrInvalidDSN, sollama-swaps://orllama-swaps://@correctly fails before reaching the scheme factory.llama-swaps: This is intentional (scheme-only, documented in ADR-0015 and theProviderLlamaSwapTLScomment). Without a DSN,Provider("llama-swaps")returns(nil, false), whichParsewill surface asErrUnknownProvider— consistent with how unregistered providers behave.urlSchemeis a parameter tollamaSwapScheme, not a loop variable, so no stale-capture bug.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 4s
🪰 Gadfly review —
minimax-m3:cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
Now I have a complete picture. Let me reason through the security lens for this PR.
What changes from a security perspective:
llama-swapsconstructshttps://<host>and passes it throughWithBaseURL/WithTokentollamaswap.New.Authorization: Bearer <token>(lines 207–209 inllamaswap.go).&http.Client{}(no TLS pinning, no customTransport).ParseDSNalready does.Trace of the only new tainted input: the DSN
hostis concatenated into a URL viaurlScheme + "://" + dsn.Host.ParseDSNonly trims trailing/; it does not validate that the host contains no whitespace, control chars, scheme, or?#/. But that's pre-existing behaviour shared with every other scheme (foreman,ollama,openai,anthropic,google,gemini) —llama-swapsis no worse than its siblings. (Strictly out-of-scope for this PR; pre-existing for all schemes, would belong to a "input validation" cleanup PR across the whole registry.)Other security checks:
token@) is documented as the credential.llama-swappackage's own path-building (/api/models/unload) is unchanged.LLM_*env var). No change in attack surface vs. the existingllama-swap://scheme. The factory passes the host straight to the existing HTTP client; nothing new is fetched, redirected-to, or parsed in a new way.json.NewDecoder(...).Decode(out)on responses is unchanged; body bounded bymaxResponseBytes = 64 << 20already.p.token, only sent asAuthorization: Bearer ...over the wire — no new logging, no new surface.InsecureSkipVerifyoverride. Thellama-swapsfactory goes through the standard Gohttp.Client, which uses the system trust store for TLS validation by default.llama-swapsis the explicit way to use TLS with a llama-swap instance, so an operator who needs TLS now has a first-class scheme rather than being nudged atopenai://.Verified by reading:
builtin.golines 22–28, 77–100 — scheme registration and factory closure construction.env.golines 27–63, 104–119 — DSN parsing andproviderFromDSNdispatch.provider/llamaswap/llamaswap.golines 49–91, 188–227 —Providerstruct,WithBaseURL/WithToken/New, anddoJSON(auth header, response cap, no insecure TLS overrides).registry.goline 51 —SchemeFactorysignature matches whatllamaSwapSchemereturns.InsecureSkipVerify/TLSClientConfig/MinVersionanywhere in the package.Verdict: No material issues found in the security lens.
The change is a tiny wiring addition (one factory closure parameterised by
urlScheme, one extra entry inr.schemes) that reuses the same token-handling, HTTP client, JSON decoding, andAuthorizationheader logic that the existingllama-swap://scheme already exercises. No new authentication, parsing, transport, or deserialization paths are introduced; the only behavioural delta is the URL prefix, which is the entire point of the feature.🎯 Correctness — No material issues found
VERDICT: No material issues found
Verified by reading
builtin.go:77-100,env.go:27-64,provider/llamaswap/llamaswap.go:82-97, andbuiltin_llamaswap_test.go:54-74:env.go:46-64) forllama-swaps://tok@swap.example.comyieldsScheme=llama-swaps,Token=tok,Host=swap.example.com. The factory (builtin.go:89-97) buildshttps://swap.example.comviaurlScheme + "://" + dsn.Host, which is exactly whatTestLlamaSwapsSchemeasserts. ✓llamaSwapSchemeis a pure factory-of-factory;urlSchemeis a string captured by value, sollamaSwapScheme("http")andllamaSwapScheme("https")produce independent factories with no aliasing risk.Newnever errors (provider/llamaswap/llamaswap.go:85-91: "Construction never fails"), so the(llm.Provider, error)return is functionally(provider, nil), matching every other scheme factory in the file — no asymmetry introduced.dsn.Hostmay carry/path(the DSN grammar isscheme://[token@]host[/path]); bothllama-swapandllama-swapsfactories passdsn.Hostthrough unchanged, so a hypotheticalllama-swaps://tok@host/proxywould correctly yieldhttps://host/proxy. No regression vs. the existing http variant.builtin.go:98): onlyProviderLlamaSwapis registered, notProviderLlamaSwapTLS. This matches the ADR-0015 contract update ("llama-swapsis a scheme only") and the PR description.token=""handling: identical to the existingllama-swapfactory — the openai-compat chat provider substitutes"no-key"for an empty token (seeprovider/llamaswap/llamaswap.go:114-118), so behavior is consistent across both schemes.The change is a small, symmetric extension of an existing factory pattern with no logic regression. Nothing in the correctness lens is materially wrong.
🧯 Error handling & edge cases — No material issues found
VERDICT: No material issues found
I reviewed
builtin.go, the new test,env.go(DSN parsing),registry.go(lazy/eager provider resolution), andprovider/llamaswap/llamaswap.go(the underlying provider) to verify how the newllama-swapsfactory interacts with the existing DSN and provider plumbing.Through the error-handling & edge-cases lens, the diff is clean:
builtin.go:89-97) only concatenate a known constant ("http"/"https") withdsn.Hostand pass tollamaswap.New.llamaswap.Newis documented (provider/llamaswap/llamaswap.go:82-91) to never fail, so theerrorreturn is alwaysnil— consistent with theSchemeFactorycontract and not a swallowed-error smell.ParseDSN(env.go:60-62) rejects an empty host withErrInvalidDSNbefore the factory is called, so the factory never sees"".ParseDSNtrims a trailing/(env.go:59), andWithBaseURLtrims again (provider/llamaswap/llamaswap.go:64-66). Port is part ofdsn.Host, sollama-swaps://tok@host:8443yieldshttps://host:8443.llama-swaps://host) leavesdsn.Token == "", andWithToken("")simply means noAuthorizationheader — same path as the existingllama-swapscheme.ProviderLlamaSwap, notProviderLlamaSwapTLS(builtin.go:98 vs :100). That's deliberate per the ADR/doc updates and avoids registering an unusable no-URL built-in.registry.go:266-269) goes throughproviderFromDSN, which uses the samer.schemeslookup and the same factory — no separate edge case introduced.Nothing material in my lane. (Aside: the DSN parser is case-sensitive on the scheme, so
LLAMA-SWAPS://…would not match — but that is pre-existing behavior ofParseDSN, not introduced by this PR, and is outside the strict scope of error/edge handling.)Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 48s
🪰 Gadfly review —
kimi-k2.7-code:cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
No material issues found
llama-swaps://scheme that builds anhttps://base URL, alongside the pre-existingllama-swap://(http, local-first). This is a security-positive addition: it gives TLS-fronted instances a first-class DSN instead of pushing them onto the genericopenai://scheme where llama-swap-specific management/image endpoints were unavailable.llamaswap.WithTokeninto the existingAuthorization: Bearer <token>path, and only when non-empty. No new logging or serialization of the token was introduced.dsn.Hoststring concatenation pattern thatllama-swap://already used ("http://"+dsn.Host).llama-swaps://simply substitutes the hardcoded"https"scheme, so no new injection surface or SSRF vector is introduced by this PR.InsecureSkipVerifyis added; the registry’s injected or defaulthttp.Clientis used, so normal certificate validation applies forhttps.r.schemes[dsn.Scheme];llama-swapscannot be confused withllama-swapat lookup time.🎯 Correctness — No material issues found
No material issues found.
I verified the implementation against the actual code:
builtin.go:89-100: the newllama-swapsscheme uses the same factory closure asllama-swap, only swapping"http"for"https"; the constructed base URL isurlScheme + "://" + dsn.Host. For the TLS variant this correctly yieldshttps://host[/path].env.go:41: the generalDSN.BaseURL()ishttps://always, but the llama-swap factory deliberately bypasses it and usesdsn.Hostdirectly with an explicit scheme, so both http and https variants are possible and explicit. That matches the PR's stated design.provider/llamaswap/llamaswap.go:64-97:WithBaseURLtrims a trailing slash and exposes it viaBaseURL(); the chat client appends/v1internally, so the registered base URL stays athttps://hostas tested.builtin_llamaswap_test.go:56-73: the new test asserts exactlyhttps://swap.example.com, which I confirmed corresponds to the factory behavior.ProviderLlamaSwap(llama-swap), not under the scheme-only TLS variant, consistent with the ADR update.The change is semantically correct and internally consistent. No logic bug or domain-correctness issue found through the Correctness lens.
🧯 Error handling & edge cases — No material issues found
No material issues found
Reviewed through the error-handling & edge-cases lens. The change is clean:
llamaSwapSchemereturns aSchemeFactorythat still delegates provider-construction errors fromllamaswap.New(which never fails) and the DSN lookup path inproviderFromDSNwraps them normally (builtin.go:89-97,env.go:115-118).r.schemes[ProviderLlamaSwapTLS]is registered alongside the http twin, soLoadEnv/providerForwill surfaceErrUnknownProviderfor the new scheme only if a user registers it externally and then unregisters it — same as any other scheme. No registration gap.llama-swapstill errors on use;llama-swapsis correctly scheme-only, so there is no accidental default provider with an empty/missing URL to mishandle.ParseDSNrejects missing hosts and missing://, and the new test uses a valid DSN. No nil/null or empty-collection edge cases are introduced.urlScheme + "://" + dsn.Hostconstruction is bounded by prior validation; no integer/buffer concerns.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 20s
🪰 Gadfly review —
deepseek-v4-pro:cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
No material issues found
The change is a straightforward addition of an HTTPS variant (
llama-swaps://) alongside the existing HTTP scheme (llama-swap://), sharing the same factory, token handling, and URL construction. From a security lens:Token in transit: The
llama-swapsscheme sends the bearer token over TLS (encrypted), which is a net improvement over the existingllama-swapHTTP scheme where the token travels in cleartext. The defaulthttp.Clientuses Go's standard TLS certificate verification — no insecure skip-verify defaults are introduced.No new injection surface: The URL construction (
urlScheme+"://"+dsn.Hostatbuiltin.go:93) is identical to the pre-existingllama-swappattern. Thedsn.Hostvalue comes from the sameParseDSNparser with the same (lack of) host sanitization — any host-injection concerns (e.g., embedding#to redirect the effective host) are pre-existing and not worsened by this PR. The DSN source is environment variables, which in practice requires process-level access.No built-in provider for the TLS scheme:
ProviderLlamaSwapTLSis registered only as a scheme factory (r.schemes), not as a default provider (r.providers). This meansllama-swapscannot be used bare (without a DSN), eliminating any risk of a no-URL default silently hitting a wrong host over TLS.Token handling unchanged: The token flows through
llamaswap.WithToken(dsn.Token)→p.token→Authorization: Bearerheader, exactly as in the existing scheme. No logging, no leakage, no new code paths for the credential.🎯 Correctness — No material issues found
No material issues found
The change is straightforward and correct:
llamaSwapScheme("http")andllamaSwapScheme("https")each capture the right scheme string in a closure, and the factory correctly buildsurlScheme+"://"+dsn.Host. Verified by readingbuiltin.go:89-100andenv.go:46-63—dsn.Hostis the rawhost[:port][/path]with no scheme prefix, so prependinghttp://orhttps://is exactly right.The
llama-swapsscheme is intentionally scheme-only (nor.providers[ProviderLlamaSwapTLS]entry), matching the ADR and PR description. Verified by readingbuiltin.go:98-100— onlyr.schemes[ProviderLlamaSwapTLS]is set, notr.providers.The test
TestLlamaSwapsSchemecorrectly assertslp.BaseURL() == "https://swap.example.com", confirming the https construction. Verified by readingbuiltin_llamaswap_test.go:56-73.No path-duplication regression: the existing
llama-swapscheme already had the samescheme+"://"+dsn.Hostpattern (previously hardcoded"http://"+dsn.Host), so the refactor to a parameterized closure is behavior-preserving for the http case. Verified by comparing the old inline factory (removed in the diff) with the newllamaSwapScheme("http")— both produce"http://"+dsn.Host.🧯 Error handling & edge cases — No material issues found
Verdict: No material issues found
The change is straightforward and follows existing patterns faithfully. After verifying the full code paths:
ParseDSNalready rejects empty hosts (env.go:60-62), sodsn.Hostis guaranteed non-empty before the factory runs. No nil/empty injection into the URL builder.nilerror, matchingllamaswap.New's contract ("Construction never fails" —llamaswap.go:85-91). This is consistent with the existingllama-swapscheme factory and all other built-in factories.llama-swapsis scheme-only (nor.providers[ProviderLlamaSwapTLS]entry). Using it as a bare provider name in a spec falls through to lazyLLM_LLAMA_SWAPSenv resolution, then to a clearErrUnknownProvider— the same path every other unregistered name takes. No panic, no silent wrong behavior.httpClientis handled by thellamaSwapOptsclosure (guardedif httpClient != nil) and again byllamaswap.WithHTTPClient(guardedif c != nil), withllamaswap.Newproviding a default&http.Client{}. Same pattern as all other providers inregisterBuiltins.WithToken("")→p.token = ""→chatProvider()substitutes"no-key"anddoJSONomits theAuthorizationheader. This is pre-existing behavior, unchanged by the new scheme.dsn.Hostcompose correctly:https://host:portandhttps://host/pathboth work, and the downstreamchatProvider()anddoJSONappend/v1and management paths on top without double-slash issues (base URL isTrimRight("/")'d byWithBaseURL).No swallowed errors, missing cleanup, panic-on-bad-input, or boundary condition issues introduced by this diff.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 34s
🪰 Gadfly review —
nemotron-3-super:cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
No material issues found
🎯 Correctness — No material issues found
No material issues found.
🧯 Error handling & edge cases — No material issues found
No material issues found
The changes introduce a new DSN scheme
llama-swapsfor TLS-fronted llama-swap instances, mirroring the existingllama-swapscheme but using https instead of http. After verifying the changes:Error handling is consistent with the existing
llama-swapscheme:ParseDSN(which returns errors for missing host or invalid format)Edge cases verified:
llamaswap.WithToken("")ParseDSNreturning errorproviderFromDSNTesting:
TestLlamaSwapsSchemeverifies https base URL constructionTestLlamaSwapSchemeunchanged and passesThe implementation correctly mirrors the redis/rediss scheme pattern with explicit http/https selection via scheme name, maintaining consistency with existing error handling approaches. No material issues found in error handling or edge cases for this lens.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 5m 23s
🪰 Gadfly review —
gpt-oss:120b-cloud(ollama-cloud)Verdict: Minor issues — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
Verdict: No material issues found
llama-swaps://scheme only affects how the base URL is constructed (https://instead ofhttp://).ParseDSNimplementation, which validates scheme, token, and host, and strips trailing slashes.llamaSwapScheme) receive the DSN struct and set the base URL using the supplied scheme string; no untrusted data is interpolated into command lines, file paths, or SQL statements.llamaswapprovider, which already handles bearer‑token authentication over TLS (or HTTP for local‑first).llama-swapscheme remains explicitly HTTP‑only for local use.Thus, from a security perspective the modifications do not create authentication/authorization gaps, injection vectors, credential leakage, or insecure defaults.
🎯 Correctness — No material issues found
Verdict: No material issues found
🧯 Error handling & edge cases — Minor issues
Verdict: Minor issues
llama-swapandllama-swapsforwarddsn.Tokendirectly tollamaswap.WithTokenwithout checking whether the token string is empty. An empty token could lead to unauthenticated requests and subsequent API errors at runtime.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 1m 29s
🪰 Gadfly review —
qwen3-coder:480b-cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
No material issues found.
The changes introduce a new
llama-swapsDSN scheme for TLS-fronted llama-swap instances, correctly building anhttps://base URL. The implementation is secure and follows the intended design:llama-swap(HTTP) andllama-swaps(HTTPS) schemes makes the security model explicit and prevents accidental insecure connections.llama-swapsscheme correctly builds an HTTPS base URL.No security vulnerabilities or issues were identified in the implementation.
🎯 Correctness — No material issues found
No material issues found.
🧯 Error handling & edge cases — No material issues found
No material issues found.
The changes introduce a new DSN scheme
llama-swapsfor TLS-fronted llama-swap instances, which correctly builds anhttps://base URL. The implementation:ProviderLlamaSwapTLS = "llama-swaps"constantllama-swap(http) andllama-swaps(https) schemesAll error handling paths appear correct:
(llm.Provider, error)but always returnsnilfor error - this is consistent with other scheme factories in the fileThe change is well-contained and properly tested. No issues in error handling or edge cases found.
Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 52s
🪰 Gadfly review —
gemma4:cloud(ollama-cloud)Verdict: No material issues found — 3 reviewers: security, correctness, error-handling
🔒 Security — No material issues found
Verdict: No material issues found
The change introduces a new DSN scheme
llama-swapsto support HTTPS (TLS) forllama-swapproviders, mirroring theredis/redissconvention. I have verified the following:llamaSwapSchemefactory uses theDSNstruct parsed byParseDSN. TheDSN.Hostis used directly in the URL construction (urlScheme + "://" + dsn.Host). Since this is used for internal provider configuration via environment variables, it is not exposed to untrusted user input in a way that would lead to injection.openai://scheme to a concretellama-swaps://scheme to regain provider-specific management methods. The implementation correctly mapsllama-swapstohttps://andllama-swaptohttp://.dsn.Tokenis passed tollamaswap.WithToken, which is the standard way tokens are handled across other providers in this codebase (e.g.,openai,anthropic).builtin.goandregistry.goto ensure the scheme factory is correctly registered and invoked. The logic is consistent with how other schemes (likeollamaoropenai) are implemented.No security gaps, injection vectors, or credential leakages were identified.
🎯 Correctness — No material issues found
Verdict: No material issues found
🧯 Error handling & edge cases — No material issues found
No material issues found.
I reviewed the change through the lens of error handling and edge cases. The implementation of the
llama-swapsscheme is a straightforward extension of the existingllama-swaplogic.urlScheme + "://" + dsn.Hostfor base URL construction is consistent with the previousllama-swapimplementation. Since theDSNstruct is populated by the registry's parser,dsn.Hostis guaranteed to be present if the scheme is recognized.SchemeFactoryreturns(llm.Provider, error). In this case,llamaswap.Newis called, which returns a provider without an error (consistent with other built-in factories in the same file likeopenaioranthropic).llamaswap.WithToken(dsn.Token).httpsforllama-swaps, the provider will correctly use the HTTPS protocol.Verified by reading
builtin.goand reviewing the provided testTestLlamaSwapsSchemeinbuiltin_llamaswap_test.go.Automated adversarial review by Gadfly. Advisory only — does not block merge. · ⏱️ reviewed in 30s