
    Qi                         U d Z ddlZddlZddlZddlmZ ej                  j                  dd       ddlm	Z	m
Z
 dZdhZh dZg dZee   ed	<   d
edefdZdee   dee   fdZdedee   ddfdZdedee   fdZy)u  파이프라인 YAML dict 검증 모듈.

설계서 Section 3-2 기반 11개 항목 검증:
  1. schema_version 존재 + 지원 버전("1.0")
  2. gates 최소 1개 이상
  3. token_budget 존재 + 양수
  4. blast_radius 유효값("step"|"team"|"org")
  5. allowed_teams 비어있지 않음
  6. 순환 DAG 검출 (Kahn's algorithm, 자기 참조 포함)
  7. 시크릿 패턴 탐지
  8. 모든 step의 target_team이 allowed_teams 내에 존재
  9. 모든 depends_on 참조가 유효한 step id
  10. 모든 step의 task_desc가 injection_guard.check_content() 통과
  11. inject_context.source 경로가 WORKSPACE_ROOT 하위인지 검증 (path traversal 방지)

작성자: 토르 (dev2-team 백엔드 개발자)
날짜: 2026-03-24
    N)dequez/home/jay/workspace)InjectionBlockedErrorcheck_contentz1.0>   orgstepteam)zAWS_ACCESS_KEY_ID=AKIAPRIVATE_KEYz	password=zsecret=zBEGIN RSA PRIVATE KEYzAPI_KEY=_SECRET_PATTERNStextreturnc                 h    t         D ])  }t        j                  || t        j                        s) y y)uH   시크릿 패턴이 text에 포함되어 있으면 True를 반환한다.TF)r
   research
IGNORECASE)r   patterns     P/home/jay/workspace/.worktrees/task-2117-dev1/orchestrator/pipeline_validator.pyscan_secretsr   )   s-    # 99WdBMM2     stepsc                    g }| D ch c]  }d|v s|d    }}| D ]F  }|j                  dd      }|j                  dg       D ]  }||k(  s	|j                  d| d        H |r|S |D ci c]  }|d }}|D ci c]  }|g  }}| D ]Q  }|j                  dd      }|j                  dg       D ](  }||v s||   j                  |       ||xx   dz  cc<   * S t        d |j                         D              }	d}
|	rI|	j	                         }|
dz  }
||   D ])  }||xx   dz  cc<   ||   dk(  s|	j                  |       + |	rI|
t        |      k7  r|j                  d	       |S c c}w c c}w c c}w )
uW   Kahn's algorithm으로 순환 의존성을 검출한다. 에러 목록을 반환한다.id 
depends_onStep 'z-' has a self-referencing cycle in depends_on.r      c              3   2   K   | ]  \  }}|d k(  s|  yw)r   N ).0nodedegs      r   	<genexpr>zvalidate_dag.<locals>.<genexpr>K   s     RytSPQdRs   zWPipeline steps contain a circular dependency cycle (Kahn's algorithm detected a cycle).)getappendr   itemspopleftlen)r   errorssstep_idsr   siddep	in_degree	adjacencyqueuevisitedr   neighbors                r   validate_dagr1   1   s   F!&4A$!)$4H4  [hhtR 88L"- 	[Cczse+XYZ	[[  4< <Ca <I <:B&C3sBw&CI&C $hhtR 88L"- 	$Ch#%%c*#!#	$$ RIOO4ERREG
}}1!$ 	'Hh1$"a'X&	'  #h-e	
 MM 5 !=&Cs   	E-E--
