Files
Gnuboard7/tests/scenarios/core-execute-upgrade-steps-standalone.yaml
T
HeuJung 67cae00dd8 fix(core): 코어 업데이트 spawn 자식의 config 캐시 오판 3건 수정 + 컨테이너 보존 래퍼 전수
7.0.9 클린 설치본에서 7.0.10 으로 올리자 업그레이드 스텝 단계가 "부모 메모리 stale" 로 중단됐다.
스텝 자식은 부모가 비우지 않은 이전 버전 config 캐시로 부팅해 env APP_VERSION 오버라이드와
신버전 config/app.php 의 update 목록을 모두 보지 못한다. 이전 릴리즈에서는 자식 진입부의
config:cache 가 전역 Container 를 일회용 앱으로 바꿔 놓는 부수효과로 가드가 우연히 침묵했고,
그 부수효과를 걷어낸 withPreservedContainer 가 잠복 결함을 드러냈다.

- stale 가드는 CoreVersionChecker::getCoreVersion(env 우선) 으로 판독
- 부모는 spawn 직전 config 캐시를 비우고, 자식은 캐시 파일이 있으면 디스크 config 를 직접 읽는다
 (7.0.10 이 추가한 public/build/ext 쓰기 권한 정상화 누락 차단)
- route:cache 도 같은 부수효과를 남기므로 RouteCacheHelper·optimizeSystem 을 보존 래퍼로 감쌌다
 (단독 스텝 재실행·시스템 최적화 뒤 정적 재게시 예약 소실)
- 과거 업그레이드 사고 14부류를 7.0.10 변경과 대조 — 재발 조건은 위 3건뿐
- audit 룰 fresh-app-artisan-call-outside-cache-helper + 픽스처, 회귀 테스트 6건(수정 전 red)
2026-09-06 18:41:53 +09:00

101 lines
8.0 KiB
YAML

