normalizeSecretValue($secretValue), ]); return hash_hmac('sha256', $payload, $this->workspaceKey($workspaceId)); } private function workspaceKey(int $workspaceId): string { $appKey = (string) config('app.key', ''); if ($appKey === '') { throw new RuntimeException('App key is required for secret fingerprinting.'); } if (Str::startsWith($appKey, 'base64:')) { $decoded = base64_decode(Str::after($appKey, 'base64:'), true); if ($decoded !== false) { $appKey = $decoded; } } return hash_hmac('sha256', 'policy-version-secret-fingerprints|'.$workspaceId, $appKey, true); } private function normalizeSecretValue(mixed $secretValue): string { $normalized = $this->normalizeValue($secretValue); return json_encode($normalized, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); } private function normalizeValue(mixed $value): mixed { if (! is_array($value)) { return $value; } if (array_is_list($value)) { return array_map(fn (mixed $item): mixed => $this->normalizeValue($item), $value); } ksort($value); foreach ($value as $key => $item) { $value[$key] = $this->normalizeValue($item); } return $value; } }