From 18665a38f3f2bd640e119f8271b6670afc532131 Mon Sep 17 00:00:00 2001 From: Dominic Ayre Date: Wed, 10 Dec 2025 15:48:48 +0000 Subject: [PATCH 1/3] Remove the depedency on OPA --- src/confcom/azext_confcom/lib/opa.py | 62 ------------------ .../azext_confcom/lib/serialization.py | 64 +++++++++++++++---- src/confcom/setup.py | 2 - 3 files changed, 50 insertions(+), 78 deletions(-) delete mode 100644 src/confcom/azext_confcom/lib/opa.py diff --git a/src/confcom/azext_confcom/lib/opa.py b/src/confcom/azext_confcom/lib/opa.py deleted file mode 100644 index 4b1fa5150d5..00000000000 --- a/src/confcom/azext_confcom/lib/opa.py +++ /dev/null @@ -1,62 +0,0 @@ -# -------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See License.txt in the project root for license information. -# -------------------------------------------------------------------------------------------- - -import platform -import requests -import hashlib -import json -import os -import subprocess - -from typing import Iterable -from pathlib import Path -from azext_confcom.lib.paths import get_binaries_dir - - -_binaries_dir = get_binaries_dir() -_opa_binaries = { - "Linux": { - "path": _binaries_dir / "opa", - "url": "https://github.com/open-policy-agent/opa/releases/download/v1.10.1/opa_linux_amd64", - "sha256": "fe8e191d44fec33db2a3d0ca788b9f83f866d980c5371063620c3c6822792877", - }, - "Windows": { - "path": _binaries_dir / "opa.exe", - "url": "https://github.com/open-policy-agent/opa/releases/download/v1.10.1/opa_windows_amd64.exe", - "sha256": "4c932053350eabca47681208924046fbf3ad9de922d6853fb12cddf59aef15ce", - }, -} - - -def opa_get(): - - for binary_info in _opa_binaries.values(): - opa_fetch_resp = requests.get(binary_info["url"], verify=True) - opa_fetch_resp.raise_for_status() - - assert hashlib.sha256(opa_fetch_resp.content).hexdigest() == binary_info["sha256"] - - with open(binary_info["path"], "wb") as f: - f.write(opa_fetch_resp.content) - - os.chmod(binary_info["path"], 0o755) - - -def opa_run(args: Iterable[str]) -> subprocess.CompletedProcess: - return subprocess.run( - [_opa_binaries[platform.system()]["path"], *args], - check=True, - stdout=subprocess.PIPE, - text=True, - ) - - -def opa_eval(data_path: Path, query: str): - return json.loads(opa_run([ - "eval", - "--format", "json", - "--data", str(data_path), - query, - ]).stdout.strip()) diff --git a/src/confcom/azext_confcom/lib/serialization.py b/src/confcom/azext_confcom/lib/serialization.py index 4dcaab18bfe..53323d3f7af 100644 --- a/src/confcom/azext_confcom/lib/serialization.py +++ b/src/confcom/azext_confcom/lib/serialization.py @@ -10,7 +10,6 @@ from textwrap import dedent from typing import Union -from azext_confcom.lib.opa import opa_eval from azext_confcom.lib.policy import Container, FragmentReference, Fragment, Policy import re @@ -80,21 +79,58 @@ def fragment_serialize(fragment: Fragment): def policy_deserialize(file_path: str): with open(file_path, 'r') as f: - content = f.read() - - package_match = re.search(r'package\s+(\S+)', content) - package_name = package_match.group(1) - - PolicyType = Policy if package_name == "policy" else Fragment - - raw_json = opa_eval(Path(file_path), f"data.{package_name}")["result"][0]["expressions"][0]["value"] - - raw_fragments = raw_json.pop("fragments", []) - raw_containers = raw_json.pop("containers", []) + content = f.readlines() + + def _brace_delta(line: str) -> int: + delta = 0 + for char in line: + if char in ['{', '[', '(']: + delta += 1 + elif char in ['}', ']', ')']: + delta -= 1 + return delta + + policy_json = {} + line_idx = 0 + + while line_idx < len(content): + line = content[line_idx] + + packages_search = re.search(r'package\s+(\S+)', line) + if packages_search: + policy_json["package"] = packages_search.group(1) + line_idx += 1 + continue + + assignment = re.match(r"\s*(?P[A-Za-z0-9_]+)\s*:=\s*(?P.*)", line) + if assignment: + name = assignment.group('name') + expr = assignment.group('expr').strip() + expr_parts = [expr] + depth = _brace_delta(expr) + + while depth > 0 and line_idx + 1 < len(content): + line_idx += 1 + continuation = content[line_idx].strip() + expr_parts.append(continuation) + depth += _brace_delta(continuation) + + full_expr = "\n".join(expr_parts).strip().rstrip(",") + try: + policy_json[name] = json.loads(full_expr) + except json.JSONDecodeError: + # Skip non-literal expressions (e.g. data.framework bindings) + ... + + line_idx += 1 + + PolicyType = Policy if policy_json.get("package") == "policy" else Fragment + + raw_fragments = policy_json.pop("fragments", []) + raw_containers = policy_json.pop("containers", []) return PolicyType( - package=package_name, + **policy_json, fragments=[FragmentReference(**fragment) for fragment in raw_fragments], containers=[Container(**container) for container in raw_containers], - **raw_json ) diff --git a/src/confcom/setup.py b/src/confcom/setup.py index 2f56737c440..580e6753725 100644 --- a/src/confcom/setup.py +++ b/src/confcom/setup.py @@ -11,7 +11,6 @@ from azext_confcom.rootfs_proxy import SecurityPolicyProxy from azext_confcom.kata_proxy import KataPolicyGenProxy from azext_confcom.cose_proxy import CoseSignToolProxy -from azext_confcom.lib.opa import opa_get try: from azure_bdist_wheel import cmdclass @@ -49,7 +48,6 @@ SecurityPolicyProxy.download_binaries() KataPolicyGenProxy.download_binaries() CoseSignToolProxy.download_binaries() -opa_get() with open("README.md", "r", encoding="utf-8") as f: README = f.read() From 74955ad91372a2b573050042923fcc2e1cc35da4 Mon Sep 17 00:00:00 2001 From: Dominic Ayre Date: Wed, 10 Dec 2025 15:52:03 +0000 Subject: [PATCH 2/3] Bump version --- src/confcom/HISTORY.rst | 4 ++++ src/confcom/setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/confcom/HISTORY.rst b/src/confcom/HISTORY.rst index 06434b1a04d..8ffb3997568 100644 --- a/src/confcom/HISTORY.rst +++ b/src/confcom/HISTORY.rst @@ -3,6 +3,10 @@ Release History =============== +1.4.5 +++++++ +* Drop the dependency on OPA + 1.4.4 ++++++ * Improve the package building process diff --git a/src/confcom/setup.py b/src/confcom/setup.py index 580e6753725..7b8c1157a0d 100644 --- a/src/confcom/setup.py +++ b/src/confcom/setup.py @@ -19,7 +19,7 @@ logger.warn("Wheel is not available, disabling bdist_wheel hook") -VERSION = "1.4.4" +VERSION = "1.4.5" # The full list of classifiers is available at # https://pypi.python.org/pypi?%3Aaction=list_classifiers From 9b1a24f41f2d82a82b55d26479277c92898b84a4 Mon Sep 17 00:00:00 2001 From: Dominic Ayre Date: Wed, 10 Dec 2025 16:00:44 +0000 Subject: [PATCH 3/3] Organise imports --- src/confcom/azext_confcom/lib/serialization.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/confcom/azext_confcom/lib/serialization.py b/src/confcom/azext_confcom/lib/serialization.py index 53323d3f7af..7702bfef8ba 100644 --- a/src/confcom/azext_confcom/lib/serialization.py +++ b/src/confcom/azext_confcom/lib/serialization.py @@ -4,14 +4,14 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -from dataclasses import asdict import json -from pathlib import Path +import re + +from dataclasses import asdict from textwrap import dedent from typing import Union from azext_confcom.lib.policy import Container, FragmentReference, Fragment, Policy -import re # This is a single entrypoint for serializing both Policy and Fragment objects