Spaces:
Running
Running
feat(membership): admin-driven account creation, real estate tier/investment work, in-progress monorepo migration state
b2dcf0f | 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'], | |
| ]; | |
| } | |
| } | |