detached ece7682

session_admission.go RawHistoryFolder

1package ports
2
3import (
4	"errors"
5	"fmt"
6	"unicode/utf8"
7
8	"github.com/bnema/vev/internal/domain"
9	"github.com/bnema/vev/internal/protocol"
10)
11
12// SessionConnectionOrigin is the closed carriage-origin taxonomy for one
13// admitted session connection: which provisioned carriage shape accepted it.
14// It is the locality bound an admission is validated against - a connection is
15// either the broker's own local carriage or one provisioned remote carriage -
16// and Unknown is never a validated admission.
17type SessionConnectionOrigin uint8
18
19const (
20	// SessionOriginUnknown is the zero value: no provisioned origin was stamped.
21	// It is refused by SessionAdmission.Validate and never produced by an
22	// accepting side that provisioned a binding.
23	SessionOriginUnknown SessionConnectionOrigin = iota
24	// SessionOriginLocal is a carriage to the accepting side's own machine
25	// daemon, which is not a configured remote host.
26	SessionOriginLocal
27	// SessionOriginRemote is a carriage provisioned for a configured remote
28	// endpoint.
29	SessionOriginRemote
30)
31
32func (o SessionConnectionOrigin) String() string {
33	switch o {
34	case SessionOriginUnknown:
35		return "unknown"
36	case SessionOriginLocal:
37		return "local"
38	case SessionOriginRemote:
39		return "remote"
40	default:
41		return fmt.Sprintf("invalid(%d)", uint8(o))
42	}
43}
44
45// Validate refuses the zero value: every validated admission names exactly one
46// provisioned locality rather than inheriting an implicit one.
47func (o SessionConnectionOrigin) Validate() error {
48	switch o {
49	case SessionOriginLocal, SessionOriginRemote:
50		return nil
51	default:
52		return errors.New("ports: invalid session connection origin")
53	}
54}
55
56// SessionAdmission is the closed admission metadata of one admitted session
57// connection: the provisioned carriage shape that accepted it,
58// the exact accepted policy, the declared stream purpose, and - for attachment
59// purposes only - the closed admission variant, its validated creation name,
60// its exact session target, and its bounded per-request environment.
61//
62// It is stamped by the accepting side from its own provisioned authority and
63// the peer's validated Open, never echoed from an untrusted request, and is
64// exposed to a daemon-consuming use case through SessionAdmissionProvider. It
65// carries no wire form of its own: the mux Open already carries every field,
66// and an admission is reconstructed at acceptance from that Open plus the
67// provisioned origin.
68type SessionAdmission struct {
69	// Origin is the provisioned carriage shape that accepted this connection.
70	// It is never Unknown on a validated admission.
71	Origin SessionConnectionOrigin
72	// Policy is the exact accepted physical policy, resolved from the
73	// provisioned binding, never the peer's requested value.
74	Policy BrokerPolicy
75	// Purpose is the closed stream purpose the admitted stream declared.
76	Purpose BrokerStreamPurpose
77	// Admission is the closed attachment-admission variant. It is nonzero only
78	// for BrokerStreamAttachment; control and observation carry none.
79	Admission BrokerStreamAdmission
80	// Name is the validated session name for BrokerAdmissionCreateNamed and
81	// BrokerAdmissionAttachNamed and is empty for every other variant.
82	Name string
83	// Target is the exact session lifecycle target for BrokerAdmissionExact and
84	// is zero for every other variant.
85	Target protocol.ExactSessionTarget
86	// Env is the bounded per-request session environment. It is empty for
87	// control and observation and is never merged into a process environment.
88	Env []string
89}
90
91// Validate enforces the closed admission contract: a known carriage origin, a
92// valid policy, a closed purpose with its matching admission shape, and the
93// per-request environment bounds. Unknown origin, an unset purpose, an
94// attachment shape that contradicts its purpose, and any out-of-bound value are
95// refused.
96//
97// Locality bound: an admission is accepted only for a known Local or Remote
98// origin. A zero (Unknown) origin is never a validated admission, so a consumer
99// can trust that an admission it is handed names exactly one carriage shape.
100func (a SessionAdmission) Validate() error {
101	if err := a.Origin.Validate(); err != nil {
102		return err
103	}
104	if err := a.Policy.Validate(); err != nil {
105		return err
106	}
107	switch a.Purpose {
108	case BrokerStreamAttachment:
109		if err := a.Admission.Validate(); err != nil {
110			return err
111		}
112		switch a.Admission {
113		case BrokerAdmissionExact:
114			if err := a.Target.Validate(); err != nil {
115				return err
116			}
117			if a.Name != "" {
118				return errors.New("ports: exact admission carries a creation name")
119			}
120		case BrokerAdmissionCreateNamed, BrokerAdmissionAttachNamed:
121			if a.Target != (protocol.ExactSessionTarget{}) {
122				return errors.New("ports: named admission carries an exact target")
123			}
124			if err := domain.ValidateSessionName(a.Name); err != nil {
125				return fmt.Errorf("ports: invalid admission session name: %w", err)
126			}
127		case BrokerAdmissionCreateEphemeral:
128			if a.Target != (protocol.ExactSessionTarget{}) {
129				return errors.New("ports: ephemeral creation carries an exact target")
130			}
131			if a.Name != "" {
132				return errors.New("ports: ephemeral creation carries a session name")
133			}
134		}
135	case BrokerStreamControl, BrokerStreamObservation:
136		if a.Admission != 0 || a.Name != "" || a.Target != (protocol.ExactSessionTarget{}) || len(a.Env) != 0 {
137			return errors.New("ports: control/observation carries attachment state")
138		}
139	default:
140		return errors.New("ports: invalid session admission purpose")
141	}
142	if uint64(len(a.Env)) > BrokerMaxEnvEntries {
143		return errors.New("ports: session admission has too many environment entries")
144	}
145	for _, entry := range a.Env {
146		if len(entry) > BrokerMaxEnvEntryBytes {
147			return errors.New("ports: session admission environment entry too long")
148		}
149		if !utf8.ValidString(entry) {
150			return errors.New("ports: session admission environment is not valid UTF-8")
151		}
152	}
153	return nil
154}
155
156// Clone returns a deep copy with an independent environment slice, so a
157// consumer that mutates what it holds can never alter admitted authority or a
158// sibling's view of it.
159func (a SessionAdmission) Clone() SessionAdmission {
160	out := a
161	out.Env = append([]string(nil), a.Env...)
162	return out
163}
164
165// SessionAdmissionProvider is the optional boundary-safe port a typed accepted
166// server connection implements when the accepting side stamped admission
167// metadata onto it. A daemon-consuming use case asserts it structurally; a
168// connection accepted without provisioned admission (the direct local daemon
169// socket used by broker-less list and stop commands) reports ok=false rather
170// than a zero admission, and the daemon applies standard Hello validation.
171//
172// The returned value is a defensive copy: mutating it never alters the
173// connection's admitted authority, and concurrent readers each receive their
174// own copy.
175type SessionAdmissionProvider interface {
176	SessionAdmission() (SessionAdmission, bool)
177}

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