0.8.93
Added
- Eval packs can now be discovered from installed packages (#3124). Package
eval discovery includes the root package plus materialized dependencies under
.harn/packages/<alias>/, soharn test package --evalsand root
eval_pack://...trigger handlers can run published eval packs through the
existing package-manager install path. .harnworker/job execution surface (#3171). Apub fnannotated
with@job("name")is now a worker entrypoint that runs on harn-serve.
harn run --as-job <file.harn> --job <name> --request <req.json> [--result-out <out.json>]runs it once against a JSON request, delivers
the request to the handler asevent.provider_payload.raw, and prints
the value the job returns as a JSON report — the drop-in shape for
read-request → do-work → emit-report workers. The job is lowered into a
trigger binding and dispatched through the existing trigger dispatcher,
so retry (@job("name", retry: { max: 3, backoff: "exponential" })),
dead-letter, per-dispatch@budget(...), scopes, and cancellation are
inherited from the dispatcher rather than re-implemented.@scheduleand
@queueattributes are parsed for the forthcomingharn serve worker
daemon. Malformed forms surfaceHARN-SRV-004..008diagnostics.
Changed
- Compiler constant-pool building. The bytecode compiler now indexes
constants while emitting chunks, avoiding quadratic duplicate scans in
generated scripts with many literals. - Harmonized
gpt-ossto a single tool-format default and dropped the stale
heredoctextpins left on the local devstral / llamacpp-qwen rows after the
fenced-json default flip. Previously the samegpt-ossmodel resolved three
ways: cerebras and groq pinnedpreferred_tool_format = "native"while
together inherited the new globaljsondefault — a correctness bug. All
threegpt-osscapability rows now inheritjson(the cerebras/groq rows drop
theirnative_tools/preferred_tool_format = "native"pins so they match
together). native is the evidenced-bad direction here:gpt-ossnative
streaming tool-calls have returned empty payloads in evals;jsonis
structurally delimiter-safe and beats heredoctext. - Dropped the explicit
preferred_tool_format = "text"pins on the llamacpp
*qwen3.6*/*qwen3*and the llamacpp + ollamadevstral-small-2*
capability rows so they inherit the globaljsondefault like their siblings.
The qwen rows keepreserved_tool_call_token = true(the remap still applies
whenever a heredoctextpin re-selects the tagged format; json's```tool
fence already sidesteps the reserved<tool_call>token). devstral has no
reserved-token constraint, so there was never a structural reason for the
heredoc pin. Confirmed live on the local-qwen3.6:8001route (json parses
delimiter-soupwrite_filecontent clean; heredoc leaks the<<EOF
delimiter); the devstral rows apply the same structural fix (not locally
reachable, backed by the audit's local-qwen3.6 json 3/3 vs heredoc 0/3).
Fixed
- Debugging and test-result edge cases. Conditional breakpoint fallback
evaluation now reports unknown or non-numeric conditions instead of silently
firing, JUnit duration parsing saturates hostile timestamps instead of
panicking, HTTP download byte counts no longer wrap, andto_intnow follows
the documented bool and invalid-float behavior. pg_migratenow recycles prepared-statement caches after DDL, and a few
std/postgresbind/setting edge cases are tightened. (1) After a migration
runs DDL, a pooled connection could reuse a cached query plan whose result
type the DDL changed and fail withcached plan must not change result type
(SQLSTATE0A000).pg_migratenow clears the pool's cached statements (and
the per-slot OID describe cache) once after applying any migration, so the
next query re-prepares cleanly. (2) An out-of-range integer bound into a
narrow (int4/int2) column now surfaces a stablenumeric_out_of_range
(SQLSTATE22003) diagnostic instead of a raw message; in-range integers bind
and round-trip correctly. (3) Anilvalue inpg_transaction(settings)is
rejected instead of being silently set as the literal text"nil".
Security
- Outbound HTTP now has a DNS-resolving SSRF/egress guard, on by default
underharn run(#3172). A new private-address classifier blocks loopback,
RFC 1918, link-local (including the169.254.169.254cloud-metadata
endpoint), broadcast, unspecified, multicast, documentation, CGNAT
(100.64/10), and benchmark (198.18/15) ranges, plus the IPv6 analogues
and IPv4-mapped addresses. URL pre-checks classify literal IPs synchronously
and resolve host names off the runtime, and a connect-timereqwestDNS
resolver re-validates every resolved address so DNS rebinding cannot reach a
private target after the check.http_*,http_download,http_stream_open,
andharness.net.*all inherit the guard through the shared client path.
Configure viaegress_policy({block_private: "private"|"off", allow_loopback: bool})orHARN_EGRESS_BLOCK_PRIVATE/HARN_EGRESS_ALLOW_LOOPBACK; the
private-block always wins overallowrules, and block reasons name only the
host so request secrets are never echoed. std/postgrestransaction settings are now allowlisted, and raw Postgres
error detail no longer leaks to.harncallers. Two hardening fixes to the
Postgres hostlib. (1)pg_transaction(settings)previously ranset_config
for any GUC key, so.harncode could set a privileged backend GUC
(role,session_authorization,is_superuser,search_path, …) to escape
row-level security at the Postgres level. Settings are now restricted to the
application's ownapp.*namespace (which RLS policies are written against)
plus the benignstatement_timeout/lock_timeout/
idle_in_transaction_session_timeoutGUCs; any other key is rejected with a
clear error. (2) A failing query/execute previously surfaced the raw Postgres
message — which embeds schema, relation, column, and constraint names — to the
caller. The hostlib boundary now maps database errors to stable, schema-free
categories (e.g.unique_violation (SQLSTATE 23505)) and keeps the full
detail in server-side tracing only.
Install / Upgrade
cargo install harn-cliFull Changelog: v0.8.92...v0.8.93