fix: display log fields in Mini App log viewer
renderLogs() was ignoring the fields property sent via WebSocket,
showing only the message. Now renders fields as {key=value, ...}
after the message, matching terminal output.
Also update CLAUDE.md: mark Log Fields masking TODO as done,
add Known Gaps section noting lack of frontend test coverage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
9e34a140f0
commit
627a6cc849
2 changed files with 15 additions and 2 deletions
|
|
@ -21,4 +21,8 @@ Lint: `golangci-lint run`
|
|||
|
||||
## Security TODOs
|
||||
|
||||
- **Log Fields masking**: `LogEntry.Fields` (`map[string]any`) is exposed via WebSocket (`/miniapp/api/logs/ws`) and snapshots (`/miniapp/api/logs/snapshot`). If any code logs sensitive values (tokens, API keys, passwords) in Fields, they will be visible to Mini App users. Add a sanitizer in `RecentLogs()` and `wsLogs()` that masks values for keys matching patterns like `token`, `key`, `secret`, `password`, `authorization`. Track in: `pkg/logger/logger.go` (RecentLogs), `pkg/miniapp/miniapp.go` (wsLogs stream).
|
||||
- ~~**Log Fields masking**~~: Done. `SanitizeFields()` in `pkg/logger/logger.go` masks keys matching `token`, `key`, `secret`, `password`, `authorization`, `credential`. Applied in `RecentLogs()` and `wsLogs()` stream.
|
||||
|
||||
## Known Gaps
|
||||
|
||||
- **Mini App log viewer has no frontend tests**: `renderLogs()` in `pkg/miniapp/static/index.html` is inline vanilla JS with no unit/E2E test coverage. Backend (Go) tests cover `RecentLogs`, `SanitizeFields`, and JSON serialization, but nothing verifies the JS rendering. This allowed the Fields display bug (fields sent but not rendered) to ship undetected.
|
||||
|
|
|
|||
|
|
@ -755,6 +755,7 @@
|
|||
.log-badge.debug { background: rgba(142,142,147,0.12); color: #8e8e93; }
|
||||
.log-comp { color: var(--link); flex-shrink: 0; font-size: 10px; }
|
||||
.log-msg { flex: 1; word-break: break-all; color: var(--text); }
|
||||
.log-fields { color: var(--hint); font-size: 10px; }
|
||||
.log-actions { display: flex; gap: 8px; align-items: center; margin-top: 8px; }
|
||||
.log-snap-btn {
|
||||
padding: 6px 12px;
|
||||
|
|
@ -1607,11 +1608,19 @@ function renderLogs() {
|
|||
var lvl = (e.level || 'info').toLowerCase();
|
||||
var ts = e.timestamp ? e.timestamp.substring(11, 19) : '';
|
||||
var comp = e.component ? '<span class="log-comp">' + escapeHtml(e.component) + '</span>' : '';
|
||||
var fields = '';
|
||||
if (e.fields && typeof e.fields === 'object') {
|
||||
var parts = [];
|
||||
for (var k in e.fields) {
|
||||
if (e.fields.hasOwnProperty(k)) parts.push(k + '=' + e.fields[k]);
|
||||
}
|
||||
if (parts.length) fields = ' <span class="log-fields">{' + escapeHtml(parts.join(', ')) + '}</span>';
|
||||
}
|
||||
html += '<div class="log-entry">' +
|
||||
'<span class="log-ts">' + ts + '</span>' +
|
||||
'<span class="log-badge ' + lvl + '">' + lvl + '</span>' +
|
||||
comp +
|
||||
'<span class="log-msg">' + escapeHtml(e.message || '') + '</span>' +
|
||||
'<span class="log-msg">' + escapeHtml(e.message || '') + fields + '</span>' +
|
||||
'</div>';
|
||||
}
|
||||
container.innerHTML = html;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue