Repository navigation
fix(credential-sources): refuse rewritten endpoint spellings and non-dns openai hosts - #2378
Conversation
…DNS openai hosts Refuse an openai source base_url or runtime.codexModelBaseUrl with spaces or control characters, a missing // after the scheme, or an @ before the host, with the shared baseUrl and auth.baseUrl messages (finding 1292). Store the normalized endpoint the profile uses, through a configuration that validateSourceConfig may return. Require an exact DNS host name on openai sources, as bearer-token hosts do (finding 1293).
Add the 2026-10-14 breaking-change notice and move the oldest notice to the archive to stay under the word limit. Describe the stored normalized endpoint, the exact DNS host rule for openai sources, and the refused spellings.
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs real behavior proof before merge. What this changesThis PR rejects ambiguous endpoint spellings, restricts OpenShell OpenAI sources to DNS hosts, and stores normalized endpoint URLs. Example: Create an OpenShell source with base_url https://MODELS.example.test:443/api/./v1/.
Review scores
ProductKind: Bug fix · Worth it: Yes · Fix scope: Complete Merge readiness⛔ Blocked before merge - 5 items remain Keep open for maintainer triage: this is a useful endpoint-admission repair, but the previously reported lifecycle-test defect remains. Priority: P2 Before merge
Findings
Tests
Agent review detailsHow this fits togetherOCC authorizes credential-source creation and stores its nonsecret configuration; the OpenShell Credential Gateway turns that configuration into provider profiles and revision attachments, while Kubernetes Compute consumes the selected model endpoint. flowchart LR
A[Credential source request] --> B[OCC authorization]
B --> C[Endpoint validation]
C --> D[Stored source configuration]
D --> E[OpenShell provider profile]
D --> F[Kubernetes Compute]
E --> G[Sandbox credential injection]
F --> G
Technical reviewBest possible solution: Keep the shared endpoint validation and canonical storage, repair the ready-source deployment regression, and establish the credential boundary and existing-state replacement behavior. Do we have a high-confidence way to reproduce the issue? Current-main source shows parser normalization occurring before spelling checks and raw configuration being retained; the added API cases cover those inputs, but no target code was executed during this read-only review. Is this the best way to solve the issue? Shared validation and storing the configuration actually consumed by the gateway address the mismatch without rejecting deliberately supported IDN, case, port, and path normalization. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against b749f9e2b992. Merge-risk optionsMaintainer options:
Provenance checked
TestingProof path: in-process harness. SecurityNeeds attention: No concrete credential disclosure or authorization bypass was found in the reviewed diff. EvidenceWhat I checked:
Likely related people:
Review metrics
LabelsLabel changes: No label changes. Label justifications:
Rating scale6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior. WorkflowClawSweeper edits this one comment on every review. Comment HistoryReview history (1 earlier review cycle)
Reviewed October 13, 2026, 11:01 PM ET / October 14, 2026, 03:01 UTC (Revision 2). |
Check the configuration a Driver returns against the catalog fields, give the deploy-time Codex endpoint refusal the spelling message, and say in the notice that a deployment or Secret update of an existing source with a refused host or spelling fails. Note that Compute still accepts IP hosts.
Problem
Two low findings on the model endpoint settings (1292, 1293):
openaicredential sourcebase_urland Kubernetes Computeruntime.codexModelBaseUrlskipped the 10-13 save-time URL rules (fix(presets): require two slashes after an http(s) baseUrl scheme and refuse userinfo in mcp env and plugin proxies #2351, fix(presets): refuse url userinfo in every env map and any env value with a scheme #2353, fix(presets): say the // is missing when a baseUrl scheme lacks it #2375).normalizeOpenAiBaseUrlis the WHATWG parser plus its own checks, so it silently rewrotehttps://@host/v1,https://:@host/v1,https:host/v1,https:/host/v1,https:///host/v1, and values with surrounding spaces or an embedded tab, newline or NUL. The source stored the raw string, andGETechoed it, while the profile, manifest andconfig.tomlused the rewritten URL.openaisource type accepted hosts its siblingbearer-tokenand OAuth2 types refuse as "must be an exact DNS name": IP literals in every spelling the parser accepts (127.0.0.1,169.254.169.254,0x7f000001,2130706433,127.1), and labels with_or an edge-. On the OpenShell path that widened egress for the member's own Sandbox.Change
openai-endpoint.ts:normalizeOpenAiBaseUrlfirst refuses a space or control character anywhere, an http(s) scheme followed by one or no slash, three or more slashes, and an@before the host. The messages match the shared baseUrl rule (must start with https:// (the // after the scheme is missing)) and theauth.baseUrlrule (must not contain user info or an @ before the host). Both the Compute setting and the source use it.validateSourceConfigmay now return the configuration in the form the gateway uses. OCC stores, returns and registers that form, so the record,GET, and the profile agree. The other option would have refused benign spellings that Support OpenAI-compatible Codex model endpoints #913 deliberately accepts and tests (https://MODELS.example.test:443/api/./v1/, IDN hosts, a trailing slash). It would also have made members write punycode. The contract change is backward compatible: a Driver that returns nothing keeps the written config.openaisources now apply thebearer-tokenexact-DNS-name host rule, at creation (The openai base_url host must be an exact DNS name.) and at registration or attachment. An existing IP-host source fails its next deployment with the endpoint requirements message, which now names IP addresses.runtime.codexModelBaseUrlstays operator-only. Its host rule is unchanged: IP and IPv6 hosts are still accepted there.localhostand in-cluster names such askubernetes.default.svcstill pass, as they do forbearer-tokenhosts. Refusing them is a separate design question. No docs or tests show a real use of an IP endpoint;https://192.0.2.1/v1appeared only as a normalization case and is now a refusal case.Verification
tests/integration/credential-source-api.test.mjs(real Fastify app, IAM, OCC and OpenShell Driver) andtests/conformance/kubernetes-compute.test.mjs:HTTPS://,:00443, full-width letters, backslashes,/./, uppercase host,:443, trailing slash) stored and returned normalized;credential-source-occ,occ-api-security,openshell-gateway-wire,occ-api,sandbox-driver-startup,secret-api,service-api-keys,plugin-computeandkubernetes-compute(846/846 pass). Alsotsc --build, plus eslint and prettier on the touched files.@,/and:found no bypass. Its notes are applied: the returned config is checked against the catalog fields, the deploy-time Codex endpoint refusal uses the spelling message, and the notice covers deployments and Secret updates of existing sources.Risks
openaisources with an IP host and for the refused spellings; the notice gives the steps.validateSourceConfiggains an optional return value. Every in-repo Driver and test double still type-checks.