From badf88f92d14eef39945329679e10cfe7918f570 Mon Sep 17 00:00:00 2001 From: John Andersen Date: Sun, 15 Oct 2023 23:49:00 -0700 Subject: [PATCH] Add server CLI arg for Federation loaded via entrypoint style load plugin helper Signed-off-by: John Andersen --- scitt_emulator/ccf.py | 8 ++++++-- scitt_emulator/federation.py | 23 +++++++++++++++++++++++ scitt_emulator/rkvst.py | 11 +++++++++-- scitt_emulator/scitt.py | 15 +++++++++++++-- scitt_emulator/server.py | 21 ++++++++++++++++++++- 5 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 scitt_emulator/federation.py diff --git a/scitt_emulator/ccf.py b/scitt_emulator/ccf.py index 825c7eea..132b3691 100644 --- a/scitt_emulator/ccf.py +++ b/scitt_emulator/ccf.py @@ -18,15 +18,19 @@ from cryptography.hazmat.primitives import hashes from scitt_emulator.scitt import SCITTServiceEmulator +from scitt_emulator.federation import SCITTFederation class CCFSCITTServiceEmulator(SCITTServiceEmulator): tree_alg = "CCF" def __init__( - self, service_parameters_path: Path, storage_path: Optional[Path] = None + self, + service_parameters_path: Path, + storage_path: Optional[Path] = None, + federation: Optional[SCITTFederation] = None, ): - super().__init__(service_parameters_path, storage_path) + super().__init__(service_parameters_path, storage_path, federation) if storage_path is not None: self._service_private_key_path = ( self.storage_path / "service_private_key.pem" diff --git a/scitt_emulator/federation.py b/scitt_emulator/federation.py new file mode 100644 index 00000000..6350869b --- /dev/null +++ b/scitt_emulator/federation.py @@ -0,0 +1,23 @@ +from pathlib import Path +from abc import ABC, abstractmethod +from typing import Optional + + +class SCITTFederation(ABC): + def __init__( + self, + config_path: Path, + service_parameters_path: Path, + storage_path: Optional[Path] = None, + ): + self.config_path = config_path + self.service_parameters_path = service_parameters_path + self.storage_path = storage_path + + @abstractmethod + def initialize_service(self): + raise NotImplementedError + + @abstractmethod + def created_entry(self, entry_id: str, receipt: bytes): + raise NotImplementedError diff --git a/scitt_emulator/rkvst.py b/scitt_emulator/rkvst.py index 54f9f5ee..677082f9 100644 --- a/scitt_emulator/rkvst.py +++ b/scitt_emulator/rkvst.py @@ -13,14 +13,18 @@ from . import rkvst_mocks from scitt_emulator.scitt import SCITTServiceEmulator +from scitt_emulator.federation import SCITTFederation class RKVSTSCITTServiceEmulator(SCITTServiceEmulator): tree_alg = "RKVST" def __init__( - self, service_parameters_path: Path, storage_path: Optional[Path] = None + self, + service_parameters_path: Path, + storage_path: Optional[Path] = None, + federation: Optional[SCITTFederation] = None, ): - super().__init__(service_parameters_path, storage_path) + super().__init__(service_parameters_path, storage_path, federation) if storage_path is not None: self._service_private_key_path = ( self.storage_path / "service_private_key.pem" @@ -115,6 +119,9 @@ def _submit_claim_async(self, claim: bytes): #event = rkvst_mocks.mock_event_lro_incomplete operation_id = self._event_id_to_operation_id(event["identity"]) + # TODO Federate created entries when operations complete + # if self.federation: + # self.federation.created_entry(entry_id, receipt) return { "operationId": operation_id, "status": "running" diff --git a/scitt_emulator/scitt.py b/scitt_emulator/scitt.py index f33ca89f..ac35eda6 100644 --- a/scitt_emulator/scitt.py +++ b/scitt_emulator/scitt.py @@ -15,6 +15,8 @@ from pycose.keys.ec2 import EC2Key import pycose.keys.curves +from scitt_emulator.federation import SCITTFederation + # temporary claim header labels, see draft-birkholz-scitt-architecture COSE_Headers_Issuer = 391 @@ -46,10 +48,14 @@ class PolicyResultDecodeError(Exception): class SCITTServiceEmulator(ABC): def __init__( - self, service_parameters_path: Path, storage_path: Optional[Path] = None + self, + service_parameters_path: Path, + storage_path: Optional[Path] = None, + federation: Optional[SCITTFederation] = None, ): self.storage_path = storage_path self.service_parameters_path = service_parameters_path + self.federation = federation if storage_path is not None: self.operations_path = storage_path / "operations" @@ -124,7 +130,7 @@ def _create_entry(self, claim: bytes) -> dict: entry_id = str(last_entry_id + 1) - self._create_receipt(claim, entry_id) + receipt = self._create_receipt(claim, entry_id) last_entry_path.write_text(entry_id) @@ -134,6 +140,10 @@ def _create_entry(self, claim: bytes) -> dict: print(f"Claim written to {claim_path}") entry = {"entryId": entry_id} + + if self.federation: + self.federation.created_entry(entry_id, receipt) + return entry def _create_operation(self, claim: bytes): @@ -270,6 +280,7 @@ def _create_receipt(self, claim: bytes, entry_id: str): with open(receipt_path, "wb") as f: f.write(receipt) print(f"Receipt written to {receipt_path}") + return receipt def get_receipt(self, entry_id: str): receipt_path = self.storage_path / f"{entry_id}.receipt.cbor" diff --git a/scitt_emulator/server.py b/scitt_emulator/server.py index 094d0b6a..f4d5e012 100644 --- a/scitt_emulator/server.py +++ b/scitt_emulator/server.py @@ -9,6 +9,7 @@ from flask import Flask, request, send_file, make_response from scitt_emulator.tree_algs import TREE_ALGS +from scitt_emulator.plugin_helpers import entrypoint_style_load from scitt_emulator.scitt import EntryNotFoundError, ClaimInvalidError, OperationNotFoundError @@ -43,8 +44,18 @@ def create_flask_app(config): clazz = TREE_ALGS[app.config["tree_alg"]] + federation = None + if app.config.get("federation", None): + federation = app.config["federation"]( + config_path=app.config.get("federation_config_path", None), + storage_path=storage_path, + service_parameters_path=app.service_parameters_path + ) + app.scitt_service = clazz( - storage_path=storage_path, service_parameters_path=app.service_parameters_path + storage_path=storage_path, + service_parameters_path=app.service_parameters_path, + federation=federation, ) app.scitt_service.initialize_service() print(f"Service parameters: {app.service_parameters_path}") @@ -117,10 +128,18 @@ def cli(fn): parser.add_argument("--use-lro", action="store_true", help="Create operations for submissions") parser.add_argument("--tree-alg", required=True, choices=list(TREE_ALGS.keys())) parser.add_argument("--workspace", type=Path, default=Path("workspace")) + parser.add_argument( + "--federation", + type=lambda value: list(entrypoint_style_load(value))[0], + default=None, + ) + parser.add_argument("--federation-config-path", type=Path, default=None) def cmd(args): app = create_flask_app( { + "federation": args.federation, + "federation_config_path": args.federation_config_path, "tree_alg": args.tree_alg, "workspace": args.workspace, "error_rate": args.error_rate,