mirror of
https://github.com/rookiestar28/ComfyUI-OpenClaw.git
synced 2026-08-14 08:52:45 +00:00
fix(tests): stabilize contract digests across line endings
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
/** Portable digest helpers for governed UTF-8 text contracts. */
|
||||
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
|
||||
export function stableTextDigest(filePath) {
|
||||
// IMPORTANT: normalize text newlines; raw hashing breaks frozen contracts after Windows checkout.
|
||||
const normalized = fs.readFileSync(filePath, "utf8").replace(/\r\n?/g, "\n");
|
||||
return crypto.createHash("sha256").update(normalized, "utf8").digest("hex");
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
"""Portable digest and write helpers for governed text contracts."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def normalize_text_newlines(payload: bytes) -> bytes:
|
||||
"""Return text bytes with CRLF and lone CR represented as LF."""
|
||||
# IMPORTANT: normalize text newlines; raw hashing breaks frozen contracts after Windows checkout.
|
||||
return payload.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
|
||||
|
||||
|
||||
def stable_text_digest(path: Path) -> str:
|
||||
"""Hash governed text independently of checkout newline representation."""
|
||||
return hashlib.sha256(normalize_text_newlines(path.read_bytes())).hexdigest()
|
||||
|
||||
|
||||
def write_text_lf(path: Path, text: str) -> None:
|
||||
"""Write UTF-8 contract text with explicit LF newlines on every platform."""
|
||||
with path.open("w", encoding="utf-8", newline="\n") as handle:
|
||||
handle.write(text)
|
||||
@@ -14,6 +14,8 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from scripts.contract_digest import stable_text_digest, write_text_lf # noqa: E402
|
||||
|
||||
CONTRACT_PATH = ROOT / "tests" / "api_config_contract_r221.json"
|
||||
|
||||
|
||||
@@ -126,10 +128,8 @@ def build_contract() -> dict[str, Any]:
|
||||
"tests.test_r219_exception_boundary_phase2",
|
||||
],
|
||||
},
|
||||
"r220_route_contract_sha256": hashlib.sha256(
|
||||
route_contract.read_bytes()
|
||||
).hexdigest(),
|
||||
"openapi_sha256": hashlib.sha256(openapi.read_bytes()).hexdigest(),
|
||||
"r220_route_contract_sha256": stable_text_digest(route_contract),
|
||||
"openapi_sha256": stable_text_digest(openapi),
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ def main() -> int:
|
||||
args = parser.parse_args()
|
||||
actual = build_contract()
|
||||
if args.write_baseline:
|
||||
CONTRACT_PATH.write_text(_canonical_json(actual), encoding="utf-8")
|
||||
write_text_lf(CONTRACT_PATH, _canonical_json(actual))
|
||||
print(f"API-CONFIG-CONTRACT-WRITTEN: {CONTRACT_PATH}")
|
||||
return 0
|
||||
expected = json.loads(CONTRACT_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import inspect
|
||||
import json
|
||||
import sys
|
||||
@@ -15,6 +14,8 @@ ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from scripts.contract_digest import stable_text_digest, write_text_lf # noqa: E402
|
||||
|
||||
CONTRACT_PATH = ROOT / "tests" / "api_route_contract_r220.json"
|
||||
|
||||
|
||||
@@ -122,7 +123,6 @@ def build_contract() -> dict[str, Any]:
|
||||
"trace_handler",
|
||||
)
|
||||
}
|
||||
openapi_bytes = (ROOT / "docs" / "openapi.yaml").read_bytes()
|
||||
return {
|
||||
"schema_version": 1,
|
||||
"registration_order": [
|
||||
@@ -149,7 +149,7 @@ def build_contract() -> dict[str, Any]:
|
||||
"families": families,
|
||||
"facade_signatures": facade,
|
||||
"facade_metadata": metadata,
|
||||
"openapi_sha256": hashlib.sha256(openapi_bytes).hexdigest(),
|
||||
"openapi_sha256": stable_text_digest(ROOT / "docs" / "openapi.yaml"),
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ def main() -> int:
|
||||
args = parser.parse_args()
|
||||
actual = build_contract()
|
||||
if args.write_baseline:
|
||||
CONTRACT_PATH.write_text(_canonical_json(actual), encoding="utf-8")
|
||||
write_text_lf(CONTRACT_PATH, _canonical_json(actual))
|
||||
print(f"API-ROUTE-CONTRACT-WRITTEN: {CONTRACT_PATH}")
|
||||
return 0
|
||||
expected = json.loads(CONTRACT_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
@@ -4,7 +4,6 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import ast
|
||||
import hashlib
|
||||
import inspect
|
||||
import json
|
||||
import sys
|
||||
@@ -15,6 +14,9 @@ from typing import Any
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from scripts.contract_digest import stable_text_digest, write_text_lf # noqa: E402
|
||||
|
||||
CONTRACT_PATH = ROOT / "tests" / "connector_router_contract_r222.json"
|
||||
|
||||
|
||||
@@ -75,7 +77,7 @@ def build_contract() -> dict[str, Any]:
|
||||
"api_route_contract_r220.json",
|
||||
):
|
||||
path = ROOT / "tests" / filename
|
||||
digests[filename] = hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
digests[filename] = stable_text_digest(path)
|
||||
return {
|
||||
"schema_version": 1,
|
||||
"constructor_signature": str(inspect.signature(CommandRouter)),
|
||||
@@ -116,7 +118,7 @@ def main() -> int:
|
||||
args = parser.parse_args()
|
||||
actual = build_contract()
|
||||
if args.write_baseline:
|
||||
CONTRACT_PATH.write_text(_canonical_json(actual), encoding="utf-8")
|
||||
write_text_lf(CONTRACT_PATH, _canonical_json(actual))
|
||||
print(f"CONNECTOR-ROUTER-CONTRACT-WRITTEN: {CONTRACT_PATH}")
|
||||
return 0
|
||||
expected = json.loads(CONTRACT_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/** Verify the frozen R224 Settings/API frontend contract. */
|
||||
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { stableTextDigest } from "./contract_digest.mjs";
|
||||
|
||||
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const CONTRACT_PATH = path.join(ROOT, "web", "tests", "fixtures", "frontend_decomposition_contract_r224.json");
|
||||
@@ -42,7 +42,7 @@ function methodSignatures(source) {
|
||||
}
|
||||
|
||||
function digest(relativePath) {
|
||||
return crypto.createHash("sha256").update(fs.readFileSync(path.join(ROOT, relativePath))).digest("hex");
|
||||
return stableTextDigest(path.join(ROOT, relativePath));
|
||||
}
|
||||
|
||||
export function buildContract() {
|
||||
|
||||
@@ -4,7 +4,6 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import ast
|
||||
import hashlib
|
||||
import inspect
|
||||
import json
|
||||
import sys
|
||||
@@ -15,6 +14,9 @@ from typing import Any
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from scripts.contract_digest import stable_text_digest, write_text_lf # noqa: E402
|
||||
|
||||
CONTRACT_PATH = ROOT / "tests" / "platform_adapter_contract_r223.json"
|
||||
|
||||
|
||||
@@ -131,9 +133,7 @@ def build_contract() -> dict[str, Any]:
|
||||
"tests.test_f74_reply_visibility_policy",
|
||||
"tests.security.test_s80_connector_ingress",
|
||||
],
|
||||
"router_contract_digest": hashlib.sha256(
|
||||
router_contract.read_bytes()
|
||||
).hexdigest(),
|
||||
"router_contract_digest": stable_text_digest(router_contract),
|
||||
}
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ def main() -> int:
|
||||
args = parser.parse_args()
|
||||
actual = build_contract()
|
||||
if args.write_baseline:
|
||||
CONTRACT_PATH.write_text(_canonical_json(actual), encoding="utf-8")
|
||||
write_text_lf(CONTRACT_PATH, _canonical_json(actual))
|
||||
print(f"PLATFORM-ADAPTER-CONTRACT-WRITTEN: {CONTRACT_PATH}")
|
||||
return 0
|
||||
expected = json.loads(CONTRACT_PATH.read_text(encoding="utf-8"))
|
||||
|
||||
Reference in New Issue
Block a user