// Package cli: validate.go provides shared input-validation helpers for // CLI command arguments that are interpolated into remote shell commands // or filesystem paths (Phase 02 injection hardening, v0.13). // // These helpers enforce strict allowlists so that attacker-controlled // values (job names, txn IDs, alloc IDs, country codes) cannot reach // shell interpolation or path joins without matching a known-safe shape. package cli import ( "regexp" "strings" ) // safeNameRe matches the allowlist for shell-interpolated identifiers // (job names, alloc IDs): ASCII letters, digits, underscore, hyphen. // Used to prevent backtick/command-substitution and metacharacter // injection into remote shell commands. var safeNameRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`) // txnIDRe matches the canonical orca transaction ID format: "T-" prefix // followed by exactly 16 lowercase hex digits. Used to validate txn IDs // before they are interpolated into filesystem paths or remote shell // commands (`orca txn rollback`, `orca nft diff --against`). var txnIDRe = regexp.MustCompile(`^T-[0-9a-f]{16}$`) // countryCodeRe matches ISO-3166 alpha-2 country codes: exactly two // uppercase ASCII letters. Used by `orca nft country block add` before // codes are interpolated into the nft ruleset. var countryCodeRe = regexp.MustCompile(`^[A-Z]{2}$`) // validSafeName reports whether s is a safe shell-interpolation // identifier (ASCII alphanumeric, underscore, hyphen only, non-empty). func validSafeName(s string) bool { return safeNameRe.MatchString(s) } // validTxnID reports whether s matches the canonical orca txn ID format // (^T-[0-9a-f]{16}$). func validTxnID(s string) bool { return txnIDRe.MatchString(s) } // validCountryCode reports whether s is a valid ISO-3166 alpha-2 code // (two uppercase letters). func validCountryCode(s string) bool { return countryCodeRe.MatchString(s) } // shellQuote single-quotes a string for safe shell interpolation over // SSH exec. It escapes embedded single-quotes via the standard '\” idiom // (POSIX shell). This is the cli-package copy of the helper duplicated // across runtime/identity/stepca/sshpush to avoid import cycles; it // hardens command interpolation against backtick/command-substitution // injection (Go's %q does NOT escape backticks, and bash executes // command substitution inside double quotes). func shellQuote(s string) string { return "'" + strings.ReplaceAll(s, "'", "'\\''") + "'" }