detached 27e453c

ci_workflow_guard.go RawHistoryFolder

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package domain
4
5import "fmt"
6
7// PushObjectType is the type of a peeled Git object.
8type PushObjectType string
9
10// Peeled object types accepted by the push tree reader.
11const (
12	PushObjectCommit PushObjectType = "commit"
13	PushObjectTree   PushObjectType = "tree"
14	PushObjectBlob   PushObjectType = "blob"
15)
16
17// PushWalkBounds bounds the walk over the commits of a push.
18type PushWalkBounds struct{ Commits, IDs int }
19
20// Bounds fail closed and count repeated parent IDs too.
21const (
22	MaxPushedCommits = 10000
23	MaxPushedIDs     = 4 * MaxPushedCommits
24)
25
26// DefaultPushWalkBounds returns the job-token push walk limits.
27func DefaultPushWalkBounds() PushWalkBounds { return PushWalkBounds{MaxPushedCommits, MaxPushedIDs} }
28
29// Subtree is the kind and identity of an entry at a tree path.
30type Subtree struct {
31	Kind EntryKind
32	ID   ObjectID
33}
34
35// PushedCommit is a newly reachable commit with its ordered parents.
36type PushedCommit struct {
37	ID      ObjectID
38	Parents []ObjectID
39}
40
41// HeadKey identifies the default branch head in PushSubtrees.Subtrees.
42const HeadKey = "HEAD"
43
44// PushSubtrees contains endpoint types and entries keyed by original object ID
45// (or HeadKey), and newly reachable commits in rev-list order. Absent entries
46// mean there is no subtree at the requested path.
47type PushSubtrees struct {
48	Ends     map[string]PushObjectType
49	Commits  []PushedCommit
50	Subtrees map[string]Subtree
51}
52
53// WorkflowTreeChange is the first forbidden workflow-tree replacement.
54// A zero Old denotes no workflow directory.
55type WorkflowTreeChange struct{ Old, New ObjectID }
56
57// WorkflowChangeOf applies the job-token workflow policy. Every new commit must
58// keep the workflows of at least one parent; then each ref must keep its old
59// workflows (HEAD's for a new ref). Disappearance and ref deletion are allowed.
60// New commits are judged before ref ends, in their supplied order. Missing ends
61// are a reader contract breach and fail closed with ErrInvalid.
62func WorkflowChangeOf(updates []RefUpdate, t PushSubtrees) (WorkflowTreeChange, bool, error) {
63	for _, up := range updates {
64		if up.IsDelete() {
65			continue
66		}
67		ids := []string{up.New}
68		if !up.IsCreate() {
69			ids = append(ids, up.Old)
70		}
71		for _, id := range ids {
72			if _, ok := t.Ends[id]; !ok {
73				return WorkflowTreeChange{}, false, fmt.Errorf("%w: missing push end %s", ErrInvalid, id)
74			}
75		}
76	}
77	dirOf := func(key string) ObjectID {
78		s := t.Subtrees[key]
79		if s.Kind != EntryDirectory {
80			return ObjectID{}
81		}
82		return s.ID
83	}
84	for _, c := range t.Commits {
85		cur := dirOf(c.ID.String())
86		if cur.IsZero() {
87			continue
88		}
89		var first ObjectID
90		same := false
91		for i, p := range c.Parents {
92			w := dirOf(p.String())
93			if i == 0 {
94				first = w
95			}
96			if w == cur {
97				same = true
98			}
99		}
100		if !same {
101			return WorkflowTreeChange{first, cur}, true, nil
102		}
103	}
104	for _, up := range updates {
105		if up.IsDelete() || t.Ends[up.New] == PushObjectBlob {
106			continue
107		}
108		cur := dirOf(up.New)
109		if cur.IsZero() {
110			continue
111		}
112		var base ObjectID
113		if up.IsCreate() {
114			base = dirOf(HeadKey)
115		} else if t.Ends[up.Old] != PushObjectBlob {
116			base = dirOf(up.Old)
117		}
118		if base != cur {
119			return WorkflowTreeChange{base, cur}, true, nil
120		}
121	}
122	return WorkflowTreeChange{}, false, nil
123}

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 4

Tags 45

↑↓ moveenter openesc close