Compare commits
2
Commits
b764707716
...
bca30e6e4b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bca30e6e4b | ||
|
|
531c607852 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
# Copy to .env, replace every placeholder, then load it into the IDE or shell.
|
||||
# Copy to .env and replace every placeholder. The dev profile imports it from the repository root.
|
||||
SPRING_PROFILES_ACTIVE=dev
|
||||
LAB_SERVER_PORT=8080
|
||||
LAB_FORWARD_HEADERS_STRATEGY=NONE
|
||||
|
||||
+21
-11
@@ -124,18 +124,21 @@ unless you intentionally want to discard your local development data.
|
||||
|
||||
## 4. Run from a terminal
|
||||
|
||||
Load the environment file in the same terminal that will run Spring Boot:
|
||||
The `dev` profile imports the ignored root `.env` file automatically. From the
|
||||
repository root, run:
|
||||
|
||||
```bash
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
./mvnw spring-boot:run
|
||||
```
|
||||
|
||||
Shell environment variables still override values from `.env`, which is useful
|
||||
for a one-off local override. If you run from another working directory, set
|
||||
`LAB_DEV_ENV_FILE` to the absolute path of your `.env` file.
|
||||
|
||||
Open:
|
||||
|
||||
- First-Admin setup: `http://localhost:8080/bootstrap`
|
||||
- First-Admin setup: open `http://localhost:8080` and follow the automatic
|
||||
redirect to `/bootstrap`.
|
||||
- Login: `http://localhost:8080/login`
|
||||
- Mailpit inbox: `http://localhost:8025`
|
||||
|
||||
@@ -177,14 +180,14 @@ Stop the application with `Control+C`.
|
||||
6. Set **JRE** to Java 25.
|
||||
7. Set **Active profiles** to `dev`.
|
||||
8. Set **Working directory** to the repository root.
|
||||
9. Open the **Environment variables** editor and add every variable from your
|
||||
local `.env` file.
|
||||
9. Leave **Environment variables** empty. With the repository root as the
|
||||
working directory, `application-dev.yaml` imports the ignored `.env` file.
|
||||
10. Apply the configuration and run it.
|
||||
|
||||
Some IntelliJ editions can load variables from an environment file directly.
|
||||
If that option is available, select the local `.env`; otherwise use the
|
||||
environment-variable table. Do not store real secrets in a shared or committed
|
||||
run configuration.
|
||||
If company policy requires IntelliJ to inject the values instead, select the
|
||||
local `.env` in the **Environment variables** field. Environment variables take
|
||||
precedence over the imported file. Do not store real secrets in a shared or
|
||||
committed run configuration.
|
||||
|
||||
Run `npm ci` and `npm run build` in IntelliJ's terminal before the first launch
|
||||
and after changing Tailwind or icon sources.
|
||||
@@ -220,6 +223,13 @@ does not by itself prove that SMTP is unavailable; use the Admin SMTP test.
|
||||
Check both **Project SDK** and the run configuration's **JRE**. They should both
|
||||
be Java 25.
|
||||
|
||||
### Spring reports an unresolved `LAB_*` placeholder
|
||||
|
||||
Confirm the run configuration uses the repository root as its working
|
||||
directory and that `.env` exists there. If the working directory must differ,
|
||||
set `LAB_DEV_ENV_FILE` to the absolute `.env` path in the run configuration's
|
||||
environment variables.
|
||||
|
||||
### Styles or icons are missing
|
||||
|
||||
Run:
|
||||
|
||||
@@ -75,9 +75,6 @@ console, not environment variables.
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env. Generate LAB_SECURITY_MASTER_KEY with: openssl rand -base64 32
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
|
||||
export JAVA_HOME=/opt/homebrew/opt/openjdk@25
|
||||
export PATH="/opt/homebrew/opt/node@24/bin:$JAVA_HOME/bin:$PATH"
|
||||
@@ -89,10 +86,12 @@ npm run build
|
||||
|
||||
Development defaults to the application on port `8080`, PostgreSQL on `55432`,
|
||||
and Mailpit SMTP on `1025`. The exact Spring settings are in
|
||||
[`application-dev.properties`](src/main/resources/application-dev.properties).
|
||||
[`application-dev.yaml`](src/main/resources/application-dev.yaml), which imports
|
||||
the ignored root `.env` file when the `dev` profile is active.
|
||||
|
||||
On first launch, open `http://localhost:8080/bootstrap`, create the first Admin,
|
||||
then configure and test SMTP or complete all five explicit deferral warnings.
|
||||
On first launch, open `http://localhost:8080`; the application redirects to
|
||||
`/bootstrap`, where you create the first Admin. Then configure and test SMTP or
|
||||
complete all five explicit deferral warnings.
|
||||
|
||||
## Verification status
|
||||
|
||||
|
||||
+2
-1
@@ -225,7 +225,8 @@ Run `java -version` and `./mvnw -version`. Both should report Java 25. Set
|
||||
|
||||
### The application cannot start for a manual browser check
|
||||
|
||||
Confirm `.env` was loaded, PostgreSQL is reachable, and
|
||||
Confirm the process working directory is the repository root so
|
||||
`application-dev.yaml` can import `.env`, PostgreSQL is reachable, and
|
||||
`LAB_SECURITY_MASTER_KEY` decodes from Base64 to 32 bytes. Automated tests do
|
||||
not need this local file.
|
||||
|
||||
|
||||
@@ -3,36 +3,47 @@
|
||||
- **Test type:** Integration
|
||||
- **Requirement IDs:** `OPS-001`, `OPS-004`, `SEC-013`
|
||||
- **Scenario IDs:** `AC-OPS-001`, `AC-SEC-005`
|
||||
- **Test class/method:** Shell configuration contract plus the full Spring Boot Maven suite
|
||||
- **Implementation commit:** `4212e9cbc2791e0c733929af62503df26097431e`
|
||||
- **Test class/method:** Shell configuration contract, an unsourced dev-profile startup probe, and the full Spring Boot Maven suite
|
||||
- **Implementation commit:** `531c6078521341b156d69cb1013e54f65c092311`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Development starts from environment-backed datasource, encryption, public-origin, server, proxy, and local Mailpit settings without committing a real `.env` or weakening application security controls.
|
||||
Development starts from datasource, encryption, public-origin, server, proxy,
|
||||
and local Mailpit values in the ignored root `.env` file without requiring an
|
||||
IDE-specific environment-variable copy, committing secrets, or weakening
|
||||
application security controls.
|
||||
|
||||
## Test method
|
||||
|
||||
A shell contract verifies that the committed placeholder and development properties exist, the superseded YAML is absent, the real `.env` is ignored, every required environment key is represented, and every application placeholder resolves after loading the local file. The full Maven suite then exercises Spring configuration binding, Flyway, JPA validation, security, and PostgreSQL behavior.
|
||||
A shell contract verifies that the committed placeholder and development YAML
|
||||
exist, the superseded properties file is absent, the YAML explicitly imports
|
||||
the ignored root `.env`, and every required placeholder remains represented. A
|
||||
real dev-profile process is launched without sourcing `.env` to prove Spring
|
||||
loads it. The full Maven suite then exercises Spring configuration binding,
|
||||
Flyway, JPA validation, security, and PostgreSQL behavior.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
The committed tree contains `.env.example` and `application-dev.properties`, never tracks `.env`, and exposes exactly the environment inputs needed by the current application. Loading the local file gives Spring a `dev` profile, PostgreSQL connection, 32-byte Base64 encryption key, public origin, local Mailpit endpoint, server port, and explicit no-forwarded-header policy.
|
||||
The committed tree contains `.env.example` and `application-dev.yaml`, never
|
||||
tracks `.env`, and exposes exactly the inputs needed by the current
|
||||
application. Starting the `dev` profile from the repository root, without
|
||||
exporting the file, gives Spring the PostgreSQL connection, 32-byte Base64
|
||||
encryption key, public origin, local Mailpit endpoint, server port, and explicit
|
||||
forwarded-header policy.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
required_files=(.env.example src/main/resources/application-dev.properties); failed=0; for file in $required_files; do if [ ! -f "$file" ]; then echo "MISSING $file"; failed=1; fi; done; if [ -f src/main/resources/application-dev.yaml ]; then echo 'STALE src/main/resources/application-dev.yaml'; failed=1; fi; if ! grep -qx '/.env' .gitignore; then echo 'MISSING /.env ignore rule'; failed=1; fi; exit "$failed"
|
||||
/bin/zsh -lc 'config_check_failed=0; if test -e src/main/resources/application-dev.properties; then echo "STALE application-dev.properties"; config_check_failed=1; fi; if ! test -f src/main/resources/application-dev.yaml; then echo "MISSING application-dev.yaml"; config_check_failed=1; fi; if test -f src/main/resources/application-dev.yaml && ! grep -Fq "optional:file:\${LAB_DEV_ENV_FILE:.env}[.properties]" src/main/resources/application-dev.yaml; then echo "MISSING .env import"; config_check_failed=1; fi; exit "$config_check_failed"'
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
MISSING .env.example
|
||||
MISSING src/main/resources/application-dev.properties
|
||||
STALE src/main/resources/application-dev.yaml
|
||||
MISSING /.env ignore rule
|
||||
STALE application-dev.properties
|
||||
MISSING application-dev.yaml
|
||||
exit 1
|
||||
```
|
||||
|
||||
@@ -41,15 +52,28 @@ exit 1
|
||||
**Command**
|
||||
|
||||
```text
|
||||
required_files=(.env.example src/main/resources/application-dev.properties); required_env=(SPRING_PROFILES_ACTIVE LAB_SERVER_PORT LAB_FORWARD_HEADERS_STRATEGY LAB_DB_URL LAB_DB_USERNAME LAB_DB_PASSWORD LAB_SMTP_HOST LAB_SMTP_PORT LAB_PUBLIC_ORIGIN LAB_SECURITY_MASTER_KEY); required_props=(server.port server.forward-headers-strategy spring.datasource.url spring.datasource.username spring.datasource.password spring.jpa.hibernate.ddl-auto spring.jpa.open-in-view spring.flyway.enabled spring.mail.host spring.mail.port lab.public-origin lab.security.master-key); failed=0; for file in $required_files; do if [ ! -f "$file" ]; then echo "MISSING $file"; failed=1; fi; done; if [ -f src/main/resources/application-dev.yaml ]; then echo 'STALE src/main/resources/application-dev.yaml'; failed=1; fi; if ! grep -qx '/.env' .gitignore; then echo 'MISSING /.env ignore rule'; failed=1; fi; for key in $required_env; do if ! grep -q "^${key}=" .env.example; then echo "MISSING example $key"; failed=1; fi; if ! grep -q "^${key}=" .env; then echo "MISSING local $key"; failed=1; fi; done; for property in $required_props; do if ! grep -q "^${property}=" src/main/resources/application-dev.properties; then echo "MISSING property $property"; failed=1; fi; done; set -a; source .env; set +a; decoded_bytes=$(printf '%s' "$LAB_SECURITY_MASTER_KEY" | base64 -d | wc -c | tr -d ' '); if [ "$decoded_bytes" != 32 ]; then echo "INVALID master key bytes=$decoded_bytes"; failed=1; fi; if ! git check-ignore -q .env; then echo 'LOCAL .env is not ignored'; failed=1; fi; if git ls-files --error-unmatch .env >/dev/null 2>&1; then echo 'LOCAL .env is tracked'; failed=1; fi; if [ "$failed" -eq 0 ]; then echo 'development configuration contract: PASS'; fi; exit "$failed"
|
||||
/bin/zsh -lc 'dev_contract_failed=0; dev_required_files=(.env.example src/main/resources/application-dev.yaml); dev_required_env=(SPRING_PROFILES_ACTIVE LAB_SERVER_PORT LAB_FORWARD_HEADERS_STRATEGY LAB_DB_URL LAB_DB_USERNAME LAB_DB_PASSWORD LAB_SMTP_HOST LAB_SMTP_PORT LAB_PUBLIC_ORIGIN LAB_SECURITY_MASTER_KEY); dev_required_placeholders=(LAB_SERVER_PORT LAB_FORWARD_HEADERS_STRATEGY LAB_DB_URL LAB_DB_USERNAME LAB_DB_PASSWORD LAB_SMTP_HOST LAB_SMTP_PORT LAB_PUBLIC_ORIGIN LAB_SECURITY_MASTER_KEY); for dev_file in $dev_required_files; do if ! test -f "$dev_file"; then echo "MISSING $dev_file"; dev_contract_failed=1; fi; done; if test -e src/main/resources/application-dev.properties; then echo "STALE application-dev.properties"; dev_contract_failed=1; fi; if ! grep -Fq "optional:file:\${LAB_DEV_ENV_FILE:.env}[.properties]" src/main/resources/application-dev.yaml; then echo "MISSING .env import"; dev_contract_failed=1; fi; if ! grep -qx "/.env" .gitignore; then echo "MISSING /.env ignore rule"; dev_contract_failed=1; fi; for dev_key in $dev_required_env; do if ! grep -q "^${dev_key}=" .env.example; then echo "MISSING example $dev_key"; dev_contract_failed=1; fi; if ! grep -q "^${dev_key}=" .env; then echo "MISSING local $dev_key"; dev_contract_failed=1; fi; done; for dev_key in $dev_required_placeholders; do dev_placeholder="\${${dev_key}}"; if ! grep -Fq "$dev_placeholder" src/main/resources/application-dev.yaml; then echo "MISSING YAML placeholder $dev_key"; dev_contract_failed=1; fi; done; set -a; source .env; set +a; dev_decoded_key_bytes=$(printf "%s" "$LAB_SECURITY_MASTER_KEY" | base64 -d | wc -c | tr -d " "); if test "$dev_decoded_key_bytes" != 32; then echo "INVALID master key bytes=$dev_decoded_key_bytes"; dev_contract_failed=1; fi; if ! git check-ignore -q .env; then echo "LOCAL .env is not ignored"; dev_contract_failed=1; fi; if git ls-files --error-unmatch .env >/dev/null 2>&1; then echo "LOCAL .env is tracked"; dev_contract_failed=1; fi; if test "$dev_contract_failed" -eq 0; then echo "development configuration contract: PASS"; fi; exit "$dev_contract_failed"'
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
development configuration contract: PASS
|
||||
```
|
||||
|
||||
A real Java 25 process loaded `.env` and `application-dev.properties`, connected to PostgreSQL 18.4, validated Flyway/JPA, and started on the environment-overridden port 18081. With temporary Mailpit on the configured SMTP port, `/actuator/health` returned HTTP 200 with `UP`, and `/login` returned HTTP 200. The process shut down and the temporary Mailpit container was removed.
|
||||
An additional Java 25 process was started with all `LAB_*` and
|
||||
`SPRING_PROFILES_ACTIVE` environment variables removed. It loaded the root
|
||||
`.env` through `application-dev.yaml`, connected to PostgreSQL 18.4, validated
|
||||
Flyway/JPA, and started successfully. The process was then stopped cleanly.
|
||||
|
||||
```text
|
||||
env -u SPRING_PROFILES_ACTIVE -u LAB_SERVER_PORT -u LAB_FORWARD_HEADERS_STRATEGY -u LAB_DB_URL -u LAB_DB_USERNAME -u LAB_DB_PASSWORD -u LAB_SMTP_HOST -u LAB_SMTP_PORT -u LAB_PUBLIC_ORIGIN -u LAB_SECURITY_MASTER_KEY -u LAB_DEV_ENV_FILE /bin/zsh -lc 'export JAVA_HOME=/opt/homebrew/opt/openjdk@25; export PATH="$JAVA_HOME/bin:$PATH"; ./mvnw -DskipTests spring-boot:run'
|
||||
|
||||
No active profile set, falling back to 1 default profile: "dev"
|
||||
Database: jdbc:postgresql://localhost:55432/labtimesheet (PostgreSQL 18.4)
|
||||
Started LabtimesheetApplication in 4.068 seconds
|
||||
Graceful shutdown complete
|
||||
BUILD SUCCESS
|
||||
```
|
||||
|
||||
## Affected suite
|
||||
@@ -57,12 +81,14 @@ A real Java 25 process loaded `.env` and `application-dev.properties`, connected
|
||||
**Command and result**
|
||||
|
||||
```text
|
||||
env -u SPRING_PROFILES_ACTIVE -u LAB_SERVER_PORT -u LAB_FORWARD_HEADERS_STRATEGY -u LAB_DB_URL -u LAB_DB_USERNAME -u LAB_DB_PASSWORD -u LAB_SMTP_HOST -u LAB_SMTP_PORT -u LAB_PUBLIC_ORIGIN -u LAB_SECURITY_MASTER_KEY /bin/zsh -lc 'export JAVA_HOME=/opt/homebrew/opt/openjdk@25; export PATH=/opt/homebrew/opt/node@24/bin:$JAVA_HOME/bin:$PATH; export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock; ./mvnw test'
|
||||
env -u SPRING_PROFILES_ACTIVE -u LAB_SERVER_PORT -u LAB_FORWARD_HEADERS_STRATEGY -u LAB_DB_URL -u LAB_DB_USERNAME -u LAB_DB_PASSWORD -u LAB_SMTP_HOST -u LAB_SMTP_PORT -u LAB_PUBLIC_ORIGIN -u LAB_SECURITY_MASTER_KEY -u LAB_DEV_ENV_FILE /bin/zsh -lc 'export JAVA_HOME=/opt/homebrew/opt/openjdk@25; export PATH=/opt/homebrew/opt/node@24/bin:$JAVA_HOME/bin:$PATH; export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock; ./mvnw test'
|
||||
|
||||
Tests run: 197, Failures: 0, Errors: 0, Skipped: 0
|
||||
BUILD SUCCESS in 01:33 using PostgreSQL 18.4 Testcontainers. No development environment value was present.
|
||||
Tests run: 201, Failures: 0, Errors: 0, Skipped: 0
|
||||
BUILD SUCCESS in 01:29 using PostgreSQL 18.4 Testcontainers.
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
The committed example cannot prove another developer's local credentials. Product SMTP and HolidayAPI revisions remain Admin-console configuration and are intentionally absent from `.env`.
|
||||
The committed example cannot prove another developer's local credentials or
|
||||
an IDE working directory. Product SMTP and HolidayAPI revisions remain
|
||||
Admin-console configuration and are intentionally absent from `.env`.
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Test Evidence: Fresh-install root navigation
|
||||
|
||||
- **Test type:** Web
|
||||
- **Requirement IDs:** `ACC-001`
|
||||
- **Scenario IDs:** `N/A — user-reported fresh-install navigation regression`
|
||||
- **Test class/method:** `com.lab.labtimesheet.feature.account.service.BootstrapIntegrationTest.rootGuidesFreshInstallToBootstrapWhileOtherRoutesRemainHidden`
|
||||
- **Implementation commit:** `531c6078521341b156d69cb1013e54f65c092311`
|
||||
|
||||
## Protected behavior
|
||||
|
||||
Before the first Admin exists, opening `/` redirects to the public one-time
|
||||
bootstrap workflow instead of rendering a Whitelabel 404 page. Other protected
|
||||
application routes remain concealed with HTTP 404 until bootstrap completes.
|
||||
|
||||
## Test method
|
||||
|
||||
The production Spring Security and bootstrap filter chain runs against a fresh
|
||||
PostgreSQL 18.4 Testcontainer. MockMvc requests `/bootstrap`, health, `/`, and
|
||||
`/dashboard`, then verifies that only the root receives the new navigation
|
||||
redirect while the protected dashboard remains hidden.
|
||||
|
||||
## Hand-derived expected result
|
||||
|
||||
On an uninitialized installation, GET `/` returns a 3xx response with Location
|
||||
`/bootstrap`. GET `/dashboard` still returns 404. The bootstrap form and health
|
||||
endpoint remain available.
|
||||
|
||||
## RED
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
export JAVA_HOME=/Users/sechmachine/Library/Java/JavaVirtualMachines/corretto-26.0.2/Contents/Home
|
||||
export PATH="$JAVA_HOME/bin:$PATH"
|
||||
export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock
|
||||
./mvnw -Dtest=BootstrapIntegrationTest#rootGuidesFreshInstallToBootstrapWhileOtherRoutesRemainHidden test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
GET / returned 404.
|
||||
Expected a 3xx redirect to /bootstrap.
|
||||
Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
|
||||
BUILD FAILURE
|
||||
```
|
||||
|
||||
## GREEN
|
||||
|
||||
**Command**
|
||||
|
||||
```text
|
||||
./mvnw -Dtest=BootstrapIntegrationTest#rootGuidesFreshInstallToBootstrapWhileOtherRoutesRemainHidden test
|
||||
```
|
||||
|
||||
**Observed result**
|
||||
|
||||
```text
|
||||
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
|
||||
BUILD SUCCESS
|
||||
PostgreSQL: 18.4
|
||||
```
|
||||
|
||||
## Affected suite
|
||||
|
||||
**Command and result**
|
||||
|
||||
```text
|
||||
./mvnw -Dtest=BootstrapIntegrationTest,AuthenticationWebIntegrationTest,BootstrapOnboardingWebIntegrationTest,SecurityResponseIntegrationTest test
|
||||
|
||||
Tests run: 10, Failures: 0, Errors: 0, Skipped: 0
|
||||
BUILD SUCCESS
|
||||
PostgreSQL: 18.4
|
||||
```
|
||||
|
||||
## External-test boundaries
|
||||
|
||||
MockMvc verifies server routing, security, and persistence-backed initialization
|
||||
state. It does not prove browser rendering or exercise the user's IntelliJ-run
|
||||
process. The existing browser screenshot independently established the original
|
||||
Whitelabel 404 symptom.
|
||||
+5
-1
@@ -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}
|
||||
@@ -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}"
|
||||
+6
-2
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user