keys->addSlot($passphrase, $label); $this->apply('slot_added', $slot); return $slot; } public function replace(int $slot, #[\SensitiveParameter] string $passphrase, ?string $label = null): void { $this->keys->replaceSlot($slot, $passphrase, $label); $this->apply('slot_replaced', $slot); } public function remove(int $slot): void { $this->keys->removeSlot($slot); $this->apply('slot_removed', $slot); } private function apply(string $event, int $slot): void { $wrapped = $this->keys->wrappedKey(); $failed = []; foreach ($this->targets->list() as $t) { try { $this->targets->repository($t)->updateWrappedKey($wrapped); } catch (\Throwable $e) { $failed[] = $t->getName(); } } $label = ''; foreach ($this->keys->slots() as $s) { if ($s['slot'] === $slot) { $label = $s['label']; } } $this->alerts->securityEvent($event, ['slot' => (string)$slot, 'label' => $label]); if ($failed !== []) { throw new \RuntimeException('Saved, but these locations could not be updated (they still accept the previous passphrases): ' . implode(', ', $failed)); } } }