Feature/ebilling generate then validate#1008
Open
jbagsik wants to merge 44 commits into
Open
Conversation
…tion in constructors
Introduce FormatRegistry with a zugferd generator strategy, additive format/artifact_content_hash columns, and rename storage columns so the later pipeline reorder can land without changing current XML→validate→merge behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
Prefactor for e-billing#5 so the upcoming BT-3 allowlist lands in one place. Co-authored-by: Cursor <cursoragent@cursor.com>
Untrusted bill_data could previously steer UNTDID codes via raw passthrough, numeric codelist lookup, or substring matching. Gate all resolution paths on allowed_document_type_codes (default 380/381). Co-authored-by: Cursor <cursoragent@cursor.com>
Pin SHA-256 digests for the validator JAR and XRechnung zip, reject zip-slip entries and HTTP redirect downgrades, stage verified artifacts before install, and resolve the JAR path deterministically from config. Closes mooxphp/kosit-validator#1 Co-authored-by: Cursor <cursoragent@cursor.com>
Add InstallerBasePathGuard and InstallerDownloadUrlGuard so --force only replaces validator/ and xrechnung/ subdirs and downloads are limited to itplr-kosit GitHub release paths unless explicitly overridden for testing. Closes mooxphp/kosit-validator#2 Co-authored-by: Cursor <cursoragent@cursor.com>
Happy-path install tests now use storage-scoped base paths and allowlisted GitHub download URLs with both escape hatches disabled, so guards are exercised on every install test run. Closes mooxphp/kosit-validator#8 Co-authored-by: Cursor <cursoragent@cursor.com>
Moves staging, backup, promote, and rollback out of InstallKositCommand so the handler stays thin. Adds KositInstallPaths value object and unifies guard throw-on-invalid methods to assertValid. Closes mooxphp/kosit-validator#9 Co-authored-by: Cursor <cursoragent@cursor.com>
Deduplicate recursive filename lookup in resolveStagedJar and scenariosPath, and consolidate repeated release-checksum config comments. Co-authored-by: Cursor <cursoragent@cursor.com>
Extract shared download Guzzle options and replace Http::fake redirect coverage with MockHandler tests that exercise actual redirect protocol enforcement offline in CI. Closes mooxphp/kosit-validator#6 Co-authored-by: Cursor <cursoragent@cursor.com>
Add an optional filesOnly flag so scenariosPath keeps prior iterator semantics while resolveStagedJar still skips directory name collisions. Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve existing base paths via realpath so symlink escapes fail containment, validate paths.* as single safe directory names, and reject before download. Closes mooxphp/kosit-validator#7 Co-authored-by: Cursor <cursoragent@cursor.com>
Keep canonical tests/TestCase.php via composer autoload-dev; delete src/Tests copy and symlink, drop in-file autoloader shim, fix migration path. Closes mooxphp/kosit-validator#3 Co-authored-by: Cursor <cursoragent@cursor.com>
Defence-in-depth for issue #5: validate() re-hashes the on-disk validator JAR before spawning Java, and SafeZipExtractor rejects entry names containing null bytes alongside existing zip-slip protections. Co-authored-by: Cursor <cursoragent@cursor.com>
Add fromConfig() so runtime KositService path resolution uses the same segment validation as kosit:install, with Pest coverage for rejections. Closes mooxphp/kosit-validator#10. Co-authored-by: Cursor <cursoragent@cursor.com>
Closes mooxphp/kosit-validator#11 Co-authored-by: Cursor <cursoragent@cursor.com>
Verify the pinned XRechnung ZIP at validate time and execute from a private temp extract so tampering the on-disk tree cannot affect runs. Hash the validator JAR in memory and spawn Java from a private temp copy. Treat missing bundle as not installed so legacy layouts prompt reinstall. Closes mooxphp/kosit-validator#12 Co-authored-by: Cursor <cursoragent@cursor.com>
Replace GenerateXmlJob/ValidateXmlJob/MergeZugferdPdfJob with GenerateArtifactJob and ValidateArtifactJob; build unencrypted hybrid PDFs before KOSIT, store SHA-256 on pass, and gate artifact downloads on validated status. Closes mooxphp/e-billing#2. Co-authored-by: Cursor <cursoragent@cursor.com>
ValidateArtifactJob now runs veraPDF alongside KOSIT for hybrid formats when installed, persists VeraPdfValidation records, and falls back to KOSIT-only when veraPDF is not configured. Includes moox/verapdf package and Seam 1 tests. Closes mooxphp/e-billing#3 Co-authored-by: Cursor <cursoragent@cursor.com>
Three-format registry (XRechnung / ZUGFeRD / Factur-X), EBillingFormatResolver reads companies.data.preferred_ebilling_format with frozen-on-generation semantics, profile-aware CII generation via ZugferdConverter. Closes mooxphp/e-billing#4. Co-authored-by: Cursor <cursoragent@cursor.com>
Extract ArtifactValidationPersister for shared KOSIT record+attach logic; veraPDF verdicts persist via supplemental closures so the shared seam does not type-hint optional validator packages. Closes mooxphp/e-billing#7. Co-authored-by: Cursor <cursoragent@cursor.com>
Extract PipelineFixtures::arrangeInvoice and named Kosit/veraPDF result factories so each scenario shows only what varies, cutting Sonar duplicated-lines noise without changing coverage. Co-authored-by: Cursor <cursoragent@cursor.com>
Extract seedVerifiedKositInstall and kositInvoiceXmlPath so each integrity test starts from a verified install and states only its tampering step. Pure test refactor — no production behaviour change. Closes mooxphp/kosit-validator#13 Co-authored-by: Cursor <cursoragent@cursor.com>
Wire scenariosPath into the tampered-tree integrity test so the returned handle is the tamper target at the call site. Co-authored-by: Cursor <cursoragent@cursor.com>
Wrap or extract over-long lines in the generate-then-validate surface and put empty-class braces on their own line; document that Pint cannot enforce a 120-col limit. Co-authored-by: Cursor <cursoragent@cursor.com>
Move Filament panel boot into opt-in FilamentTestCase so integrity tests no longer pull the duplicated Filament harness (#14). Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Replace file-level Pint exclusions with single_line_empty_body: false so Sonar-compatible braces stick without skipping the two classes entirely. Co-authored-by: Cursor <cursoragent@cursor.com>
Hoist checksum messages and test download URLs to named constants, wrap jarPath errors, and document that Pint cannot enforce a 120-col limit. Co-authored-by: Cursor <cursoragent@cursor.com>
Decompose validation orchestration and resolver lookup into named private stages without changing behaviour (closes mooxphp/e-billing#10). Co-authored-by: Cursor <cursoragent@cursor.com>
…tion. Extract backup, promote, rollback, and discard into private methods so checksum-verified staging still completes before any final-location move (#16). Co-authored-by: Cursor <cursoragent@cursor.com>
Extract named private phases so SonarQube complexity stays under threshold without changing install/validate behaviour or message shaping. Docs unchanged: pure internal refactor, no public API or CLI surface change (verapdf#9). Co-authored-by: Cursor <cursoragent@cursor.com>
Adapters implement moox/zugferd contracts that use PHP 8.4 property hooks; without an explicit constraint the package inherited core's 8.2/8.3 support and would fatal-parse on those runtimes. Co-authored-by: Cursor <cursoragent@cursor.com>
…hub.com/mooxphp/moox into feature/ebilling-generate-then-validate
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Summary
Inverts the e-billing conversion pipeline from validate-then-merge to generate-then-validate, so we validate the artifact we actually deliver (loose XRechnung XML or hybrid ZUGFeRD/Factur-X PDF). Introduces a format-strategy seam (XRechnung / ZUGFeRD / Factur-X), per-customer format resolution, a new
moox/verapdfpackage for PDF/A-3 checks on hybrids, and hardening of the KoSIT installer/runtime.What changed
moox/e-billingGenerateXmlJob/ValidateXmlJob/MergeZugferdPdfJob→GenerateArtifactJob→ValidateArtifactJobFormatRegistrywith three CII-based formats — XRechnung (pure XML,XRECHNUNGprofile), ZUGFeRD and Factur-X (hybrid PDF,EN16931)EbillingFormatResolverreadscompanies.data.preferred_ebilling_format, falls back todefault_formatconfig; format frozen onebilling_documents.formatat generation timemoox/verapdfis installed (KOSIT-only degraded mode otherwise). Shared persistence viaArtifactValidationPersisterqpdf --encrypt);artifact_content_hashstored on validation passgateway_status(generating,generation_failed,validating,validated,validation_failed,validator_error,ignored_foreign)ArtifactGenerated,ArtifactValidated,ArtifactValidationFailedvalidated+ stored hashInvoice/InvoiceLineare pure DTOs; code resolution moved to adapter/mapper layer (DocumentTypeCodeResolver,UnitCodeResolver,VatIdNormalizer)xml_storage_path+pdf_storage_path(hybrids only) +formatcolumn (fresh schema — no data migration, dev DB wipe expected)moox/verapdf(new package)VeraPdfService,VeraPdfResult, audit model + morph pivot, Pest testsmoox/kosit-validatorkosit:install(checksum verification, safe ZIP extraction, path/URL guards, scoped--forcedeletion)KositInstallPathsKositInstaller,RecursiveFileFinder, and related installer support classesmoox/zugferddocumentTypeCodeandunitCodefrom adapters (no resolution inside DTOs)Breaking changes
MergeZugferdPdfJobremoved as a pipeline stagegateway_statusenum values changedzugferd_storage_path→xml_storage_path/pdf_storage_path)Invoice/InvoiceLineconstructors no longer resolve UNTDID/Rec-20 codes — host parsers and mappers must supply resolved codes or use the new resolvers at boundariesDeploy note: republish config/migrations and wipe or recreate
ebilling_documentsin dev: