Skip to content

feat: add HAR capture and runtime help - #338

Merged
moshloop merged 2 commits into
masterfrom
feat/har-capture-runtime-help
Aug 4, 2026
Merged

feat: add HAR capture and runtime help#338
moshloop merged 2 commits into
masterfrom
feat/har-capture-runtime-help

Conversation

@moshloop

@moshloop moshloop commented Aug 4, 2026

Copy link
Copy Markdown
Member

What

  • Add property-driven HAR capture levels, metadata/full modes, replayable credentials, and safer sensitive-archive permissions.
  • Add shared runtime help for logging, HTTP tracing, HAR capture, properties, and output formats.

Notes

  • Reuse shared HAR middleware and writers across property-based and client-managed capture.
  • Cover HTTP trace configuration, topic selection, and rendering with tests.

Summary by CodeRabbit

  • New Features

    • Added HAR capture with disabled, metadata-only, and full-body modes.
    • Added configurable capture for sensitive credentials, with redaction enabled by default.
    • Added HAR file export with appropriate file permissions and capture summaries.
    • Added feature-specific and global HAR configuration support.
  • Documentation

    • Added help topics covering HAR capture, formatting, HTTP logging, and configuration options.
  • Improvements

    • Centralized HAR capture and writing behavior for consistent results across HTTP clients.

Centralize HAR capture configuration in the shared har package so HTTP clients can use consistent property-driven behavior.
Support metadata-only and full capture levels, optional replayable credentials, and safer permissions for sensitive archives.
Reuse the shared middleware and writer across property-based and client-managed capture.
Add reusable operator help for logging, HTTP tracing, HAR capture, properties, and output formats. Derive the HTTP trace ladder from runtime configuration and cover topic selection and rendering with tests.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

HAR capture

Layer / File(s) Summary
HAR capture contracts and file output
har/level.go, har/har.go, har/write.go
Adds capture levels, sensitive-data configuration, default property handling, and HAR 1.2 file writing with conditional permissions.
Metadata and sensitive-value capture
har/metadata.go, har/middleware.go, har/middleware_test.go
Adds metadata-only middleware and centralized redaction or preservation for URLs, headers, query values, and bodies.
Registry wiring and capture validation
har/registry.go, har/registry_test.go, http/client.go
Adds feature-aware registry resolution, collector deduplication, transport wiring, flushing, integration tests, and shared HAR level usage in the HTTP client.

Runtime help

Layer / File(s) Summary
Help topic model and content
help/help.go, help/format.go, help/har.go, help/logging.go, help/http.go
Adds runtime help topics for formatting, logging, HTTP tracing, and HAR configuration.
HTTP trace-level rendering
help/http.go
Adds trace-level table rows, capture descriptions, incremental capture output, and command-line flag formatting.
Help rendering and trace validation
help/help_suite_test.go, help/help_test.go
Adds Ginkgo test setup and coverage for topic selection, output formats, configuration keys, and trace-level rendering.

Sequence Diagram(s)

sequenceDiagram
  participant HTTPClient
  participant Registry
  participant HARMiddleware
  participant HARCollector
  participant WriteFile
  HTTPClient->>Registry: request capture transport
  Registry->>HARMiddleware: select metadata or full capture
  HTTPClient->>HARMiddleware: execute HTTP request
  HARMiddleware->>HARCollector: record HAR entry
  Registry->>WriteFile: flush collector
  WriteFile-->>Registry: write HAR archive
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two primary changes: HAR capture and runtime help.
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.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/har-capture-runtime-help
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/har-capture-runtime-help

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.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Gavel summary

Source Pass Fail Skip Duration
collections 60 0 0 3.1s
files 41 0 0 89ms
github.com/flanksource/commons/certs 4 0 0 310ms
github.com/flanksource/commons/cmd/hx 8 0 0 -
github.com/flanksource/commons/cmd/hx/parse 26 0 0 -
github.com/flanksource/commons/collections/syncmap 10 0 0 -
github.com/flanksource/commons/context 1 0 0 -
github.com/flanksource/commons/duration 2 0 0 -
github.com/flanksource/commons/files 16 0 0 -
github.com/flanksource/commons/har 52 0 0 50ms
github.com/flanksource/commons/hash 13 0 0 -
github.com/flanksource/commons/http 95 0 2 11.8s
github.com/flanksource/commons/logger 49 0 0 -
github.com/flanksource/commons/logger/httpretty/internal/color 15 0 0 -
github.com/flanksource/commons/logger/httpretty/internal/header 1 0 0 -
github.com/flanksource/commons/lookup 7 0 0 10ms
github.com/flanksource/commons/merge 28 0 0 -
github.com/flanksource/commons/test 5 0 1 20ms
github.com/flanksource/commons/text 1 0 0 -
github.com/flanksource/commons/tokenizer 3 0 0 -
help 11 0 0 8ms
logger 41 0 0 2ms
set 7 0 0 7ms

