| index 63f39416b..9bbc96be4 100644 |
| --- a/internal/activator/activator.go |
| +++ b/internal/activator/activator.go |
| @@ -2466,7 +2466,7 @@ func (a *Service) doWake(ctx context.Context, e *actEntry) (*wokenInstance, erro |
| ident release.StagedIdentity |
| pend pendingGeneration |
| ) |
| - env := workerEnv(a.agentSocketFor(rt), host, token) |
| + env := workerEnv(a.agentSocketFor(rt), host, token, rt.DBPath) |
| if plan.planned() { |
| // A planned worker (zero-downtime spec §6.5): the named build, |
| // behind planGate at each exec, with startWorker's publication |
| @@ -3330,19 +3330,26 @@ func (a *Service) agentSocketFor(rt registry.Route) string { |
| } |
| |
| // workerEnv is what a spawn hands the child: where to call back, who it is, |
| -// and this incarnation's credential. The backend applies it OVER the tenant's |
| -// own env file so a tenant cannot forge its own token (StartWorker's |
| -// contract). A free function of plain strings, not a method on the entry, so |
| -// the two callers — the wake (off-lock, with a token still in a local) and the |
| -// crash restart (under a.mu) — both compose it without touching entry state |
| -// they don't own. |
| -func workerEnv(socket, host, token string) map[string]string { |
| +// this incarnation's credential, and where its database is. The backend |
| +// applies it OVER the tenant's own env file so a tenant cannot forge its own |
| +// token (StartWorker's contract). A free function of plain strings, not a |
| +// method on the entry, so the two callers — the wake (off-lock, with a token |
| +// still in a local) and the crash restart (under a.mu) — both compose it |
| +// without touching entry state they don't own. |
| +// |
| +// db is the row's DBPath, handed over as CARLOS_SIDECAR_DB (sidecar |
| +// isolation D4) for flat and nested workers alike: a worker opens its |
| +// database there and nowhere else. One that computes /data/<host>.db itself |
| +// stops working the moment its row is nested, where /data is a read-only |
| +// tmpfs in the namespace. |
| +func workerEnv(socket, host, token, db string) map[string]string { |
| name, _, _ := strings.Cut(host, ".") // the sidecar's declared name |
| return map[string]string{ |
| "CARLOS_AGENT_SOCKET": socket, |
| "CARLOS_SIDECAR_TOKEN": token, |
| "CARLOS_SIDECAR_HOST": host, |
| "CARLOS_SIDECAR_NAME": name, |
| + "CARLOS_SIDECAR_DB": db, |
| } |
| } |
| |
| @@ -3638,7 +3645,7 @@ func (a *Service) respawnWorkerLocked(e *actEntry, stopOld Proc, why string, ont |
| if refused == nil { |
| // No registry write (spec §7.9): see doWake. |
| if tok, err = newWorkerToken(); err == nil { |
| - proc, ident, pend, err = a.startWorker(ctx, rt, workerEnv(a.agentSocketFor(rt), host, tok), onto, gate) |
| + proc, ident, pend, err = a.startWorker(ctx, rt, workerEnv(a.agentSocketFor(rt), host, tok, rt.DBPath), onto, gate) |
| } |
| } |
| cancel() |