///|
pub fn Packet::to_json(self : Packet) -> Json {
{
"source": self.source.to_dotted(),
"destination": self.destination.to_dotted(),
"protocol": self.protocol.render(),
"source_port": self.source_port,
"destination_port": self.destination_port,
}
}
///|
pub fn Decision::to_json(self : Decision) -> Json {
{
"action": self.action.render(),
"rule_id": match self.rule_id {
Some(x) => Json::string(x)
None => Json::null()
},
"tested_rules": self.tested_rules,
}
}
///|
fn change_json(w : ChangeWitness?) -> Json {
match w {
None => Json::null()
Some(w) =>
{
"packet": w.packet.to_json(),
"before": w.before.to_json(),
"after": w.after.to_json(),
"replayed": true,
}
}
}
///|
pub fn DiffReport::to_json(self : DiffReport) -> Json {
{
"schema": "moonpolicyproof.diff.v1",
"model": "ipv4-tcp-udp-stateless-first-match",
"equivalent": self.equivalent(),
"newly_allowed": change_json(self.newly_allowed),
"newly_denied": change_json(self.newly_denied),
"retained_nodes": self.retained_nodes,
}
}
///|
pub fn Coverage::render(self : Coverage) -> String {
match self {
Reachable => "reachable"
Partial => "partial"
Shadowed => "shadowed"
}
}
///|
fn optional_packet(p : Packet?) -> Json {
match p {
None => Json::null()
Some(p) => p.to_json()
}
}
///|
pub fn audit_json(reports : Array[RuleAudit]) -> Json {
{
"schema": "moonpolicyproof.audit.v1",
"rules": Json::array(
reports.map(r => {
"rule_id": r.rule_id,
"coverage": r.coverage.render(),
"reachable_witness": optional_packet(r.reachable_witness),
"blocked_witness": optional_packet(r.blocked_witness),
"blocked_by": match r.blocked_by {
None => Json::null()
Some(id) => Json::string(id)
},
}),
),
}
}
///|
pub fn assertions_json(results : Array[AssertionResult]) -> Json {
{
"schema": "moonpolicyproof.assertions.v1",
"passed": results.iter().all(r => r.passed),
"assertions": Json::array(
results.map(r => {
"id": r.id,
"passed": r.passed,
"counterexample": optional_packet(r.counterexample),
"actual": match r.actual {
None => Json::null()
Some(d) => d.to_json()
},
}),
),
}
}
///|
pub fn DiffReport::render(self : DiffReport) -> String {
let lines = [
"model: IPv4 TCP/UDP stateless first-match",
"equivalent: " + self.equivalent().to_string(),
]
for
entry in [
("newly allowed", self.newly_allowed),
("newly denied", self.newly_denied),
] {
let (label, w) = entry
match w {
None => lines.push(label + ": none")
Some(w) =>
lines.push(
label +
": " +
w.packet.to_json().stringify() +
" (independently replayed)",
)
}
}
lines.join("\n") + "\n"
}