Skip to content

Bump Substrate to ddb46651: templates name no sandbox, durable suspend, an identity Substrate's authorization can grant - #108

Open
Tomer Glottmann (tomergee) wants to merge 3 commits into
mainfrom
bump-substrate-latest
Open

Tomer Glottmann (tomergee) wants to merge 3 commits into
mainfrom
bump-substrate-latest

Conversation

@tomergee

@tomergee Tomer Glottmann (tomergee) commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Bumps go.ate.dev/substrate from 3a2ca623 (2026-10-16) to ddb46651 (2026-10-18). Against current Substrate main, main does not build, and a stock install refuses ate-env-api's control-plane calls.

What breaks on main today

Substrate change Effect on ate-env main Fix here
substrate#2780 (0443aec3): ActorTemplate.sandbox_config and SandboxConfig removed; the WorkerPool's sandboxClasses alone picks the sandbox. ate-api-server rejects unknown fields. go build fails. ate-env manifest template writes sandboxConfig, which Substrate refuses with InvalidArgument. The template names no sandbox. The WorkerPool already declares gvisor with the gvisor-default configRef.
substrate#2813: PauseActor removed The test fake does not compile. Dropped from the fake.
substrate#2805: SuspendActor is asynchronous by default; the snapshot stays on the node and uploads in the background SuspendEnvironment silently loses its durability guarantee: a node loss before the upload loses the environment. Request DURABILITY_MODE_SYNCHRONOUS, as Substrate's own callers that relied on the old default now do.
substrate#2780 (behavior): with no class on the template, Substrate's release note flags that a template with no workerSelector whose actor has no snapshot can be placed on a pool of any class ate-env templates set no selector. On a cluster with more than one pool, a cold-booting environment can land on another team's pool or on a microvm pool. The WorkerPool carries ate-env/workerpool: <pool>, which Substrate copies to its workers. Each template selects it through a new --workerpool flag, default <template>-workerpool as in ate-env manifest. Derived templates inherit the selector.
substrate#2591: ateapi authorization on by default (already in the 3a2ca623 pin) ate-env-api runs as the namespace's default ServiceAccount, which no policy grants. Each control-plane call is denied, and ate-env-api fails at startup. ate-env manifest creates an ate-env-api ServiceAccount and runs the Deployment as it, with no Kubernetes API token mounted, because ate-env-api never calls the API. ate-env manifest access-policy prints the policy that grants it editor on an atespace.

Install, per the updated README step 1, as an owner of the atespace (the default kubectl-ate identity on a stock install):

kubectl ate create atespace ate-env
ate-env manifest access-policy | kubectl ate create access-policy -a ate-env -f -
ate-env manifest --worker-image ... | kubectl apply -f -

Compatibility. This ate-env needs Substrate at or after 0443aec3 (2026-10-17), because an older Substrate requires sandboxConfig (+k8s:required at 3a2ca623). The README says so.

Upgrading.

  • Create the access policy before you apply the new manifest.
  • Base templates registered earlier keep working: Substrate's store drops their old field when it reads them, so derived templates come out clean.
  • Those old bases have no workerSelector. On a cluster with more than one pool, register them again after you apply the new manifest.

Verification

  • go build, go vet, go test -race ./..., staticcheck, make verify-gofmt verify-boilerplate and go mod tidy (a no-op) are clean against ddb46651.
  • Against Substrate ddb46651's own code, with scratch tests run in a Substrate checkout and then removed:
    • kubectl-ate's actorTemplateFromManifest parses the default template, a template with custom limits (cpu 999.999, 64Gi), and a rootfs-image derived template.
    • ate-api-server's strict protojson, defaults.Apply and ValidateCreateActorTemplateRequest accept all three.
    • kubectl-ate's loadAccessPolicyManifest and ValidateCreateAtespaceAccessPolicyRequest accept the access policy.
  • New and updated tests:
    • The template carries no sandbox field.
    • The manifest has the ServiceAccount, and the pod runs as it.
    • The pool's label matches the default template's selector, and --workerpool names another pool.
    • manifest access-policy names user:system:serviceaccount:<namespace>:ate-env-api as editor.
    • TestSuspend checks the synchronous mode.
  • Not run on a cluster: the test cluster still runs Substrate from 2026-10-12. A live check needs a Substrate main redeploy.

…d, an identity Substrate's authorization can grant

go.ate.dev/substrate 3a2ca623 -> ddb46651 (2026-10-18).

