main ece7682

server_admission_test.go RawHistoryFolder

1package sessionwire
2
3import (
4	"testing"
5	"time"
6
7	"github.com/stretchr/testify/require"
8
9	"github.com/bnema/vev/internal/domain"
10	"github.com/bnema/vev/internal/ports"
11	"github.com/bnema/vev/internal/protocol"
12)
13
14func wireTestPolicy() ports.BrokerPolicy {
15	return ports.BrokerPolicy{
16		ProtocolVersion:      protocol.Version,
17		CatalogSchemaVersion: 3,
18		EnvironmentPolicy:    protocol.EnvironmentPolicyDaemonOwned,
19		Transport:            "unix-mux",
20		Trust:                "same-user",
21		Launch:               "explicit",
22		Isolation:            "per-user",
23	}
24}
25
26func wireTestAdmission() ports.SessionAdmission {
27	return ports.SessionAdmission{
28		Origin:    ports.SessionOriginLocal,
29		Policy:    wireTestPolicy(),
30		Purpose:   ports.BrokerStreamAttachment,
31		Admission: ports.BrokerAdmissionExact,
32		Target:    protocol.ExactSessionTarget{LifecycleID: domain.SessionLifecycleID{4, 5, 6}, SessionName: "work"},
33		Env:       []string{"TERM=xterm-256color"},
34	}
35}
36
37// TestServerConnectionAdmissionProviderPreservedWithoutWireChange proves the
38// admission-aware constructor stores the provisioned metadata and exposes it
39// through the optional provider, while a successful typed round trip over the
40// same connection is byte-for-byte the ordinary session traffic: the admission
41// never leaks onto the session wire.
42func TestServerConnectionAdmissionProviderPreservedWithoutWireChange(t *testing.T) {
43	raw := &scriptedTransport{recv: mustServerPreambleQueue(t, mustEncodeClient(t, protocol.Ping{}))}
44	deadline := time.Now().Add(protocol.HandshakeTimeout)
45	connection := NewServerConnectionWithAdmission(raw, deadline, wireTestAdmission())
46
47	provider, ok := connection.(ports.SessionAdmissionProvider)
48	require.True(t, ok, "the admission-aware connection implements the optional provider")
49	admission, ok := provider.SessionAdmission()
50	require.True(t, ok)
51	require.Equal(t, wireTestAdmission(), admission)
52	require.NoError(t, admission.Validate())
53
54	// A typed exchange on the same connection succeeds and the sent application
55	// frame is the ordinary Pong encoding: the admission is not part of the
56	// session wire. (The preamble response precedes it.)
57	message, err := connection.ReceiveClient()
58	require.NoError(t, err)
59	require.Equal(t, protocol.Ping{}, message)
60	require.NoError(t, connection.SendServer(protocol.Pong{}))
61	require.Equal(t, 2, raw.sentLen())
62	got, err := DecodeServerEnvelope(raw.sentPayload(1))
63	require.NoError(t, err)
64	require.Equal(t, protocol.Pong{}, got)
65}
66
67// TestServerConnectionAdmissionProviderIsDefensiveCopy proves the provider hands
68// out an independent copy on every read: a consumer that mutates what it holds
69// never alters the connection's stored admission or a sibling's view.
70func TestServerConnectionAdmissionProviderIsDefensiveCopy(t *testing.T) {
71	raw := &scriptedTransport{}
72	connection := NewServerConnectionWithAdmission(raw, time.Now().Add(protocol.HandshakeTimeout), wireTestAdmission())
73	provider := connection.(ports.SessionAdmissionProvider)
74
75	mutated, ok := provider.SessionAdmission()
76	require.True(t, ok)
77	mutated.Env[0] = "TERM=mutated"
78	mutated.Policy.Trust = "mutated"
79	mutated.Target.SessionName = "mutated"
80
81	reread, ok := provider.SessionAdmission()
82	require.True(t, ok)
83	require.Equal(t, wireTestAdmission(), reread)
84
85	left, _ := provider.SessionAdmission()
86	right, _ := provider.SessionAdmission()
87	left.Env[0] = "TERM=left"
88	require.Equal(t, "TERM=xterm-256color", right.Env[0])
89}
90
91// TestServerConnectionAdmissionAbsentForLegacyConstructors proves the legacy
92// constructors carry no admission metadata: a consumer that asserts the
93// provider is told ok=false rather than trusted with a zero admission.
94func TestServerConnectionAdmissionAbsentForLegacyConstructors(t *testing.T) {
95	for _, tc := range []struct {
96		name  string
97		build func() ports.ServerConnection
98	}{
99		{name: "NewServerConnection", build: func() ports.ServerConnection { return NewServerConnection(&scriptedTransport{}) }},
100		{name: "NewServerConnectionWithDeadline", build: func() ports.ServerConnection {
101			return NewServerConnectionWithDeadline(&scriptedTransport{}, time.Now().Add(protocol.HandshakeTimeout))
102		}},
103		{name: "NewServerConnectionWithAdmission zero", build: func() ports.ServerConnection {
104			return NewServerConnectionWithAdmission(&scriptedTransport{}, time.Now().Add(protocol.HandshakeTimeout), ports.SessionAdmission{})
105		}},
106	} {
107		t.Run(tc.name, func(t *testing.T) {
108			provider, ok := tc.build().(ports.SessionAdmissionProvider)
109			require.True(t, ok)
110			admission, present := provider.SessionAdmission()
111			require.False(t, present)
112			require.Equal(t, ports.SessionAdmission{}, admission)
113		})
114	}
115}

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