diff --git a/test/integration/test_ota_metadata/__init__.py b/test/integration/test_ota_metadata/__init__.py new file mode 100644 index 000000000..bcfd866ad --- /dev/null +++ b/test/integration/test_ota_metadata/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022 TIER IV, INC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/integration/test_ota_metadata/keys/gen_certs.sh b/test/integration/test_ota_metadata/keys/gen_certs.sh new file mode 100755 index 000000000..38a996b78 --- /dev/null +++ b/test/integration/test_ota_metadata/keys/gen_certs.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# https://stackoverflow.com/questions/52500165/problem-verifying-a-self-created-openssl-root-intermediate-and-end-user-certifi + +set -eux + +CA_CHAIN_PREFIX=${1:-test} + +# Root CA: +openssl ecparam -out root.key -name prime256v1 -genkey +openssl req -new -x509 \ + -days $((365 * 100)) \ + -key root.key \ + -out ${CA_CHAIN_PREFIX}.root.pem \ + -sha256 \ + -subj "/C=JP/ST=Tokyo/O=Tier4/CN=root.tier4.jp" + +# Intermediate +openssl ecparam -out interm.key -name prime256v1 -genkey +openssl req -new \ + -key interm.key \ + -out interm.csr \ + -sha256 \ + -subj "/C=JP/ST=Tokyo/O=Tier4/CN=intermediate.tier4.jp" + +CA_INTERM_EXT=" +[ v3_intermediate_ca ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true, pathlen:0 +" +openssl x509 -req \ + -days $((365 * 100)) \ + -in interm.csr \ + -CA ${CA_CHAIN_PREFIX}.root.pem \ + -CAkey root.key \ + -out ${CA_CHAIN_PREFIX}.interm.pem \ + -sha256 -CAcreateserial \ + -extfile <(echo "${CA_INTERM_EXT}") \ + -extensions v3_intermediate_ca + +# Sign cert +SIGN_CERT_EXT=" +[ sign_cert ] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +keyUsage = critical, digitalSignature +extendedKeyUsage = codeSigning +basicConstraints = critical, CA:FALSE +" + +openssl ecparam -out sign.key -name prime256v1 -genkey +openssl req -new \ + -key sign.key \ + -out sign.csr \ + -sha256 \ + -subj "/C=JP/ST=Tokyo/O=Tier4/CN=sign.tier4.jp" + +openssl x509 -req \ + -days $((365 * 100)) \ + -in sign.csr \ + -CA ${CA_CHAIN_PREFIX}.interm.pem \ + -CAkey interm.key \ + -out sign.pem \ + -sha256 -CAcreateserial \ + -extfile <(echo "${SIGN_CERT_EXT}") \ + -extensions sign_cert + +rm -f root.key interm.key interm.csr sign.csr *.srl diff --git a/tests/test_ota_metadata/test_ca_store.py b/test/integration/test_ota_metadata/test_ca_store.py similarity index 91% rename from tests/test_ota_metadata/test_ca_store.py rename to test/integration/test_ota_metadata/test_ca_store.py index a0e6a9361..a0abe5508 100644 --- a/tests/test_ota_metadata/test_ca_store.py +++ b/test/integration/test_ota_metadata/test_ca_store.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - +"""Integration tests for `load_ca_cert_chains` against subprocess-generated CA chains.""" from __future__ import annotations @@ -23,11 +23,8 @@ from cryptography.x509 import load_pem_x509_certificate from ota_metadata.utils.cert_store import CACertStoreInvalid, load_ca_cert_chains -from tests.conftest import TEST_DIR -from tests.conftest import TestConfiguration as cfg -GEN_CERTS_SCRIPT = TEST_DIR / "keys" / "gen_certs.sh" -TEST_BASE_SIGN_PEM = Path(cfg.CERTS_DIR) / "sign.pem" +GEN_CERTS_SCRIPT = Path(__file__).parent / "keys" / "gen_certs.sh" @pytest.fixture diff --git a/test/integration/test_ota_metadata/test_legacy2/__init__.py b/test/integration/test_ota_metadata/test_legacy2/__init__.py new file mode 100644 index 000000000..bcfd866ad --- /dev/null +++ b/test/integration/test_ota_metadata/test_legacy2/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022 TIER IV, INC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/integration/test_ota_metadata/test_legacy2/conftest.py b/test/integration/test_ota_metadata/test_legacy2/conftest.py new file mode 100644 index 000000000..d5ac3cea8 --- /dev/null +++ b/test/integration/test_ota_metadata/test_legacy2/conftest.py @@ -0,0 +1,29 @@ +# Copyright 2022 TIER IV, INC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Local fixtures and constants for legacy2 metadata integration tests. + +Container dependency: + The legacy v1 OTA image fixture is baked into the test container image + by `docker/test_base/Dockerfile` (copied from the upstream + `ota_img_for_test` image). Tests in this subtree consume it via the + absolute container path `/ota-image`. +""" + +from __future__ import annotations + +from pathlib import Path + +# Absolute container path for the legacy v1 OTA image fixture; baked in by +# `docker/test_base/Dockerfile`. Do not relocate to `test/data/`. +OTA_IMAGE_DIR = Path("/ota-image") diff --git a/tests/test_ota_metadata/test_legacy2/test_csv_parser.py b/test/integration/test_ota_metadata/test_legacy2/test_csv_parser.py similarity index 94% rename from tests/test_ota_metadata/test_legacy2/test_csv_parser.py rename to test/integration/test_ota_metadata/test_legacy2/test_csv_parser.py index ff0b80340..0232e4c2c 100644 --- a/tests/test_ota_metadata/test_legacy2/test_csv_parser.py +++ b/test/integration/test_ota_metadata/test_legacy2/test_csv_parser.py @@ -11,8 +11,12 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" -NOTE: the test cases are mostly re-used from the previous implementation. +"""Integration tests for legacy v1 CSV → sqlite conversion. + +The CSV line parser cases are pure-input/expected-output checks, but the +parse-and-build test consumes the real `regulars.txt` / `dirs.txt` / +`symlinks.txt` from the container-baked `/ota-image` and writes to a real +sqlite database under `tmp_path` — hence integration tier. """ from __future__ import annotations @@ -50,11 +54,10 @@ parse_symlinks_from_csv_file, ) from ota_metadata.legacy2.rs_table import ResourceTable, ResourceTableORM -from tests.conftest import TestConfiguration as test_cfg -logger = logging.getLogger(__name__) +from .conftest import OTA_IMAGE_DIR -OTA_IMAGE_ROOT = Path(test_cfg.OTA_IMAGE_DIR) +logger = logging.getLogger(__name__) # # ------ test CSV line parser ------ # @@ -224,9 +227,9 @@ def test_persistent_txt(_input: str, _expected: str): # ------ test import sqlite3 database ------ # # -regulars_txt = OTA_IMAGE_ROOT / "regulars.txt" -dirs_txt = OTA_IMAGE_ROOT / "dirs.txt" -symlinks_txt = OTA_IMAGE_ROOT / "symlinks.txt" +regulars_txt = OTA_IMAGE_DIR / "regulars.txt" +dirs_txt = OTA_IMAGE_DIR / "dirs.txt" +symlinks_txt = OTA_IMAGE_DIR / "symlinks.txt" def test_parse_and_build_file_table_db_from_csv(tmp_path: Path): diff --git a/test/integration/test_ota_metadata/test_ota_image_v1/__init__.py b/test/integration/test_ota_metadata/test_ota_image_v1/__init__.py new file mode 100644 index 000000000..bcfd866ad --- /dev/null +++ b/test/integration/test_ota_metadata/test_ota_image_v1/__init__.py @@ -0,0 +1,13 @@ +# Copyright 2022 TIER IV, INC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/tests/test_ota_metadata/test_ota_image_v1/test_cert_verification.py b/test/integration/test_ota_metadata/test_ota_image_v1/test_cert_verification.py similarity index 84% rename from tests/test_ota_metadata/test_ota_image_v1/test_cert_verification.py rename to test/integration/test_ota_metadata/test_ota_image_v1/test_cert_verification.py index 3654d2440..e95e650cf 100644 --- a/tests/test_ota_metadata/test_ota_image_v1/test_cert_verification.py +++ b/test/integration/test_ota_metadata/test_ota_image_v1/test_cert_verification.py @@ -11,6 +11,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +"""Integration tests for v1 OTA image CA-store cert-chain verification. + +Generates root / intermediate / sign certs in subprocess via +`gen_certs.sh` for each chain prefix, then asserts that +`load_ca_store(...)` resolves the right chain map and verifies the +matching sign cert. +""" from __future__ import annotations @@ -27,14 +34,14 @@ logger = logging.getLogger(__name__) -CERT_GEN_SCRIPT = Path(__file__).parent.parent.parent / "keys" / "gen_certs.sh" +CERT_GEN_SCRIPT = Path(__file__).parents[1] / "keys" / "gen_certs.sh" CHAINS = ["dev", "stg", "prd"] @pytest.fixture def gen_ca_chains(tmp_path: Path) -> tuple[Path, Path, Path]: """ - Check tests/keys/gen_certs.sh for more details. + Check `keys/gen_certs.sh` for more details. """ _script = tmp_path / "gen_certs.sh" _ca_dir = tmp_path / "root_ca"