v3.3.1 31f1eec

app_mounts.go RawHistoryFolder

1package app
2
3import (
4	"fmt"
5	"path/filepath"
6	"regexp"
7	"strings"
8
9	"github.com/bnema/gordon/internal/domain"
10)
11
12// AppMountPolicy is one administrative bind policy declared under
13// [[app_mounts.<name>]]. The map key is the stable mount name an app manifest
14// bind references. Source is the only host path a bind may come from. Root,
15// when set, is the administrative boundary the resolved source must stay
16// under. AllowedApps and AllowedServices are exact, non-empty allowlists.
17type AppMountPolicy struct {
18	Source          string   `mapstructure:"source"`
19	ReadOnly        bool     `mapstructure:"read_only"`
20	AllowedApps     []string `mapstructure:"allowed_apps"`
21	AllowedServices []string `mapstructure:"allowed_services"`
22	Root            string   `mapstructure:"root"`
23}
24
25// policyQuotedValue matches the quoted values domain validation embeds in
26// its messages, such as configured source paths or roots.
27var policyQuotedValue = regexp.MustCompile(`"[^"]*"`)
28
29// redactedBindPolicyReason keeps the field-level reason from a domain policy
30// validation error (for example "source must be absolute") while stripping
31// every quoted value so an invalid config never echoes host paths.
32func redactedBindPolicyReason(err error) string {
33	reason := policyQuotedValue.ReplaceAllString(err.Error(), "")
34	reason = strings.Join(strings.Fields(reason), " ")
35	// Keep only the innermost detail: the outer wrap repeats the generic
36	// violation and the policy name, which is already part of the mount key.
37	if idx := strings.LastIndex(reason, ": "); idx >= 0 {
38		reason = reason[idx+2:]
39	}
40	return reason
41}
42
43// buildAppMountPolicies converts configured app mounts into validated domain
44// policies. Failures name only the mount and the field-level reason: source
45// paths are never echoed.
46func buildAppMountPolicies(cfg Config) (map[string]domain.AppBindPolicy, error) {
47	policies := make(map[string]domain.AppBindPolicy, len(cfg.AppMounts))
48	for name, mount := range cfg.AppMounts {
49		root := mount.Root
50		if root == "" && filepath.IsAbs(mount.Source) {
51			// The source's parent is the least surprising implicit
52			// administrative boundary for the documented minimal form.
53			// A symlink source may resolve within it, never escape it.
54			root = filepath.Dir(mount.Source)
55		}
56		policy := domain.AppBindPolicy{
57			Name:            name,
58			Source:          mount.Source,
59			ReadOnly:        mount.ReadOnly,
60			AllowedApps:     mount.AllowedApps,
61			AllowedServices: mount.AllowedServices,
62			Root:            root,
63		}
64		if err := policy.Validate(); err != nil {
65			return nil, fmt.Errorf("invalid app_mounts.%s: %w: %s", name, domain.ErrBindPolicy, redactedBindPolicyReason(err))
66		}
67		policies[name] = policy
68	}
69	return policies, nil
70}

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 7

Tags 106

↑↓ moveenter openesc close