Skip to content

Configure preview golden egress policies on actor templates - #2159

Merged
Benjamin Elder (BenTheElder) merged 1 commit into
agent-substrate:mainfrom
kagent-dev:feat/template-default-egress-upstream
Oct 21, 2026
Merged

Benjamin Elder (BenTheElder) merged 1 commit into
agent-substrate:mainfrom
kagent-dev:feat/template-default-egress-upstream

Conversation

@EItanya

@EItanya Eitan Yarmush (EItanya) commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Golden initialization can need network access that runtime actors should not inherit. ActorTemplate.goldenEgressPolicy configures that access behind the GoldenEgressPolicy preview gate, with client preview opt-in.

The template reconciler creates the golden actor suspended, creates its policy through the existing CreateActorEgressPolicy RPC, then calls ResumeActor. Retries recover partial creation and verify that existing rules match the template. Policy errors or conflicts block the controller from resuming the golden. Ordinary actors do not inherit this policy.

The template remains immutable and keeps the metadata-free EgressPolicyTemplate wrapper. It requires at least one rule and rejects a policy when golden snapshots are disabled. Existing templates can finish initialization after the preview gate is disabled. Actor and policy creation are separate calls, so callers must leave golden startup to the controller.

Motivation and API rationale: #2358. Related to #1324.

  • Tests pass — affected API, functional, storage, authorization, and preview suites pass with race detection; focused cases passed three shuffled runs. All repository verifiers and API validation pass. CI is pending. The full root-module race suite was not rerun locally due limited scratch space.
  • Appropriate changes to documentation are included in the PR

AI assistance: Codex helped implement, rebase, and test these changes.

Comment thread pkg/proto/ateapipb/ateapi.proto Outdated
Comment on lines +995 to +1003
// Initial egress policy, copied atomically when an Actor is created from
// this template, including the golden Actor used for initialization. The
// policy is named "default" in the Actor's atespace, with its own metadata.
// Callers may update or delete the copy independently; changing the Actor's
// template does not update its policy. If absent, no policy is created;
// an empty block creates a policy with no rules.
//
// +k8s:optional
EgressPolicyTemplate default_egress_policy = 9;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I opted to create another message here for simplicity, but we could opt to instead require the whole EgressPolicy object with metadata and require the name to be default etc.

Julian Gutierrez Oschmann (@juli4n) and Tim Hockin (@thockin) for API context

@thockin

Copy link
Copy Markdown
Collaborator

Clarify for me - does this mean that every actor created from such a template has the same policy unless subsequently changed? Maybe that should be opt-in? E.g. create actor --template=<T> --with-template-policy ?

Does this also mean that a subsequent call to set policy will require a read-modify-write? That may be surprising.

@EItanya

Copy link
Copy Markdown
Collaborator Author

Clarify for me - does this mean that every actor created from such a template has the same policy unless subsequently changed? Maybe that should be opt-in? E.g. create actor --template=<T> --with-template-policy ?

Yes it would. However, I think that if you are creating from an ActorTemplate, the default policy is actually something you always want, otherwise your actor probably won't work correct. Minus the policy would probably warrant a separate ActorTemplate. The other option could be to accept a policy when calling CreateActor. Part of the problem is that this field is actually doing 2 important, but separate things.

  1. Setting Policy for the golden snapshot, allowing the actor template to use the network to prepare the golden.
  2. Also adding that same policy as the default policy for the actor itself once created.

Now that I've spelled that out for you, I actually think these should be separate. The field I created here should really be something like golden_egress_policy, and then also accept a policy when calling CreateActor. (Doesn't have to be exactly that, but something in that spirit.)

Does that make sense?

Does this also mean that a subsequent call to set policy will require a read-modify-write? That may be surprising.

Yes, and this is a very good point. I think that can mostly be solved with documentation, but it's definitely an interaction worth calling out. This is also a result of not having multiple policy layers, and therefore needing one policy source of truth for an actor.

@EItanya Eitan Yarmush (EItanya) changed the title Apply template default egress policies to golden and newly created actors Configure egress access during golden initialization Oct 6, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I am worried on just "goldenEgressPolicy". There are going to be many usecases that you need to just fetch github repos/s3/gcs for some assets. Not necessrially part of "golden" - how do we get those to work.

maybe its an "init actor" support and a policy for that? A very common use case for that is "I want an actor with no network, but give it all this github repos available in local folders (e.g for RL)

FWIW init actor can be useful for many other things.

