pdfservice

RabbitMQ-RPC microservice that prepares, inserts, and validates PAdES digital signatures on PDF documents, plus checks PDFs for “active components” (JavaScript/XFA). Built on the EU DSS (eu.europa.ec.joinup.sd-dss) library and validates against the European List of Trusted Lists (LOTL/TSL). It is a Kotlin/Spring-Boot/Gradle JVM service (not Node.js) — verified build.gradle.kts:1-35, src/main/kotlin/com/facekom/pdfservice/PdfServiceApplication.kt:1-19.

Repo identity

Git remote/group is com.facekom and GitHub org TechTeamer (build.gradle.kts:56,88-89; README.md:64). Base branch main; only one commit visible in this shallow source clone: 7400d82 upgraded spring boot to eliminate CVA (#104).

No Git-LFS here

There is no .gitattributes and git lfs ls-files is empty. The large files in tl_cache/ are plain-text EU trust-list XML files (e.g. https___tl_bundesnetzagentur_de_TL_DE_XML ≈5.1 MB), and libs/ jars are small real jars (mq-1.4.1.jar ≈105 KB). No model weights / binary blobs. Verified by listing tl_cache/ and libs/com/facekom/mq/1.4.1/.


1. Purpose & role in FaceKom

A back-end signing/validation worker invoked over RabbitMQ RPC. Four endpoints (queue names from application.properties:23-26):

RPC queue (prod default)HandlerPurpose
pdf-prepareSignedDocumentPrepareSignatureEndpointBuild PAdES placeholder + return digests to be signed externally (contentHash, dataToBeSigned).
pdf-insertSignatureInsertSignatureEndpointInsert an externally-signed CMS into the PDF, returning signedPdf.
pdf-validateValidateSignatureEndpointValidate a PDF’s signatures against EU trust lists; returns signers + validity level.
pdf-checkActiveComponentsCheckActiveComponentsEndpointDetect active/dynamic content (JS, XFA, non-signature AcroForm fields).

Signing uses the external-CMS DSS flow (PAdESWithExternalCMSService + ExternalCMSService): pdfservice never holds the private key — it prepares digests, an external signer (the FaceKom PDF Signer, see below) signs the digest, and pdfservice inserts the resulting CMS. Verified service/signature/SigningService.kt:14-32, configuration/SigningConfig.kt:64-83, endpoints in messaging/endpoints/.

External signer dependency (FaceKomPDFSigner / "pdfsigner")

README describes vendoring the private FaceKomPDFSigner (a.k.a. pdfsigner) jar into libs/ via ./gradlew publishToMavenLocal (README.md:34-53). In this checkout libs/ contains only the com.facekom.mq connector jar (1.4.1) — the pdfsigner jar is not present and the only implementation(files(...)) line wires the mq jar (build.gradle.kts:120). The “signer” referenced in signer-config.* properties is the DSS signing config inside this repo, not a bundled pdfsigner jar.

PAdES levels: signatures are PAdES-BASELINE-LTA (CMS prepared at PAdES-BASELINE-T) — SigningConfig.kt:52-62. Validation walks levels ARCHIVAL_DATA → LONG_TERM_DATA → TIMESTAMPS → BASIC_SIGNATURES, reporting the highest that passes (model/validation/SignatureValidityLevel.kt, service/validation/PdfValidationComponent.kt:52-60).


2. Tech stack & runtime

  • Language: Kotlin 2.0.20 (build.gradle.kts:5). Official Kotlin code style (gradle.properties:1).
  • Framework: Spring Boot 3.5.14, run headless (WebApplicationType.NONE) — no HTTP server; it is a pure AMQP worker. PdfServiceApplication.kt:15, build.gradle.kts:11.
  • JVM: Java 17 toolchain (build.gradle.kts:26-30); CI/Docker use openjdk:17-jdk-slim (docker/localdev/pdfservice.Dockerfile:1, .travis.yml:4, .github/workflows/auto_release.yml JDK 17). README local-dev workaround mentions JDK 11 only for building the legacy external pdfsigner — README.md:5.
  • Build tool / package manager: Gradle (Kotlin DSL) via wrapper ./gradlew; multi-project (settings.gradle). Daemon on, -Xmx2048m (gradle.properties:2-3).
  • PDF / crypto libs: Apache PDFBox 3.0.5, EU DSS 6.3 (many dss-* modules), BouncyCastle 1.84, Nimbus JOSE+JWT 10.5, Jackson 2.21.1, Gson 2.10.1, RabbitMQ amqp-client 5.22.0 (build.gradle.kts:114-208).
  • In-house lib: com.facekom:mq:1.4.1 jar vendored under libs/ — provides ConnectionPool, QueueManager, RpcServerOptions, QueueMessage/QueueResponse (RPC + attachment encryption/integrity). Imported throughout messaging/ & configuration/MessagingConfig.kt.
  • Reproducible builds: dependency locking enabled (build.gradle.kts:235-237); SHA-256 verification metadata written in CI (.travis.yml:23).

3. Build & run

Entrypoints

  • Main class: com.facekom.pdfservice.PdfServiceApplicationKt (build.gradle.kts:34, 248).
  • Generated launch script name: pdfservice (application { applicationName = "pdfservice" }, build.gradle.kts:33) → distribution bin/pdfservice.
  • Profile selection: reads env var RUNTIME_ENV (default "default"); always also activates the "local" profile and an optional external config file:/workspace/pdfservice/config/local.properties (PdfServiceApplication.kt:13-18).

No package.json / npm scripts

This repo has no package.json and no npm/yarn/pnpm scripts. The task’s “list each package.json scripts entry” item is N/A — build/run is entirely Gradle. The equivalent commands are the Gradle tasks below.

Key Gradle tasks (verified in build.gradle.kts)

  • run — Spring Boot application run (used by dev supervisor command=./gradlew run --info, supervisor_pdfservice_dev.conf:8).
  • bootRun — Spring Boot run (used by compose entrypoint, docker/localdev/run-pdfservice.yml:22).
  • test — JUnit 5 (Jupiter only; vintage excluded), per_class lifecycle, finalized by Kover XML+HTML reports (build.gradle.kts:210-229).
  • koverXmlReport / koverHtmlReport — coverage (build.gradle.kts:220-229).
  • bootJar — fat jar, Start-Class=...PdfServiceApplicationKt, classifier boot (build.gradle.kts:246-251).
  • distTar / bootDistTar / distZip — gzip dist archives pdfservice-<version>.tar.gz / .zip; bundles src/main/resources into bin/, plus .version and supervisor_pdfservice_docker.conf (build.gradle.kts:253-280, 264-275).
  • createVersionFile — writes .version with VERSION=<v> (build.gradle.kts:239-244).
  • printVersion — prints axion-derived version (build.gradle.kts:59-63).
  • cyclonedxBom / cyclonedxDirectBom — CycloneDX SBOM for vuln scan (build.gradle.kts:107-112; CI in vulnerability_scan.yml).
  • release — axion-release tagging (build.gradle.kts:16,20,37-54; CI auto_release.yml).
  • Subproject tasks: :pdfclient:jar, :trust-list-downloader:run (used by pdfclient.Dockerfile:10 and .github/scripts/check_trust_lists.py:30).

Start commands (verified)

  • Dev (supervisor): ./gradlew run --info with RUNTIME_ENV=dev (supervisor_pdfservice_dev.conf:7-8).
  • Docker/prod (supervisor): /workspace/pdfservice/bin/pdfservice with RUNTIME_ENV=docker (supervisor_pdfservice_docker.conf:7-8).
  • One-click localdev compose: docker compose -f docker/localdev/run-pdfservice.yml up → builds service, a rabbitmq:3-management-alpine, and the pdfclient test container; entrypoint cd /workspace/pdfservice && chmod -R 777 ./build/resources/ && ./gradlew bootRun (run-pdfservice.yml:1-46).
  • Debug: inside container supervisorctl stop all then ./gradlew run --debug-jvm (listens on 5005) — README.md:84-88.

Dockerfiles (under docker/, none at repo root)

  • docker/localdev/pdfservice.Dockerfileopenjdk:17-jdk-slim + fontconfig/libfreetype6, CMD ["jshell"] (image is volume-mounted with source; actual run via compose entrypoint).
  • docker/localdev/pdfclient.Dockerfile — multi-stage; builds :pdfclient:jar, creates /client/pdfclient wrapper + picocli autocomplete, runs as non-root techteamer.
  • Compose files: docker/localdev/{run,project,debug}-pdfservice.yml, docker/release-test/release-test-pdfservice.yml, plus rabbitmq.config per env.

Release flow (README.md:55-66)

Update CHANGELOG.md + version in build.gradle.kts → commit x.y.z./bin/tag-latest.sh x.y.z./gradlew distTar → upload build/distributions/pdfservice-x.y.z.tar.gz to GitHub Releases. Automated path: .github/workflows/auto_release.yml runs ./gradlew release on merge of auto/* or maintenance/* PRs into main.


4. Top-level structure

PathWhat it is
src/main/kotlin/com/facekom/pdfservice/Main Spring Boot app (signing, validation, messaging). See §6.
src/main/resources/application.properties, application-dev.properties, logback.xml, cryptography/truststore.p12, visualsignature/ (Roboto font + qtsp_sign.png).
src/test/kotlin/com/facekom/Tests: pdfservice/** (unit) + automation/{functional,integration}/** (Spring/Testcontainers). See §8.
src/test/resources/fixtures/Test PDFs, certs, encryption keys, JSON fixtures (pdfs/{functional,integration}/...).
trust-list-downloader/Sub-Gradle-project: standalone CLI that downloads & verifies the EU LOTL and rebuilds the LOTL truststore (.p12) for the service. See §6.5.
pdfclient/Sub-Gradle-project: picocli CLI to send test messages (validate/sign/check) to a running pdfservice over RabbitMQ. “TESTING PURPOSES ONLY” (pdfclient/.../App.kt:21).
tl_cache/Pre-downloaded EU trust-list XML cache (~40 files) consumed offline by the service at startup.
libs/com/facekom/mq/1.4.1/Vendored in-house mq connector jar (+ sources/pom/module).
docker/Dockerfiles + docker-compose + rabbitmq configs for localdev and release-test.
docs/AsciiDoc system docs (pdfservice.adoc + chapters/**) and PlantUML diagrams (puml/**). Largely Hungarian.
bin/Two helper shell scripts (see §5).
.github/CI workflows + Python automation scripts (trust-list check, vuln scan, Slack notify).
.run/IntelliJ run configurations (.run.xml).
gradle/Gradle wrapper + verification metadata (gradle/wrapper/).
.scratchpad/, .travis.yml, sonar-project.properties, supervisor_*.confScratch dir, Travis CI, SonarCloud, supervisord configs.

5. Helper scripts under first-party bin/

Only two scripts in bin/ (both bash):

  • bin/show-coverage.sh — runs the test suite in a throwaway openjdk:17-jdk-slim container (mounting the project + the docker socket read-only so Testcontainers works), executes ./gradlew clean test, then xdg-opens the Kover HTML report via IntelliJ’s built-in server (localhost:63342/...). Verified bin/show-coverage.sh:1-19.
  • bin/tag-latest.sh <tag> [--force] — release tagger. Aborts unless on main; with --force deletes an existing <tag> locally+remote; deletes & re-creates the latest tag on HEAD, creates <tag>, and git push --tags. Verified bin/tag-latest.sh:1-45.

CI Python scripts (not in bin/)

.github/scripts/ holds first-party Python helpers used only by GitHub Actions: check_trust_lists.py (runs :trust-list-downloader:run, reads alert files, copies refreshed TLs to tl_cache/, opens PR), vulnerability_scan.py (grype over the CycloneDX SBOM), notifications.py/notify_pr.py/notify_release.py (Slack via SLACK_WEBHOOK_URL, suppressible with SLACK_DISABLED), and file_handler.py (yaml/config + folder copy). Verified by reading each.


6. Key modules / services / entities

6.1 Messaging layer (messaging/)

  • RabbitMqConnector (messaging/RabbitMqConnector.kt) — @PostConstruct connect() registers RPC servers for the four endpoints and calls connectionPool.connect(). @DependsOn("lotlTrustListSourceProvider") so trust lists are loaded before it accepts messages; @Profile("!exclude-rabbit") lets tests disable it. prepare/insert consume with (encryptedData, request, response, _); validate/checkActiveComponents consume with (_, request, _, _).
  • Endpoints (messaging/endpoints/): PrepareSignatureEndpoint, InsertSignatureEndpoint, ValidateSignatureEndpoint, CheckActiveComponentsEndpoint — thin handlers delegating to services; annotated with custom logging aspects @LogBefore/@LogAfter/@LogReturnValue. Prepare/Insert call messagingService.verifyAttachmentsAndParse(encryptedData, request) (attachment SHA-256 integrity check) before processing.

6.2 Signing (service/signature/)

  • SigningService — orchestrates prepareSignature (message digest + CMS-to-be-signed digest) and insertCmsSignature (sign CMS + embed). service/signature/SigningService.kt.
  • PadesWithExternalCmsFacade, ExternalCmsFacade, SignatureParametersProvider — wrap DSS PAdESWithExternalCMSService/ExternalCMSService.
  • service/signature/cms/CmsSignatureValidator (fun-interface) with CmsValidatorImpl, CryptographicCmsValidator, FormatOnlyCmsValidator: validate an externally-received CMS before inserting it.
  • service/signature/timestamp/TimestampComponent — generates signing timestamps (RFC 3161 TSA at https://bteszt.e-szigno.hu/tsa, creds from env FACEKOM_PDF_SIGNER_TSA_USERNAME / _PASS; application.properties:48-51, SigningConfig.kt:85-99).
  • service/signature/visuals/ — visual-signature rendering (auto text-wrap, scaling, rotation, image placement) built on DSS SignatureImageParameters. Key: VisualSignatureComponent, ContainerPlacementResolver, TextWrapper, ImageLoader, DssKeywordResolver, RotationKeywordResolver, textmeasurement/PdfBoxTextMeasurementProvider. Disabled by default in prod, enabled in dev (application.properties:53 vs application-dev.properties:27).

6.3 Validation (service/validation/)

  • PdfValidationService (fun-interface) with two impls chosen by ValidationConfig:
    • TrustListPdfValidationService — validates against the EU LOTL CertificateVerifier (default / prod).
    • LenientPdfValidationService — dev/test only, no trust lists (accepts self-signed; only used when trustList.enabled=false AND profile is dev/test/staging). ValidationConfig.kt:105-125.
  • PdfValidationComponent — core logic: first an offline crypto check (OfflinePdfValidator, internet disabled, AIA/OCSP/CRL nulled, BASIC_SIGNATURES), then walks PAdES levels online to find highest valid level; returns SignatureValidationResponse(signers, isValid, validityLevel). Enforces pdf.version minimum via PdfVersionComparator (default 1.2). PdfValidationComponent.kt.
  • LotlTrustListSourceProvider (bean name lotlTrustListSourceProvider, @Profile("!functional-test")) — @PostConstruct loads/refreshes trust lists from the offline cache; throws if trustList.cacheLocation is empty when trust lists are enabled. Runs validationJob.offlineRefresh(). service/validation/LotlTrustListSourceProvider.kt.

6.4 Cryptography (service/cryptography/)

  • CryptographyServiceCertificateCreationComponent (builds P12Certificate from bytes), DigestComponent (SHA-256 hex, used for attachment integrity), LenientCertificateVerifierProvider.
  • service/cryptography/verification/SigningCertificateValidator (fun-interface) with TrustListSigningCertificateValidator (prod / trust-list), LenientSigningCertificateValidator (dev), EmptySigningCertificateValidator (dev, no check). Selected in ValidationConfig.signingCertificateValidator(...).

6.5 trust-list-downloader sub-project

Standalone CLI (com.facekom.trustlistdownloader.MainKt, version 1.0.0, DSS 6.3). Main.kt flow: load application.yml → clean caches → TrustListDownloader.downloadListsAndVerify() (onlineRefresh() of the EU LOTL with pivot support + OJ signing-cert predicate) → if signature alert, abort (do not update keystore) → else rebuild combined truststore from OJ + pivots (TrustStoreBuilder) and copy the fresh .p12 into the service (chmod 777). Alert handlers (alerthandler/) write per-condition files (OJ desync, LOTL location change, signature error, project-TL outdated) that CI reads. Config trust-list-downloader/src/main/resources/application.yml pins the Official Journal URI (https://eur-lex.europa.eu/eli/C/2026/1944/oj) and LOTL URL (https://ec.europa.eu/tools/lotl/eu-lotl.xml). Verified Main.kt, service/TrustListDownloader.kt, application.yml.

6.6 pdfclient sub-project

picocli CLI (com.facekom.pdfclient.App, version 0.2) with subcommands ValidateCommand, SignCommand, CheckCommand; sends RabbitMQ messages to a running pdfservice and saves results. Bundles a test-signer jar (pdfclient/libs/com/facekom/test-signer/0.2/) and reads RABBIT_URL_OVERRIDE env or rabbit.properties. For testing only.

6.7 Cross-cutting

  • aspect/LoggingAspect + @LogBefore/@LogAfter/@LogReturnValue annotations (@EnableAspectJAutoProxy in LoggerConfig); spring-boot-starter-aop.
  • exception/RpcException, SignatureException, SigningCertValidationException.
  • model/ — request/response DTOs per domain: signature/, validation/, visualsignature/, message/, cryptography/, checkactivecomponents/.

7. Configuration

Spring property files in src/main/resources/ (.properties, not YAML). External override via config/local.properties (PdfServiceApplication.kt:16) — README notes a teammate must supply local.json/local.properties since it holds secrets and is git-ignored (README.md:78).

  • application.properties (prod defaults) — verified application.properties:1-54:
    • pdf.version=1.2
    • trustList.enabled=true, trustList.cacheLocation=/workspace/tl_cache, trustList.useTrustStore=true, trustList.trustStore=cryptography/truststore.p12, trustList.offlineLotlSource=https___ec_europa_eu_tools_lotl_eu_lotl_xml
    • queue.validateRpcName=pdf-validate, queue.prepareRpcName=pdf-prepareSignedDocument, queue.insertSignatureRpcName=pdf-insertSignature, queue.checkPdfActiveComponentsRpcName=pdf-checkActiveComponents
    • queue.urls[0]=amqps://rabbitmq:5671 (TLS), queue.options.allowTlsWithoutTrustStore=false, cert/key paths under /workspace/vuer_mq_cert/client/
    • queue.rpcTimeoutMs=10000, queue.checkActiveComponentRpcTimeoutMs=400000, queue.rpcQueueMaxSize=100
    • alerts.certificateVerifier.onOutOfRangeDate=true, ...onMissingRevocationData=true
    • signer-config.validations.checkCertValidityOnLoad=true, ...validateCertWithTrustLists=true, TSA env-var names, signer-config.reason=signature, signer-config.visual-signature.enabled=false, font path.
  • application-dev.properties (profile dev) — verified :1-27: plaintext AMQP amqp://guest:guest@localhost:5672, clears rabbit certs, trustList.cacheLocation=./tl_cache, signer-config.visual-signature.enabled=true.

Property binding (Spring @ConfigurationProperties / @Value)

  • MessagingConfig — binds queue.*RabbitMqProperties; builds QueueConfig/ConnectionPool/QueueManager and two RpcServerOptions beans (defaultRpcServerOptions, checkActiveComponentsRpcServerOptions). Quorum-queue args default x-queue-type=quorum, delivery-limit=30 (RabbitMqProperties.kt:15-21).
  • RabbitMqProperties — RPC names, urls list, timeouts, prefetch (3), TLS options. configuration/RabbitMqProperties.kt.
  • ValidationConfig — large @Configuration: trust-list/cert-verifier beans (CommonCertificateVerifier, AIA/OCSP/CRL online sources, offline FileCacheDataLoader with cacheExpiration=-1, TLValidationJob, EU LOTLSource with pivot support, keystore cert source PKCS12), and the dev-mode toggles. Dev-only relaxations apply only when profile ∈ {dev,test,staging}: isDevelopment(env) (ValidationConfig.kt:288-290). proxyConfig() returns null (proxying explicitly disabled — :182-186).
  • SigningConfig — digest algo (default SHA256), PAdES levels (LTA / T), TSA OnlineTSPSource with HostConnection auth, signWithCertOutOfDateRange (dev only). configuration/SigningConfig.kt.
  • VisualSignatureConfig / VisualSignatureProperties — binds signer-config.visual-signature.*; font resource bean is @ConditionalOnProperty(enabled=true). configuration/VisualSignature*.kt.
  • LoggerConfig — single SLF4J Logger bean named by logging.loggerName (pdfservice-logger-prod / -dev); enables AOP.
  • JsonConfig — lenient Gson bean.
  • Env vars referenced: RUNTIME_ENV (profile), FACEKOM_PDF_SIGNER_TSA_USERNAME / FACEKOM_PDF_SIGNER_TSA_PASS (TSA creds), APP_HOME & DOCKER_USER (supervisor), RABBIT_URL_OVERRIDE (pdfclient), SLACK_WEBHOOK_URL / SLACK_DISABLED (CI).

No AJV / getconfig

Configuration is Spring @ConfigurationProperties + @Value, not Node getconfig/AJV JSON-schema. The Hungarian docs/chapters/application/configuration.adoc documents these keys (and some jwt.*/extra visual-signature keys that are not present in current code — see gaps).


