detached ece7682

broker_acquisition.go RawHistoryFolder

1package ports
2
3import (
4	"context"
5	"errors"
6	"fmt"
7
8	"github.com/bnema/vev/internal/domain"
9)
10
11// BrokerEndpointFence identifies the exact route authority used for one dial.
12// Remote registrations carry their full incarnation/generation; local routes
13// are explicit and never fabricate a registration.
14type BrokerEndpointFence struct {
15	Local        bool
16	Registration domain.RemoteRegistration
17}
18
19func (f BrokerEndpointFence) Validate() error {
20	if f.Local {
21		if f.Registration != (domain.RemoteRegistration{}) {
22			return errors.New("ports: local endpoint fence carries a registration")
23		}
24		return nil
25	}
26	return f.Registration.Validate()
27}
28
29// BrokerDaemonStartMode is the closed, explicit authorization a caller attaches
30// to one acquisition: whether the transport may start the target daemon when it
31// is not already reachable, or must observe only what is already running.
32//
33// Purpose alone cannot carry this: a control stream that lists or mutates a
34// stopped daemon's persisted records is allowed to start it, while an
35// observation and the explicit daemon-stop itself must never start it. The mode
36// is an authorization, never an obligation: it can only narrow the configured
37// policy, and a policy that does not permit launching still refuses.
38type BrokerDaemonStartMode uint8
39
40const (
41	// BrokerDaemonExistingOnly authorizes only an already running daemon. A
42	// transport that carries this mode must never start a daemon, a broker, or
43	// any recursive helper process.
44	BrokerDaemonExistingOnly BrokerDaemonStartMode = iota + 1
45	// BrokerDaemonStartIfNeeded additionally authorizes starting the target
46	// daemon when it is not running, subject to the resolved policy's launch
47	// authority.
48	BrokerDaemonStartIfNeeded
49)
50
51func (m BrokerDaemonStartMode) String() string {
52	switch m {
53	case BrokerDaemonExistingOnly:
54		return "existing_only"
55	case BrokerDaemonStartIfNeeded:
56		return "start_if_needed"
57	default:
58		return fmt.Sprintf("invalid(%d)", uint8(m))
59	}
60}
61
62// Validate refuses the zero value: every acquisition states its start authority
63// explicitly rather than inheriting an implicit ability to start a daemon.
64func (m BrokerDaemonStartMode) Validate() error {
65	switch m {
66	case BrokerDaemonExistingOnly, BrokerDaemonStartIfNeeded:
67		return nil
68	default:
69		return errors.New("ports: invalid broker daemon start mode")
70	}
71}
72
73// BrokerExpectedIdentity is an explicit optional durable identity binding.
74// BrokerDaemonIdentity itself remains strict and is never valid when empty.
75type BrokerExpectedIdentity struct {
76	Identity BrokerDaemonIdentity
77	Bound    bool
78}
79
80func (e BrokerExpectedIdentity) Validate() error {
81	if !e.Bound {
82		if e.Identity != "" {
83			return errors.New("ports: unbound expected identity carries a value")
84		}
85		return nil
86	}
87	return e.Identity.Validate()
88}
89
90// BrokerDialTarget authorizes one bounded dial before authentication. Address
91// selects the adapter route; ExpectedIdentity fences an existing durable
92// binding but may be explicitly unbound for first contact. StartMode is carried
93// over from the resolution request and must reach the transport before any
94// connect-or-spawn decision.
95type BrokerDialTarget struct {
96	Fence            BrokerEndpointFence
97	Address          string
98	Policy           BrokerPolicy
99	StartMode        BrokerDaemonStartMode
100	ExpectedIdentity BrokerExpectedIdentity
101}
102
103func (t BrokerDialTarget) Validate() error {
104	if err := t.Fence.Validate(); err != nil {
105		return err
106	}
107	if err := t.StartMode.Validate(); err != nil {
108		return err
109	}
110	if err := t.Policy.Validate(); err != nil {
111		return err
112	}
113	if err := t.ExpectedIdentity.Validate(); err != nil {
114		return err
115	}
116	return validateBrokerToken(t.Address, BrokerMaxAddressBytes, "dial target address")
117}
118
119// BrokerRouteAuthority resolves current membership and route authority. It
120// performs no network I/O and never invents a daemon identity. Resolution
121// propagates BrokerOpenStreamRequest.StartMode onto the returned dial target
122// unchanged, so the resolved authority and the requested start mode are decided
123// together and neither can be widened afterwards.
124type BrokerRouteAuthority interface {
125	ResolveDialTarget(context.Context, BrokerOpenStreamRequest) (BrokerDialTarget, error)
126}
127
128// BrokerIdentityBindingRequest asks the broker authority to adopt an identity
129// learned from an authenticated carriage under the exact resolution fence.
130type BrokerIdentityBindingRequest struct {
131	Fence    BrokerEndpointFence
132	Policy   BrokerPolicy
133	Identity BrokerDaemonIdentity
134}
135
136func (r BrokerIdentityBindingRequest) Validate() error {
137	if err := r.Fence.Validate(); err != nil {
138		return err
139	}
140	if err := r.Policy.Validate(); err != nil {
141		return err
142	}
143	return r.Identity.Validate()
144}
145
146// BrokerIdentityBinder commits first-contact identity authority before a
147// physical connection may be published or carry a logical stream.
148type BrokerIdentityBinder interface {
149	BindAuthenticatedIdentity(context.Context, BrokerIdentityBindingRequest) (BrokerDaemonIdentity, error)
150}

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