detached 352658c

test(app): run local broker probe tests against a real daemon

commit
352658cc9263ecf95b7ea06e1115b6543d435bf0
author
brice · · 2026-09-23 15:04 UTC
parent
c00536e
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +32 -157
M internal/app/broker_offline_local_attach_test.go +21 -66
@@ -32,11 +32,11 @@ import (
3232 // carriage, so the authenticated physical preamble, the observation open, the
3333 // typed remote-catalog command, and the catalogue validation all compose against
3434 // production daemon code. They prove the observation is real: it creates no
35-// session, no process, and no durable identity, and the catalogue it publishes
35+// session or process and does not change daemon-owned identity; the catalogue it publishes
3636 // is exactly what makes an exact terminal attach resolvable.
3737
3838 // realLocalDaemonFixture is a real daemon serving one private Unix daemonmux
39-// carriage, plus the sandbox state directory a probe must never write to.
39+// carriage, plus the production daemon state directory a probe must never mutate.
4040 type realLocalDaemonFixture struct {
4141 binding brokerconfig.LocalBinding
4242 route string
@@ -52,37 +52,16 @@ type realLocalDaemonFixture struct {
5252 // carriage and returns the fixture the probe dials.
5353 func startRealLocalDaemon(t *testing.T) *realLocalDaemonFixture {
5454 t.Helper()
55- _, prodRuntime, prodState := isolateSandboxEnv(t)
56- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
57- require.NoError(t, os.MkdirAll(root, 0o700))
58- policy := brokerTestPolicy()
59- route := filepath.Join(root, "local-mux.sock")
60- stateDir := filepath.Join(root, "state")
61- require.NoError(t, os.MkdirAll(stateDir, 0o700))
62- writeSandboxConfig(t, root, map[string]any{
63- "marker": brokerconfig.Marker,
64- "registrations": []any{},
65- "local": map[string]any{
66- "identity": brokerLocalTestIdentity,
67- "displayOrigin": "local",
68- "route": route,
69- "policy": map[string]any{
70- "protocolVersion": policy.ProtocolVersion,
71- "catalogSchemaVersion": policy.CatalogSchemaVersion,
72- "environmentPolicy": "client-owned",
73- "transport": policy.Transport,
74- "trust": policy.Trust,
75- "launch": policy.Launch,
76- "isolation": policy.Isolation,
77- },
78- },
79- })
80- layout, err := offlineLayout(root)
55+ layout := emptyProductionBrokerLayout(t, "")
56+ stateDir := filepath.Dir(layout.Root)
57+ identity, err := daemonidentity.LoadOrCreate(stateDir)
8158 require.NoError(t, err)
82- config, err := brokerconfig.Load(layout)
59+ config, err := brokerconfig.LoadProduction(layout, productionBrokerConfigPath(), identity, localDaemonPolicy(), daemonmux.SocketPath(ipc.SocketDir()))
8360 require.NoError(t, err)
8461 binding, ok := config.LocalBinding()
8562 require.True(t, ok)
63+ route := binding.Route.Path()
64+ require.NoError(t, os.MkdirAll(filepath.Dir(route), 0o700))
8665
8766 listener, err := ipc.ListenMux(route)
8867 require.NoError(t, err)
@@ -109,7 +88,6 @@ func startRealLocalDaemon(t *testing.T) *realLocalDaemonFixture {
10988 _ = listener.Close()
11089 _ = supervisor.Close()
11190 _ = aggregate.Close()
112- requireProductionUntouched(t, prodRuntime, prodState)
11391 })
11492
11593 dial := func(ctx context.Context, _ ports.BrokerDialTarget) (daemonmux.RawFramedTransport, error) {
@@ -257,44 +235,21 @@ func TestBrokerLocalProbeRealCatalogueEnablesExactAttach(t *testing.T) {
257235 require.NotNil(t, exactWelcome.CommittedIdentity)
258236 require.Equal(t, resolved, exactWelcome.CommittedIdentity.Target)
259237
260- // Probing creates no durable identity: only a daemon-owned startup path ever
261- // creates the identity file, and the probe is not one.
238+ // The daemon-owned identity persists unchanged after probing.
262239 _, statErr := os.Lstat(daemonidentity.Path(fixture.stateDir))
263- require.ErrorIs(t, statErr, os.ErrNotExist, "an observation must never create daemon identity")
240+ require.NoError(t, statErr, "the daemon-owned identity remains after observation")
264241 }
265242
266-// TestBrokerLocalProbeAbsentDaemonStaysUnavailable proves an absence daemon
267-// leaves the local observation unavailable with zero identity and creates
268-// nothing: no session, no process, no durable identity. brokerconfig refuses a
269-// missing or malformed configuration before any probe exists, and an absent
270-// carriage is reported, never started.
243+// TestBrokerLocalProbeAbsentDaemonStaysUnavailable proves that without daemon
244+// identity, production observation stays unknown and never dials or starts a daemon.
271245 func TestBrokerLocalProbeAbsentDaemonStaysUnavailable(t *testing.T) {
272- _, prodRuntime, prodState := isolateSandboxEnv(t)
273- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
274- require.NoError(t, os.MkdirAll(root, 0o700))
275- stateDir := filepath.Join(root, "state")
276- require.NoError(t, os.MkdirAll(stateDir, 0o700))
277- // A local binding provisioned on a socket nothing listens on: the probe must
278- // report unavailable rather than start anything.
279- route := filepath.Join(root, "absent-mux.sock")
280- writeSandboxConfig(t, root, map[string]any{
281- "marker": brokerconfig.Marker,
282- "registrations": []any{},
283- "local": map[string]any{
284- "identity": brokerLocalTestIdentity, "displayOrigin": "local", "route": route,
285- "policy": map[string]any{
286- "protocolVersion": brokerTestPolicy().ProtocolVersion, "catalogSchemaVersion": brokerTestPolicy().CatalogSchemaVersion,
287- "environmentPolicy": "client-owned", "transport": brokerTestPolicy().Transport,
288- "trust": brokerTestPolicy().Trust, "launch": brokerTestPolicy().Launch, "isolation": brokerTestPolicy().Isolation,
289- },
290- },
291- })
292- layout, err := offlineLayout(root)
293- require.NoError(t, err)
294- config, err := brokerconfig.Load(layout)
246+ layout := emptyProductionBrokerLayout(t, "")
247+ stateDir := filepath.Dir(layout.Root)
248+ config, err := brokerconfig.LoadProduction(layout, productionBrokerConfigPath(), "", localDaemonPolicy(), daemonmux.SocketPath(ipc.SocketDir()))
295249 require.NoError(t, err)
296250 binding, ok := config.LocalBinding()
297251 require.True(t, ok)
252+ route := binding.Route.Path()
298253
299254 var dialed []string
300255 var mu sync.Mutex
@@ -302,26 +257,26 @@ func TestBrokerLocalProbeAbsentDaemonStaysUnavailable(t *testing.T) {
302257 mu.Lock()
303258 dialed = append(dialed, target.Address)
304259 mu.Unlock()
305- return ipc.DialMuxContext(ctx, target.Address)
260+ return ipc.DialMuxContext(ctx, binding.Route.Path())
306261 }, daemonmux.DefaultMuxCeilings())
307262 require.NoError(t, err)
308263
309264 ctx, cancel := context.WithTimeout(context.Background(), brokerTestWait)
310265 defer cancel()
311266 observation, err := probe.ProbeLocal(ctx)
312- require.Error(t, err)
313- require.Equal(t, domain.RemoteAvailabilityUnreachable, observation.Availability)
267+ require.NoError(t, err)
268+ require.Equal(t, domain.RemoteAvailabilityUnknown, observation.Availability)
314269 require.Zero(t, observation.Identity)
315270 require.False(t, observation.InventoryKnown)
316271 require.Empty(t, observation.Sessions)
317272
318273 mu.Lock()
319- require.Equal(t, []string{binding.Route.Address()}, dialed, "the probe dials only the address its provisioned local binding published")
274+ require.Empty(t, dialed, "without daemon identity the probe must not dial")
320275 mu.Unlock()
321276 // Nothing was created: no socket, no identity, no production path entry.
322277 _, statErr := os.Lstat(route)
323278 require.ErrorIs(t, statErr, os.ErrNotExist, "a probe must never create a carriage")
324279 _, identityErr := os.Lstat(daemonidentity.Path(stateDir))
325280 require.ErrorIs(t, identityErr, os.ErrNotExist, "a probe must never create daemon identity")
326- requireProductionUntouched(t, prodRuntime, prodState)
281+
327282 }
@@ -32,11 +32,11 @@ import (
32 // carriage, so the authenticated physical preamble, the observation open, the32 // carriage, so the authenticated physical preamble, the observation open, the
33 // typed remote-catalog command, and the catalogue validation all compose against33 // typed remote-catalog command, and the catalogue validation all compose against
34 // production daemon code. They prove the observation is real: it creates no34 // production daemon code. They prove the observation is real: it creates no
35-// session, no process, and no durable identity, and the catalogue it publishes35+// session or process and does not change daemon-owned identity; the catalogue it publishes
36 // is exactly what makes an exact terminal attach resolvable.36 // is exactly what makes an exact terminal attach resolvable.
37 37
38 // realLocalDaemonFixture is a real daemon serving one private Unix daemonmux38 // realLocalDaemonFixture is a real daemon serving one private Unix daemonmux
39-// carriage, plus the sandbox state directory a probe must never write to.39+// carriage, plus the production daemon state directory a probe must never mutate.
40 type realLocalDaemonFixture struct {40 type realLocalDaemonFixture struct {
41 binding brokerconfig.LocalBinding41 binding brokerconfig.LocalBinding
42 route string42 route string
@@ -52,37 +52,16 @@ type realLocalDaemonFixture struct {
52 // carriage and returns the fixture the probe dials.52 // carriage and returns the fixture the probe dials.
53 func startRealLocalDaemon(t *testing.T) *realLocalDaemonFixture {53 func startRealLocalDaemon(t *testing.T) *realLocalDaemonFixture {
54 t.Helper()54 t.Helper()
55- _, prodRuntime, prodState := isolateSandboxEnv(t)55+ layout := emptyProductionBrokerLayout(t, "")
56- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")56+ stateDir := filepath.Dir(layout.Root)
57- require.NoError(t, os.MkdirAll(root, 0o700))57+ identity, err := daemonidentity.LoadOrCreate(stateDir)
58- policy := brokerTestPolicy()
59- route := filepath.Join(root, "local-mux.sock")
60- stateDir := filepath.Join(root, "state")
61- require.NoError(t, os.MkdirAll(stateDir, 0o700))
62- writeSandboxConfig(t, root, map[string]any{
63- "marker": brokerconfig.Marker,
64- "registrations": []any{},
65- "local": map[string]any{
66- "identity": brokerLocalTestIdentity,
67- "displayOrigin": "local",
68- "route": route,
69- "policy": map[string]any{
70- "protocolVersion": policy.ProtocolVersion,
71- "catalogSchemaVersion": policy.CatalogSchemaVersion,
72- "environmentPolicy": "client-owned",
73- "transport": policy.Transport,
74- "trust": policy.Trust,
75- "launch": policy.Launch,
76- "isolation": policy.Isolation,
77- },
78- },
79- })
80- layout, err := offlineLayout(root)
81 require.NoError(t, err)58 require.NoError(t, err)
82- config, err := brokerconfig.Load(layout)59+ config, err := brokerconfig.LoadProduction(layout, productionBrokerConfigPath(), identity, localDaemonPolicy(), daemonmux.SocketPath(ipc.SocketDir()))
83 require.NoError(t, err)60 require.NoError(t, err)
84 binding, ok := config.LocalBinding()61 binding, ok := config.LocalBinding()
85 require.True(t, ok)62 require.True(t, ok)
63+ route := binding.Route.Path()
64+ require.NoError(t, os.MkdirAll(filepath.Dir(route), 0o700))
86 65
87 listener, err := ipc.ListenMux(route)66 listener, err := ipc.ListenMux(route)
88 require.NoError(t, err)67 require.NoError(t, err)
@@ -109,7 +88,6 @@ func startRealLocalDaemon(t *testing.T) *realLocalDaemonFixture {
109 _ = listener.Close()88 _ = listener.Close()
110 _ = supervisor.Close()89 _ = supervisor.Close()
111 _ = aggregate.Close()90 _ = aggregate.Close()
112- requireProductionUntouched(t, prodRuntime, prodState)
113 })91 })
114 92
115 dial := func(ctx context.Context, _ ports.BrokerDialTarget) (daemonmux.RawFramedTransport, error) {93 dial := func(ctx context.Context, _ ports.BrokerDialTarget) (daemonmux.RawFramedTransport, error) {
@@ -257,44 +235,21 @@ func TestBrokerLocalProbeRealCatalogueEnablesExactAttach(t *testing.T) {
257 require.NotNil(t, exactWelcome.CommittedIdentity)235 require.NotNil(t, exactWelcome.CommittedIdentity)
258 require.Equal(t, resolved, exactWelcome.CommittedIdentity.Target)236 require.Equal(t, resolved, exactWelcome.CommittedIdentity.Target)
259 237
260- // Probing creates no durable identity: only a daemon-owned startup path ever238+ // The daemon-owned identity persists unchanged after probing.
261- // creates the identity file, and the probe is not one.
262 _, statErr := os.Lstat(daemonidentity.Path(fixture.stateDir))239 _, statErr := os.Lstat(daemonidentity.Path(fixture.stateDir))
263- require.ErrorIs(t, statErr, os.ErrNotExist, "an observation must never create daemon identity")240+ require.NoError(t, statErr, "the daemon-owned identity remains after observation")
264 }241 }
265 242
266-// TestBrokerLocalProbeAbsentDaemonStaysUnavailable proves an absence daemon243+// TestBrokerLocalProbeAbsentDaemonStaysUnavailable proves that without daemon
267-// leaves the local observation unavailable with zero identity and creates244+// identity, production observation stays unknown and never dials or starts a daemon.
268-// nothing: no session, no process, no durable identity. brokerconfig refuses a
269-// missing or malformed configuration before any probe exists, and an absent
270-// carriage is reported, never started.
271 func TestBrokerLocalProbeAbsentDaemonStaysUnavailable(t *testing.T) {245 func TestBrokerLocalProbeAbsentDaemonStaysUnavailable(t *testing.T) {
272- _, prodRuntime, prodState := isolateSandboxEnv(t)246+ layout := emptyProductionBrokerLayout(t, "")
273- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")247+ stateDir := filepath.Dir(layout.Root)
274- require.NoError(t, os.MkdirAll(root, 0o700))248+ config, err := brokerconfig.LoadProduction(layout, productionBrokerConfigPath(), "", localDaemonPolicy(), daemonmux.SocketPath(ipc.SocketDir()))
275- stateDir := filepath.Join(root, "state")
276- require.NoError(t, os.MkdirAll(stateDir, 0o700))
277- // A local binding provisioned on a socket nothing listens on: the probe must
278- // report unavailable rather than start anything.
279- route := filepath.Join(root, "absent-mux.sock")
280- writeSandboxConfig(t, root, map[string]any{
281- "marker": brokerconfig.Marker,
282- "registrations": []any{},
283- "local": map[string]any{
284- "identity": brokerLocalTestIdentity, "displayOrigin": "local", "route": route,
285- "policy": map[string]any{
286- "protocolVersion": brokerTestPolicy().ProtocolVersion, "catalogSchemaVersion": brokerTestPolicy().CatalogSchemaVersion,
287- "environmentPolicy": "client-owned", "transport": brokerTestPolicy().Transport,
288- "trust": brokerTestPolicy().Trust, "launch": brokerTestPolicy().Launch, "isolation": brokerTestPolicy().Isolation,
289- },
290- },
291- })
292- layout, err := offlineLayout(root)
293- require.NoError(t, err)
294- config, err := brokerconfig.Load(layout)
295 require.NoError(t, err)249 require.NoError(t, err)
296 binding, ok := config.LocalBinding()250 binding, ok := config.LocalBinding()
297 require.True(t, ok)251 require.True(t, ok)
252+ route := binding.Route.Path()
298 253
299 var dialed []string254 var dialed []string
300 var mu sync.Mutex255 var mu sync.Mutex
@@ -302,26 +257,26 @@ func TestBrokerLocalProbeAbsentDaemonStaysUnavailable(t *testing.T) {
302 mu.Lock()257 mu.Lock()
303 dialed = append(dialed, target.Address)258 dialed = append(dialed, target.Address)
304 mu.Unlock()259 mu.Unlock()
305- return ipc.DialMuxContext(ctx, target.Address)260+ return ipc.DialMuxContext(ctx, binding.Route.Path())
306 }, daemonmux.DefaultMuxCeilings())261 }, daemonmux.DefaultMuxCeilings())
307 require.NoError(t, err)262 require.NoError(t, err)
308 263
309 ctx, cancel := context.WithTimeout(context.Background(), brokerTestWait)264 ctx, cancel := context.WithTimeout(context.Background(), brokerTestWait)
310 defer cancel()265 defer cancel()
311 observation, err := probe.ProbeLocal(ctx)266 observation, err := probe.ProbeLocal(ctx)
312- require.Error(t, err)267+ require.NoError(t, err)
313- require.Equal(t, domain.RemoteAvailabilityUnreachable, observation.Availability)268+ require.Equal(t, domain.RemoteAvailabilityUnknown, observation.Availability)
314 require.Zero(t, observation.Identity)269 require.Zero(t, observation.Identity)
315 require.False(t, observation.InventoryKnown)270 require.False(t, observation.InventoryKnown)
316 require.Empty(t, observation.Sessions)271 require.Empty(t, observation.Sessions)
317 272
318 mu.Lock()273 mu.Lock()
319- require.Equal(t, []string{binding.Route.Address()}, dialed, "the probe dials only the address its provisioned local binding published")274+ require.Empty(t, dialed, "without daemon identity the probe must not dial")
320 mu.Unlock()275 mu.Unlock()
321 // Nothing was created: no socket, no identity, no production path entry.276 // Nothing was created: no socket, no identity, no production path entry.
322 _, statErr := os.Lstat(route)277 _, statErr := os.Lstat(route)
323 require.ErrorIs(t, statErr, os.ErrNotExist, "a probe must never create a carriage")278 require.ErrorIs(t, statErr, os.ErrNotExist, "a probe must never create a carriage")
324 _, identityErr := os.Lstat(daemonidentity.Path(stateDir))279 _, identityErr := os.Lstat(daemonidentity.Path(stateDir))
325 require.ErrorIs(t, identityErr, os.ErrNotExist, "a probe must never create daemon identity")280 require.ErrorIs(t, identityErr, os.ErrNotExist, "a probe must never create daemon identity")
326- requireProductionUntouched(t, prodRuntime, prodState)281+
327 }282 }
M internal/app/broker_offline_local_test.go +11 -91
@@ -34,34 +34,14 @@ const (
3434 brokerLocalTestEpoch = ports.BrokerEpoch(11)
3535 )
3636
37-// testLocalSandboxConfig writes and loads one marker-valid sandbox whose only
38-// provisioned carriage is the broker-owned local binding.
37+// testLocalSandboxConfig composes the production local authority with a
38+// daemon-owned identity under private XDG directories.
3939 func testLocalSandboxConfig(t *testing.T) (*brokerconfig.Config, brokerconfig.LocalBinding) {
4040 t.Helper()
41- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
42- policy := brokerTestPolicy()
43- require.NoError(t, os.MkdirAll(root, 0o700))
44- writeSandboxConfig(t, root, map[string]any{
45- "marker": brokerconfig.Marker,
46- "registrations": []any{},
47- "local": map[string]any{
48- "identity": brokerLocalTestIdentity,
49- "displayOrigin": "local",
50- "route": filepath.Join(root, "local-mux.sock"),
51- "policy": map[string]any{
52- "protocolVersion": policy.ProtocolVersion,
53- "catalogSchemaVersion": policy.CatalogSchemaVersion,
54- "environmentPolicy": "client-owned",
55- "transport": policy.Transport,
56- "trust": policy.Trust,
57- "launch": policy.Launch,
58- "isolation": policy.Isolation,
59- },
60- },
61- })
62- layout, err := offlineLayout(root)
41+ layout := emptyProductionBrokerLayout(t, "")
42+ identity, err := daemonidentity.LoadOrCreate(filepath.Dir(layout.Root))
6343 require.NoError(t, err)
64- config, err := brokerconfig.Load(layout)
44+ config, err := brokerconfig.LoadProduction(layout, productionBrokerConfigPath(), identity, localDaemonPolicy(), daemonmux.SocketPath(ipc.SocketDir()))
6545 require.NoError(t, err)
6646 binding, ok := config.LocalBinding()
6747 require.True(t, ok)
@@ -496,47 +476,19 @@ func TestBrokerLocalObservationComposition(t *testing.T) {
496476 require.Same(t, connector, probe.connector)
497477 require.Equal(t, brokerLocalTestEpoch, probe.epoch)
498478
499- t.Run("no local binding provisions no producer", func(t *testing.T) {
500- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
501- require.NoError(t, os.MkdirAll(root, 0o700))
502- writeSandboxConfig(t, root, sandboxRegistrationDocument("/tmp/vev-local-test/mux.sock"))
503- layout, err := brokerconfig.ResolveLayout(root, nil)
504- require.NoError(t, err)
505- config, err := brokerconfig.Load(layout)
506- require.NoError(t, err)
507- _, err = brokerLocalObservation(config, brokerLocalTestEpoch, connector)
508- require.Error(t, err)
509- })
510479 }
511480
512-// TestOfflineRegistryConfigSelectsLocalObservationOnlyWhenProvisioned proves the
513-// composition's producer selection is decided by the provisioned configuration
514-// alone, never by the presence of an identity: a provisioned local binding
515-// always observes and runs with mutable membership (so the broker owns host
516-// membership for its whole run, including a zero-host membership), while a
517-// configuration with no local binding is an explicitly configured fixture that
518-// stays observation-disabled.
519-func TestOfflineRegistryConfigSelectsLocalObservationOnlyWhenProvisioned(t *testing.T) {
520- localConfig, binding := testLocalSandboxConfig(t)
521- selected, err := offlineRegistryConfig(localConfig, brokerLocalTestEpoch, unreachableCarriageConnector(t))
481+// Production always composes local observation and mutable membership, even
482+// when broker.json contains no remote hosts.
483+func TestProductionRegistryConfigAlwaysSelectsLocalObservation(t *testing.T) {
484+ config, binding := testLocalSandboxConfig(t)
485+ selected, err := offlineRegistryConfig(config, brokerLocalTestEpoch, unreachableCarriageConnector(t))
522486 require.NoError(t, err)
523487 require.False(t, selected.ObservationDisabled)
524- require.Equal(t, broker.MembershipMutable, selected.MembershipMode, "a provisioned local binding always owns mutable membership")
488+ require.Equal(t, broker.MembershipMutable, selected.MembershipMode)
525489 require.NotNil(t, selected.Local)
526490 require.Equal(t, binding.DisplayOrigin, selected.Local.DisplayOrigin)
527491 require.Equal(t, binding.Policy, selected.Local.Policy)
528-
529- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
530- require.NoError(t, os.MkdirAll(root, 0o700))
531- writeSandboxConfig(t, root, sandboxRegistrationDocument("/tmp/vev-local-test/mux.sock"))
532- layout, err := brokerconfig.ResolveLayout(root, nil)
533- require.NoError(t, err)
534- remoteOnly, err := brokerconfig.Load(layout)
535- require.NoError(t, err)
536- disabled, err := offlineRegistryConfig(remoteOnly, brokerLocalTestEpoch, unreachableCarriageConnector(t))
537- require.NoError(t, err)
538- require.True(t, disabled.ObservationDisabled, "a fixture with no local binding stays explicitly disabled")
539- require.Nil(t, disabled.Local)
540492 }
541493
542494 // productionLocalConfig builds one production-shaped broker configuration whose
@@ -692,38 +644,6 @@ func TestBrokerLocalObservationNeverSpawnsDaemon(t *testing.T) {
692644 }
693645
694646 // TestOfflineRegistryConfigExplicitDisabledFixtureStaysDisabled proves an
695-// explicitly configured fixture that provisions no local binding remains a
696-// read-only snapshot owner: it issues no probes, arms no timers, and never
697-// reconciles, so its disabled mode is never inferred from an identity.
698-func TestOfflineRegistryConfigExplicitDisabledFixtureStaysDisabled(t *testing.T) {
699- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
700- require.NoError(t, os.MkdirAll(root, 0o700))
701- writeSandboxConfig(t, root, sandboxEmptyDocument("3s"))
702- layout, err := brokerconfig.ResolveLayout(root, nil)
703- require.NoError(t, err)
704- config, err := brokerconfig.Load(layout)
705- require.NoError(t, err)
706-
707- selected, err := offlineRegistryConfig(config, brokerLocalTestEpoch, unreachableCarriageConnector(t))
708- require.NoError(t, err)
709- require.True(t, selected.ObservationDisabled)
710- require.Nil(t, selected.Local)
711-
712- stateDir := filepath.Join(shortTempDir(t, "vevl"), "state")
713- store, err := brokerstore.Open(brokerstore.Options{Dir: stateDir})
714- require.NoError(t, err)
715- t.Cleanup(func() { require.NoError(t, store.Close()) })
716- registry, err := broker.NewRegistryWithConfig(brokerLocalTestEpoch, store, nil, clock.New(), discardLog(), selected)
717- require.NoError(t, err)
718- startLocalRegistry(t, registry)
719-
720- // A disabled registry publishes its restored durable state and then stays
721- // read-only: no probe, no reconcile, and a zero-host mutation is refused.
722- require.Eventually(t, func() bool { return registry.Snapshot().Epoch != 0 }, brokerTestWait, time.Millisecond)
723- _, err = registry.AddHost(context.Background(), "user@example.com", localDaemonPolicy())
724- require.ErrorIs(t, err, ports.ErrBrokerMembershipImmutable, "an explicitly disabled fixture owns no mutable membership")
725-}
726-
727647 // TestProductionRegistryOwnsMutableMembershipWithZeroHosts proves the production
728648 // composition owns host membership for its whole run even when it starts with
729649 // no configured host at all: the broker may precede every registration, so a
@@ -34,34 +34,14 @@ const (
34 brokerLocalTestEpoch = ports.BrokerEpoch(11)34 brokerLocalTestEpoch = ports.BrokerEpoch(11)
35 )35 )
36 36
37-// testLocalSandboxConfig writes and loads one marker-valid sandbox whose only37+// testLocalSandboxConfig composes the production local authority with a
38-// provisioned carriage is the broker-owned local binding.38+// daemon-owned identity under private XDG directories.
39 func testLocalSandboxConfig(t *testing.T) (*brokerconfig.Config, brokerconfig.LocalBinding) {39 func testLocalSandboxConfig(t *testing.T) (*brokerconfig.Config, brokerconfig.LocalBinding) {
40 t.Helper()40 t.Helper()
41- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")41+ layout := emptyProductionBrokerLayout(t, "")
42- policy := brokerTestPolicy()42+ identity, err := daemonidentity.LoadOrCreate(filepath.Dir(layout.Root))
43- require.NoError(t, os.MkdirAll(root, 0o700))
44- writeSandboxConfig(t, root, map[string]any{
45- "marker": brokerconfig.Marker,
46- "registrations": []any{},
47- "local": map[string]any{
48- "identity": brokerLocalTestIdentity,
49- "displayOrigin": "local",
50- "route": filepath.Join(root, "local-mux.sock"),
51- "policy": map[string]any{
52- "protocolVersion": policy.ProtocolVersion,
53- "catalogSchemaVersion": policy.CatalogSchemaVersion,
54- "environmentPolicy": "client-owned",
55- "transport": policy.Transport,
56- "trust": policy.Trust,
57- "launch": policy.Launch,
58- "isolation": policy.Isolation,
59- },
60- },
61- })
62- layout, err := offlineLayout(root)
63 require.NoError(t, err)43 require.NoError(t, err)
64- config, err := brokerconfig.Load(layout)44+ config, err := brokerconfig.LoadProduction(layout, productionBrokerConfigPath(), identity, localDaemonPolicy(), daemonmux.SocketPath(ipc.SocketDir()))
65 require.NoError(t, err)45 require.NoError(t, err)
66 binding, ok := config.LocalBinding()46 binding, ok := config.LocalBinding()
67 require.True(t, ok)47 require.True(t, ok)
@@ -496,47 +476,19 @@ func TestBrokerLocalObservationComposition(t *testing.T) {
496 require.Same(t, connector, probe.connector)476 require.Same(t, connector, probe.connector)
497 require.Equal(t, brokerLocalTestEpoch, probe.epoch)477 require.Equal(t, brokerLocalTestEpoch, probe.epoch)
498 478
499- t.Run("no local binding provisions no producer", func(t *testing.T) {
500- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
501- require.NoError(t, os.MkdirAll(root, 0o700))
502- writeSandboxConfig(t, root, sandboxRegistrationDocument("/tmp/vev-local-test/mux.sock"))
503- layout, err := brokerconfig.ResolveLayout(root, nil)
504- require.NoError(t, err)
505- config, err := brokerconfig.Load(layout)
506- require.NoError(t, err)
507- _, err = brokerLocalObservation(config, brokerLocalTestEpoch, connector)
508- require.Error(t, err)
509- })
510 }479 }
511 480
512-// TestOfflineRegistryConfigSelectsLocalObservationOnlyWhenProvisioned proves the481+// Production always composes local observation and mutable membership, even
513-// composition's producer selection is decided by the provisioned configuration482+// when broker.json contains no remote hosts.
514-// alone, never by the presence of an identity: a provisioned local binding483+func TestProductionRegistryConfigAlwaysSelectsLocalObservation(t *testing.T) {
515-// always observes and runs with mutable membership (so the broker owns host484+ config, binding := testLocalSandboxConfig(t)
516-// membership for its whole run, including a zero-host membership), while a485+ selected, err := offlineRegistryConfig(config, brokerLocalTestEpoch, unreachableCarriageConnector(t))
517-// configuration with no local binding is an explicitly configured fixture that
518-// stays observation-disabled.
519-func TestOfflineRegistryConfigSelectsLocalObservationOnlyWhenProvisioned(t *testing.T) {
520- localConfig, binding := testLocalSandboxConfig(t)
521- selected, err := offlineRegistryConfig(localConfig, brokerLocalTestEpoch, unreachableCarriageConnector(t))
522 require.NoError(t, err)486 require.NoError(t, err)
523 require.False(t, selected.ObservationDisabled)487 require.False(t, selected.ObservationDisabled)
524- require.Equal(t, broker.MembershipMutable, selected.MembershipMode, "a provisioned local binding always owns mutable membership")488+ require.Equal(t, broker.MembershipMutable, selected.MembershipMode)
525 require.NotNil(t, selected.Local)489 require.NotNil(t, selected.Local)
526 require.Equal(t, binding.DisplayOrigin, selected.Local.DisplayOrigin)490 require.Equal(t, binding.DisplayOrigin, selected.Local.DisplayOrigin)
527 require.Equal(t, binding.Policy, selected.Local.Policy)491 require.Equal(t, binding.Policy, selected.Local.Policy)
528-
529- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
530- require.NoError(t, os.MkdirAll(root, 0o700))
531- writeSandboxConfig(t, root, sandboxRegistrationDocument("/tmp/vev-local-test/mux.sock"))
532- layout, err := brokerconfig.ResolveLayout(root, nil)
533- require.NoError(t, err)
534- remoteOnly, err := brokerconfig.Load(layout)
535- require.NoError(t, err)
536- disabled, err := offlineRegistryConfig(remoteOnly, brokerLocalTestEpoch, unreachableCarriageConnector(t))
537- require.NoError(t, err)
538- require.True(t, disabled.ObservationDisabled, "a fixture with no local binding stays explicitly disabled")
539- require.Nil(t, disabled.Local)
540 }492 }
541 493
542 // productionLocalConfig builds one production-shaped broker configuration whose494 // productionLocalConfig builds one production-shaped broker configuration whose
@@ -692,38 +644,6 @@ func TestBrokerLocalObservationNeverSpawnsDaemon(t *testing.T) {
692 }644 }
693 645
694 // TestOfflineRegistryConfigExplicitDisabledFixtureStaysDisabled proves an646 // TestOfflineRegistryConfigExplicitDisabledFixtureStaysDisabled proves an
695-// explicitly configured fixture that provisions no local binding remains a
696-// read-only snapshot owner: it issues no probes, arms no timers, and never
697-// reconciles, so its disabled mode is never inferred from an identity.
698-func TestOfflineRegistryConfigExplicitDisabledFixtureStaysDisabled(t *testing.T) {
699- root := filepath.Join(shortTempDir(t, "vevl"), "sandbox")
700- require.NoError(t, os.MkdirAll(root, 0o700))
701- writeSandboxConfig(t, root, sandboxEmptyDocument("3s"))
702- layout, err := brokerconfig.ResolveLayout(root, nil)
703- require.NoError(t, err)
704- config, err := brokerconfig.Load(layout)
705- require.NoError(t, err)
706-
707- selected, err := offlineRegistryConfig(config, brokerLocalTestEpoch, unreachableCarriageConnector(t))
708- require.NoError(t, err)
709- require.True(t, selected.ObservationDisabled)
710- require.Nil(t, selected.Local)
711-
712- stateDir := filepath.Join(shortTempDir(t, "vevl"), "state")
713- store, err := brokerstore.Open(brokerstore.Options{Dir: stateDir})
714- require.NoError(t, err)
715- t.Cleanup(func() { require.NoError(t, store.Close()) })
716- registry, err := broker.NewRegistryWithConfig(brokerLocalTestEpoch, store, nil, clock.New(), discardLog(), selected)
717- require.NoError(t, err)
718- startLocalRegistry(t, registry)
719-
720- // A disabled registry publishes its restored durable state and then stays
721- // read-only: no probe, no reconcile, and a zero-host mutation is refused.
722- require.Eventually(t, func() bool { return registry.Snapshot().Epoch != 0 }, brokerTestWait, time.Millisecond)
723- _, err = registry.AddHost(context.Background(), "user@example.com", localDaemonPolicy())
724- require.ErrorIs(t, err, ports.ErrBrokerMembershipImmutable, "an explicitly disabled fixture owns no mutable membership")
725-}
726-
727 // TestProductionRegistryOwnsMutableMembershipWithZeroHosts proves the production647 // TestProductionRegistryOwnsMutableMembershipWithZeroHosts proves the production
728 // composition owns host membership for its whole run even when it starts with648 // composition owns host membership for its whole run even when it starts with
729 // no configured host at all: the broker may precede every registration, so a649 // no configured host at all: the broker may precede every registration, so a

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close