carlos / platform Public

WIP checkpoint (not for merge): claim Plan 14 track E checkpoint 24

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev 980d85158255ab0dc54b0c1c6568be277bd7d150 parent ebff275
15 files changed, +1181 −12
  • internal/host/plan14_generation_census_kernel_linux_test.go +41 −0
  • internal/host/plan14_generation_census_root_linux_test.go +81 −0
  • internal/host/plan14_generation_inventory_process_test.go +63 −0
  • internal/host/plan14_generation_inventory_root_test.go +122 −0
  • internal/host/plan14_generation_inventory_test.go +278 −0
  • internal/host/rootgeneration_census_linux.go +84 −0
  • internal/host/rootgeneration_census_other.go +12 −0
  • internal/host/rootgeneration_inventory.go +222 −0
  • internal/host/rootgenerationpins.go +7 −7
  • internal/hostbox/generationinventory.go +74 −0
  • internal/hostbox/plan14_generation_inventory_test.go +73 −0
  • internal/hostguard/generationinventory.go +46 −0
  • internal/hostguard/plan14_generation_inventory_test.go +55 −0
  • internal/provision/plan9_b8_census_test.go +1 −0
  • internal/provision/testdata/plan14-root-reads-e.tsv +22 −5

CI passed — run details

CI log
=== gate ===
go: downloading github.com/aws/aws-sdk-go-v2 v1.44.0
go: downloading github.com/aws/aws-sdk-go-v2/config v1.32.6
go: downloading github.com/aws/aws-sdk-go-v2/service/route53 v1.64.1
go: downloading github.com/benbjohnson/litestream v0.5.14
go: downloading github.com/aws/aws-sdk-go-v2/service/ec2 v1.324.0
go: downloading github.com/aws/aws-sdk-go-v2/service/acm v1.45.0
go: downloading github.com/aws/aws-sdk-go-v2/service/sns v1.43.0
go: downloading github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.68.0
go: downloading modernc.org/sqlite v1.55.0
go: downloading github.com/aws/aws-sdk-go-v2/service/iam v1.58.2
go: downloading github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.37.0
go: downloading github.com/superfly/ltx v0.5.1
go: downloading github.com/aws/aws-sdk-go-v2/service/s3 v1.105.0
go: downloading github.com/aws/aws-sdk-go-v2/service/sts v1.45.6
go: downloading github.com/aws/smithy-go v1.28.1
go: downloading golang.org/x/crypto v0.52.0
go: downloading github.com/oschwald/maxminddb-golang v1.13.1
go: downloading github.com/aws/aws-sdk-go-v2/credentials v1.19.6
go: downloading golang.org/x/sys v0.46.0
go: downloading github.com/klauspost/compress v1.18.0
go: downloading github.com/aws/aws-sdk-go-v2/service/sesv2 v1.66.6
go: downloading golang.org/x/net v0.55.0
go: downloading github.com/pion/logging v0.2.4
go: downloading github.com/pion/stun/v3 v3.0.1
go: downloading github.com/pion/turn/v4 v4.1.4
go: downloading github.com/aws/aws-sdk-go-v2/service/costexplorer v1.67.5
go: downloading github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16
go: downloading github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4
go: downloading github.com/aws/aws-sdk-go-v2/service/signin v1.0.4
go: downloading github.com/aws/aws-sdk-go-v2/service/sso v1.30.8
go: downloading github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12
go: downloading github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.40
go: downloading github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.38
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.40
go: downloading github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23
go: downloading github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31
go: downloading github.com/pion/randutil v0.1.0
go: downloading github.com/pion/transport/v4 v4.0.1
go: downloading github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.40
go: downloading github.com/pierrec/lz4/v4 v4.1.22
go: downloading github.com/wlynxg/anet v0.0.5
go: downloading github.com/prometheus/client_golang v1.17.0
go: downloading golang.org/x/sync v0.21.0
go: downloading github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.20.18
go: downloading github.com/mattn/go-isatty v0.0.20
go: downloading github.com/lmittmann/tint v1.1.3
go: downloading github.com/cespare/xxhash/v2 v2.3.0
go: downloading github.com/prometheus/procfs v0.12.0
go: downloading github.com/prometheus/client_model v0.5.0
go: downloading github.com/beorn7/perks v1.0.1
go: downloading github.com/prometheus/common v0.45.0
go: downloading google.golang.org/protobuf v1.36.10
go: downloading github.com/pion/transport/v3 v3.0.8
go: downloading github.com/pion/dtls/v3 v3.0.7
go: downloading github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0
go: downloading golang.org/x/text v0.37.0
go: downloading modernc.org/libc v1.74.1
go: downloading modernc.org/memory v1.11.0
go: downloading github.com/dustin/go-humanize v1.0.1
go: downloading github.com/google/uuid v1.6.0
go: downloading modernc.org/mathutil v1.7.1
go: downloading github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec
cd launchctx && go vet ./... && go test ./... -count=1
ok  	amadan.net/carlos/platform.git/launchctx	0.012s
?   	amadan.net/carlos/platform.git/launchctx/controlname	[no test files]
?   	amadan.net/carlos/platform.git/launchctx/wireid	[no test files]
go vet ./...
gofmt -l .: clean
go test ./... -count=1 -timeout 30m
ok  	github.com/carlosframework/platform	355.664s
?   	github.com/carlosframework/platform/cmd/changelog	[no test files]
ok  	github.com/carlosframework/platform/cmd/console	3.209s
ok  	github.com/carlosframework/platform/cmd/moveprobe	93.370s
ok  	github.com/carlosframework/platform/cmd/zddprobe	0.709s
ok  	github.com/carlosframework/platform/internal/activator	234.726s
ok  	github.com/carlosframework/platform/internal/agentsock	0.022s
ok  	github.com/carlosframework/platform/internal/alerting	0.005s
ok  	github.com/carlosframework/platform/internal/analytics	0.021s
ok  	github.com/carlosframework/platform/internal/appconfig	2.370s
ok  	github.com/carlosframework/platform/internal/apperr	0.082s
ok  	github.com/carlosframework/platform/internal/applog	0.136s
ok  	github.com/carlosframework/platform/internal/awsinv	0.005s
ok  	github.com/carlosframework/platform/internal/boxchoice	0.008s
ok  	github.com/carlosframework/platform/internal/boxid	0.739s
?   	github.com/carlosframework/platform/internal/boxid/boxidtest	[no test files]
?   	github.com/carlosframework/platform/internal/boxid/internal/signtest	[no test files]
ok  	github.com/carlosframework/platform/internal/boxvolumes	0.008s
ok  	github.com/carlosframework/platform/internal/caps	0.012s
ok  	github.com/carlosframework/platform/internal/certwarm	0.002s
ok  	github.com/carlosframework/platform/internal/cgroup	0.703s
ok  	github.com/carlosframework/platform/internal/changelog	0.313s
ok  	github.com/carlosframework/platform/internal/clamd	0.055s
?   	github.com/carlosframework/platform/internal/cliflag	[no test files]
ok  	github.com/carlosframework/platform/internal/console	367.716s
?   	github.com/carlosframework/platform/internal/controlname	[no test files]
?   	github.com/carlosframework/platform/internal/controlsock	[no test files]
ok  	github.com/carlosframework/platform/internal/dbdoor	6.404s
ok  	github.com/carlosframework/platform/internal/dbdoor/dbdoortest	0.010s
ok  	github.com/carlosframework/platform/internal/dbverify	0.005s
ok  	github.com/carlosframework/platform/internal/dnsrec	0.003s
ok  	github.com/carlosframework/platform/internal/docsite	0.005s
ok  	github.com/carlosframework/platform/internal/domains	2.324s
ok  	github.com/carlosframework/platform/internal/doorkey	0.006s
ok  	github.com/carlosframework/platform/internal/economics	0.007s
ok  	github.com/carlosframework/platform/internal/edge	26.704s
?   	github.com/carlosframework/platform/internal/edgeproof	[no test files]
ok  	github.com/carlosframework/platform/internal/edgesfile	0.008s
ok  	github.com/carlosframework/platform/internal/fleetapi	0.146s
ok  	github.com/carlosframework/platform/internal/gate	1.656s
ok  	github.com/carlosframework/platform/internal/genselect	0.019s
ok  	github.com/carlosframework/platform/internal/geo	0.018s
ok  	github.com/carlosframework/platform/internal/geoip	0.033s
ok  	github.com/carlosframework/platform/internal/historyreadback	0.186s
ok  	github.com/carlosframework/platform/internal/host	136.501s
ok  	github.com/carlosframework/platform/internal/hostactors	0.284s
ok  	github.com/carlosframework/platform/internal/hostbox	2.252s
ok  	github.com/carlosframework/platform/internal/hostclaim	0.564s
ok  	github.com/carlosframework/platform/internal/hostevidence	0.006s
ok  	github.com/carlosframework/platform/internal/hostexec	5.505s
ok  	github.com/carlosframework/platform/internal/hostfence	0.036s
ok  	github.com/carlosframework/platform/internal/hostfiles	10.799s
ok  	github.com/carlosframework/platform/internal/hostfloor	0.016s
ok  	github.com/carlosframework/platform/internal/hostguard	1.007s
ok  	github.com/carlosframework/platform/internal/hostops	1.522s
?   	github.com/carlosframework/platform/internal/hostops/fencerelease	[no test files]
ok  	github.com/carlosframework/platform/internal/hostops/internal/fencerelease	0.002s
ok  	github.com/carlosframework/platform/internal/hostquarantine	0.002s
ok  	github.com/carlosframework/platform/internal/hostrelocate	0.480s
ok  	github.com/carlosframework/platform/internal/hostresolve	0.144s
ok  	github.com/carlosframework/platform/internal/hostwrite	0.002s
ok  	github.com/carlosframework/platform/internal/infraview	0.005s
ok  	github.com/carlosframework/platform/internal/instancectl	1.821s
ok  	github.com/carlosframework/platform/internal/instanceexec	2.723s
ok  	github.com/carlosframework/platform/internal/instancefs	0.004s
ok  	github.com/carlosframework/platform/internal/instancekey	0.002s
ok  	github.com/carlosframework/platform/internal/instanceupdates	0.011s
ok  	github.com/carlosframework/platform/internal/layout	1.469s
ok  	github.com/carlosframework/platform/internal/lease	9.499s
ok  	github.com/carlosframework/platform/internal/lease/leasetest	0.006s
ok  	github.com/carlosframework/platform/internal/ledger	0.013s
ok  	github.com/carlosframework/platform/internal/mail	0.187s
ok  	github.com/carlosframework/platform/internal/maintenance	0.085s
ok  	github.com/carlosframework/platform/internal/maintenanceexec	5.543s
ok  	github.com/carlosframework/platform/internal/maintenanceguard	0.075s
ok  	github.com/carlosframework/platform/internal/metrics	0.005s
ok  	github.com/carlosframework/platform/internal/moves	21.583s
ok  	github.com/carlosframework/platform/internal/moves/archive	0.791s
ok  	github.com/carlosframework/platform/internal/objstore	0.163s
ok  	github.com/carlosframework/platform/internal/ops	0.178s
ok  	github.com/carlosframework/platform/internal/park	0.203s
ok  	github.com/carlosframework/platform/internal/privatefile	0.003s
ok  	github.com/carlosframework/platform/internal/provision	33.826s
ok  	github.com/carlosframework/platform/internal/publicrelease	0.007s
?   	github.com/carlosframework/platform/internal/regionname	[no test files]
ok  	github.com/carlosframework/platform/internal/registry	4.298s
ok  	github.com/carlosframework/platform/internal/relay	7.289s
ok  	github.com/carlosframework/platform/internal/release	22.919s
ok  	github.com/carlosframework/platform/internal/rollout	3.838s
ok  	github.com/carlosframework/platform/internal/rolloutwords	0.004s
ok  	github.com/carlosframework/platform/internal/rootaws	0.008s
ok  	github.com/carlosframework/platform/internal/rootparticipation	0.007s
ok  	github.com/carlosframework/platform/internal/rootstate	0.025s
ok  	github.com/carlosframework/platform/internal/s3compat	0.005s
ok  	github.com/carlosframework/platform/internal/safefile	0.004s
ok  	github.com/carlosframework/platform/internal/schedule	2.311s
ok  	github.com/carlosframework/platform/internal/sim/hostlife	11.810s
ok  	github.com/carlosframework/platform/internal/sim/litestreamfacts	3.997s
ok  	github.com/carlosframework/platform/internal/status	0.042s
ok  	github.com/carlosframework/platform/internal/steering	0.006s
ok  	github.com/carlosframework/platform/internal/stopevidence	0.252s
ok  	github.com/carlosframework/platform/internal/svcrole	0.002s
ok  	github.com/carlosframework/platform/internal/telemetry	0.004s
ok  	github.com/carlosframework/platform/internal/termfence	0.004s
ok  	github.com/carlosframework/platform/internal/tunnelclient	0.005s
ok  	github.com/carlosframework/platform/internal/unixdial	0.002s
ok  	github.com/carlosframework/platform/internal/updatewords	0.004s
ok  	github.com/carlosframework/platform/internal/usage	0.005s
ok  	github.com/carlosframework/platform/internal/version	0.002s
ok  	github.com/carlosframework/platform/internal/vet	1.633s
=== cross ===
--- shard 0 of 5 ---
cross-compiling darwin/arm64
go: downloading github.com/ncruces/go-strftime v1.0.0
--- shard 1 of 5 ---
cross-compiling darwin/amd64
go: downloading github.com/ncruces/go-strftime v1.0.0
--- shard 2 of 5 ---
cross-compiling linux/arm64
--- shard 3 of 5 ---
cross-compiling windows/amd64
go: downloading github.com/ncruces/go-strftime v1.0.0
--- shard 4 of 5 ---
cross-compiling windows/arm64
go: downloading github.com/ncruces/go-strftime v1.0.0
=== minio-contract ===
minio contract: arm64, minio RELEASE.2025-09-07T16-13-09Z, mc RELEASE.2025-08-13T08-35-41Z
  minio: cached, digest verified
  mc: cached, digest verified
  minio healthy on 127.0.0.1:20999
