From bab17ae9397781a6d428ae88117c516e292c33ed Mon Sep 17 00:00:00 2001 From: cryxnet <75471375+cryxnet@users.noreply.github.com> Date: Sun, 25 Oct 2026 00:09:04 +0200 Subject: [PATCH] fix(audit): keep promptise audit verify lines whole when piped Rich wrapped the output at 80 columns when stdout was not a terminal, so 'last_hash (seq N)' split across two lines and broke scripts that extract the hash for --anchor. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 6 ++++++ docs/resources/changelog.md | 6 ++++++ src/promptise/audit_cli.py | 6 ++++-- tests/test_audit_log_verify.py | 11 +++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06321db3..7fa43f88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixed + +- **`promptise audit verify` wrapped its output at 80 columns when piped** -- a script reading the output got `last_hash (seq` and `N)` on separate lines, which broke extracting the hash for `--anchor`. Lines are no longer broken to fit the width. + ## 1.10.1 — 2026-10-24 ### Security diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 7dc719e3..151e3472 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -9,6 +9,12 @@ All notable changes to Promptise Foundry are documented here. --- +## Unreleased + +### Fixed + +- **`promptise audit verify` wrapped its output at 80 columns when piped** -- a script reading the output got `last_hash (seq` and `N)` on separate lines, which broke extracting the hash for `--anchor`. Lines are no longer broken to fit the width. + ## v1.10.1 — 2026-10-24 ### Security diff --git a/src/promptise/audit_cli.py b/src/promptise/audit_cli.py index 020c06f0..2ddf6afb 100644 --- a/src/promptise/audit_cli.py +++ b/src/promptise/audit_cli.py @@ -27,8 +27,10 @@ no_args_is_help=True, help="Check the HMAC-chained audit logs written by AuditMiddleware.", ) -_console = Console() -_err = Console(stderr=True) +# soft_wrap: a line is never broken to fit the width, so output piped to a +# script keeps "last_hash (seq N)" and ":: ..." on one line. +_console = Console(soft_wrap=True) +_err = Console(stderr=True, soft_wrap=True) @audit_app.command("verify") diff --git a/tests/test_audit_log_verify.py b/tests/test_audit_log_verify.py index 0c159747..43c572f2 100644 --- a/tests/test_audit_log_verify.py +++ b/tests/test_audit_log_verify.py @@ -11,6 +11,7 @@ import json import logging import os +import re from pathlib import Path from typing import Any @@ -357,6 +358,16 @@ def _cli(*args: str, env: dict[str, Any] | None = None) -> Any: class TestCli: + def test_piped_output_keeps_each_line_whole(self, log: Path) -> None: + """At the 80 columns of a pipe, the last_hash line used to wrap.""" + runner = CliRunner( + env={"COLUMNS": "80", "PROMPTISE_NO_DOTENV": "1", "PROMPTISE_AUDIT_SECRET": KEY} + ) + result = runner.invoke(app, ["audit", "verify", str(log)]) + assert result.exit_code == 0, result.output + [line] = [ln for ln in result.output.splitlines() if ln.startswith("last_hash ")] + assert re.fullmatch(r"last_hash [0-9a-f]{64} \(seq \d+\)", line), line + def test_intact_log_exits_zero_and_never_prints_the_key(self, log: Path) -> None: result = _cli(str(log), env={"PROMPTISE_AUDIT_SECRET": KEY}) assert result.exit_code == 0, result.output