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.4.0

2026-09-18

Minor release

  • › macOS x86_64 now ships in the standard package. Windows x64, Linux x64 (glibc 2.34+) and macOS 13+ are all built, tested and published from the same source each release; macOS was built on request before this. The macOS build is x86_64 only — there is no arm64 slice, so Apple Silicon is supported through an x86_64 (Rosetta) toolchain rather than natively. The hardware fingerprint on macOS reads IOKit for the platform UUID and enumerates every en* interface for the MAC component.
  • › Structured error codes. Every result now carries a LicenseErrorCode alongside the status, so calling code can branch on which failure occurred instead of matching English message text. Codes are grouped into reserved numeric blocks and the names are the stable contract — persist the name, not the number. The catalog is documented in Customer_API_Reference §5.9 and §4.5, and a test now enforces that every code in the catalog appears in that table.
  • › Licence Inspector: rg_inspect collects a redacted diagnostic report from a customer machine — licence state, clock anchors, fingerprint components, integrity status — and encrypts it to your support key. rg_report_read (vendor-only) opens it and names a probable root cause. Redaction is enforced by tests: MAC addresses and licence signatures are masked, never echoed. The collector ships as source so you can rebuild it with your own key.
  • › Opt-in runtime code-integrity self-check. A trust-on-first-use hash of the licence-validation code in memory, so a patched-out check is detectable at runtime rather than only at load. Off by default.
  • › Opt-in obfuscated build of the licence decision paths, compiled through an obfuscating Clang toolchain. Off by default and not used in the published binaries — every shipped zip this release is a plain build, and the manifest in the archive records that per artifact.
  • › The load-bearing licence pattern ships as a supported toolchain rather than a documented idea: rg_bind_asset seals a feature’s data under a key wrapped into the licence, rockyguard_bind_asset() wires it into your CMake, and rg_bind_lint checks you have not left the plaintext behind. A feature protected this way does not work when the licence check is removed, because the data is not there to use.
  • › ABI note: LicenseResult gained three members, appended at the end, so the struct changed size. Nothing was inserted or reordered and no existing field moved, but consumers must recompile rather than drop the new shared library beside an old executable.
  • › Rollback note: upgrading from v1.3.0 is automatic and needs no action. Rolling back from v1.4.0 to v1.3.0 does not work without deleting the anchor and counter state first. v1.3.1 changed the state HMAC salt and was never released publicly, so for anyone coming from v1.3.0 that change arrives with v1.4.0; v1.4.0 reads both formats but v1.3.0 reads only the old one and reports the newer state as “System clock manipulation detected”. The clock is not the problem — v1.3.0 maps every failed anchor check to that one message. Customer_Documentation §10.4 lists the paths to clear.
  • › Test suite: 321 on Windows, 319 on Linux, run as a gate on every release build.

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.