Added `local` successfully.
Bucket created successfully `local/contract-bucket`.
Bucket created successfully `local/denied-bucket`.
Created policy `contract-only` successfully.
Added user `scopeduser` successfully.
Attached Policies: [contract-only]
To User: scopeduser
  buckets and scoped user ready
=== RUN   TestDeliveredContractMinio
=== RUN   TestDeliveredContractMinio/put
=== RUN   TestDeliveredContractMinio/get_round-trips_the_body
=== RUN   TestDeliveredContractMinio/list_shows_the_key
=== RUN   TestDeliveredContractMinio/head_and_list_agree_on_the_version
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict
=== RUN   TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed
=== RUN   TestDeliveredContractMinio/delete_removes_it
=== RUN   TestDeliveredContractMinio/cross-bucket_denial
--- PASS: TestDeliveredContractMinio (0.02s)
    --- PASS: TestDeliveredContractMinio/put (0.00s)
    --- PASS: TestDeliveredContractMinio/get_round-trips_the_body (0.00s)
    --- PASS: TestDeliveredContractMinio/list_shows_the_key (0.00s)
    --- PASS: TestDeliveredContractMinio/head_and_list_agree_on_the_version (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/not_by_PutObjectTagging (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_its_own_object/and_not_by_x-amz-tagging_on_upload (0.00s)
    --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route (0.01s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CreateMultipartUpload (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/not_by_CopyObject_with_a_REPLACE_tagging_directive (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/but_multipart_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_copy_itself_is_allowed (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/a_POST-policy_forged_tag_with_a_matching_version_is_still_not_a_verdict (0.00s)
        --- PASS: TestDeliveredContractMinio/the_app_cannot_tag_by_any_other_route/and_an_ordinary_tagged-with-something-else_upload_is_allowed (0.00s)
    --- PASS: TestDeliveredContractMinio/delete_removes_it (0.00s)
    --- PASS: TestDeliveredContractMinio/cross-bucket_denial (0.00s)
PASS
ok  	github.com/carlosframework/platform/internal/objstore	0.024s
=== RUN   TestT4StorageProbeMinio
2026/10/14 13:24:31 moves: T4: STORE: list: operation error S3: ListObjectsV2, https response error StatusCode: 403, RequestID: 18DE68335BF22D64, HostID: 7c420053e0fbcd7f41653fdd92ffa2802c903d05303b1aa15adc2e8bb65d183f, api error SignatureDoesNotMatch: The request signature we calculated does not match the signature you provided. Check your key and signing method.
--- PASS: TestT4StorageProbeMinio (0.01s)
PASS
ok  	github.com/carlosframework/platform/internal/host	0.022s
minio contract: PASS
diff --git a/internal/host/plan14_generation_census_kernel_linux_test.go b/internal/host/plan14_generation_census_kernel_linux_test.go
new file mode 100644
index 000000000..43444945a
--- /dev/null
+++ b/internal/host/plan14_generation_census_kernel_linux_test.go
@@ -0,0 +1,41 @@
+//go:build linux
+
+package host
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestPlan14GenerationKernelCensusUnknownReference(t *testing.T) {
+ for _, attack := range []string{"none", "unreserved-executable", "unreserved-sibling", "uncontained", "namespace"} {
+ t.Run(attack, func(t *testing.T) {
+ f := generationProc(t)
+ tree := filepath.Dir(filepath.Dir(f.reservation.Binding.Tree))
+ other := filepath.Join(tree, "unreserved", "other")
+ if err := os.MkdirAll(filepath.Dir(other), 0700); err != nil {
+ t.Fatal(err)
+ }
+ generationWrite(t, other, "unknown build")
+ switch attack {
+ case "unreserved-executable":
+ generationRelink(t, other, f.task+"/exe")
+ case "unreserved-sibling":
+ generationLink(t, other, f.task+"/fd/7")
+ case "uncontained":
+ generationWrite(t, f.task+"/status", "Uid:\t1001\t1001\t1001\t1001\nKthread:\t0\n")
+ case "namespace":
+ generationRelink(t, "foreign", f.task+"/ns/mnt")
+ }
+ boot, digest, err := (generationKernel{proc: f.proc}).census(t.Context(), tree)
+ if attack == "none" {
+ if err != nil || boot == "" || len(digest) != 64 {
+ t.Fatalf("positive: %s %s %v", boot, digest, err)
+ }
+ } else if err == nil {
+ t.Fatal("unknown kernel obligation certified")
+ }
+ })
+ }
+}
diff --git a/internal/host/plan14_generation_census_root_linux_test.go b/internal/host/plan14_generation_census_root_linux_test.go
new file mode 100644
index 000000000..31a2932e1
--- /dev/null
+++ b/internal/host/plan14_generation_census_root_linux_test.go
@@ -0,0 +1,81 @@
+//go:build linux
+
+package host
+
+import (
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/rootstate"
+)
+
+func TestPlan14GenerationKernelCensusRootRunner(t *testing.T) {
+ if dir := os.Getenv("PLAN14_E24_KERNEL_CHILD"); dir != "" {
+ t.Setenv("CARLOS_OPT_DIR", dir)
+ path := filepath.Join(dir, "versions", "v1", "app")
+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(path, []byte("root census reference"), 0644); err != nil {
+ t.Fatal(err)
+ }
+ if boot, digest, err := productionGenerationKernelCensus(t.Context()); err != nil || boot == "" || len(digest) != 64 {
+ t.Fatalf("quiescent census: %s %s %v", boot, digest, err)
+ }
+ file, err := os.Open(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, _, err := productionGenerationKernelCensus(t.Context()); err == nil {
+ file.Close()
+ t.Fatal("open unreserved file certified")
+ }
+ if err := os.Remove(path); err != nil {
+ file.Close()
+ t.Fatal(err)
+ }
+ if _, _, err := productionGenerationKernelCensus(t.Context()); err == nil {
+ file.Close()
+ t.Fatal("deleted open file certified")
+ }
+ file.Close()
+ if _, _, err := productionGenerationKernelCensus(t.Context()); err != nil {
+ t.Fatal("closed file still retained", err)
+ }
+ return
+ }
+ parent := os.Getenv("PLAN14_GENERATION_INVENTORY_ROOT_RUNNER")
+ if parent == "" {
+ t.Skip("requires a designated disposable Linux root runner with unshare and cgroup support")
+ }
+ if os.Geteuid() != 0 {
+ t.Fatal("designated runner must execute as root")
+ }
+ state, err := rootstate.Open(parent, false, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+ state.Close()
+ dir, err := os.MkdirTemp(parent, "generation-kernel-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(func() {
+ if err := os.RemoveAll(dir); err != nil {
+ t.Error(err)
+ }
+ })
+ if err := os.Chmod(dir, 0755); err != nil {
+ t.Fatal(err)
+ }
+ // A private PID/mount namespace gives the scan a controlled all-root census.
+ // No generated tenant unit or running-tenant containment is accepted here.
+ cmd := exec.CommandContext(t.Context(), "unshare", "--mount", "--pid", "--fork", "--mount-proc", os.Args[0], "-test.run=^TestPlan14GenerationKernelCensusRootRunner$", "-test.count=1")
+ cmd.Dir = dir
+ cmd.Env = append(os.Environ(), "PLAN14_E24_KERNEL_CHILD="+dir)
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("isolated root census: %v %s", err, out)
+ }
+}
diff --git a/internal/host/plan14_generation_inventory_process_test.go b/internal/host/plan14_generation_inventory_process_test.go
new file mode 100644
index 000000000..c9ecdb493
--- /dev/null
+++ b/internal/host/plan14_generation_inventory_process_test.go
@@ -0,0 +1,63 @@
+package host
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/release"
+ "github.com/carlosframework/platform/internal/rootparticipation"
+)
+
+func TestPlan14GenerationInventoryProcessCrash(t *testing.T) {
+ if dir := os.Getenv("PLAN14_E24_INVENTORY_CHILD"); dir != "" {
+ disk := &rollbackDisk{dir: dir}
+ ledger := &release.RootGenerations{Store: disk}
+ v := generationReconciler{read: func(context.Context) (generationInventory, error) {
+ return generationInventory{Census: rootparticipation.Census{Schema: 1, Box: "box", Enrollment: "en", Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}}, nil
+ }, kernel: func(context.Context) (string, string, error) { os.Exit(76); return "", "", nil }}
+ if _, err := ledger.Certify(t.Context(), []release.GenerationReservation{}, v.reconcile); err != nil {
+ t.Fatal(err)
+ }
+ t.Fatal("crash boundary not reached")
+ }
+ dir := t.TempDir()
+ disk := &rollbackDisk{dir: dir}
+ ledger := &release.RootGenerations{Store: disk}
+ evidence := release.GenerationEvidence{Box: "box", Enrollment: "en", Migration: 1, Boot: "boot", Installations: strings.Repeat("a", 64), Launches: strings.Repeat("b", 64), Kernel: strings.Repeat("c", 64)}
+ if _, err := ledger.Certify(t.Context(), []release.GenerationReservation{}, func(context.Context, []release.GenerationReservation) (release.GenerationEvidence, error) {
+ return evidence, nil
+ }); err != nil {
+ t.Fatal(err)
+ }
+ cmd := exec.Command(os.Args[0], "-test.run=^TestPlan14GenerationInventoryProcessCrash$", "-test.count=1")
+ cmd.Dir = dir
+ cmd.Env = append(os.Environ(), "PLAN14_E24_INVENTORY_CHILD="+dir)
+ out, err := cmd.CombinedOutput()
+ var exit *exec.ExitError
+ if !errors.As(err, &exit) || exit.ExitCode() != 76 {
+ t.Fatalf("child: %v %s", err, out)
+ }
+ c, err := ledger.Completeness()
+ if err != nil || c.Complete {
+ t.Fatalf("stale certificate survived crash: %+v %v", c, err)
+ }
+ raw, err := os.ReadFile(filepath.Join(dir, "completeness.json"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ var saved release.GenerationCompleteness
+ if json.Unmarshal(raw, &saved) != nil || saved.Complete {
+ t.Fatal("durable invalidation missing")
+ }
+ if _, err := ledger.Certify(t.Context(), []release.GenerationReservation{}, func(context.Context, []release.GenerationReservation) (release.GenerationEvidence, error) {
+ return evidence, nil
+ }); err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/internal/host/plan14_generation_inventory_root_test.go b/internal/host/plan14_generation_inventory_root_test.go
new file mode 100644
index 000000000..88bca6946
--- /dev/null
+++ b/internal/host/plan14_generation_inventory_root_test.go
@@ -0,0 +1,122 @@
+//go:build linux
+
+package host
+
+import (
+ "encoding/json"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/hostbox"
+ "github.com/carlosframework/platform/internal/rootparticipation"
+ "github.com/carlosframework/platform/internal/rootstate"
+)
+
+func TestPlan14GenerationInventoryCheckedRootReader(t *testing.T) {
+ parent := os.Getenv("PLAN14_GENERATION_INVENTORY_ROOT_RUNNER")
+ if parent == "" {
+ t.Skip("requires a designated disposable root runner and its publicly traversable scratch parent")
+ }
+ if os.Geteuid() != 0 {
+ t.Fatal("designated runner must execute as root")
+ }
+ check, err := rootstate.Open(parent, false, true)
+ if err != nil {
+ t.Fatal(err)
+ }
+ check.Close()
+ // Match the production journal ancestry checked by OpenTrustedFile.
+ dir, err := os.MkdirTemp(parent, "generation-inventory-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Cleanup(func() {
+ if err := os.RemoveAll(dir); err != nil {
+ t.Error(err)
+ }
+ })
+ if err := os.Chmod(dir, 0755); err != nil {
+ t.Fatal(err)
+ }
+ censusPath, fencesPath, journalPath := filepath.Join(dir, "census"), filepath.Join(dir, "fences"), filepath.Join(dir, "journals.db")
+ census, err := rootstate.Open(censusPath, true, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer census.Close()
+ fences, err := rootstate.Open(fencesPath, true, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ fences.Close()
+ c := rootparticipation.Census{Schema: 1, Box: "runner", Enrollment: "runner-en", Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}
+ raw, err := json.Marshal(c)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := census.Write("census.json", raw); err != nil {
+ t.Fatal(err)
+ }
+ journal, err := hostbox.OpenLaunchJournal(journalPath)
+ if err != nil {
+ t.Fatal(err)
+ }
+ journal.Close()
+ got, err := generationInventoryAt(t.Context(), censusPath, fencesPath, journalPath)
+ if err != nil || got.Census != c || len(got.Installations) != 0 || len(got.Launches) != 0 {
+ t.Fatalf("checked snapshot: %+v %v", got, err)
+ }
+ for _, attack := range []string{"writable-db", "service-db", "symlink-db", "writable-wal", "service-wal", "missing-db", "missing-census"} {
+ t.Run(attack, func(t *testing.T) {
+ switch attack {
+ case "writable-db":
+ if err := os.Chmod(journalPath, 0666); err != nil {
+ t.Fatal(err)
+ }
+ defer os.Chmod(journalPath, 0600)
+ case "service-db":
+ if err := os.Chown(journalPath, 65534, 65534); err != nil {
+ t.Fatal(err)
+ }
+ defer os.Chown(journalPath, 0, 0)
+ case "symlink-db":
+ if err := os.Rename(journalPath, journalPath+".saved"); err != nil {
+ t.Fatal(err)
+ }
+ defer func() { os.Remove(journalPath); os.Rename(journalPath+".saved", journalPath) }()
+ if err := os.Symlink(journalPath+".saved", journalPath); err != nil {
+ t.Fatal(err)
+ }
+ case "writable-wal", "service-wal":
+ wal := journalPath + "-wal"
+ if err := os.WriteFile(wal, []byte("hostile"), 0600); err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove(wal)
+ if attack == "writable-wal" {
+ if err := os.Chmod(wal, 0666); err != nil {
+ t.Fatal(err)
+ }
+ } else {
+ if err := os.Chown(wal, 65534, 65534); err != nil {
+ t.Fatal(err)
+ }
+ }
+ case "missing-db":
+ if err := os.Rename(journalPath, journalPath+".saved"); err != nil {
+ t.Fatal(err)
+ }
+ defer os.Rename(journalPath+".saved", journalPath)
+ case "missing-census":
+ if err := census.Remove("census.json"); err != nil {
+ t.Fatal(err)
+ }
+ defer census.Write("census.json", raw)
+ }
+ if _, err := generationInventoryAt(t.Context(), censusPath, fencesPath, journalPath); err == nil {
+ t.Fatal("hostile source accepted")
+ }
+ })
+ }
+}
diff --git a/internal/host/plan14_generation_inventory_test.go b/internal/host/plan14_generation_inventory_test.go
new file mode 100644
index 000000000..4082afa96
--- /dev/null
+++ b/internal/host/plan14_generation_inventory_test.go
@@ -0,0 +1,278 @@
+package host
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/carlosframework/platform/internal/hostbox"
+ "github.com/carlosframework/platform/internal/hostclaim"
+ "github.com/carlosframework/platform/internal/hostguard"
+ "github.com/carlosframework/platform/internal/provision"
+ "github.com/carlosframework/platform/internal/release"
+ "github.com/carlosframework/platform/internal/rootparticipation"
+ "github.com/carlosframework/platform/internal/rootstate"
+)
+
+func TestPlan14GenerationInventoryCompleteness(t *testing.T) {
+ for _, attack := range []string{"none", "empty-reservations", "retired-only", "missing-installation", "missing-launch", "extra-launch", "extra-installation", "wrong-controller", "wrong-inputs", "wrong-installation", "wrong-process", "wrong-census", "unknown-migration", "incomplete-census", "kernel", "changed-snapshot"} {
+ t.Run(attack, func(t *testing.T) {
+ f, disk, _ := generationLaunchFixture(t)
+ if _, err := f.root.Serve(t.Context(), f.peer, f.req); err != nil {
+ t.Fatal(err)
+ }
+ r := readGenerationLaunch(t, disk)
+ view, err := f.root.Guard.Root.View(t.Context(), f.target.Host, hostguard.Captured{Incarnation: f.target.Incarnation, Stamp: f.target.Stamp})
+ if err != nil {
+ t.Fatal(err)
+ }
+ launch, err := f.journal.Read(t.Context(), f.target)
+ if err != nil {
+ t.Fatal(err)
+ }
+ snapshot := generationInventory{Census: rootparticipation.Census{Schema: 1, Box: f.target.Box, Enrollment: f.target.Enrollment, Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}, Installations: []hostguard.FenceView{view}, Launches: []hostbox.LaunchInventory{launch}}
+ records := []release.GenerationReservation{r}
+ switch attack {
+ case "empty-reservations":
+ records = nil
+ case "retired-only":
+ records[0].Closed = true
+ records[0].Retirement = r.Binding.Digest
+ case "missing-installation":
+ snapshot.Installations = nil
+ case "missing-launch":
+ snapshot.Launches = nil
+ case "extra-launch":
+ extra := launch
+ extra.Target.Host = "other.example"
+ snapshot.Launches = append(snapshot.Launches, extra)
+ case "extra-installation":
+ extra := view
+ extra.Host = "other.example"
+ extra.Installation.Host = extra.Host
+ extra.Installation.Record = provision.RecordKey(extra.Installation.Account, extra.Installation.App, extra.Host)
+ snapshot.Installations = append(snapshot.Installations, extra)
+ case "wrong-controller":
+ snapshot.Launches[0].ControllerPID++
+ case "wrong-inputs":
+ snapshot.Launches[0].Reservations[0].Inputs = "other"
+ case "wrong-installation":
+ records[0].Binding.Installation = "other"
+ case "wrong-process":
+ records[0].Process.PID++
+ case "wrong-census":
+ snapshot.Census.Enrollment = "other"
+ case "unknown-migration":
+ snapshot.Census.Migration = 0
+ case "incomplete-census":
+ snapshot.Census.Complete = false
+ }
+ reads, scans := 0, 0
+ verifier := generationReconciler{read: func(context.Context) (generationInventory, error) {
+ reads++
+ out := snapshot
+ if attack == "changed-snapshot" && reads > 1 {
+ out.Census.Revision++
+ }
+ return out, nil
+ }, kernel: func(context.Context) (string, string, error) {
+ scans++
+ if attack == "kernel" {
+ return "", "", os.ErrPermission
+ }
+ return "boot-now", r.Binding.Digest, nil
+ }}
+ evidence, err := verifier.reconcile(t.Context(), records)
+ if attack == "none" {
+ if err != nil || scans != 1 || reads != 2 || evidence.Box != f.target.Box || evidence.Installations == "" || evidence.Launches == "" {
+ t.Fatalf("positive: %+v %v reads=%d scans=%d", evidence, err, reads, scans)
+ }
+ } else if err == nil {
+ t.Fatalf("%s certified: %+v", attack, evidence)
+ }
+ })
+ }
+}
+
+func TestPlan14GenerationInventoryEmptyNeedsIndependentSources(t *testing.T) {
+ snapshot := generationInventory{Census: rootparticipation.Census{Schema: 1, Box: "box", Enrollment: "en", Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}}
+ for _, missing := range []string{"none", "inventory", "kernel", "census"} {
+ t.Run(missing, func(t *testing.T) {
+ v := generationReconciler{read: func(context.Context) (generationInventory, error) {
+ if missing == "census" {
+ return generationInventory{}, nil
+ }
+ return snapshot, nil
+ }, kernel: func(context.Context) (string, string, error) { return "boot", strings.Repeat("a", 64), nil }}
+ if missing == "inventory" {
+ v.read = nil
+ }
+ if missing == "kernel" {
+ v.kernel = nil
+ }
+ _, err := v.reconcile(t.Context(), nil)
+ if (err == nil) != (missing == "none") {
+ t.Fatalf("empty: %v", err)
+ }
+ })
+ }
+}
+
+func TestPlan14GenerationInventoryPinConsumer(t *testing.T) {
+ for _, attack := range []string{"none", "omitted-reservation", "kernel", "lost-census"} {
+ t.Run(attack, func(t *testing.T) {
+ f, disk, _ := generationLaunchFixture(t)
+ if _, err := f.root.Serve(t.Context(), f.peer, f.req); err != nil {
+ t.Fatal(err)
+ }
+ r := readGenerationLaunch(t, disk)
+ view, err := f.root.Guard.Root.View(t.Context(), f.target.Host, hostguard.Captured{Incarnation: f.target.Incarnation, Stamp: f.target.Stamp})
+ if err != nil {
+ t.Fatal(err)
+ }
+ launch, err := f.journal.Read(t.Context(), f.target)
+ if err != nil {
+ t.Fatal(err)
+ }
+ reads := 0
+ v := generationReconciler{read: func(context.Context) (generationInventory, error) {
+ reads++
+ c := rootparticipation.Census{Schema: 1, Box: f.target.Box, Enrollment: f.target.Enrollment, Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}
+ if attack == "lost-census" {
+ c.Complete = false
+ }
+ return generationInventory{Census: c, Installations: []hostguard.FenceView{view}, Launches: []hostbox.LaunchInventory{launch}}, nil
+ }, kernel: func(context.Context) (string, string, error) {
+ if attack == "kernel" {
+ return "", "", os.ErrPermission
+ }
+ return "boot", r.Binding.Digest, nil
+ }}
+ if attack == "omitted-reservation" {
+ names, err := disk.Names()
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, name := range names {
+ if err := disk.Remove(name); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+ s := generationPinSource{open: func() (rootstate.Store, error) { return disk, nil }, reconcile: v.reconcile}
+ pins, err := s.StagedPins(t.Context(), f.root.generations.optDir)
+ if attack != "none" {
+ if err == nil {
+ t.Fatalf("unsafe snapshot: %+v", pins)
+ }
+ return
+ }
+ if err != nil || reads != 2 {
+ t.Fatalf("pins: %v reads=%d", err, reads)
+ }
+ if pinned, err := pins.Refers(r.Binding.Path); err != nil || !pinned {
+ t.Fatalf("missing exact pin: %v", err)
+ }
+ c, err := (&release.RootGenerations{Store: disk}).Completeness()
+ if err != nil || !c.Complete {
+ t.Fatalf("certificate: %+v %v", c, err)
+ }
+ })
+ }
+ s, ok := productionRootGenerationPins().(generationPinSource)
+ if !ok || s.reconcile == nil {
+ t.Fatal("production reconciliation not connected")
+ }
+}
+
+func TestPlan14GenerationInventoryLifecycle(t *testing.T) {
+ for _, mode := range []string{"pending", "pending-wrong-controller", "retired", "retained-rebind", "unrecognized-predecessor"} {
+ t.Run(mode, func(t *testing.T) {
+ f, disk, _ := generationLaunchFixture(t)
+ prior, err := f.journal.Read(t.Context(), f.target)
+ if err != nil {
+ t.Fatal(err)
+ }
+ journal, err := hostbox.OpenLaunchJournal(filepath.Join(t.TempDir(), "launch.db"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer journal.Close()
+ if err := journal.Prelaunch(t.Context(), prior); err != nil {
+ t.Fatal(err)
+ }
+ f.root.Journal, f.journal = journal, journal
+ pending := strings.HasPrefix(mode, "pending")
+ if pending {
+ if _, err := f.root.generations.reserve(t.Context(), f.root, f.peer, f.req); err != nil {
+ t.Fatal(err)
+ }
+ } else {
+ if _, err := f.root.Serve(t.Context(), f.peer, f.req); err != nil {
+ t.Fatal(err)
+ }
+ if err := f.root.stop(t.Context(), f.peer, *f.req.Reservation); err != nil {
+ t.Fatal(err)
+ }
+ if err := journal.CloseWriters(t.Context(), f.target); err != nil {
+ t.Fatal(err)
+ }
+ }
+ r := readGenerationLaunch(t, disk)
+ if mode == "retired" {
+ v := generationRetirement{guard: f.root.Guard, journal: journal, kernel: func(context.Context, release.GenerationReservation) (string, error) { return r.Binding.Digest, nil }}
+ if err := v.retire(t.Context(), &release.RootGenerations{Store: disk}, r); err != nil {
+ t.Fatal(err)
+ }
+ }
+ if mode == "retained-rebind" || mode == "unrecognized-predecessor" {
+ captured := hostguard.Captured{Incarnation: f.target.Incarnation, Stamp: f.target.Stamp}
+ in, err := f.root.Guard.Root.Installation(t.Context(), f.target.Host, captured)
+ if err != nil {
+ t.Fatal(err)
+ }
+ next := in
+ next.Stamp += 3
+ next.InventoryRevision++
+ f.claims.set(func(c *hostclaim.Claim) { c.Holder.Stamp = next.Stamp })
+ if err := f.root.Guard.RebindRootInventory(t.Context(), captured, in.InventoryRevision, next, []byte("verified-rebind"), func(*hostclaim.Claim) error { return nil }, func() error { return nil }); err != nil {
+ t.Fatal(err)
+ }
+ }
+ v := generationReconciler{read: func(ctx context.Context) (generationInventory, error) {
+ views, err := f.root.Guard.Root.GenerationInstallations(ctx)
+ if err != nil {
+ return generationInventory{}, err
+ }
+ launches, err := journal.GenerationLaunches(ctx)
+ if err != nil {
+ return generationInventory{}, err
+ }
+ if mode == "unrecognized-predecessor" {
+ views[0].Retired = nil
+ }
+ if mode == "pending-wrong-controller" {
+ launches[0].ControllerPID++
+ }
+ return generationInventory{Census: rootparticipation.Census{Schema: 1, Box: f.target.Box, Enrollment: f.target.Enrollment, Migration: 1, Revision: 1, LaunchRevision: 1, Complete: true}, Installations: views, Launches: launches}, nil
+ }, kernel: func(context.Context) (string, string, error) { return "boot", r.Binding.Digest, nil }}
+ source := generationPinSource{open: func() (rootstate.Store, error) { return disk, nil }, reconcile: v.reconcile}
+ pins, err := source.StagedPins(t.Context(), f.root.generations.optDir)
+ if mode == "pending-wrong-controller" || mode == "unrecognized-predecessor" {
+ if err == nil {
+ t.Fatal("unbound generation certified")
+ }
+ return
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ pinned, err := pins.Refers(r.Binding.Path)
+ if err != nil || pinned != (mode != "retired") {
+ t.Fatalf("exact lifecycle pin=%v: %v", pinned, err)
+ }
+ })
+ }
+}
diff --git a/internal/host/rootgeneration_census_linux.go b/internal/host/rootgeneration_census_linux.go
new file mode 100644
index 000000000..b7c892ba5
--- /dev/null
+++ b/internal/host/rootgeneration_census_linux.go
@@ -0,0 +1,84 @@
+//go:build linux
+
+package host
+
+import (
+ "context"
+ "io/fs"
+ "os"
+ "path/filepath"
+
+ "github.com/carlosframework/platform/internal/release"
+ "github.com/carlosframework/platform/internal/rootstate"
+ "golang.org/x/sys/unix"
+)
+
+// census checks the whole staged namespace, including unreserved builds. This
+// quiescent verifier refuses uncontained service tasks and foreign namespaces.
+// Supporting running tenants requires independent containment evidence first.
+func (k generationKernel) census(ctx context.Context, tree string) (string, string, error) {
+ before, err := k.boot()
+ if err != nil {
+ return "", "", err
+ }
+ f, err := os.Open(tree)
+ if err != nil {
+ return "", "", err
+ }
+ id, err := rootstate.Identity(f)
+ f.Close()
+ if err != nil {
+ return "", "", err
+ }
+ r := release.GenerationReservation{Binding: release.GenerationBinding{Tree: tree, Path: tree, TreeIdentity: id, Executable: id}}
+ digest, err := k.absent(ctx, r)
+ if err != nil {
+ return "", "", err
+ }
+ after, err := k.boot()
+ if err != nil || after != before {
+ return "", "", os.ErrPermission
+ }
+ return before, digest, nil
+}
+func checkedGenerationTree(ctx context.Context, tree string) error {
+ state, err := rootstate.Open(tree, false, true)
+ if err != nil {
+ return err
+ }
+ defer state.Close()
+ count := 0
+ return filepath.WalkDir(tree, func(path string, entry fs.DirEntry, walkErr error) error {
+ if walkErr != nil {
+ return walkErr
+ }
+ if err := ctx.Err(); err != nil {
+ return err
+ }
+ count++
+ if count > 8192 {
+ return os.ErrPermission
+ }
+ var st unix.Stat_t
+ if err := unix.Lstat(path, &st); err != nil {
+ return err
+ }
+ if st.Uid != 0 || st.Mode&0022 != 0 || (st.Mode&unix.S_IFMT != unix.S_IFREG && st.Mode&unix.S_IFMT != unix.S_IFDIR) {
+ return os.ErrPermission
+ }
+ return nil
+ })
+}
+func productionGenerationKernelCensus(ctx context.Context) (string, string, error) {
+ if os.Geteuid() != 0 {
+ return "", "", os.ErrPermission
+ }
+ if err := verifyStopKernelMounts("/sys/fs/cgroup", "/proc"); err != nil {
+ return "", "", err
+ }
+ tree := filepath.Join(release.OptDir(), "versions")
+ if err := checkedGenerationTree(ctx, tree); err != nil {
+ return "", "", err
+ }
+ return (generationKernel{proc: "/proc"}).census(ctx, tree)
+}
diff --git a/internal/host/rootgeneration_census_other.go b/internal/host/rootgeneration_census_other.go
new file mode 100644
index 000000000..ea0ead216
--- /dev/null
+++ b/internal/host/rootgeneration_census_other.go
@@ -0,0 +1,12 @@
+//go:build !linux
+
+package host
+
+import (
+ "context"
+ "os"
+)
+
+func productionGenerationKernelCensus(context.Context) (string, string, error) {
+ return "", "", os.ErrPermission
+}
diff --git a/internal/host/rootgeneration_inventory.go b/internal/host/rootgeneration_inventory.go
new file mode 100644
index 000000000..b41cbe314
--- /dev/null
+++ b/internal/host/rootgeneration_inventory.go
@@ -0,0 +1,222 @@
+package host
+
+import (
+ "context"
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+ "os"
+
+ "github.com/carlosframework/platform/internal/hostbox"
+ "github.com/carlosframework/platform/internal/hostguard"
+ "github.com/carlosframework/platform/internal/instancectl"
+ "github.com/carlosframework/platform/internal/provision"
+ "github.com/carlosframework/platform/internal/release"
+ "github.com/carlosframework/platform/internal/rootparticipation"
+ "github.com/carlosframework/platform/internal/rootstate"
+)
+
+type generationInventory struct {
+ Census rootparticipation.Census
+ Installations []hostguard.FenceView
+ Launches []hostbox.LaunchInventory
+}
+type generationReconciler struct {
+ read func(context.Context) (generationInventory, error)
+ kernel func(context.Context) (string, string, error)
+}
+
+func generationInventoryDigest(v any) string {
+ raw, _ := json.Marshal(v)
+ sum := sha256.Sum256(raw)
+ return hex.EncodeToString(sum[:])
+}
+func generationOwner(t hostguard.FenceTarget) release.GenerationOwner {
+ return release.GenerationOwner{Host: t.Host, Incarnation: t.Incarnation, Stamp: t.Stamp, Session: t.Session, Box: t.Box, Enrollment: t.Enrollment, BootID: t.BootID, ControllerID: t.ControllerID}
+}
+func generationInstallation(v hostguard.FenceView, t release.GenerationOwner) (hostguard.RootInstallation, error) {
+ in := v.Installation
+ known := in.Incarnation == t.Incarnation && in.Stamp == t.Stamp
+ for _, old := range v.Retired {
+ if old.Incarnation == t.Incarnation && old.Stamp == t.Stamp {
+ known = true
+ }
+ }
+ if !known || in.Host != t.Host || in.Incarnation != t.Incarnation || in.Stamp < t.Stamp || in.Box != t.Box || in.Enrollment != t.Enrollment {
+ return in, os.ErrPermission
+ }
+ in.Stamp = t.Stamp
+ return in, nil
+}
+
+// Callers hold release exclusion through use. Recheck independent sources after
+// kernel inspection; a certificate never substitutes for the next inspection.
+func (v generationReconciler) reconcile(ctx context.Context, records []release.GenerationReservation) (release.GenerationEvidence, error) {
+ var zero release.GenerationEvidence
+ if v.read == nil || v.kernel == nil {
+ return zero, os.ErrPermission
+ }
+ before, err := v.read(ctx)
+ if err != nil {
+ return zero, err
+ }
+ c := before.Census
+ if c.Schema != 1 || !c.Complete || c.NeverEnrolled || c.Pending != "" || c.Migration == 0 || c.Revision == 0 || c.LaunchRevision == 0 || c.Box == "" || c.Enrollment == "" {
+ return zero, os.ErrPermission
+ }
+ installs := map[string]hostguard.FenceView{}
+ for _, view := range before.Installations {
+ in := view.Installation
+ if _, exists := installs[in.Host]; exists || view.Schema != 1 || view.Host != in.Host || in.Box != c.Box || in.Enrollment != c.Enrollment || in.Migration != c.Migration || in.InventoryRevision == 0 || in.Record != provision.RecordKey(in.Account, in.App, in.Host) {
+ return zero, os.ErrPermission
+ }
+ installs[in.Host] = view
+ }
+ matched := make([]bool, len(records))
+ hosts := map[string]bool{}
+ for _, launch := range before.Launches {
+ t := generationOwner(launch.Target)
+ if _, err := generationInstallation(installs[t.Host], t); err != nil {
+ return zero, err
+ }
+ hosts[t.Host] = true
+ seen := map[string]bool{}
+ for _, unit := range launch.Reservations {
+ if seen[unit.ID] || unit.ID == "" || !hostbox.SameLaunchOwner(unit.Target, launch.Target) {
+ return zero, os.ErrPermission
+ }
+ seen[unit.ID] = true
+ if !hostbox.IsUnitReservation(unit) {
+ if !launch.WritersClosed || unit.State != "settled" {
+ return zero, os.ErrPermission
+ }
+ continue
+ }
+ count := 0
+ for i, r := range records {
+ b := r.Binding
+ if b.Target != t || b.Attempt != unit.ID {
+ continue
+ }
+ in, err := generationInstallation(installs[t.Host], t)
+ if err != nil {
+ return zero, err
+ }
+ if matched[i] || b.Binding.Host != in.Host || b.Binding.Account != in.Account || b.Binding.App != in.App || b.Record != in.Record || b.Installation != rootHistoryInstallation(in) || b.ControllerPID != launch.ControllerPID || b.ControllerStart != launch.ProcessStart || b.Inputs != unit.Inputs || b.Invocation != unit.InvocationID || b.Executable.Device != unit.Executable.Device || b.Executable.Inode != unit.Executable.Inode || unit.Group.RelativePath != instancectl.ClaimUnitControlGroup(t.Host) {
+ return zero, os.ErrPermission
+ }
+ if unit.State != hostbox.UnitIntended && unit.State != hostbox.UnitStarted && unit.State != hostbox.UnitSettled {
+ return zero, os.ErrPermission
+ }
+ p := r.Process
+ if p != (release.GenerationProcess{}) && (p.PID != unit.PID || p.Start != unit.ProcessStart || p.Group != unit.Group.RelativePath || p.Invocation != unit.Group.InvocationID || p.GroupIdentity.Device != unit.Group.Device || p.GroupIdentity.Inode != unit.Group.Inode) {
+ return zero, os.ErrPermission
+ }
+ if r.Closed && (!launch.WritersClosed || unit.State != hostbox.UnitSettled) {
+ return zero, os.ErrPermission
+ }
+ matched[i] = true
+ count++
+ }
+ // A closed legacy launch can predate E2, but kernel inspection must still
+ // exclude its references. An open launch always needs its exact root pin.
+ if count != 1 && !(count == 0 && launch.WritersClosed && unit.State == hostbox.UnitSettled) {
+ return zero, os.ErrPermission
+ }
+ }
+ }
+ for _, view := range before.Installations {
+ if !view.Installation.Empty && !hosts[view.Host] {
+ return zero, os.ErrPermission
+ }
+ }
+ for i, r := range records {
+ if matched[i] {
+ continue
+ }
+ // Reserve precedes the launch intention. This crash window stays pinned;
+ // it cannot become a retired or observed generation without its journal.
+ in, err := generationInstallation(installs[r.Binding.Target.Host], r.Binding.Target)
+ if err != nil || r.Closed || r.Process != (release.GenerationProcess{}) || r.Binding.Installation != rootHistoryInstallation(in) || r.Binding.Binding.Account != in.Account || r.Binding.Binding.App != in.App || r.Binding.Record != in.Record || !hosts[in.Host] {
+ return zero, os.ErrPermission
+ }
+ pending := 0
+ for _, launch := range before.Launches {
+ if generationOwner(launch.Target) == r.Binding.Target && launch.ControllerPID == r.Binding.ControllerPID && launch.ProcessStart == r.Binding.ControllerStart {
+ pending++
+ }
+ }
+ if pending != 1 {
+ return zero, os.ErrPermission
+ }
+ }
+ snapshotDigest := generationInventoryDigest(before)
+ boot, kernel, err := v.kernel(ctx)
+ if err != nil {
+ return zero, err
+ }
+ decoded, err := hex.DecodeString(kernel)
+ if err != nil || len(decoded) != sha256.Size || hex.EncodeToString(decoded) != kernel || boot == "" {
+ return zero, os.ErrPermission
+ }
+ after, err := v.read(ctx)
+ if err != nil {
+ return zero, err
+ }
+ if err := ctx.Err(); err != nil {
+ return zero, err
+ }
+ if snapshotDigest != generationInventoryDigest(after) {
+ return zero, os.ErrPermission
+ }
+ return release.GenerationEvidence{Box: c.Box, Enrollment: c.Enrollment, Migration: c.Migration, Boot: boot, Installations: generationInventoryDigest(before.Installations), Launches: generationInventoryDigest([]any{c.LaunchRevision, before.Launches}), Kernel: kernel}, nil
+}
+
+func productionGenerationInventory(ctx context.Context) (generationInventory, error) {
+ return generationInventoryAt(ctx, rootparticipation.Namespace, "/var/lib/carlos-claims/authority/fences", "/var/lib/carlos-claims/journals.db")
+}
+
+func generationInventoryAt(ctx context.Context, censusPath, fencesPath, journalPath string) (generationInventory, error) {
+ var out generationInventory
+ censusState, err := rootstate.Open(censusPath, false, false)
+ census := rootparticipation.Ledger{State: censusState}
+ if err != nil {
+ return out, err
+ }
+ defer census.State.Close()
+ out.Census, err = census.Census()
+ if err != nil {
+ return out, err
+ }
+ state, err := rootstate.Open(fencesPath, false, false)
+ if err != nil {
+ return out, err
+ }
+ defer state.Close()
+ out.Installations, err = hostguard.NewRootAuthority(state).GenerationInstallations(ctx)
+ if err != nil {
+ return out, err
+ }
+ journal, err := openGenerationLaunchInventory(journalPath)
+ if err != nil {
+ return out, err
+ }
+ defer journal.Close()
+ out.Launches, err = journal.GenerationLaunches(ctx)
+ return out, err
+}
+
+func openGenerationLaunchInventory(path string) (*hostbox.LaunchJournal, error) {
+ for _, suffix := range []string{"", "-wal", "-shm"} {
+ file, err := rootstate.OpenTrustedFile(path + suffix)
+ if suffix != "" && errors.Is(err, os.ErrNotExist) {
+ continue
+ }
+ if err != nil {
+ return nil, err
+ }
+ file.Close()
+ }
+ return hostbox.OpenGenerationLaunchReader(path)
+}
diff --git a/internal/host/rootgenerationpins.go b/internal/host/rootgenerationpins.go
index 196dc3f29..31ba8526a 100644
--- a/internal/host/rootgenerationpins.go
+++ b/internal/host/rootgenerationpins.go
@@ -9,18 +9,18 @@ import (
)
type generationPinSource struct {
- legacy func() (bool, error)
- open func() (rootstate.Store, error)
- verify func(context.Context, []release.GenerationReservation) error
- retire func(context.Context, *release.RootGenerations) error
+ legacy func() (bool, error)
+ open func() (rootstate.Store, error)
+ verify func(context.Context, []release.GenerationReservation) error
+ reconcile func(context.Context, []release.GenerationReservation) (release.GenerationEvidence, error)
+ retire func(context.Context, *release.RootGenerations) error
}
func productionRootGenerationPins() release.PinSource {
s := generationPinSource{legacy: legacyRootRestart, retire: productionRetireGenerations, open: func() (rootstate.Store, error) {
return rootstate.Open(release.RootGenerationsDir, false, false)
}}
- // Until root reconciles installation, launch and kernel inventory, Verify
- // stays absent and destructive writes on census boxes remain unavailable.
+ s.reconcile = (generationReconciler{read: productionGenerationInventory, kernel: productionGenerationKernelCensus}).reconcile
return s
}
@@ -51,5 +51,5 @@ func (s generationPinSource) StagedPins(ctx context.Context, optDir string) (rel
return nil, err
}
}
- return (release.RootGenerationPins{Ledger: ledger, Verify: s.verify}).StagedPins(ctx, optDir)
+ return (release.RootGenerationPins{Ledger: ledger, Verify: s.verify, Reconcile: s.reconcile}).StagedPins(ctx, optDir)
}
diff --git a/internal/hostbox/generationinventory.go b/internal/hostbox/generationinventory.go
new file mode 100644
index 000000000..2b86e62d2
--- /dev/null
+++ b/internal/hostbox/generationinventory.go
@@ -0,0 +1,74 @@
+package hostbox
+
+import (
+ "bytes"
+ "context"
+ "database/sql"
+ "encoding/json"
+ "io"
+ "net/url"
+ "os"
+ "path/filepath"
+)
+
+// GenerationLaunches includes hosts absent from the reservation directory.
+// Only the checked local journal is eligible; an agent list is not a census.
+func (j *LaunchJournal) GenerationLaunches(ctx context.Context) ([]LaunchInventory, error) {
+ if j == nil || j.db == nil || j.remote != nil {
+ return nil, ErrUnsupported
+ }
+ if err := journalIdentity(j.path, j.identity); err != nil {
+ return nil, err
+ }
+ rows, err := journalExecutorFor(ctx, j.db).QueryContext(ctx, "SELECT identity, body FROM launches ORDER BY identity")
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ var out []LaunchInventory
+ for rows.Next() {
+ var key string
+ var body []byte
+ if err := rows.Scan(&key, &body); err != nil {
+ return nil, err
+ }
+ if len(body) > 1<<20 || len(out) >= 8192 {
+ return nil, ErrTypedInventory
+ }
+ var in LaunchInventory
+ dec := json.NewDecoder(bytes.NewReader(body))
+ dec.DisallowUnknownFields()
+ if dec.Decode(&in) != nil || dec.Decode(new(any)) != io.EOF || !validLaunchOwner(in.Target) || launchKey(in.Target) != key || !in.Completed.Valid() || in.ControllerPID <= 0 || in.ProcessStart == "" {
+ return nil, ErrTypedInventory
+ }
+ out = append(out, in)
+ }
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
+ if err := journalIdentity(j.path, j.identity); err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+// OpenGenerationLaunchReader never creates a database or initializes its schema.
+// Production callers must check root ownership of the database and sidecars.
+func OpenGenerationLaunchReader(path string) (*LaunchJournal, error) {
+ if !filepath.IsAbs(path) {
+ return nil, ErrUnsupported
+ }
+ if err := checkJournalPath(path); err != nil {
+ return nil, err
+ }
+ identity, err := os.Lstat(path)
+ if err != nil {
+ return nil, err
+ }
+ db, err := sql.Open("sqlite", "file:"+url.PathEscape(path)+"?mode=ro&_pragma=busy_timeout(5000)")
+ if err != nil {
+ return nil, err
+ }
+ db.SetMaxOpenConns(1)
+ return &LaunchJournal{db: db, path: path, identity: identity}, nil
+}
diff --git a/internal/hostbox/plan14_generation_inventory_test.go b/internal/hostbox/plan14_generation_inventory_test.go
new file mode 100644
index 000000000..4ccd5c490
--- /dev/null
+++ b/internal/hostbox/plan14_generation_inventory_test.go
@@ -0,0 +1,73 @@
+package hostbox
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestPlan14GenerationLaunchInventory(t *testing.T) {
+ for _, attack := range []string{"none", "unknown-field", "wrong-key", "oversize", "replaced-path", "missing-table"} {
+ t.Run(attack, func(t *testing.T) {
+ j, r := roleLaunchFixture(t)
+ if err := j.IntendUnit(t.Context(), r); err != nil {
+ t.Fatal(err)
+ }
+ switch attack {
+ case "unknown-field":
+ _, err := j.db.Exec("UPDATE launches SET body=json_set(body,'$.unknown',true)")
+ if err != nil {
+ t.Fatal(err)
+ }
+ case "wrong-key":
+ _, err := j.db.Exec("UPDATE launches SET identity='other'")
+ if err != nil {
+ t.Fatal(err)
+ }
+ case "oversize":
+ _, err := j.db.Exec("UPDATE launches SET body=zeroblob(1048577)")
+ if err != nil {
+ t.Fatal(err)
+ }
+ case "replaced-path":
+ if err := os.Rename(j.path, j.path+".old"); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(j.path, []byte("replacement"), 0600); err != nil {
+ t.Fatal(err)
+ }
+ case "missing-table":
+ _, err := j.db.Exec("DROP TABLE launches")
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ got, err := j.GenerationLaunches(t.Context())
+ if attack == "none" {
+ if err != nil || len(got) != 1 || len(got[0].Reservations) != 1 {
+ t.Fatalf("inventory: %+v %v", got, err)
+ }
+ } else if err == nil {
+ t.Fatal("incomplete inventory accepted")
+ }
+ })
+ }
+}
+
+func TestPlan14GenerationReaderDoesNotInitialize(t *testing.T) {
+ path := filepath.Join(t.TempDir(), "empty.db")
+ if err := os.WriteFile(path, nil, 0600); err != nil {
+ t.Fatal(err)
+ }
+ j, err := OpenGenerationLaunchReader(path)
+ if err != nil {
+ return
+ }
+ defer j.Close()
+ if _, err := j.GenerationLaunches(t.Context()); err == nil {
+ t.Fatal("missing schema was initialized as complete")
+ }
+ if info, err := os.Stat(path); err != nil || info.Size() != 0 {
+ t.Fatalf("reader changed empty database: %v %v", info, err)
+ }
+}
diff --git a/internal/hostguard/generationinventory.go b/internal/hostguard/generationinventory.go
new file mode 100644
index 000000000..0851eb378
--- /dev/null
+++ b/internal/hostguard/generationinventory.go
@@ -0,0 +1,46 @@
+package hostguard
+
+import (
+ "context"
+ "sort"
+ "strings"
+)
+
+// GenerationInstallations enumerates independently of generation reservations.
+// Pending or quarantined installations cannot certify a destructive snapshot.
+func (a *RootAuthority) GenerationInstallations(ctx context.Context) ([]FenceView, error) {
+ if a == nil || a.store == nil {
+ return nil, ErrInvalidInput
+ }
+ names, err := a.store.Names()
+ if err != nil {
+ return nil, err
+ }
+ sort.Strings(names)
+ var out []FenceView
+ for _, name := range names {
+ if err := ctx.Err(); err != nil {
+ return nil, err
+ }
+ if strings.HasSuffix(name, ".lock") {
+ continue
+ }
+ if !strings.HasSuffix(name, ".json") {
+ return nil, ErrMalformedRecord
+ }
+ host := strings.TrimSuffix(name, ".json")
+ r, err := a.read(host)
+ if err != nil {
+ return nil, err
+ }
+ view, err := a.viewLocked(host, Captured{Incarnation: r.Incarnation, Stamp: r.ActiveStamp})
+ if err != nil {
+ return nil, err
+ }
+ if view.Installation.InventoryRevision == 0 {
+ return nil, ErrNoRecord
+ }
+ out = append(out, view)
+ }
+ return out, nil
+}
diff --git a/internal/hostguard/plan14_generation_inventory_test.go b/internal/hostguard/plan14_generation_inventory_test.go
new file mode 100644
index 000000000..75c919776
--- /dev/null
+++ b/internal/hostguard/plan14_generation_inventory_test.go
@@ -0,0 +1,55 @@
+//go:build unix
+
+package hostguard
+
+import "testing"
+
+func TestPlan14GenerationInstallationInventory(t *testing.T) {
+ for _, attack := range []string{"none", "unknown-file", "malformed", "uninitialized", "quarantined", "pending"} {
+ t.Run(attack, func(t *testing.T) {
+ f, target, captured := fenceFixture(t)
+ store := &rootTestStore{dir: t.TempDir()}
+ f.g.Root = NewRootAuthority(store)
+ f.obs.Claim.Holder.Account, f.obs.Claim.Holder.App = "bab", "console"
+ in := RootInstallation{Host: target.Host, Incarnation: captured.Incarnation, Stamp: captured.Stamp, Account: "bab", App: "console", Record: "record", Box: target.Box, Enrollment: target.Enrollment, Migration: 1, InventoryRevision: 1}
+ if err := f.g.EstablishRoot(t.Context(), in, allow); err != nil {
+ t.Fatal(err)
+ }
+ switch attack {
+ case "unknown-file":
+ if err := store.Write("unknown", nil); err != nil {
+ t.Fatal(err)
+ }
+ case "malformed":
+ if err := store.Write(target.Host+".json", []byte("{}")); err != nil {
+ t.Fatal(err)
+ }
+ case "uninitialized", "quarantined", "pending":
+ r, err := f.g.Root.read(target.Host)
+ if err != nil {
+ t.Fatal(err)
+ }
+ switch attack {
+ case "uninitialized":
+ r.installation.InventoryRevision = 0
+ case "quarantined":
+ r.quarantined = true
+ case "pending":
+ r.pendingInstallation = &in
+ r.pendingInventory = []byte("pending")
+ }
+ if err := f.g.Root.write(r); err != nil {
+ t.Fatal(err)
+ }
+ }
+ got, err := f.g.Root.GenerationInstallations(t.Context())
+ if attack == "none" {
+ if err != nil || len(got) != 1 || got[0].Installation != in {
+ t.Fatalf("installations: %+v %v", got, err)
+ }
+ } else if err == nil {
+ t.Fatal("incomplete installation certified")
+ }
+ })
+ }
+}
diff --git a/internal/provision/plan9_b8_census_test.go b/internal/provision/plan9_b8_census_test.go
index 5d55256e0..82a379ccb 100644
--- a/internal/provision/plan9_b8_census_test.go
+++ b/internal/provision/plan9_b8_census_test.go
@@ -473,6 +473,7 @@ func Reviewed(ctx context.Context, s Store, k string) error {
// BEGIN REVIEWED INVENTORY
var plan9B8CensusInventory = []censusEntry{
+ {"internal/host/rootgeneration_inventory.go", "generationReconciler.reconcile", "key-site", "key:RecordKey", "35fba4c4b286b530288f83d150f93a49980cb5a587bdea1b69c4f71a90442fbf"},
{"internal/host/rootgenerations_launch.go", "rootGenerationSource.resolve", "key-site", "key:RecordKey", "1d66e9ffa6aca3ea4a2d370c04f782b01c8a15d9ae6ca93a9356632d2b032977"},
{"internal/host/rootinventory.go", "ClaimRootHTTP.recoverRootInventory", "key-site", "key:RecordKey", "10d09b5ab6d07d316437233c9a65bf0bcdfe1083db4d0769fa8303b255dfd0ac"},
{"internal/host/proofnamed.go", "proofBindingSource.record", "key-site", "key:RecordKey", "10a99ff4b355907831a904010b7019d480ce93f2f595e99e076d3c702d10ca2b"},
diff --git a/internal/provision/testdata/plan14-root-reads-e.tsv b/internal/provision/testdata/plan14-root-reads-e.tsv
index 59ad98868..acb6645b3 100644
--- a/internal/provision/testdata/plan14-root-reads-e.tsv
+++ b/internal/provision/testdata/plan14-root-reads-e.tsv
@@ -54,7 +54,7 @@ internal/release/roothistory_replace.go replacementReconstruction authority E1 S
internal/release/signedhead.go StageSignedHead authority E1 Canonical route is supplied by the root unit verifier. Verifies signed channel, digest ratchet and manifest/artifact before staging; unavailable pin census never authorizes restaging differing bytes. Fixtures: TestPlan14Incident20261006WithLedger and TestPlan14SignedNamedRecoveryAuthority. registry:Account@202,registry:Account@302,registry:Account@403,registry:App@214,registry:App@415,registry:Channel@222,registry:Host@434 ca02f04e55556ba0233dfa0848b0c533a9d9aa06cad6abd33cfd2968b3bd838a
internal/rootstate/link_linux.go ReadTrustedLink authority A,E1 Checks the full root-owned parent chain before descriptor-based live-link reading. Fixture: TestPlan14TrustedLiveLink; privileged acceptance remains required. file:Open@156 90f8e8de4e2c71f07b5d749cbe4bb1c1dfa426576a82138823449f56fc9ec5ab
internal/rootstate/link_linux.go directory.readLink authority A,E1 Pins the symlink inode with O_PATH and checks owner/type/link count before readlinkat. Fixture: TestPlan14TrustedLiveLink. file:Fstat@356,file:Openat@183,file:Readlinkat@554 a8559fe63dce48830916004ecfe7fbbe5d419568c7daf7a3073cf1b5bb12c3d7
-@coverage internal/host 8e78fc36197a3e57ec73d46b824b93a87c4a5031a6f0fd11d6e86f86d188260d
+@coverage internal/host 7a0f83f08620422a955ded1e353b5dd4e77aeaf0f07580c7bff85d7393923de2
@coverage internal/release 2bb546a86c1ab49b02e424eb0b366b46776857a1249baa2d6fb61ead4209d6bd
@coverage internal/rootstate 6338f74a6b2059cf77cf478bd6111b37b441eb9d65a309464c378359d4bdac05
internal/release/roothistory_status.go RootHistory.MigrationStatus authority E1 Exact completion binds the accepted authorization digest from durable private history to enrolled-root signed readback. Pending originals, changed evidence and canonical sources cannot supply retirement completion. Fixtures: TestPlan14HistoryReconstructionCompletion, TestPlan14HistoryRetirementCompletion, TestPlan14ReadReconstructionCompletion, TestPlan14ReadRetirementCompletion, TestPlan14RecoveryRetirementProductionCallback, TestPlan14RootHistoryReconstructionCrash, TestPlan14HistoryRetirementProcessCrash. file:Read@1062,file:Read@3891 f0ab7ad2d2d70f8c22ebfd575f5a1c6931f7eba30ccdba80ad43d0efffc88154
@@ -211,9 +211,9 @@ internal/release/rootgenerations.go type GenerationProcess authority E2 E18: cla
internal/release/rootgenerations.go type GenerationReservation authority E2 E20: exact reservation closure precedes retirement verification; retained tombstones forbid replay and require sync recommit. Retired records release only their own pins; completeness remains a separate mandatory verifier, still unavailable in production. Fixtures: TestPlan14GenerationRetirementReleasesExactPin, TestPlan14GenerationRetirementRefusals, TestPlan14GenerationClosedReplayRefused, TestPlan14GenerationRetirementProcessCrash, TestPlan14GenerationRetirementKeepsIndependentReference, TestPlan14GenerationClaimsOffRestageMatchesMain. 1917db4836b3b18b45ce6bca1a55f6d5a8082e5de26af1710d0da25db0809551
internal/release/rootgenerations.go type RootGenerations authority E2 E18: claims-on launch records the canonical installation, deployment revision, signed build, executable and containing tree before start under release exclusion; both final spawn checks reread the same reservation and identities. Root process evidence never retires the reservation. This is the launch prerequisite only; complete pins and retirement remain pending. Fixtures: TestPlan14GenerationReservedBeforeClaimSpawn, TestPlan14GenerationLaunchRefusals, TestPlan14GenerationStartedSyncFailureRetainsPin, TestPlan14GenerationReservationProcessCrash, TestPlan14GenerationProductionWiring, TestPlan14GenerationReservationDurability, TestPlan14GenerationReservationConflicts, TestPlan14GenerationObservationKeepsReservation, TestPlan14GenerationRecordRefusals. 240860014efc91f51ca7e3e920ffb5cfa98076340dc0c9e9972c35051e5eca84
internal/release/rootgenerations.go validGeneration authority E2 E20: exact reservation closure precedes retirement verification; retained tombstones forbid replay and require sync recommit. Retired records release only their own pins; completeness remains a separate mandatory verifier, still unavailable in production. Fixtures: TestPlan14GenerationRetirementReleasesExactPin, TestPlan14GenerationRetirementRefusals, TestPlan14GenerationClosedReplayRefused, TestPlan14GenerationRetirementProcessCrash, TestPlan14GenerationRetirementKeepsIndependentReference, TestPlan14GenerationClaimsOffRestageMatchesMain. 25b4b51c18290f5e169e4c8225710cf3d27078b7a89101ab069bc7a838e75335
-internal/host/rootgenerationpins.go generationPinSource.StagedPins authority E2 E21: production census-only pin reader calls exact retirement before the unchanged mandatory completeness verifier. No census performs no generation open or retirement. Fixtures: TestPlan14GenerationRetirementCensusGate, TestPlan14GenerationProductionModeGate, TestPlan14GenerationClaimsOffRestageMatchesMain. 25c90cc73e198e2a05c6e8069d35ddfbc72a5ac43ed6f5b90673bf015dce1800
-internal/host/rootgenerationpins.go productionRootGenerationPins authority E2 E21: production census-only pin reader calls exact retirement before the unchanged mandatory completeness verifier. No census performs no generation open or retirement. Fixtures: TestPlan14GenerationRetirementCensusGate, TestPlan14GenerationProductionModeGate, TestPlan14GenerationClaimsOffRestageMatchesMain. file:Open@195 8d0a7b9fc2bfd14808ec6ab8f52751fc563b4b1364f58ccf59f48ed1348b25f2
-internal/host/rootgenerationpins.go type generationPinSource authority E2 E21: production census-only pin reader calls exact retirement before the unchanged mandatory completeness verifier. No census performs no generation open or retirement. Fixtures: TestPlan14GenerationRetirementCensusGate, TestPlan14GenerationProductionModeGate, TestPlan14GenerationClaimsOffRestageMatchesMain. edbc03de4156cf4292a92928e190749d50b317041827b9b83123798882ee4481
+internal/host/rootgenerationpins.go generationPinSource.StagedPins authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. ba1ee92576995f2592b2837d535163e9c54f7bbcc63d729d69e0cc09a50e3244
+internal/host/rootgenerationpins.go productionRootGenerationPins authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. file:Open@195 68f1c801080780dd36f864abf6c2cb59fe55265aabea02566008eeaecb0d291a
+internal/host/rootgenerationpins.go type generationPinSource authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 48c0762d696c9693ed90a8003ea3eea5c72e64f72603e014eaed1cac4043b6bc
internal/host/versionsweep.go sweepStagedVersions authority E2,J3,J4 root-route E19: both destructive readers use the root reservation snapshot under existing release exclusion. Exact artifact and containing-tree identities are retained; missing completeness refuses destruction. Production installation/launch/kernel completeness and verified retirement remain unfinished. Fixtures: TestPlan14GenerationDeletionCannotUnpin, TestPlan14GenerationSnapshotCompleteness, TestPlan14GenerationSnapshotPermitsUnreservedRestage, TestPlan14GenerationSnapshotPinsContainingTree, TestPlan14GenerationSnapshotEmptyIsUnknown, TestPlan14GenerationConsumerMode. registry:GoodVersion@898,registry:GoodVersion@930,registry:PrevVersion@711,registry:PrevVersion@743,registry:Version@656,registry:Version@684,whole:Route@1231,whole:Route@435 e7fc68ed8c5ff2dc8a98daeb16c08f4d497b8016a3c459b6e4158721ba109843
internal/host/versionsweep.go sweepStagedVersionsPass authority E2 E19: both destructive readers use the root reservation snapshot under existing release exclusion. Exact artifact and containing-tree identities are retained; missing completeness refuses destruction. Production installation/launch/kernel completeness and verified retirement remain unfinished. Fixtures: TestPlan14GenerationDeletionCannotUnpin, TestPlan14GenerationSnapshotCompleteness, TestPlan14GenerationSnapshotPermitsUnreservedRestage, TestPlan14GenerationSnapshotPinsContainingTree, TestPlan14GenerationSnapshotEmptyIsUnknown, TestPlan14GenerationConsumerMode, TestPlan14GenerationProductionModeGate, TestPlan14GenerationSnapshotPermitsFreshTree. efeae77306262f47556aeccb382409933995f80c52f989e469e088e714e7d888
internal/release/adopt.go stageFrom authority E2 E19: both destructive readers use the root reservation snapshot under existing release exclusion. Exact artifact and containing-tree identities are retained; missing completeness refuses destruction. Production installation/launch/kernel completeness and verified retirement remain unfinished. Fixtures: TestPlan14GenerationDeletionCannotUnpin, TestPlan14GenerationSnapshotCompleteness, TestPlan14GenerationSnapshotPermitsUnreservedRestage, TestPlan14GenerationSnapshotPinsContainingTree, TestPlan14GenerationSnapshotEmptyIsUnknown, TestPlan14GenerationConsumerMode, TestPlan14GenerationProductionModeGate, TestPlan14GenerationSnapshotPermitsFreshTree. E22: root generation pins guard existing-tree artifact and manifest writes in adoption and moves-held staging/publication. Held snapshot is read under release exclusion before the leaf held-stage lock; failures remain restrictive for writes. Claims-off source returns no root pins. Fresh wholly absent version trees retain signed staging. Fixtures: TestPlan14GenerationSiblingWrites, TestPlan14GenerationVerifiedSiblingWrites, TestPlan14GenerationHeldStage (production source assembly, both flag values without census, lock order, pin/error/fresh cases). Production completeness remains unavailable; no new completeness grant. 30efb69f9a7ee5aca5a1909d94d3c6669065c7880207430e7e0d2a23ae90a8b6
@@ -227,7 +227,7 @@ internal/release/rootgenerationpins.go type RootGenerationPins authority E2 E23:
internal/host/rootinstallation.go rootInstallationHostApp authority E2,J1 E20: read the atomic root installation under the existing host exclusion without recursive lock acquisition; retain fresh claim, canonical record, signed artifact and final reservation checks. Fixtures: TestPlan14GenerationLaunchDoesNotReenterRootLock, TestPlan14GenerationLaunchRefusals, TestPlan14RootDispatchRejectsRegistryMutation. file:Read@488,registry:Account@1062,registry:App@1091 0bbe17aff8c82841ae47fb01e060e1e1a80865e635d4a5c95dc5a638d2754d1c
internal/hostguard/rootview.go RootAuthority.Installation authority E2,J1 E20: read the atomic root installation under the existing host exclusion without recursive lock acquisition; retain fresh claim, canonical record, signed artifact and final reservation checks. Fixtures: TestPlan14GenerationLaunchDoesNotReenterRootLock, TestPlan14GenerationLaunchRefusals, TestPlan14RootDispatchRejectsRegistryMutation. d819256332950ec26c1b541f8be21a6e8cea839708fcbd0f7b8367d118574f92
internal/release/rootgenerations.go RootGenerations.Retire authority E2 E20: exact reservation closure precedes retirement verification; retained tombstones forbid replay and require sync recommit. Retired records release only their own pins; completeness remains a separate mandatory verifier, still unavailable in production. Fixtures: TestPlan14GenerationRetirementReleasesExactPin, TestPlan14GenerationRetirementRefusals, TestPlan14GenerationClosedReplayRefused, TestPlan14GenerationRetirementProcessCrash, TestPlan14GenerationRetirementKeepsIndependentReference, TestPlan14GenerationClaimsOffRestageMatchesMain. file:Read@297 21bb00d11d6fd8474b4d0a556bd1af7e69dbf6bd75755daeb0f14481166f2a90
-@coverage internal/hostguard c69ab7fe435f0f512d92538df6b505517a0b444f776c158d51fe16250edcde64
+@coverage internal/hostguard 512a9f96349d27edba5ff3c0a016911b70b136dde59717ee9bef0a5579cff5a2
internal/host/rootgeneration_kernel_linux.go generationGroupGone authority E2 E21: bounded kernel reader retains executable, sibling, descriptor, mapping and mount references; checks controller boot/start and cgroup emptiness. Unknown nonroot tasks, foreign namespaces, missing kernel state or renamed trees refuse. Fixtures: TestPlan14GenerationKernelReferences, TestPlan14GenerationKernelMappingIdentity, TestPlan14GenerationKernelControllerIdentity, TestPlan14GenerationKernelRunningExecutable, TestPlan14GenerationKernelCgroup, TestPlan14GenerationKernelRetainedFiles, TestPlan14GenerationKernelSiblingAlias. Real proc executable tests are not full privileged namespace acceptance. file:Lstat@218 a4778a7342e51a58eb736c15463e75c93349690d1f07b0d840d201ae8f57ecc6
internal/host/rootgeneration_kernel_linux.go generationIDRef authority E2 E21: bounded kernel reader retains executable, sibling, descriptor, mapping and mount references; checks controller boot/start and cgroup emptiness. Unknown nonroot tasks, foreign namespaces, missing kernel state or renamed trees refuse. Fixtures: TestPlan14GenerationKernelReferences, TestPlan14GenerationKernelMappingIdentity, TestPlan14GenerationKernelControllerIdentity, TestPlan14GenerationKernelRunningExecutable, TestPlan14GenerationKernelCgroup, TestPlan14GenerationKernelRetainedFiles, TestPlan14GenerationKernelSiblingAlias. Real proc executable tests are not full privileged namespace acceptance. 949b4dddb141d7eafd4edc70b41f8dd337069f699ab30d86c46bc6fce986d40b
internal/host/rootgeneration_kernel_linux.go generationKernel.absent authority E2 E21: bounded kernel reader retains executable, sibling, descriptor, mapping and mount references; checks controller boot/start and cgroup emptiness. Unknown nonroot tasks, foreign namespaces, missing kernel state or renamed trees refuse. Fixtures: TestPlan14GenerationKernelReferences, TestPlan14GenerationKernelMappingIdentity, TestPlan14GenerationKernelControllerIdentity, TestPlan14GenerationKernelRunningExecutable, TestPlan14GenerationKernelCgroup, TestPlan14GenerationKernelRetainedFiles, TestPlan14GenerationKernelSiblingAlias. Real proc executable tests are not full privileged namespace acceptance. file:Readlink@312 18269bf4b64e05138dff05e7894d4925bc24bcc012fa64a336723d981a9c52dd
@@ -290,3 +290,20 @@ internal/release/materializeheld.go ServeHeldStageRequests authority E2 E23: old
internal/release/materializeheld.go ServeHeldStageRequestsWithPins authority E2 E23: old held-stage relay forwards the root generation source before artifact writes and outside publication exclusion. Request fields retain their prior hint/authorization checks; only root pins authorize destructive staging on census boxes. No-census source yields empty pins. Fixtures: TestPlan14GenerationLegacyRelay, TestHeldStagePassIsANoOpWithoutRequests, TestHeldStagePassDropsAnUnauthorizedBuild, TestServeHeldStageRequestsRefusesStaleAndTraversal. Production source wiring is inspected; privileged completeness is not claimed. file:ReadDir@429 edb9927c53af09311b4dd3e277a34d5eba7ab048d343b9b05e25f0b24a48e79d
internal/release/materializeheld.go serveHeldStageRequest authority E2 E23: old held-stage relay forwards the root generation source before artifact writes and outside publication exclusion. Request fields retain their prior hint/authorization checks; only root pins authorize destructive staging on census boxes. No-census source yields empty pins. Fixtures: TestPlan14GenerationLegacyRelay, TestHeldStagePassIsANoOpWithoutRequests, TestHeldStagePassDropsAnUnauthorizedBuild, TestServeHeldStageRequestsRefusesStaleAndTraversal. Production source wiring is inspected; privileged completeness is not claimed. file:OpenFile@615,file:ReadAll@812,whole:Route@1676 bbda896335311f5e09a75542d82c57fb993da72cbc27875b74bda79bf0239280
internal/host/heldstage.go heldStagePass authority E2 E23: old held-stage relay forwards the root generation source before artifact writes and outside publication exclusion. Request fields retain their prior hint/authorization checks; only root pins authorize destructive staging on census boxes. No-census source yields empty pins. Fixtures: TestPlan14GenerationLegacyRelay, TestHeldStagePassIsANoOpWithoutRequests, TestHeldStagePassDropsAnUnauthorizedBuild, TestServeHeldStageRequestsRefusesStaleAndTraversal. Production source wiring is inspected; privileged completeness is not claimed. 759f041ad504375f3000acccc10b5fba80aaa44ab574c3491d1df2cb49a35087
+internal/host/rootgeneration_census_linux.go checkedGenerationTree authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. file:Lstat@467,file:Open@84,file:WalkDir@192 2a9f530f41143ce64723797ef4c5628b536caa6fefb11bcbe57adbec38f9a012
+internal/host/rootgeneration_census_linux.go generationKernel.census authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. file:Open@170 5c43de2497824076701fb6275b86d629f0a1035be212d41754d90ba39c431140
+internal/host/rootgeneration_inventory.go generationInventoryAt authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. file:Open@173,file:Open@424 0fdfb9575baf9e9f5099e3ff463223d7b5100060fe3f6cf2908f20639e0e486e
+internal/hostbox/generationinventory.go LaunchJournal.GenerationLaunches authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. file:QueryContext@270 6694bd3a35b8d91f53e67134145c44854086f08593110ed1b905bca9587be290
+internal/hostbox/generationinventory.go OpenGenerationLaunchReader authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. file:Lstat@218,file:Open@283 552d8629a7932c4ae5dca9d2beef4559f7e8a2864259d11e2ff98c699fdcd999
+@coverage internal/hostbox 9e63382b4bf1376b75aef3040de0ed079cff0de80ba77d81598c0c06b62041e5
+internal/host/rootgeneration_census_linux.go productionGenerationKernelCensus authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 85f085029e0cd557c8ff8eb2d522fdf131c388229c14515fda0f45453d40eebb
+internal/host/rootgeneration_census_other.go productionGenerationKernelCensus authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. a1217cf881e9d05336fc16d6050f7f7a1a2184a0c20ff2988d0cf0f9012eaa45
+internal/host/rootgeneration_inventory.go generationInstallation authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 3e5e15d50752510acb44b10eb29621757a87bff54ceae015f704dd7f3a848ecb
+internal/host/rootgeneration_inventory.go generationInventoryDigest authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 36ff5a31c6a013ac907d85e59b754cf4088df4600646ba7df177cf14e990177a
+internal/host/rootgeneration_inventory.go generationOwner authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 69f89153837761f13116937b330ffbf406891299d5580296ea4aade905aa02ce
+internal/host/rootgeneration_inventory.go generationReconciler.reconcile authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 35fba4c4b286b530288f83d150f93a49980cb5a587bdea1b69c4f71a90442fbf
+internal/host/rootgeneration_inventory.go openGenerationLaunchInventory authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 522445e6d8acbe083d9d8f001719c4dbd3af57c56429e6b73b05c55a3826cb8b
+internal/host/rootgeneration_inventory.go productionGenerationInventory authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 8c888114e1d40fa8d5496775a7dd136dc1c7a732c997369af61449b2a0f55a41
+internal/host/rootgeneration_inventory.go type generationInventory authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 398337e54b33efb37b21b181520f1bf9bcce48c34a0d66430f2e58505ae7bf00
+internal/host/rootgeneration_inventory.go type generationReconciler authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. a979cdff1cd6311cf57d4a93e4501fb8dc2f65772d0013e622175b2a1f610d91
+internal/hostguard/generationinventory.go RootAuthority.GenerationInstallations authority E2 E24: independent root installation and launch enumeration, exact reservation reconciliation and fresh quiescent whole-version-tree kernel census; missing sources, open unreserved launches, foreign namespaces and uncontained tasks refuse. Production pin source certifies this evidence before returning pins. Fixtures: TestPlan14GenerationInventoryCompleteness, TestPlan14GenerationInventoryPinConsumer, TestPlan14GenerationInventoryLifecycle, TestPlan14GenerationInventoryProcessCrash, TestPlan14GenerationKernelCensusUnknownReference, TestPlan14GenerationLaunchInventory, TestPlan14GenerationReaderDoesNotInitialize, TestPlan14GenerationInstallationInventory. Checked production source/kernel tests are runner-pending. 593768e6ba937cf2cfa2635c8f796f767d6c2354737a72073cc351f514faed20