RockyGuard

Changelog

Release notes

RockyGuard follows Semantic Versioning 2.0.0. The format below mirrors Keep a Changelog; the source-of-truth file is shipped in the repo as CHANGELOG.md.

v1.3.2

2026-08-19

Patch release

  • Evaluation mints are metered separately from your shippable-license budget. A license issued with an expiry inside 7 days — including one already expired — no longer spends max_end_user_licenses. That budget exists to meter licenses a vendor ships; the licenses an integrator mints to exercise the failure paths (a pre-expired one for the expiry branch, a fingerprint-mismatched one to watch node-locking refuse) are not those, and counting them identically meant a careful evaluation could exhaust a small budget without producing a single shippable license.
  • The exemption carries its own ceiling (kMaxEvaluationMints, 100 per vendor license, on a separate counter with a separate HMAC). Unbounded it would be a way around max_end_user_licenses entirely — issue 7-day licenses and re-issue them on a rotation. Vendors with an unlimited budget are unmetered on both paths, exactly as before.
  • New License::is_evaluation_mint() on the public struct, documented in Customer_API_Reference §5.9. Verification never consults it: a short-dated license verifies and expires exactly like any other.
  • Free Developer tier raised from 10 end-user licenses to 50.
  • Test suite: 134, up from 131.

v1.3.1

2026-08-19

Patch release

  • Fixed: a valid license could be denied outright, unrecoverably. Each time anchor was integrity-protected with an HMAC salted by that anchor's own filesystem path, exactly as the caller spelled it — so the integrity tag depended on how the license was named rather than on which anchor it is. Any change in spelling turned an intact anchor into a failed integrity check, reported as tampering, which is deliberately never self-repaired. Upgrading is recommended for every deployment.
  • The sharp case, reported from a real integration: load() resolved the local anchor relative to the process working directory while check_expiry() resolved it against the license's own directory. When those were the same directory, both named one file — written under one salt, read under another. Deleting the file did not help, because the next run regenerated the identical mismatch, which is why the documented "delete the state files and retry" remedy never cleared it.
  • The same defect covered renaming or moving an install directory, mixing relative and absolute license paths across runs, and on Windows drive-letter case, mapped drives and junctions. The salt is now a stable per-location identifier, independent of the filesystem.
  • Migration is automatic and lossless: anchors written by v1.3.0 and earlier still verify, keep their rollback history, and are rewritten in the current form on the next successful check. No customer action required.
  • LicenseResult::status now defaults to a non-passing value. LicenseStatus::Valid is enumerator 0, so a value-initialised LicenseResult{} reported Valid and converted to true — a fail-open default. No library path was affected, but integrator code that declares a result up front and fills it in conditionally now fails closed.
  • Diagnostics: ROCKYGUARD_DEBUG_TIME_ANCHOR=1 now reports every anchor read (path, timestamp, verdict) rather than only the online time fetch, which the tamper path returns before reaching. The tamper message now names each resolved anchor path inline instead of pointing at a documentation section.
  • Test suite: 131, up from 129.

v1.3.0

2026-08-13

Third release

  • Short activation keys: license_create --output-key emits a Base32 key an end user can type, as an alternative to shipping a .lic file. LicenseVerifier::load_from_string() accepts either form and sniffs which it was given. A CRC32 inside the payload catches transcription errors before signature verification, so a mistyped key reports a mistyped key rather than a bad signature.
  • Heartbeat lifecycle callbacks: FloatingHeartbeatCallbacks surfaces connection-lost, connection-restored, license-revoked and give-up events, with max_heartbeat_failures bounding retries (0 keeps the v1.2.x retry-forever behaviour). Callbacks run on the heartbeat thread and must not call checkout() / checkin() — the re-entrancy contract is documented in the API reference.
  • Automatic re-checkout after a floating-server restart: opt in with recheckout_on_lease_lost and a wiped server lease pool is recovered transparently instead of surfacing as a revocation. Off by default, because some operators want a restart to drop every lease.
  • Per-IP rate limiting on the floating server: token bucket, defaults 50 rps / 250 burst, consumed before the TLS handshake so a flood is rejected cheaply. Set rate_limit_rps: 0 to disable.
  • Self-hosted licensing portal: a FastAPI web app under portal/ wraps license_create in a browser UI for non-technical licensing staff, with offline dependency wheels so first run needs no PyPI access. Entirely optional — everything it does is available from the CLI.
  • BREAKING (transport security): cleartext is now opt-in on both sides. The floating server refuses to start without tls_cert/tls_key unless allow_insecure_http: true is set, and FloatingLicenseClient throws at construction under the same condition, or when use_tls is set with no tls_ca_cert_path and no allow_insecure_tls. Both were silent downgrades before. A v1.2.x deployment with no TLS will refuse to start until the intent is stated in one line — deliberately, because the checkout response carries the session secret that authenticates every later request.
  • Windows GUI fingerprint tool: rg_fingerprint_gui.exe for end users who would double-click rather than open a terminal. rg_fingerprint (CLI) now writes the fingerprint to stdout, so FP=$(rg_fingerprint) and rg_fingerprint > fp.txt work as expected; previously both produced an empty result.
  • Upgrade/downgrade compatibility (Phase 8) executed for the first time on both platforms: legacy counter and anchor state read through the compatibility path, v1.2.x-issued licenses verify under the v1.3 verifier, and a downgrade to v1.2.1 neither crashes nor bypasses the generation limit.
  • Phase 4.1 onboarding dry-run, run for the first time against the shipped GA zips rather than a release candidate, and for the first time with a full six-stage cold read on both platforms — two isolated sub-agents, one per OS, neither able to see the source tree, the development history, or each other. It found 50 verified defects, 9 of them HIGH, and failed one stage outright. Four of the nine were Linux-only and structurally invisible to a Windows run, which is why the previous single-platform cold read had reported the package clean.
  • The failed stage was Premium TLS, and the cause was documentation, not code: the openssl req command in §5.2 generated a certificate with no subjectAltName, which OpenSSL 3 rejects for the 127.0.0.1 the client examples dial — so the only documented route to enabling the transport security this release made mandatory could not be followed to a working end state. Fixed, along with seven of the other eight HIGH findings, and both platforms repackaged; the demo bundles on this site are built from those zips. The ninth is the licence agreement's own template preamble, which is a decision for counsel rather than a documentation edit and is recorded as open.
  • Test suite: 128 tests on Windows, 126 on Linux (the difference is three Windows-only fingerprint/crypto cases and one Linux-only POSIX-permissions case), up from 69 / 66 at v1.2.1.

