Skip to content

Releases: latere-ai/cella

v0.22.3

Choose a tag to compare

@github-actions github-actions released this 30 Oct 00:24

Fixed

  • On Kubernetes, a sandbox can write to its home directory. The root
    file system is read only, so a tool that writes under HOME, such as
    npm install -g or Claude Code saving its settings, failed with
    ENOENT or EROFS. HOME is now the workspace unless spec.env sets
    it, as on the native runtime, and what is written there survives a
    restart. A sandbox started before this keeps the image's home until its
    next start. Every sandbox now has a Secret, which holds at least that
    path, since the Pod reads each of its variables from the sandbox's
    Secret.
  • An update that changes the boundary of a sandbox on the local runtime
    reaches it.
    The local runtime enforces the boundary with its own proxy,
    and it kept the boundary the sandbox was created with, so an update that
    narrowed the allow list was reported as enforced while commands still
    reached the hosts it removed. Every command started after the update now
    gets the new boundary; a process already running keeps its own until the
    next start. An update the runtime does not take fails and changes
    nothing.

v0.22.2

Choose a tag to compare

@github-actions github-actions released this 29 Oct 23:06

Fixed

  • A streamed answer reaches an HTTP/1.1 workload with its end marked.
    When the gateway substituted into a request whose destination streamed
    its answer over HTTP/2, as a model's is, a workload that spoke HTTP/1.1
    read the whole stream and then waited forever for the connection to
    close. Claude Code hung on its first request this way. The stream is
    now sent chunked, and the connection serves the next request.

v0.22.1

Choose a tag to compare

@github-actions github-actions released this 29 Oct 20:54

Fixed

  • A request the gateway substitutes into answers in the protocol the
    workload spoke.
    When the gateway reached the destination over HTTP/2,
    a workload that spoke HTTP/1.1 read a status line naming HTTP/2.0.
    curl read it; Bun, and so Claude Code, refused it as a connection error,
    so Claude Code could not reach a model through a mounted secret.

v0.22.0

Choose a tag to compare

@github-actions github-actions released this 29 Oct 15:50

Added

  • make run can leave its ports to the kernel. CELLA_RUN_PORT=0 make run starts cellad on two ports the kernel picks, so a script or
    a test never chooses a port that another process takes before cellad
    binds it. The stack prints the URL as before and writes the addresses
    cellad bound to out/run/cellad.addrs, one role and its address per
    line, the way the stubs' go to out/run/stubs.addrs.

Changed

  • The egress gateway connects only to public addresses. It judges the
    address each connection dials, after the name resolved, on both doors
    and for a request it substitutes a secret into, so a name that resolves
    to a private, loopback, link-local, carrier-grade NAT or unique local
    address is refused like the address written out. The workload is
    answered 403, and the connection record says NonPublicAddress; a
    request refused inside a tunnel the gateway terminates is recorded on
    its own, beside the tunnel. An installation whose sandboxes reach a
    host on its own network, such as a registry, a mirror or an OAuth token
    endpoint, names those ranges in CELLA_EGRESS_PRIVATE_RANGES on the
    gateway; without it, those connections are now refused. A range that
    reaches loopback, link-local or the unspecified address stops the
    gateway at start, since no boundary admits those.
  • The reverse door reads a port. A destination written as
    host:port in the first path segment is decided by its host, refused
    before any dial when that host is an address no boundary admits, and
    dialed and recorded at the port it names. Before, the port was part of
    the host the boundary read, and the record said 443 whatever was
    dialed.
  • The control plane's host is decided by the boundary like any other.
    The gateway no longer refuses every connection to the host in
    CELLA_URL. An installation that serves the control plane on a host it
    shares with other services, under one API host, left its sandboxes
    unable to reach any of them; a sandbox now reaches that host when its
    boundary admits it. The ControlPlane reason no longer appears in
    connection records. The cella client still reads no proxy variable,
    so a sandbox's own token never passes through the gateway.
  • The driver suite holds the ports it names. runtimetest reserves
    each port a case hands a sandbox's server, on a loopback socket of the
    host that never listens, from the moment it picks the port until the
    case ends, so no other process the machine runs takes it first. Where a
    sandbox shares the host's network, as a native one does,
    Options.Echo and Options.Listen bind the port with SO_REUSEPORT:
    a command that binds the port on loopback without it is refused, and on
    Linux one that binds it on every address is too. A sandbox with a
    network of its own binds as before.

