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.
3.7 KiB
Adoption tool spike
Status: spike. Built on the origin/main baseline so it can be cherry-picked as
a single unit once endpoint agent development is complete.
What it is
A one-shot, agentless enrollment tool. An admin generates a small download from the Endpoints key settings page; running the tool once on a PC creates a ShopDB PC (Computer) and Endpoint entry using only the endpoints collector key. It is NOT the endpoint agent: it installs nothing, runs no service, and sends no ongoing telemetry. It targets sites that want an inventory entry without running the full agent.
How it works
- Admin generates or reuses an endpoint agent key (existing
/agentkeyflow). - Admin opens the "Adoption tool" section, confirms the base URL (prefilled from the browser origin) and pastes the collector key (prefilled when a key was just generated, since the secret is only shown once).
POST /api/endpoints/adoptiontool/package(admin-gated) returns a ZIP withadopt.config.json,README.txt, andshopdb-adopt.exewhen a prebuilt binary is staged on the server.- On the target PC,
shopdb-adopt.exereads the config beside it (or CLI args), then POSTs to/api/collector/endpointswithX-API-Keyandadopt=true. The existing_adopt_computerpath creates the Computer + EndpointState.
Collection
The tool gathers the same identity, hardware, and SBOM subset the endpoint agent collects, using identical WMI queries and wire keys so the server stores it without translation:
- Identity:
hostname,loggedinuser,ipaddress. - Hardware:
serialnumber(Win32_BIOS),vendorname/pctype/modelnumber(Win32_ComputerSystem),osnameandlastboottime(Win32_OperatingSystem). - SBOM:
applications= both Uninstall registry hives (64-bit + WOW6432Node), de-duped{displayname, displayversion, publisher}. The server logs this as an unpersisted key today (same as the agent) until the SBOM store lands.
The tool requires administrator rights (enforced by its app manifest
requireAdministrator, with a runtime elevation guard) because the machine
Uninstall hives and full WMI need elevation, or collection would be silently
partial.
Cherry-pick boundary
The spike is deliberately isolated. Cherry-pick exactly:
agent/ShopDbAdoptionTool/(new standalone tool project, incl.app.manifest)agent/ShopDbEndpointAgent.slnx(one line adding the project)plugins/endpoints/api/adoption.py(new module; attaches toendpoints_bp)plugins/endpoints/api/__init__.py(one-line import to register the route)plugins/endpoints/frontend/views/AgentKeySettings.vue(new UI section only)plugins/endpoints/ADOPTION-TOOL-SPIKE.md(this file)
plugins/endpoints/api/routes.py is intentionally untouched so the delivery
spike changes there do not tangle with this feature.
Prebuilt exe distribution
The api container has no .NET SDK, so the package embeds the exe only when a
prebuilt copy is staged at instance/adoptiontool/shopdb-adopt.exe. Otherwise
the ZIP ships the config plus README (build the exe out of band, same model as
the endpoint agent installer bundle). Follow-up: a CI job that publishes
shopdb-adopt.exe and stages it into the image or instance path.
Known follow-ups
- Agentless health signal: an adopted PC never reports again, so
EndpointState.lastreportedatreflects only the adoption moment. The fleet health/dashboard logic should distinguish "agentless, adopted" from "agent expected but silent" so these PCs do not read as permanently failed. Left out of this spike to keep the server create-path unchanged for a clean cherry-pick; the tool does not send anagentlessmarker yet because the server does not persist one (KNOWN_PAYLOAD_KEYS). - CI packaging of the prebuilt exe (see above).