mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-06-10 06:10:46 +00:00
843b550651
Runtime package management with security hardening: - pkg-helper: root-privileged daemon for apk install/uninstall via Unix socket - HTTP API: /v1/packages (list/install/uninstall/runtimes), admin role required for writes - Shell deny groups: 15 configurable groups (per-agent overrides via context) - Packages UI: Web page for managing system/pip/npm packages with confirmation dialogs - Docker: privilege separation (root entrypoint → su-exec drop), init for zombie reaping - Security: umask socket creation, persist file validation, deny pattern hardening (Node.js fetch/http, Python from/import, curl localhost, sensitive env vars) - Auth: empty gateway token → admin role (dev/single-user mode)
140 lines
4.6 KiB
Go
140 lines
4.6 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type contextKey string
|
|
|
|
const (
|
|
// UserIDKey is the context key for the external user ID (TEXT, free-form).
|
|
UserIDKey contextKey = "goclaw_user_id"
|
|
// AgentIDKey is the context key for the agent UUID.
|
|
AgentIDKey contextKey = "goclaw_agent_id"
|
|
// AgentTypeKey is the context key for the agent type ("open" or "predefined").
|
|
AgentTypeKey contextKey = "goclaw_agent_type"
|
|
// SenderIDKey is the original individual sender's ID (not group-scoped).
|
|
// In group chats, UserIDKey is group-scoped but SenderIDKey preserves
|
|
// the actual person who sent the message.
|
|
SenderIDKey contextKey = "goclaw_sender_id"
|
|
// SelfEvolveKey indicates whether a predefined agent can update its SOUL.md.
|
|
SelfEvolveKey contextKey = "goclaw_self_evolve"
|
|
// LocaleKey is the context key for the user's preferred locale (e.g. "en", "vi", "zh").
|
|
LocaleKey contextKey = "goclaw_locale"
|
|
// SharedMemoryKey indicates memory should be shared (no per-user scoping).
|
|
SharedMemoryKey contextKey = "goclaw_shared_memory"
|
|
// ShellDenyGroupsKey holds per-agent shell deny group overrides.
|
|
ShellDenyGroupsKey contextKey = "goclaw_shell_deny_groups"
|
|
)
|
|
|
|
// WithShellDenyGroups returns a new context with shell deny group overrides.
|
|
func WithShellDenyGroups(ctx context.Context, groups map[string]bool) context.Context {
|
|
return context.WithValue(ctx, ShellDenyGroupsKey, groups)
|
|
}
|
|
|
|
// ShellDenyGroupsFromContext returns shell deny group overrides from the context, or nil.
|
|
func ShellDenyGroupsFromContext(ctx context.Context) map[string]bool {
|
|
v, _ := ctx.Value(ShellDenyGroupsKey).(map[string]bool)
|
|
return v
|
|
}
|
|
|
|
// WithUserID returns a new context with the given user ID.
|
|
func WithUserID(ctx context.Context, id string) context.Context {
|
|
return context.WithValue(ctx, UserIDKey, id)
|
|
}
|
|
|
|
// UserIDFromContext extracts the user ID from context. Returns "" if not set.
|
|
func UserIDFromContext(ctx context.Context) string {
|
|
if v, ok := ctx.Value(UserIDKey).(string); ok {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// WithAgentID returns a new context with the given agent UUID.
|
|
func WithAgentID(ctx context.Context, id uuid.UUID) context.Context {
|
|
return context.WithValue(ctx, AgentIDKey, id)
|
|
}
|
|
|
|
// AgentIDFromContext extracts the agent UUID from context. Returns uuid.Nil if not set.
|
|
func AgentIDFromContext(ctx context.Context) uuid.UUID {
|
|
if v, ok := ctx.Value(AgentIDKey).(uuid.UUID); ok {
|
|
return v
|
|
}
|
|
return uuid.Nil
|
|
}
|
|
|
|
// WithAgentType returns a new context with the given agent type.
|
|
func WithAgentType(ctx context.Context, t string) context.Context {
|
|
return context.WithValue(ctx, AgentTypeKey, t)
|
|
}
|
|
|
|
// AgentTypeFromContext extracts the agent type from context. Returns "" if not set.
|
|
func AgentTypeFromContext(ctx context.Context) string {
|
|
if v, ok := ctx.Value(AgentTypeKey).(string); ok {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// WithSenderID returns a new context with the original individual sender ID.
|
|
func WithSenderID(ctx context.Context, id string) context.Context {
|
|
return context.WithValue(ctx, SenderIDKey, id)
|
|
}
|
|
|
|
// SenderIDFromContext extracts the sender ID from context. Returns "" if not set.
|
|
func SenderIDFromContext(ctx context.Context) string {
|
|
if v, ok := ctx.Value(SenderIDKey).(string); ok {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// WithSelfEvolve returns a new context with the self-evolve flag.
|
|
func WithSelfEvolve(ctx context.Context, v bool) context.Context {
|
|
return context.WithValue(ctx, SelfEvolveKey, v)
|
|
}
|
|
|
|
// SelfEvolveFromContext extracts the self-evolve flag from context. Returns false if not set.
|
|
func SelfEvolveFromContext(ctx context.Context) bool {
|
|
if v, ok := ctx.Value(SelfEvolveKey).(bool); ok {
|
|
return v
|
|
}
|
|
return false
|
|
}
|
|
|
|
// WithSharedMemory returns a context flagged for shared memory (skip per-user scoping).
|
|
func WithSharedMemory(ctx context.Context) context.Context {
|
|
return context.WithValue(ctx, SharedMemoryKey, true)
|
|
}
|
|
|
|
// IsSharedMemory returns true if memory should be shared across users.
|
|
func IsSharedMemory(ctx context.Context) bool {
|
|
v, _ := ctx.Value(SharedMemoryKey).(bool)
|
|
return v
|
|
}
|
|
|
|
// MemoryUserID returns the userID to use for memory operations.
|
|
// Returns "" (shared/global) when shared memory is active, otherwise the per-user ID.
|
|
func MemoryUserID(ctx context.Context) string {
|
|
if IsSharedMemory(ctx) {
|
|
return ""
|
|
}
|
|
return UserIDFromContext(ctx)
|
|
}
|
|
|
|
// WithLocale returns a new context with the given locale.
|
|
func WithLocale(ctx context.Context, locale string) context.Context {
|
|
return context.WithValue(ctx, LocaleKey, locale)
|
|
}
|
|
|
|
// LocaleFromContext extracts the locale from context. Returns "en" if not set.
|
|
func LocaleFromContext(ctx context.Context) string {
|
|
if v, ok := ctx.Value(LocaleKey).(string); ok && v != "" {
|
|
return v
|
|
}
|
|
return "en"
|
|
}
|