diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..12901f9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.analysis.typeCheckingMode": "basic" +} diff --git a/README.md b/README.md index 8066694..a752322 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "rules_opa", - sha256 = "510c9e0a2f556ea443a7da567d84e76b3ebc7aea48665109f35c7029d9a6d56e", - strip_prefix = "rules_opa-0.2.0", - url = "https://github.com/ticketmaster/rules_opa/archive/refs/tags/v0.2.0.tar.gz", + sha256 = "", + strip_prefix = "rules_opa-", + url = "https://github.com/ticketmaster/rules_opa/archive/refs/tags/.tar.gz", ) load("@rules_opa//opa:deps.bzl", "opa_register_toolchains", "opa_rules_dependencies") @@ -54,3 +54,11 @@ opa_test( bundle = ":simple", ) ``` + +## Upgrade + +To upgrade the opa version, run the following command + +```shell +bazel run -- //tools:opa_upgrade --version +``` diff --git a/opa/private/opa_rules_dependencies.bzl b/opa/private/opa_rules_dependencies.bzl index e083ccb..bb8c851 100644 --- a/opa/private/opa_rules_dependencies.bzl +++ b/opa/private/opa_rules_dependencies.bzl @@ -1,7 +1,19 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +DEFAULT_VERSION = "0.57.1" + _OPA_SHA256 = { + "0.57.1": { + "opa_darwin_amd64": "54a2d229638baddb0ac6f7c283295e547e6f491ab2ddcaf714fa182427e8421d", + "opa_darwin_arm64_static": "367adba9c1380297c87a83019965a28bb0f33fe7c0854ff6beedb4aa563e4b4f", + "opa_linux_amd64": "5212d513dad9bd90bc67743d7812e5ec7019b2a994f30c0d8dbb2b2c6772f094", + "opa_linux_amd64_static": "59e8c6ef9ae2f95b76aa79344eb81ca6f3950a0fd7a23534c4d7065f42fda99f", + "opa_linux_arm64_static": "6d581ef6f9a066c0d2a36f3cb7ee605ec8195e49631121d1707248549758806b", + "opa_windows_amd64": "9a6d3ef2279760efbcead6a7095393e04adaa1be3c7458eb62a2b79d93df4bc3", + "opa_capabilities_json": "3a99b25a99f484b9de2037ef459af50cfa3c2da01219d38ddb049ad0c2384411", + "opa_builtin_metadata_json": "5e9aeb1048a49e9fc04c694be53a4eead8a1b5f4acff71d14b1610d84fb347b4", + }, "0.54.0": { "opa_darwin_amd64": "a33e829306cd2210ed743da7f4f957588ea350a184bb6ecbb7cbfd77ae7ca401", "opa_darwin_arm64_static": "74500746e5faf0deb60863f1a3d1e3eed96006ff8183940f1c13f1a47969059d", @@ -24,7 +36,7 @@ _SUPPORTED_PLATFORMS = [ ] def opa_rules_dependencies( - version = "0.54.0"): + version = DEFAULT_VERSION): """Install the opa dependencies Args: diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index c91384d..258aff8 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -13,6 +13,11 @@ py_binary( visibility = ["//visibility:public"], ) +py_binary( + name = "opa_upgrade", + srcs = ["opa_upgrade.py"], +) + toolchain_type(name = "toolchain_type") opa_toolchain( diff --git a/tools/opa_ctx.py b/tools/opa_ctx.py index e5729bc..1d91329 100644 --- a/tools/opa_ctx.py +++ b/tools/opa_ctx.py @@ -2,15 +2,16 @@ from dataclasses import dataclass from argparse import ArgumentParser from subprocess import run, PIPE, STDOUT +from typing import List, Optional import os import sys @dataclass class Args: - output: str | None - inputs: list[str] - command: list[str] + output: Optional[str] + inputs: List[str] + command: List[str] wd: str @@ -43,7 +44,7 @@ def chdir(): os.chdir(user_dir) -def split_once_or_double(s: str, delimiter: str) -> list[str]: +def split_once_or_double(s: str, delimiter: str) -> List[str]: parts = s.split(delimiter, 1) return parts if len(parts) == 2 else [s, s] diff --git a/tools/opa_signer.py b/tools/opa_signer.py index 904e630..1c298ce 100644 --- a/tools/opa_signer.py +++ b/tools/opa_signer.py @@ -3,6 +3,7 @@ from subprocess import run, PIPE,STDOUT from dataclasses import dataclass from io import BytesIO +from typing import List import sys import os @@ -12,7 +13,7 @@ class Args: output: str signing_key: str signing_alg: str - command: list[str] + command: List[str] def parse_args() -> Args: parser = ArgumentParser(prog="rules_opa::opa_signer", description="Tool to re-bundle an opa bundle with a signature file") diff --git a/tools/opa_upgrade.py b/tools/opa_upgrade.py new file mode 100644 index 0000000..3d819bf --- /dev/null +++ b/tools/opa_upgrade.py @@ -0,0 +1,101 @@ +import os +import re +from typing import TypeVar, Optional +from argparse import ArgumentParser, Namespace +from urllib.request import urlopen +from pathlib import Path +from hashlib import sha256 + +ARTIFACTS = [ + "opa_darwin_amd64", + "opa_darwin_arm64_static", + "opa_linux_amd64", + "opa_linux_amd64_static", + "opa_linux_arm64_static", + "opa_windows_amd64", +] + +T = TypeVar('T') + + +def required(value: Optional[T], name: str) -> T: + if value is None: + raise ValueError(f"Expected value for {name}") + + return value + + +def get_sha256(artifact_name: str, version: str) -> str: + ext = ".exe" if "windows" in artifact_name else "" + + with urlopen(f"https://github.com/open-policy-agent/opa/releases/download/v{version}/{artifact_name}{ext}.sha256") as res: + return res.read().decode().split(' ')[0] + + +def get_sha256_file(file: str, version: str) -> str: + file_url = f"https://raw.githubusercontent.com/open-policy-agent/opa/v{version}/{file}" + + with urlopen(file_url) as res: + return sha256(res.read()).hexdigest() + + +def main(args: Namespace): + d = dict([ + (artifact_name, get_sha256(artifact_name, args.version)) + for artifact_name in ARTIFACTS + ]) + + bzl_path = WORKSPACE_ROOT.joinpath( + 'opa', 'private', 'opa_rules_dependencies.bzl') + + with open(bzl_path) as bzl_file: + bzl_content = bzl_file.read() + + version_match = re.search( + r"DEFAULT_VERSION\s*=\s*[\"'](.*?)[\"']", bzl_content) + + if version_match is None: + raise ValueError(f"Could not find DEFAULT_VERSION in file {bzl_path}") + + start_version = version_match.start(1) + end_version = version_match.end(1) + + bzl_content = bzl_content[:start_version] + \ + args.version + bzl_content[end_version:] + + dict_match = re.search( + r"^_OPA_SHA256\s*=\s*{\s*$", bzl_content, re.MULTILINE) + + if dict_match is None: + raise ValueError(f"Could not find _OPA_SHA256 in file {bzl_path}") + + bzl_content = bzl_content[:dict_match.end( + )] + f"\n \"{args.version}\": {{\n" + '\n'.join([ + f" \"{artifact_name}\": \"{sha256}\"," + for artifact_name, sha256 in d.items() + ] + [ + f" \"opa_capabilities_json\": \"{get_sha256_file('capabilities.json', args.version)}\",", + f" \"opa_builtin_metadata_json\": \"{get_sha256_file('builtin_metadata.json', args.version)}\",", + ]) + "\n }," + bzl_content[dict_match.end():] + + with open(bzl_path, "w", encoding="utf-8") as bzl_file: + bzl_file.write(bzl_content) + + +def get_workspace_root(wd: Path) -> Path: + while not wd.joinpath("WORKSPACE").exists(): + wd = wd.parent + + return wd + + +BUILD_WORKING_DIRECTORY = Path( + required(os.getenv("BUILD_WORKING_DIRECTORY"), "BUILD_WORKING_DIRECTORY")) +WORKSPACE_ROOT = get_workspace_root(BUILD_WORKING_DIRECTORY) + +if __name__ == '__main__': + + parser = ArgumentParser() + parser.add_argument('--version', '-v', required=True) + + main(parser.parse_args())