Normalizes qualified signature-validation reports (EU DSS behind a signing API) into one stable, wire-ready answer shape — so every service and UI renders the same fields from one place, instead of hand-copying the answer struct per consumer.
go get github.com/gmb-lib/go-validation-answer
See CHANGELOG.md for what each release changed, and what it means for code that
already uses this library, before you bump.
Zero dependencies (standard library only). Import path package name: answer.
The upstream validation report is relayed verbatim by the validation
service, and its layout varies across API versions: the signer identity may be
nested under signerExt or sit at the signature entry's top level; timestamps
may be flat (timeStamp, ocspResponceTime — upstream spelling) or nested
under info (bestSignatureTime, ocspResponseCreationTime); the
included-file list may be ["a.pdf"] or [{"filename":"a.pdf"}], under
validatedDocument or at the data level. NormalizeReport reads the known
layouts with fallback resolution and produces one answer.
res, err := answer.NormalizeReport(rawReport) // the verbatim {data:{…}} bytesanswer.Validation — document-level verdict (PASSED / INDETERMINATE /
FAILED), pass, container form, signed-file names, and signatures[]
(answer.Signature: per-signature verdict, format profile, legal-meaning
level, signer identity, signing / revocation / max-validity times, warnings,
errors). The top-level per-signer fields mirror the first signature for
single-signature callers. signatureId / documentId / reportId /
validatedAt are caller context, set by the serving side — validatedAt is
when the validation actually ran (RFC 3339): validation is time-anchored
(revocation can post-date it), so an answer served later than it was produced
renders "as of" that moment, never as current.
Rules baked in:
- Verdicts are mapped, never recomputed:
TOTAL-PASSED/TOTAL-FAILEDmap directly; anything else isINDETERMINATE. The overall verdict fails on any failed signature and passes only when every signature passed and the report's own counts agree. - Levels map to legal meaning (
QESIG→QES,QESEAL→SEAL,ADESIG*/ADESEAL*→AdES); unknown codes pass through visibly rather than being guessed. - An organisation's registration number is preferred over a bare serial; a single PDF's placeholder "file list" is dropped rather than surfaced.
- Timestamps pass through as RFC 3339 (a legacy locale format is converted).
- In-process extras (
SignaturesCount,ValidSignaturesCount,ValidationLevel— e.g.ARCHIVAL_DATAafter an archive timestamp) are available on the struct but deliberately off the wire.
The wire key set is pinned by a test (TestWireContractKeys) — changing it is
an explicit, reviewed act, never a side effect.
- No validation calls, no HTTP — bytes in, answer out.
- No cryptographic interpretation; presence/verdict mapping only.
- The verbatim report itself is not reshaped or re-served by this package.
Bug reports and pull requests are welcome. CONTRIBUTING.md names the gate a change has to pass, what a change to this library needs, and the sign-off every commit carries.
Suspected vulnerabilities go through the private route in SECURITY.md — never a public issue.
MIT — see LICENSE.