]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commit
refactor(ocpp2): OCPP 2.0.1 audit fixes — spec compliance, type safety, test coverage...
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Tue, 3 Mar 2026 17:08:43 +0000 (18:08 +0100)
committerGitHub <noreply@github.com>
Tue, 3 Mar 2026 17:08:43 +0000 (18:08 +0100)
commit26c08ac2eaedc641d67cdc5d47c9ef5bc19e69d0
tree101e00fe78a2c951912bc988db7dff60d53df426
parent9d923d52097db14f7678c221a3853d483de837b6
refactor(ocpp2): OCPP 2.0.1 audit fixes — spec compliance, type safety, test coverage (#1697)

* feat(ocpp2): add TriggerMessage, UnlockConnector and TransactionEvent types

* fix(tests): resolve pre-existing LSP type errors in test infrastructure

* refactor(ocpp2): extract enforceMessageLimits utility to eliminate DRY violation

* refactor(ocpp2): dynamic isComponentValid and fix OCPP 1.6 key usage

* feat(ocpp2): handle TransactionEventResponse fields

* feat(ocpp2): implement TriggerMessage/UnlockConnector handlers and Reset hardening

- Implement TriggerMessage handler (F06): supports BootNotification,
  Heartbeat, and StatusNotification triggers with EVSE targeting
- Implement UnlockConnector handler (F05): full spec compliance with
  Unlocked, UnlockFailed, OngoingAuthorizedTransaction, UnknownConnector
  response statuses
- Add AllowReset variable check and firmware update blocking to Reset handler
- Add 4 missing schema validations for certificate commands
- Add TriggerMessage/UnlockConnector schema validator configs
- Document RFC 6960 DER encoding deviation in computeCertificateHash

* refactor(ocpp2): eliminate unsafe type casts in handlers and VariableManager

- Add private toHandler() helper in OCPP20IncomingRequestService that concentrates
  the single 'as unknown as IncomingRequestHandler' cast with documentation comment
- Replace 13 per-binding casts in constructor with this.toHandler() calls
- Remove 15 'as unknown as StandardParametersKey' casts from OCPP20VariableManager —
  string is already a member of ConfigurationKeyType, no cast needed
- Remove now-unused import of StandardParametersKey from OCPP20VariableManager

* feat(ocpp2): expose TriggerMessage and UnlockConnector handlers in testable interface

* test(ocpp2): add TriggerMessage handler tests (F06) — 14 tests

* test(ocpp2): add UnlockConnector handler tests (F05) — 9 tests

* test(ocpp2): add TransactionEventResponse handler tests (E01-E04) — 7 tests

* test(ocpp2): fix firmware blocking tests and add AllowReset variable guard tests (T22) — 25 tests

* fix(ocpp2): add AJV strict:false and schema validation unit tests (T21)

- Set strict:false in all three AJV constructors (IncomingRequest, Request,
  Response) to allow OCPP 2.0 schemas that use additionalItems without
  array items (a draft-07 pattern AJV 8 strict mode rejects at compile time)
- Replace integration-style schema tests (blocked by tsx path resolution)
  with direct AJV schema unit tests: load schemas from src/assets directly,
  compile with AJV, verify invalid payloads are rejected — 15 tests pass

* fix(ocpp2): correct registry key separator in isComponentValid (T5-bugfix)

The `#validComponentNames` set was built using split('/') but registry keys
use '::' as separator (e.g. 'AlignedDataCtrlr::Available'). This caused the
set to contain full keys like 'AlignedDataCtrlr::Available' instead of just
component names like 'AlignedDataCtrlr', making isComponentValid return false
for all components and causing UnknownComponent responses for all Set/GetVariables.

Also update the EVSE test to assert UnknownVariable (not UnknownComponent) since
EVSE is a valid component in the registry but AuthorizeRemoteStart is not one of
its variables.

* test(ocpp2): add enforceMessageLimits utility tests (T23) — 14 tests

* test(ocpp2): add integration tests for multi-command flows (T24) — 6 tests

* fix(ocpp2): add error diagnostics, additionalInfo fields, and async timeout guard (T25)

* fix(ocpp2): resolve tsc type errors in UUIDv4 cast, override modifier, and mock cast (F1)

* fix(ocpp2): add try/catch to TriggerMessage and UnlockConnector handlers, add integration test

- Add try/catch blocks to handleRequestTriggerMessage and
  handleRequestUnlockConnector following the handleRequestReset
  golden pattern with structured error responses
- Add 4th integration test: SetVariables on unknown component
  returns rejected, GetVariables confirms unknown component

* fix(ocpp2): address PR review findings — remove dead code, consolidate types, fix test mock

* fix(ocpp2): spec compliance — F06.FR.17 BootNotification guard, F05.FR.02 connector-level tx check

- TriggerMessage: reject BootNotification trigger when last boot was
  already Accepted per F06.FR.17 (returns Rejected + NotEnabled)
- UnlockConnector: check transaction on the specific target connector
  instead of all EVSE connectors per F05.FR.02
- Add 3 new tests covering both spec requirements

* fix(ocpp2): address code review — timer leak, diagnostic logging, TODO annotation

- Fix withTimeout timer leak: clear setTimeout when promise resolves first
- readMessageLimits: replace empty catch with logger.debug diagnostic
- handleResponseTransactionEvent: add TODO noting log-only is intentional,
  future work should act on idTokenInfo.status and chargingPriority

* style: fix jsdoc warnings in OCPP 2.0 handlers and tests

Add missing @returns tags and @param descriptions to satisfy
jsdoc/require-returns and jsdoc/require-param-description ESLint rules.
Replace empty JSDoc blocks with minimal valid documentation to satisfy
jsdoc/require-jsdoc rule. Achieves 0 lint warnings matching main branch
baseline.

* fix(types): reduce tsc errors to zero and fix all lint warnings

Eliminate all TypeScript compiler errors across src/ and test files by
fixing type mismatches, adding missing type annotations, and correcting
union type handling. Fix remaining ESLint issues including no-base-to-string
in ChargingProfile id extraction and jsdoc/tag-lines formatting.

* fix(ocpp2): fix AllowReset dead code, evseId===0 routing, and EVSE-scoped connector lookup

- AllowReset check now resolves via OCPP20VariableManager (runtime value) instead of static registry defaultValue
- Reset handler evseId===0 now routes to full station reset instead of EVSE-specific path
- TriggerMessage StatusNotification uses EVSE-scoped connector lookup instead of global getConnectorStatus

* ci: add typecheck step (tsc --noEmit --skipLibCheck) to CI pipeline

esbuild does not surface type errors at build time, so this catches
regressions before build+test. Runs on ubuntu/node-22 alongside lint.

* fix(ocpp2): remove DiagnosticsStatusNotification from MessageTriggerEnumType

This value is OCPP 1.6 only and not part of the OCPP 2.0.1 spec
(absent from TriggerMessageRequest.json schema).

* docs(readme): align OCPP 2.0.x section with spec and actual code

- Fix section letters to match OCPP 2.0.1 spec (A→B, B→C, C→G, etc.)
- Reorder sections to match spec block order (B,C,D,E,F,G,L,M,P)
- Add missing implemented commands: TriggerMessage, UnlockConnector,
  Get15118EVCertificate, GetCertificateStatus
- Move GetVariables/SetVariables from Monitoring to B. Provisioning
- Replace stale 'variables not implemented' note with actual support listing

* fix(ocpp2): add missing AJV response validators for 7 incoming request commands

CALLRESULT payloads were not validated against JSON schemas for
CertificateSigned, DeleteCertificate, GetInstalledCertificateIds,
GetVariables, InstallCertificate, Reset, and SetVariables.

All schema files already existed; only the validator map registration
was missing. Aligns OCPP 2.0 with OCPP 1.6 which validates all
incoming request responses (17/17).

* style(ocpp2): harmonize comment style with existing OCPP 1.6 sparse convention

Remove ~135 paraphrase/over-comments from OCPP 2.0 source files that
described what the next line obviously does. Keeps spec references
(C11.FR.04, F06.FR.17, OCPP 2.0.1 §2.10), TODO annotations, RFC 6960
deviation notes, eslint-disable directives, and terse comments matching
the existing OCPP 1.6 style. Test @file/@description headers preserved
per test style guide.

* [autofix.ci] apply automated fixes

* fix(ocpp2): correct spec references and harmonize format

- Fix wrong FR code: F03.FR.09 (triggerReason) → F03.FR.04 (meter
  values in TransactionEvent Ended)
- Harmonize FR comment format to 'X00.FR.00: description' style
- Harmonize section references to § symbol (was mixed Section/§)
- Harmonize RFC references to 'RFC 6960 §4.1.1' (was missing §)

* fix(ocpp): remove redundant strict:false from AJV instances

keywords: ['javaType'] already declares the custom keyword, making
strict:false unnecessary. Removing it enables AJV strict mode (default
since v7), which will flag any future non-standard schema keywords
instead of silently ignoring them.

* fix(types): make MeterValuesRequest/Response version-agnostic union types

Remove versioned OCPP16MeterValue import and casts from ChargingStation.ts,
following the established pattern of using union types outside the OCPP stack.

* fix(types): remove versioned type imports from Helpers.ts

Add ChargingSchedule union type, replace satisfies with version-agnostic
BootNotificationRequest, and rename getOCPP16ChargingSchedule to
getSingleChargingSchedule with union return type.

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
63 files changed:
.github/workflows/ci.yml
README.md
package.json
scripts/runtime.d.ts [new file with mode: 0644]
src/charging-station/ChargingStation.ts
src/charging-station/Helpers.ts
src/charging-station/broadcast-channel/ChargingStationWorkerBroadcastChannel.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
src/charging-station/ocpp/2.0/OCPP20CertificateManager.ts
src/charging-station/ocpp/2.0/OCPP20Constants.ts
src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/2.0/OCPP20ResponseService.ts
src/charging-station/ocpp/2.0/OCPP20ServiceUtils.ts
src/charging-station/ocpp/2.0/OCPP20VariableManager.ts
src/charging-station/ocpp/2.0/__testable__/OCPP20RequestServiceTestable.ts
src/charging-station/ocpp/2.0/__testable__/index.ts
src/charging-station/ocpp/OCPPServiceUtils.ts
src/performance/storage/MikroOrmStorage.ts
src/types/index.ts
src/types/ocpp/1.6/Requests.ts
src/types/ocpp/1.6/Responses.ts
src/types/ocpp/2.0/Common.ts
src/types/ocpp/2.0/Requests.ts
src/types/ocpp/2.0/Responses.ts
src/types/ocpp/2.0/Transaction.ts
src/types/ocpp/2.0/index.ts
src/types/ocpp/ChargingProfile.ts
src/types/ocpp/Common.ts
src/types/ocpp/Requests.ts
src/types/ocpp/Responses.ts
tests/charging-station/ChargingStation-Connectors.test.ts
tests/charging-station/ChargingStation-Lifecycle.test.ts
tests/charging-station/ChargingStation-Resilience.test.ts
tests/charging-station/ChargingStation-Transactions.test.ts
tests/charging-station/ChargingStation.test.ts
tests/charging-station/Helpers.test.ts
tests/charging-station/helpers/StationHelpers.ts
tests/charging-station/ocpp/2.0/OCPP20CertificateManager.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-CertificateSigned.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-DeleteCertificate.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-GetVariables.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-InstallCertificate.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-RemoteStartAuth.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-RequestStartTransaction.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-Reset.test.ts
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-TriggerMessage.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/2.0/OCPP20IncomingRequestService-UnlockConnector.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/2.0/OCPP20Integration-Certificate.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/2.0/OCPP20Integration.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/2.0/OCPP20RequestService-ISO15118.test.ts
tests/charging-station/ocpp/2.0/OCPP20RequestService-NotifyReport.test.ts
tests/charging-station/ocpp/2.0/OCPP20RequestService-SignCertificate.test.ts
tests/charging-station/ocpp/2.0/OCPP20ResponseService-TransactionEvent.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/2.0/OCPP20SchemaValidation.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-TransactionEvent.test.ts
tests/charging-station/ocpp/2.0/OCPP20ServiceUtils-enforceMessageLimits.test.ts [new file with mode: 0644]
tests/charging-station/ocpp/2.0/OCPP20TestUtils.ts
tests/charging-station/ocpp/2.0/OCPP20VariableManager.test.ts
tests/charging-station/ocpp/auth/adapters/OCPP16AuthAdapter.test.ts
tests/charging-station/ui-server/UIWebSocketServer.test.ts