Skip to content

Commit 246a3e0

Browse files
test(runtime): refuse stale owner before native signal
1 parent 35987a4 commit 246a3e0

2 files changed

Lines changed: 26 additions & 12 deletions

File tree

‎docs/native-qualification.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ intact. FastAPI Stop releases its environment, so restart uses Init then Start.
3333
At manager load the test captures the authenticated agent-group leader identity.
3434
After restart it requires the current full owner identity to equal that original
3535
birth before Core's identity-bound signal kills only the disposable agent owner.
36+
A stale-birth negative must be refused by that guard, with both original owners
37+
and uvicorn workload births still alive, before the valid owner-death case.
3638
The existing CLI previews that exact authenticated-v2 orphan, then consumes its
3739
unchanged receipt to recover it. The sibling must still retain its exact birth
3840
and live owner, and its ordinary Stop must also remove its registration.

‎native_ownership_test.go‎

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,16 @@ func TestNativeAgentOwnershipLifecycle(t *testing.T) {
7777
require.NoError(t, err)
7878
require.Equal(t, runtimev0.InitStatus_READY, initialized.GetStatus().GetState(), initialized.GetStatus().GetMessage())
7979
startNativeWorkload(t, ctx, a)
80-
owner, err := runners.InspectProcess(a.owner.PID)
81-
if err != nil {
82-
t.Fatal(err)
83-
}
84-
// The current PID must still be the original authenticated manager child.
85-
// SignalProcess rechecks that identity at delivery; never select a new birth.
86-
require.Equal(t, a.owner, owner, "agent owner birth changed before signaling")
87-
t.Logf("owner pre-signal identity equals original: %+v", a.owner)
88-
if err := runners.SignalProcess(ctx, a.owner, syscall.SIGKILL); err != nil {
89-
t.Fatal(err)
90-
}
80+
// A stale birth must be refused before SIGKILL delivery. If this guard
81+
// delivered to the live PID, the exact owner and workload checks would fail.
82+
stale := a.owner
83+
stale.StartID++
84+
require.ErrorContains(t, signalNativeOwner(ctx, stale), "owner identity changed")
85+
assertNativeOwnership(t, ctx, a, true)
86+
assertNativeOwnership(t, ctx, b, true)
87+
t.Log("stale owner refused with original agent and uvicorn births still alive")
88+
require.NoError(t, signalNativeOwner(ctx, a.owner))
89+
t.Logf("signaled owner only after full identity matched original: %+v", a.owner)
9190
waitNativeCondition(t, func() bool {
9291
ownership, err := a.group.InspectOwnership(ctx)
9392
return err == nil && ownership.Authenticated && !ownership.OwnerAlive
@@ -103,7 +102,7 @@ func TestNativeAgentOwnershipLifecycle(t *testing.T) {
103102
t.Fatalf("preview: %v", err)
104103
}
105104
expected, err := runners.ParseProcessGroupRecoveryExpectation(preview)
106-
if err != nil || expected.Namespace != "authenticated-v2" || expected.PGID != a.group.PGID() || expected.Owner.PID != owner.PID || expected.Owner.BootID != owner.BootID || expected.Owner.StartID != owner.StartID {
105+
if err != nil || expected.Namespace != "authenticated-v2" || expected.PGID != a.group.PGID() || expected.Owner.PID != a.owner.PID || expected.Owner.BootID != a.owner.BootID || expected.Owner.StartID != a.owner.StartID {
107106
t.Fatalf("actual agent did not write the expected v2 registration: %+v, %v", expected, err)
108107
}
109108
t.Logf("orphan preview: %s", preview)
@@ -266,6 +265,19 @@ func startNativeWorkload(t *testing.T, ctx context.Context, service *ownedNative
266265
})
267266
}
268267

268+
// signalNativeOwner is only the fixture's admission guard. Core owns delivery
269+
// and rechecks the current full identity at the kernel-bound signal seam.
270+
func signalNativeOwner(ctx context.Context, original runners.ProcessIdentity) error {
271+
current, err := runners.InspectProcess(original.PID)
272+
if err != nil {
273+
return err
274+
}
275+
if current != original {
276+
return fmt.Errorf("owner identity changed: original=%+v current=%+v", original, current)
277+
}
278+
return runners.SignalProcess(ctx, current, syscall.SIGKILL)
279+
}
280+
269281
func assertNativeOwnership(t *testing.T, ctx context.Context, service *ownedNativeService, ownerAlive bool) {
270282
t.Helper()
271283
ownership, err := service.group.InspectOwnership(ctx)

0 commit comments

Comments
 (0)