feat: portability safeguards — signed goldens, HTTP contract suite, committed OpenAPI (Task 6)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3aae8b67ef
commit
fb2b8ce372
@@ -0,0 +1,67 @@
|
||||
"""Task 6: one-shot generator for `tests/fixtures/test_cert.pfx` -- a
|
||||
self-signed TEST-ONLY A1 certificate, NEVER a real one (design spec's "os 3
|
||||
seguros de portabilidade", item (b)/(c) extended by the F2 emenda: goldens
|
||||
ASSINADOS need a FIXED test certificate, committed as a binary fixture).
|
||||
|
||||
Re-running this script produces a DIFFERENT RSA key pair (key generation is
|
||||
not seeded) -- that is fine and expected: this is meant to be run ONCE and
|
||||
the output COMMITTED. The determinism `tests/test_signed_goldens.py` relies
|
||||
on comes from every test run reusing the SAME committed `.pfx` file (so the
|
||||
same private key signs the same canonicalized XML the same way every time,
|
||||
RSA PKCS#1v1.5 having no random padding) -- NOT from this generator being
|
||||
reproducible bit-for-bit across runs. Re-run only if the fixture needs to be
|
||||
rotated, and regenerate `tests/goldens_signed/*.expected.xml`
|
||||
(`scripts/generate_signed_goldens.py`) together with it, in the same commit.
|
||||
|
||||
uv run python scripts/generate_test_cert.py
|
||||
"""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.primitives.serialization import pkcs12
|
||||
from cryptography.x509.oid import NameOID
|
||||
|
||||
# Mesmo CNPJ do emitente usado em TODOS os casos golden da lib
|
||||
# (`sowai_fiscal.goldens/*.input.json`) -- ver esse pacote se algum caso
|
||||
# novo usar um CNPJ diferente; este script/fixture precisaria acompanhar.
|
||||
CNPJ = "12345678000190"
|
||||
PASSWORD = "test-cert-password"
|
||||
OUT_PATH = Path(__file__).resolve().parents[1] / "tests" / "fixtures" / "test_cert.pfx"
|
||||
|
||||
|
||||
def main() -> None:
|
||||
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
subject = issuer = x509.Name(
|
||||
[
|
||||
x509.NameAttribute(NameOID.COMMON_NAME, f"AUTOPECAS THIAGO LTDA:{CNPJ}"),
|
||||
x509.NameAttribute(NameOID.SERIAL_NUMBER, CNPJ),
|
||||
]
|
||||
)
|
||||
now = datetime.now(timezone.utc)
|
||||
cert = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(subject)
|
||||
.issuer_name(issuer)
|
||||
.public_key(key.public_key())
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(now - timedelta(days=1))
|
||||
.not_valid_after(now + timedelta(days=3650))
|
||||
.sign(key, hashes.SHA256())
|
||||
)
|
||||
pfx_bytes = pkcs12.serialize_key_and_certificates(
|
||||
name=b"sowai-fiscal-svc-test",
|
||||
key=key,
|
||||
cert=cert,
|
||||
cas=None,
|
||||
encryption_algorithm=serialization.BestAvailableEncryption(PASSWORD.encode("utf-8")),
|
||||
)
|
||||
OUT_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUT_PATH.write_bytes(pfx_bytes)
|
||||
print(f"wrote {OUT_PATH} (cnpj={CNPJ}, password={PASSWORD!r})")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user