Cybersecurity-Projects/PROJECTS/intermediate/credential-rotation-enforcer/src/cre/cli/cli.cr

71 lines
2.6 KiB
Crystal

# ===================
# ©AngelaMos | 2026
# cli.cr
# ===================
require "option_parser"
require "../version"
require "./output"
require "./commands"
module CRE::Cli
USAGE = <<-USAGE
cre - Credential Rotation Enforcer
Usage: cre <subcommand> [options]
Subcommands:
run headless daemon (production / systemd)
watch engine + live TUI in same process
check evaluate policies once, exit non-zero on violations
rotate <credential-id> manually rotate a single credential
policy list list compiled-in policies
policy show <name> inspect one policy
export --framework=<name> generate signed compliance evidence bundle
audit verify verify hash chain + HMAC ratchet + Merkle batches
verify-bundle <zip> verify a compliance evidence ZIP offline
demo tier-1 zero-deps demo (SQLite + .env rotator)
tui-demo 8-second TUI preview with synthetic events
version print version
help this message
Common options:
--output=human|json|ndjson output format (default: human)
--config=PATH config file (default: $CRE_CONFIG or ./config.cr)
USAGE
def self.dispatch(argv : Array(String), io : IO = STDOUT) : Int32
if argv.empty? || %w[--help -h help].includes?(argv.first)
io.puts USAGE
return argv.empty? ? 64 : 0 # 64 = EX_USAGE
end
subcommand = argv.shift
case subcommand
when "version"
io.puts CRE::VERSION
0
when "run" then Commands::Run.new.execute(argv, io)
when "watch" then Commands::Watch.new.execute(argv, io)
when "check" then Commands::Check.new.execute(argv, io)
when "rotate" then Commands::Rotate.new.execute(argv, io)
when "policy" then Commands::Policy.new.execute(argv, io)
when "export" then Commands::Export.new.execute(argv, io)
when "audit" then Commands::Audit.new.execute(argv, io)
when "verify-bundle" then Commands::VerifyBundle.new.execute(argv, io)
when "demo" then Commands::Demo.new.execute(argv, io)
when "tui-demo" then Commands::TuiDemo.new.execute(argv, io)
else
io.puts "unknown subcommand: #{subcommand}"
io.puts USAGE
64
end
rescue ex : OptionParser::InvalidOption | OptionParser::MissingOption
io.puts "error: #{ex.message}"
64
rescue ex
io.puts "error: #{ex.message}"
1
end
end