Add log collection, script output capture, and timestamp fixes
Log Collector: a new collect_log action reads a plaintext log file from a known path and returns its tail for viewing and download. Rides the existing endpoints.updateapp grant rather than inventing one, since collecting a log is the same trust level as pushing an application. Collected logs land in their own table with per-asset retention of 20 instead of overloading the command audit row, and the agent refuses UNC, traversal, wildcards, directories and non-text content independently of the server check. collect_log is POLICY_EXEMPT. Every existing Configuration Policy predates the action and so cannot name it, and the intersection in ALLOWED_ACTIONS_FOR drops anything unnamed - so every policied endpoint refused log collection outright, including for admins, who saw a permission-shaped error for a grant they held. Exemption from policy is not exemption from permission: the elevated grant still applies, and a regression test asserts both halves so a future edit cannot quietly loosen the grant while "fixing" the policy gate. Script output capture: successful runs can return output, gated per script by captureoutput. Failures always returned it; success never did, which left a green badge as the only evidence a run produced. Timestamps: Activity and Operator Reports rendered date-only because the shared formatter's 'date' branch drops the clock time. Run Scripts additionally labels its timestamp, since a bare time meant "completed" on a terminal row but "queued" on an in-flight one - indistinguishable, and the wrong reading. Agent 1.16.0. Minor: collect_log is a new action name, so an older agent asked for it fails closed on the unknown-action default.
This commit is contained in:
@@ -6,6 +6,8 @@ body never lives on the endpoint ahead of time and never crosses the command
|
||||
wire; the agent downloads it with its collector credential and verifies sha256.
|
||||
"""
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
from shopdb.extensions import db
|
||||
from .base import BaseModel
|
||||
|
||||
@@ -69,6 +71,17 @@ class Script(BaseModel):
|
||||
# existed reads as the permissive behavior it was authored under.
|
||||
errormode = db.Column(db.String(16), default=ERRORMODE_DEFAULT, nullable=False,
|
||||
server_default=ERRORMODE_DEFAULT)
|
||||
# Whether a SUCCESSFUL run sends its output back to the server. Failures
|
||||
# always do: a failed run has to be diagnosable. Success is opt-in because
|
||||
# script output carries whatever the body printed - hostnames, paths, a
|
||||
# token an author echoed while debugging - and a run nobody needs to
|
||||
# diagnose is not worth that exposure by default. The endpoint log keeps the
|
||||
# full copy either way, so this only controls what crosses to the server.
|
||||
#
|
||||
# Off by default so existing scripts keep the behavior they were authored
|
||||
# under, same rule as errormode above.
|
||||
captureoutput = db.Column(db.Boolean, default=False, nullable=False,
|
||||
server_default=sa.false())
|
||||
|
||||
def to_dict(self):
|
||||
result = super().to_dict()
|
||||
|
||||
Reference in New Issue
Block a user