Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/jacs-mcp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Install system dependencies (D-Bus for keychain support)
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev pkg-config

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
Expand All @@ -50,3 +53,4 @@ jobs:
run: cargo test -p jacs-mcp --features full-tools --verbose
env:
JACS_MCP_PROFILE: full
JACS_KEYCHAIN_BACKEND: disabled
4 changes: 4 additions & 0 deletions .github/workflows/release-cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ jobs:
$requiredFiles | Set-Content -Path $manifest
tar -xf $archive -C $workspace --strip-components 1 -T $manifest

- name: Install system dependencies (D-Bus for keychain support)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev pkg-config

- uses: dtolnay/rust-toolchain@stable
with:
toolchain: '1.93'
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release-crate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install system dependencies (D-Bus for keychain support)
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev pkg-config

- uses: actions-rust-lang/setup-rust-toolchain@v1

- name: Pre-publish compile check (all crates)
Expand Down
39 changes: 34 additions & 5 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,20 @@ jobs:
- name: Validate schema $id fields match file paths
run: ./scripts/validate-schemas.sh

- name: Check no bare serial annotations
run: ./scripts/check-no-bare-serial.sh

quick-jacs:
name: Quick jacs core (ubuntu)
name: Quick jacs ${{ matrix.shard }} (ubuntu)
if: |
github.event_name == 'pull_request' ||
(github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/')) ||
(github.event_name == 'workflow_dispatch' && github.event.inputs.run_full != 'true')
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [lib, bin-shard-a, bin-shard-b]

steps:
- name: Checkout code
Expand All @@ -101,8 +108,8 @@ jobs:
- name: Cache cargo dependencies
uses: Swatinem/rust-cache@v2

- name: Run quick Rust test suite (core)
run: make test-jacs-fast
- name: Run quick Rust test suite (core - ${{ matrix.shard }})
run: make test-jacs-fast-${{ matrix.shard }}

quick-jacs-cli:
name: Quick jacs CLI (ubuntu)
Expand All @@ -116,6 +123,9 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Install system dependencies (D-Bus for keychain support)
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev pkg-config

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
Expand All @@ -126,6 +136,8 @@ jobs:

- name: Run CLI integration tests
run: make test-jacs-cli
env:
JACS_KEYCHAIN_BACKEND: disabled

quick-binding-core:
name: Quick binding-core (ubuntu)
Expand Down Expand Up @@ -216,6 +228,10 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Install system dependencies (D-Bus for keychain support)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev pkg-config

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
Expand All @@ -232,14 +248,18 @@ jobs:

- name: Run full jacs tests
run: |
cargo build -p jacs-cli
cargo test -p jacs --features agreements,a2a,attestation,pq-tests --lib --tests --verbose
cargo test -p jacs-binding-core --features pq-tests --lib --tests --verbose
cargo build -p jacs-cli
cargo test -p jacs-mcp --lib --tests --verbose
cargo test -p jacs-cli --verbose
env:
JACS_KEYCHAIN_BACKEND: disabled

- name: Run jacs-mcp tests (without attestation)
run: cargo test -p jacs-mcp --no-default-features --features mcp --lib --tests --verbose
env:
JACS_KEYCHAIN_BACKEND: disabled

- name: Run in-process backend crate tests (release)
run: |
Expand All @@ -251,6 +271,10 @@ jobs:
if: runner.os == 'Linux'
run: cargo test -p jacs-postgresql --lib --tests --verbose

- name: Keychain integration tests (macOS)
if: runner.os == 'macOS'
run: cargo test -p jacs --features keychain-tests -- keychain_macos --verbose

- name: Run cross-language and observability suites
run: |
make test-jacs-cross-language
Expand All @@ -265,6 +289,9 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4

- name: Install system dependencies (D-Bus for keychain support)
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev pkg-config

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
Expand All @@ -280,11 +307,13 @@ jobs:

- name: Run nightly full Rust tests
run: |
cargo build -p jacs-cli
cargo test -p jacs --features agreements,a2a,attestation,pq-tests --lib --tests --verbose
cargo test -p jacs-binding-core --features pq-tests --lib --tests --verbose
cargo build -p jacs-cli
cargo test -p jacs-mcp --lib --tests --verbose
cargo test -p jacs-cli --verbose
env:
JACS_KEYCHAIN_BACKEND: disabled

- name: Run jacs-mcp tests (without attestation)
run: cargo test -p jacs-mcp --no-default-features --features mcp --lib --tests --verbose
Expand Down
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
## 0.9.7 (unreleased)

### Features

- **OS Keychain Integration**: Store and retrieve private key passwords from the OS credential store (macOS Keychain, Linux Secret Service via D-Bus). Eliminates the need for environment variables or plaintext password files on developer workstations.
- New CLI commands: `jacs keychain set`, `jacs keychain get`, `jacs keychain delete`, `jacs keychain status`
- Automatic password resolution: env var -> password file -> OS keychain
- New config field `jacs_keychain_backend` (`"auto"`, `"macos-keychain"`, `"linux-secret-service"`, `"disabled"`)
- Set `JACS_KEYCHAIN_BACKEND=disabled` for CI/headless environments
- Feature-gated behind `keychain` Cargo feature (enabled by default in `jacs-cli`, optional in `jacs` core)
- **Memory-pinned key storage**: Decrypted private key bytes are now held in `mlock()`-pinned memory (`LockedVec`) that is excluded from core dumps (`MADV_DONTDUMP` on Linux) and zeroized before `munlock()` on drop.
- **Key directory safety**: `quickstart` and `create_with_params` now generate `.gitignore` and `.dockerignore` files in the key directory to prevent accidental exposure of private keys and password files.

### Security

- New `KeyBackend::OsKeychain` variant for desktop OS credential stores
- `resolve_private_key_password()` is now the single source of truth for password resolution across all encryption/decryption paths
- Platform integration tests for macOS Keychain (real backend) and Linux Secret Service

---

## 0.9.6

### Fixes
Expand Down
17 changes: 16 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.PHONY: build-jacs build-jacsbook build-jacsbook-pdf \
test test-all test-all-pq test-rust-pr test-bindings-fast test-rust-slow test-jacs test-jacs-fast test-jacs-features test-jacs-pq test-jacs-cli test-jacs-cross-language test-jacs-observability \
test test-all test-all-pq test-rust-pr test-bindings-fast test-rust-slow test-jacs test-jacs-fast test-jacs-fast-lib test-jacs-fast-bin-shard-a test-jacs-fast-bin-shard-b test-jacs-features test-jacs-pq test-jacs-cli test-jacs-cross-language test-jacs-observability \
test-jacs-mcp test-jacs-binding-core test-jacs-binding-core-pq \
test-jacs-duckdb test-jacs-redb test-jacs-surrealdb test-jacs-postgresql test-jacs-storage \
test-jacspy test-jacspy-parallel test-jacsnpm test-jacsnpm-parallel \
Expand Down Expand Up @@ -53,6 +53,11 @@ JACS_POSTGRESQL_VERSION := $(shell grep '^version' jacs-postgresql/Cargo.toml |
JACS_TEST_BINS := $(basename $(notdir $(shell find jacs/tests -maxdepth 1 -name '*.rs' -print | sort)))
JACS_FAST_TEST_BINS := $(filter-out a2a_cross_language_tests attestation_cross_lang_tests cli_flags cli_tests cross_language_tests observability_oltp_meter observability_tests pq2025_tests pq_tests,$(JACS_TEST_BINS))

# Alphabetical shard split for CI parallelization.
# Shard A: test names starting with a-d. Shard B: test names starting with e-z.
JACS_FAST_BIN_SHARD_A := $(filter a% b% c% d%,$(JACS_FAST_TEST_BINS))
JACS_FAST_BIN_SHARD_B := $(filter-out a% b% c% d%,$(JACS_FAST_TEST_BINS))

# ============================================================================
# BUILD
# ============================================================================
Expand Down Expand Up @@ -85,6 +90,16 @@ test-jacs:
test-jacs-fast:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation --lib $(foreach test,$(JACS_FAST_TEST_BINS),--test $(test)) -- --nocapture

# Sharded fast targets for CI parallelization (each maps to one local command).
test-jacs-fast-lib:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation --lib -- --nocapture

test-jacs-fast-bin-shard-a:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation $(foreach test,$(JACS_FAST_BIN_SHARD_A),--test $(test)) -- --nocapture

test-jacs-fast-bin-shard-b:
cd jacs && RUST_BACKTRACE=1 cargo test --features agreements,a2a,attestation $(foreach test,$(JACS_FAST_BIN_SHARD_B),--test $(test)) -- --nocapture

# Full test run: includes post-quantum algorithm tests (slow keygen)
test-jacs-pq:
RUST_BACKTRACE=1 cargo test -p jacs --features agreements,a2a,attestation,pq-tests --lib --tests --verbose
Expand Down
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,18 @@ JACS has four core operations. Everything else builds on these:
### Password Setup

```bash
# Developer / desktop workflow
export JACS_PRIVATE_KEY_PASSWORD='use-a-strong-password'
```

For Linux or other headless service environments, prefer a secret-mounted
password file over keeping the password in the process environment:

```bash
export JACS_PASSWORD_FILE=/run/secrets/jacs-password
export JACS_KEYCHAIN_BACKEND=disabled
```

### Python

```python
Expand Down Expand Up @@ -196,6 +205,22 @@ jacs mcp --profile full # start with all tools

Set the profile via `--profile <name>` or `JACS_MCP_PROFILE` environment variable.

The MCP server uses stdio only. It does not expose HTTP endpoints.

For Linux/headless startup, provide both the config path and a non-interactive
password source before launching:

```bash
export JACS_CONFIG=/srv/my-project/jacs.config.json
export JACS_PASSWORD_FILE=/run/secrets/jacs-password
export JACS_KEYCHAIN_BACKEND=disabled
jacs mcp
```

For embedded Python/Node processes, prefer in-memory secret injection over
environment variables when possible. The low-level bindings expose per-agent
password setters for that use case.

## Integrations

Framework adapters for signing AI outputs with zero infrastructure:
Expand Down Expand Up @@ -234,4 +259,4 @@ Framework adapters for signing AI outputs with zero infrastructure:

---

v0.9.6 | [Apache-2.0 OR MIT](./LICENSE-APACHE) | [Third-Party Notices](./THIRD-PARTY-NOTICES)
v0.9.7 | [Apache-2.0 OR MIT](./LICENSE-APACHE) | [Third-Party Notices](./THIRD-PARTY-NOTICES)
4 changes: 2 additions & 2 deletions binding-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "jacs-binding-core"
version = "0.9.6"
version = "0.9.7"
edition = "2024"
rust-version = "1.93"
resolver = "3"
Expand All @@ -19,7 +19,7 @@ attestation = ["jacs/attestation"]
pq-tests = []

[dependencies]
jacs = { version = "0.9.6", path = "../jacs" }
jacs = { version = "0.9.7", path = "../jacs" }
serde_json = "1.0"
base64 = "0.22.1"
serde = { version = "1.0", features = ["derive"] }
Expand Down
Loading
Loading