Compatibility fixtures
These fixtures pin password-store 1.7.4 at commit
1078f2514d579178d5df7042c6a790e9c9b731ad and pass-otp 1.2.0 at commit
1e9d10ca75ae1a8672a7f192809713463657778e. The behavioral catalog was
written from the projects' published command documentation and pinned source;
no upstream source or test code is copied here.
The v1.2.0 pass-otp tag reports 1.1.1 from its version command. The
fixture records that observable upstream behavior explicitly rather than
silently correcting it.
All identities, passphrases, plaintexts, OTP secrets, Git identities, and remote names are synthetic and public. They must never be reused for real secrets. The generator reuses the checked-in identities and produces:
- ASCII-armored and binary public keys;
- passphrase-protected ASCII-armored and binary secret keys;
- binary OpenPGP messages in an ordinary pass directory tree;
- root, nested, signed, and multi-recipient
.gpg-idpolicies; - TOTP and HOTP entries;
- valid loose-object Git repository templates, including an automatic-commit history and nested-repository boundaries.
gnupg-aead/ is a separate, non-generated compatibility case. Its synthetic
Alice entry was encrypted by GnuPG 2.4.8 with AES-256 and --force-ocb, yielding
GnuPG AEAD packet type 20 addressed to Alice's encryption subkey. The directory
contains the exact producer profile and ciphertext digest, a normal
password-store tree, and the expected plaintext. It deliberately lives outside
the reproducible generator's stores/, expected/, and repositories/
directories so a refresh cannot silently replace genuine GnuPG producer output.
Rust tests parse keys, verify signatures, decrypt every entry, compare exact
plaintext bytes, validate ciphertext digests, validate Git objects and refs,
and materialize isolated stores and repositories. They never invoke pass,
gpg, git, a shell, or an OTP/QR helper.
Refreshing fixtures
From the repository root:
cargo run -p ironstorage --example refresh_compatibility_fixtures
cargo test -p ironstorage --test compatibility_fixtures
Normal refreshes are byte-for-byte reproducible at the locked dependency versions because checked-in identities are reused. Deleting the key fixtures explicitly rotates the synthetic identities; OpenPGP self-signature timestamps then make that rotation intentionally non-reproducible. Review all binary changes and the generated fingerprints, digests, and Git object IDs before committing them.
When rotating the checked-in synthetic identities, regenerate the packet-20
case explicitly with the producer profile in gnupg-aead/fixture.toml, update
both recorded fingerprints and the digest, and independently inspect it with
GnuPG's packet listing before review.
An optional developer interoperability audit may import the generated keys
into a disposable GnuPG home, decrypt the .gpg entries, and point an
upstream pass 1.7.4 checkout at a materialized store. That audit is never a
test prerequisite and must use a temporary keyring and the synthetic fixture
passphrases. Refreshing observable behavior against upstream pass or
pass-otp is similarly development-only; application/runtime code may not
execute either tool.