@EItanya

Copy link
Copy Markdown
Collaborator Author

I am worried on just "goldenEgressPolicy". There are going to be many usecases that you need to just fetch github repos/s3/gcs for some assets. Not necessrially part of "golden" - how do we get those to work.

If it's not part of the golden then it's already supported. When an actor comes up from golden it will already have its own identity. I specifically narrowed the scope of this PR to just handle the golden identity.

Adding policy for pre readyz should already work.

maybe its an "init actor" support and a policy for that? A very common use case for that is "I want an actor with no network, but give it all this github repos available in local folders (e.g for RL)

That would be exactly what this would enable. The actor identity would not be allowed to make network calls, only during golden preparation. Mounting other data can/should be done with volumes otherwise.

FWIW init actor can be useful for many other things.

Comment thread cmd/ateapi/internal/controlapi/actor.go Outdated
// Save the data in the storage layer.
stored, err := s.store.CreateActor(ctx, outActor)
var policy *ateapipb.EgressPolicy
if initial := template.GetGoldenEgressPolicy(); initial != nil && atespace == resources.GoldenActorAtespace {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this policy only be used when creating a golden for the template, rather than every CreateActor() ? IIUC this will use the golden policy for every derived actor, which is exactly what we said it was NOT?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is a leftover, I agree with you. However, this and the comment below do basically land us at changing the RPC to accept an optional initial policy, which could be used internally for goldens, and externally to use a single call to create the Actor. Overall I think the UX would be improved there anyway.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is especially relevant given that we're moving goldens out of this magical atespace

storageClassLister storagev1listers.StorageClassLister
}

var _ store.Interface = (*ServiceImpl)(nil)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I know Julian Gutierrez Oschmann (@juli4n) thinking about layers

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

As I said above, going to change the RPC and see how we feel about that

@EItanya Eitan Yarmush (EItanya) changed the title Configure egress access during golden initialization Configure initial egress policies for actors and goldens Oct 14, 2026
@EItanya
Eitan Yarmush (EItanya) force-pushed the feat/template-default-egress-upstream branch from 2555fa5 to 8f23f53 Compare October 14, 2026 13:51
@bowei Bowei Du (bowei) added area/api User-facing API changes area/api-machinery area/security Security related issue/pr kind/feature An enhancement / feature request or implementation labels Oct 14, 2026
@EItanya
Eitan Yarmush (EItanya) force-pushed the feat/template-default-egress-upstream branch from 8f23f53 to 70da2cd Compare October 15, 2026 12:44

@thockin Tim Hockin (thockin) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

My comments are inconsequential, get this merged and we can discuss if it matters.

