Ben Baker's installed-software collection, software delivery (run_script and
update_app), agentless adoption tool and command-queue hardening, with his
authorship preserved.
Reviewed before promotion. Fixed: the endpoints plugin tests were never collected
by pytest, the SBOM snapshot table's key would exhaust on MySQL, ingest did not
truncate two columns strict MySQL would reject, and update_app's version branch
pinned a digest for a file that route never serves. Agent packaging moved off
require_role('admin') onto a new endpoints.agentpackage permission.
Contract 0.27.0. Full suite 2231, frontend 314.
113 lines
4.8 KiB
Markdown
113 lines
4.8 KiB
Markdown
# Delivery testing notes (update_app + run_script)
|
|
|
|
Temporary field notes for exercising the endpoint delivery path end to end and
|
|
for handing the UI work to Cameron. ASCII only, no em-dashes, no emojis, per
|
|
repo style. Remove the dev test bench (view, route, nav entry) once the
|
|
production delivery UI lands.
|
|
|
|
## What exists today (the contract Cameron builds against)
|
|
|
|
Server allowlist (`plugins/endpoints/commands.py`):
|
|
|
|
- `run_script` - targetkind `script`. `target` is a script NAME the agent
|
|
already holds in its local `scriptpaths` allowlist. No body or path crosses
|
|
the wire.
|
|
- `update_app` - targetkind `app`. `target` is an `appversionid` that resolves
|
|
to a ShopDB-hosted installer package. The server pins the package by SHA-256
|
|
and passes this version's `silentargs`.
|
|
|
|
Both actions require `endpoints.deploy` ON TOP OF `endpoints.command`. Queueing
|
|
one is the actual authority (audited with the requesting user). The agent claims
|
|
it with its collector credential.
|
|
|
|
Enqueue call (same route as every other endpoint command):
|
|
|
|
```
|
|
POST /api/endpoints/<assetid>/commands
|
|
{ "action": "run_script", "target": "remove-network-drives" }
|
|
{ "action": "update_app", "target": "<appversionid>" }
|
|
```
|
|
|
|
Rules the UI must respect:
|
|
|
|
- At most one pending/running command per endpoint. A second enqueue returns
|
|
409 (treat as "already in flight", not a failure).
|
|
- `update_app` is validated at enqueue: an appversionid with no installer
|
|
package or unknown id is rejected 400 before it is queued.
|
|
- A version with no `sha256` has no uploaded package yet. Do not offer it for
|
|
`update_app`; the agent's integrity check will fail closed.
|
|
|
|
Read the result back:
|
|
|
|
```
|
|
GET /api/endpoints/<assetid>/commands
|
|
```
|
|
|
|
Each row carries `status` (pending/running/succeeded/failed), `resultmessage`
|
|
(short summary) and `resultjson` (structured detail: for run_script the exit
|
|
code and script path; for update_app the installer path, exit code and digest
|
|
check).
|
|
|
|
Agent-facing package download (collector-authenticated, not user JWT):
|
|
|
|
```
|
|
GET /api/endpoints/apppackage/<appversionid> (X-API-Key collector token)
|
|
```
|
|
|
|
## The dev test bench
|
|
|
|
Route: `/endpoints/delivery-test` (sidebar "Delivery test bench", gated on
|
|
`endpoints.deploy`). It is deliberately minimal: pick an endpoint, push a script
|
|
by name or push an app version, then watch the command log pane. There is no
|
|
script-library component yet, so `run_script` takes a free-text name; the agent
|
|
runs it only if that name is in its `scriptpaths`.
|
|
|
|
## Preparing the test endpoint
|
|
|
|
1. Copy the dev build to the test box:
|
|
- `agent\dev-bin\agent\shopdbagent.exe`
|
|
- `agent\dev-bin\agent\appsettings.json`
|
|
Stage them the same way the site installer does (service exe + appsettings).
|
|
2. Provision the collector credential and base URL. Per repo policy these are
|
|
NOT in appsettings.json; set the registry values under
|
|
`HKLM\SOFTWARE\GE\ShopDB` (`CollectorKey`, `BaseUrl`). The shipped
|
|
appsettings has `baseurl` empty and `apikey` = REPLACE_WITH_COLLECTOR_KEY so
|
|
the agent fails closed until provisioned.
|
|
3. Stage the sample script where appsettings points:
|
|
`C:\ProgramData\ShopDB\EndpointAgent\scripts\remove-network-drives.ps1`
|
|
(source: `agent\dev-bin\scripts\remove-network-drives.ps1`). The
|
|
`scriptpaths` entry in appsettings.json maps the name `remove-network-drives`
|
|
to that path.
|
|
4. For an `update_app` test, create the application in the Applications module,
|
|
upload its installer package (this stamps the version's `sha256`), and note
|
|
the version's `appversionid`.
|
|
|
|
## Collecting logs
|
|
|
|
Endpoint side (the agent):
|
|
|
|
- Rolling diagnostics log: `%ProgramData%\ShopDB\EndpointAgent\logs`
|
|
(override with `logpath` in appsettings). This is where run_script and
|
|
update_app record what they resolved, the digest check, and the installer or
|
|
script exit code.
|
|
- Windows Event Log source `ShopDB Endpoint Agent` for service faults.
|
|
|
|
Web UI / ShopDB side:
|
|
|
|
- The command log pane on the bench (or `GET /api/endpoints/<assetid>/commands`)
|
|
shows `status`, `resultmessage` and `resultjson` reported by the agent.
|
|
- Ingest observability: unknown/unpersisted telemetry keys are logged by the
|
|
endpoints plugin on the API container, so incoming agent data is visible in
|
|
the app logs even before UI persistence catches up.
|
|
- Audit log records each enqueue (`created EndpointCommand`, action + target +
|
|
asset) with the requesting user.
|
|
|
|
## Notes to capture during testing (for Cameron)
|
|
|
|
- Round-trip latency from enqueue to a terminal status, at the agent cadence.
|
|
- Whether `resultmessage` alone is enough for the operator, or the UI needs to
|
|
surface `resultjson` (exit codes, digest mismatches).
|
|
- How a 409 (already in flight) should read in the real UI.
|
|
- What a failed digest check or non-zero installer exit looks like end to end,
|
|
so the production UI can present it clearly.
|