Skip to content

feat: Write roles fingerprints to /var/log/sysroles.jsonl [citest_skip] - #514

Merged
richm merged 2 commits into
mainfrom
fingerprint-write-to-file
Aug 6, 2026
Merged

feat: Write roles fingerprints to /var/log/sysroles.jsonl [citest_skip]#514
richm merged 2 commits into
mainfrom
fingerprint-write-to-file

Conversation

@spetrosi

@spetrosi spetrosi commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Feature: Write roles fingerprints to /var/log/sysroles.jsonl [citest_skip]

Reason: By default logs are printed to rsyslog. This change adds a possibility to write logs to a file on the system for the downstream users.

Result: For the upstream, this makes rsyslog log message more detailed. For the downstream - also writes logs to /var/log/sysroles.jsonl

@spetrosi spetrosi self-assigned this Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Ignore keyword(s) in the title.

⛔ Ignored keywords (1)
  • [citest_skip]

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ec10c358-7e89-484b-aef3-70c527841e21

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

The Ansible module now collects structured role fingerprints, formats them for syslog, and optionally writes JSONL records with locking and size trimming. Unit tests cover collection, formatting, persistence, check mode, validation, errors, and timestamps.

Structured fingerprint reporting

Layer / File(s) Summary
Fingerprint contract and handling
library/sr_fingerprint.py
Replaces sr_message with structured fingerprint arguments, field derivation helpers, record formatting, validation, and check-mode handling.
JSONL persistence and log management
library/sr_fingerprint.py
Adds directory creation, locked JSONL writes, log trimming, metadata preservation, and write-error reporting.
Fingerprint behavior validation
tests/unit/test_sr_fingerprint.py
Tests fingerprint fields, formatting, JSONL behavior, trimming, check mode, validation failures, write failures, and timestamp output.
🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description Format ⚠️ Warning The authored description includes Reason, Result, and a valid Signed-off-by line, but it has no required Enhancement: or Feature: section. Add an Enhancement: or Feature: section that describes the change, while retaining the existing required sections.
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title follows Conventional Commits format and accurately describes the fingerprint log file feature.
Description check ✅ Passed The description includes the feature, reason, and result; the optional issue tracker section is not included.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@library/sr_fingerprint.py`:
- Around line 283-287: Update _format_fingerprint_key_value to escape or reject
carriage-return and newline characters in value before constructing either
output branch, ensuring formatted fields contain no literal CR or LF while
preserving existing quote escaping. Add a regression test covering field values
containing both control characters and asserting the formatted output contains
neither literal character.
- Around line 231-234: Update the log rotation logic around _trim_log_file to
remove the full excess, calculated from cur_size plus the new-line size minus
max_size, before appending whenever the write would exceed max_size. Explicitly
define the policy for a single JSONL row larger than max_size, implement that
behavior consistently, and add tests covering both existing oversized logs and
oversized individual rows.
- Around line 336-346: Update the remaining sr_fingerprint invocations in
tasks/set_vars.yml and tasks/main.yml to pass the structured arguments required
by run_module, including status, role_name, role_path, ansible_play_hosts_all,
and applicable logging or distribution fields. Remove the obsolete sr_message
argument and ensure each call matches the validation defined in
sr_fingerprint.py.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ae937c6b-8a36-45c8-87c4-6b8297ecc518

📥 Commits

Reviewing files that changed from the base of the PR and between ace03f7 and 8db551a.

📒 Files selected for processing (2)
  • library/sr_fingerprint.py
  • tests/unit/test_sr_fingerprint.py

Comment thread library/sr_fingerprint.py
Comment on lines +231 to +234
if max_size > 0 and cur_size + len(new_line) > max_size and cur_size > 0:
_trim_log_file(log_file, len(new_line))
with open(log_file, "a") as log_fd:
log_fd.write(new_line)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Enforce max_log_size for existing oversized logs.

The trim call removes only len(new_line). If an operator lowers max_log_size below the current file size, the next write leaves the file far above the configured limit. A new row larger than max_log_size also exceeds the limit without a defined policy.

Calculate the excess as cur_size + new_line_size - max_log_size. Remove that amount before appending. Define and test the behavior when one JSONL row exceeds the limit.

🧰 Tools
🪛 ast-grep (0.45.0)

[warning] 232-232: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(log_file, "a")
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@library/sr_fingerprint.py` around lines 231 - 234, Update the log rotation
logic around _trim_log_file to remove the full excess, calculated from cur_size
plus the new-line size minus max_size, before appending whenever the write would
exceed max_size. Explicitly define the policy for a single JSONL row larger than
max_size, implement that behavior consistently, and add tests covering both
existing oversized logs and oversized individual rows.

