Skip to content

feat(requestrouter): let request routers say they need no API key or base URL - #43

Merged
Quick104 merged 3 commits into
Silo-Server:mainfrom
blurbery:feat/request-router-optional-credentials
Oct 15, 2026
Merged

Quick104 merged 3 commits into
Silo-Server:mainfrom
blurbery:feat/request-router-optional-credentials

Conversation

@blurbery

@blurbery blurbery commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Closes #42
Related issue: Silo-Server/silo-server#2380

A request-router plugin can't say it works without an API key or a base URL. Silo skips every router connection whose key is empty, and its admin form won't save a server without both. A router that talks to a local tool, or authenticates some other way, never receives a request unless the admin types in a dummy key.

Approach

RequestRouterDescriptor gets two plain booleans, api_key_optional = 4 and base_url_optional = 5, read from the manifest like the existing flags.

silo-server#2380 suggested requires_api_key and requires_base_url, defaulting to true. A proto3 bool can't default to true, and this descriptor's contract is that an absent descriptor means every flag is false. Naming the flags the other way round keeps that contract. Unset flags, an absent descriptor, a host on an older SDK, and code that reads the generated getters all mean "needs both", which is how every router is treated today. An optional bool with presence would have needed a nil-means-true helper, and a host that forgot it would treat every existing router as key-less.

The proto comments, a new "API key and base URL" section in the README, and docs/compatibility.md cover:

  • what a host does with each flag;
  • what older hosts do;
  • that hosts read the flags from the capability metadata stored when a plugin is installed or updated.

The README also notes that httpclient still refuses an empty key or URL, so a key-less router needs its own client.

Release impact: additive, so a minor release. docs/compatibility.md says "added in v0.26.0", following the README's release rules.

Downstream: silo-server reads the flags for routing, status checks, the connection test and the admin form in Silo-Server/silo-server#2439. That PR builds on this one and stays a draft until a release with these fields is tagged. No first-party router needs a change, because the Sonarr/Radarr and Seerr plugins need both.

Validation

  • go test for ./pkg/pluginsdk/manifest/, ./pkg/pluginsdk/convert/ and ./pkg/pluginproto/silo/plugin/v1/: pass. The new tests cover:
    • loading both flags from a manifest;
    • manifests without them, with other flags or with no descriptor;
    • the stored-capability round trip for each flag and the stored JSON field names;
    • unchanged stored metadata for a plugin without the flags;
    • decoding metadata stored before the flags existed.
  • go vet on those packages: clean. go build of all four examples: pass.
  • Regenerated with buf generate using protoc-gen-go v1.36.11 and protoc-gen-go-grpc v1.6.1. Only request_router.pb.go changes. protoc isn't installed here, so I ran buf generate directly rather than make proto; buf compiles the protos itself.
  • buf lint: no new findings, the same 70 as v0.25.0. buf breaking against v0.25.0: pass.
  • gofmt -l on the touched packages: clean. Across the repo it lists pkg/pluginsdk/runtime/scan_source_test.go, which this PR doesn't touch and which main already lists.
  • The silo-server change builds and passes its tests against this branch through a local go.work.
  • Not run locally: go test ./... across the whole repo. CI runs it.

Risks

  • Existing plugins and hosts: no change. Unset flags add no keys to stored metadata and decode as before.
  • A plugin that sets api_key_optional is still skipped by a host that predates it, so on such a host it works only with a key entered.
  • Silo reads a bare plugin binary's manifest strictly, so a Silo version built on an older SDK refuses to install a binary that declares the flags. An archive installs. The docs say so, and A plugin whose manifest has fields the server doesn't know can't be uploaded as a binary or started silo-server#2436 tracks the fix.
  • Hosts read the flags from metadata stored when the plugin was installed or updated. A plugin stored by a host on an older SDK lacks them until it is next updated.
  • The two JSON names become part of the manifest contract once tagged.

Checklist

  • I read and can explain the complete diff.
  • This pull request addresses one concern.

AI Disclosure

  • Harness: Claude Code (Claude desktop app)

  • Tool(s): Claude Code, Claude Code subagents for exploration and review, GitHub CLI, buf

  • Model(s): claude-opus-5-5

  • Involvement: AI-assisted with Claude Opus. I directed the task and designed the work.

  • Adversarial review: a separate Claude Code subagent reviewed the diff. It covered the proto contract, the generated code, buf lint and breaking checks, and how manifests are loaded, stored and decoded. It found three problems in the docs, which also had test gaps:

    • sentences that overstated what hosts enforce;
    • advice to reinstall a plugin, which gives it a new installation ID and unbinds its servers;
    • no mention that httpclient refuses an empty key or URL.

    All of these are fixed in 8336f80. Testing the flags live on a Silo dev build then showed the strict binary-manifest parse above, and 076eab6 documents it.

…base URL

Add api_key_optional and base_url_optional to RequestRouterDescriptor. A
router that sets api_key_optional receives connections whose api_key is
empty; one that sets base_url_optional can be saved and tested without a
base URL. Unset, or an absent descriptor, keeps today's behaviour: a
connection needs both.

Closes Silo-Server#42
Say that the admin form, not the API, refuses a server without a key or URL,
that only Fulfill, CheckStatus and ListConfigOptions skip a connection
without a key, and that httpclient needs both. Update the plugin rather than
reinstall it, so its servers stay bound. Cover base_url_optional alone and
unchanged metadata for plugins without the flags.
@silo-kody

