Commit Graph

6 Commits

Author SHA1 Message Date
benjamin.baker
8f115ca330 Split shipped monitor bundle into per-monitor policies
The product shipped one Configuration Policy carrying every shopfloor app
monitor, wrapped in a shipped Site Policy that applied it to every endpoint.
That bundled two decisions a site cannot separate: which monitors exist, and
which endpoints get them. A site that wanted eDNC on one PC type and MTConnect
on another had to delete the shipped policy and rebuild both halves.

Ship one Configuration Policy per monitor with no PC type attribution, and stop
shipping a Site Policy at all. Composition is a site decision; the product now
supplies parts, not an assembled opinion.

Shipped Configuration Policies become editable and deletable. Provenance stays
a source tag rather than a lock, which is safe because seeding is insert-if-
absent and no reconciling seeder exists, so a site edit is never stomped. The
stale comments claiming shipped rows were read-only and reconciled described
behavior the code never had.
2026-09-08 15:22:10 -04:00
benjamin.baker
aa9dafc5ca Add application-driven policy generation with an acknowledgement gate
Ticking "Required on all PCs" now generates a configuration policy that
installs the application on every non-server endpoint it matches, rather
than only flagging a software-compliance report row.

Because that save is a fleet-wide deployment, it requires explicit
acknowledgement. The gate is enforced in the API, not only in the form:
a confirmation dialog that can be sidestepped by POSTing directly is
decoration, not a safeguard. It fires only on the transition INTO the
required state, since re-saving an already-required application deploys
nothing new.

Generated policies carry a new 'autoapp' source. They stay editable, and
hand-editing one transfers ownership to 'local' so it survives a later
uncheck; 'shipped' remains read-only. Existing required applications are
not migrated retroactively - policies are only created on save.

Also adds the monitorable fields that the shipped-policy breakup will
build on, and repairs a mangled non-ASCII byte in copilot-instructions.md
that was failing the style gate.
2026-09-07 13:27:59 -04:00
benjamin.baker
52c9d2b009 Add multi-action policy holds and exempt collect_now from policy
Adds PolicyActionHold so an admin can suspend specific actions on a computer without editing the policy itself, covering the break-glass case where a machine must be quiesced immediately. Holds cover multiple actions in one atomic submission rather than one row per action, so a partial failure cannot leave a half-applied hold. Duration is free-form with 0 meaning indefinite (migration 0006 makes expiresat nullable); the prior fixed ceiling was removed because an admin quiescing a misbehaving machine does not know in advance how long it needs, and a hold silently expiring is worse than one that must be cleared deliberately. The What This Does explainer reflects indefinite holds.

collect_now exemption: refreshing status was denied on any endpoint with a non-empty effective policy even when the caller held the matching grant, because policy intersection silently removed the action. collect_now is a read-only status refresh with no side effects, so it now sits in POLICY_EXEMPT_ACTIONS alongside the other routine actions. Verified against a synthetic non-empty policy: operators can refresh status again while every write action stays gated.
2026-09-07 12:38:55 -04:00
benjamin.baker
d973ce6c26 Add configuration policy monitors and action picker for computers
Configuration policies need a way to attach process/service monitors so drift can be evaluated against a machine's desired state. This wires the policy resolver and routes to the shared monitor catalog and adds an action picker UI that can create process monitors with an optional launch path.
2026-09-01 15:45:52 -04:00
7bda8e6d60 Store the policy JSON columns as TEXT for MySQL 5.6
The branch stored scopejson, desiredstate and params as sa.JSON, the only JSON
columns in the product. MySQL 5.6 has no JSON type - it arrived in 5.7 - and the
migration failed there with a bare syntax error near the word JSON.

They are TEXT now, through a JSONText type decorator, so the seventeen call sites
still assign and read dicts. The convention elsewhere is already TEXT:
guides.blocksjson, geenforce.manifestjson.

Spec regenerated: 331 paths, 477 operations across 22 surfaces.
2026-08-28 16:18:34 -04:00
benjamin.baker
01734e5449 harden CSV import reconciliation and preserve saved model selections
Default fuzzy reconcile threshold to 0 and refuse merges when digit runs differ so numbered labels like Bay 311 never bind to Bay 310. Keep edit forms from clearing saved model fields when category filtering hides untyped rows. Includes in-progress computers policy and endpoints command feature work.
2026-08-28 09:29:09 -04:00