Comment thread library/sr_fingerprint.py
Comment on lines +283 to +287
def _format_fingerprint_key_value(field, value):
text = "" if value is None else str(value)
if any(char in text for char in ' "='):
return '%s="%s"' % (field, text.replace('"', '""'))
return "%s=%s" % (field, text)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Escape CR and LF characters before writing syslog fields.

A value containing \n or \r does not enter the quoted branch. It can create forged syslog lines and corrupt the downstream key-value record stream. Escape or reject control characters before formatting the field. Add a regression test that asserts the output contains no literal CR or LF from field values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@library/sr_fingerprint.py` around lines 283 - 287, Update
_format_fingerprint_key_value to escape or reject carriage-return and newline
characters in value before constructing either output branch, ensuring formatted
fields contain no literal CR or LF while preserving existing quote escaping. Add
a regression test covering field values containing both control characters and
asserting the formatted output contains neither literal character.

Comment thread library/sr_fingerprint.py
Comment on lines +336 to +346
def run_module():
module_args = dict(
status=dict(type="str", required=True, choices=["begin", "success"]),
write_log_file=dict(type="bool", default=False),
log_file=dict(type="path", default="/var/log/sysroles.jsonl"),
max_log_size=dict(type="int", default=2000000),
role_name=dict(type="str", required=True),
role_path=dict(type="path", required=True),
ansible_play_hosts_all=dict(type="list", elements="str", required=True),
distribution=dict(type="str", default=""),
distribution_version=dict(type="str", default=""),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 5 \
  --glob '*.yml' --glob '*.yaml' --glob '*.py' \
  '(^[[:space:]]*([[:alnum:]_]+\.)?sr_fingerprint:[[:space:]]*$|^[[:space:]]*sr_message:)' \
  .

Repository: linux-system-roles/logging

Length of output: 2807


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant fingerprint module args =="
sed -n '1,125p' library/sr_fingerprint.py
sed -n '320,380p' library/sr_fingerprint.py

echo
echo "== call sites =="
sed -n '10,18p' tasks/set_vars.yml
sed -n '138,146p' tasks/main.yml

echo
echo "== structural search for free-form dict and sr_message =="
python3 - <<'PY'
import glob, re
for p in glob.glob('library/sr_fingerprint.py'):
    text=open(p, encoding='utf-8').read()
    print(p, 'has sr_message arg:', 'sr_message' in text, 'status required:', 'choices=["begin", "success"]' in text)
PY

Repository: linux-system-roles/logging

Length of output: 6620


Update the remaining sr_fingerprint call sites.

tasks/set_vars.yml and tasks/main.yml still call sr_fingerprint with sr_message, but library/sr_fingerprint.py now requires structured fields (status, role_name, role_path, ansible_play_hosts_all, etc.). Migrate these calls or argument validation will reject the role tasks at runtime.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@library/sr_fingerprint.py` around lines 336 - 346, Update the remaining
sr_fingerprint invocations in tasks/set_vars.yml and tasks/main.yml to pass the
structured arguments required by run_module, including status, role_name,
role_path, ansible_play_hosts_all, and applicable logging or distribution
fields. Remove the obsolete sr_message argument and ensure each call matches the
validation defined in sr_fingerprint.py.

@spetrosi spetrosi changed the title feat: Write roles fingerprints to /var/log/sysroles.jsonl feat: Write roles fingerprints to /var/log/sysroles.jsonl [citest_skip] Aug 6, 2026
Feature: Write roles fingerprints to /var/log/sysroles.jsonl [citest_skip]

Reason: By default logs are printed to rsyslog. This change adds a possibility to write logs to a file on the system for the downstream users.

Result: For the upstream, this makes rsyslog log message more detailed. For the downstream - also writes logs to /var/log/sysroles.jsonl
Signed-off-by: Sergei Petrosian <spetrosi@redhat.com>
@spetrosi
spetrosi force-pushed the fingerprint-write-to-file branch from 8db551a to a078f1e Compare August 6, 2026 15:03
The sr_fingerprint module was rewritten to accept structured parameters
(status, role_name, role_path, etc.) instead of a free-form sr_message.
Update the role tasks and tests to match the new module interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@spetrosi

spetrosi commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

[citest]

@richm
richm merged commit 41db12f into main Aug 6, 2026
9 of 10 checks passed
@richm
richm deleted the fingerprint-write-to-file branch August 6, 2026 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants