archive: Auftragstabelle statt Marker, exklusiver Abschluss, Quarantäne, Restore über Payload-Identität und signierte Exporte, Schlüsselrotation (Umsetzungsaudit 29.09.: A-01 bis A-15, OPT-6, 5.1 d; 02.10.: O04, O05, O07, O08)
- A-01/A-02/A-04: archive_pending_jobs je Vorgang (ArchivePendingQueue), Depublikationsstand am Auftrag festgehalten, Nachholer ohne Schlüssel FAILURE; archive_pending_at nur noch Sammelmarker - O07: Direktweg und Nachholer beanspruchen den Auftrag unter Zeilensperre - O08: fehlende Snapshot-Datei → Verweis auf den image_removed-Eintrag oder offener Auftrag, nie ein still unvollständiger Nachweis - A-03/A-06: Sweep verschiebt in die Quarantäne, Pause beim Restore, archive:reregister; Restore-Abgleich löscht Anwendungskopien erneut - O04/O05: Restore ordnet über den Payload-Pfad zu; unsignierte Exporte nur mit --accept-unsigned, reregister bricht bei ungültigem/fehlendem Export ab - A-05, A-07 bis A-15: Altbestand als möglicherweise veröffentlicht, Hold- Historie, Zweck per POST, Nachweise gelöschter Bilder nur mit compliance:manage, Anhänge auf ihrer Disk, Schlüssel-ID und ARCHIVE_PREVIOUS_KEYS, HMAC per HKDF, archive:verify-export - 5.1 d: Depublikation im Meldeverfahren trägt legal_request_id PressReleaseService.php enthält zusätzlich K-01 (Prüfung im Publish-Lock), N19 (archive() gibt Kopien frei) und N09 (markImagesPublished nur für auslieferbare Bilder), weil die Datei ungeteilt committet ist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
f0eeef0144
commit
7cd84b2be3
29 changed files with 2918 additions and 412 deletions
|
|
@ -7,7 +7,10 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|||
|
||||
/**
|
||||
* Lesender Zugriff auf einen Archiveintrag (Beweisarchiv 4.3): wer, wann,
|
||||
* wozu. Insert-only.
|
||||
* wozu. Insert-only. Seit dem Umsetzungsaudit 29.09.2026 (A-07) auch
|
||||
* Legal Hold setzen/aufheben (`hold_set`/`hold_released`, Vermerk als
|
||||
* Zweck) und Name/E-Mail des Admins, damit die Zeile eine Kontolöschung
|
||||
* überlebt.
|
||||
*/
|
||||
class ArchiveAccessLog extends Model
|
||||
{
|
||||
|
|
@ -15,7 +18,7 @@ class ArchiveAccessLog extends Model
|
|||
|
||||
protected $table = 'archive_access_log';
|
||||
|
||||
protected $fillable = ['entry_id', 'admin_id', 'action', 'purpose', 'accessed_at'];
|
||||
protected $fillable = ['entry_id', 'admin_id', 'admin_name', 'admin_email', 'action', 'purpose', 'accessed_at'];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class ArchiveEntry extends Model
|
|||
'payload_path',
|
||||
'payload_hash',
|
||||
'payload_bytes',
|
||||
'key_id',
|
||||
'retain_until',
|
||||
'legal_hold',
|
||||
'legal_hold_note',
|
||||
|
|
|
|||
74
app/Models/ArchivePendingJob.php
Normal file
74
app/Models/ArchivePendingJob.php
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\ArchiveReasonCategory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* Ausstehender Beweisarchiv-Eintrag (Umsetzungsaudit 29.09.2026, A-02):
|
||||
* einer je Vorgang, angelegt in der fachlichen Transaktion, gelöscht mit
|
||||
* dem geschriebenen Eintrag. `event` ist ein Wert aus ArchiveEvent oder
|
||||
* eine der Sonderarten unten. Anlegen und Abschließen nur über
|
||||
* App\Services\Archive\ArchivePendingQueue.
|
||||
*
|
||||
* @property int $id
|
||||
* @property int $press_release_id
|
||||
* @property string $event
|
||||
* @property string|null $subject_type
|
||||
* @property int|null $subject_id
|
||||
* @property ArchiveReasonCategory|null $reason_category
|
||||
* @property int|null $legal_request_id
|
||||
* @property int|null $actor_id
|
||||
* @property string|null $note
|
||||
* @property array<string, mixed>|null $payload
|
||||
* @property int $attempts
|
||||
* @property string|null $last_error
|
||||
* @property Carbon|null $last_attempted_at
|
||||
* @property Carbon|null $created_at
|
||||
*/
|
||||
class ArchivePendingJob extends Model
|
||||
{
|
||||
/**
|
||||
* Nie veröffentlichtes Bild, dessen Sofortlöschung gescheitert ist
|
||||
* (A-10): kein Archiveintrag, sondern die Löschung wird nachgeholt.
|
||||
*/
|
||||
public const EVENT_IMAGE_PURGE = 'image_purge';
|
||||
|
||||
/**
|
||||
* Marker `archive_pending_at` aus der Zeit vor den Aufträgen (Deploy
|
||||
* vom 28.09.2026). Der Nachholer wendet darauf die bisherige Heuristik
|
||||
* einmalig an.
|
||||
*/
|
||||
public const EVENT_LEGACY_MARKER = 'legacy_marker';
|
||||
|
||||
public const UPDATED_AT = null;
|
||||
|
||||
protected $fillable = [
|
||||
'press_release_id',
|
||||
'event',
|
||||
'subject_type',
|
||||
'subject_id',
|
||||
'reason_category',
|
||||
'legal_request_id',
|
||||
'actor_id',
|
||||
'note',
|
||||
'payload',
|
||||
'attempts',
|
||||
'last_error',
|
||||
'last_attempted_at',
|
||||
'created_at',
|
||||
];
|
||||
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'reason_category' => ArchiveReasonCategory::class,
|
||||
'payload' => 'encrypted:array',
|
||||
'attempts' => 'integer',
|
||||
'last_attempted_at' => 'datetime',
|
||||
'created_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue