Files
goclaw/internal/tools/credential_presets.go
T
Goon 75c570e951 feat(security): credentialed exec + HTTP RBAC + API key cache (#197)
- Secure CLI credential injection via AES-256-GCM encrypted env vars
- API key management with fine-grained RBAC scopes
- resolveAuth/requireAuth middleware across all 25+ HTTP handlers
- In-memory API key cache with TTL, negative caching, pubsub invalidation
- Sandbox-first execution (fails if unavailable, no silent fallback)
- Credential scrubbing, constant-time token comparison, Admin-only CLI creds
- SQL migration 000020: secure_cli_binaries + api_keys tables
- 14 unit tests for cache and RBAC with race detector

Closes #197
2026-03-15 20:13:18 +07:00

103 lines
3.3 KiB
Go

package tools
import "sort"
// CLIPreset defines a built-in configuration template for a common CLI tool.
// Presets eliminate admin research friction by pre-filling env var names,
// deny patterns, timeout, and usage tips.
type CLIPreset struct {
BinaryName string `json:"binary_name"`
Description string `json:"description"`
EnvVars []EnvVarDef `json:"env_vars"`
DenyArgs []string `json:"deny_args"`
DenyVerbose []string `json:"deny_verbose"`
Timeout int `json:"timeout"`
Tips string `json:"tips"`
}
// EnvVarDef describes an environment variable required by a CLI tool.
type EnvVarDef struct {
Name string `json:"name"`
Desc string `json:"desc"`
IsFile bool `json:"is_file,omitempty"` // credential is a file path (e.g. GOOGLE_APPLICATION_CREDENTIALS)
Optional bool `json:"optional,omitempty"`
}
// CLIPresets contains built-in presets for common CLI tools.
var CLIPresets = map[string]CLIPreset{
"gh": {
BinaryName: "gh",
Description: "GitHub CLI",
EnvVars: []EnvVarDef{{Name: "GH_TOKEN", Desc: "GitHub PAT or App token"}},
DenyArgs: []string{`auth\s+`, `ssh-key`, `gpg-key`, `repo\s+delete`, `secret\s+`},
DenyVerbose: []string{`--verbose`, `-v`},
Timeout: 30,
Tips: "Use --json flag for structured output",
},
"gcloud": {
BinaryName: "gcloud",
Description: "Google Cloud CLI",
EnvVars: []EnvVarDef{
{Name: "GOOGLE_APPLICATION_CREDENTIALS", Desc: "Service account JSON", IsFile: true},
},
DenyArgs: []string{`iam\s+`, `auth\s+`, `projects\s+delete`, `services\s+disable`, `kms\s+`},
DenyVerbose: []string{`--verbosity=debug`, `--log-http`},
Timeout: 120,
Tips: "Use --format=json for structured output",
},
"aws": {
BinaryName: "aws",
Description: "AWS CLI",
EnvVars: []EnvVarDef{
{Name: "AWS_ACCESS_KEY_ID", Desc: "AWS access key"},
{Name: "AWS_SECRET_ACCESS_KEY", Desc: "AWS secret key"},
{Name: "AWS_DEFAULT_REGION", Desc: "AWS region", Optional: true},
},
DenyArgs: []string{`iam\s+`, `organizations\s+`, `sts\s+assume`, `ec2\s+terminate`},
DenyVerbose: []string{`--debug`},
Timeout: 60,
Tips: "Use --output json for structured output",
},
"kubectl": {
BinaryName: "kubectl",
Description: "Kubernetes CLI",
EnvVars: []EnvVarDef{
{Name: "KUBECONFIG", Desc: "Path to kubeconfig", IsFile: true},
},
DenyArgs: []string{`delete\s+namespace`, `delete\s+node`, `drain\s+`, `cordon\s+`},
DenyVerbose: nil,
Timeout: 60,
Tips: "Use -o json for structured output",
},
"terraform": {
BinaryName: "terraform",
Description: "Terraform CLI",
EnvVars: []EnvVarDef{
{Name: "TF_TOKEN_app_terraform_io", Desc: "Terraform Cloud token", Optional: true},
},
DenyArgs: []string{`destroy`, `force-unlock`},
DenyVerbose: nil,
Timeout: 300,
Tips: "Use -json flag for structured output",
},
}
// GetPreset returns a preset by name, or nil if not found.
func GetPreset(name string) *CLIPreset {
p, ok := CLIPresets[name]
if !ok {
return nil
}
return &p
}
// ListPresetNames returns all available preset names sorted alphabetically.
func ListPresetNames() []string {
names := make([]string, 0, len(CLIPresets))
for name := range CLIPresets {
names = append(names, name)
}
sort.Strings(names)
return names
}