fix(release): 7.0.7 회귀 검수 발견 결함 3건 수정 — 표현식 배열 구조 분해·스케줄 확장 명령 웹 검증·JSON-LD 이스케이프

- 표현식 평가기가 화살표/함수 파라미터의 평탄한 배열 구조 분해(([k, v]) =>, 엘리전 홀)를
 지원하지 않아 배포 레이아웃 60여 파일(게시판 권한 computed·검증 오류 표시)이 평가 실패하던
 7.0.7 평가기 교체 회귀 수정 (engine-v1.60.5) + --production 재빌드.
- 스케줄 저장 검증이 HTTP 문맥에서 확장 커맨드를 해석하지 못하던 문제(확장 프로바이더의
 runningInConsole 등록 게이트로 Artisan 레지스트리 부재)를 프로바이더 $commands 선언 폴백으로
 수정 — 판정 기준(클래스 네임스페이스 + 실제 명령명 대조) 동일, fail-closed 유지.
- 봇 렌더 JSON-LD json_encode 에 JSON_HEX_TAG 추가 — 사용자 입력(검색어·게시글 제목)의
 </script> 조기 종료로 인한 저장형 XSS 차단, schema.org 데이터는 무손실.
- SeoMetaResolverTest 의 og_default_site_name 미고정 환경의존 실패를 setUp 고정으로 격리.
- 루트 CHANGELOG 7.0.7 Security/Fixed 각 1건(기출시 결함만), 시나리오 매니페스트 2건 갱신.
This commit is contained in:
HeuJung committed 2026-08-18 10:00:01 +09:00
1 parent b3d0da9355
commit a1e1706ddc
13 files changed
+359 -28

No files matched your search

@@ -675,6 +675,40 @@ class ScheduleCommandValidatorTest extends TestCase
$this->assertSame(ScheduleCommandValidator::ARTISAN_REASON_OPTION, $verdict['reason']);
}
/**
* Artisan 에 커맨드가 등록되지 않은 문맥(HTTP 요청)에서도, 활성 프로바이더가
* `$commands` 로 선언한 확장 소유 명령은 자동 허용된다.
*
* 실제 확장 프로바이더는 `runningInConsole()` 일 때만 커맨드를 등록하므로,
* 관리자 화면의 스케줄 저장 검증(HTTP)에서는 `Artisan::all()` 에 확장 커맨드가
* 없다. 등록 인스턴스가 없으면 프로바이더 선언(클래스 네임스페이스 + 실제 명령명
* 대조)을 폴백으로 해석해야 한다 — 없으면 "설치된 확장 명령 자동 허용" 약속이
* 웹 저장 경로에서 통째로 동작하지 않는다 (7.0.7 검수 발견).
*
* @scenario command_class=extension_owned, enforcement_point=validator_unit
*
* @effects extension_owned_commands_resolved_without_console_registration
*/
#[Test]
public function it_allows_provider_declared_extension_commands_without_console_registration(): void
{
require_once __DIR__.'/../../Fixtures/Extension/FakeExtensionScheduleCommand.php';
require_once __DIR__.'/../../Fixtures/Extension/FakeExtensionScheduleServiceProvider.php';
// Artisan::registerCommand 를 호출하지 않는다 — HTTP 문맥 재현.
$this->app->register(\Modules\G7Testing\Providers\FakeExtensionScheduleServiceProvider::class);
$verdict = ScheduleCommandValidator::inspectArtisanCommand('g7-testing-fake-extension-command --scope=all');
$this->assertTrue($verdict['allowed'], '프로바이더 선언 확장 명령이 HTTP 문맥에서 거부됨');
$this->assertSame('g7-testing-fake-extension-command', $verdict['name']);
// 자기 정의에 없는 옵션은 같은 폴백 경로에서도 거부되어야 한다.
$optionVerdict = ScheduleCommandValidator::inspectArtisanCommand('g7-testing-fake-extension-command --g7-not-a-real-option');
$this->assertFalse($optionVerdict['allowed']);
$this->assertSame(ScheduleCommandValidator::ARTISAN_REASON_OPTION, $optionVerdict['reason']);
}
/**
* 확장 네임스페이스를 비워도 코어 허용목록은 그대로 동작한다 (계층 독립성).
*