Shared Go library for logic common to the Issuer API and Merchant API.
Module: github.com/interledger/cards-utils
Run the below command to build the project.
go build ./...Run the below command to run the unit tests.
go test ./...Produces loggable copies of API and domain values with sensitive fields masked
or hidden, driven by sensitive:"<class>" struct tags. Classification follows
the ILF EMV Field Data v1.0 sensitivity key.
Never log a request/response/domain struct directly — always go through
redact.Redact or redact.Object:
log.Info().Object("merchant", redact.Object(m)).Msg("merchant created")Highlights:
- Tag-driven:
pii/confidentialare masked,crypto_key/crypto_data/credential/pciare hidden,dynamicmaps are redacted by key rules. ProfileApp(default) masks identifiers;ProfileAuditfails closed and hides everything classified.redact.JSONredacts raw JSON bodies by key rules for byte-level logging.redact.Objectintegrates with zerolog structured logging;redact.AuditObjectdoes the same underProfileAudit, for audit events.redact.Errorreturns an error's message with URLs and HTTP request targets redacted.
Each consuming service keeps its own sentinel/property tests (under
internal/redact) that assert its own types are classified correctly; the
reusable redaction engine lives here.
Static checks a service runs from its tests, with its own allowlists of justified exceptions:
redactcheck.LogCallsfails on a zerolog.Interface,.Any,.Fieldsor.Objectcall whose value is not aredact.*call.redactcheck.TagCoveragefails on a struct field that looks sensitive but has nosensitive:"<class>"tag.
func TestZerologCallsAreRedacted(t *testing.T) {
redactcheck.LogCalls(t, "../..", loggingAllowlist)
}The services' zerolog setup and echo middleware: Init, a request-scoped
logger (WithLogger, FromContext), ZerologMiddleware (one
request_completed line per successful request), BodyMiddleware (redacted
JSON bodies at debug, behind a flag), LogPanic for echo's Recover
middleware, and Audit for audit events. See the package doc for the
conventions, including the middleware order.
Validates the EMV authorized amount (9F02) in BER-TLV payloads and provides
numeric BCD conversion:
err := tlv.ValidateAmount(payload, "100")Validation errors can be classified with errors.Is using the exported
sentinels such as tlv.ErrParsingTLV and tlv.ErrAmountMismatch.
Until this module is tagged and published, consuming services reference it with
a replace directive pointing at a sibling checkout:
replace github.com/interledger/cards-utils => ../cards-utils