6f8b825f5f
The `weknora` command-line client for the WeKnora RAG server. Full command surface: kb / doc / chunk / session / message / agent / model / search / chat / auth / profile / link / api / mcp / skills / config / doctor / schema / exit-codes. Agent-first wire contract: JSON envelope by default, typed error codes mapped to stable exit codes, error.retry_argv / retryable / partial-failure status, global --dry-run preview, the exit-10 confirmation protocol for writes, and control/ANSI/Bidi input hygiene. Stateless env-credential auth (WEKNORA_API_KEY / WEKNORA_TOKEN + WEKNORA_HOST) for headless/CI/agent use. A curated read-only MCP tool surface (`mcp serve`) and embedded Agent Skills (`skills install`). Extensive unit + contract-golden tests and CI.
49 lines
1.5 KiB
Go
49 lines
1.5 KiB
Go
package cmdutil
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// ValidateProfileName enforces the profile-name allowlist: letters, digits,
|
|
// dash, underscore, dot. The `.` exception lets email / DNS-like names
|
|
// through; `.` / `..` and path separators are structurally rejected so a
|
|
// hand-edited config.yaml can't claim a profile whose name walks out of the
|
|
// keyring namespace.
|
|
//
|
|
// Crucially this also rejects shell metacharacters (space, `;`, `&`, `|`,
|
|
// `$`, quotes, backticks, etc.), so the profile name remains safe to embed
|
|
// in envelope.error.retry_argv — even an agent that joins the argv and exec's
|
|
// `sh -c <joined>` cannot be tricked via a maliciously-named profile.
|
|
func ValidateProfileName(name string) error {
|
|
if name == "" {
|
|
return &Error{
|
|
Code: CodeInputInvalidArgument,
|
|
Message: "profile name must not be empty",
|
|
}
|
|
}
|
|
if name == "." || name == ".." || strings.Contains(name, "/") || strings.Contains(name, "\\") {
|
|
return &Error{
|
|
Code: CodeInputInvalidArgument,
|
|
Message: fmt.Sprintf("profile name %q is reserved or path-like", name),
|
|
Hint: "use letters, digits, dashes, underscores, or dots",
|
|
}
|
|
}
|
|
for _, r := range name {
|
|
switch {
|
|
case r >= 'a' && r <= 'z',
|
|
r >= 'A' && r <= 'Z',
|
|
r >= '0' && r <= '9',
|
|
r == '-' || r == '_' || r == '.':
|
|
continue
|
|
default:
|
|
return &Error{
|
|
Code: CodeInputInvalidArgument,
|
|
Message: fmt.Sprintf("profile name %q contains invalid character %q", name, r),
|
|
Hint: "use letters, digits, dashes, underscores, or dots",
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|