feat(protocol): validate generated gateway contracts
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compile and exercise strict generated Swift and Rust gateway contracts."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def run(command: list[str], directory: pathlib.Path) -> None:
|
||||
result = subprocess.run(command, cwd=directory, text=True, capture_output=True, check=False)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError("%s\n%s%s" % (" ".join(command), result.stdout, result.stderr))
|
||||
|
||||
|
||||
def run_failure(command: list[str], directory: pathlib.Path, expected: str) -> None:
|
||||
result = subprocess.run(command, cwd=directory, text=True, capture_output=True, check=False)
|
||||
if result.returncode == 0 or expected not in result.stdout + result.stderr:
|
||||
raise RuntimeError("expected failure: %s\n%s%s" % (" ".join(command), result.stdout, result.stderr))
|
||||
|
||||
|
||||
def main() -> int:
|
||||
with tempfile.TemporaryDirectory(prefix="versevdi-generated-contracts-") as temporary:
|
||||
workspace = pathlib.Path(temporary)
|
||||
swift = workspace / "main.swift"
|
||||
swift.write_text(
|
||||
"""import Foundation
|
||||
|
||||
let capability = try CapabilityProfile(
|
||||
transport: "quic-tls13", framing: "datagram-v1", media: "encoded",
|
||||
audio: "encoded", sourceRateControl: "server", clientDecode: "h264-opus"
|
||||
)
|
||||
let request = try TunnelAdmissionRequest(
|
||||
version: "1", sessionId: "session", gatewayId: "gateway", audience: "audience",
|
||||
grant: String(repeating: "g", count: 43), reconnectSequence: 0,
|
||||
clientNonce: String(repeating: "n", count: 16), capabilities: capability
|
||||
)
|
||||
_ = request
|
||||
let incompatible = try CapabilityProfile(
|
||||
transport: "quic-tls13", framing: "datagram-v1", media: "encoded",
|
||||
audio: "encoded", sourceRateControl: "server", clientDecode: "hevc-opus"
|
||||
)
|
||||
do {
|
||||
guard try CapabilityProfile.intersection([capability, capability]) == capability else {
|
||||
fatalError("matching capability profiles did not intersect")
|
||||
}
|
||||
} catch { fatalError("matching capability profiles did not intersect") }
|
||||
do {
|
||||
_ = try CapabilityProfile.intersection([capability, incompatible])
|
||||
fatalError("profiles without overlap were accepted")
|
||||
} catch { }
|
||||
let valid = try request.encodeJSON()
|
||||
var unsupported = try JSONSerialization.jsonObject(with: valid) as! [String: Any]
|
||||
unsupported["version"] = "2"
|
||||
var downgrade = try JSONSerialization.jsonObject(with: valid) as! [String: Any]
|
||||
downgrade["version"] = "0"
|
||||
var unknown = try JSONSerialization.jsonObject(with: valid) as! [String: Any]
|
||||
unknown["unknown"] = true
|
||||
for invalid in [
|
||||
try JSONSerialization.data(withJSONObject: unsupported),
|
||||
try JSONSerialization.data(withJSONObject: downgrade),
|
||||
try JSONSerialization.data(withJSONObject: unknown),
|
||||
Data("{".utf8),
|
||||
valid + Data(" {}".utf8),
|
||||
] {
|
||||
do {
|
||||
_ = try TunnelAdmissionRequest.decodeJSON(invalid)
|
||||
fatalError("invalid tunnel admission request was accepted")
|
||||
} catch { }
|
||||
}
|
||||
do {
|
||||
_ = try AllocationPolicy(
|
||||
minimumKbps: 100, targetKbps: 50, maximumKbps: 25, tier: "standard",
|
||||
audience: "audience", protocolValue: "verse", protocolVersion: 1,
|
||||
grantTtlSeconds: 60, reservationLeaseSeconds: 300
|
||||
)
|
||||
fatalError("invalid allocation bounds were accepted")
|
||||
} catch { }
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
run(["swiftc", str(ROOT / "gen/swift/Protocol.swift"), str(swift), "-o", str(workspace / "swift-contracts")], ROOT)
|
||||
run([str(workspace / "swift-contracts")], ROOT)
|
||||
|
||||
rust = workspace / "protocol.rs"
|
||||
shutil.copyfile(ROOT / "gen/rust/protocol.rs", rust)
|
||||
with rust.open("a", encoding="utf-8") as output:
|
||||
output.write(
|
||||
"""
|
||||
fn main() {
|
||||
let capabilities = CapabilityProfile::new(
|
||||
"quic-tls13".into(), "datagram-v1".into(), "encoded".into(),
|
||||
"encoded".into(), "server".into(), "h264-opus".into(),
|
||||
).unwrap();
|
||||
assert!(TunnelAdmissionRequest::new(
|
||||
"2".into(), "session".into(), "gateway".into(), "audience".into(),
|
||||
"g".repeat(43), 0, "n".repeat(16), capabilities.clone(),
|
||||
).is_err());
|
||||
assert!(TunnelAdmissionRequest::new(
|
||||
"0".into(), "session".into(), "gateway".into(), "audience".into(),
|
||||
"g".repeat(43), 0, "n".repeat(16), capabilities.clone(),
|
||||
).is_err());
|
||||
assert!(TunnelAdmissionRequest::new(
|
||||
"1".into(), "session".into(), "gateway".into(), "audience".into(),
|
||||
"g".repeat(43), 0, "short".into(), capabilities.clone(),
|
||||
).is_err());
|
||||
assert!(intersect_capability_profiles(&[capabilities.clone(), capabilities.clone()]).is_ok());
|
||||
let incompatible = CapabilityProfile::new(
|
||||
"quic-tls13".into(), "datagram-v1".into(), "encoded".into(),
|
||||
"encoded".into(), "server".into(), "hevc-opus".into(),
|
||||
).unwrap();
|
||||
assert!(intersect_capability_profiles(&[capabilities, incompatible]).is_err());
|
||||
assert!(AllocationPolicy::new(
|
||||
100, 50, 25, "standard".into(), "audience".into(), "verse".into(), 1, 60, 300,
|
||||
).is_err());
|
||||
}
|
||||
"""
|
||||
)
|
||||
run(["rustc", str(rust), "-o", str(workspace / "rust-contracts")], ROOT)
|
||||
run([str(workspace / "rust-contracts")], ROOT)
|
||||
rust_unknown = workspace / "unknown.rs"
|
||||
shutil.copyfile(ROOT / "gen/rust/protocol.rs", rust_unknown)
|
||||
with rust_unknown.open("a", encoding="utf-8") as output:
|
||||
output.write("\nfn main() { let _ = CapabilityProfile { unknown: String::new() }; }\n")
|
||||
run_failure(["rustc", str(rust_unknown), "-o", str(workspace / "rust-unknown")], ROOT, "no field named `unknown`")
|
||||
print("Generated strict contract checks passed")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user