Skip to content

Fixa uppdaterare och auditlogg-integritet vid SIE-ersättningsimport#98

Merged
perNyfelt merged 5 commits into
mainfrom
fix/updater-och-auditlogg-integritet
Jul 24, 2026
Merged

Fixa uppdaterare och auditlogg-integritet vid SIE-ersättningsimport#98
perNyfelt merged 5 commits into
mainfrom
fix/updater-och-auditlogg-integritet

Conversation

@perNyfelt

Copy link
Copy Markdown
Member

Summary

  • Windows-uppdateraren skrev bara om klassvägsraden för huvud-jaren i AlipsaAccounting.cfg. Om en beroende-jar (t.ex. swing-widgets) bytte version mellan releaser blev raden kvar och pekade på en fil som redan tagits bort, så appen startade inte efter uppdatering 1.5.1 → 1.6.1. Klassvägen genereras nu från de jar-filer som faktiskt finns i den uppackade releasen.
  • Samma skript lämnade ibland kvar ett "The batch file cannot be found"-fönster (call :main-mönstret krävde att cmd.exe läste tillbaka filen efter att :main returnerat). Skriptkroppen omdirigeras nu som ett enda block i stället.
  • archiveFiscalYearAuditLogRows() (körs vid SIE-ersättningsimport) nollställde referenskolumner på arkiverade auditrader utan att räkna om entry_hash, vilket permanent bröt validateIntegrity() för de raderna. V27 tar bort de begränsande FK:erna och återställer redan skadade rader; arkivering nollställer inte längre kolumnerna.
  • Det avslöjade en andra, sedan tidigare existerande bugg i validateIntegrityForCompany(): den kände inte till att arkivering avsiktligt hoppar över arkiverade rader i kedjan, så första icke-arkiverade raden efter en arkivering flaggades felaktigt. Validering och rebuildIntegrityChain() känner nu igen hoppet.

Test plan

  • ./gradlew :app:test (hela testsviten) — grön
  • Regressionstest i SieImportExportServiceTest som kör en riktig ersättningsimport och verifierar att validateIntegrity() är ren efteråt
  • Nytt Windows-exekveringstest i UpdateServiceUpdaterScriptTest som faktiskt kör det genererade .bat-skriptet
  • Manuellt verifierat mot en verklig, tidigare trasig lokal installation: uppdaterare, "Startup-verifiering"-varningen och de kvarvarande terminalfönstren är alla borta efter fixen

🤖 Generated with Claude Code

perNyfelt and others added 5 commits July 23, 2026 22:48
Windows-uppdateraren skrev bara om klassvägsraden för huvud-jaren
(app-*.jar) i AlipsaAccounting.cfg. Om en beroende-jar bytte version
mellan releaser (t.ex. swing-widgets 1.1.1 -> 1.1.2) blev den gamla
raden kvar och pekade på en fil som redan flyttats till backup och
tagits bort, vilket gjorde att appen inte startade efter uppdatering.

Klassvägen genereras nu från de jar-filer som faktiskt finns i den
uppackade releasen, och kopieras in via en förberedd .cfg-fil i
stället för radvis sed/PowerShell-textersättning.

Samtidigt åtgärdas ett kvarvarande "The batch file cannot be found"-
fönster: call :main-mönstret krävde att cmd.exe läste tillbaka filen
efter att :main returnerat, vilket kunde slå fel om filen tillfälligt
var otillgänglig (t.ex. antivirus-skanning). Hela skriptkroppen
omdirigeras nu som ett enda block i stället.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
archiveFiscalYearAuditLogRows() nollställde voucher_id/fiscal_year_id
med mera på arkiverade auditrader för att kringgå "on delete restrict"
innan de underliggande verifikationerna togs bort. entry_hash beräknas
dock utifrån just de kolumnerna vid skrivtillfället och räknades aldrig
om, så validateIntegrity() flaggade permanent alla arkiverade rader
efter en ersättningsimport från SIE.

