carlos / platform Public

zdd-readiness: final review round 1, one definition of the claim containment name

Merge item 8: internal/cgroup's retaining setup recognised claim containment groups by a hand copy of internal/host's claim-<hex>.local format, and it runs flag off. The format now lives in internal/cgroup (ClaimContainmentName, IsClaimContainment, platform-neutral); internal/host builds its names with it, and a host test pins that every name it makes reads as a claim containment there, as a host name and as its exec cgroup's name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 9e1428d2ee73d49366eb76d0d4efa49e26807618 parent ccf0d31
4 files changed, +64 −11
  • internal/cgroup/cgroup.go +26 −0
  • internal/cgroup/recreate_linux.go +2 −10
  • internal/host/claimcontainment_name_test.go +35 −0
  • internal/host/claimroleassembly.go +1 −1
diff --git a/internal/cgroup/cgroup.go b/internal/cgroup/cgroup.go
index 2266b79e5..55fad4bb8 100644
--- a/internal/cgroup/cgroup.go
+++ b/internal/cgroup/cgroup.go
@@ -43,6 +43,32 @@ func IsExecName(name string) bool {
return strings.HasPrefix(name, execPrefix) && len(name) > len(execPrefix)
}
+// The claim containment groups' host names: claim-<id>.local, where id is
+// the hex digest internal/host derives from the claim's fence target. This
+// is the ONE definition of the format (final review round 1, merge item 8):
+// internal/host builds names with ClaimContainmentName, and the retaining
+// setup (SetupRetaining), which runs flag off too, recognises them with
+// IsClaimContainment, so the two cannot drift apart.
+const (
+ claimContainmentPrefix = "claim-"
+ claimContainmentSuffix = ".local"
+)
+
+// ClaimContainmentName is the containment group host name for a claim whose
+// identity digest is id (hex).
+func ClaimContainmentName(id string) string {
+ return claimContainmentPrefix + id + claimContainmentSuffix
+}
+
+// IsClaimContainment reports whether name is a claim containment group's:
+// its host name (ClaimContainmentName) or its exec cgroup's directory name
+// (ExecName of one).
+func IsClaimContainment(name string) bool {
+ host := strings.TrimPrefix(name, execPrefix)
+ return strings.HasPrefix(host, claimContainmentPrefix) && strings.HasSuffix(host, claimContainmentSuffix) &&
+ len(host) > len(claimContainmentPrefix)+len(claimContainmentSuffix)
+}
+
// Limit is what Start writes into a host's cgroup before the child lands
// in it. MemoryMax is bytes; zero means "write nothing" — the pre-spec
// behaviour for a caller with no tier. memory.high is derived (90% of
diff --git a/internal/cgroup/recreate_linux.go b/internal/cgroup/recreate_linux.go
index affd524d5..ec730ff40 100644
--- a/internal/cgroup/recreate_linux.go
+++ b/internal/cgroup/recreate_linux.go
@@ -236,7 +236,7 @@ func refuseKilledChild(parent *Prepared, name string) error {
// the first start into it makes it fresh. Being marked costs an empty
// cgroup only a recreation. A directory that holds a process, or whose
// population cannot be read, is never marked: removing it is not ours to
-// do. The claim containment groups (carlos-exec@claim-<id>.local, unique
+// do. The claim containment groups (IsClaimContainment: carlos-exec@claim-<id>.local, unique
// to one controller) are left alone: they are the retained evidence the
// retaining mode exists to keep, and nothing starts into them again.
func (m *Manager) seedKilled() {
@@ -246,7 +246,7 @@ func (m *Manager) seedKilled() {
}
seeded := 0
for _, e := range entries {
- if !e.IsDir() || !IsExecName(e.Name()) || isClaimContainment(e.Name()) {
+ if !e.IsDir() || !IsExecName(e.Name()) || IsClaimContainment(e.Name()) {
continue
}
dir := filepath.Join(m.root, e.Name())
@@ -295,11 +295,3 @@ func seedIfEmpty(dir string) bool {
markKilled(id)
return true
}
-
-// isClaimContainment reports whether an exec cgroup name is a claim
-// containment group's: carlos-exec@claim-<hex>.local, as
-// internal/host's claimContainmentName makes them.
-func isClaimContainment(name string) bool {
- host := strings.TrimPrefix(name, execPrefix)
- return strings.HasPrefix(host, "claim-") && strings.HasSuffix(host, ".local")
-}
diff --git a/internal/host/claimcontainment_name_test.go b/internal/host/claimcontainment_name_test.go
new file mode 100644
index 000000000..4c498bc60
--- /dev/null
+++ b/internal/host/claimcontainment_name_test.go
@@ -0,0 +1,35 @@
+package host
+
+import (
+ "testing"
+
+ "github.com/carlosframework/platform/internal/cgroup"
+ "github.com/carlosframework/platform/internal/hostguard"
+)
+
+// Final review round 1, merge item 8: internal/cgroup's retaining setup
+// leaves claim containment groups alone (it seeds and sweeps around them,
+// flag off included), and it knows them only by their name. The name's
+// format has one definition, in internal/cgroup, and every name this
+// package makes must read as one there, both as the containment's host name
+// and as its exec cgroup's directory name. A plain host never does.
+func TestClaimContainmentNamesAreRecognisedByTheCgroupPackage(t *testing.T) {
+ for _, target := range []hostguard.FenceTarget{
+ {},
+ {Host: "a.example.com", Incarnation: "inc-1", Stamp: 3, Session: 9, Box: "box-1", Enrollment: "e", BootID: "boot", ControllerID: "ctl"},
+ {Host: "claim-x.local", Incarnation: "inc-2", Stamp: 1, Session: 1, Box: "box-2"},
+ } {
+ name := claimContainmentName(target)
+ if !cgroup.IsClaimContainment(name) {
+ t.Fatalf("cgroup.IsClaimContainment(%q) = false for a claim containment name", name)
+ }
+ if !cgroup.IsClaimContainment(cgroup.ExecName(name)) {
+ t.Fatalf("cgroup.IsClaimContainment(%q) = false for its exec cgroup", cgroup.ExecName(name))
+ }
+ }
+ for _, plain := range []string{"a.example.com", cgroup.ExecName("a.example.com"), "claim-a.example.com", "x.local"} {
+ if cgroup.IsClaimContainment(plain) {
+ t.Fatalf("cgroup.IsClaimContainment(%q) = true for a name that is not a claim containment's", plain)
+ }
+ }
+}
diff --git a/internal/host/claimroleassembly.go b/internal/host/claimroleassembly.go
index 5946bcc55..b5764512e 100644
--- a/internal/host/claimroleassembly.go
+++ b/internal/host/claimroleassembly.go
@@ -38,7 +38,7 @@ func claimContainmentName(target hostguard.FenceTarget) string {
}{target.Host, target.Incarnation, target.Stamp, target.Session, target.Box, target.Enrollment, target.BootID, target.ControllerID}
raw, _ := json.Marshal(identity)
sum := sha256.Sum256(raw)
- return "claim-" + hex.EncodeToString(sum[:24]) + ".local"
+ return cgroup.ClaimContainmentName(hex.EncodeToString(sum[:24])) // the one format (merge item 8)
}
// launchTarget binds the observed session to this controller's verified tuple.