Changelog¶
All notable changes to Isopace are recorded here. The format is based on Keep a Changelog, and the project follows Semantic Versioning as described in the versioning policy.
Unreleased¶
Added¶
vaultcapability interfaces for HSM adapters. Thevault.Vaultfaçade is now composed fromPINEncryptor,PINTranslator, andMacer, so a hardware adapter can implement exactly the operations its device supports — a general-purpose PKCS#11 HSM providesMacer(and possiblyPINEncryptor), while a payment HSM additionally providesPINTranslator.Vaultkeeps the same method set, so this is source-compatible.PINTranslatordocuments the PCI PIN Security contract: a conforming hardware implementation must re-encipher atomically inside the device so the clear PIN never leaves it, and an adapter that cannot do so (e.g. stock PKCS#11) must not implement it.adapters/pkcs11— HSM-backed MAC via a PKCS#11 token. The adapter now implementsvault.Macer(GenerateMAC/VerifyMAC) for ISO 9797-1 algorithm 1 (single-DES CBC-MAC) and algorithm 3 (ANSI X9.19 retail MAC), composed from the token's 3DES primitives so the key never leaves the device. The output is byte-for-byte identical tovault.GenerateMAC, cross-checked against a real token under SoftHSM2 in CI. Per thePINTranslatorcontract the type deliberately advertises onlyMacer— it does not implement PIN translate (no PCI-secure stock-PKCS#11 mechanism exists) or PIN-block encrypt (a clear-PIN, issuer-context operation). Separate cgo module; the core stays stdlib-only.adapters/payshield— Thales payShield payment-HSM adapter (scaffold). A reference adapter that exposes a payShield over its host-command protocol as the fullvault.Vault:vault.PINEncryptor(issuer-context clear-PIN encrypt),vault.PINTranslator(PCI-secure PIN translate — the operation a general-purpose PKCS#11 HSM cannot do), andvault.Macer(ISO 9797-1 MAC). A payment HSM performs every one of these inside the device, so the adapter satisfies the whole façade. Keys are named by the device's LMK key token; the clear key never leaves the device. Ships with an in-repoSimulator— a protocol test double whose cryptography is the Isopace software vault — so the command flow (framing, command building, response/error-code parsing, capability surface) is exercised end to end in CI without hardware. Scaffold: the on-wire field layout is a simplified stand-in for payShield's positional fields and it has not been validated against real hardware/LMK schemes — pending device validation and security review (B1). Separate, stdlib-only module.
1.0.0-rc.1 - 2026-06-09¶
First release candidate for v1.0.0. This is an interim, feedback-seeking
tag under a "may still change" banner — not the v1.0.0 contract itself. Per
the roadmap to v1,
it deliberately narrows what v1 will
freeze and is published to gather integration feedback before the API freeze:
- Stable candidate — the core.
iso8583,packager,fieldcodec,lengthcodec, andrenderare proposed for the v1 API freeze. Feedback is solicited against these surfaces specifically. - Experimental — may still change. The higher layers (
runtime,flow,space,store,mux,link,listener,connector,gateway,teq,vault,rbac,ops) remain explicitly experimental and are not covered by the rc's stability intent until they have soaked. - Production crypto (HSM) is not yet shipped. The only
vaultbackends are software (SoftVault,SealedVault); the certified-HSM / PKCS#11 path (roadmap B1) is outstanding. Do not treat the crypto path as production-ready.
No code change since 0.3.0 in the root module; the OpenTelemetry and SQL
adapters ship as separate modules (adapters/otel, adapters/sql) so the core
dependency graph stays empty. Still stdlib-only; every package is
gofmt/go vet clean and tested under go test -race.
Added¶
adapters/otel/andadapters/sql/— the first production integrations as standalone modules (each its owngo.mod): aruntime.Observerover the OpenTelemetry SDK, and astore.Storeoverdatabase/sql(driver chosen by the integrator, so none enters the core graph). The root module remains dependency-free.
Changed¶
- Docs: corrected the
CoralPay/Zoneprofile descriptions to state their actual provenance — clean-room layouts composed from public ISO 8583:1987 field semantics and the acquirers' published field tables — replacing earlier wording that implied derivation from a jPOS packager definition. No code change.
0.3.0 - 2026-06-02¶
The acquirer-profiles release: two more ISO 8583:1987 switch profiles —
CoralPay and Zone — each a clean-room layout composed from public
ISO 8583:1987 field semantics and the acquirer's published field tables, plus
the two wire primitives those links need: a
prefix-keyed SHA-256 message MAC and a fixed-width tag-length-value codec. Still
stdlib-only; every package is gofmt/go vet clean and tested under
go test -race.
Added¶
packager.CoralPay()— the CoralPay acquirer profile. An ISO 8583:1987 layout for the CoralPay acquirer link: ASCII MTI, an ASCII-hex primary+secondary bitmap, hex-on-wire (ASCII-hex) DE 52 PIN data, ASCII message-hash fields DE 64 / DE 128, and the DE 127 reserved-private subfield group carried under a 6-digit length prefix over a 1-level sub-bitmap. Registered inProfiles()as"coralpay". Round-trip tested (MTI, ASCII fields, 8-byte DE 52). A clean-room composition from public ISO 8583:1987 field semantics.packager.Zone()— the Zone acquirer profile. An ISO 8583:1987 layout for the Zone acquirer link: numeric-ASCII MTI, a binary primary+secondary bitmap, raw-binary DE 52 PIN data, and the same DE 127 reserved-private subfield group under a 6-digit length prefix. Registered inProfiles()as"zone". This reintroduces aZone()constructor and the"zone"profile id — distinct from the representative "site" layout removed in 0.2.0 — a clean-room composition from public ISO 8583:1987 field semantics. Round-trip tested.vault.SHA256MAC/vault.VerifySHA256MAC— prefix-keyed SHA-256 message MAC. ComputesSHA-256(key ‖ data), the message-hash MAC used by acquirer links such as CoralPay (DE 128 message hash, and the parameter-download DE 64) — not HMAC, a plain prefix-keyed digest.VerifySHA256MACconstant-time compares the leftmostlen(mac)bytes. Callers hex-encode the 32-byte digest to the 64-character on-wire field.tlv— a fixed-width tag-length-value codec. A new package withDecode/Encode/Getfor streams of (TagWidth-character tag +LenWidth-decimal-digit length + value) elements — for example CoralPay's terminal-parameter DE 62 ("03"+"015"+<15-char MID>,"05"+"003"+<currency>, …). Distinct from the BER-TLV composite infieldcodec, which uses encoded tag/length octets.
0.2.0 - 2026-06-02¶
The switching-layer release: a jPOS Q2-style container (teq) that keeps switch
connections open, routes and transforms transactions, and traces each one — plus
XML rendering and a built-in message describer. Still stdlib-only; every
package is gofmt/go vet clean and tested under go test -race.
Added¶
teq+cmd/teq— the container (jPOS Q2 analog), assembled. Wrapsruntime.Hostwith first-class switch connections (Q.Switch/Q.To), a name registrar (Q.Get/Q.Put/Q.Names), and a shared tuple space (Q.Space). Start from code (Start/Run/ListenAndServe) or runcmd/teqas a daemon that boots from a directory of JSON component descriptors and hot-(re)deploys them. Switch and routing-gateway descriptors are fully declarative — packager, framer, TLS, sign-on, echo, reconnect — so adding a switch needs no code.connector— supervised, self-healing outbound switch links. Keeps alink.Linkdialled and amux.Muxrunning over it, reconnecting with bounded backoff; optionalOnConnect(sign-on / key exchange) andKeepalive(0800 echo) hooks; routes server-initiated frames to a space queue. Satisfiesruntime.Component. (The jPOS ChannelAdaptor + QMUX analog.)gateway— the inbound routing/transforming switch server. Receives a transaction, routes it to an upstreamForwarder, edits the request (BeforeRequest) and the response (BeforeResponse) en route, and replies — with anOnErrordecline path. Handles messages on a link concurrently; satisfiesruntime.Component.trace— per-transaction lifecycle. Records one request/response cycle as a single correlated unit (timestamped steps + PCI-masked message dumps), carried in the request context so every participant annotates the same trace. Renders with optional ANSI colour (WithColor) and a toggleable timestamp column (NoTimestamps).render/xmlioand an XML channel framer (link). Schema-aware ISO-8583 XML (un)marshal, plus a matching XML wire framer.iso8583.Describe/Dump/LogValuer. A built-in, schema-aware message describer with PCI masking (PAN / track / PIN), an optional raw-hex column, andWithColor()for ANSI output.mux.Mux.Done()/Err(). Observe a multiplexer's link death (or clean close) without issuing a request — the basis for the reconnecting connector.packager.Postilion()— an ISO 8583:1987 profile for Postilion-style switch links (e.g. agency/Interswitch acquirers): ASCII MTI, a binary primary+secondary bitmap, ASCII fixed and LL/LLL variable fields, and a DE 127 reserved-private subfield group carried under a 6-digit length prefix over a binary sub-bitmap. Registered inProfiles()as"postilion". Validated end-to-end against a live host (0800 sign-on → 0810, 0200 → 0210). A clean-room composition from public ISO 8583:1987 field semantics.- Examples —
flowdemo(two-phase transaction flow),runtimehost(component lifecycle + hot deploy),teq(named switch connections), andteqswitch(the routing + transforming gateway, with-serve).
Removed¶
packager.Switch(),packager.Fields(),packager.Zone()and their embeddedschemadef/{switch,fields,zone}.json— the representative "site" layouts, superseded by the validatedPostilion()profile. Breaking: code referencing those constructors or the"switch"/"fields"/"zone"profile ids must move toPostilion()/"postilion".
0.1.0 - 2026-06-01¶
First tagged release. A feature-complete, clean-room Go framework for ISO-8583
messaging and payment switching. The module is stdlib-only — no third-party
dependency in the module graph — and every package is gofmt/go vet clean and
tested under go test -race.
Added¶
- ISO-8583 core (
iso8583) — immutable, copy-on-writeMessage; zero-copy lazyCodec(Unmarshal/Marshal/Validate);Schema/SchemaBuilder; fixed-pointDecimal/Amount;FieldPathgrammar (incl. BER-TLV tags); the typed generic accessorGet[T]and struct-bindingBinder[T]; exhaustive validation with structured errors. - Codec catalog (
fieldcodec,lengthcodec) — orthogonal value × length codecs: ASCII / EBCDIC (CP037/CP1047) / packed-BCD / binary, amount and bitmap codecs, and a BER-TLV composite for EMV field 55, all resolvable by name. - Packager profiles (
packager) — ISO 8583:1987 A/B/C, 1993 A/B, Visa and Mastercard overlays, three concrete site layouts (zone,fields,switch— the last with DE 127 as a headerless positional-subfield group, so127.2,127.22, … address like55.9F26), and a declarative JSON loader (go:embed) whose schemas are generated from the same field tables so the two forms cannot drift. Supporting catalog primitives: thesubfield.isopositional-subfield composite codec, theb.hexASCII-hex binary codec, 5-/6-digit length prefixes (len.lllll.ascii/len.llllll.ascii), andSchemaBuilder.Headerless(). - Alternate renderings (
render) — schema-aware JSON (PAN masking, TLV nesting), a descriptor-driven protobuf wire codec, and an ISO 20022 pacs.008 bridge — all from one read-onlyView. - Conformance & QA (
conformance) — hand-derived golden wire vectors, fuzz targets, and allocation/throughput benchmarks (allocation-free clean Marshal). - Transport (
link,listener,mux) — framed TCP connection (pluggable framer, filters, TLS), a graceful-shutdown server, a connection pool with backoff, and a request/response switch correlating by aKeyer. - Runtime (
runtime) — component host with ordered start / reverse stop and partial-start unwind; declarative deploy descriptors with hot redeploy; JSON+env configuration with hot reload;log/slogsetup; and anObservertraces/metrics facade (no-op and slog backends; OpenTelemetry as a drop-in). - Transaction manager (
flow) — two-phaseFlow/Stage/Exchangepipeline with conditional routing between groups, journaling, idempotent replay, per-stage retry, and a profiler. - Coordination (
space) — a keyed tuple space (Space) with an in-process backend and a durable, crash-safe store-and-forwardStore. - Security (
vault) — ISO 9564 PIN blocks, ISO 9797-1 MAC (incl. retail MAC) and CMAC, DUKPT (ANSI X9.24-1, validated against the public test vector), TR-31 version B key blocks, and EMV ARQC/ARPC, behind aVaultfaçade. Two software backends:SoftVault(keys in memory) and the hardenedSealedVault(working keys encrypted at rest under a caller-supplied KEK via AES-GCM, decrypted only transiently and zeroized after each operation, with key check values, per-key usage enforcement, and an audit hook); HSM/PKCS#11 is a drop-in adapter. - Enterprise / ops (
rbac,store,ops) — role-based access control with PBKDF2 credentials and constant-time authentication; a collection/key/value persistenceStore; and an operational surface with health checks, a metrics registry (Prometheus text; implementsruntime.Observer), cluster membership, and an rbac-guarded HTTP admin API. - Examples — runnable
acquirerandissuerprograms, asimulatortest host assembled fromruntime+ops+ transport, and the sharedposdemolibrary with an end-to-end loopback test. - Project governance & tooling — dual-license scaffolding (AGPLv3 +
commercial CLA,
NOTICE,AUTHORS,SECURITY.md), a draft commercial-license template (COMMERCIAL-AGREEMENT.md, pending counsel review), and an.air.tomllive-reload config for thesimulator(dev tooling, not a module dependency).
Security notes¶
vault.SoftVaultis for development, testing, and conformance only. Production PIN and key handling must use a certified HSM behind theVaultinterface.- The admin API distinguishes 401 (unauthenticated) from 403 (forbidden) and authenticates in constant time; expose it only behind appropriate network controls.