배포 프리플라이트 (배포 가능성 및 blocker 수집)
배포를 실행하기 전에(terraform apply 또는 컨트롤 플레인 수정 PR)
deploy-preflight 검사를 사용하세요. 이 검사는 대상 환경에서 배포를 차단하거나 배포
품질을 저하시킬 수 있는 모든 요인을 수집합니다. 각 항목을 해당 항목을 발생시킨 정확한
규칙과 연결하고, 문제를 해결할 수 있는 구체적인 제어 수단에 매핑합니다. 이는 단일 작업에
적용하던 what-if 검증기를
배포 전체로 확장한 것입니다.
이 검사는 계획 자체는 올바르지만 대상 구독의 보호 정책으로 인해 거부되는 반복적인 실패를 해결합니다. 예를 들어 허용되지 않는 리소스 유형, 차단된 패키지 또는 이미지 출처, 누락된 역할 할당, 소진된 할당량, 해당 리소스보다 먼저 준비해야 하는 종속성이 있습니다. terraform apply가 실패할 때마다 이러한 문제를 하나씩 발견하는 대신, 사전 검사에서 모든 문제를 배포 전에 한 번에 보고합니다.
고객 환경에 종속되지 않음: 아래의 모든 denylist, 차단된 호스트, 미러 엔드포인트 및 토글 값은 구성 또는 포크에서 제공됩니다. 업스트림은 검사 메커니즘과 범용 분류 체계만 제공하며, 고객별 보호 정책 값은 포함하지 않습니다(generic-scope.instructions.md).
실행 루프에서의 위치
섹션 제목: “실행 루프에서의 위치”설계에서는 하나의 분석기를 공유하는 두 가지 진입점을 정의합니다. 사람의 승인이 필요한 보호된 배포 경로는 독립 실행형 실행 스크립트로 제공됩니다. 컨트롤 플레인 경로는 현재 통합 경계까지만 구현되어 있습니다.
- 컨트롤 플레인(일부 구현됨): 실행기가 수정 PR을 생성하기 전에 분석기가 해당 변경 사항을 대상 범위에 실제로 적용할 수 있는지 확인합니다. 차단 요인이 발견되면 정책 위반으로 실패할 PR을 생성하는 대신 작업을
hil로 낮춥니다. 이러한 실행 순서를 강제하는 결정론적 게이트와 정확한 패치 갱신을 위한 전달 래퍼는 구현 및 테스트가 완료되었습니다. 다만 필수 갱신을 연결하는 실제 실행 경로는 아직 구현되지 않았습니다. - 사람이 수행하는 배포(구현됨): 비공개 실행기 워크플로는 계획 수립 전에 보고서를 생성하고, 증거 다이제스트를 exact-plan 메타데이터에 연결합니다. PR 댓글 및 GitHub Check를 통한 결과 전달은 후속 작업으로 남아 있습니다.
두 경로 모두 결정론적 처리 우선(deterministic-first) 방식(T0 계열)을 따릅니다. 클라우드 호출이 없는 정적 분석으로 대부분의 발견 사항을 처리하고, 범위가 제한된 읽기 전용 실제 환경 프로브로 나머지 항목(외부 네트워크 연결 가능 여부, 할당량 등)을 확인합니다. 사전 검사 과정에서는 어떤 대상도 변경하지 않습니다.
프로브 분류 체계
섹션 제목: “프로브 분류 체계”프로브는 PreflightTarget(배포가 대상으로 하는 범위와 리소스 유형, 외부 연결 호스트 및 필수 링크)을 검사하고, 하나의 범주에 속하는 근거가 확인된 발견 사항을 반환합니다. 범용 프로브 목록은 다음과 같습니다.
| 카테고리 | 대표 차단 요인 | 탐지 (deterministic-first) |
|---|---|---|
policy_guardrail | disallowed 리소스 types, NSG 필수, 인라인 디스크 거부, 공개 IP 거부 | terraform plan JSON을 policies/(OPA)에 재검증 + Azure Policy 거부 시뮬레이션 (정적) |
supply_chain_egress | docker.io 차단, PyPI / npm / apt 차단, 외부 base 이미지 pull 거부 | NSG / Firewall / UDR 규칙 분석 (정적) + 범위가 제한된 egress 도달성 프로브 (라이브) |
identity_rbac | 실행기 아이덴티티가 대상 범위에 역할 없음; 역할 배정 생성 불가 | 인벤토리 그래프에서 범위 role-assignment 확인 (정적) |
quota_capacity | SKU / 지역 쿼터 초과, 영역 용량 없음 | 쿼터 조회 (라이브, 캐시) |
dependency_ordering | disk before VM, NSG before 서브넷, 비공개 엔드포인트 before 리소스 | 정책 + 모듈 의존성 그래프에서 도출한 순서 위반 (정적) |
secret_config | Key Vault 참조 해결 불가, 필수 시크릿 부재 | 시크릿 존재 / 도달성 확인 (정적) |
policy_guardrail과 supply_chain_egress는 보안이 강화된 네트워크에서 고객이 가장 자주
마주치는 두 카테고리입니다. Azure Policy deny 가드레일(Not allowed resource types /
Allowed resource types)과 방화벽 egress denylist에 직접 매핑됩니다. 기저 규칙의 출처는
rule-catalog-collection-ko.md를 참조하세요.
준비 상태 리포트
섹션 제목: “준비 상태 리포트”발견 사항은 하나의 DeploymentReadinessReport
(core/deploy_preflight/report.py)
로 조합합니다. 각 발견 사항에는 다음 세 항목이 필요합니다:
- 근거 - 그것을 만들어낸 규칙의 CSP-neutral 인용
(
policy:<neutral-id>,nsg:<neutral-id>/rule:<name>). 출처를 인용할 수 없는 프로브는 발견 사항을 발행해서는 안 됩니다; 근거 없는 차단 요인은 결함이며, T2 검증기가 따르는 규칙과 동일합니다. - 심각도 -
blocking(강제 적용 모드에서 배포를 차단) 또는warning(표시하지만 배포를 차단하지 않음)입니다. - 해결 방법 - 해소 방법을 제시하며, 가능하면 구체적인 조정 수단에 연결합니다 (아래 토글 표 참조).
결정 의미론
섹션 제목: “결정 의미론”| 결정 | 의미 |
|---|---|
clear | 발견 사항 없음 |
needs_review | 발견 사항은 있으나 차단은 없음 (경고만) |
blocked | 최소 하나의 차단 발견 사항 |
보고서는 항상 실제 평가에 따른 판정을 기록합니다. 판정으로 배포를 통제할지는 별도
플래그 blocks_deploy로 나타내며, 검사가 enforce 모드로 실행됐을 때만 true입니다.
관찰 우선
섹션 제목: “관찰 우선”모든 새 프로브는 관찰 모드로 출시됩니다: 차단 요인을 진실하게 보고하지만
blocks_deploy는 false로 유지되어, 검증되지 않은 프로브가 오탐으로 사람의 배포를
잘못 막을 수 없습니다. 프로브는 고정된 시나리오 세트에서 false-positive율이 측정된 후에만
카테고리별로 enforce로 승격됩니다 - 자율 액션에
ActionType 계약가 적용하는 것과 동일한 승격 규율입니다.
게시 보류
섹션 제목: “게시 보류”재조립으로 차단 요인을 해소했더라도 그 결정은 과거 시점에 내린 것입니다. 교정 제안을 제출하기 전에 게이트는 누적된 오버라이드로 동일한 분석기를 다시 실행하고, 새 리포트가 게시를 정당화하지 못하면 보류합니다:
| 보류 | 원인 |
|---|---|
no_applied_toggle | 루프가 토글을 적용하지 않음, 거부가 아니라 무동작 패스임 |
reassembly_escalated | 루프가 에스컬레이션함, 부분 재조립은 결코 제출하지 않음 |
blocking_finding | 재검증된 리포트에 여전히 차단 발견 사항이 있음 |
stale_evidence | 리포트가 신선도 창을 벗어났거나 타임스탬프를 쓸 수 없음 |
scope_drift | 리포트 또는 적용된 토글이 기대한 범위에 묶여 있지 않음 |
모든 보류는 첫 제출 이전에 결정되므로, 보류된 패스는 부분 제안 집합이 아니라 아무것도
제출하지 않으며, blocks_deploy가 false로 유지되는 관찰 모드에서도 진실한 판정이
게시를 차단합니다. 검증기에서 예외가 발생하면 제출 전에 전파되며, 호출자는 해당 검사를
hil로 라우팅합니다.
PR 전달 경계의 별도 래퍼는 재전달을 포함한 모든 게시 시도에서 호출자가 제공한 읽기 전용 계획 갱신을 다시 실행합니다. 검증된 수정안의 SHA-256이 변경 불가능한 제안 수정안과 같고, 보고서 범위가 호출자가 신뢰하는 범위와 같으며, 모든 필수 프로브 범주를 검사해야 합니다. 갱신 누락, 수정안 변경, 검사 범위 누락, 오래된 근거, 차단 요인이 있으면 관찰 모드에서도 PR을 보류합니다. 래퍼는 타임스탬프만으로 프로바이더의 재검사를 증명할 수 없습니다. 호출자는 원본이나 Inventory가 변경된 뒤에도 권위 있는 재렌더링과 읽기 전용 재분석을 제공해야 합니다. 연결되지 않은 래퍼는 실제 운영 게이트가 아닙니다. 현재 PR 발행기는 갱신 결과를 후속 기준 브랜치 확인에 아직 연결하지 않으므로, 두 작업 사이의 원본 변경은 실제 운영 조립을 막는 미해결 사항입니다.
GitHub Checks 어댑터는 기존 PR의 정확한 최신 커밋에만 검사 결과를 붙일 수 있습니다. 모드, 결정, 상한이 있는 발견 사항 수, 검사한 범주 수만 노출합니다. 원본 범위, 근거, 발견 사항 문구, 호출자 메타데이터는 노출하지 않습니다. 관찰 모드 보고서는 권고용입니다. 어댑터 부재나 검사 게시 실패는 프리플라이트 완료를 입증하지 못하며, 이미 열린 PR을 되돌릴 수도 없습니다. GitHub는 프로세스 사이에서 원자적으로 “없을 때만 검사 생성” 연산을 제공하지 않으므로, 분산 멱등성을 주장하려면 실제 조립에 단일 작성자 전달이나 영속 잠금이 필요합니다.
차단 요인에서 Terraform 토글로의 매핑
섹션 제목: “차단 요인에서 Terraform 토글로의 매핑”보고서는 단순한 문제 목록이 아닙니다. 각 terraform_toggle 발견 사항은 배포가 규칙을
준수하도록 만드는 인프라 하위 모듈과 변수 재정의를 지정합니다. 이는 기존 infra/modules/<seam>/ +
var.<seam>_kind 선택 패턴(project-structure-ko.md)을
리소스-프로비저닝 모드로 일반화한 것으로, 모듈 출력 계약은 고정된 채 내부 배선만 전환됩니다:
| 토글 | 값 | 효과 |
|---|---|---|
disk_provisioning | inline | attach_existing | VM 디스크를 인라인 생성 vs 사전 프로비저닝된 디스크 첨부 (var.existing_disk_ids) |
nsg_provisioning | create | byo | NSG 생성 vs 기존 NSG 참조(var.existing_nsg_id), 가드레일이 요구하는 대로 첨부 |
registry_source | docker_io | acr_mirror | base 이미지를 docker.io 대신 내부 레지스트리 미러에서 pull |
python_index_url | (문자열) | 패키지 설치를 내부 PyPI 미러 / 산출물 피드로 지정 |
dependency_ordering | strict | 선행 리소스(disk, NSG, 비공개 엔드포인트)를 순서 있는 적용 단계로 분리 |
이 매핑으로 거부된 리소스 타입으로 인한 문제를 해소할 수 있습니다. 인라인 디스크 거부는
disk_provisioning=attach_existing으로 해소되어, 계획이 애초에 거부된 연산을 발행하지
않습니다. 해결 방법에 autofix가 표시되면 분석기가 사람의 판단 없이 토글 변경을
교정 PR로 제안할 수 있습니다; 그렇지 않으면 지침을 발행하고 검토로 라우팅합니다.
서브시스템 레이아웃
섹션 제목: “서브시스템 레이아웃”| 조각 | 위치 | 역할 |
|---|---|---|
| 프로브 경계 | shared/providers/feasibility_probe.py | FeasibilityProbe 프로토콜 + 발견 사항 / 대상 데이터 클래스 |
| 제네릭 프로브 | shared/providers/local/feasibility.py | 결정론적·구성 주도 상류 기본값 (네트워크 없음) |
| 오케스트레이터 | core/deploy_preflight/analyzer.py | 프로브에 동시 확산, 리포트 조립 (실패 시 차단) |
| 리포트 | core/deploy_preflight/report.py | 조립된 산출물 + 판정 + blocks_deploy |
| 게시 전 게이트 | core/deploy_preflight/pre_publication_gate.py | 제안 제출 전 재검증, 보류 후 사람 검토로 라우팅 |
| PR 전달 래퍼 | delivery/deploy_preflight/pr_publication.py | 주입된 PR 발행기 전에 정확한 수정안의 갱신 요구 |
| GitHub Checks 어댑터 | delivery/github/preflight_checks.py | 승인 권한 없이 기존 PR의 최신 커밋에 제한된 상태 게시 |
core/는 FeasibilityProbe 프로토콜만 봅니다; 프로브는
조립 루트 에서 Container.feasibility_probes
경계를 통해 주입됩니다. 상류 기본값은 프로브를 바인딩하지 않습니다(denylist는 고객 구성);
포크 또는 라이브 Azure 어댑터가 core/를 편집하지 않고 자체 구현을 등록합니다.
안전 자세
섹션 제목: “안전 자세”- 실패 시 차단 - 프로브에서 발생한 예외는 전파됩니다. 검사는 일부만 실행된 상태에서
clear를 절대 보고하지 않습니다. 차단 발견 사항은 컨트롤 플레인 액션을 게이팅되지 않은 auto-action이 아니라hil로 격하시킵니다. - 읽기 전용 - 프로브는 대상을 변경하지 않습니다. 검사는 모든 배포에서 실행해도 안전합니다.
- 멱등적 - 발견 사항은 결정론적으로 정렬되어(차단 먼저, 그 다음 id 순), 같은 입력에 대한 재실행은 바이트-동일한 리포트를 생성합니다.
- 근거 있음 - 출처 규칙을 인용하는 근거 없이는 발견 사항이 없습니다.
- 발견 피드백 - 여러 환경에 걸친 반복 차단 요인(예: 모든 범위가
docker.io차단)는 발견 루프가 새 기본 토글이나 규칙을 제안하도록 하는 신호입니다 (architecture.instructions.md § Rule 카탈로그).
전달 상태
섹션 제목: “전달 상태”배포됨: 프로브 경계, 제네릭 결정론적 프로브, 분석기와 리포트, 독립 실행형 Azure 프리플라이트 스크립트, 배포 작업 흐름의 보호된 계획 근거 연결 및 테스트.
- Azure 탐색과 protected-plan 근거(배포됨):
delivery/azure/preflight/의 공유 읽기 전용 ARM 클라이언트(AzureArmClient, 주입된httpx.AsyncClient+WorkloadIdentitybearer 토큰, 실패 시 차단)와AzurePolicyGuardrailProbe(실제 Azure Policydeny가드레일 -Not allowed/Allowed resource types),AzureQuotaProbe(구독 + 위치별 Compute 사용량)가 모의 HTTP 단위 테스트와 함께 반영됐습니다. 정책 파서는 모든 형제 조건이 정본 type-exists 가드인 경우에만 기본 제공allOf타입 제약을 허용하며, 알 수 없는 형제 조건이 있으면 계속 차단합니다. 격리된 실제 운영 검증에서 리소스 그룹 범위의 디스크 거부는disk_provisioning=attach_existing로 매핑됐고 실제 할당량 부족은 수동 차단 요인으로 남았으며, 임시 할당은 검토된 롤백으로 제거됐습니다.scripts/deployment/azure/run_live_preflight.py는 Azure CLI 워크로드 신원, 범위가 제한된 읽기 전용 ARM 전송 계층, neutral-to-ARM 타입 대응, 정제된 실패 시 차단 오류와 함께 두 탐색을 같은 analyzer에 조립합니다. 기존 Resource Graph 역할 관찰기도AzureIdentityRbacProbe를 통해 조립되어 principal 또는 role-definition id를 출력하지 않고 누락된 event-bus 및 secret-reader 실행기 역할을 보고합니다.AzureSecretConfigProbe는 상태만으로 필수 Key Vault 참조를 검사하고 응답 본문 또는 시크릿 값을 읽지 않으며 hashed 참조를 출력합니다. 보고는 clear인 경우에도 정제된 per-category 검사 커버리지를 기록합니다. 비공개 실행기는 강제 적용 모드에서 Azure category 네 개를 모두 요구하고 범위가 제한된 TLS egress 근거와 결합합니다. 정제된 보고만 비공개 Blob 저장소에 저장하고 두 근거 다이제스트를 exact-plan 검증에 연결합니다. Firewall / NSG 토폴로지 어댑터는 별도의 향후 개선 사항이며, 실행기의 직접 도달 가능성을 입증하는 데는 필요하지 않습니다. - 기능 모드 토글 scaffold(배포됨):
infra/modules/preflight-toggles/와 disk 참조 소비자가 두 렌더링을 검증합니다. 리소스 소유권과 통합은 포크 소유이므로 제네릭 상류 루트는 구체적인 소비자를 인스턴스화하지 않습니다. - 검사 발행 경계(일부 제공됨): 코어 함수, 프로바이더 프로토콜, 메모리 내 발행기, 정제된 GitHub Checks 어댑터가 있습니다. 인프라 PR 생성 후 런타임 연결은 아직 계획 단계입니다.
- 배포 환경 프로파일 새로 고침(범위가 제한된 작업으로 제공됨): 기존 메모리 내 기본 요소에 더해 공유 상태 저장소를 사용하는 전달 계층의 영속 작업이 있습니다. 복구 Inventory 변경 작업은 커서를 진행하기 전에 프로파일을 무효화합니다. 호출자는 읽기 전용 생성기를 주입하고 만료 및 재시작 복구를 포함한 새로 고침을 실행할 수 있습니다. 운영 환경의 프로파일 생성기와 스케줄러는 아직 연결되지 않았으며, 프로파일은 게시 전 최신 상태를 확인하는 게이트를 대체하지 않습니다.
- Control-loop pre-PR 게이트(일부 제공됨):
pre_publication_gate.py가 게시 직전에 누적된 오버라이드로 같은 analyzer를 다시 실행하고, 차단 발견 사항·오래된 증거·범위 변경·에스컬레이션된 재조립 등 검증되지 않은 모든 경우를 보류하여 패스를hil로 라우팅하고 아무것도 제출하지 않습니다. PR 전달 래퍼도 정확한 수정안에 묶인 근거가 무효화되면 보류합니다. 두 경계 모두 실제 실행기 경로에는 아직 연결되지 않았습니다.
- architecture.instructions.md - 컨트롤 루프, quality 게이트, 안전성 불변식
- project-structure-ko.md - 모듈 경계, 인프라 서브모듈 패턴
- risk-classification-ko.md - 차단 발견 사항이
hil로 라우팅되는 방식 - rule-catalog-collection-ko.md - 기저 가드레일 규칙의 출처
관련 문서
섹션 제목: “관련 문서”| 알아볼 내용 | 읽을 문서 |
|---|---|
| 구현 상태 및 남은 작업 | 구현 원장 |