Files
Gnuboard7/tests/scenarios/extension-test-isolation.yaml
T
HeuJung c0e0d82459 refactor(extension): 확장 미들웨어 선언적 self-gate 정규화
확장이 SP Kernel 미들웨어 그룹을 직접 조작하거나 라우트 파일에 미들웨어
FQCN 을 직접 부착하던 임시 방식을, 확장이 부착 대상(targets)을 명시 선언하고
코어가 요청 시점에 라우트명·URI 로 매칭해 실행하는 self-gate 로 정규화.
번들 7건(ecommerce/gdpr/pay 3종) 이전, audit 룰 3건·문서·버전 동기화 동반.

부수적으로 generate-skills.cjs 가 재생성 시 신의성실(부수의무) 섹션을 소실
시키던 회귀를 수정 — 스킬별 불릿을 스크립트 SSoT 로 편입해 재생성에도 보존.
2026-07-16 10:22:51 +09:00

79 lines
5.0 KiB
YAML

# audit:allow test-scenario-coverage reason: axes cross product 는 환경×allowlist상태×확장유형×등록표면×테스트종류의 조합 열거로, 실질 회귀 가드는 effects 18건이 담당한다. effects 는 test_files 의 메서드 docblock @effects 로 전수 매핑되어 개별 검증된다. cross product 개별 케이스의 docblock 마킹은 effects 매핑과 중복이므로 생략.
feature: 테스트 환경 확장 격리 (requiredExtensions allowlist)
description: |
PHPUnit 환경에서 테스트 클래스가 명시한 확장만 ServiceProvider / route 등록
대상이 되도록 통제하는 격리 레이어. 기존 requiredExtensions 프로퍼티를
마이그레이션 등록 전용에서 ServiceProvider / route 등록 allowlist 로 승격한다.
핵심 동작:
- ExtensionTestAllowlist 가 testing 환경 + 명시적 set 시에만 isActive() = true
- allowlist 활성 시 PluginServiceProvider / ModuleServiceProvider 는
allowlist 밖 확장의 ServiceProvider register() 를 건너뜀
- PluginRouteServiceProvider / ModuleRouteServiceProvider 는 동일 기준으로 route 차단
- 확장 자체 테스트는 selfExtension() (테스트 파일 경로 기반 자동 탐지) 로
자기 확장을 allowlist 에 자동 포함 → 무수정 동작. 이 동작은 GDPR 플러그인
자체 테스트 178건 / sirsoft-page 모듈 자체 테스트 167건이 requiredExtensions
선언 없이 통과함으로써 실증된다 (selfExtension 은 ReflectionClass 로 테스트
파일 경로를 보므로 단위 테스트 격리가 불가 — 실제 확장 테스트 통과가 증거).
- 비-testing 환경 또는 allowlist 미설정 시 isActive() = false → 전수 로딩 보존
적용 범위 한정:
ModuleManager::loadModules / PluginManager::loadPlugins (hook listener / config /
채널 등록 경로) 에는 가드를 적용하지 않는다. 그 경로는 fixture 확장을 직접
생성해 loadModules/loadPlugins 를 호출하는 다수의 확장 테스트가 의존하므로
가드 적용 시 광범위한 회귀를 유발한다.
확장 미들웨어와 self-gate:
확장 미들웨어(GDPR CookieConsentMiddleware 등)는 더 이상 provider boot 에서
web/api 그룹에 직접 등록되지 않는다. 코어 ExtensionMiddlewareGate 래퍼가 항상
web/api 그룹에 등록되고, 각 확장이 getMiddleware() 로 선언한 미들웨어를 요청
시점에 대상 매칭될 때만 실행한다. 미들웨어를 실제로 실행하는 후보로 삼으려면
확장이 ExtensionMiddlewareRegistry 인덱스에 수집돼야 하며, 인덱스는 활성 확장
(getActive{Modules,Plugins}) 만 포함한다. 따라서 core-only 테스트는 비활성 GDPR
미들웨어를 게이트가 실행하지 않고, allowlist 로 GDPR 을 활성화한 테스트에서만
게이트가 그 미들웨어를 매칭한다. 격리의 핵심 목적(비대상 확장 미들웨어 미개입)은
ServiceProvider register 가드 + registry 활성 확장 필터의 이중으로 충족된다.
axes:
app_env: [testing, production]
allowlist_state: [unset, empty, contains_target, contains_other]
extension_type: [plugin, module]
registration_surface: [service_provider, route]
test_class_kind: [core_test, extension_self_test]
exclusions:
- { app_env: production, allowlist_state: empty, reason: "비-testing 환경은 allowlist 무관 — isActive false 고정" }
- { app_env: production, allowlist_state: contains_target, reason: "동일 — production 은 가드 비활성" }
- { app_env: production, allowlist_state: contains_other, reason: "동일" }
- { test_class_kind: extension_self_test, allowlist_state: unset, reason: "확장 자체 테스트는 selfExtension 으로 항상 자기 확장 포함" }
effects:
- allowlist_inactive_when_app_env_not_testing
- allowlist_inactive_when_never_configured
- allowlist_active_when_testing_and_configured
- empty_allowlist_is_active_and_blocks_all_extensions
- set_classifies_plugin_and_module_by_path_prefix
- set_normalizes_trailing_slash
- set_ignores_prefixless_entries
- set_recall_replaces_previous_allowlist
- reset_deactivates_guard
- core_only_test_does_not_register_gdpr_service_provider
- core_only_test_does_not_register_gdpr_middleware_in_web_group
- core_only_test_does_not_register_gdpr_middleware_in_api_group
- core_only_test_does_not_register_gdpr_plugin_routes
- allowlisted_plugin_service_provider_is_registered
- allowlisted_plugin_middleware_is_registered_in_web_group
- selfExtension_returns_null_for_core_tests
- production_env_keeps_full_extension_loading
test_files:
- tests/Unit/Extension/ExtensionTestAllowlistTest.php
- tests/Feature/Extension/ExtensionTestIsolationTest.php
- tests/Feature/Extension/ExtensionTestIsolationGdprAllowedTest.php
rules_layer_coverage:
- rule: service-provider-db-guard
coverage: 가드는 register()/boot() 초입에서 ExtensionTestAllowlist::isActive() 만 검사 — DB 접근 없음