From 142cdb9b18e0d710c07356bf2a149cae1e983d86 Mon Sep 17 00:00:00 2001 From: stanley31 Date: Wed, 27 May 2026 15:38:06 +0800 Subject: [PATCH 1/6] add hsm tests for NXP ELE add hsm tests for NXP Edge Lock device --- .../bin/nxp_ele_test.py | 376 ++++++++++++++++++ .../units/crypto/manifest.pxu | 5 + .../units/crypto/nxp-secure-element.pxu | 74 ++++ .../units/crypto/test-plan-nxp.pxu | 10 + .../units/test-plan-ce-oem.pxu | 1 + 5 files changed, 466 insertions(+) create mode 100755 contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py create mode 100644 contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/nxp-secure-element.pxu create mode 100644 contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/test-plan-nxp.pxu diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py new file mode 100755 index 0000000000..980891a450 --- /dev/null +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python3 +"""Checkbox helper for NXP ELE TV discovery and execution.""" + +import argparse +import os +import re +import shutil +import subprocess +import sys +from pathlib import Path +from typing import Dict, List, Set, Tuple + +ELE_HSM_TEST_COMMAND_CANDIDATES = [ + "oem-imx-secure-enclave.ele-hsm-test", + "ele_hsm_test", +] +ELE_HSM_PERF_TEST_COMMAND_CANDIDATES = [ + "oem-imx-secure-enclave.ele-hsm-perf-test", + "ele_hsm_perf_test", +] +NVM_DAEMON_SERVICE_CANDIDATES = [ + "nvm_daemon.service", + "nvm_daemon", + "snap.oem-imx-secure-enclave.nvm-daemon.service", +] +NVM_DATA_DIRECTORIES = [Path("/etc/ele"), Path("/var/lib/se")] +TV_EXTENSIONS = {".tv", ".txt", ".json", ".bin"} +CANDIDATE_DIRECTORIES = [ + Path("/var/snap/oem-imx-secure-enclave/common"), + Path("/snap/oem-imx-secure-enclave/current"), + Path("/usr/share/oem-imx-secure-enclave"), + Path("/usr/share/se/test_vectors"), +] + + +def eprint(message: str) -> None: + """Print to stderr.""" + print(message, file=sys.stderr) + + +def resolve_command(candidates: List[str], command_label: str) -> str: + """Resolve the first available executable command from a candidate list.""" + for candidate in candidates: + if shutil.which(candidate) is not None: + return candidate + raise RuntimeError( + f"[NXP_ELE] Required command for {command_label} not found. " + f"Tried: {', '.join(candidates)}" + ) + + +def ensure_systemctl_available() -> None: + """Ensure systemctl is available for daemon lifecycle management.""" + if shutil.which("systemctl") is None: + raise RuntimeError("[NXP_ELE] Required command 'systemctl' was not found in PATH.") + + +def run_with_optional_sudo(command: List[str], allow_failure: bool = False) -> int: + """Run command directly as root or through sudo when needed.""" + final_command = list(command) + if os.geteuid() != 0: + sudo_path = shutil.which("sudo") + if sudo_path is None: + raise RuntimeError( + "[NXP_ELE] Root privileges are required and 'sudo' is not available." + ) + final_command = [sudo_path] + final_command + + print(f"[NXP_ELE] Running command: {' '.join(final_command)}") + result = subprocess.run(final_command, check=False) + if result.returncode != 0 and not allow_failure: + raise RuntimeError( + "[NXP_ELE] Command failed with exit code " + f"{result.returncode}: {' '.join(final_command)}" + ) + return result.returncode + + +def resolve_nvm_daemon_service_name() -> str: + """Resolve the available NVM daemon systemd unit name.""" + list_units_cmd = ["systemctl", "list-unit-files", "--type=service", "--no-legend"] + result = subprocess.run( + list_units_cmd, + check=False, + capture_output=True, + text=True, + ) + if result.returncode != 0: + raise RuntimeError( + "[NXP_ELE] Failed to query systemd unit files via " + f"'{' '.join(list_units_cmd)}'." + ) + + available_units = set() + for line in result.stdout.splitlines(): + line = line.strip() + if not line: + continue + unit_name = line.split()[0] + available_units.add(unit_name) + + for candidate in NVM_DAEMON_SERVICE_CANDIDATES: + if candidate in available_units: + return candidate + if candidate.endswith(".service") and candidate[:-8] in available_units: + return candidate[:-8] + + raise RuntimeError( + "[NXP_ELE] Could not find supported NVM daemon service. " + f"Tried: {', '.join(NVM_DAEMON_SERVICE_CANDIDATES)}" + ) + + +def set_nvm_daemon_state(action: str, service_name: str) -> None: + """Start or stop the NVM daemon service.""" + if action not in ("start", "stop"): + raise RuntimeError(f"[NXP_ELE] Unsupported daemon action: {action}") + run_with_optional_sudo(["systemctl", action, service_name]) + + +def cleanup_nvm_data() -> None: + """Delete NVM test data directories content when present.""" + for directory in NVM_DATA_DIRECTORIES: + if not directory.exists(): + print(f"[NXP_ELE] Cleanup skipped (not found): {directory}") + continue + + print(f"[NXP_ELE] Cleaning directory: {directory}") + for child in directory.iterdir(): + if child.is_dir() and not child.is_symlink(): + run_with_optional_sudo(["rm", "-rf", str(child)]) + else: + run_with_optional_sudo(["rm", "-f", str(child)]) + + +def sanitize_name(name: str) -> str: + """Convert a file stem into a Checkbox-id-friendly token.""" + cleaned = re.sub(r"[^a-zA-Z0-9_]+", "_", name.strip().lower()) + cleaned = re.sub(r"_+", "_", cleaned).strip("_") + return cleaned or "tv" + + +def parse_tv_metadata(tv_file: Path) -> Tuple[str, str]: + """ + Parse category and variant from a TV filename stem. + + Example: + test_vectors_set0_kgen_persistent_ap -> + category=set0_kgen, variant=persistent_ap + """ + stem = tv_file.stem + prefix = "test_vectors_" + raw = stem[len(prefix) :] if stem.startswith(prefix) else stem + + variant_candidates = ("persistent_ap", "volatile_ap", "ap", "n", "p") + for variant in variant_candidates: + suffix = f"_{variant}" + if raw.endswith(suffix): + category = raw[: -len(suffix)] + if category: + return sanitize_name(category), sanitize_name(variant) + break + + return sanitize_name(raw), "generic" + + +def get_candidate_directories() -> List[Path]: + """Build candidate TV directories, including snap revision paths.""" + candidates: List[Path] = list(CANDIDATE_DIRECTORIES) + snap_root = Path("/snap/oem-imx-secure-enclave") + if snap_root.is_dir(): + for revision_dir in sorted(snap_root.iterdir(), key=lambda path: path.name): + if not revision_dir.is_dir(): + continue + candidates.append(revision_dir / "usr/share/se/test_vectors") + candidates.append(revision_dir / "usr/share/se/test_vectors/psa") + candidates.append(revision_dir / "usr/share/oem-imx-secure-enclave") + + return candidates + + +def discover_tv_files() -> List[Path]: + """Discover test vector files from candidate directories.""" + found: Set[str] = set() + results: List[Path] = [] + + all_candidates = get_candidate_directories() + existing_dirs = [directory for directory in all_candidates if directory.is_dir()] + if not existing_dirs: + candidates = ", ".join(str(path) for path in all_candidates) + raise RuntimeError( + "[NXP_ELE] No candidate TV directories found. " + f"Checked: {candidates}" + ) + + for root in existing_dirs: + for dirpath, _, filenames in os.walk(root): + for filename in filenames: + file_path = Path(dirpath) / filename + if file_path.suffix.lower() not in TV_EXTENSIONS: + continue + normalized = str(file_path.resolve()) + if normalized in found: + continue + found.add(normalized) + results.append(Path(normalized)) + + results.sort(key=lambda path: str(path)) + return results + + +def build_tv_records(tv_files: List[Path]) -> List[Dict[str, str]]: + """ + Build tv records for Checkbox resource output. + + Each record contains: + - tv_file: full path + - tv_name: unique, id-friendly identifier + - tv_category: parsed functional category (e.g. set1_cipher) + - tv_variant: parsed profile/variant (e.g. ap, p, n, persistent_ap) + """ + records: List[Dict[str, str]] = [] + used_names: Dict[str, int] = {} + + for tv_file in tv_files: + base_name = sanitize_name(tv_file.stem) + tv_category, tv_variant = parse_tv_metadata(tv_file) + sequence = used_names.get(base_name, 0) + used_names[base_name] = sequence + 1 + tv_name = base_name if sequence == 0 else f"{base_name}_{sequence + 1}" + + records.append( + { + "tv_file": str(tv_file), + "tv_name": tv_name, + "tv_category": tv_category, + "tv_variant": tv_variant, + } + ) + + return records + + +def list_tv_records() -> int: + """List TV records in key=value format for Checkbox resource plugin.""" + tv_files = discover_tv_files() + if not tv_files: + eprint( + "[NXP_ELE] No test vector files found with extensions: " + + ", ".join(sorted(TV_EXTENSIONS)) + ) + return 1 + + for record in build_tv_records(tv_files): + print(f"tv_file: {record['tv_file']}") + print(f"tv_name: {record['tv_name']}") + print(f"tv_category: {record['tv_category']}") + print(f"tv_variant: {record['tv_variant']}") + print() + + return 0 + + +def run_with_nvm_lifecycle(test_command: List[str], success_message: str, fail_label: str) -> int: + """Execute one test command with the NVM daemon stop/cleanup/start/stop lifecycle.""" + ensure_systemctl_available() + service_name = resolve_nvm_daemon_service_name() + + test_exit = 1 + daemon_stop_failed = False + try: + print(f"[NXP_ELE] Stopping {service_name} before cleanup") + set_nvm_daemon_state("stop", service_name) + + cleanup_nvm_data() + + print(f"[NXP_ELE] Starting {service_name} for test execution") + set_nvm_daemon_state("start", service_name) + + test_exit = run_with_optional_sudo(test_command, allow_failure=True) + if test_exit != 0: + eprint( + f"[NXP_ELE] {fail_label} failed with exit code {test_exit}" + ) + else: + print(success_message) + finally: + print(f"[NXP_ELE] Stopping {service_name} after test") + try: + set_nvm_daemon_state("stop", service_name) + except RuntimeError as exc: + eprint(str(exc)) + daemon_stop_failed = True + + if daemon_stop_failed and test_exit == 0: + return 1 + return test_exit + + +def run_tv_file(tv_file: str) -> int: + """Run one TV file with required daemon stop/cleanup/start/stop lifecycle.""" + test_command_bin = resolve_command(ELE_HSM_TEST_COMMAND_CANDIDATES, "ele_hsm_test") + file_path = Path(tv_file).expanduser().resolve() + if not file_path.exists() or not file_path.is_file(): + eprint(f"[NXP_ELE] TV file does not exist: {file_path}") + return 1 + return run_with_nvm_lifecycle( + [test_command_bin, str(file_path)], + f"[NXP_ELE] PASS: TV execution succeeded for {file_path}", + f"ELE HSM test ({test_command_bin})", + ) + + +def run_perf_test() -> int: + """Run ELE HSM performance test with required daemon lifecycle.""" + perf_command_bin = resolve_command(ELE_HSM_PERF_TEST_COMMAND_CANDIDATES, "ele_hsm_perf_test") + return run_with_nvm_lifecycle( + [perf_command_bin], + f"[NXP_ELE] PASS: Performance test succeeded ({perf_command_bin})", + f"ELE HSM performance test ({perf_command_bin})", + ) + + +def parse_args() -> argparse.Namespace: + """Parse CLI arguments.""" + parser = argparse.ArgumentParser( + description=( + "List NXP ELE test vectors or execute ELE HSM tests " + "with NVM daemon setup." + ) + ) + action_group = parser.add_mutually_exclusive_group(required=True) + action_group.add_argument( + "--list-tv", + action="store_true", + help="List discovered TV files as Checkbox resource records (key=value).", + ) + action_group.add_argument( + "--run-tv", + metavar="PATH", + help=( + "Run one TV file via: [sudo] oem-imx-secure-enclave.ele-hsm-test , " + "including nvm_daemon stop/cleanup/start/stop." + ), + ) + action_group.add_argument( + "--run-perf", + action="store_true", + help=( + "Run ELE HSM performance test via: " + "[sudo] oem-imx-secure-enclave.ele-hsm-perf-test, " + "including nvm_daemon stop/cleanup/start/stop." + ), + ) + return parser.parse_args() + + +def main() -> int: + """Program entry point.""" + try: + args = parse_args() + if args.list_tv: + return list_tv_records() + if args.run_perf: + return run_perf_test() + if args.run_tv is None: + eprint("[NXP_ELE] --run-tv requires a path argument.") + return 1 + return run_tv_file(args.run_tv) + except RuntimeError as exc: + eprint(str(exc)) + return 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/manifest.pxu b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/manifest.pxu index 97ce6d433b..1dd25ba7c8 100644 --- a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/manifest.pxu +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/manifest.pxu @@ -17,3 +17,8 @@ unit: manifest entry id: has_hardware_rng _name: Hardware Random Number Generate support value-type: bool + +unit: manifest entry +id: has_nxp_secure_element_ele +name: NXP EdgeLock Secure Enclave (ELE) supported on this device? +value-type: bool diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/nxp-secure-element.pxu b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/nxp-secure-element.pxu new file mode 100644 index 0000000000..6a4a652757 --- /dev/null +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/nxp-secure-element.pxu @@ -0,0 +1,74 @@ +id: nxp_ele_list_tv_files +plugin: resource +_summary: Enumerate available NXP ELE test vector files +_description: + Discover test vector files from common oem-imx-secure-enclave locations. + Outputs Checkbox resource records with tv_file, tv_name, tv_category and tv_variant + for category-aware template expansion. +estimated_duration: 5 +command: + nxp_ele_test.py --list-tv + +id: ce-oem-nxp-ele/device-node +category_id: crypto +_summary: Check OP-TEE device node has been probed in the system. +plugin: shell +user: root +estimated_duration: 20.0 +requires: manifest.has_nxp_secure_element_ele == 'True' +imports: from com.canonical.plainbox import manifest +command: + node="$(find /dev -type c -regex '.*/\(hsm\)[0-9]_ch[0-9]')" + if [[ -n $node ]]; then + echo -e "\nInfo: Find HSM node in the system!" + for x in $node + do + echo -e "\n$x" + done + else + echo -e "\nError: Not able to find HSM node in the system!" + exit 1 + fi + +id: ce-oem-nxp-ele/hsm_run_perf +plugin: shell +_summary: Run NXP ELE HSM performance test +_description: + Execute oem-imx-secure-enclave.ele-hsm-perf-test with nvm_daemon + stop/cleanup/start/stop lifecycle. +user: root +category_id: crypto +imports: from com.canonical.plainbox import manifest +requires: manifest.has_nxp_secure_element_ele == 'True' +depends: ce-oem-nxp-ele/device-node +flags: also-after-suspend +estimated_duration: 120 +command: + nxp_ele_test.py --run-perf + +unit: template +template-resource: nxp_ele_list_tv_files +template-unit: job +template-engine: jinja2 +template-id: ce-oem-nxp-ele/hsm_run_tv +id: ce-oem-nxp-ele/hsm_run_tv_{{ tv_category }}_{{ tv_variant }}_{{ tv_name }} +_summary: Run NXP ELE {{ tv_category }} ({{ tv_variant }}) vector +_template-summary: Run NXP ELE test vector by category +_description: + Execute oem-imx-secure-enclave.ele-hsm-test with test vector. + Category: {{ tv_category }} + Variant: {{ tv_variant }} + Vector: {{ tv_name }} + File: {{ tv_file }} + The test runs with nvm_daemon stop/cleanup/start/stop lifecycle + to ensure clean state for each vector execution. +plugin: shell +imports: from com.canonical.plainbox import manifest +requires: manifest.has_nxp_secure_element_ele == 'True' +depends: ce-oem-nxp-ele/device-node +user: root +category_id: crypto +flags: also-after-suspend +estimated_duration: 60 +command: + nxp_ele_test.py --run-tv "{{ tv_file }}" diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/test-plan-nxp.pxu b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/test-plan-nxp.pxu new file mode 100644 index 0000000000..8dbe62593c --- /dev/null +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/crypto/test-plan-nxp.pxu @@ -0,0 +1,10 @@ +id: ce-oem-nxp-ele-automated +unit: test plan +_name: NXP ELE tests +_description: Automated NXP EdgeLock ELE validation using test vectors. +bootstrap_include: + nxp_ele_list_tv_files +include: + ce-oem-nxp-ele/device-node + ce-oem-nxp-ele/hsm_run_perf + ce-oem-nxp-ele/hsm_run_tv diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu index df3bd996d0..6582b88204 100644 --- a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/units/test-plan-ce-oem.pxu @@ -107,6 +107,7 @@ nested_part: ce-oem-barcode-scanner-automated ce-oem-printer-automated ce-oem-credit-card-reader-automated + ce-oem-nxp-ele-automated certification_status_overrides: apply blocker to .* From d04bff574c24d8926c8b9f08950421c3282039c6 Mon Sep 17 00:00:00 2001 From: stanley31 Date: Thu, 11 Jun 2026 10:59:39 +0800 Subject: [PATCH 2/6] applied suggestions applied suggestions --- .../bin/nxp_ele_test.py | 58 +++++++++++-------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py index 980891a450..073b594533 100755 --- a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py @@ -7,6 +7,7 @@ import shutil import subprocess import sys +from contextlib import contextmanager from pathlib import Path from typing import Dict, List, Set, Tuple @@ -261,13 +262,13 @@ def list_tv_records() -> int: return 0 -def run_with_nvm_lifecycle(test_command: List[str], success_message: str, fail_label: str) -> int: - """Execute one test command with the NVM daemon stop/cleanup/start/stop lifecycle.""" +@contextmanager +def nvm_daemon_lifecycle(): + """Context manager for NVM daemon lifecycle around test execution.""" ensure_systemctl_available() service_name = resolve_nvm_daemon_service_name() + is_started = False - test_exit = 1 - daemon_stop_failed = False try: print(f"[NXP_ELE] Stopping {service_name} before cleanup") set_nvm_daemon_state("stop", service_name) @@ -276,25 +277,35 @@ def run_with_nvm_lifecycle(test_command: List[str], success_message: str, fail_l print(f"[NXP_ELE] Starting {service_name} for test execution") set_nvm_daemon_state("start", service_name) + is_started = True - test_exit = run_with_optional_sudo(test_command, allow_failure=True) - if test_exit != 0: - eprint( - f"[NXP_ELE] {fail_label} failed with exit code {test_exit}" - ) - else: - print(success_message) + yield finally: - print(f"[NXP_ELE] Stopping {service_name} after test") - try: - set_nvm_daemon_state("stop", service_name) - except RuntimeError as exc: - eprint(str(exc)) - daemon_stop_failed = True - - if daemon_stop_failed and test_exit == 0: + if is_started: + print(f"[NXP_ELE] Stopping {service_name} after test") + try: + set_nvm_daemon_state("stop", service_name) + except RuntimeError as exc: + eprint(str(exc)) + + +def run_with_nvm_lifecycle(test_command: List[str], test_label: str) -> int: + """Execute one test command with the NVM daemon stop/cleanup/start/stop lifecycle.""" + test_exit = 1 + try: + with nvm_daemon_lifecycle(): + test_exit = run_with_optional_sudo(test_command, allow_failure=True) + if test_exit != 0: + eprint( + f"[NXP_ELE] {test_label} failed with exit code {test_exit}" + ) + return test_exit + + print("[NXP_ELE] PASS: {} execution succeeded".format(test_label)) + return 0 + except RuntimeError as exc: + eprint("[NXP_ELE] Error during {}: {}".format(test_label, str(exc))) return 1 - return test_exit def run_tv_file(tv_file: str) -> int: @@ -304,10 +315,10 @@ def run_tv_file(tv_file: str) -> int: if not file_path.exists() or not file_path.is_file(): eprint(f"[NXP_ELE] TV file does not exist: {file_path}") return 1 + return run_with_nvm_lifecycle( [test_command_bin, str(file_path)], - f"[NXP_ELE] PASS: TV execution succeeded for {file_path}", - f"ELE HSM test ({test_command_bin})", + "TV execution", ) @@ -316,8 +327,7 @@ def run_perf_test() -> int: perf_command_bin = resolve_command(ELE_HSM_PERF_TEST_COMMAND_CANDIDATES, "ele_hsm_perf_test") return run_with_nvm_lifecycle( [perf_command_bin], - f"[NXP_ELE] PASS: Performance test succeeded ({perf_command_bin})", - f"ELE HSM performance test ({perf_command_bin})", + "Performance test", ) From 82767dc73b074568355e7611a4c3db60cad2b5e5 Mon Sep 17 00:00:00 2001 From: stanley31 Date: Thu, 11 Jun 2026 13:35:04 +0800 Subject: [PATCH 3/6] fix coding style issue fix coding style issue --- .../bin/nxp_ele_test.py | 133 ++++++++++++------ .../checkbox-provider-ce-oem/tox.ini | 3 + 2 files changed, 92 insertions(+), 44 deletions(-) diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py index 073b594533..8c7eb619c0 100755 --- a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py @@ -40,46 +40,60 @@ def eprint(message: str) -> None: def resolve_command(candidates: List[str], command_label: str) -> str: - """Resolve the first available executable command from a candidate list.""" + """ + Resolve the first available executable command from a candidate list. + """ for candidate in candidates: if shutil.which(candidate) is not None: return candidate raise RuntimeError( - f"[NXP_ELE] Required command for {command_label} not found. " - f"Tried: {', '.join(candidates)}" + "[NXP_ELE] Required command for {} not found. Tried: {}".format( + command_label, + ", ".join(candidates), + ) ) def ensure_systemctl_available() -> None: """Ensure systemctl is available for daemon lifecycle management.""" if shutil.which("systemctl") is None: - raise RuntimeError("[NXP_ELE] Required command 'systemctl' was not found in PATH.") + raise RuntimeError( + "[NXP_ELE] Required command 'systemctl' was not found in PATH." + ) -def run_with_optional_sudo(command: List[str], allow_failure: bool = False) -> int: +def run_with_optional_sudo( + command: List[str], allow_failure: bool = False +) -> int: """Run command directly as root or through sudo when needed.""" final_command = list(command) if os.geteuid() != 0: sudo_path = shutil.which("sudo") if sudo_path is None: raise RuntimeError( - "[NXP_ELE] Root privileges are required and 'sudo' is not available." + "Root privileges are required and 'sudo' is not available." ) final_command = [sudo_path] + final_command - print(f"[NXP_ELE] Running command: {' '.join(final_command)}") + print("[NXP_ELE] Running command: {}".format(" ".join(final_command))) result = subprocess.run(final_command, check=False) if result.returncode != 0 and not allow_failure: raise RuntimeError( - "[NXP_ELE] Command failed with exit code " - f"{result.returncode}: {' '.join(final_command)}" + "[NXP_ELE] Command failed with exit code {}: {}".format( + result.returncode, " ".join(final_command) + ) ) return result.returncode def resolve_nvm_daemon_service_name() -> str: """Resolve the available NVM daemon systemd unit name.""" - list_units_cmd = ["systemctl", "list-unit-files", "--type=service", "--no-legend"] + list_units_cmd = [ + "systemctl", + "list-unit-files", + "--type=service", + "--no-legend", + ] result = subprocess.run( list_units_cmd, check=False, @@ -88,8 +102,9 @@ def resolve_nvm_daemon_service_name() -> str: ) if result.returncode != 0: raise RuntimeError( - "[NXP_ELE] Failed to query systemd unit files via " - f"'{' '.join(list_units_cmd)}'." + "[NXP_ELE] Failed to query systemd unit files via {}".format( + " ".join(list_units_cmd) + ) ) available_units = set() @@ -103,19 +118,23 @@ def resolve_nvm_daemon_service_name() -> str: for candidate in NVM_DAEMON_SERVICE_CANDIDATES: if candidate in available_units: return candidate - if candidate.endswith(".service") and candidate[:-8] in available_units: + if ( + candidate.endswith(".service") + and candidate[:-8] in available_units + ): return candidate[:-8] raise RuntimeError( - "[NXP_ELE] Could not find supported NVM daemon service. " - f"Tried: {', '.join(NVM_DAEMON_SERVICE_CANDIDATES)}" + "Could not find supported NVM daemon service. Tried: {}".format( + ", ".join(NVM_DAEMON_SERVICE_CANDIDATES) + ) ) def set_nvm_daemon_state(action: str, service_name: str) -> None: """Start or stop the NVM daemon service.""" if action not in ("start", "stop"): - raise RuntimeError(f"[NXP_ELE] Unsupported daemon action: {action}") + raise RuntimeError("Unsupported daemon action: {}".format(action)) run_with_optional_sudo(["systemctl", action, service_name]) @@ -123,10 +142,10 @@ def cleanup_nvm_data() -> None: """Delete NVM test data directories content when present.""" for directory in NVM_DATA_DIRECTORIES: if not directory.exists(): - print(f"[NXP_ELE] Cleanup skipped (not found): {directory}") + print("# Cleanup skipped (not found): {}".format(directory)) continue - print(f"[NXP_ELE] Cleaning directory: {directory}") + print("# Cleaning directory: {}".format(directory)) for child in directory.iterdir(): if child.is_dir() and not child.is_symlink(): run_with_optional_sudo(["rm", "-rf", str(child)]) @@ -155,7 +174,7 @@ def parse_tv_metadata(tv_file: Path) -> Tuple[str, str]: variant_candidates = ("persistent_ap", "volatile_ap", "ap", "n", "p") for variant in variant_candidates: - suffix = f"_{variant}" + suffix = "_{}".format(variant) if raw.endswith(suffix): category = raw[: -len(suffix)] if category: @@ -167,15 +186,19 @@ def parse_tv_metadata(tv_file: Path) -> Tuple[str, str]: def get_candidate_directories() -> List[Path]: """Build candidate TV directories, including snap revision paths.""" - candidates: List[Path] = list(CANDIDATE_DIRECTORIES) + candidates = list(CANDIDATE_DIRECTORIES) snap_root = Path("/snap/oem-imx-secure-enclave") if snap_root.is_dir(): - for revision_dir in sorted(snap_root.iterdir(), key=lambda path: path.name): + for revision_dir in sorted( + snap_root.iterdir(), key=lambda path: path.name + ): if not revision_dir.is_dir(): continue candidates.append(revision_dir / "usr/share/se/test_vectors") candidates.append(revision_dir / "usr/share/se/test_vectors/psa") - candidates.append(revision_dir / "usr/share/oem-imx-secure-enclave") + candidates.append( + revision_dir / "usr/share/oem-imx-secure-enclave" + ) return candidates @@ -186,12 +209,15 @@ def discover_tv_files() -> List[Path]: results: List[Path] = [] all_candidates = get_candidate_directories() - existing_dirs = [directory for directory in all_candidates if directory.is_dir()] + existing_dirs = [ + directory for directory in all_candidates if directory.is_dir() + ] if not existing_dirs: candidates = ", ".join(str(path) for path in all_candidates) raise RuntimeError( - "[NXP_ELE] No candidate TV directories found. " - f"Checked: {candidates}" + "[NXP_ELE] No candidate TV directories found. Checked: {}".format( + candidates + ) ) for root in existing_dirs: @@ -228,7 +254,10 @@ def build_tv_records(tv_files: List[Path]) -> List[Dict[str, str]]: tv_category, tv_variant = parse_tv_metadata(tv_file) sequence = used_names.get(base_name, 0) used_names[base_name] = sequence + 1 - tv_name = base_name if sequence == 0 else f"{base_name}_{sequence + 1}" + if sequence > 0: + tv_name = "{}_{}".format(base_name, sequence + 1) + else: + tv_name = base_name records.append( { @@ -253,10 +282,10 @@ def list_tv_records() -> int: return 1 for record in build_tv_records(tv_files): - print(f"tv_file: {record['tv_file']}") - print(f"tv_name: {record['tv_name']}") - print(f"tv_category: {record['tv_category']}") - print(f"tv_variant: {record['tv_variant']}") + print("tv_file: {}".format(record["tv_file"])) + print("tv_name: {}".format(record["tv_name"])) + print("tv_category: {}".format(record["tv_category"])) + print("tv_variant: {}".format(record["tv_variant"])) print() return 0 @@ -270,19 +299,19 @@ def nvm_daemon_lifecycle(): is_started = False try: - print(f"[NXP_ELE] Stopping {service_name} before cleanup") + print("[NXP_ELE] Stopping {} before cleanup".format(service_name)) set_nvm_daemon_state("stop", service_name) cleanup_nvm_data() - print(f"[NXP_ELE] Starting {service_name} for test execution") + print("[NXP_ELE] Starting {} for test execution".format(service_name)) set_nvm_daemon_state("start", service_name) is_started = True yield finally: if is_started: - print(f"[NXP_ELE] Stopping {service_name} after test") + print("[NXP_ELE] Stopping {} after test".format(service_name)) try: set_nvm_daemon_state("stop", service_name) except RuntimeError as exc: @@ -290,17 +319,23 @@ def nvm_daemon_lifecycle(): def run_with_nvm_lifecycle(test_command: List[str], test_label: str) -> int: - """Execute one test command with the NVM daemon stop/cleanup/start/stop lifecycle.""" + """ + Execute one test command with the NVM daemon lifecycle. + """ test_exit = 1 try: with nvm_daemon_lifecycle(): - test_exit = run_with_optional_sudo(test_command, allow_failure=True) + test_exit = run_with_optional_sudo( + test_command, allow_failure=True + ) if test_exit != 0: eprint( - f"[NXP_ELE] {test_label} failed with exit code {test_exit}" + "[NXP_ELE] {} failed with exit code {}".format( + test_label, test_exit + ) ) return test_exit - + print("[NXP_ELE] PASS: {} execution succeeded".format(test_label)) return 0 except RuntimeError as exc: @@ -309,11 +344,15 @@ def run_with_nvm_lifecycle(test_command: List[str], test_label: str) -> int: def run_tv_file(tv_file: str) -> int: - """Run one TV file with required daemon stop/cleanup/start/stop lifecycle.""" - test_command_bin = resolve_command(ELE_HSM_TEST_COMMAND_CANDIDATES, "ele_hsm_test") + """ + Run one TV file with required daemon stop/cleanup/start/stop lifecycle. + """ + test_command_bin = resolve_command( + ELE_HSM_TEST_COMMAND_CANDIDATES, "ele_hsm_test" + ) file_path = Path(tv_file).expanduser().resolve() if not file_path.exists() or not file_path.is_file(): - eprint(f"[NXP_ELE] TV file does not exist: {file_path}") + eprint("[NXP_ELE] TV file does not exist: {}".format(file_path)) return 1 return run_with_nvm_lifecycle( @@ -324,7 +363,9 @@ def run_tv_file(tv_file: str) -> int: def run_perf_test() -> int: """Run ELE HSM performance test with required daemon lifecycle.""" - perf_command_bin = resolve_command(ELE_HSM_PERF_TEST_COMMAND_CANDIDATES, "ele_hsm_perf_test") + perf_command_bin = resolve_command( + ELE_HSM_PERF_TEST_COMMAND_CANDIDATES, "ele_hsm_perf_test" + ) return run_with_nvm_lifecycle( [perf_command_bin], "Performance test", @@ -337,19 +378,23 @@ def parse_args() -> argparse.Namespace: description=( "List NXP ELE test vectors or execute ELE HSM tests " "with NVM daemon setup." - ) + ), ) action_group = parser.add_mutually_exclusive_group(required=True) action_group.add_argument( "--list-tv", action="store_true", - help="List discovered TV files as Checkbox resource records (key=value).", + help=( + "List discovered TV files as Checkbox resource records" + " (key=value)." + ), ) action_group.add_argument( "--run-tv", metavar="PATH", help=( - "Run one TV file via: [sudo] oem-imx-secure-enclave.ele-hsm-test , " + "Run one TV file via: " + "[sudo] oem-imx-secure-enclave.ele-hsm-test , " "including nvm_daemon stop/cleanup/start/stop." ), ) diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/tox.ini b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/tox.ini index 33f78fd869..b7422ba562 100644 --- a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/tox.ini +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/tox.ini @@ -111,3 +111,6 @@ deps = pyparsing == 3.1.1 distro == 1.9.0 PyYAML == 6.0.1 + +[flake8] +extend-ignore = E203 From 299a1b8bf4b965fc61276dff79b175fedcf01811 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Jun 2026 06:15:16 +0000 Subject: [PATCH 4/6] Resolve merge conflicts with origin/main --- .../__pycache__/nxp_ele_test.cpython-312.pyc | Bin 0 -> 18007 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/__pycache__/nxp_ele_test.cpython-312.pyc diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/__pycache__/nxp_ele_test.cpython-312.pyc b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/__pycache__/nxp_ele_test.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2647fac2dc6c02f866b4e0c75264607c4787de74 GIT binary patch literal 18007 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 ca)NvQ`1enL_wrvmi=NH@7lvwV>Hq)$ literal 0 HcmV?d00001 From 09935ea1c471ae8fa2c77d7d369593de7670b2b2 Mon Sep 17 00:00:00 2001 From: stanley31 Date: Tue, 16 Jun 2026 10:09:05 +0800 Subject: [PATCH 5/6] remove pyc file remove pyc file --- .../__pycache__/nxp_ele_test.cpython-312.pyc | Bin 18007 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/__pycache__/nxp_ele_test.cpython-312.pyc diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/__pycache__/nxp_ele_test.cpython-312.pyc b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/__pycache__/nxp_ele_test.cpython-312.pyc deleted file mode 100644 index 2647fac2dc6c02f866b4e0c75264607c4787de74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18007 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 ca)NvQ`1enL_wrvmi=NH@7lvwV>Hq)$ From 5539d43abc859d625c28b1601ffcaa1c54348dee Mon Sep 17 00:00:00 2001 From: stanley31 Date: Tue, 16 Jun 2026 10:17:53 +0800 Subject: [PATCH 6/6] fix coding style issue fix coding style issue --- .../checkbox-provider-ce-oem/bin/nxp_ele_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py index 8c7eb619c0..de1c56f8ec 100755 --- a/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py +++ b/contrib/checkbox-ce-oem/checkbox-provider-ce-oem/bin/nxp_ele_test.py @@ -9,7 +9,7 @@ import sys from contextlib import contextmanager from pathlib import Path -from typing import Dict, List, Set, Tuple +from typing import Dict, List, Tuple ELE_HSM_TEST_COMMAND_CANDIDATES = [ "oem-imx-secure-enclave.ele-hsm-test", @@ -205,8 +205,8 @@ def get_candidate_directories() -> List[Path]: def discover_tv_files() -> List[Path]: """Discover test vector files from candidate directories.""" - found: Set[str] = set() - results: List[Path] = [] + found = set() + results = [] all_candidates = get_candidate_directories() existing_dirs = [ @@ -246,8 +246,8 @@ def build_tv_records(tv_files: List[Path]) -> List[Dict[str, str]]: - tv_category: parsed functional category (e.g. set1_cipher) - tv_variant: parsed profile/variant (e.g. ap, p, n, persistent_ap) """ - records: List[Dict[str, str]] = [] - used_names: Dict[str, int] = {} + records = [] + used_names = {} for tv_file in tv_files: base_name = sanitize_name(tv_file.stem)