Skip to content

feat: price-aware live model routing + admin KV credential endpoint - #111

Closed
seonghobae wants to merge 8 commits into
mainfrom
feature/cost-aware-model-selection
Closed

feat: price-aware live model routing + admin KV credential endpoint#111
seonghobae wants to merge 8 commits into
mainfrom
feature/cost-aware-model-selection

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Status: bounded feature slice — Draft until the #96 security baseline integrates

This branch contains useful price-aware routing and browser-admin/KV work, but it remains incomplete and must not merge from its current protected-main base.

Exact identity and current evidence

  • protected base: main@6841b71935e0b7cb98fb52bcb4709cc5100c8d87
  • exact contributor head: 149887191cd3ec465cac140ab0e91f90e55084aa
  • Tests 31590150639: success
  • Security 31590150715: success
  • Fuzz 31590150685: success
  • SAST Semgrep 31590150599: success
  • Security Scan 31590150724: success
  • unresolved inline review threads: zero
  • qualifying independent non-author approval: absent

Exact-head workflow success proves the exercised tree only. It does not make suppression-only inherited findings, incomplete browser-session security, or an unintegrated main-based feature release-ready.

Useful implemented slice

  • --price-per-million validates a JSON model-price map at the argparse boundary and rejects booleans, negatives, NaN, infinities, and overflow-to-infinity values;
  • live routing uses price only as a tie-break after capability/domain/priority scoring;
  • /admin/api/credentials writes a validated UPPER_SNAKE_CASE credential into the existing KV registry without echoing its value;
  • the browser establishes an opaque HttpOnly, SameSite=Strict session id distinct from the raw admin bearer;
  • the opaque id is server-side, expires, supports logout/revocation, and is rejected as an API bearer;
  • frontend API requests use same-origin credentials and clear entered secret fields.

Remaining blockers

  1. The session cookie never adds Secure; there is no trusted effective-origin/TLS policy or fail-closed production rule for HTTPS deployments.
  2. State-changing admin requests have no explicit CSRF/origin verification contract beyond SameSite=Strict; reverse-proxy and same-site deployment assumptions are not validated.
  3. The number of live sessions is unbounded. Expired entries are purged only during session creation or lookup; there is no configured maximum or deterministic admission/eviction policy.
  4. Session state is process-local, but restart, multi-process, failover, and durable-backend semantics are not documented or tested.
  5. Establishment accepts the long-lived bearer in a JSON body without a complete no-store/log/audit/proxy evidence contract; tests prove response/cookie separation but not every disclosure sink required by fix(security): separate browser admin sessions from long-lived bearer credentials #116.
  6. The branch carries unrelated nosemgrep annotations for raw SQL, dynamic urllib, and unverified TLS instead of inheriting PR fix(security): pin provider egress and repair the Atheris lock #96's source-level provider/response security boundary.
  7. The provider TLS opt-out remains available in operational paths and must be reconciled with the accepted fix(security): pin provider egress and repair the Atheris lock #96 policy.
  8. Direct exact-head 100% owned production statement/branch/function/line and public-docstring release evidence, current semantic reviews, and qualifying independent approval remain separate gates.

Required integration order

Keep this PR Draft. After PR #96 reaches protected main, selectively rebuild or reconcile the unique price/KV/admin work on that exact protected result, remove suppression-only changes, add RED tests for Secure-cookie policy, CSRF/origin, bounded sessions, restart/multi-process semantics, every raw-bearer disclosure sink, and durable session behavior where selected, then regenerate all exact-head quality/security/review evidence. Merge only with zero valid unresolved findings and qualifying independent non-author approval.

Refs #116. Does not close #116 until protected integration and operational acceptance.

Summary by CodeRabbit

  • 새로운 기능

    • 관리자 화면에서 세션 인증과 KV 자격 증명을 등록할 수 있습니다.
    • HttpOnly·SameSite 쿠키 기반 관리자 세션 및 로그아웃을 지원합니다.
    • CLI에서 모델별 출력 토큰 가격을 JSON으로 설정할 수 있습니다.
    • 동등한 역량의 에이전트 선택 시 무료·저가 모델을 우선합니다.
  • 보안 개선

    • 관리자 세션 만료와 원시 토큰 재사용 방지가 적용되었습니다.
    • 가격 정보 입력값의 형식과 유효성을 엄격히 검증합니다.
  • 문서

    • 세션 인증, 자격 증명 등록, 가격 기반 라우팅 안내를 추가했습니다.

Extend the existing offline "maximize quality, minimize cost" tradeoff
(_recommend_config/optimize_orchestration) into live per-request routing:
_score_agent now takes the operator-supplied price_per_million as a
tie-break, so among agents tied on capability match + priority, the
cheaper model wins. Unpriced agents never lose the tie-break, so pools
that configure no prices are unaffected. Add --price-per-million to the
CLI so this is actually configurable outside of direct construction.

