From 30daa2307856f0aa2e5ab8974f98eb8de653363d Mon Sep 17 00:00:00 2001 From: Open-Squilla <275096992+Open-Squilla@users.noreply.github.com> Date: Fri, 21 Aug 2026 12:34:08 +0800 Subject: [PATCH] Handle ossutil JSON timing output --- .github/workflows/mirror-oss.yml | 10 ++++------ scripts/ossutil_json.py | 34 ++++++++++++++++++++++++++++++++ tests/test_ossutil_json.py | 33 +++++++++++++++++++++++++++++++ tests/test_workflow_contract.py | 2 ++ 4 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 scripts/ossutil_json.py create mode 100644 tests/test_ossutil_json.py diff --git a/.github/workflows/mirror-oss.yml b/.github/workflows/mirror-oss.yml index a4080a7..71ded3d 100644 --- a/.github/workflows/mirror-oss.yml +++ b/.github/workflows/mirror-oss.yml @@ -128,10 +128,9 @@ jobs: --endpoint "${OSS_ENDPOINT}" \ --output-format json > bucket-versioning.json python - <<'PY' - import json - from pathlib import Path + from scripts.ossutil_json import load_ossutil_json - value = json.loads(Path("bucket-versioning.json").read_text(encoding="utf-8")) + value = load_ossutil_json("bucket-versioning.json") def statuses(node): if isinstance(node, dict): @@ -187,12 +186,11 @@ jobs: --endpoint "${OSS_ENDPOINT}" \ --output-format json > "${metadata}" METADATA_PATH="${metadata}" python - <<'PY' - import json import os import re - from pathlib import Path + from scripts.ossutil_json import load_ossutil_json - value = json.loads(Path(os.environ["METADATA_PATH"]).read_text(encoding="utf-8")) + value = load_ossutil_json(os.environ["METADATA_PATH"]) def version_ids(node): if isinstance(node, dict): diff --git a/scripts/ossutil_json.py b/scripts/ossutil_json.py new file mode 100644 index 0000000..13e3450 --- /dev/null +++ b/scripts/ossutil_json.py @@ -0,0 +1,34 @@ +"""Parse the JSON document emitted by ossutil API commands. + +ossutil 2.x appends a human-readable elapsed-time line to otherwise valid JSON +output. Keep accepting that documented CLI decoration while rejecting any +other trailing bytes so API responses remain fail-closed. +""" + +from __future__ import annotations + +import json +import re +from pathlib import Path +from typing import Any + +_ELAPSED_SUFFIX = re.compile(r"\d+(?:\.\d+)?\(s\) elapsed") + + +def load_ossutil_json(path: str | Path) -> Any: + """Load one JSON document from an ossutil output file. + + The parser accepts leading whitespace and ossutil's trailing elapsed-time + line, but rejects any other trailing output or malformed JSON. + """ + + raw = Path(path).read_text(encoding="utf-8") + document = raw.lstrip("\ufeff \t\r\n") + if not document.startswith(("{", "[")): + raise ValueError("ossutil output does not start with a JSON object or array") + decoder = json.JSONDecoder() + value, end = decoder.raw_decode(document) + trailing = document[end:].strip() + if trailing and not _ELAPSED_SUFFIX.fullmatch(trailing): + raise ValueError("unexpected output after ossutil JSON document") + return value diff --git a/tests/test_ossutil_json.py b/tests/test_ossutil_json.py new file mode 100644 index 0000000..aae5bf9 --- /dev/null +++ b/tests/test_ossutil_json.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +import json + +import pytest + +from scripts.ossutil_json import load_ossutil_json + + +def test_load_ossutil_json_accepts_elapsed_suffix(tmp_path) -> None: + output = tmp_path / "response.json" + output.write_text( + json.dumps({"Status": "Enabled"}, indent=2) + "\n\n0.012345(s) elapsed\n", + encoding="utf-8", + ) + + assert load_ossutil_json(output) == {"Status": "Enabled"} + + +def test_load_ossutil_json_rejects_unexpected_trailing_output(tmp_path) -> None: + output = tmp_path / "response.json" + output.write_text('{"Status": "Enabled"}\nwarning\n', encoding="utf-8") + + with pytest.raises(ValueError, match="unexpected output"): + load_ossutil_json(output) + + +def test_load_ossutil_json_rejects_missing_document(tmp_path) -> None: + output = tmp_path / "response.json" + output.write_text("0.012345(s) elapsed\n", encoding="utf-8") + + with pytest.raises(ValueError, match="does not start"): + load_ossutil_json(output) diff --git a/tests/test_workflow_contract.py b/tests/test_workflow_contract.py index 72097f7..a617f46 100644 --- a/tests/test_workflow_contract.py +++ b/tests/test_workflow_contract.py @@ -73,6 +73,8 @@ def test_oss_workflow_has_no_moving_alias_and_uses_reviewed_shared_bucket() -> N assert "expected one non-null OSS Version ID" in workflow assert "oss-version-ids.json" in workflow assert 'active != {"enabled"}' in workflow + assert "load_ossutil_json" in workflow + assert "scripts.ossutil_json" in workflow def test_all_external_actions_are_pinned_to_full_commit_sha() -> None: