///|
fn usage() -> String {
(
#|MoonAnsi Guard command-line audit tool
#|
#|Usage:
#| moon run cmd/audit -- [options]
#|
#|Options:
#| --escaped Decode \e, \a, \r, \n, \t, \b and \\ in input
#| --styled Preserve SGR color and emphasis sequences
#| --clean-only Print sanitized text without the audit report
#| --json Print a machine-readable JSON report
#| --redacted Remove captured payloads from reports
#| --strict-gate Apply conservative CI decision thresholds
#| --permissive-gate
#| Apply trusted-terminal decision thresholds
#| --help Show this help
#|
#|Examples:
#| moon run cmd/audit -- "plain build log"
#| moon run cmd/audit -- --escaped "ok\e]52;c;secret\aend"
)
}
///|
fn decode_escaped(input : String) -> String {
let chars = input.to_array()
let output : Array[Char] = []
let mut index = 0
while index < chars.length() {
if chars[index] == '\\' && index + 1 < chars.length() {
let next = chars[index + 1]
if next == 'e' {
output.push('\u{1b}')
index = index + 2
} else if next == 'a' {
output.push('\u{07}')
index = index + 2
} else if next == 'r' {
output.push('\r')
index = index + 2
} else if next == 'n' {
output.push('\n')
index = index + 2
} else if next == 't' {
output.push('\t')
index = index + 2
} else if next == 'b' {
output.push('\b')
index = index + 2
} else if next == '\\' {
output.push('\\')
index = index + 2
} else {
output.push(chars[index])
index = index + 1
}
} else {
output.push(chars[index])
index = index + 1
}
}
String::from_array(output)
}
///|
fn join_text(parts : Array[String]) -> String {
let mut text = ""
for index, part in parts {
if index > 0 {
text = text + " "
}
text = text + part
}
text
}
///|
fn main {
let args = @env.args()
let text_parts : Array[String] = []
let mut escaped = false
let mut styled = false
let mut clean_only = false
let mut json = false
let mut redacted = false
let mut strict_gate = false
let mut permissive_gate = false
let mut show_help = false
for index = 1; index < args.length(); index = index + 1 {
let arg = args[index]
if arg == "--escaped" {
escaped = true
} else if arg == "--styled" {
styled = true
} else if arg == "--clean-only" {
clean_only = true
} else if arg == "--json" {
json = true
} else if arg == "--redacted" {
redacted = true
} else if arg == "--strict-gate" {
strict_gate = true
} else if arg == "--permissive-gate" {
permissive_gate = true
} else if arg == "--help" || arg == "-h" {
show_help = true
} else {
text_parts.push(arg)
}
}
if show_help || text_parts.length() == 0 {
println(usage())
return
}
let raw = join_text(text_parts)
let input = if escaped { decode_escaped(raw) } else { raw }
let policy = if styled {
@guard.Policy::styled()
} else {
@guard.Policy::strict()
}
let result = @guard.scan_with_policy(input, policy)
if clean_only {
println(result.text())
} else if json {
let report_policy = if redacted {
@guard.ReportPolicy::redacted()
} else {
@guard.ReportPolicy::full()
}
println(result.json_report_with(report_policy))
} else if redacted {
println(result.redacted_audit_report())
} else {
println(result.audit_report())
let gate = if permissive_gate {
@guard.GatePolicy::permissive()
} else if strict_gate {
@guard.GatePolicy::strict()
} else {
@guard.GatePolicy::balanced()
}
println("configured gate: \{result.decide_with(gate).label()}")
for reason in result.decision_reasons(gate) {
println("- \{reason}")
}
}
}