Comment thread tools/apitool/exemptions.json Outdated
@@ -1,4 +1,9 @@
[
{
"rule": "create-request-shape",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't understand this exemption? What causes it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is caused by the Create RPC now accepting the subresource EgressPolicy

@juli4n Julian Gutierrez Oschmann (juli4n) Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We have a rule that CreateRequest only passes the resource (plus options) and nothing else "out of band". We are diverging here from the style guide.

IIUC, the idea here is that when you create a resource, you can also create a singleton sub-resource in the same request. If we are ok with that, we can keep the exemption for now, and update the linter rule later.

Comment thread pkg/proto/ateapipb/ateapi.proto Outdated
// The policy can subsequently be managed through the Actor egress policy RPCs.
//
// +k8s:optional
EgressPolicy initial_egress_policy = 2;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Super nit: I don't think "initial" adds much here

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Actually, should this be part of the preview? If not for golden policy, would we add this as an atomic txn?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Actually, should this be part of the preview? If not for golden policy, would we add this as an atomic txn?

Can you explain this comment a bit more? This is implemented in the DB as an atomic txn, but the way this is written it seems like you're referring to atomicity at the RPC layer so just wanted to clarify.

These resources and their lifecycle are intimately tied, so I think this is net positive anyway. If we marked this preview would it be the same preview gate or a different one? I think it would have to be the same as this is a pre-req to the golden working properly.

@thockin

Copy link
Copy Markdown
Collaborator

Need rebase, otherwise LGTM

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

generally onboard, including manual + agent nits but nothing egregious

Comment thread pkg/proto/ateapipb/ateapi.proto Resolved
// +k8s:optional
ActorTemplateStatus status = 8;

// Egress policy for the golden Actor during initialization. The template

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: status should be declared last (not field number, but in the type?)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Julian Gutierrez Oschmann (@juli4n) I feel like we should extend apitool to cover this, WDYT?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Moved status to the end of the declaration, keeping field number 7. Apitool enforcement can be a separate follow-up.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes, not suggesting doing that here, but this PR made me wonder if we should do that as well.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Today the field order doesn't have any semantics, although the apitool docsite generator (#2775) will honor it when rendering the fields table. I think having all statuses at the end makes sense. Also, IIRC kubectl ate -o yaml/json is not honoring the order either (which I think it should).

We can look into this as a separate task though (and introduce a linter rule).

Comment thread cmd/ateapi/internal/store/store.go Resolved
@EItanya
Eitan Yarmush (EItanya) force-pushed the feat/template-default-egress-upstream branch 5 times, most recently from dc0a775 to 79a2cca Compare October 20, 2026 21:58
@EItanya Eitan Yarmush (EItanya) changed the title Configure initial egress policies for actors and goldens Configure preview golden egress policies on actor templates Oct 20, 2026
return err
}
if !proto.Equal(&ateapipb.EgressPolicyTemplate{Rules: existing.GetRules()}, want) {
return apierror.FailedPrecondition("golden actor egress policy does not match the template")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The apierror type is to signal that an inbound RPC request failed, but the reconciler runs in a background loop so it doesn't really apply here. I would just return a regular Go error.

Related: IIUC a mismatch here can only happen if another client writes the golden actor's policy. Sounds very unlikely, but if we want to handle it, should we r.fail like we do in the other bad conditions? That would make the error visible in the ActorTemplate status.

@EItanya
Eitan Yarmush (EItanya) force-pushed the feat/template-default-egress-upstream branch 2 times, most recently from 9f1daff to c96018e Compare October 21, 2026 17:45
Golden initialization can need network access that runtime actors should not inherit. Have the template reconciler create and verify the golden policy through existing RPCs before resuming the actor.

Signed-off-by: Eitan Yarmush <[email protected]>
@BenTheElder
Benjamin Elder (BenTheElder) added this pull request to the merge queue Oct 21, 2026
Merged via the queue into agent-substrate:main with commit 5ddce4f Oct 21, 2026
15 checks passed
Julian Gutierrez Oschmann (juli4n) pushed a commit to juli4n/substrate that referenced this pull request Oct 22, 2026
…be passes (agent-substrate#2117)

An actor's egress was turned on only after every container answered its
wakeup probe, so a workload that downloads what it needs to become ready
(a model, a Git repository) could not start. atunnel closed the
connection inside the sandbox before it reached the gateway. Egress is
now turned on before the first container starts, on both sandbox classes
and for both run and restore; ingress still waits for the probe. The
atenet gateway admits `RESUMING` actors as well as `RUNNING` ones, and
atunnel and the gateway now log the connections they refuse.

The actor's EgressPolicy still applies. The new e2e test gives the
golden actor its policy through the template's `goldenEgressPolicy`
(agent-substrate#2159), so it runs only with the `GoldenEgressPolicy` preview gate. A
restored actor's wakeup probe also waits for a fresh fetch as itself,
which covers the restore paths. agentgateway moves to
`v0.0.0-alpha.9d36620d`, which admits `RESUMING` actors too
(agentgateway/agentgateway#3882), so the test runs on both dataplanes.

Tested on kind with gVisor on both dataplanes, before the move to
`goldenEgressPolicy`: the test passed with this change and failed
without it (on agentgateway, against the previous pin). The rest of the
gVisor e2e suite also passes on the agentgateway lane, apart from the
external-volume tests, which could not mount NFS on my rootless setup.

Part of agent-substrate#1543

- [x] Tests pass
- [x] Appropriate changes to documentation are included in the PR

---------

Signed-off-by: QuentinBisson <[email protected]>
Co-authored-by: Timo Derstappen <[email protected]>
Co-authored-by: Lior Lieberman <[email protected]>
pood1e (pood1e) added a commit to pood1e/substrate that referenced this pull request Oct 28, 2026
Backports two changes onto v0.6.0-alpha3 for AgentOS:

- ActorTemplate.golden_egress_policy from agent-substrate#2159,
  creating egress rules for golden preparation in the same transaction.
- The startup egress fix from giantswarm/substrate@6be3d50, enabling the
  egress tunnel before the container starts while ingress still waits for
  the readiness probe.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api User-facing API changes area/api-machinery area/network area/security Security related issue/pr kind/feature An enhancement / feature request or implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants