Files
Gnuboard7/tests/scenarios/language-pack-php-whitelist-and-activation-boundary.yaml
HeuJung 3f29f9fd1e chore(core,board,ecommerce,page,gdpr): 7.0.6 공개 릴리즈 누출 검사 차단 요인 제거
prepare-release.sh 의 파일 본문 누출 검사가 error 10건으로 릴리즈를 차단하고 있었다.
공개 저장소는 를 제외하므로, 배포되는 파일이 그 경로나 를 참조하면
공개본에서 깨진 참조가 된다.

- 시나리오 매니페스트 4건: test_files 의 내부 하네스 테스트 경로 제거
- Playwright spec 3건: 룰 파일 경로/@see 포인터를 자기완결 서술로 교체
 (@see 2건은 이미 stale — 가리키던 사례 번호가 실제와 달랐다)
- 소스/테스트 주석 3건: 파일명 노출 제거

내부 역할 호칭이 공개본에 영구 노출되는 warn 23건 중 21건도 함께 중립 표현으로
정정했다. API 표면 파일 2건은 주석만 고쳐도 문서 커버리지 게이트에 영구 면제가
필요해져 보류한다 — warn 은 릴리즈를 차단하지 않는다.

부수로 드러난 기존 결함 둘을 같은 세션에서 처리:
- gdpr Playwright config 에 locale 고정 누락 — 첫 로드가 en-US 로 나가 화면이 영어로
 굳으면 한국어 문구를 단언하는 spec 이 전부 실패한다
- 언어팩 시나리오의 정적 검사 계층 전용 효과 2건을 effects 에서 rules_layer_coverage
 로 이관 — 런타임 테스트로 성립하지 않는 항목이라 그 칸이 정합 위치다

검증: 누출 검사 error 0, audit --working 위반 0(룰 192), 시나리오 매니페스트 8건
errors 0, gdpr Vitest 148 green, PHP lint/JSON/YAML 정상.
버전 정합은 코어 working 7.0.6 / 공개 latest 7.0.5 = new-bump 로 릴리즈 가능 상태.
2026-08-10 17:46:17 +09:00

96 lines
7.0 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
feature: 언어팩 PHP 구문 화이트리스트 및 활성화 권한 경계
description: |
언어팩의 PHP 파일은 활성화되면 fallback 경로에 배선되어 `require` 된다. 즉 파일 내용이
그대로 실행되며, `Accept-Language: {locale}` 요청 한 번이면 발화한다.
기존 방어는 두 지점 모두 뚫려 있었다.
- 내용 검사: 위험 함수 11개를 정규식으로 나열한 블록리스트 —
`file_put_contents` `fopen` `call_user_func` `assert` 백틱 등이 목록에 없어 통과했고,
`('system')('id')` 처럼 함수 이름을 아예 쓰지 않는 형태는 원리적으로 잡을 수 없었다.
- 권한 경계: 설치(install)와 활성화(manage)는 별도 권한인데, 설치 요청의
`auto_activate` 플래그가 `activate()` 를 우회하고 `status=Active` 를 직접 기록해
install 권한만으로 활성화가 성립했다. 활성 승격이 `require` 배선의 필수 조건이므로
이 경계가 체인의 마지막 관문이다.
본 기능은 판정을 뒤집는다.
- 내용: "번역 배열만" 통과시키는 토큰 상태기계 (함수 호출은 이름과 무관하게 전부 거부)
- 형식·위치: 확장자 화이트리스트(json/php/md, 대소문자 무관) + PHP 위치 강제 + 심볼릭 링크 거부
- 권한: 외부 소스(파일·URL·GitHub)의 `auto_activate` 에 활성화 권한을 필드 단위로 요구
- 활성화 경로 단일화: 설치 트랜잭션은 항상 installed 로 기록하고 activate() 를 경유
axes:
vector: [php_syntax_validator, assert_security_rules, install_from_untrusted_source, install_from_bundled, finalize_install_activation]
actor_permission: [cli_system, install_only, manage_only, install_and_manage]
cross_product: |
vector × actor_permission 이 핵심이다. 같은 판정이라도 어느 계층에 걸리느냐에 따라
깨뜨리는 것이 다르다 — 권한 검사를 서비스 계층에 두면 CLI(`language-pack:install`,
`language-pack:provision`)와 확장 설치 cascade 가 깨지고, FormRequest 의 `authorize()`
에 두면 `auto_activate` 를 보내지 않은 정상 설치까지 403 이 된다.
페이로드 형태(문자열 리터럴 호출 / 가변 변수 / heredoc / 닫는 태그 뒤 코드 / 대문자 확장자
/ phar / 잘못된 locale 디렉토리 / 심볼릭 링크)는 별도 axis 로 두지 않는다. 전부 같은
문법 규칙 하나 또는 같은 파일 정책 하나에서 갈리므로 axis 로 두면 조합만 늘고 판정
지점은 하나다. 대신 DataProvider 로 전수 전개하고 effects 로 대표한다.
exclusions:
- { vector: php_syntax_validator, actor_permission: install_only, reason: "프레임워크 의존이 없는 순수 판정 유틸 — 권한 컨텍스트가 존재하지 않는다" }
- { vector: php_syntax_validator, actor_permission: manage_only, reason: "동일 — 권한 개념 없음" }
- { vector: php_syntax_validator, actor_permission: install_and_manage, reason: "동일 — 권한 개념 없음" }
- { vector: assert_security_rules, actor_permission: install_only, reason: "서비스 계층의 내용·형식 검사로 권한과 무관하게 모든 설치 경로에 동일 적용" }
- { vector: assert_security_rules, actor_permission: manage_only, reason: "동일 — 권한별 분기 없음" }
- { vector: assert_security_rules, actor_permission: install_and_manage, reason: "동일 — 권한별 분기 없음" }
- { vector: install_from_untrusted_source, actor_permission: cli_system, reason: "CLI 는 FormRequest 를 거치지 않는다 — 권한 게이트를 서비스에 두지 않기로 한 설계의 직접 귀결이다. CLI 비파괴 자체는 finalize_install_activation × cli_system 셀이 실 커맨드 실행으로 단언한다(cli_installation_is_unaffected_by_the_http_activation_gate)" }
- { vector: install_from_bundled, actor_permission: manage_only, reason: "설치 권한이 없어 라우트 미들웨어에서 끊긴다 — 외부 소스 쪽에서 같은 경계를 이미 단언하므로 번들에서 반복하지 않는다" }
- { vector: install_from_bundled, actor_permission: cli_system, reason: "동일 — FormRequest 미경유" }
- { vector: finalize_install_activation, actor_permission: install_only, reason: "서비스 계층 활성화 경로로 HTTP 권한 컨텍스트가 없다 — 권한 판정은 FormRequest 계층이 소유" }
- { vector: finalize_install_activation, actor_permission: manage_only, reason: "동일 — 권한 컨텍스트 없음" }
- { vector: finalize_install_activation, actor_permission: install_and_manage, reason: "동일 — 권한 컨텍스트 없음" }
effects:
# 구문 화이트리스트
- translation_array_files_are_accepted
- function_calls_are_rejected_regardless_of_name
- name_free_bypasses_are_rejected
- broken_and_oversized_sources_are_rejected_early
- violation_line_is_reported
# 파일 정책
- install_rejects_php_that_is_not_a_translation_array
- install_rejects_files_outside_the_extension_whitelist
- install_rejects_php_outside_the_declared_locale_directory
- install_rejects_packages_containing_symlinks
- install_accepts_real_world_translation_files
- every_bundled_pack_passes_the_new_validator
# 권한 경계
- install_only_user_cannot_auto_activate
- install_without_auto_activate_is_not_blocked
- manage_user_can_auto_activate
- manage_only_user_cannot_install_at_all
- overwriting_an_active_pack_does_not_inherit_active_status
# 활성화 경로 단일화
- activated_hook_fires_exactly_once_on_auto_activate
- auto_activate_skipped_when_slot_occupied
- auto_activate_goes_through_activate_and_enforces_dependencies
- reinstalling_an_active_pack_does_not_demote_it
- cli_installation_is_unaffected_by_the_http_activation_gate
- update_of_an_active_pack_keeps_it_active
- update_of_an_inactive_pack_does_not_promote_it
# E2E axis 없음: 판정은 전부 서버측(FormRequest / Service)이다. 관리자 화면에서
# auto_activate 를 보내는 곳은 번들 재설치 모달 하나뿐이고, 게이트를 네 경로 전부에
# 걸기로 하면서(프로젝트 결정 2026-08-04) 이 모달이 보내는 값을 운영자의 활성화 권한
# (`abilities.can_activate`)으로 분기하도록 바꿨다 — 권한이 없으면 auto_activate 를
# 보내지 않아 재설치는 그대로 되고 팩만 installed 로 내려간다.
#
# 이 분기는 표현식 한 줄이고 관측 지점이 "요청 본문에 무엇이 실렸는가" 하나뿐이라,
# 브라우저를 띄우는 것보다 서버측 권한 조합 테스트가 같은 것을 더 촘촘히 고정한다
# (install_only / install_and_manage 두 조합 모두 단언). 렌더 결과·조작 흐름이
# 달라지지 않으므로 E2E axis 를 두지 않는다.
test_files:
- tests/Unit/Services/LanguagePack/LanguagePackPhpArrayValidatorTest.php
- tests/Unit/Services/LanguagePack/LanguagePackSecurityTest.php
- tests/Unit/Services/LanguagePack/LanguagePackServiceTest.php
- tests/Feature/Api/Admin/LanguagePackControllerTest.php