E2=
E7objstringsc                     t        | t              r|j                  |        yt        | t              r"| j	                         D ]  }t        ||        yt        | t              r| D ]  }t        ||        yy)uJ   dict/list/str을 재귀 탐색하여 모든 문자열 값을 수집한다.N)
isinstancestrr#   dictvalues_collect_all_stringslist)r2   r3   vitems       r   r9   r9   ]   si    #ss	C	 	-A G,	-	C	 	0D w/	0 
r   pipelinec                    g }| j                  d      }||j                  d       n$|t        vr|j                  d| dt         d       | j                  d      }||j                  d       n/t        |t              rt        |      d	k(  r|j                  d
       | j                  d      }||j                  d       n0t        |t        t        f      r|d	k  r|j                  d|d       | j                  d      }|-|t        vr%|j                  d| dt        t               d       | j                  dg       }t        |t              rt        |      d	k(  r|j                  d       t        |t              rt        |      n	t               }| j                  dg       }|D 	ch c]  }	d|	v s|	d    }
}	g }t        | |       |D ]'  }t        |      s|j                  d|dd d        n |r|j                  t        |             |D ]  }|j                  dd      }|j                  d      }|(||vr$|j                  d| d| dt        |       d       |j                  dg       D ]  }||
vs|j                  d| d| d       ! |j                  d      }|	 t        t!        |             |j                  d!      }t        |t$              s|j                  d"d#      }d$t!        |      v r|j                  d| d%|d       t&        j(                  j+                  t&        j(                  j-                  t.        t!        |                  }|j1                  t.              ri|j                  d| d&| d'        |S c c}	w # t"        $ r#}|j                  d| d | d       Y d}~d}~ww xY w)(u`   파이프라인 YAML dict를 검증하고 에러 목록을 반환한다. 빈 리스트 = 유효.schema_versionNz'Missing required field: schema_version.zUnsupported schema_version: 'z'. Supported: .gatesz<Missing required field: gates (must have at least one gate).r   zBField gates must be a non-empty list (at least one gate required).token_budgetz%Missing required field: token_budget.z3Field token_budget must be a positive number, got: blast_radiuszInvalid blast_radius: 'z'. Allowed values: allowed_teamsz-Field allowed_teams must be a non-empty list.r   r   z:Secret pattern (secret/key) detected in pipeline content: P   z	<unknown>target_teamr   z': target_team 'z' is not in allowed_teams r   z*': depends_on references unknown step id 'z'.	task_descz+': task_desc failed injection guard check: inject_contextsourcer   z..z@': inject_context.source contains path traversal sequence '..': z': inject_context.source path 'z6' is outside WORKSPACE_ROOT (path traversal rejected).)r"   r#   _SUPPORTED_SCHEMA_VERSIONSr5   r:   r&   intfloat_VALID_BLAST_RADIUSsortedsetr9   r   extendr1   r   r6   r   r7   ospathnormpathjoinWORKSPACE_ROOT
startswith)r=   r'   r?   rA   rB   rC   rD   allowed_teams_setr   r(   r)   all_stringsr   r   r*   rF   r+   rG   excrH   rI   norms                         r   validate_pipeliner[   i   s   F \\"23N?@	9	9+N+;>JdIeefg	

 LL!E}TUt$E
aZ[ <</L=>sEl3|q7HKLK[[\]^ <</LL8K$K%l^3FvNaGbFccde	

 LL"5MmT*c-.@A.EEF.8.MM*SVSX Wb1E!&4A$!)$4H4  K;/ MMLTRUSUYMYZ[  l5)* $hht[) hh}-"{:K'KMM-k]:TU[\mUnToopq
 88L"- 	_C("se+UVYUZZ\]^	_
 HH[)	 _c)n-
 "23nd+#''"5Fs6{"SE!abhakklm ww''^S[(QR~6MM %DVH  MC  DE$L Mm 5H ) _se+VWZV[[\]^^_s$   1	N";N"5N''	O0OO)__doc__rQ   r   syscollectionsr   rR   insertutils.injection_guardr   r   rU   rJ   rM   r
   r:   r6   __annotations__boolr   r7   r1   objectr9   r[   r   r   r   <module>rd      s   & 
 	 
  ( ) F&#W -  $s) s t )T
 )tCy )X	0f 	0tCy 	0T 	0_ _c _r   