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.
49 lines
1.8 KiB
Python
49 lines
1.8 KiB
Python
"""Add scripts captureoutput
|
|
|
|
Backs the per-script "may a successful run send its output back" field.
|
|
|
|
The agent already captures a script's full output and always writes it to the
|
|
endpoint log. What this controls is narrower: whether that output also crosses
|
|
to the server and is persisted in the command's resultjson, where the Run
|
|
Scripts history can show it.
|
|
|
|
Failures have always sent output and still do - a failed run has to be
|
|
diagnosable without walking to the machine. Success is the case in question,
|
|
and it is opt-in because output carries whatever the body happened to print:
|
|
hostnames, share paths, an account name, a token an author echoed while
|
|
debugging. Accepting that exposure for every routine green run is a poor
|
|
trade, so the author decides per script, after reading the body.
|
|
|
|
BOOLEAN NOT NULL defaulting FALSE, so every script row written before this
|
|
migration keeps exactly today's behaviour: metadata on success, output only on
|
|
failure. Same rule as errormode - never retroactive, because a library-wide
|
|
flip would start persisting output from bodies nobody re-read with this
|
|
question in mind.
|
|
|
|
Revision ID: 7d50_script_captureoutput
|
|
Revises: 7d49_script_errormode
|
|
Create Date: 2026-09-09
|
|
|
|
"""
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
|
|
|
|
revision = '7d50_script_captureoutput'
|
|
down_revision = '7d49_script_errormode'
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
def upgrade():
|
|
op.add_column('scripts', sa.Column(
|
|
'captureoutput', sa.Boolean(), nullable=False,
|
|
server_default=sa.false(),
|
|
comment='When true, a successful run also returns its output to the '
|
|
'server; failures always do. Off by default because script '
|
|
'output can contain whatever the body printed.'))
|
|
|
|
|
|
def downgrade():
|
|
op.drop_column('scripts', 'captureoutput')
|