diff --git a/app/Provisioning/Steps/Customer/CompleteProvisioning.php b/app/Provisioning/Steps/Customer/CompleteProvisioning.php index d3a2054..7b51ffb 100644 --- a/app/Provisioning/Steps/Customer/CompleteProvisioning.php +++ b/app/Provisioning/Steps/Customer/CompleteProvisioning.php @@ -32,13 +32,17 @@ class CompleteProvisioning extends CustomerStep $encrypted = $run->context('admin_password'); if ($encrypted !== null && ! $this->hasResource($run, 'credentials_sent')) { - // Pass the ENCRYPTED password — CloudReady is queued, so plaintext - // would land in the queue payload; it decrypts only when building the mail. + // Pass the ENCRYPTED password (decrypted only when building the mail). Notification::route('mail', $order->customer->email)->notify( new CloudReady($instance, (string) $instance->nc_admin_ref, $encrypted), ); // Record delivery so a retry after a crash doesn't re-send. $this->recordResource($run, $instance->host, 'credentials_sent', (string) $instance->nc_admin_ref); + } + + // Always scrub once delivery is recorded — even if a crash interrupted a + // previous attempt between recording and scrubbing. + if ($this->hasResource($run, 'credentials_sent')) { $run->forgetContext('admin_password'); } diff --git a/app/Services/Monitoring/HttpMonitoringClient.php b/app/Services/Monitoring/HttpMonitoringClient.php index 01f3721..503cef1 100644 --- a/app/Services/Monitoring/HttpMonitoringClient.php +++ b/app/Services/Monitoring/HttpMonitoringClient.php @@ -18,8 +18,19 @@ class HttpMonitoringClient implements MonitoringClient return 'mon-'.substr(sha1($url), 0, 12); } - return (string) Http::withToken((string) config('services.monitoring.token')) - ->post(rtrim($endpoint, '/').'/monitors', ['friendly_name' => $name, 'url' => $url, 'type' => 'https']) + $base = rtrim($endpoint, '/'); + $token = (string) config('services.monitoring.token'); + + // Idempotent: reuse an existing monitor for this URL rather than creating + // a duplicate when a crash retries after a prior successful POST. + $existing = collect(Http::withToken($token)->get($base.'/monitors')->throw()->json('monitors', [])) + ->first(fn ($monitor) => ($monitor['url'] ?? null) === $url); + if ($existing !== null) { + return (string) $existing['id']; + } + + return (string) Http::withToken($token) + ->post($base.'/monitors', ['friendly_name' => $name, 'url' => $url, 'type' => 'https']) ->throw()->json('monitor.id'); }