본문으로 건너뛰기

Pipeline Studio 코드 노드 QA 가이드 — Python · Shell

이 문서는 Pipeline Studio 코드 노드(Python/Shell)를 QA가 화면에서 직접 따라 검증할 수 있도록 단계별 스크린샷과 함께 정리한 것입니다. 모든 화면은 실제 GenD 환경의 데모 워크스페이스에서 캡처했습니다.

개요

코드 노드는 워크스페이스에서 작성한 사용자 코드(Python transform 함수 또는 Shell 스크립트)를 적재 파이프라인의 한 단계로 실행합니다. 코드는 격리 러너(gend-codexec) 안에서만 돌고, 그 러너는 네트워크 차단 · 시크릿 없음 · 자원 상한(시간/메모리) 으로 봉인돼 있습니다.

Phase 1 범위(이 가이드 대상) — "순수 변환": 상위 노드가 준 데이터(text/chunks/metadata 등)를 받아 변환해 돌려줍니다.

  • ✅ Python 표준 라이브러리(json/re/math/datetime…) 사용
  • ✅ 배포 전 드라이런으로 샘플 입력에 대해 즉시 테스트
  • ❌ 네트워크 호출 · 외부 시크릿/DB/S3 접근 · pip install — (후속 Phase. 지금은 차단됨)