silo-kody Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Silo Kody — review complete

Review finished. Check the inline comments for findings and verify each suggestion against the code and tests.

Reviewing changes in Silo
  • Include the related issue, expected behavior, and validation steps in the PR description.
  • For API changes, describe the effect on Apple and Android clients and Jellyfin compatibility.
  • For plugin changes, identify the affected SDK contract, plugin, and catalog entry.
  • Follow this repository's AGENTS.md and CONTRIBUTING.md.
  • Request another review with @kody start-review in a PR comment.
  • React with 👍 or 👎 to give feedback on individual suggestions.
Review settings
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ❌

@coderabbitai

coderabbitai Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cb2a446f-fc1b-427d-959f-dcba78eba648
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@silo-triage silo-triage Bot added enhancement New feature or request go Pull requests that update go code triaged High-confidence review completed; does not mean fixed, validated, or accepted for release. labels Oct 14, 2026
… the flags

Silo reads a bare plugin binary's manifest strictly, so a host that predates
the flags refuses such a binary; an archive installs. Tracked in
Silo-Server/silo-server#2436.
@silo-kody

silo-kody Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

Silo Kody — review complete

Review finished. Check the inline comments for findings and verify each suggestion against the code and tests.

Reviewing changes in Silo
  • Include the related issue, expected behavior, and validation steps in the PR description.
  • For API changes, describe the effect on Apple and Android clients and Jellyfin compatibility.
  • For plugin changes, identify the affected SDK contract, plugin, and catalog entry.
  • Follow this repository's AGENTS.md and CONTRIBUTING.md.
  • Request another review with @kody start-review in a PR comment.
  • React with 👍 or 👎 to give feedback on individual suggestions.
Review settings
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug ✅
Performance ✅
Security ✅
Business Logic ❌
⚠️ 2 Kody Rule(s) were not evaluated

These rules declare that they need repository context beyond this diff, and the review could not retrieve it, so they were not judged on this pull request:

  • Share optional authentication service resolution across interface types
  • Find the last complete-line boundary with bounded memory

@Quick104
Quick104 merged commit 6d71747 into Silo-Server:main Oct 15, 2026
4 checks passed
Quick104 added a commit to Silo-Server/silo-server that referenced this pull request Oct 15, 2026
* chore(api): drop breaking-change approvals consumed by #2413

The getBrandingCapabilities and getThemeOverrides approvals belong to the
change #2413 merged, so the contract check reports them as stale against
the new base for any change to the v2 contract.

* fix(requests): send requests to routers that need no API key

A request_router plugin can now declare api_key_optional and
base_url_optional (silo-plugin-sdk#42). Routing, status checks, the download
refresh, the route preview and the connection test use a connection without
a key when its plugin declares api_key_optional, through one check that
reads the declaration only for a connection without a key. A server saved
without a key can change its URL without one; a saved key still has to be
typed again.

The v2 plugin installation view carries both flags on a request_router.v1
capability, and the admin form saves and tests a server without a key or
URL when its plugin needs neither, and stops showing it as needing setup.

Closes #2380

* chore(deps): build against silo-plugin-sdk#43 until it is released

Temporary: replace the SDK with the commit of Silo-Server/silo-plugin-sdk#43
so CI can build this branch. Replace this commit with a bump to the release
that carries api_key_optional and base_url_optional before merging.

* style(plugins): keep Silo imports in their own group in the plugin handlers

* fix(requests): keep progress, saved keys and cleared URLs right for key-less routers

- The download refresh keeps a key-less target's progress when its router's
  declaration can't be read, instead of clearing it: statusCheckable now
  returns the read error.
- The save checks again, under the row lock, that a blank key keeps the
  saved key only for the address it was saved for, so a key or address saved
  by another admin between validation and the write is never paired with a
  different address.
- A blank URL on a saved server is tested and validated as blank when its
  router declares base_url_optional, since that is what the save stores.

* fix(requests): count a cleared URL as a change of address for a saved key

For a router that declares base_url_optional, clearing a saved server's URL
pointed the saved key at a different destination without asking for it
again. A blank address is now a different address everywhere the rule
applies: the save asks for the key again, the locked write refuses to keep
it, and the connection test goes without it.

* fix(requests): test the saved address when a probe leaves base_url out

The v2 options body lets a client leave base_url out to test a saved
server. For a router that declares base_url_optional, that was treated
like a cleared URL and tested without an address. Only a base_url sent
blank on purpose is a clear now; the request carries that through
Integration.BaseURLCleared, and an omitted URL tests the saved one.

* fix(requests): validate and probe the blank base URL a save stores

A save with a blank URL for a server saved without a key validated the
saved address but stored a blank one. With api_key_optional such a server
takes requests, so routing would send the plugin an empty URL. The save now
validates the URL it is given; a blank URL still stands for the saved
address in a connection test.

A v2 base_url of spaces also reached the plugin as sent when the router
takes no URL, while the save stored it blank. adminRequestBaseURL now
returns "" for any blank address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(deps): build against silo-plugin-sdk v0.26.0

silo-plugin-sdk#43 is released in v0.26.0, so the temporary replace that
pointed the SDK at the change's fork commit goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Quick104 <31828688+Quick104@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request go Pull requests that update go code triaged High-confidence review completed; does not mean fixed, validated, or accepted for release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Let request routers say they need no API key or base URL

2 participants