Skip to content

Add webhook plugin integration and configuration changes#1983

Open
AttriPardeep wants to merge 1 commit intosteve-community:masterfrom
AttriPardeep:webhook-integration
Open

Add webhook plugin integration and configuration changes#1983
AttriPardeep wants to merge 1 commit intosteve-community:masterfrom
AttriPardeep:webhook-integration

Conversation

@AttriPardeep
Copy link

No description provided.

@qodo-free-for-open-source-projects

Review Summary by Qodo

Add webhook plugin integration with async sender and retry mechanism

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add comprehensive webhook plugin for OCPP event integration
• Implement async webhook sender with HMAC-SHA256 signing and retry logic
• Create event models for connector status, transactions, and meter values
• Configure HTTP client with connection pooling and smart meter filtering
• Update production configuration with webhook settings and REST API endpoints
Diagram
flowchart LR
  OCPP["OCPP Events<br/>StatusNotification<br/>StartTransaction<br/>StopTransaction<br/>MeterValues"]
  Listener["OcppEventListener<br/>Converts to webhook events"]
  Sender["WebhookSender<br/>HMAC-SHA256 signing<br/>Async execution"]
  Retry["WebhookRetryQueue<br/>Exponential backoff<br/>Max 3 attempts"]
  Backend["VoltStartEV Backend<br/>Webhook endpoint"]
  
  OCPP -->|Spring events| Listener
  Listener -->|sendAsync| Sender
  Sender -->|success| Backend
  Sender -->|failure| Retry
  Retry -->|scheduled retry| Sender
Loading

Grey Divider

File Changes

1. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/SteveWebhookPluginApplication.java ✨ Enhancement +27/-0

Spring Boot application entry point with scheduling

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/SteveWebhookPluginApplication.java


2. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/AsyncConfig.java ⚙️ Configuration changes +49/-0

Thread pool executor for async webhook sending

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/AsyncConfig.java


3. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/HttpClientConfig.java ⚙️ Configuration changes +66/-0

HTTP client with connection pooling and timeouts

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/HttpClientConfig.java


View more (15)
4. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/WebhookProperties.java ⚙️ Configuration changes +36/-0

Configuration properties for webhook behavior

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/WebhookProperties.java


5. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/SteveWebhookEvent.java ✨ Enhancement +27/-0

Base interface for all webhook events

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/SteveWebhookEvent.java


6. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/ConnectorStatusEvent.java ✨ Enhancement +46/-0

Event model for connector status changes

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/ConnectorStatusEvent.java


7. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/TransactionStartedEvent.java ✨ Enhancement +47/-0

Event model for transaction start events

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/TransactionStartedEvent.java


8. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/TransactionStoppedEvent.java ✨ Enhancement +70/-0

Event model for transaction stop with meter data

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/TransactionStoppedEvent.java


9. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/MeterValuesEvent.java ✨ Enhancement +67/-0

Event model for meter values with sampling support

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/events/MeterValuesEvent.java


10. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java ✨ Enhancement +179/-0

OCPP event listener with smart meter filtering

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java


11. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetry.java ✨ Enhancement +53/-0

Retry model with exponential backoff logic

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetry.java


12. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetryQueue.java ✨ Enhancement +98/-0

Scheduled retry queue processor with backpressure

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetryQueue.java


13. steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java ✨ Enhancement +185/-0

Core webhook sender with HMAC signing and metrics

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java


14. steve-webhook-plugin/pom.xml Dependencies +66/-0

Maven dependencies for webhook plugin

steve-webhook-plugin/pom.xml


15. steve-webhook-plugin/src/main/resources/application.properties ⚙️ Configuration changes +28/-0

Default webhook configuration properties

steve-webhook-plugin/src/main/resources/application.properties


16. steve-webhook-plugin/steve-header.txt 📝 Documentation +17/-0

GPL license header template for source files

steve-webhook-plugin/steve-header.txt


17. steve-webhook-plugin/add-license.sh Miscellaneous +14/-0

Bash script to add license headers to files

steve-webhook-plugin/add-license.sh


18. src/main/resources/application-prod.properties ⚙️ Configuration changes +38/-6