Totals: 496 passed · 0 failed · 3 skipped · 15.4s

View full results

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
http/client.go (1)

834-839: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Install the metadata HAR middleware through harMiddlewares.

HARCollector appends to harMiddlewares, but HARMetadata calls Client.Use, which appends to transportMiddlewares. The round-trip applies harMiddlewares internally before transportMiddlewares, so metadata capture runs outer to auth headers. Call c.HARCollector(collector) for HARMetadata, or mirror HARCollector’s harMiddlewares append in this branch.

🤖 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 `@http/client.go` around lines 834 - 839, Update the HARMetadata branch in the
level switch to install the metadata middleware through harMiddlewares, matching
HARCollector’s ordering; replace the Client.Use call with
c.HARCollector(collector) or the equivalent harMiddlewares append while
preserving the existing HARFull behavior.

Source: Coding guidelines

🧹 Nitpick comments (2)
har/level.go (1)

36-49: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

List every accepted value in the error text.

ParseLevel accepts off, none, debug, trace and bodies, but the error names only metadata, full and disabled. An operator who mistypes traces gets an error that hides the synonym they wanted.

♻️ Proposed message update
-		return def, fmt.Errorf("invalid HAR level %q: expected metadata, full or disabled", value)
+		return def, fmt.Errorf("invalid HAR level %q: expected one of disabled (off, none), metadata (debug) or full (trace, bodies)", value)
🤖 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 `@har/level.go` around lines 36 - 49, Update the invalid-value error returned
by ParseLevel to list every accepted non-empty value, including disabled, off,
none, metadata, debug, full, trace, and bodies, while preserving the existing
parsing behavior.
har/registry_test.go (1)

28-34: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Restore the previous property value, not the empty string.

setProperty clears the key on cleanup. Properties are process-global, and this file nests property scopes (TestRegistry_Level sets http.har in the parent test and http.har.level in each subtest). No current test sets the same key at two levels, so the tests pass today. If a future subtest overrides a key its parent set, the subtest cleanup will clear the parent value for the remaining subtests, and the failure will look unrelated.

♻️ Proposed change
 func setProperty(t *testing.T, key, value string) {
 	t.Helper()
+	previous := properties.String("", key)
 	properties.Set(key, value)
-	t.Cleanup(func() { properties.Set(key, "") })
+	t.Cleanup(func() { properties.Set(key, previous) })
 }
🤖 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 `@har/registry_test.go` around lines 28 - 34, Update setProperty to capture the
property’s existing value before calling properties.Set, then restore that
captured value in t.Cleanup instead of always setting the key to an empty
string. Preserve the current test-scoped setup and cleanup behavior for
properties without a prior value.
🤖 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 `@har/write.go`:
- Around line 29-37: Update Registry.Flush and the fileMode-related write flow
so that when collector.Config.CaptureSensitive is true, the HAR file mode is
explicitly set to 0600 after os.WriteFile succeeds, including for existing
files; preserve the current 0644 behavior for non-sensitive output.

---

Outside diff comments:
In `@http/client.go`:
- Around line 834-839: Update the HARMetadata branch in the level switch to
install the metadata middleware through harMiddlewares, matching HARCollector’s
ordering; replace the Client.Use call with c.HARCollector(collector) or the
equivalent harMiddlewares append while preserving the existing HARFull behavior.

---

Nitpick comments:
In `@har/level.go`:
- Around line 36-49: Update the invalid-value error returned by ParseLevel to
list every accepted non-empty value, including disabled, off, none, metadata,
debug, full, trace, and bodies, while preserving the existing parsing behavior.

In `@har/registry_test.go`:
- Around line 28-34: Update setProperty to capture the property’s existing value
before calling properties.Set, then restore that captured value in t.Cleanup
instead of always setting the key to an empty string. Preserve the current
test-scoped setup and cleanup behavior for properties without a prior value.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 62748455-f844-4c43-b03b-4ea0db2d82af

📥 Commits

Reviewing files that changed from the base of the PR and between 84ca9f9 and 471d66c.

📒 Files selected for processing (16)
  • har/har.go
  • har/level.go
  • har/metadata.go
  • har/middleware.go
  • har/middleware_test.go
  • har/registry.go
  • har/registry_test.go
  • har/write.go
  • help/format.go
  • help/har.go
  • help/help.go
  • help/help_suite_test.go
  • help/help_test.go
  • help/http.go
  • help/logging.go
  • http/client.go

Comment thread har/write.go
Comment on lines +29 to +37
return os.WriteFile(path, append(data, '\n'), fileMode(collector))
}

