- 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>
62 lines
2.5 KiB
PHP
62 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Services\Archive\EvidenceArchive;
|
|
use Illuminate\Console\Command;
|
|
|
|
/**
|
|
* Beweisarchiv (N11, Umsetzungsaudit 29.09.2026 A-03): Payload-Dateien ohne
|
|
* Archivzeile nach Karenzzeit in die Quarantäne verschieben (nicht löschen
|
|
* — nach einem DB-Restore fehlen echten Einträgen die Zeilen), liegen-
|
|
* gebliebene .tmp löschen, abgelaufene Quarantäne-Tage entfernen. Läuft
|
|
* täglich nach dem Purge. `--pause`/`--resume` schalten den Sweep aus und
|
|
* ein; der Restore-Abgleich setzt ihn automatisch aus.
|
|
*/
|
|
class ArchiveSweepOrphans extends Command
|
|
{
|
|
protected $signature = 'archive:sweep-orphans
|
|
{--hours=24 : Nur Dateien, die älter als X Stunden sind}
|
|
{--dry-run : Nur zählen}
|
|
{--pause : Sweep aussetzen (z. B. nach einem Restore)}
|
|
{--resume : Ausgesetzten Sweep wieder aufnehmen}';
|
|
|
|
protected $description = 'Verschiebt Beweisarchiv-Payloads ohne zugehörige Archivzeile in die Quarantäne';
|
|
|
|
public function handle(EvidenceArchive $archive): int
|
|
{
|
|
if ($this->option('pause')) {
|
|
$archive->pauseSweep();
|
|
$this->info('Orphan-Sweep ausgesetzt. Fortsetzen mit archive:sweep-orphans --resume (nach archive:reregister).');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
if ($this->option('resume')) {
|
|
$archive->resumeSweep();
|
|
$this->info('Orphan-Sweep wieder aktiv'.(config('archive.sweep_paused') ? ' — ARCHIVE_SWEEP_PAUSED hält ihn weiterhin an.' : '.'));
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$result = $archive->sweepOrphans((bool) $this->option('dry-run'), max(1, (int) $this->option('hours')));
|
|
|
|
if ($result['paused']) {
|
|
$this->warn('Orphan-Sweep ausgesetzt (Restore-Abgleich oder ARCHIVE_SWEEP_PAUSED) — nichts verschoben. Fortsetzen mit --resume.');
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$this->info(sprintf(
|
|
'%s: %d Dateien geprüft, %d verwaist, %d in Quarantäne, %d entfernt; Quarantäne abgelaufen: %d.',
|
|
$this->option('dry-run') ? 'Trockenlauf' : 'Bereinigung',
|
|
$result['scanned'],
|
|
$result['orphans'],
|
|
$result['quarantined'],
|
|
$result['removed'],
|
|
$result['expired'],
|
|
));
|
|
|
|
return ! $this->option('dry-run') && $result['orphans'] > $result['quarantined'] + $result['removed'] ? self::FAILURE : self::SUCCESS;
|
|
}
|
|
}
|