56 lines
2.3 KiB
Python
56 lines
2.3 KiB
Python
"""Task 6: one-shot generator for `tests/goldens_signed/*.expected.xml` --
|
|
NOT run automatically by the test suite. Run manually whenever a golden case
|
|
in the `sowai-fiscal` lib is added/changed (or `tests/fixtures/test_cert.pfx`
|
|
is rotated), then commit the regenerated files.
|
|
|
|
Signs each `sowai_fiscal.goldens/*.input.json` case's `DadosEmissao` (loaded
|
|
via `sowai_fiscal.golden_helpers.dados_from_json` -- SAME helper the lib's
|
|
own pre-signature goldens use, so `chave_acesso`/`numero`/`cnf`/`dh_emi` are
|
|
whatever that JSON already pins, unchanged) with the FIXED test certificate.
|
|
Deterministic because RSA PKCS#1v1.5 signing has no random padding: the SAME
|
|
(input XML, private key) pair always produces the SAME signature bytes --
|
|
this is the byte-exact assertion `tests/test_signed_goldens.py` checks.
|
|
|
|
uv run python scripts/generate_signed_goldens.py
|
|
"""
|
|
import importlib.resources
|
|
from pathlib import Path
|
|
|
|
from cryptography.hazmat.primitives.serialization import pkcs12
|
|
from sowai_fiscal.golden_helpers import dados_from_json
|
|
from sowai_fiscal.xml_builder import build_nfe
|
|
|
|
from fiscal_svc.emission.service import _serialize_nfe, sign_nfe_xml
|
|
|
|
REPO_DIR = Path(__file__).resolve().parents[1]
|
|
CERT_PATH = REPO_DIR / "tests" / "fixtures" / "test_cert.pfx"
|
|
CERT_PASSWORD = "test-cert-password" # must match generate_test_cert.py
|
|
OUT_DIR = REPO_DIR / "tests" / "goldens_signed"
|
|
|
|
|
|
def main() -> None:
|
|
if not CERT_PATH.exists():
|
|
raise SystemExit(
|
|
f"{CERT_PATH} não existe -- rode scripts/generate_test_cert.py primeiro"
|
|
)
|
|
pfx_bytes = CERT_PATH.read_bytes()
|
|
private_key, cert, _ca_certs = pkcs12.load_key_and_certificates(
|
|
pfx_bytes, CERT_PASSWORD.encode("utf-8")
|
|
)
|
|
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
|
|
goldens_dir = Path(str(importlib.resources.files("sowai_fiscal") / "goldens"))
|
|
for input_path in sorted(goldens_dir.glob("*.input.json")):
|
|
case = input_path.name.removesuffix(".input.json")
|
|
dados = dados_from_json(input_path)
|
|
nfe = build_nfe(dados)
|
|
xml_str = _serialize_nfe(nfe)
|
|
xml_assinado = sign_nfe_xml(xml_str, dados.chave_acesso, private_key, cert)
|
|
out_path = OUT_DIR / f"{case}.expected.xml"
|
|
out_path.write_text(xml_assinado, encoding="utf-8")
|
|
print(f"wrote {out_path}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|