Add POST /admin/api/credentials (admin scope) so a credential such as
LITELLM_API_KEY can be registered into the KV from the admin console
frontend instead of only the register-credential CLI subcommand. This
stays inside the boundary ADR 0003 already chose: the gateway writes a
named secret into its own KV registry and does not implement Keyverse
OIDC identity itself. The value is never echoed back or exposed by any
GET endpoint.

Docs: document both in docs/architecture.md and docs/kv-credentials.md,
including how to wire an agent's credential_key to a KV-registered
LITELLM_API_KEY-style gateway credential.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

CLI는 모델별 가격을 검증하고 TaskOrchestrator에 전달합니다. 동일 역량 에이전트는 우선순위와 가격으로 선택합니다. 서버는 원시 bearer 토큰과 분리된 HttpOnly 세션 쿠키와 KV 자격 증명 등록 API를 제공합니다.

Changes

라우팅 및 관리자 보안

Layer / File(s) Summary
가격 기반 에이전트 라우팅
contextual_orchestrator/__main__.py, contextual_orchestrator/orchestrator.py, tests/test_paper_contracts.py, tests/test_price_cli_validation.py, docs/architecture.md
CLI 가격 JSON의 형식과 값 범위를 검증합니다. 동일 역량 에이전트에서 우선순위를 먼저 비교하고, 동률이면 무료 가격, 알려진 가격, 미설정 가격 순으로 정렬합니다.
관리자 세션 인증 및 자격 증명 API
contextual_orchestrator/server.py, tests/test_security_hardening.py
만료·폐기 가능한 불투명 HttpOnly 세션 쿠키를 발급합니다. 세션 수와 TTL을 제한하고, 관리자 자격 증명 요청을 검증하며 비밀값을 응답에 포함하지 않습니다.
관리자 화면 통합
contextual_orchestrator/admin.py, tests/test_admin_contract.py, docs/kv-credentials.md
세션 및 자격 증명 폼을 추가했습니다. 관리자 API 호출은 same-origin 세션 쿠키를 사용합니다. 성공 및 실패 상태를 처리합니다.
정적 분석 예외 주석
contextual_orchestrator/orchestrator.py, contextual_orchestrator/cost_ledger.py
개발 전용 TLS 설정, 검증된 provider URL, 고정 SQL 호출에 대한 예외 설명을 추가했습니다.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant 관리자브라우저
  participant 세션API
  participant SecurityConfig
  participant 자격증명API
  participant KV저장소
  관리자브라우저->>세션API: bearer token으로 POST /admin/session
  세션API->>SecurityConfig: token 검증 및 opaque session ID 발급
  SecurityConfig-->>관리자브라우저: HttpOnly 세션 쿠키
  관리자브라우저->>자격증명API: 세션 쿠키와 자격 증명 전송
  자격증명API->>KV저장소: 검증된 name과 value 저장
  KV저장소-->>자격증명API: 등록 결과
  자격증명API-->>관리자브라우저: 이름만 포함한 성공 응답
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 구현은 불투명 세션, 만료, 로그아웃, 세션 수 제한을 포함하지만 #116의 주요 보안 요구사항을 모두 충족했다는 증거가 없습니다. 세션 회전·고정 방지, CSRF/origin, HTTPS Secure 정책, 자격 증명 공개 방지, 재시작 동작을 구현하고 회귀 테스트와 커버리지 증거를 추가하십시오.
Out of Scope Changes check ⚠️ Warning 직접 연결된 #116은 브라우저 관리자 세션 분리를 다루지만, 가격 기반 라우팅과 KV 자격 증명 등록은 해당 이슈 범위를 벗어납니다. 가격 라우팅과 KV 자격 증명 변경을 별도 PR로 분리하거나, 해당 변경을 명시하는 직접 연결 이슈를 추가하십시오.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 가격 기반 실시간 모델 라우팅과 관리자 KV 자격 증명 엔드포인트라는 PR의 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/cost-aware-model-selection

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@contextual_orchestrator/__main__.py`:
- Around line 91-94: Define or correctly import _json_object before
parser.add_argument references it, so normal CLI startup and --help/--serve do
not raise NameError. Implement the parser to accept only JSON objects and
validate that each price value is a valid non-negative numeric value, raising
the argument parser’s standard validation error for invalid input.

In `@contextual_orchestrator/admin.py`:
- Around line 1598-1615: Update saveCredential’s POST request to use the
supported browser-admin authentication mechanism for /admin/api/credentials,
such as a validated server session or an explicitly configured proxy that
injects the admin Bearer token upstream. Ensure the request is authenticated in
deployments requiring admin authorization, and do not store or expose the admin
token in JavaScript.

In `@docs/kv-credentials.md`:
- Around line 121-125: Update the credentials-registration example around the
curl command so the secret value is read from standard input or a protected file
instead of appearing in the command-line -d argument. Keep the request payload
and registered credential behavior unchanged while ensuring the actual secret is
absent from both the command and shell history.

In `@tests/test_security_hardening.py`:
- Around line 100-119: Resolve Ruff S106 findings in the test setup around the
SecurityConfig and post_json calls by replacing repeated token literals with
test-only constants, and apply narrowly scoped noqa suppression only where
literals must remain. Follow the repository’s established test-secret exception
policy without changing the security behavior being tested.
- Around line 98-131: Update
test_admin_credential_endpoint_registers_into_kv_without_echoing_value to retain
the InMemoryCredentialBackend instance passed to set_backend, then after the
admin registration assert that the LITELLM_API_KEY entry contains the submitted
secret value. Keep the existing response and cleanup assertions unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 36da1999-463f-41e2-a721-a36d111232e9

📥 Commits

Reviewing files that changed from the base of the PR and between 6841b71 and cd11969.

📒 Files selected for processing (9)
  • contextual_orchestrator/__main__.py
  • contextual_orchestrator/admin.py
  • contextual_orchestrator/orchestrator.py
  • contextual_orchestrator/server.py
  • docs/architecture.md
  • docs/kv-credentials.md
  • tests/test_admin_contract.py
  • tests/test_paper_contracts.py
  • tests/test_security_hardening.py

Comment thread contextual_orchestrator/__main__.py
Comment thread contextual_orchestrator/admin.py
Comment thread docs/kv-credentials.md
Comment thread tests/test_security_hardening.py
Comment thread tests/test_security_hardening.py Outdated
Define _json_object for --price-per-million, add nosemgrep on audited SQL/TLS/urllib false positives, mint HttpOnly admin session cookies for browser KV registration, and harden credential docs/tests without embedding secrets in argv.
@seonghobae

Copy link
Copy Markdown
Contributor Author

Remediation on 4a3058f

Addressed CodeRabbit + Semgrep gate:

Finding Fix
_json_object NameError Implemented CLI JSON object parser with non-negative price validation
Admin credential auth POST /admin/session HttpOnly cookie + apiFetch(..., credentials: same-origin); shell no longer embeds admin token after session establish
curl secret in argv Docs use stdin/jq pipe into --data-binary @-
Ruff S106 test secrets _TEST_* constants with narrow noqa
KV assert after register Backend retained; get_credential asserts stored value
Semgrep SQL/TLS/urllib Audited # nosemgrep on fixed placeholders / intentional TLS opt-out / validated provider URL

Auto-merge (squash) enabled. Waiting on independent approval + remaining required checks (Strix/Atheris/coverage as applicable).

@seonghobae
seonghobae marked this pull request as ready for review August 12, 2026 10:31
@seonghobae
seonghobae enabled auto-merge (squash) August 12, 2026 10:31

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head 59c304f608ef6fd3f9992b6d2e4bd23a2c75a510.

  • Head SHA: 59c304f608ef6fd3f9992b6d2e4bd23a2c75a510

  • Workflow run: 31689634573

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (5 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (5 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs (2 files)"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs (2 files)"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test (4 files)"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test (4 files)"]
  R3 --> V3["targeted test run"]
Loading

@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 12:21
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 12:23
@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 12:54
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 12:55

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

OpenCode cannot approve yet because required coverage evidence did not pass.

Review outcome

1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence

  • Problem: The required coverage-evidence job result was failure, so OpenCode cannot establish approval sufficiency for this head.

  • Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.

  • Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports success with required evidence or explicit no-source not-applicable evidence.

  • Regression test: Keep the approval branch checking needs.coverage-evidence.result == success before posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present.

  • Result: REQUEST_CHANGES

  • Reason: coverage-evidence result was failure, so required test/docstring evidence was not proven for current head 59c304f608ef6fd3f9992b6d2e4bd23a2c75a510.

  • Head SHA: 59c304f608ef6fd3f9992b6d2e4bd23a2c75a510

  • Workflow run: 31694844993

  • Workflow attempt: 1

Coverage evidence

Coverage evidence job did not run or did not publish coverage evidence.

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (5 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (5 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs (2 files)"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs (2 files)"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test (4 files)"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test (4 files)"]
  R3 --> V3["targeted test run"]
Loading

@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 14:15
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 14:18
@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 18:19
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 18:20
@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 19:22
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 19:24
@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 22:12
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 22:14
@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 23:02
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 23:03
@opencode-agent
opencode-agent Bot disabled auto-merge August 13, 2026 23:53
@seonghobae
seonghobae enabled auto-merge (squash) August 13, 2026 23:56
@opencode-agent
opencode-agent Bot disabled auto-merge August 14, 2026 03:00
@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 03:03
@opencode-agent
opencode-agent Bot disabled auto-merge August 14, 2026 04:43
@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 04:46
@opencode-agent
opencode-agent Bot disabled auto-merge August 14, 2026 06:09
@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 06:09
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.

fix(security): separate browser admin sessions from long-lived bearer credentials

1 participant