Skip to content

V0.9.14#75

Merged
Hendler merged 15 commits intomainfrom
v0.9.14
Apr 8, 2026
Merged

V0.9.14#75
Hendler merged 15 commits intomainfrom
v0.9.14

Conversation

@Hendler
Copy link
Copy Markdown
Contributor

@Hendler Hendler commented Apr 3, 2026

  • Config signing — agents can now sign their jacs.config.json at creation time and detect tampering on load. Full rotation-journal infrastructure ensures crash-safe key rotation with rollback recovery.
  • Key rotation hardening — rotate_with_mutex() replaces per-binding rotation logic so CLI, binding-core, and MCP all use the same full pipeline (journal, save, config re-sign). Transition proofs are cryptographically
    verifiable. 10 new edge-case integration tests and proptest-based crypto fuzzing added.
  • Security fixes — bounded gzip inflation during embedded-file export (prevents decompression bombs via JACS_MAX_DOCUMENT_SIZE cap), atomic owner-only password file creation (0600 permissions), rejection of
    group/world-readable .jacs_password files, symlink-safe journal writes.
  • Binding parity — rotate_keys wired through all bindings (Python, Node.js, Go, MCP). Tool counts updated to 29 core / 43 full. fastmcp import path updated for upstream rename.
  • License simplification — dual Apache-2.0/MIT → Apache-2.0 only. LICENSE-MIT removed.
  • Schema — jacsKeyRotationProof added to agent.schema.json (oldPublicKeyHash, newPublicKeyHash, signature, signingAlgorithm, timestamp, transitionMessage).

Key changes by area

Core (jacs/src/)

  • agent/mod.rs: Config-signing verification on load, rotation journal recovery, warn_if_config_tampered(), verify_transition_proof()
  • keystore/mod.rs: Rotation journal (create/load/complete/cleanup), secure journal file I/O, algorithm validation
  • config/mod.rs: is_signed/raw_json fields, sign_config_file(), tamper detection
  • agent/document.rs: Bounded gzip inflation via decode_embedded_gzip_base64()
  • dns/bootstrap.rs: Version-date ordering preferred over mtime

Bindings

  • binding-core: rotate_with_mutex(), rotate_keys CLI command, MCP jacs_rotate_keys tool
  • jacsnpm: rotateKeys on JacsSimpleAgent, RotationResult TypeScript type, client async/sync pair
  • jacspy: rotate_keys on PyO3 class, mcp.py refactored for fastmcp import
  • jacsgo: Parity map updated

Tests (102 files, +5782/-1078)

  • config_signing_integration.rs — 814 lines of config signing tests
  • rotation_edge_case_tests.rs — 10 edge-case integration tests
  • proptest_crypto.rs — property-based crypto fuzzing
  • Cross-binding parity and MCP contract snapshot updates

Test plan

  • cargo test -p jacs --features attestation
  • cargo test -p jacs-binding-core --features a2a,attestation
  • cargo test -p jacs-mcp
  • cd jacsnpm && npm test
  • cd jacspy && pytest
  • Verify jacs rotate-keys CLI command works end-to-end
  • Verify config signing on fresh jacs quickstart

Hendler added 15 commits March 29, 2026 18:54
  - Add config signing/verification: sign_config, verify_config, update_config
    on Agent. Configs are signed on create, rotation, and migration. Unsigned
    configs still load (backward compat) with a warning logged on tamper detection.
  - Add agent_email field to config schema and Config struct.
  - Simplify license from "Apache-2.0 OR MIT" to "Apache-2.0" across all crates,
    package.json, pyproject.toml, deny.toml, docs, and README. Remove LICENSE-MIT.
  - Fix DNS TXT record parsing: filter for v=jacs records among SPF/DKIM/DMARC
    (new find_jacs_txt_record function with 4 tests).
  - Replace .unwrap() with proper error propagation on poisoned mutexes in
    InMemoryKeyStore (4 tests).
  - Bump fips204 0.4.3 → 0.4.6.
  - Add TODO comments for ML-DSA context hardening and agreement .expect() cleanup.
  - Integration tests for config signing across create, rotate, and migrate paths.
…ne 42), document.rs (line 804). Exporting embedded jacsFiles.contents would inflate attacker-controlled gzip data without a hard cap. It now stops at JACS_MAX_DOCUMENT_SIZE and fails with DocumentTooLarge instead of allowing decompression-bomb behavior.

