feat(ffi+cli): implement jk_* C ABI and CLI lifecycle — both product-gap gates green (closes #61, #62)#63
Merged
Conversation
Rewrite ffi/zig/src/main.zig from the old `januskey_*` scaffold to the
authoritative `jk_*` C ABI declared in ffi/zig/include/januskey.h
(generated from src/abi/{Foreign,Types,Layout}.idr), so that
ffi/zig/test/integration_test.zig passes.
- extern-struct value types ContentHash (32B), KeyId (16B) and
OblitProof (112B, 8-aligned: content_hash 32 + nonce 32 +
commitment 32 + overwrite_passes u64 + passes_valid u8), with
comptime size/align/offset assertions pinning them to Layout.idr.
- Error enum(c_int) with the 12 JK_OK / JK_ERR_* wire values.
- Sized, heap-allocated Handle struct (not opaque-with-fields)
tracking init state + the single in-flight transaction; pointer
round-trips through ?*anyopaque at the C boundary.
- jk_init/jk_open/jk_close, jk_execute/jk_undo/jk_obliterate,
jk_generate_key/jk_rotate_key/jk_revoke_key,
jk_tx_begin/commit/rollback (one-active-tx invariant ->
TX_CONFLICT; foreign/null token -> TX_NOT_ACTIVE), jk_version.
- jk_execute takes op as c_int (the C enum wire type the test passes)
and jk_version returns [*c]const u8 (C nullable const char*) so the
conformance suite's literal/null-check usages typecheck.
Crypto/CNO internals are honest scaffolds marked TODO(product:);
the lifecycle, transaction-state and null-guard semantics the suite
asserts are real.
Also gitignore Zig build artefacts (.zig-cache/, zig-out/).
https://claude.ai/code/session_01GJatEm2TVFSTBEkKXmserJ
Make the `jk` CLI satisfy the init->execute->undo->obliterate lifecycle the E2E test drives. - `init` now takes an optional positional path (`jk init <dir>`), initialising that directory (created if absent) and overriding --dir/--repo when given. - Add a global `-r/--repo <dir>` flag (alias of --dir, takes precedence) so `jk -r <repo> <cmd>` selects the repository. - Add an `obliterate <paths...>` subcommand implementing GDPR Art. 17 erasure of concrete files via a new public `obliteration::obliterate_file`: hash, DoD-style multi-pass secure overwrite, unlink, and return a proof. Irreversible, so it refuses to run without --yes when stdin is not a TTY (never auto-confirms destructive erasure unattended) and prompts otherwise. Scaffold-level where noted with TODO(product:) (repo-side scrub of content-store copies and op-log pruning on obliterate). https://claude.ai/code/session_01GJatEm2TVFSTBEkKXmserJ
- tests/e2e/lifecycle_e2e.sh: replace ((PASS++))/((FAIL++))/((SKIP++)) with PASS=$((PASS+1)) etc. Under `set -euo pipefail` a post-increment of a 0-valued var returns exit 1 and aborted the script on the first check (same fix already present in the aspect test). - tests/aspect/cross_cutting_test.sh: prune .zig-cache/ and zig-out/ from the Zig SPDX `find` so a generated, header-less dependencies.zig left by `zig build` cannot skew the count when the test runs in an already-built tree. https://claude.ai/code/session_01GJatEm2TVFSTBEkKXmserJ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes januskey's two product-gap CI checks pass for real — the gaps left tracked when #55 merged (issues #61, #62). All three gates verified green locally with the actual Zig 0.13 + Cargo toolchains on a clean tree.
Closes #61. Closes #62.
Gate 1 — Zig FFI Build + Test
ffi/zig/src/main.zigwas an oldjanuskey_*scaffold that didn't satisfy the repo's own conformance suite. Rewrote it to implement the authoritativejk_*C ABI declared inffi/zig/include/januskey.h(itself generated fromsrc/abi/{Foreign,Types,Layout}.idr):extern structtypesContentHash(32) /KeyId(16) /OblitProof(112, 8-aligned) with comptime@sizeOf/@alignOf/@offsetOfassertions pinning them toLayout.idr— the build fails loudly if the ABI ever drifts from the Idris spec.Error enum(c_int)with the exactJK_OK/JK_ERR_*wire values;OpKind/Algorithmenums.Handle(notopaque) tracking init state + the one-active-transaction invariant (TX_CONFLICT/TX_NOT_ACTIVE).jk_*functions with correct return codes.zig build0,zig build test0 (15/15 tests).TODO(product):markers; the lifecycle/transaction/null-guard semantics the suite exercises are real.Gate 2 — E2E Lifecycle
tests/e2e/lifecycle_e2e.sh:((PASS++))underset -e(old value 0 → exit 1) replaced withPASS=$((PASS+1))— the script could never pass before.crates/januskey-cli:initnow takes a positional<dir>; added global-r/--repo; addedobliterate <paths…>backed by a newobliteration::obliterate_file(hash → DoD multi-pass secure overwrite → unlink → proof).init/copy/undouse real reversible-core ops.obliteraterefuses destructive erasure when stdin isn't a TTY and no-yis given — it errors cleanly (never auto-confirms, never hangs), so the non-interactive e2e skips that one step rather than faking a wipe.cargo build --release0,jk init0,cargo test --all0,bash tests/e2e/lifecycle_e2e.sh0 (PASS: 6 FAIL: 0 SKIP: 2).Gate 3 — Aspect Tests (kept green)
bash tests/aspect/cross_cutting_test.sh0 (PASS: 29 FAIL: 0). Hardened the Zig-SPDX check to prune.zig-cache//zig-out/(a built tree drops a header-less generateddependencies.zigthat would otherwise skew the count). Added.zig-cache/+zig-out/to.gitignore.🤖 Draft — opened for review.
https://claude.ai/code/session_01GJatEm2TVFSTBEkKXmserJ
Generated by Claude Code