Ë
    ÛJêj.Q  ã                  ó  — d Z ddlmZ ddlZddlZddlZddlmZmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZmZmZmZmZ  G d	„ d
ee
«      Z G d„ dee
«      Ze G d„ d«      «       Ze G d„ d«      «       Z G d„ d«      Zg d¢Zy)aŽ  Audit - security audit logging and evidence tracking.

Audit tracks security-relevant events across the system:
- user, agent, task, model, tool, action
- policy decision, approval, result, error
- resource usage, latency, network action
- memory write, security alert

**What "immutable" means here, precisely.** Records are hash-chained: each one
carries the digest of its predecessor, so an in-place edit, a deletion, a
reordering, or a truncation of the beginning is detected and localised by
:func:`~cyberbrain26.security_plane.audit.chain.verify_chain`.

The chain does **not** make the log impossible to alter. The digest is plain
SHA-256 with no secret, so an adversary holding write access to the database can
rewrite the log and recompute every link, presenting a chain that verifies
perfectly; deleting the end of the chain has the same effect. That is a residual
risk tracked in the plan's F6 section, not an oversight.

This is also why :meth:`AuditLog.clear` and :meth:`AuditLog.prune_expired` exist
and why they are not silent: they are the operations a chain alone cannot make
safe, so they mark what they did instead of pretending they did nothing.
é    )ÚannotationsN)Ú	dataclassÚfield)ÚEnum)ÚAny)ÚSQLiteDatabase)ÚGENESISÚTamperClassÚVerificationReportÚcompute_event_hashÚverify_chainc                  óp   — e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZy)ÚAuditEventTypezTypes of audit events.Úuser_actionÚagent_startedÚagent_finishedÚtask_createdÚtask_startedÚtask_finishedÚtool_calledÚtool_resultÚmodel_discoveredÚmodel_validatedÚmodel_failedÚpolicy_decisionÚapproval_requiredÚapproval_grantedÚapproval_deniedÚsecurity_alertÚresource_limitÚmemory_updatedÚidentity_checkÚpermission_checkÚfirewall_checkÚdata_accessÚconfig_changeÚerrorN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚUSER_ACTIONÚAGENT_STARTEDÚAGENT_FINISHEDÚTASK_CREATEDÚTASK_STARTEDÚTASK_FINISHEDÚTOOL_CALLEDÚTOOL_RESULTÚMODEL_DISCOVEREDÚMODEL_VALIDATEDÚMODEL_FAILEDÚPOLICY_DECISIONÚAPPROVAL_REQUIREDÚAPPROVAL_GRANTEDÚAPPROVAL_DENIEDÚSECURITY_ALERTÚRESOURCE_LIMITÚMEMORY_UPDATEDÚIDENTITY_CHECKÚPERMISSION_CHECKÚFIREWALL_CHECKÚDATA_ACCESSÚCONFIG_CHANGEÚERROR© ó    úP/home/oem/CyberBrain26-unified/src/cyberbrain26/security_plane/audit/__init__.pyr   r   ,   s�   „ Ù à€KØ#€MØ%€NØ!€LØ!€LØ#€MØ€KØ€KØ)ÐØ'€OØ!€LØ'€OØ+ÐØ)ÐØ'€OØ%€NØ%€NØ%€NØ%€NØ)ÐØ%€NØ€KØ#€MØ�ErE   r   c                  ó   — e Zd ZdZdZdZdZy)ÚAuditEventStatuszStatus of an audit event.ÚrecordedÚ
correlatedÚarchivedN)r(   r)   r*   r+   ÚRECORDEDÚ
CORRELATEDÚARCHIVEDrD   rE   rF   rH   rH   I   s   „ Ù#à€HØ€JØ�HrE   rH   c                  ó\  — e Zd ZU dZded<   ded<   ded<   dZded	<   dZded
<   dZded<   dZded<   dZ	ded<   dZ
ded<   dZded<   dZded<   dZded<   dZded<   dZded<    ee¬«      Zded<   dZded<   dZded<   dZded<   dZded<    ee¬«      Zded<   ej2                  Zded<   y) Ú
AuditEventzA single audit event.ÚstrÚevent_idr   Ú
event_typeÚfloatÚ	timestampÚ ÚactorÚagent_idÚtask_idÚmodelÚtoolÚactionÚresourcer   Úapproval_idÚresultr'   )Údefault_factoryúdict[str, Any]Úresource_usageç        Ú
latency_msÚnetwork_actionÚmemory_writer   ÚmetadatarH   ÚstatusN)r(   r)   r*   r+   Ú__annotations__rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   r   Údictrb   rd   re   rf   r   rg   rH   rL   rh   rD   rE   rF   rP   rP   Q   s×   … áàƒMØÓØÓØ€Eˆ3ƒOØ€HˆcÓØ€GˆSÓØ€Eˆ3ƒOØ€Dˆ#ƒNØ€FˆCÓØ€HˆcÓØ€O�SÓØ€K�ÓØ€FˆCÓØ€Eˆ3ƒOÙ%*¸4Ô%@€N�NÓ@Ø€J�ÓØ€N�CÓØ€L�#ÓØ€N�CÓÙ$°TÔ:€HˆnÓ:Ø/×8Ñ8€FÐÔ8rE   rP   c                  ó�   — e Zd ZU dZdZded<   dZded<   dZded<   dZded<   dZ	ded	<   dZ
ded
<   dZded<   dZded<   dZded<   y)Ú
AuditQueryz,Query parameters for filtering audit events.NzAuditEventType | NonerS   z
str | NonerW   rX   rY   r\   r]   úfloat | NoneÚsinceÚuntiléd   ÚintÚlimit)r(   r)   r*   r+   rS   ri   rW   rX   rY   r\   r]   rn   ro   rr   rD   rE   rF   rl   rl   l   s`   … á6à(,€JÐ%Ó,Ø€Eˆ:ÓØ€HˆjÓØ€GˆZÓØ€FˆJÓØ€HˆjÓØ€Eˆ<ÓØ€Eˆ<ÓØ€Eˆ3ÔrE   rl   c                  ó  — e Zd ZdZddd„Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zedd„«       Zdd„Zddd„Z	dd„Z
dd	„Zddd
„Zdd„Zdd„Zd d„Zddœd!d„Zd"d„Zdd„Zed#d„«       Zy)$ÚAuditLogam  Append-only, hash-chained audit log for security events.

    Events are written to `audit_events` and kept in an in-memory list. Each
    record commits to its predecessor's digest via ``seq``, ``prev_hash`` and
    ``entry_hash`` (computed with ``compute_event_hash`` from
    ``cyberbrain26.security_plane.audit.chain``), so corruption, deletion,
    reordering and prefix truncation are all detectable and localisable. The
    chain is tamper-evident, not tamper-proof: an attacker with write access
    can rewrite the log and recompute any digest without the HMAC key
    (``CYBERBRAIN_CHAIN_KEY``).

    `clear()` and `prune_expired()` both DELETE rows; the docstring on each
    method states this explicitly rather than pretending the log is immutable.

    Usage:
        audit = AuditLog()
        audit.record(AuditEventType.SECURITY_ALERT, agent_id="agent-1",
                      security_alert="suspicious activity detected")
        events = audit.query(agent_id="agent-1")

        report = audit.verify_chain()
        if not report.intact:
            ...

    **Single writer.** The head digest is read and the new link appended within
    one transaction, so concurrent writers cannot fork the chain. Two
    ``AuditLog`` instances writing to the same database in the same process
    would not be safe; that is a precondition, not something this class enforces.
    Nc                ód   — || _         g | _        | j                   �| j                  «       | _        y y ©N)ÚdatabaseÚ_eventsÚ_load_persisted)Úselfrw   s     rF   Ú__init__zAuditLog.__init__š   s/   € Ø ˆŒØ)+ˆŒØ�=‰=Ð$Ø×/Ñ/Ó1ˆD�Lð %rE   c                óP  — t        d i ddt        j                  «       j                  dd › �“d|“dt	        j                  «       “d|“d|“d	|“d
|“d|“d|“d|“d|	“d|
“d|“d|“d|xs i “d|“d|“d|“d|“d|xs i “Ž}| j
                  €| j                  j                  |«       |S | j                  |«      }| j
                  j                  «       5 }|j                  d«      j                  «       }|€dt        }}d}n|d   }|d   }t        |«      dz   }||d<   ||d<   t        ||«      |d<   |j                  d|j                  |j                   j"                  |j$                  |j&                  |j(                  |j*                  |j,                  |j.                  |j0                  |j2                  |j4                  |j6                  |j8                  |j:                  t=        j>                  |j@                  d¬«      |jB                  |jD                  |jF                  |jH                  t=        j>                  |jJ                  d¬«      |jL                  j"                  |d   |d   |d   f«       ddd«       | j                  j                  |«       |S # 1 sw Y   Œ&xY w)!a…  Record a new audit event, linked to the current head of the chain.

        The head digest is read and the new link appended inside one transaction,
        so two writers cannot both claim the same predecessor. Every field that
        goes into the digest is the same value that is persisted, which is what
        lets a verifier recompute the chain from the stored row alone.
        rR   Úaudit_Né   rS   rU   rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   rb   rd   re   rf   r   rg   z_SELECT seq, entry_hash FROM audit_events WHERE entry_hash IS NOT NULL ORDER BY seq DESC LIMIT 1é   ÚseqÚ
entry_hashÚ	prev_hasha	  
                INSERT INTO audit_events(
                    event_id, event_type, timestamp, actor, agent_id, task_id,
                    model, tool, action, resource, policy_decision, approval_id,
                    result, error, resource_usage_json, latency_ms, network_action,
                    memory_write, security_alert, metadata_json, status,
                    seq, prev_hash, entry_hash
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                ©ú,ú:©Ú
separatorsrD   )'rP   ÚuuidÚuuid4ÚhexÚtimerw   rx   ÚappendÚ_chain_fieldsÚtransactionÚexecuteÚfetchoner	   rq   r   rR   rS   ÚvaluerU   rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   ÚjsonÚdumpsrb   rd   re   rf   r   rg   rh   )rz   rS   rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   rb   rd   re   rf   r   rg   ÚeventÚrowÚ
connectionÚheadÚprevious_seqr‚   Únext_seqs                             rF   ÚrecordzAuditLog.record    sè  € ô8 ò 
ØœdŸj™j›l×.Ñ.¨s°Ð3Ð4Ñ5ð
á!ð
ô —i‘i”kð
ñ ð	
ñ
 ð
ñ ð
ñ ð
ñ ð
ñ ð
ñ ð
ñ ,ð
ñ $ð
ñ ð
ñ ð
ð *Ò/¨Røð
ñ  "ð!
ñ" *ð#
ñ$ &ð%
ñ& *ð'
ð( ’^ øð)
ˆð. �=‰=Ð ð �L‰L×Ñ Ô&ØˆLà× Ñ  Ó'ˆà�]‰]×&Ñ&Ó(ð 5	¨JØ×%Ñ%ðIó÷ ‰h‹jð ð ˆ|Ø*.´˜i�Ø‘à# E™{�Ø  Ñ.�	Ü˜|Ó,¨qÑ0�à!ˆC�‰JØ(ˆC�ÑÜ 2°3¸	Ó BˆC�Ñà×Ñðð —N‘NØ×$Ñ$×*Ñ*Ø—O‘OØ—K‘KØ—N‘NØ—M‘MØ—K‘KØ—J‘JØ—L‘LØ—N‘NØ×)Ñ)Ø×%Ñ%Ø—L‘LØ—K‘KÜ—J‘J˜u×3Ñ3À
ÔKØ×$Ñ$Ø×(Ñ(Ø×&Ñ&Ø×(Ñ(Ü—J‘J˜uŸ~™~¸*ÔEØ—L‘L×&Ñ&Ø˜‘JØ˜Ñ$Ø˜Ñ%ð1ô$÷#5	ðn 	�‰×Ñ˜EÔ"Øˆ÷q5	ð 5	ús   ÃF!JÊJ%c                óš  — i d| j                   “d| j                  j                  “d| j                  “d| j                  “d| j
                  “d| j                  “d| j                  “d| j                  “d	| j                  “d
| j                  “d| j                  “d| j                  “d| j                  “d| j                  “dt        j                   | j"                  d¬«      “d| j$                  “d| j&                  “| j(                  | j*                  t        j                   | j,                  d¬«      | j.                  j                  dœ¥S )zëThe record as the chain sees it: every column, JSON columns flattened.

        The digest must be computable from the stored row alone, so nested
        structures are encoded exactly as ``_load_persisted`` will decode them.
        rR   rS   rU   rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   Úresource_usage_jsonrƒ   r†   rd   re   )rf   r   Úmetadata_jsonrh   )rR   rS   r‘   rU   rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   r’   r“   rb   rd   re   rf   r   rg   rh   )r”   s    rF   r�   zAuditLog._chain_fields  sp  € ð
Ø˜Ÿ™ð
à˜%×*Ñ*×0Ñ0ð
ð ˜Ÿ™ð
ð �U—[‘[ð	
ð
 ˜Ÿ™ð
ð �u—}‘}ð
ð �U—[‘[ð
ð �E—J‘Jð
ð �e—l‘lð
ð ˜Ÿ™ð
ð ˜u×4Ñ4ð
ð ˜5×,Ñ,ð
ð �e—l‘lð
ð �U—[‘[ð
ð "¤4§:¡:Ø×$Ñ$°ô$ð
ð$ ˜%×*Ñ*ð%
ð& ˜e×2Ñ2ð'
ð( "×.Ñ.Ø#×2Ñ2Ü!ŸZ™Z¨¯©À:ÔNØ—l‘l×(Ñ(ò/
ð 	
rE   c                ól   — | j                  «        | j                  D ]  }|j                  |k(  sŒ|c S  y)zRetrieve an event by its ID.N)Ú_refresh_persistedrx   rR   )rz   rR   r”   s      rF   ÚgetzAuditLog.get6  s7   € à×ÑÔ!Ø—\‘\ò 	ˆEØ�~‰~ Ó)Ø’ð	ð rE   c                ó4  — | j                  «        |xs
 t        «       }g }| j                  D �]F  }|j                  �|j                  |j                  k7  rŒ*|j                  �|j                  |j                  k7  rŒP|j
                  �|j
                  |j
                  k7  rŒv|j                  �|j                  |j                  k7  rŒœ|j                  �|j                  |j                  k7  rŒÂ|j                  �|j                  |j                  k7  rŒè|j                  �|j                  |j                  k  r�Œ|j                  �|j                  |j                  kD  r�Œ6|j                  |«       �ŒI |j                  d„ d¬«       |d|j                   S )z™Query events with optional filters.

        Returns events matching all specified criteria,
        most recent first, limited by params.limit.
        Nc                ó   — | j                   S rv   ©rU   ©Úes    rF   ú<lambda>z AuditLog.query.<locals>.<lambda>\  s
   €  1§;¡;€ rE   T©ÚkeyÚreverse)rŸ   rl   rx   rS   rW   rX   rY   r\   r]   rn   rU   ro   rŒ   Úsortrr   )rz   ÚparamsÚresultsr”   s       rF   ÚqueryzAuditLog.query>  sJ  € ð 	×ÑÔ!ØÒ'œ:›<ˆØ$&ˆà—\‘\ó 	"ˆEØ× Ñ Ð,°×1AÑ1AÀV×EVÑEVÒ1VØØ�|‰|Ð'¨E¯K©K¸6¿<¹<Ò,GØØ�‰Ð*¨u¯~©~ÀÇÁÒ/PØØ�~‰~Ð)¨e¯m©m¸v¿~¹~Ò.MØØ�}‰}Ð(¨U¯\©\¸V¿]¹]Ò-JØØ�‰Ð*¨u¯~©~ÀÇÁÒ/PØØ�|‰|Ð'¨E¯O©O¸f¿l¹lÒ,JÙØ�|‰|Ð'¨E¯O©O¸f¿l¹lÒ,JÙà�N‰N˜5Ö!ð%	"ð( 	�‰Ñ.¸ˆÔ=Ø�~˜Ÿ™Ð&Ð&rE   c                óL   — | j                  «        t        | j                  «      S )z Total number of recorded events.)rŸ   Úlenrx   ©rz   s    rF   ÚcountzAuditLog.count_  s   € à×ÑÔ!Ü�4—<‘<Ó Ð rE   c                ó`   ‡— | j                  «        t        ˆfd„| j                  D «       «      S )z Count events of a specific type.c              3  óB   •K  — | ]  }|j                   ‰k(  sŒd –— Œ y­w)r   N)rS   )Ú.0r¥   rS   s     €rF   ú	<genexpr>z)AuditLog.count_by_type.<locals>.<genexpr>g  s   øè ø€ ÒI˜¨a¯l©l¸jÓ.H”1ÑIùs   ƒ˜)rŸ   Úsumrx   )rz   rS   s    `rF   Úcount_by_typezAuditLog.count_by_typed  s$   ø€ à×ÑÔ!ÜÓI˜dŸl™lÔIÓIÐIrE   c                ó^   — | j                  «        t        | j                  d„ d¬«      }|d| S )z#List all events, most recent first.c                ó   — | j                   S rv   r£   r¤   s    rF   r¦   z#AuditLog.list_all.<locals>.<lambda>l  s
   € °A·K±K€ rE   Tr§   N)rŸ   Úsortedrx   )rz   rr   Úeventss      rF   Úlist_allzAuditLog.list_alli  s-   € à×ÑÔ!Ü˜Ÿ™Ñ*?ÈÔNˆØ�f�uˆ~ÐrE   c                óÒ   — | j                   j                  «        | j                  �5| j                  j                  «       5 }|j	                  d«       ddd«       yy# 1 sw Y   yxY w)az  Delete every event. NOT a chain operation - it severs the chain.

        This exists for tests and fixtures. Calling it on a live log destroys
        the evidence a chain exists to protect, and no chain can report that,
        because there is nothing left to verify. That is the honest limitation,
        and it is why this method is not silent about what it does.
        NzDELETE FROM audit_events)rx   Úclearrw   rŽ   r�   )rz   r–   s     rF   r¾   zAuditLog.clearo  s^   € ð 	�‰×ÑÔØ�=‰=Ð$Ø—‘×*Ñ*Ó,ð ?°
Ø×"Ñ"Ð#=Ô>÷?ð ?ð %÷?ð ?ús   ÁAÁA&c                ó„  — | j                   €g S | j                   j                  «       5 }|j                  d«      j                  «       d   }|r |j                  d«      j	                  «       }n|j                  d«      j	                  «       }ddd«       g }D ]˜  }|j                  i d|d   “d|d   “d|d   “d	|d	   “d
|d
   “d|d   “d|d   “d|d   “d|d   “d|d   “d|d   “d|d   “d|d   “d|d   “d|d   “d|d   “d|d   “|d   |d   |d   |d   |d   |d   |d   dœ¥«       Œš |S # 1 sw Y   ŒªxY w)aH  Return persisted records in chain order, shaped as the chain sees them.

        Ordered by ``seq`` when a chain exists, and by timestamp otherwise, so a
        pre-chain (epoch 0) log still verifies as a declared boundary instead of
        as a broken link.

        Two literal queries rather than one interpolated ``ORDER BY``: an
        f-string in SQL is not injectable here (the clause is a fixed literal),
        but it reads as if it were, and the next person to "fix" that reading
        would introduce the hole. Interpolation is avoided for that reason alone.
        Nz<SELECT COUNT(*) AS n FROM audit_events WHERE seq IS NOT NULLÚnz+SELECT * FROM audit_events ORDER BY seq ASCz<SELECT * FROM audit_events ORDER BY timestamp ASC, rowid ASCrR   rS   rU   rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   rœ   rd   re   rf   r   r�   rh   r€   r‚   r�   )rf   r   r�   rh   r€   r‚   r�   )rw   r–   r�   r�   ÚfetchallrŒ   )rz   r–   Úhas_seqÚrowsÚshapedr•   s         rF   Ú
chain_rowszAuditLog.chain_rows|  s  € ð �=‰=Ð ØˆIØ�]‰]×%Ñ%Ó'ð 	¨:Ø ×(Ñ(ØNóç‰h‹j˜ñˆGñ Ø!×)Ñ)ØAóç‘(“*ñ ð "×)Ñ)ØRóç‘(“*ð ÷	ð (*ˆØò 	ˆCØ�M‰MðØ  J¡ðà  # lÑ"3ðð    [Ñ!1ðð ˜S ™\ð	ð
   J¡ðð ˜s 9™~ðð ˜S ™\ðð ˜C ™Kðð ˜c (™mðð   J¡ðð & sÐ+<Ñ'=ðð " 3 }Ñ#5ðð ˜c (™mðð ˜S ™\ðð *¨3Ð/DÑ+Eðð  ! # lÑ"3ð!ð" % cÐ*:Ñ&;ð#ð$ %(¨Ñ$7Ø&)Ð*:Ñ&;Ø%(¨Ñ%9Ø! (™mØ˜u™:Ø!$ [Ñ!1Ø"% lÑ"3ò1õð	ð: ˆ÷U	ð 	ús   ©A$D6Ä6D?c                ó4   — t        | j                  «       «      S )ao  Verify the persisted chain and report what, if anything, is wrong.

        Reports ``linkage_ok`` and ``integrity_ok`` separately - collapsing them
        hides which attack occurred. A log written before the chain existed
        returns ``unverified_premise=True`` and ``intact=False``: "never chained"
        is a declared boundary, never a clean pass.
        )r   rÅ   r°   s    rF   r   zAuditLog.verify_chain¶  s   € ô ˜DŸO™OÓ-Ó.Ð.rE   ©Únowc               óŒ  — | j                   €y|€t        j                  «       }|| j                   j                  dz  dz  dz  z
  }| j                   j                  |«      }|dk(  ry| j	                  «       }| j                   j                  |¬«      d   }| j                  t        j                  dd|j                  rdnd	d
|› d|d›d|j                  › d|j                  › d|j                  j                  › �
|||j                  |j                  |j                  j                  dœ¬«       | j                  «       | _        |S )aß  Apply retention, marking the range if it was purged over an open break.

        Retention is a deadline, so it is not refused when the chain is already
        broken. But it is never bridged silently, because a silent bridge turns a
        loud finding into a green verdict. When the chain is intact the purge is
        clean. When it is broken, this records a chained event naming the purged
        range and the reason, so the fact outlives the rows it describes.
        r   é   é<   rÇ   Úaudit_eventszaudit.retentionÚchain_range_purgedÚpurgedÚpurged_over_unexplained_breakzretention removed z audit record(s) older than z.0fz; chain_intact_before_purge=z; first_broken_seq=z; tamper_class=)ÚcutoffÚdeletedÚchain_intact_before_purgeÚfirst_broken_seqÚtamper_class)rW   r\   r_   r   rg   )rw   r‹   Úretention_daysÚcount_audit_beforer   Úprune_expiredrš   r   r;   ÚintactrÓ   rÔ   r‘   ry   rx   )rz   rÈ   rÐ   Ú
rows_goingÚbeforerÑ   s         rF   r×   zAuditLog.prune_expiredÀ  sL  € ð �=‰=Ð ØØˆ;Ü—)‘)“+ˆCØ�t—}‘}×3Ñ3°bÑ8¸2Ñ=ÀÑBÑBˆà—]‘]×5Ñ5°fÓ=ˆ
Ø˜Š?Øð ×"Ñ"Ó$ˆà—-‘-×-Ñ-°#Ð-Ó6°~ÑFˆð 	�‰Ü×)Ñ)Ø#Ø'Ø%Ÿ}š}‘8Ð2Qà$ W IÐ-IÈ&ÐQTÈð V-Ø-3¯]©]¨Oð <$Ø$*×$;Ñ$;Ð#<ð = Ø &× 3Ñ 3× 9Ñ 9Ð:ð<ð !Ø"Ø-3¯]©]Ø$*×$;Ñ$;Ø &× 3Ñ 3× 9Ñ 9ñð 	ô 	
ð( ×+Ñ+Ó-ˆŒØˆrE   c                ó  — | j                   €J ‚| j                   j                  «       5 }|j                  d«      j                  «       }d d d «       D �cg c]  }| j	                  |«      ‘Œ c}S # 1 sw Y   Œ(xY wc c}w )Nz1SELECT * FROM audit_events ORDER BY timestamp ASC)rw   r–   r�   rÁ   Ú_row_to_event)rz   r–   rÃ   r•   s       rF   ry   zAuditLog._load_persistedñ  sx   € Ø�}‰}Ð(Ð(Ð(Ø�]‰]×%Ñ%Ó'ð 	¨:Ø×%Ñ%ØCóç‰h‹jð ÷	ð 48Ö8¨C�×"Ñ" 3Õ'Ò8Ð8÷		ð 	üò 9s   © A0ÁA<Á0A9c                óH   — | j                   �| j                  «       | _        y y rv   )rw   ry   rx   r°   s    rF   rŸ   zAuditLog._refresh_persistedù  s!   € Ø�=‰=Ð$Ø×/Ñ/Ó1ˆD�Lð %rE   c           	     ó€  — t        di d| d   “dt        | d   «      “d| d   “d| d   “d| d   “d| d   “d| d   “d| d   “d	| d	   “d
| d
   “d| d   “d| d   “d| d   “d| d   “dt        j                  | d   «      “d| d   “d| d   “d| d   “d| d   “dt        j                  | d   «      “dt	        | d   «      “ŽS )NrR   rS   rU   rW   rX   rY   rZ   r[   r\   r]   r   r^   r_   r'   rb   rœ   rd   re   rf   r   rg   r�   rh   rD   )rP   r   r’   ÚloadsrH   )r•   s    rF   rÜ   zAuditLog._row_to_eventý  s[  € äò 
Ø˜’_ð
ä% c¨,Ñ&7Ô8ð
ð ˜+Ò&ð
ð �g’,ð	
ð
 ˜’_ð
ð ˜	’Nð
ð �g’,ð
ð �V’ð
ð �x’=ð
ð ˜’_ð
ð  Ð 1Ò2ð
ð ˜MÒ*ð
ð �x’=ð
ð �g’,ð
ô  Ÿ:™: cÐ*?Ñ&@ÔAð
ð  ˜<Ò(ð!
ð" Ð/Ò0ð#
ð$ ˜^Ò,ð%
ð& Ð/Ò0ð'
ô( —Z‘Z  OÑ 4Ô5ð)
ô* $ C¨¡MÔ2ð+
ð 	
rE   rv   )rw   zSQLiteDatabase | NoneÚreturnÚNone)rV   rV   rV   rV   rV   rV   rV   rV   rV   rV   rV   Nrc   rV   rV   rV   N)&rS   r   rW   rQ   rX   rQ   rY   rQ   rZ   rQ   r[   rQ   r\   rQ   r]   rQ   r   rQ   r^   rQ   r_   rQ   r'   rQ   rb   údict[str, Any] | Nonerd   rT   re   rQ   rf   rQ   r   rQ   rg   râ   rà   rP   )r”   rP   rà   ra   )rR   rQ   rà   zAuditEvent | None)r«   zAuditQuery | Nonerà   úlist[AuditEvent])rà   rq   )rS   r   rà   rq   )rp   )rr   rq   rà   rã   )rà   rá   )rà   zlist[dict[str, Any]])rà   r   )rÈ   rm   rà   rq   )rà   rã   )r•   r   rà   rP   )r(   r)   r*   r+   r{   rš   Ústaticmethodr�   r    r­   r±   r·   r¼   r¾   rÅ   r   r×   ry   rŸ   rÜ   rD   rE   rF   rt   rt   {   s€  „ ñô<2ð ØØØØØØØ!ØØØØ04ØØ ØØ Ø*.ð'sà"ðsð ðsð ð	sð
 ðsð ðsð ðsð ðsð ðsð ðsð ðsð ðsð ðsð .ðsð ðsð  ð!sð" ð#sð$ ð%sð& (ð'sð( 
ó)sðj ò
ó ð
ó@ô'óB!ó
Jô
ó?ó8ót/ð 48õ /ób9ó2ð ò
ó ñ
rE   rt   )r	   rP   rH   r   rt   rl   r
   r   )r+   Ú
__future__r   r’   r‹   rˆ   Údataclassesr   r   Úenumr   Útypingr   Ú$cyberbrain26.data_plane.sqlite_storer   Ú'cyberbrain26.security_plane.audit.chainr	   r
   r   r   r   rQ   r   rH   rP   rl   rt   Ú__all__rD   rE   rF   ú<module>rì      s�   ðñõ0 #ã Û Û ß (Ý Ý å ?÷õ ô�S˜$ô ô:�s˜Dô ð ÷9ð 9ó ð9ð4 ÷ð ó ð÷Z
ñ Z
òz	�rE   