From 98688dec7e897595de80f0da9c5f675c368a6f30 Mon Sep 17 00:00:00 2001 From: sechmachine <97589681+sechmachine727@users.noreply.github.com> Date: Sat, 15 Aug 2026 02:50:27 +0700 Subject: [PATCH] correct platform verification evidence --- docs/tests/integration/account-activation.md | 8 +- docs/tests/integration/account-boundary.md | 4 +- .../integration/first-admin-bootstrap.md | 17 ++-- .../integration/internship-start-guard.md | 72 ++++++++++++++ docs/tests/integration/platform-foundation.md | 2 +- docs/tests/integration/smtp-onboarding.md | 10 +- .../unit/package-by-feature-structure.md | 4 +- docs/tests/unit/platform-javadoc-retrofit.md | 79 ++++++++++++++++ docs/tests/unit/smtp-transport-boundaries.md | 69 ++++++++++++++ docs/tests/web/account-activation-flow.md | 8 +- .../web/authenticated-dashboard-landing.md | 2 +- docs/tests/web/platform-onboarding-forms.md | 93 +++++++++++++++++++ docs/tests/web/platform-security-responses.md | 73 +++++++++++++++ docs/tests/web/project-login-flow.md | 4 +- .../model/dto/EncryptedSecret.java | 1 + 15 files changed, 418 insertions(+), 28 deletions(-) create mode 100644 docs/tests/integration/internship-start-guard.md create mode 100644 docs/tests/unit/platform-javadoc-retrofit.md create mode 100644 docs/tests/unit/smtp-transport-boundaries.md create mode 100644 docs/tests/web/platform-onboarding-forms.md create mode 100644 docs/tests/web/platform-security-responses.md diff --git a/docs/tests/integration/account-activation.md b/docs/tests/integration/account-activation.md index 951613e..22bf289 100644 --- a/docs/tests/integration/account-activation.md +++ b/docs/tests/integration/account-activation.md @@ -1,10 +1,10 @@ # Test Evidence: SMTP-gated account creation and activation - **Test type:** Integration -- **Requirement IDs:** `ACC-008`–`ACC-014`, `ACC-019`, `ACC-020`, `NOT-008`, `SEC-005`, `SEC-007` -- **Scenario IDs:** `AC-ACC-001`, `AC-ACC-002`, `AC-ACC-003`, `AC-ACC-007` +- **Requirement IDs:** `ACC-008`–`ACC-012`, `ACC-014`, `ACC-019`, `ACC-020`, `NOT-008`, `SEC-002`–`SEC-004` +- **Scenario IDs:** `AC-ACC-004` (Mentor path), `AC-ACC-005` (Mentor/Intern paths), `AC-ACC-006` (initial delivery failure only) - **Test class/method:** `com.lab.labtimesheet.feature.account.service.AccountActivationIntegrationTest#smtpGatedCreationHashesSingleUseActivationAndRetainsFailedDeliveryHistory` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `98a52a1ac23591fa1cd30b7b175da81ec607e521`; start-date guard added in `6181984cf85f184be39513d6313f9cbe8267add5` ## Protected behavior @@ -65,4 +65,4 @@ BUILD SUCCESS ## External-test boundaries -The recording SMTP boundary proves the exact in-memory handoff but not Mailpit/network delivery. MVC creation, activation, login, role denial, and logout are covered separately by `AccountWebIntegrationTest`; resend, password reset, session invalidation after credential/state changes, lock/deactivation, and production origin/readiness hardening remain separate slices. +The recording SMTP boundary proves the exact in-memory handoff but not Mailpit/network delivery. MVC creation, activation, login, role denial, logout, and the additional-Admin path are covered separately by `AccountWebIntegrationTest`. This test covers only the Mentor path of SMTP gating and the Mentor/Intern paths of hash-only creation; it does not claim all-role coverage for AC-ACC-004/005. It covers the initial failure/invalidation part of AC-ACC-006, not resend. Resend, password reset, session invalidation after credential/state changes, lock/deactivation, and production origin/readiness hardening remain separate slices. diff --git a/docs/tests/integration/account-boundary.md b/docs/tests/integration/account-boundary.md index 8fe5c41..016a90d 100644 --- a/docs/tests/integration/account-boundary.md +++ b/docs/tests/integration/account-boundary.md @@ -2,9 +2,9 @@ - **Test type:** Integration - **Requirement IDs:** `ACC-002, ACC-014, ACC-020–ACC-021, PRJ-017, ATT-007` -- **Scenario IDs:** `AC-ACC-002, AC-ATT-001` +- **Scenario IDs:** No direct acceptance-scenario mapping (cross-feature API regression) - **Test class/method:** `com.lab.labtimesheet.feature.account.service.BootstrapIntegrationTest.exposesIdentityAndDateAwareInternEligibilityWithoutPersistenceTypes` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `1235204bf1298599264a07943ca1167432556bd2` ## Protected behavior diff --git a/docs/tests/integration/first-admin-bootstrap.md b/docs/tests/integration/first-admin-bootstrap.md index a94a6bf..9eba892 100644 --- a/docs/tests/integration/first-admin-bootstrap.md +++ b/docs/tests/integration/first-admin-bootstrap.md @@ -1,18 +1,18 @@ # Test Evidence: Atomic first administrator bootstrap - **Test type:** Integration -- **Requirement IDs:** `ACC-001–ACC-004, SEC-001–SEC-002, GOV-013` -- **Scenario IDs:** `AC-ACC-001, AC-ACC-002, AC-SEC-001` +- **Requirement IDs:** `ACC-001–ACC-003, ACC-009, SEC-001` +- **Scenario IDs:** `AC-ACC-001, AC-ACC-002` - **Test class/method:** `com.lab.labtimesheet.feature.account.service.BootstrapIntegrationTest` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `bc70db1d0d8eaa68bb8e22db44e38af27b0fa945`; restart characterization added in `8ff6ee3d873db909b1ce9df690f7a3abb2c3c79d` ## Protected behavior -Before initialization only bootstrap and health are reachable. Concurrent valid submissions create exactly one active Admin, atomically persist initialization, and permanently close bootstrap. The public account service resolves the winning Admin by normalized email or ID without exposing JPA entities or repositories. +Before initialization only bootstrap, bootstrap assets, health, and error rendering are reachable. Concurrent valid submissions create exactly one active Admin, atomically persist initialization, and permanently close bootstrap. A separately started Spring application context connected to the same PostgreSQL database observes the initialized state and cannot create another Admin. ## Test method -A PostgreSQL 18.4 integration test releases two Java 25 virtual-thread-safe requests onto the same service concurrently and asserts the row-locked outcomes and database state through Spring Data JPA. MockMvc checks pre/post-bootstrap route exposure, and the account API is checked against the actual concurrent winner. +A PostgreSQL 18.4 integration test releases two Java 25 tasks onto the same service concurrently and asserts the row-locked outcomes and database state through Spring Data JPA. MockMvc checks pre/post-bootstrap route exposure. A characterization method then starts and closes an independent servlet application context against the same container datasource and verifies the durable state through the public bootstrap service. ## Hand-derived expected result @@ -47,16 +47,19 @@ The public bootstrap behavior did not exist. export JAVA_HOME=/opt/homebrew/opt/openjdk@25 export PATH="$JAVA_HOME/bin:/opt/homebrew/opt/node@24/bin:$PATH" export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock -./mvnw -Dtest=BootstrapIntegrationTest,SmtpAccountIntegrationTest test +./mvnw -Dtest=BootstrapIntegrationTest test ``` **Observed result** ```text -Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 +Tests run: 4, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS ``` +The independent-context restart assertion was added as characterization coverage for an evidence gap. No +retrospective RED is claimed because the persisted implementation already satisfied it when the test was added. + ## Affected suite **Command and result** diff --git a/docs/tests/integration/internship-start-guard.md b/docs/tests/integration/internship-start-guard.md new file mode 100644 index 0000000..1558499 --- /dev/null +++ b/docs/tests/integration/internship-start-guard.md @@ -0,0 +1,72 @@ +# Test Evidence: Internship cannot activate before its business start date + +- **Test type:** Integration +- **Requirement IDs:** `ACC-019`, `ACC-020` +- **Scenario IDs:** `AC-ACC-010` (start-date transition only) +- **Test class/method:** `com.lab.labtimesheet.feature.account.service.AccountActivationIntegrationTest#internshipCannotActivateBeforeItsBusinessStartDate` +- **Implementation commit:** `6181984cf85f184be39513d6313f9cbe8267add5` + +## Protected behavior + +An active Intern account cannot move its separately stored internship from `NOT_STARTED` to `ACTIVE` before the +configured inclusive start date in the application's injected business timezone. + +## Test method + +The PostgreSQL 18.4 test creates and activates an Intern account through the production SMTP/account services. Its +internship starts one business day after the fixed test clock. The Admin attempts the lifecycle transition and the +test reloads the profile through the owning feature repository. + +## Hand-derived expected result + +The service throws an actionable start-date error and the persisted internship remains `NOT_STARTED`. + +## RED + +**Command** + +```text +export JAVA_HOME=/opt/homebrew/opt/openjdk@25 +export PATH="$JAVA_HOME/bin:$PATH" +export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock +./mvnw -Dtest=AccountActivationIntegrationTest#internshipCannotActivateBeforeItsBusinessStartDate test +``` + +**Observed result** + +```text +Tests run: 1, Failures: 1, Errors: 0, Skipped: 0 +Expected code to raise a throwable, but the internship activated before its start date. +BUILD FAILURE +``` + +## GREEN + +**Command** + +```text +./mvnw -Dtest=AccountActivationIntegrationTest#internshipCannotActivateBeforeItsBusinessStartDate 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,SmtpOnboardingWebIntegrationTest,AccountActivationIntegrationTest,AccountWebIntegrationTest,BootstrapOnboardingWebIntegrationTest,JavaMailSmtpProbeTest,SecurityResponseIntegrationTest test +Tests run: 20, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +``` + +## External-test boundaries + +This covers only the early-activation guard. It does not claim the later scheduler, completion, withdrawal, transfer, +or session-lifecycle portions of AC-ACC-010. diff --git a/docs/tests/integration/platform-foundation.md b/docs/tests/integration/platform-foundation.md index ec1b8cc..ff30d21 100644 --- a/docs/tests/integration/platform-foundation.md +++ b/docs/tests/integration/platform-foundation.md @@ -4,7 +4,7 @@ - **Requirement IDs:** `ARC-001–ARC-008, DB-003–DB-012, OPS-003, TST-001–TST-010` - **Scenario IDs:** `AC-DB-001, AC-OPS-002, AC-TST-001` - **Test class/method:** `com.lab.labtimesheet.config.PlatformFoundationTest.flywayCreatesApprovedPostgresCatalog`, `com.lab.labtimesheet.config.PlatformFoundationTest.testClockIsDeterministic` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `4b37f8fd05804d2d76e11cec1afce52919f2eb59` ## Protected behavior diff --git a/docs/tests/integration/smtp-onboarding.md b/docs/tests/integration/smtp-onboarding.md index 8b7fe4b..703c3e8 100644 --- a/docs/tests/integration/smtp-onboarding.md +++ b/docs/tests/integration/smtp-onboarding.md @@ -2,9 +2,9 @@ - **Test type:** Integration - **Requirement IDs:** `INT-001–INT-008, ACC-011, SEC-001` -- **Scenario IDs:** `AC-INT-001, AC-INT-002, AC-ACC-004` +- **Scenario IDs:** `AC-INT-001, AC-INT-002` - **Test class/method:** `com.lab.labtimesheet.feature.integration.service.SmtpIntegrationTest.failedSmtpTestNeverActivatesDraftAndSecretsRemainEncrypted` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `bc70db1d0d8eaa68bb8e22db44e38af27b0fa945` ## Protected behavior @@ -32,8 +32,8 @@ export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock **Observed result** ```text -SmtpAccountIntegrationTest.java: cannot find symbol class SmtpConfigurationService -SmtpAccountIntegrationTest.java: cannot find symbol class SmtpProbe +The pre-refactor RED test source, then named SmtpAccountIntegrationTest.java, reported missing +SmtpConfigurationService and SmtpProbe symbols. 17 compilation errors BUILD FAILURE ``` @@ -48,7 +48,7 @@ The SMTP revision and controllable delivery boundaries were absent. export JAVA_HOME=/opt/homebrew/opt/openjdk@25 export PATH="$JAVA_HOME/bin:/opt/homebrew/opt/node@24/bin:$PATH" export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock -./mvnw -Dtest=BootstrapIntegrationTest,SmtpAccountIntegrationTest test +./mvnw -Dtest=SmtpIntegrationTest test ``` **Observed result** diff --git a/docs/tests/unit/package-by-feature-structure.md b/docs/tests/unit/package-by-feature-structure.md index b8acc9a..38d3b3c 100644 --- a/docs/tests/unit/package-by-feature-structure.md +++ b/docs/tests/unit/package-by-feature-structure.md @@ -2,9 +2,9 @@ - **Test type:** Unit - **Requirement IDs:** `ARC-001–ARC-008` -- **Scenario IDs:** `AC-ARC-001` +- **Scenario IDs:** No direct acceptance-scenario mapping (architecture regression) - **Test class/method:** `com.lab.labtimesheet.config.LayerStructureTest.applicationUsesOnlyApprovedPackageByFeatureStructure` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `1235204bf1298599264a07943ca1167432556bd2` ## Protected behavior diff --git a/docs/tests/unit/platform-javadoc-retrofit.md b/docs/tests/unit/platform-javadoc-retrofit.md new file mode 100644 index 0000000..1e43ebf --- /dev/null +++ b/docs/tests/unit/platform-javadoc-retrofit.md @@ -0,0 +1,79 @@ +# Test Evidence: Platform production API Javadocs + +- **Test type:** Unit (documentation/static verification) +- **Requirement IDs:** Repository Javadoc implementation standard; Iteration 1 retrofit exception +- **Scenario IDs:** No runtime acceptance-scenario mapping +- **Test class/method:** Maven Javadoc Plugin 3.12.0 over Platform production sources +- **Implementation commit:** `8ff6ee3d873db909b1ce9df690f7a3abb2c3c79d` + +## Protected behavior + +Platform-owned production types and declared public/protected non-trivial APIs under the root application package, +`config`, `feature.account`, and `feature.integration` describe their business purpose and important authorization, +transaction, state-transition, time, persistence, encryption, and raw-token boundaries. Trivial form/entity accessors +remain intentionally undocumented as permitted by the repository standard. + +## Test method + +The Maven Javadoc Plugin generates protected/public API documentation using Java 25 with doclint enabled. The +`missing` category is disabled because the repository explicitly exempts trivial accessors and generated methods; +all structural HTML/reference/syntax categories remain enabled. Compilation and the full runtime suite separately +verify the documented sources. + +## Hand-derived expected result + +Documentation generation completes without doclint errors or warnings for the selected categories, and Java +compilation plus all Platform tests remain green. + +## RED + +**Command** + +```text +Not applicable: this is the approved Iteration 1 documentation retrofit. No runtime RED was invented. +``` + +**Observed result** + +```text +Before the retrofit, manual source audit found missing type and non-trivial API Javadocs throughout Platform-owned +config, account, and integration code. This is review evidence, not a claimed executable RED. +``` + +## GREEN + +**Command** + +```text +export JAVA_HOME=/opt/homebrew/opt/openjdk@25 +export PATH="$JAVA_HOME/bin:$PATH" +./mvnw -DskipTests -Dshow=protected -Ddoclint=all,-missing javadoc:javadoc +``` + +**Observed result** + +```text +Maven Javadoc Plugin 3.12.0 +BUILD SUCCESS +No Javadoc warnings were emitted. +``` + +## Affected suite + +**Command and result** + +```text +export JAVA_HOME=/opt/homebrew/opt/openjdk@25 +export PATH="$JAVA_HOME/bin:$PATH" +export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock +./mvnw test +Tests run: 26, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +PostgreSQL: 18.4 +``` + +## External-test boundaries + +Generated Javadocs validate documentation syntax and references, not whether every statement is behaviorally true. +The focused and full production-shaped tests provide that separate runtime evidence. Private fields/helpers and +trivial accessors are outside the retrofit contract. diff --git a/docs/tests/unit/smtp-transport-boundaries.md b/docs/tests/unit/smtp-transport-boundaries.md new file mode 100644 index 0000000..a30bfa9 --- /dev/null +++ b/docs/tests/unit/smtp-transport-boundaries.md @@ -0,0 +1,69 @@ +# Test Evidence: Bounded SMTP transport and configured sender name + +- **Test type:** Unit +- **Requirement IDs:** `INT-005`, `INT-007`, `NOT-008` +- **Scenario IDs:** No direct acceptance-scenario mapping (transport-adapter regression) +- **Test class/method:** `com.lab.labtimesheet.feature.integration.service.JavaMailSmtpProbeTest` +- **Implementation commit:** `6181984cf85f184be39513d6313f9cbe8267add5` + +## Protected behavior + +Immediate SMTP calls configure finite connection, read, and write timeouts for SMTP and SMTPS, and apply both the +configured From address and human-readable From name to the MIME message. + +## Test method + +The test injects a local JavaMail sender factory, exercises both STARTTLS and TLS connections, and inspects the +resulting JavaMail properties and MIME From header without opening a network connection or exposing a real secret. + +## Hand-derived expected result + +STARTTLS uses `mail.smtp.*` timeout properties; TLS uses `mail.smtps.*`. Each timeout is 5000 milliseconds and the +encoded From header contains the configured address and display name. + +## RED + +**Command** + +```text +export JAVA_HOME=/opt/homebrew/opt/openjdk@25 +export PATH="$JAVA_HOME/bin:$PATH" +./mvnw -Dtest=JavaMailSmtpProbeTest test +``` + +**Observed result** + +```text +BUILD FAILURE during test compilation: JavaMailSmtpProbe had no injectable sender-factory constructor needed to +inspect production message construction without network I/O. +``` + +## GREEN + +**Command** + +```text +./mvnw -Dtest=JavaMailSmtpProbeTest test +``` + +**Observed result** + +```text +Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +``` + +## Affected suite + +**Command and result** + +```text +./mvnw -Dtest=BootstrapIntegrationTest,SmtpOnboardingWebIntegrationTest,AccountActivationIntegrationTest,AccountWebIntegrationTest,BootstrapOnboardingWebIntegrationTest,JavaMailSmtpProbeTest,SecurityResponseIntegrationTest test +Tests run: 20, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +``` + +## External-test boundaries + +This is a network-free adapter construction test. It does not prove DNS, TLS negotiation, authentication, Mailpit, +or production SMTP interoperability. Test values are non-secret fixtures. diff --git a/docs/tests/web/account-activation-flow.md b/docs/tests/web/account-activation-flow.md index 924e103..7883c5f 100644 --- a/docs/tests/web/account-activation-flow.md +++ b/docs/tests/web/account-activation-flow.md @@ -2,9 +2,9 @@ - **Test type:** Web - **Requirement IDs:** `ACC-008–ACC-011, ACC-014, ACC-019, AUTH-001–AUTH-002, SEC-002–SEC-004` -- **Scenario IDs:** `AC-ACC-005, AC-ACC-007, AC-AUTH-001` +- **Scenario IDs:** `AC-ACC-005` (Mentor/Intern browser paths), `AC-ACC-007` - **Test class/method:** `com.lab.labtimesheet.feature.account.controller.AccountWebIntegrationTest.adminCreatesMentorAndInternThenMentorActivatesAuthenticatesAndLogsOut` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `8e786ba37ba7fcff09cf88d5951acb21fbb36ea8`; validation/additional-Admin coverage added in `17fa25bb0921718f780037cd8c55a956bbdf6b19` ## Protected behavior @@ -62,7 +62,7 @@ export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock **Observed result** ```text -Tests run: 1, Failures: 0, Errors: 0, Skipped: 0 +Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 BUILD SUCCESS ``` @@ -82,4 +82,4 @@ BUILD SUCCESS ## External-test boundaries -This test does not contact Mailpit or an external SMTP server and is not a real browser/accessibility test. It does not cover activation resend, password reset, account lock/deactivation, session invalidation after credential/state changes, production origin configuration, containerization, CI, or deployment. +This test does not contact Mailpit or an external SMTP server and is not a real browser/accessibility test. Hash-only persistence and exact expiry are covered by the integration test. It does not cover activation resend, password reset, account lock/deactivation, session invalidation after credential/state changes, production origin configuration, containerization, CI, or deployment. diff --git a/docs/tests/web/authenticated-dashboard-landing.md b/docs/tests/web/authenticated-dashboard-landing.md index 31c4a27..3a08a65 100644 --- a/docs/tests/web/authenticated-dashboard-landing.md +++ b/docs/tests/web/authenticated-dashboard-landing.md @@ -4,7 +4,7 @@ - **Requirement IDs:** `I1-UI-03, I1-UI-04` - **Scenario IDs:** `I1-UI-04 authentication integration follow-up` - **Test class/method:** `com.lab.labtimesheet.feature.account.controller.AuthenticationWebIntegrationTest.projectLoginPageSupportsFailureNormalizedSuccessAndLogout` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `c4656a88806a92cb59b2e588035a4124854feb92` ## Protected behavior diff --git a/docs/tests/web/platform-onboarding-forms.md b/docs/tests/web/platform-onboarding-forms.md new file mode 100644 index 0000000..2caea33 --- /dev/null +++ b/docs/tests/web/platform-onboarding-forms.md @@ -0,0 +1,93 @@ +# Test Evidence: Validated bootstrap, SMTP, and account onboarding + +- **Test type:** Web +- **Requirement IDs:** `ACC-005–ACC-012`, `INT-004`, `INT-006–INT-008`, `SEC-001` +- **Scenario IDs:** `AC-ACC-003`; `AC-INT-002` (Admin browser boundary) +- **Test class/method:** `com.lab.labtimesheet.feature.account.controller.BootstrapOnboardingWebIntegrationTest`, `com.lab.labtimesheet.feature.integration.controller.SmtpOnboardingWebIntegrationTest`, `com.lab.labtimesheet.feature.account.controller.AccountWebIntegrationTest#invalidAndDuplicateAccountFormsReturnActionableErrorsWithoutCreatingAnotherAccount` +- **Implementation commit:** `17fa25bb0921718f780037cd8c55a956bbdf6b19`; SMTP failure feedback added in `8ff6ee3d873db909b1ce9df690f7a3abb2c3c79d` + +## Protected behavior + +Bootstrap offers SMTP setup after creating the first Admin. The Admin can save a validated draft, test it, and +activate only a successful test; or traverse five distinct ordered deferral acknowledgements before finishing. +Restricted-installation warnings persist until activation. Invalid bootstrap/account/SMTP forms retain only safe +non-secret values and show actionable errors. All state-changing browser operations require CSRF. + +## Test method + +MockMvc drives the production controllers, Bean Validation, Thymeleaf rendering, Spring Security filter chain, JPA +services, and PostgreSQL 18.4. SMTP is replaced only at its network adapter. The tests inspect rendered status, +buttons, warnings, validation messages, password non-retention, CSRF denial, ordered deferral navigation, and the +failed-probe response while verifying that activation remains unavailable. + +## Hand-derived expected result + +Successful bootstrap lands on `/admin/smtp?onboarding`. A saved draft shows Test but not Activate; a successful test +shows Activate; activation clears the restricted warning. Deferral exposes warnings one through five in order, Back +and Configure on every screen, and Finish only on screen five. Invalid data returns HTTP 200 with field/global errors +and no submitted password. A failed SMTP probe displays its safe error and leaves the draft untested. + +## RED + +**Command** + +```text +export JAVA_HOME=/opt/homebrew/opt/openjdk@25 +export PATH="$JAVA_HOME/bin:$PATH" +export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock +./mvnw -Dtest=BootstrapOnboardingWebIntegrationTest,SmtpOnboardingWebIntegrationTest test +``` + +**Observed result** + +```text +Tests run: 6, Failures: 5, Errors: 1, Skipped: 0 +Bootstrap redirected to /login instead of SMTP onboarding; deferral returned 404; SMTP status and warning were +absent; invalid form input raised a validation exception. +BUILD FAILURE +``` + +The later failure-feedback regression used this focused command: + +```text +./mvnw -Dtest=SmtpOnboardingWebIntegrationTest#failedSmtpTestRendersActionableFeedbackWithoutActivatingTheDraft test +Tests run: 1, Failures: 1, Errors: 0, Skipped: 0 +Expected the configured connection-refusal message, but smtp/form omitted it. +BUILD FAILURE +``` + +## GREEN + +**Command** + +```text +export JAVA_HOME=/opt/homebrew/opt/openjdk@25 +export PATH="$JAVA_HOME/bin:$PATH" +export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock +./mvnw -Dtest=BootstrapOnboardingWebIntegrationTest,SmtpOnboardingWebIntegrationTest test +``` + +**Observed result** + +```text +Tests run: 7, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +PostgreSQL: 18.4 +``` + +## Affected suite + +**Command and result** + +```text +./mvnw -Dtest=BootstrapIntegrationTest,SmtpOnboardingWebIntegrationTest,AccountActivationIntegrationTest,AccountWebIntegrationTest,BootstrapOnboardingWebIntegrationTest,JavaMailSmtpProbeTest,SecurityResponseIntegrationTest test +Tests run: 20, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +PostgreSQL: 18.4 +``` + +## External-test boundaries + +The SMTP adapter is in-memory here, so this does not prove external Mailpit/server interoperability. MockMvc is not a +real browser or accessibility run. The test exposes only the adapter's safe failure message fixture and never a raw +password, integration secret, or activation bearer token. diff --git a/docs/tests/web/platform-security-responses.md b/docs/tests/web/platform-security-responses.md new file mode 100644 index 0000000..f70b4f7 --- /dev/null +++ b/docs/tests/web/platform-security-responses.md @@ -0,0 +1,73 @@ +# Test Evidence: Public assets and activation-safe response headers + +- **Test type:** Web +- **Requirement IDs:** `ACC-001`, `SEC-001`, `SEC-003`, `SEC-009` +- **Scenario IDs:** No direct acceptance-scenario mapping (response-security regression) +- **Test class/method:** `com.lab.labtimesheet.config.SecurityResponseIntegrationTest` +- **Implementation commit:** `6181984cf85f184be39513d6313f9cbe8267add5` + +## Protected behavior + +Public `/assets/**` requests remain reachable before bootstrap in both the Spring Security chain and bootstrap access +filter. Responses use `Referrer-Policy: no-referrer` so an activation URL bearer token cannot be forwarded in a +same-origin Referer header when a user follows another link. + +## Test method + +MockMvc starts the production filter chain against PostgreSQL 18.4 before initialization. It requests a known static +test asset and the activation page, asserting successful resource delivery and the exact global response header. + +## Hand-derived expected result + +The known asset returns HTTP 200 before bootstrap. The activation response contains exactly +`Referrer-Policy: no-referrer`. + +## RED + +**Command** + +```text +export JAVA_HOME=/opt/homebrew/opt/openjdk@25 +export PATH="$JAVA_HOME/bin:$PATH" +export DOCKER_HOST=unix:///Users/sechmachine/.orbstack/run/docker.sock +./mvnw -Dtest=SecurityResponseIntegrationTest test +``` + +**Observed result** + +```text +Tests run: 2, Failures: 2, Errors: 0, Skipped: 0 +The asset request returned 404 and the activation response Referrer-Policy header was null. +BUILD FAILURE +``` + +## GREEN + +**Command** + +```text +./mvnw -Dtest=SecurityResponseIntegrationTest test +``` + +**Observed result** + +```text +Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +PostgreSQL: 18.4 +``` + +## Affected suite + +**Command and result** + +```text +./mvnw -Dtest=BootstrapIntegrationTest,SmtpOnboardingWebIntegrationTest,AccountActivationIntegrationTest,AccountWebIntegrationTest,BootstrapOnboardingWebIntegrationTest,JavaMailSmtpProbeTest,SecurityResponseIntegrationTest test +Tests run: 20, Failures: 0, Errors: 0, Skipped: 0 +BUILD SUCCESS +``` + +## External-test boundaries + +This verifies server response behavior through MockMvc, not browser enforcement of Referrer-Policy or Reporting's +integrated asset graph. It does not place a real activation token in logs, evidence, or request fixtures. diff --git a/docs/tests/web/project-login-flow.md b/docs/tests/web/project-login-flow.md index 3adcf83..2296de2 100644 --- a/docs/tests/web/project-login-flow.md +++ b/docs/tests/web/project-login-flow.md @@ -1,10 +1,10 @@ # Test Evidence: Project-owned login flow - **Test type:** Web -- **Requirement IDs:** `ACC-009, SEC-001, SEC-005, I1-UI-04` +- **Requirement IDs:** `ACC-009, SEC-001, I1-UI-04` - **Scenario IDs:** `I1-UI-04 authentication integration follow-up` - **Test class/method:** `com.lab.labtimesheet.feature.account.controller.AuthenticationWebIntegrationTest.projectLoginPageSupportsFailureNormalizedSuccessAndLogout` -- **Implementation commit:** `this milestone commit` +- **Implementation commit:** `a18d8e1d3dd02c8978033f09563d2ec9341926c7` ## Protected behavior diff --git a/src/main/java/com/lab/labtimesheet/feature/integration/model/dto/EncryptedSecret.java b/src/main/java/com/lab/labtimesheet/feature/integration/model/dto/EncryptedSecret.java index 238d986..8aa21df 100644 --- a/src/main/java/com/lab/labtimesheet/feature/integration/model/dto/EncryptedSecret.java +++ b/src/main/java/com/lab/labtimesheet/feature/integration/model/dto/EncryptedSecret.java @@ -8,6 +8,7 @@ package com.lab.labtimesheet.feature.integration.model.dto; * @param keyVersion key-rotation identifier */ public record EncryptedSecret(byte[] ciphertext, byte[] nonce, int keyVersion) { + /** Defensively copies both byte arrays before this value can cross the encryption boundary. */ public EncryptedSecret { ciphertext = ciphertext.clone(); nonce = nonce.clone();