V27 tar bort de begränsande främmande nycklarna från audit_log (en
revisionslogg ska inte vara låst av poster som senare kan renderas) och
återställer voucher_id/fiscal_year_id på redan skadade rader utifrån
den orörda details-texten. archiveFiscalYearAuditLogRows() nollställer
inte längre kolumnerna.

Detta avslöjade en andra, sedan tidigare existerande bugg: validate-
IntegrityForCompany() antog att alla rader bildar en obruten kedja i
id-ordning, men arkivering återställer avsiktligt kedjehuvudet till
senaste *icke arkiverade* rad så att nya händelser hoppar över de
arkiverade. Det är första gången företaget körde en ersättningsimport,
så detta hade aldrig synts förut. Valideringen känner nu igen hoppet,
och rebuildIntegrityChain() sätter kedjehuvudet till senaste icke
arkiverade rad i stället för sista raden rakt av.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
StandardCharsets-importen hade fel alfabetisk position, vilket fick
CI:s spotlessGroovyCheck att fela.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Testet jämförde det genererade Windows-skriptets innehåll mot en
hårdkodad "\\"-separator, men Path.toString() ger "/" när testet körs
på en Linux-CI-körare (bara os.name simuleras som Windows, filsystemet
är fortfarande Linux). Bygger nu förväntad sökväg från samma Path-
objekt som produktionskoden använder, precis som redan gjordes för
motsvarande unix-test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… ombyggnad

Tre separata fynd från PR-granskning:

- V27 återställde bara voucher_id/fiscal_year_id, men den gamla arkiveringskoden
  nollställde alla fem referenskolumner (även attachment_id/accounting_period_id/
  vat_period_id) oavsett händelsetyp. Arkiverade bilage-, periodlås- och
  momshändelser fortsatte därför fela validateIntegrity() efter migreringen.
  Flyttade återställningen från SQL-regex i migreringen till testbar Groovy
  (AuditLogService.repairArchivedReferencesFromDetails), som hanterar alla fem
  fält och alla händelsetyper - inklusive VAT_PERIOD_LOCKED där voucher_id
  historiskt spelades in under nyckeln transferVoucherId, inte voucherId. Det
  som ändå inte går att återställa (t.ex. CANCEL_VOUCHER, som aldrig sparade
  fiscalYearId i details) stängs igen genom att bygga om företagets hashkedja
  (repairIntegrityForAllCompanies), som DatabaseService nu kör exakt en gång,
  precis när en databas passerar V27.

- rebuildIntegrityChain() kedjade fortfarande levande rader genom arkiverad
  historik: batchPreviousHash uppdaterades för varje rad oavsett arkiverings-
  status, så en levande rad efter en arkiverad blev kedjad till den arkiverade
  radens hash i stället för till den senaste levande radens - trots att
  arkiveringsmodellen (och validate IntegrityForCompany) förutsätter att
  levande rader hoppar över arkiverad historik. Ombyggnaden särskiljer nu
  rå-kedjan (som arkiverade rader kedjas mot) från den levande kedjan (som
  levande rader kedjas mot), exakt som vid vanlig skrivning.

- Återställde en kort kommentar om att Windows-skriptets avsaknad av
  självradering (till skillnad från Unix-skriptets rm -f "$0") är avsiktlig,
  inte ett förbiseende - annars ser en framtida läsare bara en förvirrande
  asymmetri.

Nya regressionstester i AuditLogServiceTest täcker båda fynden: en som
verifierar att en levande rad efter en nyligen arkiverad hoppar över den vid
ombyggnad, och en som skapar arkiverade rader av flera händelsetyper
(inklusive en med genuint irreparabelt fält) och verifierar att alla
referenser som går att återställa faktiskt återställs och att hela kedjan
validerar rent efteråt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@perNyfelt
perNyfelt merged commit 2883929 into main Jul 24, 2026
3 checks passed
@perNyfelt
perNyfelt deleted the fix/updater-och-auditlogg-integritet branch July 24, 2026 10:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant