Repository navigation
feat: add --redact/--compress/--open for heap-dump, jstall bundle, and JRE-only fallback - #56
Open
parttimenerd wants to merge 97 commits into
Open
parttimenerd wants to merge 97 commits into
parttimenerd wants to merge 97 commits into
Conversation
- Embeds hprof-redact binaries (linux/amd64, linux/arm64, darwin/arm64, windows/amd64) via //go:embed; extracted to ~/.cache/cf-java-plugin/ on first use (SHA8-keyed, reused on subsequent runs). - --compress: passes gz=1 to jmap (JDK 17+) to compress the dump on the remote container before transfer, saving bandwidth. jvmmon path falls back to post-creation gzip on the container. Output is .hprof.gz. - --redact: pipes the downloaded dump through hprof-redact (lean mode: zeros primitive arrays only). Output is -redacted.hprof or -redacted.hprof.gz when --compress is also set. - --redact-complete: like --redact but zeros all primitive values (instance scalar fields + CLASS_DUMP statics) via two-pass redaction. - --compress and --redact can be combined: compress on remote to reduce transfer, redact locally (hprof-redact reads .hprof.gz natively). - Adds FindHeapDumpGzFile to utils for locating *.hprof.gz on the container (jvmmon+compress path). - Extracts osWindows and cmdHeapDump constants to satisfy goconst.
- hprof-analyzer release.yml: add aarch64-pc-windows-msvc target on windows-11-arm runner; compile-all includes GOOS=windows GOARCH=arm64 - redact.go: embed dist/hprof-redact-windows-arm64.exe (stub until v0.3.1 ships); add windows/arm64 case; guard against 0-byte stubs - cfutils.go: add CopyOverCatGunzip (io.Pipe + compress/gzip for transparent streaming decompression) and ProbeRemoteFileGzip (checks gzip magic bytes 1f8b via SSH) - cf_cli_java_plugin.go: heap-dump SSHCommand now uses shell-level gz probe (jmap -h | grep gz) so jmap auto-uses gz=1 on JDK 17+; Go post-command probes the remote file magic bytes to decide: - remote gz + no --compress → CopyOverCatGunzip, save as .hprof - remote gz + --compress → CopyOverCat, save as .hprof.gz - not gz + --compress → warn JDK 17+ required, save uncompressed Removes @JMAP_GZ Go expansion (replaced by shell probe); keeps @COMPRESS_FLAG for jvmmon path
- appInstanceIndexSet: simonleung8/flags IsSet() returns true for any registered flag whose non-zero default was set at init time, making it impossible to distinguish user-provided from default. Compare against known default (-1) instead. - CheckRequiredTools wrapped in !options.DryRun guard so dry-run works without CF login or SSH access. - var err declaration hoisted before GenerateFiles block (needed after CheckRequiredTools was scoped inside the if block).
…-dump - Feature list in intro - Examples: --redact, --redact-complete, --compress, combined usage - New "Heap Dump Privacy" subsection: redaction modes table, what is preserved, file naming, supported platforms - New "Compressed Transfer" subsection: JDK 17+ requirement, fallback behaviour, transparent gz transfer without --compress - CHANGELOG [Unreleased]: all four new behaviours
- Use context.WithTimeout(context.Background(), 5s) for srv.Shutdown instead of the request context (which may already be canceled); suppress contextcheck lint with explanation since this is intentional - Add empty title arg to Windows `cmd /c start` to avoid URL being interpreted as the window title - Replace non-blocking done-channel check in test with a 2s timeout select to avoid a false-pass race condition
…eakage and restrict access to single file
… in serveFileOnce
…s only affects local file format
golangci-lint typecheck fails when the dist/ hprof-redact binaries are missing (go:embed pattern not satisfied). Add a download step mirroring build.py, placed after the existing jstall download and before lint.
The previous attempt tried to curl the binaries directly, but they are packed inside tar.gz/zip archives. Add --deps-only flag to build.py to run only the download+extraction step (no go build), and use it in the PR validation workflow before golangci-lint.
dbriemann
reviewed
Sep 18, 2026
ansteiner
requested changes
Sep 18, 2026
…uffer The 192 KB file fit entirely in the kernel TCP send buffer, so io.Copy completed successfully even after the client disconnected — spuriously triggering server shutdown and failing the test. Also updates dist/jstall-minimal.jar with the vm-vitals two-section fix (recent samples + extremes capped at max(10, topN)).
Update dist/jstall-minimal.jar to v0.8.2 (vm-vitals parser rewrite, Trends + Observations sections, heap-comm/meta-comm duplicate-column fix). Update CHANGELOG to document the new vm-vitals features. Add two unit tests covering the app/command swap-detection logic.
Update dist/jstall-minimal.jar to latest jstall main branch nightly (includes v0.8.3 trend-legend footnote and v0.8.4 --vital-rows fixes). Switch all CI workflows from releases/latest curl download to 'gh run download -R parttimenerd/jstall -n jstall-minimal-jar' so PRs and releases always embed the latest unreleased nightly. Update snapshot/release version reporting to show commit SHA + run ID.
…ain" This reverts commit f8dcf7f.
…ed on all runners
… is UTF-8 on Windows
- All three workflow files now download jstall-minimal.jar from v0.8.6 release - buildJstallArgs passes --unicode off so jstall always uses ASCII output when invoked from the CF plugin; avoids Unicode arrow garbling on Windows CP1252 terminals regardless of local JVM encoding settings
femtocli routes --unicode to BaseAnalyzerCommand (the subcommand), not to Main, so it must appear after the subcommand name in the arg list. Previous position (before jstallArgs which contains the subcommand) caused 'Unknown option: --unicode' errors. Adds a test asserting --unicode comes after the subcommand.
Previous jstall-minimal.jar embedded in the v0.8.6 release was actually v0.8.5 content (Main.java wasn't bumped). This updates to the corrected v0.8.6 JAR that properly reports --version 0.8.6 and includes: - Symbols class for guaranteed ASCII output (--unicode off) - --unicode flag on BaseAnalyzerCommand subcommands
All three CI workflows previously pinned jstall to a hardcoded tag (v0.8.6). Switch to 'gh release download' without a tag so CI always picks up the latest published release. After downloading, run 'java -jar jstall-minimal.jar --version' and compare against the release tag — fails the build if they don't match (catches stale or incorrectly assembled JARs before they get embedded). Also add 'make verify-jstall' as a local convenience target.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New heap-dump flags
--redact: zeros primitive arrays (byte[],char[], etc.) before saving (lean redaction mode). Uses the bundled hprof-redact binary. Supported on Linux (amd64/arm64), macOS (Apple Silicon), Windows (amd64/arm64).--redact-complete: zeros all primitive arrays and individual primitive fields (complete redaction, maximum privacy). Mutually exclusive with--redact.--compress: saves the dump as.hprof.gzinstead of decompressing after transfer (requires JDK 17+ on container).jmap gz=1to reduce SSH transfer size, decompressing on the fly.--compresskeeps the file compressed locally.--open: after downloading, spins up a temporary single-serve local HTTP server and opens hprof-analyzer in the browser with the dump pre-loaded. Server shuts down automatically after the file is fetched once.--open-url <URL>: override the hprof-analyzer base URL (e.g. a locally running instance). Implies--open.Bundled jstall (JVM inspection)
cf java jstall APP_NAME(or thestatus/record-statusshortcuts). Requires Java 17+ locally.status(thread analysis, metaspace, GC, compiler queue),record-status(repeated sampling),flame-graph,heap-info. All jstall subcommands available via--args.JRE-only container support
heap-dump,thread-dump,vm-info,vm-version,jcmd, and all jstall-based commands now work on containers without JDK tools (jmap,jstack,jcmd) by falling back to the HotSpot attach socket vianc -U.netcat-openbsdornmap-ncaton the container. Supports JDK 9–25 on Linux and macOS.Windows fixes
cf install-plugin <URL>now works on Windows: Windows binary released ascf-cli-java-plugin-windows-amd64.exe(with.exe). CF CLI previously rejected the temp file without the extension.cf java statusand other jstall-based commands now work on Windows: JVM propertyjdk.lang.Process.allowAmbiguousCommands=falseensures embedded quotes in remote shell payloads are correctly escaped viaProcessBuilder.UX improvements
cf java my-app heap-dump): suggests the corrected command if the first argument matches a known app.Maintenance
upload-artifactto v7,download-artifactto v8.darwin/amd64dropped.Security notes (
--open)127.0.0.1only (loopback, not reachable from network)io.Copydirectly (nothttp.ServeFile) to prevent path traversal