95 lines
6.1 KiB
Markdown
95 lines
6.1 KiB
Markdown
# Test Evidence: Development environment configuration
|
|
|
|
- **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, an unsourced dev-profile startup probe, and the full Spring Boot Maven suite
|
|
- **Implementation commit:** `531c6078521341b156d69cb1013e54f65c092311`
|
|
|
|
## Protected behavior
|
|
|
|
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 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.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
|
|
/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
|
|
STALE application-dev.properties
|
|
MISSING application-dev.yaml
|
|
exit 1
|
|
```
|
|
|
|
## GREEN
|
|
|
|
**Command**
|
|
|
|
```text
|
|
/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
|
|
```
|
|
|
|
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
|
|
|
|
**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 -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: 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 or
|
|
an IDE working directory. Product SMTP and HolidayAPI revisions remain
|
|
Admin-console configuration and are intentionally absent from `.env`.
|