fix(site-runtime): reject invalid runtime actor names at the site gate and never let ActorOf escalate to the Deployment Manager (review 2026-10-21 01/SR-C1)

An instance unique name Akka refuses as a path element (space, '#', '/',
non-ASCII) made Context.ActorOf throw on the singleton's own thread; the
default Restart stopped every Instance Actor on the site. DeployCompileValidator
now checks the instance + script/alarm/native-source actor names with
ActorPath.IsValidPathElement (the Commons ActorNameRules mirror is stricter
than Akka for " ( ), pinned by a parity sweep), CreateInstanceActor catches
InvalidActorNameException and every caller reports it, and the Instance Actor
skips a refused child name like a compile failure.
This commit is contained in:
Joseph Doherty
2026-10-22 06:24:28 -04:00
parent b5cebf9fa6
commit f5090fcd9e
8 changed files with 606 additions and 23 deletions
@@ -72,11 +72,16 @@ public class DeploymentManagerRedeployTests : TestKit, IDisposable
/// <summary>
/// Builds a config that deserializes and compiles cleanly (so it passes the deploy
/// compile gate) but whose script's canonical name contains a space — illegal as an
/// Akka actor name, so <c>Context.ActorOf(props, "script-dies on init")</c> throws
/// compile gate) but carries two scripts with the SAME canonical name, so the second
/// <c>Context.ActorOf(props, "script-dup")</c> throws a not-unique
/// <c>InvalidActorNameException</c> during the Instance Actor's PreStart. The failure
/// surfaces as an <c>ActorInitializationException</c> the DM decider stops — the exact
/// "Instance Actor dies during init" S6 scenario.
/// <para>
/// This used an illegal (space-containing) script name until review 2026-10-21 01/SR-C1:
/// the gate now rejects such names up front and the Instance Actor skips a refused child
/// name, so a name with a space no longer reaches PreStart as a throw.
/// </para>
/// </summary>
private static string CtorThrowingConfig(string instanceName) =>
JsonSerializer.Serialize(new FlattenedConfiguration
@@ -88,7 +93,8 @@ public class DeploymentManagerRedeployTests : TestKit, IDisposable
],
Scripts =
[
new ResolvedScript { CanonicalName = "dies on init", Code = "return 1;" }
new ResolvedScript { CanonicalName = "dup", Code = "return 1;" },
new ResolvedScript { CanonicalName = "dup", Code = "return 2;" }
]
});
@@ -382,7 +388,7 @@ public class DeploymentManagerRedeployTests : TestKit, IDisposable
public async Task InstanceActorInitFailure_OnStartup_EvictsDeadRefAndLogsSiteEvent()
{
// A stored config that compiles cleanly but whose Instance Actor cannot
// initialize (illegal child actor name → ActorInitializationException → Stop).
// initialize (duplicate child actor name → ActorInitializationException → Stop).
// The DM watches every Instance Actor, so on the unexpected Termination it must
// evict the dead ref from the routing map and log a `deployment` Error event
// rather than leaving a routing entry that points at a stopped actor (S6).