v1.2.1

2026-05-11

Second release

  • Runtime version-range enforcement: LicenseVerifier::check_version() consults the version_range field that v1.2.0 carried but did not enforce. Glob form ("3.*", "3.1.*") and comparator form (">=3.0,<4.0", "!=3.5.0") both supported.
  • Auto-detect signature algorithm: SignatureAlgorithm::AutoDetect is now the LicenseVerifier default; inspects the loaded key and dispatches to Ed25519 or RSA without the caller tracking the algorithm. Same applies to license_create --algo auto.
  • Per-machine seat cap for floating licenses: new max_leases_per_machine_id YAML key bounds the concurrent leases any one workstation can hold. Denied checkouts surface as MachineSeatLimitReached even when the global pool still has seats.
  • Floating-server log rotation: log_max_bytes (default 100 MiB) and log_keep_count (default 5, capped at 100). Replaces v1.2.0 unbounded growth; opt out by setting log_max_bytes <= 0.
  • License metadata pass-through: license_create --metadata key=value attaches arbitrary metadata that round-trips through sign / verify and surfaces as License::metadata. New --show-count flag for read-only inspection of the generation counter.
  • Debug-CRT static library on Windows: rockyguard_mdd.lib ships alongside rockyguard.lib so Debug-CRT consumers no longer hit LNK2038 / LNK1319 (closes GA-013).
  • AI-agent integration guide: AI_INTEGRATION_GUIDE.md at the customer-zip root and a dedicated page at /docs/ai-integration so customers can hand the integration to Claude Code, Cursor, Copilot, etc.
  • Phase 4.1 library defect closed: check_node_locked() with threshold == 0 and an empty hardware_fingerprint now ACCEPTS the license (the documented "intentionally not hardware-locked" opt-out), matching what the docs already promised.
  • ABI-compatible with v1.2.0: +5 customer-facing exported symbols (check_version + four gen_counter::* helpers), 0 removals. DUMPBIN /EXPORTS and nm -D probes both verify.
  • Test count: 59 / 56 (Win / Linux) at v1.2.0 grew to 69 / 66 at v1.2.1 (+10 each). Two new QA harnesses (ghost_checkout_exhaustion, log_rotation) both pass on Windows + Linux.

v1.2.0

2026-04-23

Inaugural shipping release

  • First public release. v1.2.0 is the inaugural shipping version of the library.
  • Linux x86_64 support (glibc 2.34 or newer) shipped alongside Windows x64 in per-platform zips.
  • Ten-phase pre-release QA plan now gates every release; full plan published as docs/RockyGuard_QA_Plan.txt.
  • Three independent Phase 4.1 customer-onboarding dry-runs (Windows + Linux full Stages 0-5) by isolated cold-read sub-agents; 16 gaps surfaced and 8 fixed in-session, the rest deferred to v1.2.1 with full transparency in the Phase 4.1 Report.
  • Eight late-cycle defects closed: WMI UTF-8 narrowing on Chinese / Japanese locale; floating-server JSON type-error crash-DoS; Windows system cert store not loaded for time-anchor TLS; sha256_file_hex short-read on locked DLL; Windows tools missing Control Flow Guard; session_secret leaked into debug logs via signed-envelope redaction; Quick Start linking docs missing libssl on Windows AND Linux; Release-CRT library cannot link Debug consumer builds (Windows).
  • 74 numbered code-review issues addressed across four review rounds (three internal + one external).
  • Per-platform README split, per-platform CMake build directories, append-only archives/MANIFEST.txt for audit-grade artifact tracking.