v0.2.0 13c6a90

security_capture_test.go RawHistoryFolder

1package drm
2
3import (
4	"context"
5	"errors"
6	"os"
7	"sync/atomic"
8	"testing"
9
10	"github.com/bnema/neferwl/internal/adapters/capture"
11	portsmocks "github.com/bnema/neferwl/internal/mocks/ports"
12	"github.com/bnema/neferwl/internal/ports"
13	"github.com/stretchr/testify/mock"
14)
15
16func TestSecurityEngageDuringExcludeRenderRejectsCaptureTransfer(t *testing.T) {
17	o, _, commits := testOutput(t)
18	o.cursor = nil
19	var state atomic.Uint64
20	securityGate(t, o, &state)
21	r := portsmocks.NewMockRenderer(t)
22	f, _ := protectionFence(t, false)
23	r.EXPECT().UseTarget(0).Return().Once()
24	r.EXPECT().Render(mock.Anything, mock.Anything).RunAndReturn(func(ports.Scene, map[ports.WindowID]ports.SurfaceContent) (*os.File, error) {
25		state.Store(3)
26		return f, nil
27	}).Once()
28	replies := make(chan ports.CaptureDone, 2)
29	pipeline := capture.NewPipeline(context.Background(), replies)
30	requests := []ports.CaptureRequest{sessionRequest(t, 1, true), sessionRequest(t, 2, false)}
31	files := []*os.File{requests[0].Dst.File, requests[1].Dst.File}
32	_, err := o.submitFrame(context.Background(), r, drmSessionScene(), nil, nil, requests, pipeline)
33	if !errors.Is(err, errSecurityScene) || len(*commits) != 0 {
34		t.Fatalf("capture admission result: %v", err)
35	}
36	if len(o.readFences) != 1 || o.readDone() {
37		t.Fatal("rejected excluded render dropped GPU reads")
38	}
39	if _, err := f.Stat(); !errors.Is(err, os.ErrClosed) {
40		t.Fatal("returned excluded fence not closed")
41	}
42	// Match Run's remaining-credit rejection: nothing was transferred to the
43	// worker, each request is failed once, and every owned FD is closed.
44	for _, q := range requests {
45		if capture.Handed(q) {
46			t.Fatal("obsolete capture transferred credit")
47		}
48		capture.Fail(context.Background(), q, err, replies)
49	}
50	pipeline.Close(r)
51	r.AssertNotCalled(t, "BeginCapture")
52	if len(replies) != 2 {
53		t.Fatalf("capture replies %d", len(replies))
54	}
55	for range 2 {
56		if reply := <-replies; !errors.Is(reply.Err, errSecurityScene) {
57			t.Fatalf("reply %+v", reply)
58		}
59	}
60	for _, file := range files {
61		if _, err := file.Stat(); !errors.Is(err, os.ErrClosed) {
62			t.Fatal("capture FD not closed")
63		}
64	}
65	o.dropRead()
66}
67
68func TestSecurityHiddenAdmissionRechecksBeforeNativeStart(t *testing.T) {
69	o, _, _ := testOutput(t)
70	o.cursor = nil
71	security := portsmocks.NewMockSessionSecurity(t)
72	security.EXPECT().Snapshot().Return(ports.SecurityState{}).Once()
73	security.EXPECT().Snapshot().Return(ports.SecurityState{Generation: 1, Protected: true})
74	o.Security = security
75	r := portsmocks.NewMockRenderer(t)
76	child := portsmocks.NewMockRenderer(t)
77	replies := make(chan ports.CaptureDone, 1)
78	pipeline := capture.NewPipeline(context.Background(), replies)
79	pipeline.EnableOffscreen(func(int, int) (ports.Renderer, error) {
80		t.Fatal("obsolete hidden capture created child")
81		return child, nil
82	})
83	s := drmSessionScene()
84	s.CaptureScene = &ports.Scene{OutputWidth: 200, OutputHeight: 100, Scale: 1}
85	requests := []ports.CaptureRequest{sessionRequest(t, 1, true)}
86	file := requests[0].Dst.File
87	_, err := o.submitFrame(context.Background(), r, s, nil, nil, requests, pipeline)
88	if !errors.Is(err, errSecurityScene) || capture.Handed(requests[0]) {
89		t.Fatalf("hidden admission result %v", err)
90	}
91	capture.Fail(context.Background(), requests[0], err, replies)
92	pipeline.Close(r)
93	if len(replies) != 1 || (<-replies).ID != 1 {
94		t.Fatal("hidden request credit not failed once")
95	}
96	if _, err := file.Stat(); !errors.Is(err, os.ErrClosed) {
97		t.Fatal("hidden FD not closed")
98	}
99	r.AssertNotCalled(t, "BeginCapture")
100	child.AssertNotCalled(t, "Render", mock.Anything, mock.Anything)
101	child.AssertNotCalled(t, "BeginCapture")
102}

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 25

Tags 10

↑↓ moveenter openesc close