chore(v2): lint pass — black + ruff auto-fix + mypy regressions (#29 v1.1)

Pre-merge lint hygiene on the PR #30 touched files:

- `black` reformatted 9 files (cassette_transport, crud, models, tasks,
  views_api, nip44, all 3 cassette test files, migrations). Cosmetic:
  line lengths, trailing commas, multi-line argument layout.
- `ruff check --fix` cleared 176 of 202 errors auto-fixed. Mostly
  `UP006` `typing.Optional` → `| None` modernization, `I001` import
  sort order, `UP035` typing-extensions cleanup.
- Two new mypy regressions introduced by the migration commit dcb7de0
  fixed:
  - `crud.py:apply_bootstrap_state` — annotated `existing_first: dict
    | None` on the dedup fetch.
  - `tasks.py:_cassette_consumer_tick` — `# type: ignore[arg-type]` on
    the `nostr_client.relay_manager.add_subscription` call; nostrclient's
    upstream typing declares `list[str]` for filters but the actual
    Nostr protocol takes `list[<filter-dict>]`. The runtime accepts it
    (live smoke at 13:43Z dispatched `nip44_decrypt` cleanly through
    this subscription); the typing mismatch is upstream's.

Remaining lint state, intentionally not addressed in this commit
(all pre-existing baseline, not regressions):
- 8 mypy errors in `calculations.py` + the unchanged-by-this-PR parts
  of `crud.py` — pre-existing on v2-bitspire.
- 26 ruff style warnings: 14 are N805 false-positives on Pydantic
  validators (`cls` first-arg is correct for `@validator`-decorated
  methods); 4 are N818 exception-name-suffix preferences on my new
  exception classes (renaming would touch many call sites; keep
  `OperatorIdentityMissing` / `SignerUnavailable` / `RelayUnavailable`
  / `_NostrclientUnavailable` as-is for clarity); 5 are E501 line-too-
  long on docstrings (the long lines are formatted for clarity);
  1 RUF002 unicode-minus in a docstring.

Tests: 155 passed, 1 pre-existing async-plugin failure unchanged.
Live smoke (both publish + consume directions through the bunker)
unaffected — this is purely a code-style pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-31 15:50:14 +02:00
commit d448fab0d2
10 changed files with 249 additions and 352 deletions

View file

@ -57,7 +57,6 @@ import hashlib
import hmac as hmac_stdlib
import os
import struct
from typing import Optional
import coincurve
from cryptography.hazmat.primitives import hashes, hmac
@ -71,7 +70,9 @@ _MIN_PLAINTEXT_LEN = 1
_MAX_PLAINTEXT_LEN = 65535
_NONCE_LEN = 32
_MAC_LEN = 32
_MIN_PAYLOAD_LEN = 1 + _NONCE_LEN + (2 + 32) + _MAC_LEN # version + nonce + min padded + mac
_MIN_PAYLOAD_LEN = (
1 + _NONCE_LEN + (2 + 32) + _MAC_LEN
) # version + nonce + min padded + mac
_MAX_PAYLOAD_LEN = 1 + _NONCE_LEN + (2 + 65536) + _MAC_LEN
@ -98,8 +99,8 @@ class Nip44LengthError(Nip44Error):
def _calc_padded_len(plaintext_len: int) -> int:
"""Per NIP-44 v2 padding scheme:
if L <= 32: padded_len = 32
else: chunk = max(32, next_power_2(L-1) // 8); padded_len = chunk * ((L-1) // chunk + 1)
if L <= 32: padded_len = 32
else: chunk = max(32, next_power_2(L-1) // 8); padded_len = chunk * ((L-1) // chunk + 1)
"""
if plaintext_len <= 32:
return 32
@ -205,7 +206,7 @@ def encrypt_with_conversation_key(
plaintext: str,
conversation_key: bytes,
*,
nonce: Optional[bytes] = None,
nonce: bytes | None = None,
) -> str:
"""Encrypt `plaintext` under a precomputed `conversation_key` (32B PRK).
@ -224,9 +225,9 @@ def encrypt_with_conversation_key(
chacha_key, chacha_nonce, hmac_key = _derive_message_keys(conversation_key, nonce)
ciphertext = _chacha20(chacha_key, chacha_nonce, padded)
mac = _hmac_aad(hmac_key, nonce, ciphertext)
return base64.b64encode(
bytes([_VERSION]) + nonce + ciphertext + mac
).decode("ascii")
return base64.b64encode(bytes([_VERSION]) + nonce + ciphertext + mac).decode(
"ascii"
)
def decrypt_with_conversation_key(payload_b64: str, conversation_key: bytes) -> str:
@ -239,7 +240,9 @@ def decrypt_with_conversation_key(payload_b64: str, conversation_key: bytes) ->
"""
try:
raw = base64.b64decode(payload_b64, validate=True)
except Exception as exc: # noqa: BLE001 — we want any base64 failure surfaced uniformly
except (
Exception
) as exc:
raise Nip44LengthError(f"payload is not valid base64: {exc}") from exc
if len(raw) < _MIN_PAYLOAD_LEN or len(raw) > _MAX_PAYLOAD_LEN:
@ -272,7 +275,7 @@ def encrypt_for(
sender_privkey_hex: str,
recipient_pubkey_hex: str,
*,
nonce: Optional[bytes] = None,
nonce: bytes | None = None,
) -> str:
"""Encrypt `plaintext` from the sender (holding the privkey) to the recipient
(identified by pubkey). The recipient can decrypt with `decrypt_from(