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 built by a legacy constructor that carries no provisioned
169// admission reports ok=false rather than a zero admission.
170//
171// The returned value is a defensive copy: mutating it never alters the
172// connection's admitted authority, and concurrent readers each receive their
173// own copy.
174type SessionAdmissionProvider interface {
175 SessionAdmission() (SessionAdmission, bool)
176}