Spaces:
Running
Running
File size: 3,595 Bytes
b2dcf0f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | <?php
namespace App\Domain\Config;
use App\Domain\Audit\AuditService;
use App\Infrastructure\Ids\UuidGenerator;
use App\Shared\Exceptions\ApiException;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
class SecretMetadataService
{
public function __construct(
private readonly UuidGenerator $ids,
private readonly AuditService $audit,
) {
}
public function list(): array
{
return [
'secrets' => DB::table('secret_metadata')
->whereNull('deleted_at')
->orderBy('service_name')
->orderBy('secret_name')
->get()
->map(fn ($row): array => $this->payload((array) $row))
->all(),
];
}
public function create(array $input, string $actorUserId): array
{
foreach (['secret_value', 'value', 'password', 'token'] as $forbidden) {
if (array_key_exists($forbidden, $input)) {
throw new ApiException('RAW_SECRET_NOT_ALLOWED', 'Raw secret values must not be submitted to secret metadata.', [], 422);
}
}
$id = $this->ids->generate();
$now = Carbon::now();
DB::table('secret_metadata')->insert([
'id' => $id,
'service_name' => strtoupper($input['service_name']),
'secret_name' => strtoupper($input['secret_name']),
'vault_path' => $input['vault_path'],
'status' => $input['status'] ?? 'ACTIVE',
'last_rotated_at' => $input['last_rotated_at'] ?? null,
'next_rotation_due_at' => $input['next_rotation_due_at'] ?? null,
'created_by_user_id' => $actorUserId,
'created_at' => $now,
'updated_at' => $now,
]);
$this->audit->record('SECRET_METADATA_CREATED', $actorUserId, null, 'secret_metadata', $id, 'SUCCESS', [
'service_name' => strtoupper($input['service_name']),
'secret_name' => strtoupper($input['secret_name']),
]);
return ['secret' => $this->payload((array) DB::table('secret_metadata')->where('id', $id)->first())];
}
public function rotate(string $id, string $actorUserId): array
{
$secret = DB::table('secret_metadata')->where('id', $id)->whereNull('deleted_at')->first();
if ($secret === null) {
throw new ApiException('SECRET_METADATA_NOT_FOUND', 'Secret metadata record was not found.', [], 404);
}
DB::table('secret_metadata')->where('id', $id)->update([
'status' => 'ROTATED',
'last_rotated_at' => Carbon::now(),
'next_rotation_due_at' => Carbon::now()->addDays(90),
'updated_at' => Carbon::now(),
]);
$this->audit->record('SECRET_METADATA_ROTATED', $actorUserId, null, 'secret_metadata', $id, 'SUCCESS');
return ['secret' => $this->payload((array) DB::table('secret_metadata')->where('id', $id)->first())];
}
private function payload(array $row): array
{
return [
'id' => $row['id'],
'service_name' => $row['service_name'],
'secret_name' => $row['secret_name'],
'vault_path' => $row['vault_path'],
'status' => $row['status'],
'last_rotated_at' => $row['last_rotated_at'],
'next_rotation_due_at' => $row['next_rotation_due_at'],
'created_by_user_id' => $row['created_by_user_id'],
'created_at' => $row['created_at'],
'updated_at' => $row['updated_at'],
];
}
}
|