Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 86 additions & 1 deletion drift_guard/guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,85 @@ def cmd_check(url: str = DEFAULT_OPENAPI_URL) -> None:
# CLI dispatcher
# ---------------------------------------------------------------------------

# The auto-generated footer line used as a marker in api_reference.md.
# The audit section is inserted just before this line.
_AUTOGEN_FOOTER_PREFIX = "_This file was auto-generated by"


def _append_audit_section_to_api_ref(
entries: list[dict], total: int, timestamp: str
) -> None:
"""Append (or replace) a Runtime Mismatches section in api_reference.md.

The section is inserted just before the auto-generated footer line.
If a previous audit section exists it is replaced so we don't accumulate
stale data across multiple audit runs.
"""
if not API_REF_PATH.exists():
return

content = API_REF_PATH.read_text()

# Strip any existing audit section (between marker and footer)
audit_header = "## Runtime Mismatches"
if audit_header in content:
# Remove from the audit header to just before the footer
before_audit = content[: content.index(audit_header)]
# Find the footer after the audit section
footer_idx = content.find(_AUTOGEN_FOOTER_PREFIX, content.index(audit_header))
if footer_idx != -1:
after_audit = content[footer_idx:]
else:
after_audit = ""
content = before_audit + after_audit

# Build the audit section
section_lines = [
"## Runtime Mismatches",
"",
]

if total == 0:
section_lines.append("No runtime mismatches recorded.")
section_lines.append("")
else:
section_lines.append(f"**{total} mismatch(es) recorded**")
section_lines.append("")
section_lines.append(
"| Method | Path | Issue Type | Details | Client IP |"
)
section_lines.append(
"|--------|------|------------|---------|-----------|"
)
for entry in entries:
method = entry.get("method", "")
path = entry.get("path", "")
issue_type = entry.get("issue_type", "")
details = entry.get("details", "").replace("|", "\\|")
client_ip = entry.get("client_ip", "")
section_lines.append(
f"| {method} | `{path}` | {issue_type} | {details} | {client_ip} |"
)
section_lines.append("")

section_lines.append(f"_Audit last run: {timestamp}_")
section_lines.append("")
section_lines.append("---")
section_lines.append("")

audit_section = "\n".join(section_lines)

# Insert before the footer line
if _AUTOGEN_FOOTER_PREFIX in content:
footer_pos = content.index(_AUTOGEN_FOOTER_PREFIX)
new_content = content[:footer_pos] + audit_section + content[footer_pos:]
else:
# No footer found — just append at the end
new_content = content.rstrip("\n") + "\n\n" + audit_section

_write_text(API_REF_PATH, new_content)


def cmd_audit(url: str = DEFAULT_AUDIT_URL) -> None:
"""Fetch the runtime audit log, summarise mismatches, and notify Slack."""
console.rule("[bold blue]Drift Guard – Audit[/bold blue]")
Expand Down Expand Up @@ -236,7 +315,7 @@ def cmd_audit(url: str = DEFAULT_AUDIT_URL) -> None:
summary = "\n".join(lines)
console.print(summary)

# Write audit report
# Write standalone audit report (kept for CI artifact uploads)
now = _timestamp()
machine = _machine()
audit_report = (
Expand All @@ -253,6 +332,12 @@ def cmd_audit(url: str = DEFAULT_AUDIT_URL) -> None:
_write_text(audit_path, audit_report)
console.print(f"\n Wrote audit report to [cyan]{audit_path}[/cyan]")

# Append Runtime Mismatches section to docs/api_reference.md
_append_audit_section_to_api_ref(entries, total, now)
console.print(
f" Appended Runtime Mismatches section to [cyan]{API_REF_PATH}[/cyan]"
)
Comment on lines +336 to +339

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

🟡 Misleading success message printed when api_reference.md does not exist

When API_REF_PATH does not exist, _append_audit_section_to_api_ref silently returns at line 215-216 without writing anything. However, cmd_audit unconditionally prints "Appended Runtime Mismatches section to docs/api_reference.md" at lines 337-339, misleading the user into thinking the section was successfully written.

Root Cause

The function _append_audit_section_to_api_ref has an early return when the file doesn't exist (drift_guard/guard.py:215-216), but the caller at drift_guard/guard.py:336-339 does not check whether the operation actually succeeded:

# Line 215-216: silently returns
if not API_REF_PATH.exists():
    return
# Lines 336-339: always prints success
_append_audit_section_to_api_ref(entries, total, now)
console.print(
    f"  Appended Runtime Mismatches section to [cyan]{API_REF_PATH}[/cyan]"
)

Impact: If a user runs audit before running baseline (which creates api_reference.md), they see a success message but the audit section is never written. This could cause confusion during CI or manual debugging.

Suggested change
_append_audit_section_to_api_ref(entries, total, now)
console.print(
f" Appended Runtime Mismatches section to [cyan]{API_REF_PATH}[/cyan]"
)
# Append Runtime Mismatches section to docs/api_reference.md
if API_REF_PATH.exists():
_append_audit_section_to_api_ref(entries, total, now)
console.print(
f" Appended Runtime Mismatches section to [cyan]{API_REF_PATH}[/cyan]"
)
else:
console.print(
f" [dim]Skipped updating {API_REF_PATH} (file not found)[/dim]"
)
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


# Slack notification
send_slack_notification(
title="\U0001f6a8 API Call Guard: Runtime mismatches detected",
Expand Down