-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2bdd963
commit c02da85
Showing
8 changed files
with
694 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[url "https://github.com/"] | ||
insteadOf = ssh://[email protected]/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from argparse import ArgumentParser | ||
from pathlib import Path | ||
from typing import Dict | ||
from collections import defaultdict | ||
import json | ||
|
||
APP_LOAD_PARAMS_ALLOWED = { | ||
"targetId", | ||
"targetVersion", | ||
"apiLevel", | ||
"fileName", | ||
"icon", | ||
"curve", | ||
"path", | ||
"path_slip21", | ||
"appName", | ||
# "signature", # Reserved for internal usage | ||
# "signApp", # Reserved for internal usage | ||
"appFlags", | ||
# "bootAddr", # Deprecated? | ||
# "rootPrivateKey", # Should not be used for app deployment | ||
# "signPrivateKey", # Should not be used for app deployment | ||
# "apdu", # Should not be used for app deployment | ||
# "deployLegacy", # Deprecated? | ||
"delete", | ||
# "params", # Deprecated? | ||
"tlv", | ||
"dataSize", | ||
"appVersion", | ||
# "offline", # Should not be used for app deployment | ||
# "offlineText", # Should not be used for app deployment | ||
# "installparamsSize", # Deprecated? | ||
"tlvraw", | ||
# "dep", # Deprecated? | ||
"nocrc", | ||
} | ||
|
||
APP_LOAD_PARAMS_VALUE_CHECK = { | ||
"curve", | ||
"path", | ||
"path_slip21", | ||
"appName", | ||
"appFlags", | ||
} | ||
|
||
|
||
def parse_listapploadparams(app_load_params_str: str) -> Dict: | ||
# Convert to dict. Store value in list type as some params can appear | ||
# multiple times (e.g `--path`). | ||
|
||
app_load_params = defaultdict(list) | ||
for param in app_load_params_str.split("--"): | ||
param = param.strip() | ||
if not param: | ||
continue | ||
|
||
if param.startswith("targetVersion="): | ||
parts = param.split("=") | ||
else: | ||
parts = param.split(" ") | ||
|
||
param_name = parts[0] | ||
|
||
param_value = None | ||
if len(parts) > 1: | ||
param_value = " ".join(parts[1:]) | ||
|
||
app_load_params[param_name].append(param_value) | ||
|
||
return dict(app_load_params) | ||
|
||
|
||
def check_manifest(manifest: dict, database: dict) -> None: | ||
ret = 0 | ||
|
||
for variant, data in manifest["VARIANTS"].items(): | ||
target = data["TARGET"] | ||
print(f"Checking for target '{target}' and variant '{variant}'") | ||
|
||
app_load_params_str = data["APP_LOAD_PARAMS"] | ||
app_load_params = parse_listapploadparams(app_load_params_str) | ||
print("Retrieved listapploadparams:") | ||
print(json.dumps(app_load_params, indent=4)) | ||
|
||
# Check that no unknown or reserved param is used | ||
for key in app_load_params: | ||
if key not in APP_LOAD_PARAMS_ALLOWED: | ||
print(f"[ERROR] Not allowed '{key}' in APP_LOAD_PARAMS") | ||
ret = -1 | ||
|
||
# Retrieve database app_params | ||
app_params_ref = database.get(variant) | ||
if not app_params_ref: | ||
print(f"[ERROR] Missing '{variant}' definition in the database") | ||
ret = -1 | ||
break | ||
|
||
# Check that the params match with the one from the database | ||
for key in APP_LOAD_PARAMS_VALUE_CHECK: | ||
app_params_ref_value = app_params_ref.get(key) | ||
app_load_params_value = app_load_params.get(key) | ||
if key == "appName": | ||
if len(app_load_params_value) != 1: | ||
print(f"[ERROR] Expected a single value for 'appName' ({app_load_params_value} vs {app_params_ref_value})") | ||
ret = -1 | ||
continue | ||
app_load_params_value = app_load_params_value[0] | ||
elif key == "appFlags": | ||
if not app_load_params_value: | ||
app_load_params_value = ["0x000"] | ||
|
||
if len(app_load_params_value) != 1: | ||
print(f"[ERROR] Expected a single value for 'appFlags' ({app_load_params_value} vs {app_params_ref_value})") | ||
ret = -1 | ||
continue | ||
|
||
app_load_params_value = app_load_params_value[0] | ||
if app_load_params_value.startswith("0x"): | ||
app_load_params_value = int(app_load_params_value, 16) | ||
else: | ||
app_load_params_value = int(app_load_params_value) | ||
|
||
app_params_ref_value = app_params_ref_value.get(target) | ||
if not app_params_ref_value: | ||
print(f"[ERROR] Missing 'appFlags' for '{target}'") | ||
ret = -1 | ||
continue | ||
if app_params_ref_value.startswith("0x"): | ||
app_params_ref_value = int(app_params_ref_value, 16) | ||
else: | ||
app_params_ref_value = int(app_params_ref_value) | ||
|
||
if not app_load_params_value == app_params_ref_value: | ||
print(f"[ERROR] Unexpected value for '{key}' ({app_load_params_value} vs {app_params_ref_value})") | ||
ret = -1 | ||
|
||
return ret | ||
|
||
|
||
def check_app(app_manifests_path: Path, database_path: Path) -> None: | ||
ret = 0 | ||
|
||
# Retrieve database | ||
with open(database_path, 'r') as f: | ||
database = json.load(f) | ||
|
||
manifest_list = [x for x in app_manifests_path.iterdir() if x.name.endswith(".json")] | ||
for manifest_path in manifest_list: | ||
# Retrieve manifest | ||
with open(manifest_path, 'r') as f: | ||
manifest = json.load(f) | ||
|
||
print(f"Checking {manifest_path.name}") | ||
ret |= check_manifest(manifest, database) | ||
|
||
if ret: | ||
print("Please fix the issues by either:") | ||
print("- Updating your app Makefile") | ||
print("- Creating a PR on https://github.com/LedgerHQ/ledger-app-database" | ||
" to update the app-params-database.json") | ||
|
||
exit(ret) | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = ArgumentParser() | ||
|
||
parser.add_argument("--app_manifests_path", required=True, type=Path) | ||
parser.add_argument("--database_path", required=True, type=Path) | ||
|
||
args = parser.parse_args() | ||
|
||
check_app(args.app_manifests_path, args.database_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from argparse import ArgumentParser | ||
from pathlib import Path | ||
from app_load_params_utils import load_database, save_database | ||
from makefile_dump import get_app_listvariants, get_app_listparams | ||
from app_load_params_check import APP_LOAD_PARAMS_VALUE_CHECK, parse_listapploadparams | ||
import json | ||
from collections import namedtuple | ||
|
||
Models = namedtuple('Models', ['sdk_value', 'device_name']) | ||
|
||
MODELS = [Models("$NANOS_SDK", "nanos"), | ||
Models("$NANOX_SDK", "nanox"), | ||
Models("$NANOSP_SDK", "nanosp"), | ||
Models("$STAX_SDK", "stax")] | ||
|
||
|
||
BUILD_PATH_LIST = { | ||
"app-acala" : "app" , | ||
"app-algorand" : "app" , | ||
"app-avalanche" : "app" , | ||
"app-arweave" : "app" , | ||
"app-alephzero" : "app" , | ||
"app-astar" : "app" , | ||
"app-axelar" : "app" , | ||
"app-bifrost" : "app" , | ||
"app-bifrost-kusama" : "app" , | ||
"app-bifrost-new" : "app" , | ||
"app-blockstack" : "app" , | ||
"app-coti" : "app" , | ||
"app-casper" : "app" , | ||
"app-centrifuge" : "app" , | ||
"app-cosmos" : "app" , | ||
"app-cryptocom" : "app" , | ||
"app-dgld" : "app" , | ||
"app-decimal" : "app" , | ||
"app-desmos" : "app" , | ||
"app-dock" : "app" , | ||
"app-edgeware" : "app" , | ||
"app-equilibrium" : "app" , | ||
"app-filecoin" : "app" , | ||
"app-firmachain" : "app" , | ||
"app-flow" : "app" , | ||
"app-genshiro" : "app" , | ||
"app-iov" : "app" , | ||
"app-internetcomputer" : "app" , | ||
"app-karura" : "app" , | ||
"app-khala" : "app" , | ||
"app-kusama" : "app" , | ||
"app-medibloc" : "app" , | ||
"app-near" : "workdir/app-near" , | ||
"app-nodle" : "app" , | ||
"app-oasis" : "app" , | ||
"app-panacea" : "app" , | ||
"app-parallel" : "app" , | ||
"app-persistence" : "app" , | ||
"app-phala" : "app" , | ||
"app-polkadex" : "app" , | ||
"app-polkadot" : "app" , | ||
"app-polymesh" : "app" , | ||
"app-reef" : "app" , | ||
"app-secret" : "app" , | ||
"app-stacks" : "app" , | ||
"app-statemine" : "app" , | ||
"app-statemint" : "app" , | ||
"app-thorchain" : "app" , | ||
"app-terra" : "app" , | ||
"app-xxnetwork" : "app" , | ||
} | ||
|
||
|
||
def gen_variant(app_name: str, output_file: Path = "", workdir: Path = "") -> dict: | ||
print(f"Generating for {app_name}") | ||
|
||
app_build_path = BUILD_PATH_LIST.get(app_name, "./") | ||
if app_build_path != "./": | ||
app_full_path = workdir / app_name / app_build_path | ||
else: | ||
app_full_path = workdir / app_name | ||
|
||
# Retrieve database | ||
|
||
database_params = { | ||
"name": app_name, | ||
} | ||
|
||
# Retrieve available variants | ||
for model in MODELS: | ||
try: | ||
variant_param_name, variants = get_app_listvariants(app_full_path, model.sdk_value, allow_failure=True) | ||
except: | ||
print("Skipping generation due to error") | ||
continue | ||
|
||
database_params["variant_param"] = variant_param_name | ||
database_params["variants_" + model.device_name] = variants | ||
if app_build_path != "./": | ||
database_params["build_path"] = app_build_path | ||
|
||
return database_params | ||
|
||
|
||
def gen_all_variants(config: str, output_file: Path = "", workdir: Path = "") -> str: | ||
output = [] | ||
for key in config: | ||
if key["name"]: | ||
output.append(gen_variant(key["name"], output_file, workdir)) | ||
return output | ||
|
||
|
||
def get_variants(input_file: Path = "", input_list: str = "", output_file: Path = "", workdir: Path = "") -> str: | ||
if input_file: | ||
config = load_database(input_file) | ||
else: | ||
config = input_list | ||
|
||
output = gen_all_variants(config, output_file, workdir) | ||
|
||
if output_file: | ||
save_database(output, output_file) | ||
|
||
return output | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = ArgumentParser() | ||
|
||
parser.add_argument("--config_file", required=True, type=Path) | ||
parser.add_argument("--database_path", required=True, type=Path) | ||
|
||
args = parser.parse_args() | ||
|
||
if args.config_file is not None: | ||
config = load_database(args.config_file) | ||
gen_all_variants(config, args.database_path) | ||
else: | ||
parser.print_help() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from pathlib import Path | ||
import json | ||
|
||
|
||
def format_database(database: dict) -> str: | ||
database_str = json.dumps(database, indent=2, sort_keys=True) | ||
# Drop some newlines to compact a bit the data while still | ||
# making it readable. | ||
database_str = database_str.replace("[\n ", "[") | ||
database_str = database_str.replace("{\n ", "{") | ||
database_str = database_str.replace("\n ]", "]") | ||
database_str = database_str.replace("\n }", "}") | ||
database_str = database_str.replace("\n ", " ") | ||
|
||
# Add newline at the end of file | ||
database_str += "\n" | ||
|
||
return database_str | ||
|
||
|
||
def load_database(database_path: Path): | ||
database = {} | ||
if database_path.exists(): | ||
with open(database_path, 'r') as f: | ||
database = json.load(f) | ||
else: | ||
with open(database_path, 'w') as f: | ||
print("File created:", database_path) | ||
database = [] | ||
return database | ||
|
||
|
||
def save_database(database: dict, database_path: Path): | ||
database_str = format_database(database) | ||
with open(database_path, 'w') as f: | ||
f.write(database_str) |
Oops, something went wrong.