- substrate#2780 removed ActorTemplate.sandbox_config and the SandboxConfig
  message; the WorkerPool's sandboxClasses alone chooses the sandbox, and
  ate-api-server rejects a template that still sends sandboxConfig. The
  generated template drops it. The WorkerPool already declares gvisor with
  the gvisor-default configRef. An older Substrate requires the field, thus
  this ate-env needs Substrate at or after 0443aec3.
- substrate#2813 removed PauseActor; the fake control plane drops it.
- substrate#2805 made SuspendActor asynchronous by default (the snapshot
  stays on the node and uploads in the background). ate-env-api asks for
  DURABILITY_MODE_SYNCHRONOUS, the behavior it always had, so a suspended
  environment survives the loss of its node. The fake records the mode and
  TestSuspend checks it.
- Substrate enforces ateapi authorization by default (substrate#2591; also
  in the previous pin). ate-env-api ran as the namespace's default
  ServiceAccount, which no policy grants, so each control-plane call was
  denied on a stock install. `ate-env manifest` now creates an ate-env-api
  ServiceAccount (no Kubernetes API token mounted; ate-env-api never calls
  the API) and runs the Deployment as it, and `ate-env manifest
  access-policy` prints the policy that grants it editor on an atespace,
  for `kubectl ate create access-policy -a <atespace> -f -`.
… install step

The README's compatibility note names ddb46651 and the 0443aec3 boundary
(templates without sandboxConfig), says that ate-env-api suspends
synchronously, and that Substrate enforces authorization. Step 1 now creates
the atespace and the access policy before the manifest, with what to do when
the atespace already has a policy. The upgrade notes cover the access policy
(without it ate-env-api fails at startup), old base templates (Substrate drops
their sandboxConfig when it stores them) and the earlier limits boundary. The
rootfs-image docs no longer say that a template carries a sandbox class.
Since substrate#2780 the template names no sandbox class, and Substrate's
release note flags that a template with no workerSelector whose actor has
no snapshot can be placed on a pool of any class. ate-env templates had no
selector. On a cluster with more than one pool (another team's, or an
OpenShell microvm pool), a cold-booting environment could land on the
wrong one.

The WorkerPool now carries `ate-env/workerpool: <pool>`; Substrate copies a
pool's labels to its workers. Each template selects that label, through a
new --workerpool flag on `ate-env manifest template` that defaults to
<template>-workerpool, as `ate-env manifest` does. Derived per-image
templates inherit the selector from their base. Templates with the selector
pass Substrate ddb46651's validation. The README explains the selection and
when to register old bases again.
Tomer Glottmann (tomergee) added a commit to tomergee/env that referenced this pull request Oct 19, 2026
…ndbox class

Rebased onto the Substrate ddb46651 bump (agent-substrate#108). Since substrate#2780 the
ActorTemplate has no sandboxConfig and the WorkerPool alone chooses the
sandbox, thus `ate-env manifest template` lost --sandbox-class and
--sandbox-config (`ate-env manifest` keeps them for the pool). Without a
selector a cold-booting OpenShell actor could land on a gVisor pool, where
OpenShell's sandbox does not qualify.

- deploy/workerpool.yaml carries `ate-env/workerpool: <pool>`; install.sh
  rewrites it with the pool name and registers the template with
  --workerpool instead of the sandbox flags.
- The README and docs/openshell.md name the 0443aec3 boundary, the label
  selection, and the access policy from ate-env's README step 1.
@sunnylovestiramisu

Copy link
Copy Markdown
Collaborator

Two issues:

  1. Delete now waits on a full durable snapshot upload (main issue). internal/ate/client.go Delete() calls c.Suspend() first, because Substrate only deletes suspended actors. Suspend is now always synchronous. So every delete (environment teardown, swebench cleanup and so on) waits for a snapshot to reach object storage and then deletes it straight away.
  • Fix: split the call so only Suspend uses SYNCHRONOUS. Delete should use ASYNCHRONOUS or the default, for example through a private suspend(ctx, …, mode) helper.
  • Test: add one to TestDelete using the new SuspendModes recorder.
  1. The default pool name can be too long for a label value. The pool name is used as the value of the ate-env/workerpool label, and label values are limited to 63 characters, while WorkerPool names can be up to 253. With the default -workerpool, any template name over 52 characters produces an invalid label, and the error won't be obvious. Validate the length in both manifest and manifest template, or document the limit.

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.

2 participants