Jenkins config.xml을 API로 올릴 때는 Content-Type에 charset=UTF-8을 붙인다
잡 설정에 한글이 들어 있으면 charset 없는 POST가 500과 「Invalid XML character」로 실패합니다. application/xml; charset=UTF-8로 보내고 --data-binary로 파일을 그대로 올립니다.
잡 설정을 코드로 관리하면서 POST /job/<잡>/config.xml로 설정을 올리면, 어떤 잡은 잘 바뀌고 어떤 잡은 500으로 실패합니다. Jenkins 로그에는 Invalid XML character (Unicode: 0x8c) 같은 줄이 남습니다. 실패하는 잡을 보면 설명·파라미터 설명·셸 단계 주석 어딘가에 한글이 들어 있습니다.
원인은 요청의 문자 인코딩입니다. 파일은 UTF-8로 저장돼 있지만 Content-Type: application/xml만 보내고 charset을 빼면, 받는 쪽이 본문을 UTF-8이 아닌 다른 인코딩으로 읽을 수 있습니다. 그러면 한글 한 글자를 이루는 3바이트가 따로따로 글자로 풀리고, 그중 XML에 쓸 수 없는 제어 문자(0x80~0x9F 구간)가 나오는 순간 파싱이 실패합니다. 영문만 있는 잡은 어느 인코딩으로 읽어도 같아서 문제가 드러나지 않습니다.
해법은 헤더에 charset=UTF-8을 명시하는 것입니다. 함께 챙길 것이 두 가지 있습니다. 첫째, 파일은 -d가 아니라 --data-binary로 보냅니다. -d는 줄바꿈을 지워 셸 단계 스크립트를 한 줄로 뭉갭니다. 둘째, 인증은 API 토큰으로 합니다. 비밀번호·세션 쿠키로 보낼 때는 CSRF crumb을 먼저 받아 헤더와 쿠키를 같이 실어야 합니다.
curl -fsS -X POST \
-u "$JENKINS_USER:$JENKINS_API_TOKEN" \
-H 'Content-Type: application/xml; charset=UTF-8' \
--data-binary @config.xml \
"$JENKINS_URL/job/example-job/config.xml"
올린 뒤에는 같은 주소를 GET으로 받아 원본과 비교하면, 한글이 깨지지 않고 그대로 들어갔는지 바로 확인할 수 있습니다.