返回 DeepSeek-Reasonix
write_access.go
根目录 / internal / config / write_access.go
1 package config
2
3 import (
4 "os"
5 "path/filepath"
6 "strings"
7
8 "reasonix/internal/permission"
9 "reasonix/internal/sandbox"
10 )
11
12 // PersistWorkspaceWriteAccess records extra writable directories and an
13 // optional allow rule for workspace root under the user's Reasonix home, in
14 // one locked update. permRule may be empty when permission is already allowed.
15 func PersistWorkspaceWriteAccess(reasonixHome, root string, dirs []string, permRule string) error {
16 home, _ := os.UserHomeDir()
17 return NewProjectGrantStore(reasonixHome).Update(root, func(g ProjectGrant) (ProjectGrant, error) {
18 for _, dir := range dirs {
19 formatted := sandbox.FormatConfigWritePath(dir, home)
20 if formatted != "" && !writeRootCovered(g.AllowWrite, formatted, home) {
21 g.AllowWrite = append(g.AllowWrite, formatted)
22 }
23 }
24 if rule := strings.TrimSpace(permRule); rule != "" && coveredPermissionRule(g.Allow, rule) == "" {
25 g.Allow = append(pruneCoveredPermissionRules(g.Allow, rule), rule)
26 }
27 return g, nil
28 })
29 }
30
31 func writeRootCovered(existing []string, candidate, home string) bool {
32 candAbs := expandPersistedWritePath(candidate, home)
33 for _, item := range existing {
34 existAbs := expandPersistedWritePath(item, home)
35 if existAbs == "" || candAbs == "" {
36 if item == candidate {
37 return true
38 }
39 continue
40 }
41 if sandbox.PathWithin(existAbs, candAbs) {
42 return true
43 }
44 }
45 return false
46 }
47
48 func expandPersistedWritePath(raw, home string) string {
49 raw = strings.TrimSpace(raw)
50 if raw == "" {
51 return ""
52 }
53 abs, _, err := sandbox.NormalizeWriteDir(raw, "", home)
54 if err != nil {
55 if filepath.IsAbs(raw) {
56 return filepath.Clean(raw)
57 }
58 return raw
59 }
60 return abs
61 }
62
63 func coveredPermissionRule(existing []string, candidate string) string {
64 for _, item := range existing {
65 if permission.RuleCoversString(item, candidate) {
66 return item
67 }
68 }
69 return ""
70 }
71
72 func pruneCoveredPermissionRules(existing []string, candidate string) []string {
73 out := make([]string, 0, len(existing))
74 for _, item := range existing {
75 if permission.RuleCoversString(candidate, item) && item != candidate {
76 continue
77 }
78 out = append(out, item)
79 }
80 return out
81 }
82
82 lines GO