Skip to content

feat: add reusable egress policies for agents and sandboxes - #3177

Merged
EItanya merged 36 commits into
mainfrom
feat/agent-egress-policies
Oct 17, 2026
Merged

EItanya merged 36 commits into
mainfrom
feat/agent-egress-policies

Conversation

@EItanya

@EItanya EItanya commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

This PR adds reusable EgressPolicy resources for HTTP(S) access beyond an agent's inferred model, MCP, and artifact access. Agent and SandboxTemplate select policies through spec.egressPolicyRefs in the same namespace. Authentication uses a header, optional literal prefix, and Secret key reference:

authentication:
  header: Authorization
  prefix: "Bearer "
  secretKeyRef:
    name: ticket-auth
    key: token

The elected Agent and SandboxTemplate reconcilers resolve policies from cached Kubernetes inputs and persist grants on the source definition. Effective policy merges those grants with a revision's pinned integration access when read. Create, resume, and checkpoint forks use that persisted state without translating Kubernetes inputs. Explicit grants stay outside the revision hash.

Every preparation applies persisted policy to the source's running and suspended actors across retained revisions, with at most 16 updates in parallel. Unchanged policies skip the Substrate write. Failures retry through the existing preparation queue, and startup replays every source. Slow actor updates therefore delay that preparation queue. Source finalizers preserve deletion through controller downtime and remain until actor revocation succeeds. Substrate version preconditions order competing applications, and creation rechecks policy after applying it so concurrent updates are not missed. Convergence remains asynchronous.

New instances can use the latest successful runtime revision while edits are pending or failed. Grants continue updating even when a Harness, template, or WorkerPool cannot be resolved. Missing or invalid policies revoke explicit grants while preserving pinned integration access. Recreating a source does not transfer grants to its old instances. Conflicts with pinned credentials, token passthrough origins, or the merged rule limit withhold explicit grants and emit warnings.

Credential injection requires an exact HTTPS origin, and Secret values stay out of runtime revisions. Includes CRDs, clients, Helm packaging, and API and lifecycle documentation.

E2E coverage uses the same OCI skill and shell probe through kagent, Codex, Claude, and BYO Go ADK. It checks live grant/revocation, creation from the last successful revision, resume, and checkpoint forks. A separate HTTPS scenario checks actual Secret header replacement, with and without a prefix. Standalone sandboxes have lifecycle coverage through their process API.

Validation: the full Go test suite with the race detector, PostgreSQL store and migration tests (including inline SQL preparation), and Go lint passed locally. Runtime E2E validation for this refactor is pending CI; the available local cluster uses the old API.

@blacksmith-sh

This comment has been minimized.

Comment on lines +65 to +75
// validCredentialHeader excludes routing, framing, hop-by-hop and cookie headers.
func validCredentialHeader(header string) bool {
if len(header) > 256 || !httpguts.ValidHeaderFieldName(header) {
return false
}
switch strings.ToLower(header) {
case "host", "connection", "content-length", "transfer-encoding", "te", "trailer", "upgrade", "keep-alive", "proxy-authorization", "proxy-authenticate", "cookie":
return false
}
return true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This applies now to the RemoteMCPServer.spec.headersFrom[].name field. Maybe we could add the CEL rule to validate this into the CRD. WDYT?

BTW, this breaks existing RemoteMCPServer objects that use any of the not allowed headers, so let's make sure this is released as a breaking change (PR title, PR description, etc).

@EItanya
EItanya force-pushed the feat/agent-egress-policies branch from d99e039 to f112f42 Compare October 13, 2026 17:57
@blacksmith-sh

This comment has been minimized.

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Oct 13, 2026
@EItanya
EItanya marked this pull request as ready for review October 13, 2026 20:30
@EItanya
EItanya requested review from a team and Charlesthebird as code owners October 13, 2026 20:30

@codyhartsook codyhartsook 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.

🤖 AI-generated review.

Comment thread go/core/internal/egress/credentials.go
@ernoaapa

Copy link
Copy Markdown

Thanks, this is what we need for per-agent egress. Would you accept a bare * as an origin, for allow-all? Substrate already supports * hostnames, and some of our agents (developers building code with many package registries) need open egress. Exact-origin rules with credentials would still win for their hosts. Happy to send a follow-up PR if that fits.

Comment thread docs/architecture/egress-policies.md Outdated
@EItanya

EItanya commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

Thanks, this is what we need for per-agent egress. Would you accept a bare * as an origin, for allow-all? Substrate already supports * hostnames, and some of our agents (developers building code with many package registries) need open egress. Exact-origin rules with credentials would still win for their hosts. Happy to send a follow-up PR if that fits.

Makes sense, let's do a follow-up

@EItanya
EItanya force-pushed the feat/agent-egress-policies branch from f0fe942 to 5d6a8d1 Compare October 15, 2026 16:00
@blacksmith-sh

This comment has been minimized.

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
…edits

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Use a revision-keyed workqueue to serialize publication and replay changes received during an in-flight write. Keep startup actor recovery separate, and require a persisted policy before the store promotes a revision.

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Recover offline Agent deletions through preparation instead of a finalizer. Hash compiled runtime inputs while retaining full source provenance, and keep source actor queries inline in the store.

Allow credentials on exact HTTP origins and exercise delivery with a plain HTTP origin, removing shared gateway configuration changes from the e2e fixture.

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Resolve policies independently and retain still-requested last-good grants when additions conflict. Filter only incompatible grants for older revisions, expose EgressPoliciesApplied on Agents and SandboxTemplates, and bound deleted-Agent recovery to retained instances.

Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
@EItanya
EItanya force-pushed the feat/agent-egress-policies branch from c8fec1c to 61288e3 Compare October 17, 2026 22:25
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io>
@EItanya
EItanya merged commit a0ad6cb into main Oct 17, 2026
29 of 30 checks passed
@EItanya
EItanya deleted the feat/agent-egress-policies branch October 17, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants