Perfil del registro de auditoría Docuten eArchiving v1

Docuten eArchiving Audit Register Profile v1

Metadato Valor
Versión / Version 1
Estado / Status Vigente desde la fase 06.3 para todo AIP nuevo
URI del perfil / Profile URI https://docs.docuten.com/earchiving/audit-register-profile/v1
Dónde se declara / Where it is declared Elemento auditRegister/profile de documentation/package-profile.xml (esquema package-profile-v1.xsd) y, como identificadores, los linkingEventIdentifier del objeto de entidad intelectual de metadata/preservation/premis.xml
Implementación / Implementation AuditAppender y AuditEntryHashes (earchiving-auditlog), HashChain y SealEnvelope (earchiving-core/.../core/crypto/), PremisEventPersistenceService (earchiving-ingest), PremisHistoryReaderAdapter (earchiving-app)
Decisiones / Decisions D-14, D-15, D-16 (06.3-CONTEXT.md); D-09 para el orden temporal de los eventos del sello #1
Fecha / Date 2026-10-21

1. Propósito / Purpose

Este documento explica cómo se localiza en el registro de auditoría de Docuten eArchiving la historia de un AIP a partir de identificadores estables que el propio AIP lleva dentro, y cómo se comprueba que esas entradas no han sido alteradas. Es el documento que la URI de la tabla anterior identifica.

La URI es un identificador, no una URL que deba resolverse (D-16). No se dereferencia en tiempo de ingesta, sellado ni verificación.

This document explains how the history of an AIP is located in the Docuten eArchiving audit register from stable identifiers carried inside the AIP itself, and how those entries are checked for alteration. The URI is an identifier, not a URL to be dereferenced (D-16).


2. Qué lleva el AIP / What the AIP carries

En metadata/preservation/premis.xml (generado en el paso 10, antes del sello #2):

En documentation/package-profile.xml, el elemento auditRegister con tres valores: esta URI (profile), el tenantId y el sipId. No lleva la lista de ids de evento, que vive solo en premis.xml (D-15). Los dos identificadores coinciden con los tenant-id y sip-id del IE.

Lo que NO lleva, a propósito: ni el id del sello del lote (sealId) ni un rango de seq. El paquete se sella antes de que exista el sello del lote que contendrá sus eventos, así que esa referencia no se puede conocer en el momento de sellar el AIP (D-14).

The IE in premis.xml carries the aipId, tenant-id and sip-id identifiers and one linkingEventIdentifier per event of steps 1-7, whose values are audit_log.premis_event_id, in audit_log.seq order. The package profile carries a pointer (this URI, tenantId, sipId) without the event list. Neither carries a sealId or a seq range: the package is sealed before the batch seal covering its events exists.


3. Cómo localizar los eventos / How to locate the events

Eventos de la ingesta (pasos 1-11), por tenant + sipId + premis_event_id. PremisEventPersistenceService.persist escribe cada evento PREMIS de la saga en dos sitios:

  1. Una entrada de audit_log con premis_event_id = el eventIdentifierValue del evento y detail_json = el evento serializado.
  2. Una fila de sip_event_index (premis_event_id, sip_id, tenant_id).

Para localizar los eventos se recorren esas dos tablas en ese orden: el índice da los ids del SIP y audit_log da las entradas, ordenadas por seq. Las dos tablas tienen FORCE ROW LEVEL SECURITY por tenant. Así lo hacen:

Los eventos posteriores al paso 7 de la misma ingesta se localizan por el mismo índice del sipId:

Están en audit_log y NO en premis.xml (D-01).

Eventos posteriores ligados al AIP, por aipId. Varias entradas posteriores llevan el aipId dentro de su detail_json y no se indexan por sipId:

Las tres últimas entradas se escriben con deduplicación atómica: una sola por (tenant, acción, aipId) aunque el barrido se repita (un blob que reaparece y vuelve a perderse no emite otra). Su detalle lleva solo las claves aipId, tenantId, kind y rowSubmittedAt, todas en texto.

Hoy no existe un endpoint que filtre por aipId. Estas entradas se leen con GET /api/v1/admin/audit (AuditController, paginado por cursor y filtrable por action) y se seleccionan por el aipId del detalle. El aipId y el sipId están en el IE de premis.xml y en la fila del catálogo (aips.aip_id, aips.sip_id).

Ingestion events (steps 1-11) are indexed per SIP in sip_event_index and read from audit_log in seq order (GET /api/v1/ingest/sip/{sipId}/audit). Later AIP-bound entries carry the aipId in their detail_json (including the inventory-sweep findings AIP_BLOB_MISSING, SIDECAR_MISSING and AIP_BLOB_UNRESOLVED, one entry per tenant, action and aipId) and are read through GET /api/v1/admin/audit; there is no aipId filter today.


4. Cómo verificar la cadena / How to verify the chain

Cadena de entradas (por tenant).

Sellos del lote.

Each entry carries entry_hash = SHA-256(JCS(id, tenantId, seq, timestamp, action, detailJson) || prev_hash), with genesis SHA-256("") per tenant. Batches are sealed over a seven-field envelope (SealEnvelope) whose tree follows merkle-profile-v2.md, chained by prevSealHash. A seal is verified through GET /api/v1/admin/audit/seals/{sealId}/verify; the full-chain verifier (AuditChainVerifier) runs as a scheduled sweep.


5. Propiedades y límites / Properties and limits

Chain order (seq) may differ from eventDateTime order (seal #1 events emitted on a resume; the timestamp event carries the token genTime, D-09). A foreign tenant sees no rows and the history read fails closed. D-16 is an assumption: identifier, not resolvable URL; what Umbus expects is pending.


6. Versionado / Versioning

La v1 es inmutable: todo AIP sellado que la cite la cita para siempre. Cualquier cambio en lo que este documento describe se publica como un perfil nuevo con su propia URI (…/audit-register-profile/v2) y no se edita esta versión.

v1 is immutable; any change is published as v2 under its own URI.