Import the wilm endpoint-monitor and channel-distribution work

Everything on origin/wilm that is not on the published main, applied as one
change because the published history has rewritten hashes: per-commit
cherry-pick conflicts against our main even though the squashed diff applies
clean.

Contents: endpoint monitor catalog + policy attachment + warn-only drift
reconciler, operator issue reports from the tray, agent launch-path allowlist,
and the GHCR channel-image distribution path for dev workstations.

NOT READY FOR main. Open items:
  - 10 new routes are absent from docs/api-inventory.json, so
    test_api_inventory_parity fails. That gate SKIPS on the published mirror
    (the test ships, its data file is scrubbed), which is why wilm never saw it.
  - dev-bootstrap.ps1 and Start-ShopDBDev.ps1 hardcode the ge-aero GitHub org.
  - plugins/endpoints/plugin.py carries a whitespace-only re-indent.

Scope: product
This commit is contained in:
cproudlock
2026-09-02 10:05:44 -04:00
parent 1480b30e8c
commit 27b2817fd7
76 changed files with 5930 additions and 173 deletions

View File

@@ -64,6 +64,40 @@ PUBLIC_SETTING_KEYS = {
'site_timezone',
}
# Environment channel label. Sourced from the SHOPDB_ENV_LABEL environment
# variable (set by the edge docker-compose override and the bleeding-edge
# installer, unset on stable/main), NOT from a settings row. It is injected as a
# synthetic public item into the settings list so the frontend picks it up
# through the same read-through it already uses for branding, with no extra
# request. Empty when unset, which is how a stable deployment renders no DEV
# badge. Public and read-only: it carries no secret and cannot be edited via the
# settings API, only by redeploying with a different environment value.
ENV_LABEL_KEY = 'env_label'
def _env_label() -> str:
"""The configured environment channel label (e.g. 'DEV'), or '' when unset."""
return (os.environ.get('SHOPDB_ENV_LABEL') or '').strip()
def _env_label_item() -> dict:
"""Synthetic, serialized settings item carrying the environment label.
Shaped like a real serialized Setting so the frontend read-through treats it
as just another public key. settingid is None because it is not a DB row.
"""
return {
'settingid': None,
'key': ENV_LABEL_KEY,
'value': _env_label(),
'valuetype': 'string',
'category': 'branding',
'description': 'Environment channel label (from SHOPDB_ENV_LABEL); '
'drives the DEV badge in the sidebar. Read-only.',
'createddate': None,
'modifieddate': None,
}
def _plugin_declared_settings() -> dict:
"""Declared settings ({key: entry}) of every loaded plugin, or {}."""
@@ -576,7 +610,19 @@ def list_settings():
# bootstrap keys); an authed principal sees everything (secrets masked).
if get_jwt_identity() is None:
settings = [s for s in settings if _is_public_setting(s)]
return success_response([_serialize_setting(s) for s in settings])
items = [_serialize_setting(s) for s in settings]
# Inject the environment channel label as a synthetic public item so the
# frontend read-through surfaces it alongside branding. It is env-sourced,
# not a DB row, and is always present (empty string when unset) so the
# public-settings contract can rely on the key existing. Drop any DB row that
# somehow shares the key so the env value is authoritative and appears once.
# Skip it when a category filter is active and does not select branding, so a
# scoped query is not polluted.
if not category or category == 'branding':
items = [i for i in items if i.get('key') != ENV_LABEL_KEY]
items.append(_env_label_item())
return success_response(items)
@settings_bp.route('/<key>', methods=['GET'])

View File

@@ -53,7 +53,7 @@ PLUGIN_TABLE_OWNERS: dict[str, Iterable[str]] = {
'configurationpolicies', 'configurationpolicyactions',
'businesspolicies', 'businesspolicyitems'),
'employees': ('directoryemployees',),
'endpoints': ('endpointstates', 'endpointevents', 'endpointcommands', 'endpointapplications'),
'endpoints': ('endpointstates', 'endpointevents', 'endpointcommands', 'endpointapplications', 'endpointmonitors', 'operatorreports'),
'geenforce': ('manifestscopes', 'manifestentries', 'manifestentrypctypes',
'manifestentryhostnames', 'manifestentrymachinenumbers',
'manifestinusechecks', 'manifestinusecheckprocesses',