Production config with webhook and REST API settings

src/main/resources/application-prod.properties


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Mar 14, 2026

Code Review by Qodo

🐞 Bugs (7) 📘 Rule violations (5) 📎 Requirement gaps (0)

Grey Divider


Action required

1. db.password plaintext in prod 📘 Rule violation ⛨ Security
Description
The production properties file now contains a hardcoded database password in plaintext. This
violates boundary security hardening requirements and risks credential leakage via source control or
deployments.
Code

src/main/resources/application-prod.properties[13]

+db.password = StevePass2026!
Evidence
PR Compliance ID 5 forbids persisting secrets in plaintext; the PR changes db.password from a
placeholder to a real-looking password in application-prod.properties.

src/main/resources/application-prod.properties[13-13]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`application-prod.properties` contains a plaintext database password (`db.password`), which is prohibited for production secret storage.

## Issue Context
Compliance requires secrets not be persisted in plaintext in repo-tracked configuration.

## Fix Focus Areas
- src/main/resources/application-prod.properties[13-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. voltstartev.webhook.secret in prod 📘 Rule violation ⛨ Security
Description
The production configuration adds a webhook shared secret value directly in the properties file.
Storing shared secrets in plaintext configuration violates secret storage hardening and increases
leak risk.
Code

src/main/resources/application-prod.properties[83]

+voltstartev.webhook.secret=your-super-secret-webhook-key-min-32-characters
Evidence
PR Compliance ID 5 requires protecting credentials and forbids plaintext secret persistence; the PR
adds voltstartev.webhook.secret directly in prod properties.

src/main/resources/application-prod.properties[83-83]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Production config stores `voltstartev.webhook.secret` as plaintext in a repo-tracked properties file.

## Issue Context
Webhook shared secrets should be injected at runtime (env var / secret manager), not committed.

## Fix Focus Areas
- src/main/resources/application-prod.properties[83-83]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. webhook.secret committed in plugin 📘 Rule violation ⛨ Security
Description
The plugin’s application.properties commits a concrete HMAC secret value. This is plaintext secret
persistence and risks credential exposure if the repository or artifacts are shared.
Code

steve-webhook-plugin/src/main/resources/application.properties[R8-10]

+# Shared secret for HMAC-SHA256 signature (MUST MATCH backend)
+voltstartev.webhook.secret=4c89055d36eefb7fd2422483544bd7a39dbb62d06b0b3c04bdc9dd709bf46fc8
+
Evidence
PR Compliance ID 5 forbids storing secrets in plaintext; the plugin configuration includes a fixed
voltstartev.webhook.secret value.

steve-webhook-plugin/src/main/resources/application.properties[8-10]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A real webhook HMAC secret is committed in `steve-webhook-plugin/src/main/resources/application.properties`.

## Issue Context
Per compliance, secrets must not be persisted in plaintext in repository configuration.

## Fix Focus Areas
- steve-webhook-plugin/src/main/resources/application.properties[8-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (6)
4. Unresolved webapi placeholders 🐞 Bug ✓ Correctness
Description
In prod, webapi.key and webapi.value are commented out, but application.yml still requires
${webapi.key}/${webapi.value}, which can prevent Spring from resolving placeholders and stop SteVe
from starting in the prod profile.
Code

src/main/resources/application-prod.properties[R23-24]

+#webapi.key = STEVE-API-KEY
+#webapi.value =  
Evidence
SteVe binds steve.auth.web-api-key/secret from placeholders ${webapi.key}/${webapi.value}. The prod
properties file no longer defines those keys, so the placeholders may become unresolvable at
startup.

src/main/resources/application-prod.properties[20-25]
src/main/resources/application.yml[38-47]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Prod profile comments out `webapi.key`/`webapi.value`, but `application.yml` still references `${webapi.key}`/`${webapi.value}`. This can lead to unresolved placeholders and application startup failure.

### Issue Context
`steve.auth.web-api-key` and `steve.auth.web-api-secret` are bound from these placeholders.

### Fix Focus Areas
- src/main/resources/application-prod.properties[20-25]
- src/main/resources/application.yml[38-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Prod service exposed publicly 🐞 Bug ⛨ Security
Description
application-prod.properties binds the server to 0.0.0.0 and enables extensive DEBUG logging,
increasing exposure of the admin interface and sensitive operational data in logs.
Code

src/main/resources/application-prod.properties[R34-37]

+#server.host = 0.0.0.0
+server.address = 0.0.0.0
+server.port = 8080
server.gzip.enabled = true
Evidence
The prod profile now listens on all interfaces while still using a trivial admin password; combined
with DEBUG logging, this increases the blast radius of any exposed instance and risks leaking
operational/security-relevant details.

src/main/resources/application-prod.properties[15-19]
src/main/resources/application-prod.properties[32-37]
src/main/resources/application-prod.properties[90-98]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Prod config binds on `0.0.0.0` and enables DEBUG logging broadly, while retaining weak default admin credentials.

### Issue Context
This combination significantly increases attack surface and risks log-based data exposure.

### Fix Focus Areas
- src/main/resources/application-prod.properties[15-19]
- src/main/resources/application-prod.properties[32-37]
- src/main/resources/application-prod.properties[90-98]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Missing Lombok dependency 🐞 Bug ✓ Correctness
Description
steve-webhook-plugin uses Lombok annotations (@Data, @AllArgsConstructor, etc.) but does not declare
Lombok in its pom.xml, which will fail compilation of the plugin module.
Code

steve-webhook-plugin/pom.xml[R19-56]

+    <dependencies>
+        <!-- Spring Boot -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        
+        <!-- HTTP Client with connection pooling -->
+        <dependency>
+            <groupId>org.apache.httpcomponents.client5</groupId>
+            <artifactId>httpclient5</artifactId>
+            <version>5.2.1</version>
+        </dependency>
+        
+        <!-- JSON Processing -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        
+        <!-- Metrics (optional) -->
+        <dependency>
+            <groupId>io.micrometer</groupId>
+            <artifactId>micrometer-registry-prometheus</artifactId>
+        </dependency>
+        
+        <!-- SteVe Core (provided by SteVe runtime) -->
+        <dependency>
+            <groupId>de.rwth.idsg</groupId>
+            <artifactId>steve</artifactId>
+            <version>3.11.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
Evidence
The plugin code relies on Lombok but the module pom has no Lombok dependency/annotation processor
configuration, so generated getters/setters/constructors will be missing at compile time.

steve-webhook-plugin/pom.xml[19-56]
steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/WebhookProperties.java[17-24]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Plugin module uses Lombok annotations but does not depend on Lombok, causing compilation failure.

### Issue Context
Multiple plugin classes rely on Lombok-generated methods/constructors.

### Fix Focus Areas
- steve-webhook-plugin/pom.xml[19-56]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/WebhookProperties.java[17-24]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Missing imports break plugin 🐞 Bug ✓ Correctness
Description
steve-webhook-plugin references ThreadPoolExecutor and WebhookProperties without importing them,
which prevents the module from compiling.
Code

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/AsyncConfig.java[R34-43]

+    @Bean(name = "webhookExecutor")
+    public Executor webhookExecutor() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(10);
+        executor.setMaxPoolSize(20);
+        executor.setQueueCapacity(100);
+        executor.setThreadNamePrefix("webhook-");
+        executor.setRejectedExecutionHandler(
+            new ThreadPoolExecutor.CallerRunsPolicy()  // Backpressure: run in caller thread if queue full
+        );
Evidence
AsyncConfig uses ThreadPoolExecutor.CallerRunsPolicy without an import, and other plugin classes use
WebhookProperties but do not import it, causing immediate compilation errors.

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/AsyncConfig.java[17-46]
steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[17-42]
steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetryQueue.java[17-38]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Plugin sources reference types that are not imported, causing compilation to fail.

### Issue Context
`AsyncConfig` uses `ThreadPoolExecutor.CallerRunsPolicy`, and multiple classes reference `WebhookProperties` without importing it.

### Fix Focus Areas
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/AsyncConfig.java[17-46]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[17-42]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetryQueue.java[17-38]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. MeterRegistry DI failure 🐞 Bug ⛯ Reliability
Description
WebhookSender requires a MeterRegistry bean, but the plugin module doesn’t include Spring Boot
actuator autoconfiguration and defines no MeterRegistry bean, so the plugin will fail at startup
with an unsatisfied dependency.
Code

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java[R57-67]

+    public WebhookSender(RestTemplate restTemplate,
+                        WebhookProperties properties,
+                        WebhookRetryQueue retryQueue,
+                        ObjectMapper objectMapper,
+                        MeterRegistry meterRegistry) {
+        this.restTemplate = restTemplate;
+        this.properties = properties;
+        this.retryQueue = retryQueue;
+        this.objectMapper = objectMapper;
+        this.meterRegistry = meterRegistry;
+        
Evidence
The constructor requires MeterRegistry, but the pom only adds the Prometheus registry library and
there is no plugin configuration providing a MeterRegistry bean.

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java[57-67]
steve-webhook-plugin/pom.xml[43-48]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`WebhookSender` requires `MeterRegistry`, but the plugin does not ensure a `MeterRegistry` bean exists.

### Issue Context
Without actuator autoconfiguration or an explicit `@Bean`, Spring will fail to create `WebhookSender`.

### Fix Focus Areas
- steve-webhook-plugin/pom.xml[43-48]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. Webhook integration not triggered 🐞 Bug ✓ Correctness
Description
The plugin’s components are in package com.voltstartev..., which SteVe won’t component-scan, and the
listener subscribes to event types that SteVe doesn’t publish (and MeterValues publishes no event),
so webhook sending will never run in the SteVe runtime.
Code

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[R47-88]

+    @EventListener
+    public void onConnectorStatus(ConnectorStatusUpdate event) {
+        ConnectorStatusEvent webhookEvent = new ConnectorStatusEvent(
+            event.getChargeBoxId(),
+            event.getConnectorId(),
+            event.getStatus().getValue(),
+            event.getErrorCode() != null ? event.getErrorCode().getValue() : null,
+            event.getInfo(),
+            event.getTimestamp(),  // OCPP timestamp
+            Instant.now()          // Received at SteVe
+        );
+        
+        webhookSender.sendAsync("connector.status", webhookEvent);
+    }
+
+    /**
+     * Handle StartTransaction
+     */
+    @EventListener
+    public void onTransactionStart(TransactionStart event) {
+        TransactionStartedEvent webhookEvent = new TransactionStartedEvent(
+            event.getChargeBoxId(),
+            event.getConnectorId(),
+            event.getTransactionId(),
+            event.getIdTag(),
+            event.getStartMeterValue(),
+            event.getStartTimestamp(),
+            Instant.now(),
+            event.getReservationId()
+        );
+        
+        webhookSender.sendAsync("transaction.started", webhookEvent);
+    }
+
+    /**
+     * Handle StopTransaction
+     */
+    @EventListener
+    public void onTransactionStop(TransactionStop event) {
+        // Convert transaction data if present
+        List<TransactionStoppedEvent.MeterValue> transactionData = null;
+        if (event.getTransactionData() != null && !event.getTransactionData().isEmpty()) {
Evidence
SteVe’s application class is in package de.rwth.idsg.steve, so it won’t scan com.voltstartev.* by
default. Separately, SteVe publishes OcppTransactionStarted/OcppTransactionEnded (and status-related
events) but not the ConnectorStatusUpdate/TransactionStart/TransactionStop/EnhancedMeterValue events
the plugin listens to; MeterValues handling in SteVe also doesn’t publish any event at all.

src/main/java/de/rwth/idsg/steve/SteveApplication.java[19-36]
steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[47-67]
steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[125-128]
src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[174-185]
src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[215-223]
src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[248-255]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
Webhook plugin code is not executed because it is neither discovered by SteVe’s component scan nor subscribed to events that SteVe actually publishes.

### Issue Context
SteVe publishes `OcppTransactionStarted`/`OcppTransactionEnded` and does not publish a MeterValues Spring event.

### Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/SteveApplication.java[19-36]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[47-88]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[125-128]
- src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[174-185]
- src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[215-223]
- src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[248-255]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

10. eventTimestamp used without nullcheck 📘 Rule violation ⛯ Reliability
Description
Webhook payload construction dereferences event.getEventTimestamp() without a null check, which
can cause runtime failures if upstream events omit timestamps. This violates the null-safety
requirement for external/nullable inputs.
Code

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java[R119-122]

+        payload.put("chargeBoxId", event.getChargeBoxId());
+        payload.put("connectorId", event.getConnectorId());
+        payload.put("eventTimestamp", event.getEventTimestamp().toString());  // OCPP time
+        payload.put("data", event);  // Full event details
Evidence
PR Compliance ID 3 requires explicit null checks before dereference; WebhookSender calls
event.getEventTimestamp().toString() and the retry/idempotency logic calls toEpochMilli()
without guarding against null.

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java[119-122]
steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetry.java[35-40]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`event.getEventTimestamp()` is dereferenced without null checks in webhook payload creation and idempotency/retry key generation, risking `NullPointerException`.

## Issue Context
Events may originate from external systems; compliance requires explicit null checks and semantically correct exceptions for missing required fields.

## Fix Focus Areas
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java[119-122]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetry.java[35-40]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. event.getTimestamp() null risk 📘 Rule violation ⛯ Reliability
Description
MeterValues filtering dereferences event.getTimestamp() without checking for null, which can
trigger runtime failures when timestamps are absent. This violates the explicit null-check
requirement for nullable/external inputs.
Code

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[R145-148]

+        return event.getSampledValue().stream()
+            .anyMatch(sv -> "Energy.Active.Import.Register".equals(sv.getMeasurand()))
+            && event.getTimestamp().toEpochMilli() % (properties.getMeterValuesMinIntervalSeconds() * 1000) < 5000;
+    }
Evidence
PR Compliance ID 3 requires null checks before dereference; the new filtering logic calls
event.getTimestamp().toEpochMilli() without guarding against null.

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[145-148]
Best Practice: Learned patterns

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`shouldSendMeterValues()` dereferences `event.getTimestamp()` without a null check, risking `NullPointerException`.

## Issue Context
Compliance requires explicit null checks for potentially-null external inputs.

## Fix Focus Areas
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[145-148]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. MeterValues sampling misfilters 🐞 Bug ✓ Correctness
Description
The MeterValues sampling gate uses epoch-modulo time windows, which can consistently suppress
MeterValues webhooks for chargers that report at a fixed offset, causing missing telemetry.
Code

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[R142-148]

+    private boolean shouldSendMeterValues(EnhancedMeterValue event) {
+        // For now, use simple time-based filtering
+        // In production, you'd track last sent time/energy per connector in a cache
+        return event.getSampledValue().stream()
+            .anyMatch(sv -> "Energy.Active.Import.Register".equals(sv.getMeasurand()))
+            && event.getTimestamp().toEpochMilli() % (properties.getMeterValuesMinIntervalSeconds() * 1000) < 5000;
+    }
Evidence
The condition sends only when the event timestamp falls into the first ~5s of each epoch-aligned
interval. If a charger reports periodically with a stable phase offset, the modulo remainder stays
constant and may never satisfy the <5000ms window.

steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[142-148]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
MeterValues sampling is tied to epoch boundaries via modulo arithmetic, which can lead to consistent, silent dropping of events depending on charger reporting phase.

### Issue Context
Sampling should be based on last-sent time/energy per connector/transaction.

### Fix Focus Areas
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[142-148]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

db.schema = stevedb
db.user = steve
db.password = changeme
db.password = StevePass2026!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. db.password plaintext in prod 📘 Rule violation ⛨ Security

The production properties file now contains a hardcoded database password in plaintext. This
violates boundary security hardening requirements and risks credential leakage via source control or
deployments.
Agent Prompt
## Issue description
`application-prod.properties` contains a plaintext database password (`db.password`), which is prohibited for production secret storage.

## Issue Context
Compliance requires secrets not be persisted in plaintext in repo-tracked configuration.

## Fix Focus Areas
- src/main/resources/application-prod.properties[13-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


# SteVe Webhook Plugin Environment Variables
voltstartev.webhook.url=http://localhost:3000/api/webhooks/steve
voltstartev.webhook.secret=your-super-secret-webhook-key-min-32-characters

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. voltstartev.webhook.secret in prod 📘 Rule violation ⛨ Security

The production configuration adds a webhook shared secret value directly in the properties file.
Storing shared secrets in plaintext configuration violates secret storage hardening and increases
leak risk.
Agent Prompt
## Issue description
Production config stores `voltstartev.webhook.secret` as plaintext in a repo-tracked properties file.

## Issue Context
Webhook shared secrets should be injected at runtime (env var / secret manager), not committed.

## Fix Focus Areas
- src/main/resources/application-prod.properties[83-83]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +8 to +10
# Shared secret for HMAC-SHA256 signature (MUST MATCH backend)
voltstartev.webhook.secret=4c89055d36eefb7fd2422483544bd7a39dbb62d06b0b3c04bdc9dd709bf46fc8

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. webhook.secret committed in plugin 📘 Rule violation ⛨ Security

The plugin’s application.properties commits a concrete HMAC secret value. This is plaintext secret
persistence and risks credential exposure if the repository or artifacts are shared.
Agent Prompt
## Issue description
A real webhook HMAC secret is committed in `steve-webhook-plugin/src/main/resources/application.properties`.

## Issue Context
Per compliance, secrets must not be persisted in plaintext in repository configuration.

## Fix Focus Areas
- steve-webhook-plugin/src/main/resources/application.properties[8-10]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +23 to +24
#webapi.key = STEVE-API-KEY
#webapi.value =

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Unresolved webapi placeholders 🐞 Bug ✓ Correctness

In prod, webapi.key and webapi.value are commented out, but application.yml still requires
${webapi.key}/${webapi.value}, which can prevent Spring from resolving placeholders and stop SteVe
from starting in the prod profile.
Agent Prompt
### Issue description
Prod profile comments out `webapi.key`/`webapi.value`, but `application.yml` still references `${webapi.key}`/`${webapi.value}`. This can lead to unresolved placeholders and application startup failure.

### Issue Context
`steve.auth.web-api-key` and `steve.auth.web-api-secret` are bound from these placeholders.

### Fix Focus Areas
- src/main/resources/application-prod.properties[20-25]
- src/main/resources/application.yml[38-47]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +34 to 37
#server.host = 0.0.0.0
server.address = 0.0.0.0
server.port = 8080
server.gzip.enabled = true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

5. Prod service exposed publicly 🐞 Bug ⛨ Security

application-prod.properties binds the server to 0.0.0.0 and enables extensive DEBUG logging,
increasing exposure of the admin interface and sensitive operational data in logs.
Agent Prompt
### Issue description
Prod config binds on `0.0.0.0` and enables DEBUG logging broadly, while retaining weak default admin credentials.

### Issue Context
This combination significantly increases attack surface and risks log-based data exposure.

### Fix Focus Areas
- src/main/resources/application-prod.properties[15-19]
- src/main/resources/application-prod.properties[32-37]
- src/main/resources/application-prod.properties[90-98]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +19 to +56
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- HTTP Client with connection pooling -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>

<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>

<!-- Metrics (optional) -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- SteVe Core (provided by SteVe runtime) -->
<dependency>
<groupId>de.rwth.idsg</groupId>
<artifactId>steve</artifactId>
<version>3.11.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

6. Missing lombok dependency 🐞 Bug ✓ Correctness

steve-webhook-plugin uses Lombok annotations (@Data, @AllArgsConstructor, etc.) but does not declare
Lombok in its pom.xml, which will fail compilation of the plugin module.
Agent Prompt
### Issue description
Plugin module uses Lombok annotations but does not depend on Lombok, causing compilation failure.

### Issue Context
Multiple plugin classes rely on Lombok-generated methods/constructors.

### Fix Focus Areas
- steve-webhook-plugin/pom.xml[19-56]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/WebhookProperties.java[17-24]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +34 to +43
@Bean(name = "webhookExecutor")
public Executor webhookExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("webhook-");
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy() // Backpressure: run in caller thread if queue full
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

7. Missing imports break plugin 🐞 Bug ✓ Correctness

steve-webhook-plugin references ThreadPoolExecutor and WebhookProperties without importing them,
which prevents the module from compiling.
Agent Prompt
### Issue description
Plugin sources reference types that are not imported, causing compilation to fail.

### Issue Context
`AsyncConfig` uses `ThreadPoolExecutor.CallerRunsPolicy`, and multiple classes reference `WebhookProperties` without importing it.

### Fix Focus Areas
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/config/AsyncConfig.java[17-46]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[17-42]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/retry/WebhookRetryQueue.java[17-38]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +57 to +67
public WebhookSender(RestTemplate restTemplate,
WebhookProperties properties,
WebhookRetryQueue retryQueue,
ObjectMapper objectMapper,
MeterRegistry meterRegistry) {
this.restTemplate = restTemplate;
this.properties = properties;
this.retryQueue = retryQueue;
this.objectMapper = objectMapper;
this.meterRegistry = meterRegistry;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

8. Meterregistry di failure 🐞 Bug ⛯ Reliability

WebhookSender requires a MeterRegistry bean, but the plugin module doesn’t include Spring Boot
actuator autoconfiguration and defines no MeterRegistry bean, so the plugin will fail at startup
with an unsatisfied dependency.
Agent Prompt
### Issue description
`WebhookSender` requires `MeterRegistry`, but the plugin does not ensure a `MeterRegistry` bean exists.

### Issue Context
Without actuator autoconfiguration or an explicit `@Bean`, Spring will fail to create `WebhookSender`.

### Fix Focus Areas
- steve-webhook-plugin/pom.xml[43-48]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/service/WebhookSender.java[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +47 to +88
@EventListener
public void onConnectorStatus(ConnectorStatusUpdate event) {
ConnectorStatusEvent webhookEvent = new ConnectorStatusEvent(
event.getChargeBoxId(),
event.getConnectorId(),
event.getStatus().getValue(),
event.getErrorCode() != null ? event.getErrorCode().getValue() : null,
event.getInfo(),
event.getTimestamp(), // OCPP timestamp
Instant.now() // Received at SteVe
);

webhookSender.sendAsync("connector.status", webhookEvent);
}

/**
* Handle StartTransaction
*/
@EventListener
public void onTransactionStart(TransactionStart event) {
TransactionStartedEvent webhookEvent = new TransactionStartedEvent(
event.getChargeBoxId(),
event.getConnectorId(),
event.getTransactionId(),
event.getIdTag(),
event.getStartMeterValue(),
event.getStartTimestamp(),
Instant.now(),
event.getReservationId()
);

webhookSender.sendAsync("transaction.started", webhookEvent);
}

/**
* Handle StopTransaction
*/
@EventListener
public void onTransactionStop(TransactionStop event) {
// Convert transaction data if present
List<TransactionStoppedEvent.MeterValue> transactionData = null;
if (event.getTransactionData() != null && !event.getTransactionData().isEmpty()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

9. Webhook integration not triggered 🐞 Bug ✓ Correctness

The plugin’s components are in package com.voltstartev..., which SteVe won’t component-scan, and the
listener subscribes to event types that SteVe doesn’t publish (and MeterValues publishes no event),
so webhook sending will never run in the SteVe runtime.
Agent Prompt
### Issue description
Webhook plugin code is not executed because it is neither discovered by SteVe’s component scan nor subscribed to events that SteVe actually publishes.

### Issue Context
SteVe publishes `OcppTransactionStarted`/`OcppTransactionEnded` and does not publish a MeterValues Spring event.

### Fix Focus Areas
- src/main/java/de/rwth/idsg/steve/SteveApplication.java[19-36]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[47-88]
- steve-webhook-plugin/src/main/java/com/voltstartev/steve/plugin/listener/OcppEventListener.java[125-128]
- src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[174-185]
- src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[215-223]
- src/main/java/de/rwth/idsg/steve/service/CentralSystemService16_Service.java[248-255]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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