Fixed

  • A secret mounted on a workload that exists reaches its environment.
    An owner who added a secret to a workload by an update had its value in
    the gateway at once, but the placeholder never reached the workload's
    environment, not even after a restart. The driver now records the new
    environment, and the workload has the placeholder from its next start;
    a running process keeps the environment it started with. The same holds
    when a secret's inject moves to another header or query parameter,
    which changes its <env>_HEADER or <env>_QUERY companion. A driver
    that did not take the new environment, such as a worker that was not
    connected, fails no apply: the next apply or secret change hands it
    again.
  • A secret mounted by its sec_ id keeps its placeholder. Each
    rotation, and each apply, gave such a mount a new placeholder in the
    gateway's map, while the workload kept the one it started with, so the
    secret stopped being substituted after its first rotation.
  • An update that fails after its map reached the gateway puts the old
    map back.
    An update refused by the driver, or one whose write failed,
    left the gateway holding the map it asked for while the workload stayed
    as it was. The gateway now holds the map the workload has, with the
    placeholders it holds.
  • make run no longer reads the last run's addresses. A restart over
    the kept state directory could read the stubs' addresses of the run
    before, a moment before the new stubs wrote theirs, and start cellad
    against an issuer that was gone.

v0.21.1

Choose a tag to compare

@github-actions github-actions released this 22 Oct 07:04

Fixed

  • A sandbox created right after its worker registers waits for the
    worker's stream.
    An environment reads Ready from the moment a
    worker's registration is answered, a moment before the worker opens its
    stream, and a sandbox created on it in between failed with
    CreateFailed. It now stays Pending until the stream opens and then
    runs. The control plane logs a worker's stream opened, with the
    worker's id, each time a stream opens, since a registration alone
    already counts in status.workers.

v0.21.0

Choose a tag to compare

@github-actions github-actions released this 22 Oct 03:00

Added

  • A device's network can be any: any public host but those you
    block.
    Beside allowlist and none, the host policy of latere devices takes network.mode: any with a network.blocked list of
    hosts: a host, an address or *.example.com for the names below
    example.com (not example.com itself, so block both), alone or as
    host:port. With it, everything readable in a granted folder can be
    sent to any public host, and the connect screen, its facts and a notice
    at every start say so. Whatever a name resolves to, a command still
    reaches nothing on your computer, its Wi-Fi and Ethernet networks, or
    any address that is not public. network.hosts under any names a
    port beyond 443 and 80 as host:port. any is never the default, and
    ProposePolicy never proposes it: a connect query asking for it is
    refused, and a file that had it proposes the allow list of the default
    hosts again. It is enforced by macOS's own sandbox alone; elsewhere, and
    in a program that does not call hostsandbox.Main, a connect, a change
    or a start that names it is refused with the new code
    device_network_unenforceable, never run as another network. cellad
    takes the same as CELLA_LOCAL_NETWORK=any with CELLA_LOCAL_BLOCKED.
  • A refused connection is told. Each host a session's command is
    refused, by this computer's network or the session's own, reaches every
    subscriber of the engine as an EventNetworkRefused and the activity
    log as a network_refused line, with the host and port and the session,
    agent and sandbox it came from, never the request. A command repeating
    a refusal is told once a minute. latere devices prints the line, and
    GET /v1/approvals?follow=1 carries the event.
  • A refused host can be allowed for one session, or saved.
    Engine.AllowSessionHost(ctx, session, host, port) lets that session's later
    commands reach the host, without changing the host policy file, until
    the session's sandbox stops or is deleted, or the engine stops, pauses
    or reloads. Engine.SaveHost(host, port) writes it into the policy, and
    every session's next command reaches it at once, with no restart, so no
    running session stops. A command that runs keeps the network it started
    with: the host reaches the next one. Under any, an allowance lifts the
    policy's own block of the host by name; a host a *. entry blocks is
    refused with the new code device_host_not_allowed, as is a network of
    none. The control socket answers both as POST /v1/sessions/{session}/hosts and POST /v1/policy/hosts with {"host", "port"}; an unknown session is 404 no_session. Each allowance is a
    host_allowed or host_saved line in the activity log.
  • For embedders: local.Options takes OnRefused, Allowed and
    Isolation; local.Network takes Blocked; local.HostEntry builds
    the entry a host and port are allowed as, and local.Network.Allow
    saves one. An embedder that shows its own words keys the new connect
    fact network_ports, and the codes above.
  • The manifest's host network has an open mode. A worker whose
    computer admits any public host registers {"mode": "open", "blocked": [...]} in status.hosts. A sandbox asking open there gets open
    denying what it or the host blocks, one asking allowlist keeps the
    hosts the host does not block, and a local driver that declares open
    holds that deny list itself, with no gateway. The control plane must
    run this release before a computer serves any: an older one narrows
    every sandbox on such a computer to no network.

