$username, "database.connections.{$connection}.read.username" => $username, "database.connections.{$connection}.write.username" => $username, ]); } /** * 설치 완료 상태에서 정상 계정이면 웹 요청을 통과시켜야 한다. * * @scenario account_kind=normal, enforcement_point=runtime_web, install_state=completed * * @effects runtime_passes_through_with_normal_account */ public function test_passes_through_with_normal_account(): void { config(['app.installer_completed' => true]); $this->setDbUsername('g7user'); $response = $this->get('/'); $this->assertNotEquals(503, $response->getStatusCode()); } /** * 정상 계정이면 API 요청도 통과시켜야 한다 (과잉 차단 방지). * * @scenario account_kind=normal, enforcement_point=runtime_api, install_state=completed * * @effects runtime_passes_through_with_normal_account */ public function test_passes_through_with_normal_account_for_api(): void { config(['app.installer_completed' => true]); $this->setDbUsername('g7user'); $response = $this->getJson('/api/test'); $this->assertNotEquals(503, $response->getStatusCode()); } /** * 최고권한 계정이면 웹 요청에 503 전용 에러 페이지를 반환해야 한다. * * @scenario account_kind=privileged, enforcement_point=runtime_web, install_state=completed * * @effects runtime_returns_503_error_page */ #[DataProvider('privilegedUsernameProvider')] public function test_returns_error_page_for_privileged_account(string $username): void { config(['app.installer_completed' => true]); $this->setDbUsername($username); $response = $this->get('/'); $response->assertStatus(503); $response->assertViewIs('database-credential-error'); } /** * 빈 사용자명(설정 누락)도 동일하게 전용 에러 페이지를 반환해야 한다. * * @scenario account_kind=empty, enforcement_point=runtime_web, install_state=completed * * @effects runtime_returns_503_error_page */ #[DataProvider('emptyUsernameProvider')] public function test_returns_error_page_for_empty_account(?string $username): void { config(['app.installer_completed' => true]); $this->setDbUsername($username); $response = $this->get('/'); $response->assertStatus(503); $response->assertViewIs('database-credential-error'); } /** * @return array */ public static function privilegedUsernameProvider(): array { return [ 'root' => ['root'], 'postgres' => ['postgres'], '대문자 ROOT (우회 차단)' => ['ROOT'], '앞뒤 공백 " root " (우회 차단)' => [' root '], ]; } /** * @return array */ public static function emptyUsernameProvider(): array { return [ '빈 문자열 (설정 누락)' => [''], 'null (설정 누락)' => [null], ]; } /** * 최고권한 계정일 때 API 요청에는 HTML 이 아니라 JSON 503 을 반환해야 한다. * * @scenario account_kind=privileged, enforcement_point=runtime_api, install_state=completed * * @effects runtime_returns_503_json_for_api */ public function test_returns_json_for_api_requests(): void { config(['app.installer_completed' => true]); $this->setDbUsername('root'); $response = $this->getJson('/api/test'); $response->assertStatus(503); $response->assertJson(['success' => false]); } /** * 빈 사용자명일 때도 api/* 경로는 Accept 헤더와 무관하게 JSON 이어야 한다. * * @scenario account_kind=empty, enforcement_point=runtime_api, install_state=completed * * @effects runtime_returns_503_json_for_api */ public function test_returns_json_for_api_path_requests(): void { config(['app.installer_completed' => true]); $this->setDbUsername(''); $response = $this->get('/api/settings'); $response->assertStatus(503); $response->assertHeader('content-type', 'application/json'); } /** * 설치 전(installer_completed=false)에는 최고권한 계정이어도 통과해야 한다. * * 설치 전에는 DB 설정이 비어 있는 것이 정상이며, public/index.php 가 * 이미 /install 로 유도한다. 여기서 막으면 설치 자체가 불가능해진다. * * @scenario account_kind=privileged, enforcement_point=runtime_web, install_state=not_completed * * @effects runtime_passes_through_when_not_installed */ public function test_passes_through_when_not_installed(): void { config(['app.installer_completed' => false]); $this->setDbUsername('root'); $response = $this->get('/'); $this->assertNotEquals(503, $response->getStatusCode()); } /** * 설치 전에는 사용자명이 비어 있어도 통과해야 한다 (설치 전 정상 상태). * * @scenario account_kind=empty, enforcement_point=runtime_web, install_state=not_completed * * @effects runtime_passes_through_when_not_installed */ public function test_passes_through_when_not_installed_with_empty_username(): void { config(['app.installer_completed' => false]); $this->setDbUsername(''); $response = $this->get('/'); $this->assertNotEquals(503, $response->getStatusCode()); } /** * 에러 페이지는 미인증 공개 페이지이므로 실제 DB 계정명을 노출하면 안 된다. * * @effects error_page_does_not_leak_account_name */ public function test_error_page_does_not_leak_account_name(): void { config(['app.installer_completed' => true]); $this->setDbUsername('postgres'); $response = $this->get('/'); $content = $response->getContent(); $response->assertStatus(503); $this->assertStringNotContainsString('postgres', $content); } /** * 확장·템플릿이 로딩되지 않은 상태에서 뜨는 페이지이므로 * 외부 에셋(JS/CSS)에 의존하지 않고 자체 완결이어야 한다. * * @effects error_page_is_self_contained_without_external_assets */ public function test_error_page_has_no_external_dependencies(): void { config(['app.installer_completed' => true]); $this->setDbUsername('root'); $response = $this->get('/'); $content = $response->getContent(); $response->assertStatus(503); $this->assertStringNotContainsString('