feat(secrets): webhook URL and git tokens sealed; run output masks its secrets (#5037)
#5037 "Secrets at rest and in run output: webhook URL and git token encrypted, askpass via env, secret values scrubbed from logs". - webhook.url joins SECRET_KEYS; existing values are sealed at startup by migrate_plaintext_secrets. Settings -> Notifications no longer echoes the URL: it names the saved host, keeps it when left blank, and has a Remove box. - Git source http_token is sealed inside ansible.sources on save and at startup, opened in get_sources, and counted by the undecryptable-secrets scan as ansible.sources[<name>].http_token. - The askpass script holds no token: git runs it with STEWARD_GIT_TOKEN in its environment and printf prints it as data. - The executor masks every secret the run is handed (become/vault passwords, bootstrap passwords, sensitive run vars, and the per-host agent tokens the host_agent plugin now passes as redact) in each line before it is broadcast, logged or stored. - Bundled "Write agent config" tasks are no_log; a test fails if any bundled task templating steward_token lacks it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ async def trigger_run(
|
||||
inventory_content: str | None = None,
|
||||
connection: dict | None = None,
|
||||
secret_vars: dict | None = None,
|
||||
redact: list[str] | None = None,
|
||||
):
|
||||
"""Resolve inventory for the scope, persist an AnsibleRun, and launch it.
|
||||
|
||||
@@ -39,7 +40,8 @@ async def trigger_run(
|
||||
first-contact provisioning — passed to the executor but deliberately NOT
|
||||
stored on the AnsibleRun row (params), so the password never lands in the DB.
|
||||
secret_vars (sensitive run-time playbook variables) are likewise passed
|
||||
through to the executor but never persisted.
|
||||
through to the executor but never persisted. redact names further values
|
||||
to mask in the run's output (a bespoke inventory's per-host tokens).
|
||||
Returns (run, source, error): on success error is None; on failure run is
|
||||
None and error is a short human-readable reason.
|
||||
"""
|
||||
@@ -85,7 +87,7 @@ async def trigger_run(
|
||||
executor.start_run(
|
||||
app, run_id, playbook_path, inventory_path or "",
|
||||
source["path"], params or None, inventory_content,
|
||||
connection=connection, secret_vars=secret_vars,
|
||||
connection=connection, secret_vars=secret_vars, redact=redact,
|
||||
)
|
||||
)
|
||||
task.add_done_callback(
|
||||
|
||||
Reference in New Issue
Block a user