carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package appconfig
2
3import "strings"
4
5// Agent-owned vars (parent spec §7.3): CARLOS_PURGE is set by the platform
6// when the box has a cache and REMOVED when it does not — the removal half
7// is load-bearing, since the env layers are tenant-supplied and a tenant
8// advertising a purge channel that does not exist would have apps skip
9// their own invalidation and serve stale content indefinitely.
10// CARLOS_CONTROL_SOCKET is stripped for the stronger reason: a
11// tenant-chosen socket path is a name the agent never vouched for. This
12// mirrors the exec backend's withoutVars (internal/activator/backend_exec.go);
13// the two lists must not drift.
14//
15// The sync appends CARLOS_PURGE=header UNCONDITIONALLY because cache
16// construction is unconditional in carlos agent (internal/host/agent.go,
17// edge.NewCache at startup) — every box this sync runs on serves through
18// that cache. The day the cache grows an off switch, this must learn to
19// read it.
20func agentOwned(name string) bool {
21 return name == "CARLOS_PURGE" || name == "CARLOS_CONTROL_SOCKET"
22}
23
24// applyAgentVars rewrites one rendered env file: tenant-supplied
25// agent-owned vars are dropped and the agent's own CARLOS_PURGE=header is
26// appended last (last assignment wins under systemd EnvironmentFile, so
27// even a hand-staged earlier line could not override it — but we strip
28// those anyway). Deterministic and idempotent, so syncHost's bytes.Equal
29// convergence check still short-circuits the steady state.
30//
31// RenderEnv (materialize.go) emits exactly one `KEY=value\n` line per var,
32// keys sorted, and nothing else — no comments, no blank lines — so dropping
33// blank lines here is a no-op against its actual output; it's kept because a
34// transformation over line-oriented KEY=value content should not depend on
35// its input never containing one.
36func applyAgentVars(rendered []byte) []byte {
37 var out strings.Builder
38 for _, line := range strings.Split(string(rendered), "\n") {
39 s := strings.TrimSpace(line)
40 if s == "" {
41 continue
42 }
43 if name, _, ok := strings.Cut(s, "="); ok && agentOwned(strings.TrimSpace(name)) {
44 continue
45 }
46 out.WriteString(line)
47 out.WriteByte('\n')
48 }
49 out.WriteString("CARLOS_PURGE=header\n")
50 return []byte(out.String())
51}
52