mirror of
https://github.com/Tencent/WeKnora.git
synced 2026-10-15 19:42:35 +08:00
* feat(localsandbox): add host OS sandbox core and macOS Seatbelt backend Introduce a standalone localsandbox package so Lite can run agent commands on the user's machine under Seatbelt, without linking this into cmd/server or changing remote sandbox behavior. * fix(localsandbox): stop post-wait Kill, deny credential files, and refuse swapped roots Seatbelt was SIGKILL-ing the process group after every successful Wait, credential write denies omitted literal matches for files, PathGuard followed a replaced workspace root, and the login-shell test never ran -lc. * fix(localsandbox): tighten app-data deny, env inherit, and post-wait Kill Keep ask/full from silently widening to auto, stop inheriting host secrets, and make session workspaces survive midnight so the Seatbelt kernel stays fail-closed before adapter wiring. * fix(localsandbox): pass gofmt, errcheck, and revive on the new package CI now lints from the merge base, so the host sandbox needs formatted tests, checked Close() results, and exported comments. * fix(localsandbox): refuse broad workspaces and stop leaking host secrets Keep the host sandbox fail-closed before adapter wiring: home/Users/Volumes cannot be the workspace, login shells no longer re-import rc secrets, and Service applies the env allowlist on every Run. Also close the Lstat TOCTOU and post-wait Kill window. * fix(localsandbox): check Close() in seatbelt spawn tests * fix(localsandbox): deny host temp dirs and refuse leftover wide workspaces file-read* still left /tmp and /var/folders readable, and Build/Relax accepted /private/var, /System/Volumes/Data, and ~/Library/** as a workspace, which re-opened the private deny. Also re-open only ~/.local/bin. --------- Co-authored-by: hailongzhao <hailongzhao@tencent.com> Co-authored-by: wizardchen <wizardchen@tencent.com>
42 lines
1.3 KiB
Go
42 lines
1.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// shellAssignmentPattern finds NAME=value in a model-built shell command.
|
|
// The name must be UPPER_SNAKE_CASE so flags like --model and URLs are not
|
|
// treated as environment variables.
|
|
var shellAssignmentPattern = regexp.MustCompile(
|
|
`(?:^|[;|&\s])(?:export\s+)?([A-Z_][A-Z0-9_]{0,127})=(?:"([^"]*)"|'([^']*)'|([^\s;|&]+))`,
|
|
)
|
|
|
|
// MaskCommandAssignments replaces the value of every NAME=value assignment
|
|
// with a placeholder. A command is logged at Info, and passing a credential
|
|
// inline is a documented way to hand a skill its key, so the raw string must
|
|
// never reach the log.
|
|
func MaskCommandAssignments(command string) string {
|
|
return shellAssignmentPattern.ReplaceAllStringFunc(command, func(match string) string {
|
|
eq := strings.Index(match, "=")
|
|
if eq < 0 {
|
|
return match
|
|
}
|
|
return match[:eq+1] + "***"
|
|
})
|
|
}
|
|
|
|
// ExtractShellAssignments returns NAME=value pairs from a model-built command.
|
|
func ExtractShellAssignments(command string) map[string]string {
|
|
out := map[string]string{}
|
|
for _, match := range shellAssignmentPattern.FindAllStringSubmatch(command, -1) {
|
|
name := match[1]
|
|
value := match[2] + match[3] + match[4]
|
|
if name == "" || value == "" {
|
|
continue
|
|
}
|
|
out[name] = value
|
|
}
|
|
return out
|
|
}
|