oc_chat
Loading...
Searching...
No Matches
events_writer.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# oc_chat/registry/auth/events_writer.py
4
5# OCT-LINT: disable=tests_exist reason="Covered by oc_chat/tests/registry/test_auth_signing.py"
6"""
7Dedicated auth-event writer.
8
9Purpose
10-------
11Record failed HMAC verification attempts in a short transaction that is
12separate from the main registry mutation.
13
14Responsibilities
15----------------
16- Insert one ``auth_events`` row for each failed verification.
17- Keep failure writes out of ``operation_log``.
18- Avoid exposing secret material in diagnostics.
19
20Diagnostics
21-----------
22Domain: OC_CHAT.MAIN
23Levels:
24 L2 - lifecycle events
25 L3 - semantic details
26 L4 - deep tracing
27
28Contracts
29---------
30- The caller has not opened the mutating registry transaction yet.
31- ``failure_reason`` is one of the schema-enumerated values.
32
33Dependencies
34------------
35- oc_chat.registry.backends.sqlite (SQLite backend whose dedicated transaction records the failure row)
36- oc_chat.registry.auth.signing (payload digest stored with each failure)
37- oc_diagnostics (structured debug logging via _dbg)
38"""
39from __future__ import annotations
40
41from typing import Mapping
42
43from oc_diagnostics import _dbg
44
45from oc_chat.registry.auth.signing import payload_sha256
46from oc_chat.registry.backends.sqlite import SQLiteBackend
47
48
49_dbg("OC_CHAT.MAIN", "module", "loaded", 4)
50
51
53 """Write failed-auth rows through a dedicated transaction."""
54
55 def __init__(self, backend: SQLiteBackend) -> None:
56 self.backend = backend
57
59 self,
60 *,
61 attempted_slot: str | None,
62 hmac_key_id: str | None,
63 command: str,
64 payload: Mapping[str, object],
65 failure_reason: str,
66 remote_hint: str | None = None,
67 ) -> int:
68 """Insert one failed-auth row and return its row id."""
69
70 digest = payload_sha256(payload)
71 with self.backend.transaction("immediate") as conn:
72 cursor = conn.execute(
73 # OCT-LINT: disable=no_hardcoded_secrets reason="Auth event field names are schema identifiers"
74 "INSERT INTO auth_events("
75 "ts, attempted_slot, hmac_key_id, command, payload_sha256, "
76 "auth_ok, failure_reason, remote_hint"
77 ") VALUES (?, ?, ?, ?, ?, 0, ?, ?)",
78 (
79 self.backend.clock.now_wall(),
80 attempted_slot,
81 hmac_key_id,
82 command,
83 digest,
84 failure_reason,
85 remote_hint,
86 ),
87 )
88 return int(cursor.lastrowid)
int write_failure(self, *, str|None attempted_slot, str|None hmac_key_id, str command, Mapping[str, object] payload, str failure_reason, str|None remote_hint=None)