func fileMode(collector *Collector) fs.FileMode {
if collector != nil && collector.Config.CaptureSensitive {
return 0o600
}
return 0o644
}

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm no other code chmods the HAR file after WriteFile, and check
# whether any caller reuses an existing HAR path across runs.
rg -nP -C4 '\bWriteFile\s*\(|\bos\.Chmod\s*\(' --type=go
rg -nP -C6 'func \(r \*Registry\) Flush' --type=go

Repository: flanksource/commons

Length of output: 157


🏁 Script executed:

#!/bin/bash
set +e
printf 'Files of interest:\n'
git ls-files | rg '(^|/)har/(write\.go|registry\.go|collector\.go|har\.go|registry_test\.go|.*\.go)$|(^|/)http/client\.go$' || true
printf '\nWriteFile and Chmod grep:\n'
rg -n -C4 '\bWriteFile\s*\(|\bos\.Chmod\s*\(' -t go || true
printf '\nRegistry flush:\n'
rg -n -C6 'func \(r \*Registry\) Flush' -t go || true
printf '\nRelevant source snippets:\n'
for f in har/write.go har/registry.go http/client.go har/registry_test.go; do
  if [ -f "$f" ]; then
    echo "---- $f ----"
    wc -l "$f"
    sed -n '1,140p' "$f"
  fi
done

Repository: flanksource/commons

Length of output: 437


🏁 Script executed:

#!/bin/bash
set +e
printf 'WriteFile and Chmod grep:\n'
rg -n -C4 'WriteFile\s*\(|\bos\.Chmod\s*\(' -t go || true
printf '\nRegistry flush:\n'
rg -n -C6 'func \(r \*Registry\) Flush' -t go || true
printf '\nWriteHARFile callers:\n'
rg -n -C4 'WriteHARFile\(' -t go || true
printf '\nhar/write.go:\n'
sed -n '1,80p' har/write.go
printf '\nhar/registry.go flush section:\n'
sed -n '80,140p' har/registry.go
printf '\nhttp/client.go around WriteHARFile:\n'
sed -n '820,870p' http/client.go
printf '\nregistry tests relevant section:\n'
sed -n '300,365p' har/registry_test.go

Repository: flanksource/commons

Length of output: 183


Sensitive Data Exposure (CWE-732): Incorrect Permission Assignment for Critical Resource

Reachability: Internal

Reachability path
● Entry
  har/middleware_test.go
│
▼
● Hop
  http/client.go:352
  Transport
│
▼
● Hop
  har/registry.go:104
  Flush
│
▼
● Sink
  har/write.go

Enforce 0600 on an existing sensitive HAR file.

os.WriteFile only applies the mode when it creates the file. If path already exists, Registry.Flush can leave a sensitive archive group- and world-readable, including when it overwrites a prior non-sensitive run. Set the mode explicitly after the write when collector.Config.CaptureSensitive is true.

🔒️ Proposed fix
 	data, err := json.MarshalIndent(file, "", "  ")
 	if err != nil {
 		return fmt.Errorf("marshal HAR: %w", err)
 	}
-	return os.WriteFile(path, append(data, '\n'), fileMode(collector))
+	mode := fileMode(collector)
+	if err := os.WriteFile(path, append(data, '\n'), mode); err != nil {
+		return err
+	}
+	// os.WriteFile honours mode only on creation; an archive holding live
+	// credentials must not inherit a looser mode from a previous run.
+	return os.Chmod(path, mode)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return os.WriteFile(path, append(data, '\n'), fileMode(collector))
}
func fileMode(collector *Collector) fs.FileMode {
if collector != nil && collector.Config.CaptureSensitive {
return 0o600
}
return 0o644
}
mode := fileMode(collector)
if err := os.WriteFile(path, append(data, '\n'), mode); err != nil {
return err
}
// os.WriteFile honours mode only on creation; an archive holding live
// credentials must not inherit a looser mode from a previous run.
return os.Chmod(path, mode)
}
func fileMode(collector *Collector) fs.FileMode {
if collector != nil && collector.Config.CaptureSensitive {
return 0o600
}
return 0o644
}
🤖 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 `@har/write.go` around lines 29 - 37, Update Registry.Flush and the
fileMode-related write flow so that when collector.Config.CaptureSensitive is
true, the HAR file mode is explicitly set to 0600 after os.WriteFile succeeds,
including for existing files; preserve the current 0644 behavior for
non-sensitive output.

@moshloop
moshloop merged commit a09cb96 into master Aug 4, 2026
11 checks passed
@moshloop
moshloop deleted the feat/har-capture-runtime-help branch August 4, 2026 19:29
@flankbot

flankbot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.55.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants