Merge origin/main (West Jeff) into wilm

Bring in the natural-key import fix, Metrics->Monitors rename, PC detail tabbing and panel groups, guest search grants, and the 2026-08-30 security fixes. Reconcile endpoint packaging/installer, migrations, contract version, and tests; keep the delivery uninstaller and 6-step installer alongside main's permission-based RBAC and pin-drift protection.
This commit is contained in:
benjamin.baker
2026-08-31 16:59:07 -04:00
59 changed files with 2859 additions and 180 deletions

View File

@@ -64,10 +64,17 @@ public sealed class CommandClient : IDisposable
// result is logged and swallowed so a transient network blip does not crash
// the worker; the command simply stays 'running' server-side until a later
// operator retry supersedes it.
// hostname rides along so the server can check this agent owns the command
// it is finalizing. The shared collector key does not say who is calling,
// so without it any agent can post a result for any command id. The server
// treats the parameter as optional for older agents and enforces it when
// present, so shipping this ahead of a fleet update is safe.
public async Task ReportResultAsync(
int commandId, CommandResult result, CancellationToken token)
int commandId, string hostname, CommandResult result,
CancellationToken token)
{
var url = $"api/endpoints/commands/{commandId}/result";
var url = $"api/endpoints/commands/{commandId}/result?hostname="
+ Uri.EscapeDataString(hostname);
using var response = await http.PostAsJsonAsync(
url, result, JsonOptions, token);
if (!response.IsSuccessStatusCode)

View File

@@ -130,7 +130,8 @@ public sealed class CommandWorker : BackgroundService
};
}
await client.ReportResultAsync(claim.EndpointCommandId, result, token);
await client.ReportResultAsync(
claim.EndpointCommandId, hostname, result, token);
logger.LogInformation("Command {Id} finished succeeded={Succeeded}",
claim.EndpointCommandId, result.Succeeded);