8. Tests

  • Framework: JUnit 5 (Jupiter), Mockito + mockito-kotlin, AssertJ, Spring Boot Test, Testcontainers (RabbitMQ), WireMock standalone. build.gradle.kts:185-207. Lifecycle per_class, vintage engine excluded (:210-215).
  • Location: src/test/kotlin/com/facekom/
    • pdfservice/** — focused unit tests (per service/component/config; e.g. CmsValidatorImplTest, PdfVersionComparatorTest, endpoint tests).
    • automation/functional/** — Spring-context functional tests (FunctionalTest, FunctionalTestConfig, profile functional-test disables LotlTrustListSourceProvider; TestTrustSourceProvider). Covers lenient/trust-list validation, visual signatures, check-active-components.
    • automation/integration/** — full integration incl. RabbitMQ Testcontainers (IntegrationTest, ApplicationTest, TrustListDownloadOfflineTest, SignCmsEndpoint test signer).
    • Fixtures under src/test/resources/fixtures/ (PDFs, certs, encryption keys, JSON).
  • Run: ./gradlew test (→ Kover XML+HTML auto-generated). Containerized helper: bin/show-coverage.sh. CI: .travis.yml runs ./gradlew clean build koverXmlReport. Coverage → SonarCloud (build/reports/kover/report.xml; build.gradle.kts:86-100, sonar-project.properties).
  • Sub-projects also have tests: pdfclient/src/test/.../FileServiceTest.kt, trust-list-downloader/src/test/** (incl. internet-requiring functional/LotlCertificateTest.kt).

Testcontainers needs the Docker socket

Integration tests spin up real RabbitMQ containers — bin/show-coverage.sh mounts /var/run/docker.sock into the test container for this reason.


9. Dependencies on other FaceKom services / infra

Evidenced in code/config:

  • RabbitMQ (required, central): the only transport. Consumes RPC queues pdf-prepareSignedDocument, pdf-insertSignature, pdf-validate, pdf-checkActiveComponents (application.properties:23-26, RabbitMqConnector.kt). Prod connects over AMQPS amqps://rabbitmq:5671 with mutual-TLS using certs at /workspace/vuer_mq_cert/client/ (application.properties:28-36). Quorum queues with delivery-limit=30 (RabbitMqProperties.kt). RPC partner = the FaceKom core/orchestration that calls these queues (the external signer signs the dataToBeSigned digest between prepare and insert).
  • External RFC 3161 TSA: https://bteszt.e-szigno.hu/tsa (e-Szignó test TSA) for PAdES timestamps (application.properties:51).
  • EU PKI / internet (outbound): AIA, OCSP, CRL endpoints queried directly for revocation during online validation (ValidationConfig.kt:128-154); EU LOTL at https://ec.europa.eu/tools/lotl/eu-lotl.xml (offline-cached in tl_cache/). CHANGELOG 2.0.0 notes this is now direct — the old trust-list-proxy/nginx dependency was removed (CHANGELOG.md:1-14).
  • Shared paths (host volumes, prod): /workspace/pdfservice (app), /workspace/tl_cache (trust-list cache), /workspace/vuer_mq_cert/client/ (mq certs). Implies a vuer_docker-style compose providing RabbitMQ, PostgreSQL & nginx (README.md:70-81) — but no DB/Redis usage in pdfservice’s own code (no JDBC/Redis deps in build.gradle.kts; the service is stateless beyond the on-disk trust-list cache).

No HTTP server / no DB

pdfservice exposes no HTTP endpoints (WebApplicationType.NONE) and uses no database or Redis. All I/O is RabbitMQ in + outbound HTTP(S) to PKI/TSA.


10. Verified gotchas

Trust-list cache must be pre-populated (prod)

With trustList.enabled=true, startup throws IllegalStateException if trustList.cacheLocation (/workspace/tl_cache) is missing/empty — the service refuses to accept RabbitMQ messages until trust lists load (LotlTrustListSourceProvider.kt:33-38, RabbitMqConnector @DependsOn). The tl_cache/ dir in-repo seeds this; CI (check_trust_lists.yml) refreshes it weekly via PR.

"Lenient" / no-trust-list validation is dev-only and silently ignored in prod

trustList.enabled=false, validateCertWithTrustLists=false, checkCertValidityOnLoad=false, signWithCertOutOfDateRange=true, and the LogOnStatusAlert relaxations only take effect when the active profile is dev/test/staging (ValidationConfig.isDevelopment, SigningConfig.kt:101-105). In prod these toggles are forced to the strict path regardless of config — confirmed by both code and docs/.../configuration.adoc:9,13,59-61.

External-CMS signing — pdfservice does not own the key

Signing is split: prepare returns digests, an external signer produces the CMS, insert embeds it. The bundled FaceKomPDFSigner jar (README workaround) is absent from this clone’s libs/. If you try to run the full sign flow locally you must supply that signer (or use the pdfclient test-signer for tests).

Default truststore password is empty string

The LOTL/keystore PKCS12 sources are opened with "".toCharArray() (empty password) — ValidationConfig.kt:274,280, trust-list-downloader/.../TrustListDownloader.kt:67. Not a typo.

application-dev.properties points rabbit at localhost guest

Dev profile uses amqp://guest:guest@localhost:5672 with TLS disabled; do not assume prod-like AMQPS in dev (application-dev.properties:11-18).

Docs are partly aspirational / bilingual

docs/chapters/application/configuration.adoc lists jwt.* (signing/encryption keys) and several signer-config.visual-signature.* keys (backgroundColor/originX/width/…) that map to DSS-based visual config or to the mq lib’s JWE handling — jwt.* keys are not read by any Kotlin file in this repo (grep found none). Treat the AsciiDoc as a system spec, the .properties + @ConfigurationProperties classes as ground truth. Attachment encryption/JWE (A256KW, per CHANGELOG 1.0.3/1.0.4) is handled inside the vendored com.facekom.mq jar, not in this source tree.


Unverified / gaps

  • Surveyed structurally, not line-by-line:
    • service/signature/visuals/** and …/textmeasurement/** (read VisualSignatureComponent in full + class names of the rest; the geometry resolvers ContentDimensionResolver/LayoutDimensionResolver/ContainerPlacementResolver were not each read line-by-line).
    • service/signature/cms/** (read the CmsSignatureValidator interface; the three impls’ bodies surveyed by name/test only).
    • All model/** DTOs (read SignatureValidityLevel; others identified by filename, excluded from coverage per build.gradle.kts:80 packages("*model*")).
    • Full aspect/** bodies, exception/** bodies, and most *Test.kt bodies (enumerated, not read individually).
    • trust-list-downloader/alerthandler/**, alertdetector/**, configuration/**, TrustStoreBuilder, FileHandler (read Main, TrustListDownloader, application.yml; helpers surveyed by name).
    • pdfclient/** beyond App.kt (commands/services identified by filename).
    • .github/scripts/*.pycheck_trust_lists.py read in full; others read by head only.
    • docs/chapters/** and docs/puml/** — read pdfservice.adoc, rabbitmq.adoc, configuration.adoc; remaining chapters/PUML not read.
  • The vendored com.facekom.mq jar internals (encryption/JWE, ConnectionPool/QueueManager semantics) are a binary dependency — not decompiled per read-only/no-vendored rules.
  • config/local.properties / local.json secret values are git-ignored and absent — exact secret keys (rabbit truststore passwords, JWE key) unknown.
  • The exact identity of the upstream RabbitMQ caller service (which FaceKom component publishes to these RPC queues) is not named in this repo; inferred only as “FaceKom core / external signer”.

Sources

Files read (all under /Users/levander/coding/facekom-v2-clones/pdfservice/):

  • README.md, CHANGELOG.md, build.gradle.kts, settings.gradle, gradle.properties, .travis.yml, .dockerignore, sonar-project.properties, supervisor_pdfservice_dev.conf, supervisor_pdfservice_docker.conf
  • bin/show-coverage.sh, bin/tag-latest.sh
  • src/main/kotlin/com/facekom/pdfservice/PdfServiceApplication.kt
  • src/main/kotlin/com/facekom/pdfservice/messaging/RabbitMqConnector.kt
  • src/main/kotlin/com/facekom/pdfservice/messaging/endpoints/{Prepare,Insert,Validate}SignatureEndpoint.kt, CheckActiveComponentsEndpoint.kt
  • src/main/kotlin/com/facekom/pdfservice/configuration/{MessagingConfig,RabbitMqProperties,ValidationConfig,SigningConfig,VisualSignatureConfig,VisualSignatureProperties,JsonConfig,LoggerConfig}.kt
  • src/main/kotlin/com/facekom/pdfservice/service/signature/SigningService.kt, service/signature/cms/CmsSignatureValidator.kt, service/signature/visuals/VisualSignatureComponent.kt
  • src/main/kotlin/com/facekom/pdfservice/service/validation/{PdfValidationService,PdfValidationComponent,TrustListPdfValidationService,OfflinePdfValidator,LotlTrustListSourceProvider}.kt
  • src/main/kotlin/com/facekom/pdfservice/service/cryptography/CryptographyService.kt
  • src/main/kotlin/com/facekom/pdfservice/service/checkactivecomponents/CheckActiveComponentService.kt
  • src/main/kotlin/com/facekom/pdfservice/service/message/{MessagingService,AttachmentComponent}.kt
  • src/main/kotlin/com/facekom/pdfservice/model/validation/SignatureValidityLevel.kt
  • src/main/resources/application.properties, application-dev.properties
  • src/test/kotlin/com/facekom/automation/AutomationTest.kt (+ test tree listing)
  • docker/localdev/pdfservice.Dockerfile, pdfclient.Dockerfile, run-pdfservice.yml
  • trust-list-downloader/build.gradle.kts, src/main/kotlin/com/facekom/trustlistdownloader/Main.kt, service/TrustListDownloader.kt, src/main/resources/application.yml
  • pdfclient/src/main/kotlin/com/facekom/pdfclient/App.kt
  • docs/pdfservice.adoc, docs/chapters/misc/rabbitmq.adoc, docs/chapters/application/configuration.adoc
  • .github/workflows/{auto_release,check_trust_lists,vulnerability_scan}.yml, .github/scripts/check_trust_lists.py (+ heads of vulnerability_scan.py, notifications.py, notify_pr.py, notify_release.py, file_handler.py)
  • .run/pdfservice dev.run.xml
  • Directory listings + LFS/attribute checks for tl_cache/, libs/com/facekom/, src/main, src/test, top-level.

Sibling docs: architecture-overview · customization-architecture · vuer_oss