# audit:allow test-scenario-coverage reason: 본 매니페스트는 `core:execute-upgrade-steps` 단독 실행 안전화 (사전 2단계 + 사후 3단계 자동 수행 + 5개 --skip-* 옵션) 의 시나리오 매트릭스 SSoT. 핵심 회귀 가드는 test_files 의 통과 테스트로 커버.
feature: core:execute-upgrade-steps 단독 실행 안전화 (사전·사후 단계 자동 수행 + 5개 --skip-* 옵션)
description: |
공개 이슈 [gnuboard/g7#34](https://github.com/gnuboard/g7/issues/34) (beta.3 → beta.4 우회 절차) 의 운영자 안내문이
11단계의 수동 명령 (rsync → composer dump-autoload → cache:clear →
core:execute-upgrade-steps → migrate --force → reloadCoreConfigAndResync via tinker →
sed APP_VERSION → cache:clear → module/plugin/template:update --force --source=bundled)
을 요구했던 근본 원인은 `core:execute-upgrade-steps` 가 단독 호출 시
부모 `CoreUpdateCommand` 가 수행하던 Step 9 (Migration + Resync), Step 11
(.env 버전 + 캐시 정리), 번들 확장 일괄 업데이트 prompt 를 모두 누락한 것.
본 매니페스트는 5개 누락 단계를 자식 기본값에 포함시키고, 부모 spawn 호출 시엔
5개 `--skip-*` 옵션으로 중복 회피하는 cross product 의 회귀 가드.
추가 가드 (2026-05-14): 구버전 부모(beta.5 이하) 가 신버전 자식(beta.6+) 을 spawn 할 때
`--skip-*` 5개 옵션은 모르지만 `G7_UPDATE_IN_PROGRESS=1` env 는 beta.3+ 부모부터
항상 설정한다. 자식은 env 시그널만으로도 spawn 컨텍스트를 감지하여 5단계 모두 스킵해야
한다 (옵션 부재 + non-interactive 환경에서 prompt 호출로 인한 Aborted exit=1 회귀 차단).
구성:
1. 5개 사전·사후 단계 각각의 단독 호출 / `--skip-*` 옵션 분기 검증.
2. 부모 `CoreUpdateCommand::spawnUpgradeStepsProcess` 가 자식 command 배열에
5개 옵션을 모두 전달하는지 (escapeshellarg 후 commandLine 문자열 검증).
3. `runUpgradeSteps` 본 임무는 항상 호출 (옵션 무관).
4. 5개 옵션을 모두 전달한 경우 CoreUpdateCommand spawn 시나리오 등가 — 사전·사후 미수행.
5. `G7_UPDATE_IN_PROGRESS=1` env 만으로도 5단계 모두 스킵 (구버전 부모 V-1 안전 가드).
axes:
invocation_origin: [standalone_operator, parent_spawn_with_skip_options, parent_spawn_env_only] # 누가 호출했는가
skip_migrations: [present, absent]
skip_resync: [present, absent]
skip_version_env: [present, absent]
skip_cache_clear: [present, absent]
skip_bundled_updates: [present, absent]
spawn_env_flag: [present, absent] # G7_UPDATE_IN_PROGRESS=1 시그널
force_flag: [present, absent] # bundled prompt 우회 여부
bundled_updates_count: [zero, modules_only, plugins_only, templates_only, lang_packs_only, mixed]
from_to_relation: [from_lt_to, from_eq_to_forced] # version_compare 분기
exclusions:
- { invocation_origin: parent_spawn_with_skip_options, skip_migrations: absent, reason: "부모(beta.6+) spawn 시엔 5개 옵션 모두 전달 — 일부 절단 시뮬은 인위적 비현실 분기" }
- { invocation_origin: parent_spawn_with_skip_options, skip_resync: absent, reason: "동일 — 부모 spawn 시 5개 옵션 일괄 전달" }
- { invocation_origin: parent_spawn_with_skip_options, skip_version_env: absent, reason: "동일" }
- { invocation_origin: parent_spawn_with_skip_options, skip_cache_clear: absent, reason: "동일" }
- { invocation_origin: parent_spawn_with_skip_options, skip_bundled_updates: absent, reason: "동일" }
- { invocation_origin: parent_spawn_env_only, skip_migrations: present, reason: "구버전 부모(beta.5) 는 5개 옵션을 모르므로 전달하지 않음 — 본 분기는 env 가드 단독 효과 검증" }
- { invocation_origin: parent_spawn_env_only, skip_resync: present, reason: "동일" }
- { invocation_origin: parent_spawn_env_only, skip_version_env: present, reason: "동일" }
- { invocation_origin: parent_spawn_env_only, skip_cache_clear: present, reason: "동일" }
- { invocation_origin: parent_spawn_env_only, skip_bundled_updates: present, reason: "동일" }
- { invocation_origin: parent_spawn_env_only, spawn_env_flag: absent, reason: "정의상 env_only 분기는 env=1 필수" }
- { invocation_origin: standalone_operator, spawn_env_flag: present, reason: "운영자 수동 호출은 env 미설정 — env 설정 시는 parent_spawn 분기로 분류" }
- { invocation_origin: standalone_operator, bundled_updates_count: zero, skip_bundled_updates: absent, force_flag: absent, reason: "0건 + 옵션 미사용 + force 미사용 시 prompt 발동되나 본 매트릭스의 회귀 대상은 옵션 분기뿐" }
effects:
# §1 사전 단계 자동 수행
- ExecuteUpgradeStepsCommand_invokes_runMigrations_by_default
- ExecuteUpgradeStepsCommand_skips_runMigrations_when_skip_migrations_present
- ExecuteUpgradeStepsCommand_invokes_reloadCoreConfigAndResync_by_default
- ExecuteUpgradeStepsCommand_skips_reloadCoreConfigAndResync_when_skip_resync_present
# §2 사후 단계 자동 수행
- ExecuteUpgradeStepsCommand_invokes_updateVersionInEnv_with_to_version_by_default
- ExecuteUpgradeStepsCommand_skips_updateVersionInEnv_when_skip_version_env_present
- ExecuteUpgradeStepsCommand_invokes_clearAllCaches_by_default
- ExecuteUpgradeStepsCommand_skips_clearAllCaches_when_skip_cache_clear_present
- ExecuteUpgradeStepsCommand_invokes_runBundledExtensionUpdatePrompt_by_default
- ExecuteUpgradeStepsCommand_skips_bundled_updates_when_skip_bundled_updates_present
# §3 본 임무 (runUpgradeSteps) 는 옵션 무관 항상 호출
- ExecuteUpgradeStepsCommand_always_invokes_runUpgradeSteps_regardless_of_skip_options
# §4 부모 spawn 5개 옵션 전달
- CoreUpdateCommand_spawnUpgradeStepsProcess_appends_skip_migrations_to_command_array
- CoreUpdateCommand_spawnUpgradeStepsProcess_appends_skip_resync_to_command_array
- CoreUpdateCommand_spawnUpgradeStepsProcess_appends_skip_version_env_to_command_array
- CoreUpdateCommand_spawnUpgradeStepsProcess_appends_skip_cache_clear_to_command_array
- CoreUpdateCommand_spawnUpgradeStepsProcess_appends_skip_bundled_updates_to_command_array
# §5 운영자 안내문 (resumeCommand) 호환성 — 옵션 없이도 기본값으로 안전 실행
- resume_command_without_skip_options_invokes_all_five_pre_and_post_steps_safely
# §6 구버전 부모 V-1 안전 가드 (env 시그널 단독)
- ExecuteUpgradeStepsCommand_skips_runMigrations_when_spawn_env_flag_present_without_skip_options
- ExecuteUpgradeStepsCommand_skips_reloadCoreConfigAndResync_when_spawn_env_flag_present_without_skip_options
- ExecuteUpgradeStepsCommand_skips_updateVersionInEnv_when_spawn_env_flag_present_without_skip_options
- ExecuteUpgradeStepsCommand_skips_clearAllCaches_when_spawn_env_flag_present_without_skip_options
- ExecuteUpgradeStepsCommand_skips_bundled_updates_when_spawn_env_flag_present_without_skip_options
- ExecuteUpgradeStepsCommand_env_guard_dominates_over_force_flag_for_post_steps
- ExecuteUpgradeStepsCommand_standalone_invocation_without_env_runs_all_five_steps_intact
- execute_upgrade_steps_child_reads_update_config_from_disk_when_config_is_cached
test_files:
- tests/Feature/Console/Commands/ExecuteUpgradeStepsStandaloneTest.php
- tests/Feature/Console/Commands/ExecuteUpgradeStepsCommandHandoffTest.php
# 본 매트릭스의 cross product 는 수백 케이스이나, 실제 회귀 가드는 test_files 의
# 통과 테스트가 SSoT — 매니페스트는 매트릭스 SSoT 역할.
#
# 의도적 제외:
# - maintenance 모드 자동 제어 (down/up) : 단독 실행 시 운영자가 직접 제어. 매트릭스 대상 아님.
# - ownership snapshot / cleanupPending / deleteBackup : 단독 실행 컨텍스트에 해당 자원 자체가 없음.
# - composer 재실행 : 디스크 코어 파일은 이미 신버전 적용된 상태가 단독 실행의 전제.