github fabriziosalmi/certmate v2.6.11
v2.6.11 - drill-down modal on Recent Executions (close #207 enh 1)

2 hours ago

Closes enhancement 1 of issue #207 (raised by @tuxpowered).

What changed

Clicking a row in the Settings → Deployment → Recent Executions table now opens a modal showing the full execution: timestamp, hook name + id, domain, event, dry-run flag, success / exit code, duration, error (when present), and the captured command, stdout and stderr streams. The backend was already recording all of these in data/deploy_history.jsonl (modules/core/deployer.py:165-179) and the /api/deploy/history endpoint was already serving the full record — the UI was rendering only 6 of the 13 fields.

Implementation

  • templates/partials/settings_deploy.html — each <tr> in the history table is now role="button" tabindex="0" with @click and @keydown.enter|space.prevent bindings to showExecutionDetail(entry). Hover affordance + aria-label per row carrying the hook name and domain. A new modal block at the end of the deploy panel uses the standard _modal.html macro (size="lg", icon="fa-terminal"). Body is gated by <template x-if="selectedExecution"> so bindings are skipped until a row is clicked.
  • static/js/settings-deploy.js — adds selectedExecution: null data and showExecutionDetail(entry) which stashes the entry and calls CertMate.modal.open('executionDetailModal'). Read-only; no extra fetch.
  • No backend change.

Security

All modal fields render via x-text (DOM textContent), never x-html. Operator-controlled command / stdout / stderr / error / hook_name strings cannot inject HTML or script tags. The data route is still @require_role('admin')-gated. Streams are truncated to 4096 chars at write time in the deployer; a footer line in the modal calls this out so a viewer is not surprised by clipped output.

Verification

Full pytest: 876 passed, 14 skipped, 2 xfailed, 0 failed in 104s.

Built a v2.6.11 image + isolated fixture dir, seeded data/deploy_history.jsonl with 4 varied entries including an XSS canary (<script>alert('xss')</script><img src=x onerror=alert(2)> in stdout). Headless Playwright smoke against the running container asserted:

Assertion Result
4 rows rendered OK
row[0] role=button, tabindex=0 OK
modal initial class has hidden OK
modal after row click: hidden removed OK
stdout pre.textContent contains literal payload OK
<script> children inside modal DOM 0
window.alert called during render never
Esc closes modal OK
Enter on focused row opens modal OK

Out of scope (separate follow-ups against #207)

  • Relabel "Hook name" → "path to script or cmd" + "Description:" prefix on the example field.
  • Dedicated webhook configuration flow (URL + method + auth + freeform JSON payload + variable selector), distinct from the shell-script hook flow.

Don't miss a new certmate release

NewReleases is sending notifications on new releases.