Repository navigation
v0.10.0
PerfLens 0.10.0
Highlights
The pre-launch stabilization pass. The project has never been shared
publicly; this closes what an audit turned up before it is.
Upgrading — read this first. The agent now requires a peer to
authenticate, and the hello no longer carries a token.
- Upgrade the server first, then the agents. A 0.10.0 agent sends no
hello token, so an older server started with--tokenwill reject it. A
0.10.0 server accepts a pre-0.10.0 agent on its hello token, with a
warning. --listennow needs a pairing code. The agent prints one at startup
when you don't supply--token; the server must present it. In the UI it
goes in the Live Debug wizard's new Pairing code field. Read it back on
the device withgrep -i "pairing code" /tmp/agent.log.--binddefaults to0.0.0.0, unchanged.
Security
- Authenticated agent control.
--listenbound every interface, accepted
any peer, and executed all 13 commands with no authentication — profiling
any PID, enumerating every process and command line, and triggering a
self-update. The agent now always holds a secret (--token, or one
generated from/dev/urandomand written to its log) and gates
dispatch_commandon the peer proving knowledge of it. Three failures, or
30 seconds without a valid code, drops the connection. - The agent no longer transmits its secret.
--tokenused to be embedded
in the hello — which, in--listenmode, is sent to whoever completes the
TCP handshake, before that peer has proved anything. A port scanner could
harvest the shared secret. The hello now carries no token at all. - The server no longer republishes agent tokens over HTTP.
AgentHello
had atokenfield returned verbatim byGET /api/agent. Removed, and
stripped from legacy agents' hellos on the compatibility path. - Device metrics no longer stream before authentication. The metrics
thread started on connect, sending CPU, memory, temperature and
per-process detail to unproven peers every 2s. updateis refused on a session with no configured pairing code, and
PERFLENS_UPDATE_URLpointing at a plaintexthttp://origin is refused.- Release assets now publish
.sha256sidecars, verified by
install-agent.shandperflens push-agent. The C agent does not verify
them — it carries no hash implementation. See SECURITY.md for what that
does and does not cover. - New SECURITY.md: threat model, what is deliberately not
protected (the channel is plaintext), and the deprecation timeline.
Fixed
GET /api/snapshotdeclared the wrong response schema. Without
?event=it returns{per_event, version}, but declared
SnapshotResponse, which requiresevent+data. The correct model
existed and was referenced by no route. The wrong type had already
propagated intofrontend/openapi.jsonand the generated TypeScript.--binarywas applied to every frame, including libc, libm and kernel
ones — 62k of 124k frames in the committed ARM fixture. Those addresses do
not exist in that file; it is also why ip-based line recovery needs its
span check. Shared objects and perf's bracketed pseudo-modules now resolve
against their own module path.make all-crossleft the last-built architecture's binary at
agent-c/perflens-agent, so a cross-compile silently replaced the native
binary and the protocol tests failed withExec format errorinstead of
skipping. Each architecture now builds intobuild/<arch>/, and the skip
guard checks that the binary actually runs on this host rather than only
that it is executable.- A
--serveragent that connected but failed to authenticate reset the
reconnect backoff, so a misconfigured fleet would reconnect once a second
per device indefinitely.
Added
--bind ADDRon the agent, for narrowing--listento a single interface.- Type checking, in a codebase that had none:
mypyoversrc/perflens
(clean), andfrontend/tsconfig.test.jsoncovering the ten.tsfiles
that were in no tsconfig project — the vitest specs, the Playwright e2e
spec, the docs-shots harness andplaywright.config.ts. Both run in CI. build.ymlgained apull_requesttrigger. Wheel packaging and the five
agent cross-compiles were post-merge discoveries.- Issue templates and a pull-request template.
Still open
Carried forward from 0.9.0, unaddressed by this pass:
- Server RSS still drifts ~3 MB/min after the sample ring fills, and did not
flatten within a 22-minute soak. The 0.9.0 interning work moved the plateau
from ~1.9 GB to ~1.1 GB but did not end the drift. - Big-endian remains compile-only. All five agent targets build and the
byte-order audit is clean, but no big-endian hardware was available, and
byte-order bugs are invisible on little-endian by construction. The new
pairing-code code is byte-order independent (it compares hex strings), so
this pass did not widen the exposure.
Tests
308 pytest (was 192), 24 vitest, 10 Playwright.
tests/test_line_oracle.py— line-level annotation checked against marker
comments in a hand-written C file rather than against captured output.
Both existing fixtures were produced by running the agent, so when
annotation regressed to reporting declaration lines, the fixtures recorded
the broken behaviour and 165 tests agreed with it. Verified non-vacuous:
fed the frame shape the regression produced, it fails.tests/test_response_models.py— validates every JSON route's real body
against its declaredresponse_model. Handlers return pre-serialized
orjson, so FastAPI skips validation and all 26 declared schemas went
unchecked. This is what found the/api/snapshotbug above.tests/test_agentlink_auth.py, driven by a pure-Python fake agent so the
server's half of the handshake is tested even whenagent-cis not built.tests/test_export.py,tests/test_cli.py— first coverage for either.- Agent protocol tests grew a
--listenharness mode (that direction had
never been tested at all) and auth coverage, including a regression test
that no metrics frame arrives before authentication.
Install
# Server (any machine with Python 3.10+; everything user-space):
uvx perflens # or: pipx install perflens
uvx --from ./perflens-0.10.0-py3-none-any.whl perflens # from this release
# Agent (on the target device — zero dependencies, no sudo):
curl -fsSL https://raw.githubusercontent.com/harshithsunku/perflens/master/install-agent.sh | shAssets
| Asset | What it is |
|---|---|
| perflens-0.10.0-py3-none-any.whl | Server — Python wheel |
| perflens-0.10.0.tar.gz | Server — Python sdist |
| perflens-agent-c-0.10.0-linux-aarch64.tar.gz | Agent — versioned tarball |
| perflens-agent-c-0.10.0-linux-aarch64_be.tar.gz | Agent — versioned tarball |
| perflens-agent-c-0.10.0-linux-armeb.tar.gz | Agent — versioned tarball |
| perflens-agent-c-0.10.0-linux-armv7.tar.gz | Agent — versioned tarball |
| perflens-agent-c-0.10.0-linux-x86_64.tar.gz | Agent — versioned tarball |
| perflens-agent-linux-aarch64 | Agent — static binary (stable name; used by install-agent.sh and --update) |
| perflens-agent-linux-aarch64.sha256 | Agent binary checksum |
| perflens-agent-linux-aarch64_be | Agent — static binary (stable name; used by install-agent.sh and --update) |
| perflens-agent-linux-aarch64_be.sha256 | Agent binary checksum |
| perflens-agent-linux-armeb | Agent — static binary (stable name; used by install-agent.sh and --update) |
| perflens-agent-linux-armeb.sha256 | Agent binary checksum |
| perflens-agent-linux-armv7 | Agent — static binary (stable name; used by install-agent.sh and --update) |
| perflens-agent-linux-armv7.sha256 | Agent binary checksum |
| perflens-agent-linux-x86_64 | Agent — static binary (stable name; used by install-agent.sh and --update) |
| perflens-agent-linux-x86_64.sha256 | Agent binary checksum |
| perflens-tools-linux-aarch64.tar.gz | Static addr2line+readelf for perflens provision |
| perflens-tools-linux-aarch64.tar.gz.sha256 | Tools bundle checksum |
| perflens-tools-linux-x86_64.tar.gz | Static addr2line+readelf for perflens provision |
| perflens-tools-linux-x86_64.tar.gz.sha256 | Tools bundle checksum |