Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions docs/routing/NATIVE_ROUTER_RFC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
---
title: "Native Router Workstream RFC"
version: 3.8.43
lastUpdated: 2026-07-03
---

<!-- markdownlint-disable MD025 -->

# Native Router Workstream RFC

Status: proposed
Tracker: [#5670](https://github.com/diegosouzapw/OmniRoute/issues/5670)
Related PRs: #6071, #6079, #6081, #6083

## Problem

OmniRoute already has mature combo routing, provider cooldown, usage history, and
compression evaluation surfaces. The native-router backlog should not land as
independent helper PRs until the maintainer accepts a staged contract for how those
surfaces fit together.

The current deferred slices are:

- #6071: router evaluation gate using retained replay/evaluation output.
- #6079: backend failure/cooldown state helper keyed by backend identity.
- #6083: provider plugin manifest HTTP client for sidecars and native backends.
- #6081: backend migration plan for the native-router workstream.

## Goals

- Define the order that turns the deferred PRs into a single 3.9/4.0 workstream.
- Keep existing combo routing behavior stable while native backends are introduced.
- Require measurable routing quality gates before routing selection changes.
- Keep provider cooldown semantics explicit across combo targets and future native backends.
- Avoid adding a new provider manifest path until its trust and cache boundaries are clear.

## Non-Goals

- Do not replace current combo routing in one release.
- Do not change provider credential storage or encryption as part of the first native-router slice.
- Do not persist transient combo failures as provider-wide cooldowns without provider-specific evidence.
- Do not introduce a sidecar manifest client as an implicit security boundary.

## Current Source Anchors

- Combo cascade and live combo events are surfaced through `src/hooks/useLiveDashboard.ts`.
- Provider cooldown and combo-live behavior are exercised by
`scripts/test/combo-live-vps.mjs`.
- Provider connection data is stored in `provider_connections`, referenced by
`scripts/dev/sync-env.mjs`.
- Usage and call-log history are documented around `usage_history` and `call_logs` in
`docs/ops/DATABASE_GUIDE.md`.
- Compression evaluation already has a CLI entrypoint in `scripts/compression-eval/index.ts`.
- Session cooldown state exists in `open-sse/services/sessionPool/session.ts`.

## Proposed Stages

### Stage 0: Contract and Fixture Inventory

Before code changes, document the native-router boundary:

- Inputs: request metadata, provider/model candidates, account health, usage history.
- Outputs: ordered backend candidates, rejection reasons, selected backend, fallback history.
- State that can affect future calls: provider/account cooldown, circuit-breaker state,
usage aggregates, and explicit user policy.

Exit criteria:

- The router contract can be tested without live provider credentials.
- Existing combo routing remains the default.
- Every new persisted field has an owner and a rollback plan.

### Stage 1: Evaluation Gate

Land the #6071 class of work first, but only as a read-only gate:

- Replay retained request/call history.
- Produce scorecards for current routing behavior.
- Track regressions before native routing can select traffic.
- Fail the gate only on deterministic fixtures, not on live-provider variance.

Exit criteria:

- A maintainer can run the gate locally without secrets.
- The report explains which routing decision changed and why.
- No production routing path depends on the new evaluator yet.

### Stage 2: Backend State Model

Land the #6079 class of work after the gate exists:

- Normalize backend failure and cooldown state behind a single helper.
- Keep provider/account cooldown distinct from transient combo-target failure.
- Preserve current `provider_connections` semantics unless an issue provides raw
provider evidence requiring a broader cooldown classification.

Exit criteria:

- Tests cover provider-wide cooldown, account-specific cooldown, and transient target failure.
- Existing combo behavior remains unchanged unless the new helper is explicitly enabled.
- The data model avoids ambiguous "backend" IDs that cannot be mapped back to a provider/account.

### Stage 3: Provider Manifest Client

Land the #6083 class of work only after Stage 2 defines backend identity:

- Treat manifests as untrusted input.
- Validate provider IDs, model IDs, endpoint URLs, and capability flags.
- Cache manifests with explicit TTL and failure behavior.
- Do not allow a manifest to override credential, egress, or auth policy.

Exit criteria:

- Manifest parsing is covered by fixtures for missing, malformed, stale, and hostile input.
- Network fetch failures do not block existing configured providers.
- The manifest client does not become a hidden bypass around provider config.

### Stage 4: Native Backend Migration Plan

Land the #6081 class of work as the release plan:

- 3.9: evaluator and state helper ship behind non-routing paths.
- 3.9.x: manifest client ships as opt-in discovery only.
- 4.0: native-router selection can become eligible after scorecard parity.

Exit criteria:

- Rollout can be disabled without schema rollback.
- Dashboards show current route, candidate order, and fallback reason.
- Known rollback path is documented before native-router selection is enabled.

## Acceptance Gates

- No route-selection change lands without a deterministic replay fixture.
- No provider cooldown behavior changes without a unit test and, when provider-specific,
a captured raw upstream status/body/header sample.
- No manifest-sourced backend is eligible until validation and trust boundaries are tested.
- No dashboard-visible state is added without a stable event/field owner.

## Risks

- A native-router slice could accidentally change combo semantics before the evaluation gate exists.
- Backend identity could collapse provider/account/model into one key and make cooldowns too broad.
- Manifest discovery could become a policy bypass if it is treated as trusted configuration.
- Live-provider tests can be flaky; deterministic fixtures must remain the release gate.

## Recommended Next PR Order

1. RFC-only PR for this document.
2. Rebase #6071 as a read-only evaluator/gate PR.
3. Rebase #6079 as a backend state helper with no default routing behavior change.
4. Rebase #6083 as a manifest parser/client behind opt-in discovery.
5. Rebase #6081 as the 3.9/4.0 migration plan after the first three contracts are accepted.
204 changes: 204 additions & 0 deletions docs/security/ISSUE_AGENT_RFC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
title: "Issue Agent Security Boundary RFC"
version: 3.8.43
lastUpdated: 2026-07-03
---

<!-- markdownlint-disable MD025 -->

# Issue Agent Security Boundary RFC

Status: proposed
Tracker: [#5620](https://github.com/diegosouzapw/OmniRoute/issues/5620)
Related PR: #5867

## Problem

The issue-agent workflow can create high-impact automation: read a GitHub issue,
triage it, modify code, run checks, and prepare a pull request. That is useful only
if the security boundary is explicit before implementation resumes.

The previous implementation work should remain parked until the maintainer accepts
what the agent may read, write, execute, and publish.

## Goals

- Define the trust boundary for issue-to-PR automation.
- Make repository writes opt-in and auditable.
- Keep generated code changes behind local validation before any PR is opened.
- Prevent issue text, comments, or labels from becoming unsandboxed instructions.
- Reuse existing guardrail, credential, and error-sanitization patterns.

## Non-Goals

- Do not run untrusted issue text as shell instructions.
- Do not grant production credentials to issue-agent runs.
- Do not auto-merge or auto-release agent-created PRs.
- Do not allow issue labels alone to bypass maintainer approval.
- Do not expose raw secrets, tokens, stack traces, or local paths in issue comments.

## Current Source Anchors

- Security guardrail documentation exists in `docs/security/GUARDRAILS.md`.
- CLI token authentication is documented in `docs/security/CLI_TOKEN_AUTH.md`.
- Secret and public credential handling is documented in `docs/security/PUBLIC_CREDS.md`.
- Error response sanitization is documented in `docs/security/ERROR_SANITIZATION.md`.
- Workflow state modeling exists in `open-sse/services/workflowFSM.ts`.
- GitHub/token redaction patterns are present in `scripts/sre/redact-logs.mjs`.
- Local-only and management route classification lives in
`src/server/authz/routeGuard.ts`.
- Spawn-capable route prefixes are centralized in
`src/shared/constants/spawnCapablePrefixes.ts`.
- Settings validation rejects unsafe local-only bypasses in
`src/shared/validation/settingsSchemas.ts`.
- Shared log redaction helpers live in `src/shared/utils/logRedaction.ts`.
- Outbound URL guarding lives in `src/shared/network/outboundUrlGuard.ts`.

## Threat Model

### Assets

- Repository write access.
- GitHub tokens and local credentials.
- Maintainer identity and review trust.
- Local workspace files and environment variables.
- CI minutes and release automation.

### Attackers

- External issue author attempting prompt injection.
- Contributor with comment access attempting workflow escalation.
- Compromised dependency or generated code path.
- Malicious or malformed issue payload causing unsafe shell execution.

### Trust Boundaries

- GitHub issue content is untrusted input.
- Repository contents are trusted only at the checked-out revision.
- Local secrets are never part of agent context.
- Generated patches are untrusted until tests and review pass.
- CI/release automation is out of scope for the issue agent.
- Any route that can spawn `git`, `gh`, package-manager checks, model CLIs, or
Docker workers is a local-only execution boundary.
- Diagnostic bundles cross a redaction boundary before persistence and before any
model/provider request.

## Permission Model

The issue agent should operate in four modes:

| mode | allowed | forbidden |
| ---------- | ----------------------------------------------------- | ------------------------------ |
| `recorded` | store issue context and proposed next steps | subprocesses, checkout writes |
| `triage` | summarize issue, classify area, identify likely files | edit files, run network writes |
| `patch` | edit local files, run local checks, produce diff | push, post comments, open PR |
| `publish` | push branch, open draft PR, post bounded summary | merge, release, modify secrets |

Mode escalation requires an explicit maintainer action. The agent must record:

- issue URL and revision timestamp;
- selected mode;
- files changed;
- commands run;
- tests passed or failed;
- whether network write actions were used.

## Workflow

### Stage 0: RFC and Audit Contract

- Land this RFC before reviving #5867.
- Add an audit envelope for every issue-agent run.
- Define the exact GitHub permissions required for each mode.
- Keep the feature default-off and add an emergency kill switch that short-circuits
new runs before enqueue or worker dispatch.

Exit criteria:

- Maintainer can review what the agent is allowed to do before any code path lands.
- The audit record is generated even when the run fails.

### Stage 1: Triage-Only Agent

- Add route-guard tests before any execution route exists.
- Read issue title/body/comments.
- Classify affected area from repository search.
- Produce a no-edit report with suspected files and test entrypoints.

Exit criteria:

- No file writes.
- No push/comment/PR side effects.
- No subprocess execution.
- Prompt-injection fixtures prove issue text cannot override system policy.

### Stage 2: Patch Agent

- Apply local edits on an isolated branch or worktree.
- Run targeted checks.
- Produce a diff and validation report.

Exit criteria:

- Dirty workspace is detected before edits.
- Commands are allowlisted.
- Secrets are redacted from logs before summaries are generated.
- Host checkout mutation is impossible outside the explicit patch mode.

### Stage 2.5: Worker Isolation

- Run fix-capable work in a Docker worker or equivalent isolated process boundary.
- Do not mount the host Docker socket.
- Mount source read-only unless the run is explicitly in patch mode.
- Pass only scoped GitHub credentials and required environment variables.
- Apply outbound URL guards before any issue-agent fetches untrusted URLs.

Exit criteria:

- Tests prove `recorded`, `triage`, and planning modes cannot mutate the host checkout.
- Tests prove command allow-list denial is logged and fails closed.
- A worker failure cannot leak raw environment variables in the API response.

### Stage 3: Draft PR Publisher

- Push only the prepared branch.
- Open a draft PR with the audit summary.
- Link back to the originating issue.

Exit criteria:

- PR remains draft by default.
- No auto-merge path exists.
- Failed checks are surfaced instead of hidden.

## Acceptance Gates

- Unit tests cover prompt injection in issue body, comments, and labels.
- Tests cover mode escalation denial.
- Tests cover dirty-workspace refusal or isolation.
- Tests cover redaction of GitHub tokens and generic secret patterns.
- Documentation states exactly which mode can post comments or open PRs.
- The eventual issue-agent route prefix is local-only for every endpoint that can
enqueue or execute work.
- Spawn-capable issue-agent routes cannot be added to manage-scope bypass
prefixes.
- Request bodies are schema-validated and size-bounded before route execution.
- Run storage is retention-pruned and never stores raw tokens or environment
variables.
- Audit records include actor, mode, issue/PR URL, run ID, branch, redaction
counts, command outcomes, and final status.
- Draft PR creation is impossible from `recorded`, `triage`, or planning modes.

## Open Questions

- Should publish mode require a label, a slash command, or both?
- Should patch mode run in an isolated worktree by default?
- Should comments be posted only on success, or should failures also be reported?
- What retention period should audit records use?

## Recommended Next PR Order

1. RFC-only PR for this document.
2. Triage-only implementation with prompt-injection fixtures.
3. Patch mode with dirty-workspace isolation and allowlisted commands.
4. Draft PR publisher with explicit maintainer-gated escalation.
Loading