diff --git a/onekey_client/cli/firmware_upload.py b/onekey_client/cli/firmware_upload.py index 52a9fba..c2b36d1 100644 --- a/onekey_client/cli/firmware_upload.py +++ b/onekey_client/cli/firmware_upload.py @@ -32,7 +32,12 @@ ) @click.option("--version", help="Firmware version") @click.option("--name", help="Firmware name") -@click.argument("filename", type=click.Path(exists=True, path_type=Path)) +@click.option( + "--sbom", help="Firmware SBOM", type=click.Path(exists=True, path_type=Path) +) +@click.argument( + "filename", type=click.Path(exists=True, path_type=Path), required=False +) @click.pass_obj def upload_firmware( client: Client, @@ -42,17 +47,23 @@ def upload_firmware( analysis_configuration_name: str, version: str | None, name: str | None, - filename: Path, + sbom: Path | None, + filename: Path | None, ): - """Upload a firmware to the ONEKEY platform.""" + """Upload a firmware / SBOM to the ONEKEY platform.""" + if filename is None and sbom is None: + error = "Either `--sbom` or `FILENAME` or both must be provided" + raise click.BadParameter(error) + product_group_id = _get_product_group_id_by_name(client, product_group_name) analysis_configuration_id = _get_analysis_configuration_id_by_name( client, analysis_configuration_name ) if name is None: + postfix = filename.name if filename is not None else sbom.stem name = ( - f"{vendor_name}-{product_name}-{filename.name}" + f"{vendor_name}-{product_name}-{postfix}" if version is None else f"{vendor_name}-{product_name}-{version}" ) @@ -67,7 +78,9 @@ def upload_firmware( ) try: - res = client.upload_firmware(metadata, filename, enable_monitoring=False) + res = client.upload_firmware( + metadata, filename, sbom_path=sbom, enable_monitoring=False + ) click.echo(res["id"]) except QueryError as e: click.echo("Error during firmware upload:") diff --git a/onekey_client/client.py b/onekey_client/client.py index 4504a95..8354bc0 100644 --- a/onekey_client/client.py +++ b/onekey_client/client.py @@ -188,11 +188,14 @@ def query(self, query: str, variables: dict | None = None, timeout=60): def upload_firmware( self, metadata: m.FirmwareMetadata, - path: Path, + path: Path | None, *, + sbom_path: Path | None = None, enable_monitoring: bool, timeout=60, ): + assert path is not None or sbom_path is not None + variables = { "firmware": { "name": metadata.name, @@ -215,9 +218,12 @@ def upload_firmware( raise errors.QueryError(res["createFirmwareUpload"]["errors"]) upload_url = res["createFirmwareUpload"]["uploadUrl"] - return self._post_with_token( - upload_url, files={"firmware": path.open("rb")}, timeout=timeout - ) + + files = {} + files["firmware"] = path.open("rb") if path is not None else b"" + if sbom_path is not None: + files["sbom"] = sbom_path.open("rb") + return self._post_with_token(upload_url, files=files, timeout=timeout) @_tenant_required def get_product_groups(self): diff --git a/pyproject.toml b/pyproject.toml index eb9fdb2..612f5d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,9 +1,9 @@ [project] name = "onekey_client" -version = "2.4.0" +version = "2.5.0" description = "ONEKEY API client" authors = [{ name = "ONEKEY", email = "support@onekey.com" }] -requires-python = ">=3.9" +requires-python = ">=3.10" readme = "README.md" license = "MIT" keywords = ["iot", "security", "firmware", "analysis"]