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:
1 parent
b3d0da9355
commit
a1e1706ddc
13 files changed
+359
-28
No files matched your search
@@ -591,15 +591,88 @@ class ScheduleCommandValidator
|
||||
|
||||
$command = self::findRegisteredCommand($name);
|
||||
|
||||
if ($command === null) {
|
||||
if ($command !== null) {
|
||||
$class = get_class($command);
|
||||
|
||||
foreach ($namespaces as $namespace) {
|
||||
if (str_starts_with($class, $namespace)) {
|
||||
return $command->getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$class = get_class($command);
|
||||
// 레지스트리에 없으면 프로바이더 선언 폴백 — HTTP 요청에서는 확장 프로바이더가
|
||||
// `runningInConsole()` 게이트로 커맨드 등록을 건너뛰어 `Artisan::all()` 에
|
||||
// 확장 커맨드가 존재하지 않는다. 관리자 화면의 스케줄 저장 검증이 바로 이
|
||||
// 문맥이므로, 등록 인스턴스가 없을 때는 활성 프로바이더의 `$commands` 선언을
|
||||
// 같은 기준(클래스 네임스페이스 + 실제 명령명 대조)으로 해석한다.
|
||||
return self::resolveProviderDeclaredCommandDefinition($name, $namespaces);
|
||||
}
|
||||
|
||||
foreach ($namespaces as $namespace) {
|
||||
if (str_starts_with($class, $namespace)) {
|
||||
return $command->getDefinition();
|
||||
/**
|
||||
* 활성 서비스 프로바이더가 `$commands` 프로퍼티로 선언한 확장 커맨드에서
|
||||
* 명령명을 해석해 정의를 돌려줍니다.
|
||||
*
|
||||
* 판정 기준은 레지스트리 경로와 동일하다 — 커맨드 **클래스**의 네임스페이스가
|
||||
* 확장 네임스페이스여야 하고, 요청된 이름은 그 클래스를 실제 인스턴스화해 얻은
|
||||
* 선언 명령명과 일치해야 한다(이름만으로 위조할 수 없다). 프로바이더가 커맨드
|
||||
* 목록을 생성자에서 동적으로 만들면 기본값이 비므로 이 폴백에는 걸리지 않는다
|
||||
* (fail-closed 유지).
|
||||
*
|
||||
* @param string $name 명령명
|
||||
* @param array<int, string> $namespaces 허용 확장 네임스페이스 접두사
|
||||
* @return InputDefinition|null 해석 불가하면 null
|
||||
*/
|
||||
private static function resolveProviderDeclaredCommandDefinition(string $name, array $namespaces): ?InputDefinition
|
||||
{
|
||||
try {
|
||||
$providers = app()->getLoadedProviders();
|
||||
} catch (Throwable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (array_keys($providers) as $providerClass) {
|
||||
if (! class_exists($providerClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$defaults = (new \ReflectionClass($providerClass))->getDefaultProperties();
|
||||
} catch (Throwable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ((array) ($defaults['commands'] ?? []) as $commandClass) {
|
||||
if (! is_string($commandClass) || ! class_exists($commandClass)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$owned = false;
|
||||
foreach ($namespaces as $namespace) {
|
||||
if (str_starts_with($commandClass, $namespace)) {
|
||||
$owned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $owned) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var SymfonyCommand $instance */
|
||||
$instance = app()->make($commandClass);
|
||||
} catch (Throwable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $instance instanceof SymfonyCommand || $instance->getName() !== $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $instance->getDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user