fix(platform): repair development bootstrap flow

This commit is contained in:
sechmachine
2026-08-15 12:47:25 +07:00
parent b764707716
commit 531c607852
10 changed files with 227 additions and 73 deletions
@@ -19,7 +19,7 @@ public class BootstrapAccessFilter extends OncePerRequestFilter {
private final BootstrapService bootstrap;
/**
* Returns HTTP 404 for hidden routes before bootstrap so no authentication surface is exposed prematurely.
* Redirects the installation root to bootstrap and returns HTTP 404 for every other hidden route.
*
* @param request current HTTP request
* @param response current HTTP response
@@ -31,6 +31,10 @@ public class BootstrapAccessFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
String path = request.getRequestURI();
if (!bootstrap.isInitialized() && path.equals(request.getContextPath() + "/")) {
response.sendRedirect(request.getContextPath() + "/bootstrap");
return;
}
if (!bootstrap.isInitialized() && !allowedBeforeBootstrap(path)) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
@@ -1,35 +0,0 @@
# Development profile. Values that differ between machines come from an untracked .env file.
server.port=${LAB_SERVER_PORT}
server.forward-headers-strategy=${LAB_FORWARD_HEADERS_STRATEGY}
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=false
server.servlet.session.cookie.same-site=lax
server.error.include-message=never
server.error.include-stacktrace=never
spring.datasource.url=${LAB_DB_URL}
spring.datasource.username=${LAB_DB_USERNAME}
spring.datasource.password=${LAB_DB_PASSWORD}
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.jdbc.time_zone=UTC
spring.flyway.enabled=true
spring.flyway.locations=classpath:db/migration
spring.docker.compose.enabled=false
# Mailpit keeps Spring's mail health check local. User-facing SMTP credentials remain Admin-console data.
spring.mail.host=${LAB_SMTP_HOST}
spring.mail.port=${LAB_SMTP_PORT}
spring.mail.protocol=smtp
spring.mail.test-connection=false
spring.mail.properties.mail.smtp.auth=false
spring.mail.properties.mail.smtp.starttls.enable=false
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000
management.endpoints.web.exposure.include=health,info
management.endpoint.health.show-details=when_authorized
lab.public-origin=${LAB_PUBLIC_ORIGIN}
lab.security.master-key=${LAB_SECURITY_MASTER_KEY}
+64
View File
@@ -0,0 +1,64 @@
# Development profile. Machine-specific values come from the ignored root .env file.
spring:
config:
import: "optional:file:${LAB_DEV_ENV_FILE:.env}[.properties]"
datasource:
url: "${LAB_DB_URL}"
username: "${LAB_DB_USERNAME}"
password: "${LAB_DB_PASSWORD}"
jpa:
hibernate:
ddl-auto: validate
open-in-view: false
properties:
hibernate:
jdbc:
time_zone: UTC
flyway:
enabled: true
locations: classpath:db/migration
docker:
compose:
enabled: false
# Mailpit keeps Spring's mail health check local. User-facing SMTP credentials remain Admin-console data.
mail:
host: "${LAB_SMTP_HOST}"
port: "${LAB_SMTP_PORT}"
protocol: smtp
test-connection: false
properties:
mail:
smtp:
auth: false
starttls:
enable: false
connectiontimeout: 5000
timeout: 5000
writetimeout: 5000
server:
port: "${LAB_SERVER_PORT}"
forward-headers-strategy: "${LAB_FORWARD_HEADERS_STRATEGY}"
servlet:
session:
cookie:
http-only: true
secure: false
same-site: lax
error:
include-message: never
include-stacktrace: never
management:
endpoints:
web:
exposure:
include: "health,info"
endpoint:
health:
show-details: when_authorized
lab:
public-origin: "${LAB_PUBLIC_ORIGIN}"
security:
master-key: "${LAB_SECURITY_MASTER_KEY}"
@@ -2,6 +2,7 @@ package com.lab.labtimesheet.feature.account.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.time.LocalDate;
@@ -57,10 +58,13 @@ class BootstrapIntegrationTest {
private DataSource dataSource;
@Test
void onlyBootstrapAndHealthAreAvailableBeforeInitialization() throws Exception {
void rootGuidesFreshInstallToBootstrapWhileOtherRoutesRemainHidden() throws Exception {
mockMvc.perform(get("/bootstrap")).andExpect(status().isOk());
mockMvc.perform(get("/actuator/health")).andExpect(status().isOk());
mockMvc.perform(get("/")).andExpect(status().isNotFound());
mockMvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/bootstrap"));
mockMvc.perform(get("/dashboard")).andExpect(status().isNotFound());
bootstrapService.bootstrap("admin@example.com", "Admin", "correct horse battery staple");
mockMvc.perform(get("/bootstrap")).andExpect(status().isNotFound());