Insecure shared password-file handling: lib.rs (line 236), lib.rs (line 561). The binding core now rejects Unix .jacs_password files that are group/world readable, and auto-generated password files are created atomically with owner-only permissions (0600) instead of write-then-chmod.

     1. Crash during rotation (High risk) -- If the process dies after rotate_self() but before the config is re-written, keys and config become inconsistent. The fix is a write-ahead journal file in the key directory that
      enables auto-repair on next load.
     2. No transition signature (Medium risk) -- The documented JACS_KEY_ROTATION:{id}:{old_hash}:{new_hash}:{timestamp} pattern exists only in docs, never in code. The fix generates a jacsKeyRotationProof signed with the
     OLD key and embeds it in the agent document.
     3. CLI commands unimplemented (Medium risk) -- jacs agent rotate-keys, keys list, and keys revoke are marked "Coming Soon" in docs but do not exist. The fix adds three CLI commands and binding-core/Python/Node/Go/MCP
     wrappers.
     4. Algorithm field stale on cross-algorithm rotation (Low risk) -- The fix adds an algorithm parameter to rotate() and rotate_self() so cross-algorithm rotation is atomic.
  - Issue 001 (Critical): Tasks 005-007 implemented (CLI, binding-core, MCP)
  - Issue 002 (High): Added Agent::verify_transition_proof() + test
  - Issue 003 (High): Fixed vacuous assertion in test_double_rotation_preserves_chain
  - Issue 004 (High): Fixed double config repair in apply_config_and_load
  - Issue 011 (Critical): Refactored to rotate_with_mutex() — binding-core and MCP now use the full rotation pipeline (journal, save, config re-sign)
  - Issue 012 (High): Added test_transition_proof_verifiable_with_old_key test

  Still outstanding (lower priority):
  - Issue 005 (Medium): Algorithm validation in rotate_self()
  - Issue 006 (Medium): Journal load() silently swallows parse errors
  - Issue 008 (High): Some specified unit tests still missing
  - Issue 010 (Low): jacsKeyRotationProof not in agent schema
  - Issue 013 (High): Python/Node/Go binding wrappers
  - Issues 014-019: Medium/Low remaining items
  - Task 008: Dedicated rotation_edge_case_tests.rs file
  - Task 009: Docs and "Coming Soon" cleanup
…, MCP)

  - Issue 002 (High): Added Agent::verify_transition_proof() + test
  - Issue 003 (High): Fixed vacuous assertion in test_double_rotation_preserves_chain
  - Issue 004 (High): Fixed double config repair in apply_config_and_load
  - Issue 011 (Critical): Refactored to rotate_with_mutex() — binding-core and MCP now use the full rotation pipeline (journal, save, config re-sign)
  - Issue 012 (High): Added test_transition_proof_verifiable_with_old_key test
…───────────────────────────────────┐

  │   Issue    │ Status │                                  What was done                                   │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 005 (Med)  │ Done   │ Algorithm validation in rotate_self() against known set                          │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 006 (Med)  │ Done   │ Journal load() logs warnings instead of silently swallowing                      │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 008 (High) │ Done   │ 3 new unit tests added to config_signing_integration                             │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 010 (Low)  │ Done   │ jacsKeyRotationProof added to agent.schema.json                                  │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 013 (High) │ Done   │ Python + Node binding wrappers for rotate_keys                                   │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 016 (Med)  │ Done   │ Chain-linkage assertions in double rotation test                                 │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 017 (Low)  │ Done   │ "Coming Soon" labels removed from docs, new sections added                       │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ 019 (Low)  │ Done   │ jacsVersionDate preferred over mtime for version ordering                        │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ Task 008   │ Done   │ rotation_edge_case_tests.rs — 10 integration tests                               │
  ├────────────┼────────┼──────────────────────────────────────────────────────────────────────────────────┤
  │ Task 009   │ Done   │ Docs updated with Transition Signature, Crash Recovery, Cross-Algorithm sections │
  └────────────┴────────┴──────────────────────────────────────────────────────────────────────────────────┘
…───────────────────────────────────┐

  │ Workflow │                      Root Cause                      │               Status               │
  ├──────────┼──────────────────────────────────────────────────────┼────────────────────────────────────┤
  │ Python   │ rotate_keys missing from parity map                  │ Fixed in 5abfc86 (already pushed) │
  ├──────────┼──────────────────────────────────────────────────────┼────────────────────────────────────┤
  │ Go       │ rotate_keys parity + MCP contract drift              │ Fixed in 5abfc86 (already pushed) │
  ├──────────┼──────────────────────────────────────────────────────┼────────────────────────────────────┤
  │ MCP      │ Tool count 42→43                                     │ Fixed in 5abfc86 (already pushed) │
  ├──────────┼──────────────────────────────────────────────────────┼────────────────────────────────────┤
  │ Node.js  │ rotateKeys on JacsAgent only, NOT on JacsSimpleAgent │ Fixed locally (new)                │
  └──────────┴──────────────────────────────────────────────────────┴────────────────────────────────────┘
… added to parity maps, MCP 42→43)

  2. Node.js — rotateKeys added to JacsSimpleAgent class in jacsnpm/src/lib.rs (was only on legacy JacsAgent)
  3. MCP core-tools count — updated 28→29 in profiles.rs (preventive fix for non-full-tools builds)
…ry other method on the class (delegate to self.inner, convert via .to_napi()). Correctly sync-only, matching the JacsSimpleAgent design.

  - Tool counts — 29 core = 6+3+5+4+5+1+5 and 43 full = 29+4+3+3+4. Both verified against actual tool registration code.
  - Delegation chain is clean — every binding goes through SimpleAgentWrapper → Rust core rotate(). No layer does bespoke rotation logic.
  - client.ts — async/sync pair follows the v0.7.0 pattern. RotationResult TypeScript interface has correct field types including transition_proof: string | null matching Rust's Option<String>.
  - Generated files (index.d.ts, client.d.ts, client.js) — consistent with source changes.
  - mcp.py refactor — fastmcp import update from mcp.server.fastmcp to fastmcp (the package was renamed/restructured upstream). No behavioral changes to signing/verification.
@Hendler Hendler merged commit d84fa84 into main Apr 8, 2026
15 checks passed
@Hendler Hendler deleted the v0.9.14 branch April 8, 2026 14:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant