Add dockerized fake-agent for integration testing and live edge-broker smoke tests. Introduce agent CLI status command and report helpers. Add browser shell session handling for disconnected agents. Extend tests and improve token validation flow.

This commit is contained in:
Jeppe Bundgaard
2026-04-09 16:31:38 +02:00
parent 745e68aa4f
commit 2a0a3468c1
11 changed files with 955 additions and 44 deletions
@@ -166,13 +166,14 @@ class edge_gateway_manager
public function recordHeartbeat(int $gatewayId, string $plainToken, array $payload): array
{
$gateway = $this->authenticateGateway($gatewayId, $plainToken);
$existingMetadata = (array)($gateway->metadata_json->value() ?? []);
$gateway->status->set((string)($payload['status'] ?? self::STATUS_ONLINE));
$gateway->hostname->set($payload['hostname'] ?? $gateway->hostname->value());
$gateway->installed_version->set($payload['installed_version'] ?? $gateway->installed_version->value());
$gateway->target_version->set($payload['target_version'] ?? $gateway->target_version->value());
$gateway->last_heartbeat_at->set($this->now());
$gateway->last_seen_ip->set($this->remoteIp());
$gateway->metadata_json->set((array)($payload['metadata'] ?? $gateway->metadata_json->value() ?? []));
$gateway->metadata_json->set(array_merge($existingMetadata, (array)($payload['metadata'] ?? [])));
if (isset($payload['inventory']) && is_array($payload['inventory'])) {
$this->syncDeviceInventory($gatewayId, $payload['inventory']);
@@ -612,6 +613,11 @@ class edge_gateway_manager
return 'curl -fsSL ' . escapeshellarg($this->buildInstallScriptUrl($plainToken)) . ' | sudo bash';
}
public function buildInstallTokenVerifyUrl(string $plainToken): string
{
return rtrim($this->getApiBaseUrl(), '/') . '/edge-agent/install-token/verify?token=' . urlencode($plainToken);
}
public function buildInstallScriptUrl(string $plainToken): string
{
return rtrim($this->getApiBaseUrl(), '/') . '/edge-agent/install.sh?token=' . urlencode($plainToken);
@@ -631,6 +637,7 @@ class edge_gateway_manager
$script = <<<'BASH'
#!/usr/bin/env bash
set -euo pipefail
curl -fsSL "__VERIFY_URL__" >/dev/null
INSTALL_DIR=/opt/truckwash-edge-agent
mkdir -p "$INSTALL_DIR"
export DEBIAN_FRONTEND=noninteractive
@@ -665,12 +672,32 @@ echo 'TruckWash edge agent installed.'
BASH;
return strtr($script, [
'__VERIFY_URL__' => $this->buildInstallTokenVerifyUrl($plainToken),
'__PACKAGE_URL__' => rtrim($this->getApiBaseUrl(), '/') . '/edge-agent/artifacts/package.json',
'__AGENT_URL__' => rtrim($this->getApiBaseUrl(), '/') . '/edge-agent/artifacts/agent.mjs',
'__CONFIG_JSON__' => (string)$configJson,
]);
}
/**
* @throws Exception
*/
public function verifyInstallToken(string $plainToken): array
{
$claimToken = $this->requireClaimToken($plainToken);
if ($claimToken->used_at->value() !== null) {
throw new Exception('Install token has already been used');
}
return [
'valid' => true,
'claim_token_id' => (int)$claimToken->id,
'department_id' => (int)$claimToken->department_id->value(),
'label' => $claimToken->label->value(),
'expires_at' => (string)$claimToken->expires_at->value(),
];
}
public function buildBrowserShellWsUrl(string $sessionToken): ?string
{
$brokerUrl = $this->getBrokerPublicUrl();
@@ -700,15 +727,7 @@ BASH;
return $this->normalizeBrokerPublicUrl($configured);
}
$apiBaseUrl = $this->getApiBaseUrl();
$parsed = parse_url($apiBaseUrl);
if (!is_array($parsed) || !isset($parsed['host'])) {
return null;
}
$scheme = ($parsed['scheme'] ?? 'https') === 'https' ? 'https' : 'http';
$port = getenv('EDGE_BROKER_PUBLIC_PORT') ?: '4300';
return $this->normalizeBrokerPublicUrl($scheme . '://' . $parsed['host'] . ':' . $port);
return $this->buildNormalizedBrokerOrigin($this->getApiBaseUrl());
}
public function getApiBaseUrl(): string
@@ -785,9 +804,15 @@ BASH;
private function normalizeBrokerPublicUrl(string $url): string
{
$parsed = parse_url($url);
$normalized = $this->buildNormalizedBrokerOrigin($url);
return $normalized ?? trim($url);
}
private function buildNormalizedBrokerOrigin(string $url): ?string
{
$parsed = parse_url(trim($url));
if (!is_array($parsed) || !isset($parsed['host'])) {
return trim($url);
return null;
}
$host = (string)$parsed['host'];
@@ -800,15 +825,6 @@ BASH;
if (isset($parsed['port'])) {
$normalized .= ':' . $parsed['port'];
}
if (isset($parsed['path'])) {
$normalized .= $parsed['path'];
}
if (isset($parsed['query'])) {
$normalized .= '?' . $parsed['query'];
}
if (isset($parsed['fragment'])) {
$normalized .= '#' . $parsed['fragment'];
}
return $normalized;
}