권한 (업데이트됨, #2106 P1): 인라인 코드 노드의 직접 배포는 여전히 관리자(admin) 만 가능합니다(일반 멤버는 배포 시 403). 단, 워크스페이스 멤버도 이제 코드 드라이런과 재사용 스텝 제출(승인 대기)이 가능하고, 워크스페이스 admin(/tenants/<slug>/admins)이 승인한 library_ref 스텝만으로 구성한 파이프라인은 멤버도 배포할 수 있습니다. 페르소나별 전체 흐름은 비-admin 코드 작성 QA 가이드 참조.


1. Python 코드 노드 — 작성 & 드라이런

1-1. 코드 노드 추가

파이프라인 스튜디오 빌더 좌측 노드 팔레트Python 코드 / Shell 코드 가 있습니다. 캔버스로 끌어다 놓습니다.

팔레트의 Python/Shell 코드 노드

1-2. 코드 작성

노드를 클릭하면 우측 설정 패널에 코드 에디터가 열립니다. Python은 transform(input: dict) -> dict 함수를 정의합니다. 타임아웃(초) · 메모리(MB) · 샘플 입력(드라이런용 JSON) 도 함께 설정합니다.

Python 코드 노드 설정 패널

1-3. ✅ 드라이런(배포 전 테스트)

▶ 드라이런 버튼을 누르면 샘플 입력으로 코드를 격리 러너에서 즉시 실행하고 결과를 보여줍니다. status: ok · output: {...} · metrics(소요시간/메모리) 가 표시됩니다.

Python 드라이런 성공 — status ok + output

확인 포인트(QA): 입력({})에 transform이 더한 키(marker)가 output에 보이면 정상입니다. 배포 없이 여기서 코드를 검증할 수 있습니다.


2. ✅ 엣지: 보안 가드 — 위험 코드 거부

Python 코드는 배포·드라이런 시 정적 보안 검사(L1) 를 통과해야 합니다. import socket/subprocess/os/eval 등 네트워크·시스템 접근은 거부됩니다.

import socket 을 넣고 드라이런하면 python 코드 정책 위반 [import] line N: socket 토스트가 뜨고 러너에 도달하지 않습니다(작성 단계에서 차단).

import socket → 정책 위반 거부

확인 포인트(QA): 금지 모듈/호출이 줄 번호와 함께 거부되는지, 그리고 거부 시 실행이 일어나지 않는지 확인하세요.

Python vs Shell — 정적 게이트 비대칭 (보안 운영자 주의)

Python 코드는 배포·드라이런 전에 정적 보안 검사(L1 AST) 를 통과해야 합니다(socket/subprocess/os/eval/open 등 금지). Shell 코드는 이에 상응하는 정적 게이트가 없습니다sh 스크립트를 정적으로 안전 판정할 등가물이 없기 때문입니다. 따라서 Shell 의 안전성은 전적으로 런타임 샌드박스 경계(egress 차단 NetworkPolicy · 시크릿 env 0 · 전용 노드풀 podMaxPids PID 캡 · CPU/메모리/시간 자원 상한)에 의존합니다. 둘 다 격리 러너 안에서만 실행되어 호스트/클러스터에 닿지 못하지만, "작성 단계 거부"는 Python 에만 적용된다는 점을 운영 시 인지하세요.


3. Shell 코드 노드

Shell 노드는 stdin 으로 입력 JSON 을 받아 stdout 으로 출력 JSON 을 내보내는 스크립트입니다(jq/coreutils 사용 가능). 예: cat(그대로 통과), jq '.chunks |= map(ascii_upcase)'.

Shell 코드 드라이런 성공

확인 포인트(QA): Shell 은 정적 보안 검사 등가물이 없어 샌드박스 경계(네트워크 0·시크릿 0·자원 상한) 에만 의존합니다(설계상 의도). 출력은 반드시 JSON 한 줄이어야 합니다.


4. ✅ 엣지: 타임아웃

무한 루프·장시간·과도한 자원 사용 코드는 자원 상한(CPU·시간·메모리) 에서 강제 종료되어 status: error 로 끝납니다. 예: timeout=2while True: pass → CPU 상한 초과로 execution killed (signal …; CPU/메모리/시간 자원 상한 초과). (블로킹 대기는 wall-clock 초과 시 execution timeout.) 참고로 import time 같은 비허용 모듈은 실행 이전에 L1 보안 검사에서 먼저 거부됩니다.

타임아웃 → status error

확인 포인트(QA): 무한 루프/장시간 코드가 파이프라인을 멈추지 않고 타임아웃으로 끊기는지 확인하세요. (메모리 초과·과도한 출력도 같은 방식으로 status: error.)


5. 풀 파이프라인에 코드 노드 넣고 실행

코드 노드는 그래프 어디든 끼울 수 있습니다(통과형). 예: 소스 → 파싱 → Python 코드 → 청킹 → 임베딩 → 벡터 적재. 코드 노드는 상위 데이터를 받아 변환한 뒤 그대로 하위로 흘려보냅니다.

코드 노드를 포함한 6노드 그래프

저장 → 배포 → 실행 하면 코드 노드가 실제 적재 실행 안에서 격리 러너로 돌고, 모든 노드가 성공(초록)으로 끝납니다.

풀 파이프라인 실행 — 코드 노드 포함 전 노드 성공

확인 포인트(QA): 코드 노드(Python 코드)를 포함해 6개 노드가 모두 초록(성공)이면, 사용자 코드가 실제 파이프라인 런에서 격리 실행된 것입니다.


6. 출력 유형 선언 (output_type) — 변환 체인에 끼워넣기

코드 노드는 기본적으로 pass-through(입력 유형을 그대로 전달)라, rest_source(records) 뒤에 붙여도 다음 노드에는 여전히 records 로 보입니다 — 그래서 청킹(text 요구) 같은 노드에 연결할 수 없었습니다. 고급 설정 → "출력 유형" 을 선언하면 이 제약이 풀립니다.

선언출력 JSON 계약이어지는 노드 예
records{"records": [ {...}, ... ]}싱크 (Intel Bronze + MCP)
text{"text": "..."}청킹
chunks{"chunks": ["...", ...]}임베딩 / 벡터 적재

예 — 법제처 본문을 커스텀 노드로 시맨틱 인덱싱 체인에 넣기:

rest_source(상세 fan-out) → Python(output_type=text) → 청킹 → 임베딩 → 벡터 적재
def transform(input):
# 목록 레코드들의 본문(detail)을 하나의 텍스트로 합쳐 청킹에 넘긴다
parts = []
for r in input.get("records", []):
d = r.get("detail") or {}
parts.append(str(d.get("조문", "")))
return {"text": "\n\n".join(parts)}

2026-07-23 prod 실측 — 아래 화면은 실제 prod 에서 이 체인을 구성·실행한 것입니다 (법제처 목록+본문 fan-out → Python 조문 추출 → 청킹 → 임베딩 → Weaviate 7개 벡터 적재 확인).

고급 설정의 "출력 유형" 드롭다운:

코드 노드 고급 설정 — 출력 유형 드롭다운(records/text/chunks)

완성된 체인 — rest_source → Python(출력 유형=text) → 청킹 → 임베딩 → 벡터 적재. 선언 전에는 Python→청킹 연결이 거부되지만, 선언 후에는 드래그로 연결됩니다:

커스텀 노드 변환 체인 캔버스 + 출력 유형=text 설정 패널

실행 성공 (모든 노드 ok):

실행 탭 — 커스텀 체인 run 성공

동작 규칙:

  • 선언하면 검증기가 그 유형으로 다음 노드 연결을 허용합니다. 상류 토큰(records 등)은 실행기의 병합 전달({...upstream, ...출력}) 그대로 계속 흐릅니다.
  • 실행 시 실제 출력이 선언과 다르면 노드가 즉시 실패합니다(예: output_type=text 인데 출력에 text 문자열 키가 없음). 선언 노드가 선언하지 않은 상류 키를 덮어쓰는 것도 실패 처리됩니다 — 빈 입력/오염으로 다운스트림이 조용히 잘못 성공하는 것을 막는 가드입니다.
  • 커스텀 전처리(내 서비스 호출) 노드도 동일하게 지원 — 응답 매핑으로 선언 키를 만들고 출력 유형을 선언하면 됩니다.
실측에서 확인된 주의 2가지
  1. 배포 권한: 인라인 코드 노드가 있는 그래프는 기존 정책(#2462)대로 관리자 배포가 필요합니다(버튼 툴팁으로 안내됨). 승인된 라이브러리 스텝으로 바꾸면 analyst 도 직접 배포할 수 있습니다.
  2. 대용량 텍스트 주의: 본문 전체를 그대로 text 로 내보내면 청크가 수백 개로 불어나 임베딩 호출이 타임아웃될 수 있습니다(실측: 법령 3건 조문 전체 → embed 타임아웃). 추출 단계에서 필요한 범위로 잘라 내보내거나 임베딩 노드의 타임아웃을 조정하세요.

QA 체크리스트 요약

#시나리오기대 결과
1Python transform 드라이런status: ok + output 에 변환 결과
2import socket 드라이런정책 위반 토스트(줄번호), 실행 안 됨
3Shell cat 드라이런status: ok
4time.sleep > 타임아웃status: error / execution timeout
5코드 노드 포함 파이프라인 실행전 노드 성공(초록)
6일반 멤버(비admin)가 코드 노드 배포403 차단(관리자 전용)

#6(비admin 차단)은 관리자 계정이 아닌 별도 멤버 계정으로 배포를 시도해 확인합니다(API/단위 테스트로도 검증됨).


알아두기 (Phase 1 제약)

  • 네트워크 0 · 시크릿 0: 코드에서 외부 호출·DB·S3·환경변수 시크릿에 접근할 수 없습니다(러너가 봉인). 외부 연동이 필요하면 커스텀 전처리 — 내 서비스 호출(http_api) 노드를 쓰세요.
  • Python = 표준 라이브러리만(Phase 1). 임의 pip 패키지는 후속 Phase.
  • Shell 정적검사 없음: 위 격리 경계에만 의존(설계 명시).
  • 자원 상한: 노드별 타임아웃/메모리 설정값이 강제됩니다(플랫폼 상한 내).