Compare commits

..

3 Commits

Author SHA1 Message Date
32cb5b57d7 Merge pull request 'update README' (#5) from dev into main
Reviewed-on: #5
2025-12-24 16:45:40 +00:00
6037788dbd Merge pull request 'add README.md' (#4) from dev into main
Reviewed-on: #4
2025-12-24 16:40:33 +00:00
706631c57b Merge pull request 'dev' (#3) from dev into main
Reviewed-on: #3
2025-12-24 15:05:01 +00:00
4 changed files with 35 additions and 58 deletions

View File

@@ -2,6 +2,8 @@
A Spring Boot (Java 21) application acting as a secure bridge between Infisical and Dokploy, enabling automated synchronization and deployment of secrets through APIs and webhooks. A Spring Boot (Java 21) application acting as a secure bridge between Infisical and Dokploy, enabling automated synchronization and deployment of secrets through APIs and webhooks.
---
## Features ## Features
- Secure integration with Infisical - Secure integration with Infisical
@@ -9,6 +11,8 @@ A Spring Boot (Java 21) application acting as a secure bridge between Infisical
- Webhook-driven synchronization - Webhook-driven synchronization
- Docker and Docker Compose ready - Docker and Docker Compose ready
---
## Architecture Overview ## Architecture Overview
Infisical Infisical
@@ -17,6 +21,8 @@ InfisicalDokploy Bridge (Spring Boot)
↓ (Dokploy API) ↓ (Dokploy API)
Dokploy Dokploy
---
## Requirements ## Requirements
- Java 21 - Java 21
@@ -24,6 +30,8 @@ Dokploy
- Infisical account - Infisical account
- Dokploy instance with API access - Dokploy instance with API access
---
## Environment Variables ## Environment Variables
### Infisical ### Infisical
@@ -38,6 +46,8 @@ Dokploy
- DOKPLOY_API_URL: Base URL of Dokploy API - DOKPLOY_API_URL: Base URL of Dokploy API
- DOKPLOY_API_KEY: Dokploy API key - DOKPLOY_API_KEY: Dokploy API key
---
## Docker Compose ## Docker Compose
```txt ```txt
@@ -53,6 +63,7 @@ services:
DOKPLOY_API_URL: ${DOKPLOY_API_URL} DOKPLOY_API_URL: ${DOKPLOY_API_URL}
DOKPLOY_API_KEY: ${DOKPLOY_API_KEY} DOKPLOY_API_KEY: ${DOKPLOY_API_KEY}
``` ```
---
## Running ## Running
@@ -72,45 +83,29 @@ Application runs on http://localhost:8080
Use a service like ngrok. Use a service like ngrok.
---
## Infisical Webhook Configuration ## Infisical Webhook Configuration
When creating a webhook in Infisical, the following rules must be respected. When creating a webhook in Infisical, the following rules must be respected.
### Webhook URL Formats ### Webhook URL format
Infisical bridge supports two webhook URL formats, depending on the Dokploy resource you want to update. ${INFISICAL_API_URL}/webhook?dokployComposeId=${DOKPLOY_COMPOSE_ID}
#### Dokploy Compose Webhook - `dokployComposeId` must be the target Dokploy compose identifier
- This value is required and used to determine which Dokploy service is updated
`${INFISICAL_API_URL}/webhook?dokployComposeId=${DOKPLOY_COMPOSE_ID}`
Parameters:
- dokployComposeId (required):
The identifier of the target Dokploy Compose.
This value is used to determine which Dokploy compose service should be updated when the webhook is triggered.
#### Dokploy Application Webhook
`${INFISICAL_API_URL}/webhook?dokployApplicationId=${DOKPLOY_APPLICATION_ID}`
Parameters:
- dokployApplicationId (required):
The identifier of the target Dokploy Application.
This value is used to determine which Dokploy application should be updated when the webhook is triggered.
#### Notes
- Exactly one identifier must be provided per webhook URL.
- If no identifier or multiple identifiers are provided, the webhook request will be rejected.
- Ensure the provided ID matches an existing Dokploy resource.
### Webhook Secret ### Webhook Secret
The webhook secret **must exactly match**: The webhook secret **must exactly match**:
`${INFISICAL_WEBHOOK_SECRET}` ${INFISICAL_WEBHOOK_SECRET}
Requests with an invalid or missing secret will be rejected. Requests with an invalid or missing secret will be rejected.
---
## Webhooks Behavior ## Webhooks Behavior
- Incoming webhook signatures are validated - Incoming webhook signatures are validated
@@ -118,6 +113,8 @@ Requests with an invalid or missing secret will be rejected.
- Dokploy is updated using its API - Dokploy is updated using its API
- Invalid or unsigned requests are ignored - Invalid or unsigned requests are ignored
---
## Security Notes ## Security Notes
- Secrets are never persisted - Secrets are never persisted
@@ -125,11 +122,13 @@ Requests with an invalid or missing secret will be rejected.
- HTTPS is recommended in production - HTTPS is recommended in production
- Restrict network access to trusted sources only - Restrict network access to trusted sources only
---
## Testing ## Testing
```sh
./gradlew test ./gradlew test
```
---
## Tech Stack ## Tech Stack
@@ -138,6 +137,8 @@ Requests with an invalid or missing secret will be rejected.
- Gradle (Kotlin DSL) - Gradle (Kotlin DSL)
- Docker / Docker Compose - Docker / Docker Compose
---
## License ## License
MIT License MIT License

View File

@@ -4,7 +4,6 @@ import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
import com.abnov.infisicalbridge.dto.DokployApplicationUpdateRequest;
import com.abnov.infisicalbridge.dto.DokployComposeUpdateRequest; import com.abnov.infisicalbridge.dto.DokployComposeUpdateRequest;
@FeignClient(name = "dokployClient", url = "${dokploy.api-url}", configuration = DokployFeignConfig.class) @FeignClient(name = "dokployClient", url = "${dokploy.api-url}", configuration = DokployFeignConfig.class)
@@ -12,7 +11,4 @@ public interface DokployClient {
@PostMapping("/compose.update") @PostMapping("/compose.update")
void updateCompose(@RequestBody DokployComposeUpdateRequest request); void updateCompose(@RequestBody DokployComposeUpdateRequest request);
@PostMapping("/application.update")
void updateApplication(@RequestBody DokployApplicationUpdateRequest request);
} }

View File

@@ -1,6 +0,0 @@
package com.abnov.infisicalbridge.dto;
public record DokployApplicationUpdateRequest(
String applicationId,
String env) {
}

View File

@@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.abnov.infisicalbridge.dokploy.DokployClient; import com.abnov.infisicalbridge.dokploy.DokployClient;
import com.abnov.infisicalbridge.dto.DokployApplicationUpdateRequest;
import com.abnov.infisicalbridge.dto.DokployComposeUpdateRequest; import com.abnov.infisicalbridge.dto.DokployComposeUpdateRequest;
import com.abnov.infisicalbridge.dto.InfisicalWebhookEventResponse; import com.abnov.infisicalbridge.dto.InfisicalWebhookEventResponse;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
@@ -39,8 +38,7 @@ public class InfisicalWebhookController {
@PostMapping @PostMapping
public ResponseEntity<Void> handleWebhook( public ResponseEntity<Void> handleWebhook(
@RequestBody String payload, @RequestBody String payload,
@RequestParam(required = false) String dokployComposeId, @RequestParam String dokployComposeId,
@RequestParam(required = false) String dokployApplicationId,
@RequestHeader(value = "X-Infisical-Signature", required = false) String signature) @RequestHeader(value = "X-Infisical-Signature", required = false) String signature)
throws InfisicalException { throws InfisicalException {
@@ -82,7 +80,6 @@ public class InfisicalWebhookController {
.map(s -> s.getSecretKey() + "=" + s.getSecretValue()) .map(s -> s.getSecretKey() + "=" + s.getSecretValue())
.collect(Collectors.joining("\n")); .collect(Collectors.joining("\n"));
if (dokployComposeId != null) {
try { try {
dokployClient.updateCompose( dokployClient.updateCompose(
new DokployComposeUpdateRequest(dokployComposeId, envContent)); new DokployComposeUpdateRequest(dokployComposeId, envContent));
@@ -90,17 +87,6 @@ public class InfisicalWebhookController {
log.error("Failed to update Dokploy compose {}", dokployComposeId, e); log.error("Failed to update Dokploy compose {}", dokployComposeId, e);
return ResponseEntity.status(HttpStatus.BAD_GATEWAY).build(); return ResponseEntity.status(HttpStatus.BAD_GATEWAY).build();
} }
}
if (dokployApplicationId != null) {
try {
dokployClient.updateApplication(
new DokployApplicationUpdateRequest(dokployApplicationId, envContent));
} catch (Exception e) {
log.error("Failed to update Dokploy application {}", dokployApplicationId, e);
return ResponseEntity.status(HttpStatus.BAD_GATEWAY).build();
}
}
return ResponseEntity.ok().build(); return ResponseEntity.ok().build();
} }