Changed

  • latere.ai/x/pkg v0.109.0. Under macOS's own sandbox every command now
    starts from its launcher, one with no network included, so a program
    embedding the engine or the local runtime calls hostsandbox.Main as
    the first statement of main (latere and Latere Studio do), and a
    test binary that uses Seatbelt calls it in TestMain.
  • A command started in a sandbox gets the computer's network as it is
    now: a sandbox started again after its computer narrowed its network
    gets the narrower one, where before it kept the network it was created
    with.

v0.20.4

Choose a tag to compare

@github-actions github-actions released this 21 Oct 22:15

Fixed

  • device.Forget with dropFile deletes a host policy file that names no
    device. When latere devices remove removed the computer while
    latere devices connect was serving it, the serving engine saw the
    removal first and cleared the device from the file, and the file then
    stayed with its folders, though removing says it deletes the file.

v0.20.3

Choose a tag to compare

@github-actions github-actions released this 21 Oct 21:18

Fixed

  • On macOS, a command cannot get around a denial through a folder.
    Through latere.ai/x/pkg v0.108.0, a command in a sandbox cannot clone
    a folder, which would copy files it may not read into a copy it may;
    cannot rename, swap or remove the folders between a granted folder and
    a path denied inside it; and cannot create one of those folders that is
    missing, so it cannot plant a denied path under a name it controls. A
    granted folder with a long path, about 255 bytes or more, now runs
    commands; before, each one exited 65.
  • A device creates ~/.config and ~/.docker before it serves a
    folder above your home directory.
    Each holds a path the sandbox
    always denies, ~/.config/gcloud and ~/.docker/config.json, so under
    the rule above a session granted that folder could not create either,
    and a tool that keeps its settings in one would fail. The engine that
    latere devices and an application embedding latere.ai/x/cella/device
    run now creates each one that is missing, mode 0700, before it serves a
    writable grant of a folder above your home directory. A name already
    there, a link or a file included, is left as it is. A create that fails
    stops the engine with the new code device_home_folder_failed, whose
    detail names the folder and the cause; an embedder that shows its own
    words adds a sentence for it. Your home directory itself is still
    refused as a grant.

v0.20.2

Choose a tag to compare

@github-actions github-actions released this 21 Oct 17:36

Fixed

  • A worker replaced before its stream opened now stops. On an
    environment with spec.workers.max, a registration with the same key
    from the same host that replaced a worker which had registered but not
    yet opened its stream left that worker uninformed: its stream was
    refused as one that never registered, so it registered again and took
    the place back from its replacement. Its stream is now closed with
    worker_replaced as soon as it opens, as a live worker's is, and Run
    returns. A stream that opened before its key was revoked or its
    environment deleted, and said hello after, is closed with key_revoked
    or serve_refused the same way.

v0.20.1

Choose a tag to compare

@github-actions github-actions released this 21 Oct 15:03

Added

  • device.PathsFrom(lookup) resolves the paths device.DefaultPaths
    does, with the XDG and LATERE_* variables read through lookup
    instead of the process's environment, for an application the desktop
    starts that reads them from the person's login shell.

Fixed

  • Built with Go 1.27.3, which fixes GO-2026-6809, a flaw in the
    standard library's certificate verification that this code can reach.