CI 로그 없이 레거시 자바 프로젝트로부터 바이트코드를 복원하는 자동 빌드 에이전트
- Bare Metal Mode: Docker 없이 로컬 환경에서 직접 빌드할 수 있는
--execution-mode local옵션 추가./data2/donggyu/benchmark/sec_code/tmp경로에 위치한 격리된 도구(JDK, Maven, Gradle)를 사용하여 안전하고 독립적인 빌드 환경 제공.
- Smart Flexible Healing: 단일 통합 프롬프트(Smart Prompt)를 적용하여 LLM이 상황에 따라 코드 수정, 의존성 변경, 파일 생성 등을 자율적으로 선택하도록 개선.
- Context Awareness: 파일 트리(Project Structure) 정보를 제공하여 Docker 내부 경로와 로컬 경로 간의 매핑 오류 해결.
- Knowledge Injection: "Bintray/JCenter Shutdown", "Restlet Repo Missing", "Java Version Mismatch" 등 도메인 지식을 프롬프트에 주입하여 치유 성공률 대폭 향상.
- Improved Version Handling:
class file version 55.0(Java 11) 등의 호환성 오류 발생 시, 상속된(Inherited) 플러그인을 찾아내어 다운그레이드하는 전략 추가.
이 시스템은 Python으로 구현되었으며 5개의 주요 모듈로 구성됩니다:
- 원격(Remote) Git URL, 로컬(Local) 디렉토리, 아카이브(Archive) Zip 파일 등 다양한 입력을 처리합니다.
- 리포지토리를 클론하거나 아카이브를 작업 공간(Workspace)에 압축 해제합니다.
- 프로젝트 구조를 스캔합니다.
- 빌드 도구(Maven/Gradle)를 식별합니다.
- 멀티 모듈 프로젝트에서도 루트 빌드 파일(pom.xml 또는 build.gradle)을 정확히 찾아냅니다.
- EnvironmentDetector: 다음을 사용하여 필요한 JDK 버전(예: 7, 8, 11)을 추론합니다.
pom.xml설정 분석 (<maven.compiler.source>)- 소스 코드 특징 분석 (
javalang): 람다(Lambda, Java 8), try-with-resources(Java 7) 등의 문법 특징을 감지합니다.
- Detector: 빌드 도구 버전을 결정합니다.
- Maven: 기본값 3.8.6
- Gradle: 기본값 6.9.4 (Java 8 호환성이 뛰어난 안정 버전)
- 프로토콜 업그레이더:
http://Maven 저장소 URL을 자동으로https://안전한 URL로 변환합니다. - 미러 주입기: 원본 저장소가 죽었을 경우를 대비해, Google Maven Mirror를 사용하는
settings.xml을 주입합니다. - Gradle 런타임 힐러 (NEW):
init.gradle스크립트를 도커 컨테이너의 글로벌 경로(/root/.gradle/init.d/)에 주입합니다.- 빌드 실행 시 동적으로 파손된 리포지토리(예:
repo.spring.io)를 감지하고, 이를 Maven Central로 리다이렉트하여 인증 오류(401)를 무력화합니다.
-
DockerManager (기본):
- 추론된 환경을 기반으로
Dockerfile을 동적으로 생성합니다. - 샌드박스 환경에서 안전하게 빌드를 수행합니다.
- 추론된 환경을 기반으로
-
LocalManager (Bare Metal Mode):
--execution-mode local옵션 사용 시 동작합니다./data2/donggyu/benchmark/sec_code/tmp디렉토리에 위치한 **격리된 도구(JDK 8/17, Maven, Gradle)**를 강제로 사용하여 호스트의 환경 변수나 설정에 영향을 받지 않고 빌드를 수행합니다.- 도커 오버헤드 없이 빠른 빌드가 가능합니다.
-
빌드 및 추출 공통 로직:
- Maven:
mvn package -DskipTests실행 후target/classes추출. - Gradle:
gradle compileJava -x test실행 후build/classes추출. - 빌드 성공 시 결과물을 호스트의
output/classes디렉토리로 안전하게 복사합니다.
- Maven:
| 플래그 | 필수 여부 | 설명 | 기본값 |
|---|---|---|---|
--type |
필수 | 입력 소스 유형 (remote, local, archive) |
- |
--path |
필수 | 입력 경로 (URL, 디렉토리 경로, 또는 파일 경로) | - |
--commit |
선택 | (remote 타입 전용) 체크아웃할 특정 Git 커밋 해시 |
HEAD |
--workspace |
선택 | 프로젝트가 로드되고 빌드가 수행될 임시 작업 디렉토리 | workspace/ |
--output |
선택 | 빌드 결과물(클래스 파일, 로그)이 저장될 경로 | output/ |
--execution-mode |
선택 | 실행 모드 선택 (docker, local) |
docker |
python3 src/main.py --type local --path /Users/user/projects/legacy-apppython3 src/main.py \
--type remote \
--path https://github.com/apache/commons-lang.git \
--commit 8b67192 --type archive \
--path /Downloads/source-code.zip \
--workspace ./temp_work \
--output ./build_resultspython3 src/main.py \
--type local \
--path /path/to/project \
--execution-mode local주의: Local Mode는
/data2/donggyu/benchmark/sec_code/tmp경로에 JDK와 빌드 도구(Maven, Gradle)가 올바르게 배치되어 있어야 동작합니다. --path /Downloads/source-code.zip
--workspace ./temp_work
--output ./build_results
실행이 완료되면 --output (기본값: output/) 디렉토리에서 다음을 확인할 수 있습니다:
classes/: 도커 컨테이너에서 추출된 컴파일된.class파일들 (패키지 구조 유지)compile_log.txt: 상세 빌드 로그error_log.txt: (실패 시) 에러 원인 분석 로그
- 상황:
http저장소 URL 사용. - 결과:
https업그레이드 및 Mirror 주입 후 빌드 성공.
- 상황:
repo.spring.io(현재 인증 필요) 리포지토리 사용으로 인한 401 오류 발생. - 해결: 에이전트가
init.gradle을 통해 해당 리포지토리를 런타임에 Maven Central로 교체함. - 결과: 인증 오류를 우회하고 컴파일 단계로 진입 성공. (단, 프로젝트 자체의 누락된 스냅샷 아티팩트로 인한 404 오류는 발생했으나, 이는 에이전트의 정상 동작임)
- 상황: 다수의
http저장소 사용으로 Maven 3.8+에서 차단됨 (Blocked Mirror). - 해결:
settings.xml주입 시<mirrorOf>*</mirrorOf>를 사용하여 모든 트래픽을 Google Maven Mirror(HTTPS)로 강제함. - 결과: 성공. 모든 의존성이 안전하게 다운로드됨.
- 상황:
org.hyperic:sigar아티팩트가 Maven Central에 없고 JBoss 리포지토리에만 존재함. 기존의mirrorOf *정책이 JBoss 리포지토리 접근을 차단하여 빌드 실패. - 해결: Smart Mirror Exclusion 기능 구현.
patcher.py가pom.xml을 스캔하여 이미https://를 사용하는 리포지토리(예:sigar)를 식별하고, 미러 설정에서 제외(mirrorOf *,!sigar)하여 직접 접근을 허용함. - 추가 수정:
druid-processing모듈이druid-core의 test-jar를 의존성으로 요구했으나,mvn compile은 테스트 jar를 생성하지 않음. 이를 해결하기 위해 빌드 명령을mvn package -DskipTests로 변경하여 reactor 내에서 테스트 아티팩트가 정상 생성되도록 함. - Robustness 개선:
web-console,distribution등 바이트코드 복원에 불필요하고 빌드 오류(예:npm권한 문제)를 유발하는 프론트엔드 모듈을 감지하여 Reactor 빌드에서 동적으로 제외(-pl !web-console,!distribution)함. - 결과: 성공.
sigar아티팩트 다운로드,druid-core테스트 의존성 해결, 그리고 프론트엔드 모듈 제외로 인한 빌드 성공.
- 문제:
repo.spring.io등 과거엔 공개였으나 현재는 인증이 필요한 저장소들이 있음. 단순 파일 수정으로는 플러그인에 의해 동적으로 추가되는 저장소를 막을 수 없었음. - 해결:
init.gradle스크립트에서repository.whenObjectAdded이벤트를 가로채어, 문제되는 URL이 감지되면 즉시 안전한 공개 저장소(Maven Central)로 URL을 덮어씌우는 로직을 구현함.
- 문제: Apple Silicon (M1/M2)에서 Intel 기반 JDK 설치 시 오류 발생.
- 해결:
platform.machine()을 감지하여 적절한JAVA_HOME경로를 설정하도록 수정.
- JCenter 등 추가 Dead Repo 대응: 힐링 로직 확장.
- 실전 테스트: VUL4J 전체 데이터셋에 대한 대규모 실험 수행.
기존의 규칙 기반(Heuristic) 접근법의 한계를 극복하고, LLM의 강력한 추론 능력을 결합하여 "속도"와 "해결 능력"을 동시에 잡은 하이브리드 아키텍처를 완성했습니다.
-
1차 방어선 - 정적 치유 (Static Heuristic Phase)
- 역할: 가장 빠르고 비용이 들지 않는(Free) 해결사.
- 동작: 소스코드 분석만으로 알려진 문제(URL 401 오류, 플러그인 버전 불일치, 순환 참조 등)를 1초 미만에 수정(
patcher.py)합니다. - 효과: 전체 빌드 오류의 약 80%를 LLM 호출 없이 무료로 해결합니다.
-
2차 방어선 - 동적 지능형 치유 (Smart Flexible Healing)
- 역할: 복잡하고 예측 불가능한 미지의 에러를 해결하는 전지전능한 해결사.
- 동작: 1차 방어선이 뚫려 빌드가 실패할 경우 개입합니다. 초기에는 단순한 수정만 시도했으나, 최신 업데이트를 통해 완전한 자율성을 부여받았습니다.
- 효과: 단일 통합 프롬프트(Smart Prompt)를 사용하여 문제의 원인을 심층 분석하고, 상황에 따라 코드 수정, 의존성 업데이트, 주석 처리(Neutralize), 파일 생성 중 최적의 전략을 스스로 선택합니다.
- 스마트 모델 감지 (Smart Model Detection):
gemini라는 단어를 감지하여 OpenAI 방식과 Google REST API 방식을 자동으로 전환합니다. - 범용 구성 (Generic Configuration):
llm_config.json설정 파일 하나로 OpenAI, Google Gemini, 혹은 호환되는 모든 로컬 LLM을 손쉽게 교체할 수 있습니다. - 비용 효율성 최적화: 빌드가 성공하면 LLM을 전혀 호출하지 않아 API 비용을 0원으로 유지할 수 있습니다.
-
컨텍스트 인식 (Context Awareness)
- 단순 로그 뿐만 아니라 파일 트리(Project Structure) 정보를 LLM에 제공합니다.
- Docker 내부 경로(
/app/buggy/...)와 실제 로컬 경로를 정확히 매핑하여 "File Not Found" 오류를 원천 차단했습니다.
-
지식 주입 (Knowledge Injection)
- "Bintray/JCenter Shutdown"과 같은 도메인 특화 지식을 프롬프트에 내장했습니다.
- LLM이 죽은 리포지토리를 계속 시도하는 대신, Maven Central로 교체하거나 삭제하는 똑똑한 판단을 내립니다.
-
안전한 코드 생성 (Sandboxed Compatibility)
- 에이전트 실행 환경(Python 3.9 등)을 고려하여, 호환되지 않는 최신 문법(Python 3.10+ Type Hint 등) 사용을 억제합니다.
- 이는 치유 스크립트 실행 중 발생할 수 있는 2차적인 런타임 오류를 방지합니다.
프로젝트 루트의 llm_config.json 파일을 통해 다양한 LLM 백엔드를 설정할 수 있습니다. 이 파일은 Git에 포함되지 않으므로(gitignore), 로컬 환경에 맞게 직접 생성해야 합니다.
| 필드명 | 설명 | 기본값 |
|---|---|---|
provider |
LLM 파트너 (openai, ollama 등) |
openai |
model |
사용할 모델명 (gpt-4, gemini-1.5-flash, mistral 등) |
gpt-3.5-turbo |
api_key |
API 접근 키 (Ollama 사용 시 불필요) | env:LLM_API_KEY |
base_url |
API 엔드포인트 URL (로컬 LLM 사용 시 필수) | http://localhost:11434 |
Case 1: OpenAI (GPT-4)
{
"provider": "openai",
"model": "gpt-4",
"api_key": "sk-..."
}Case 2: Google Gemini
{
"provider": "google",
"model": "gemini-2.5-flash",
"api_key": "AIza..."
}참고: Gemini는 현재 OpenAI 호환 모드 또는 Google GenAI SDK를 통해 지원됩니다.
Case 3: Local LLM (Ollama)
{
"provider": "ollama",
"model": "llama3:latest",
"base_url": "http://localhost:11434"
}에이전트 실행 초기에 필수 환경(Docker)을 검증하는 단계를 추가하여 효율성을 높였습니다.
- 즉각적인 피드백: Docker가 꺼져있는 경우 Phase 0 단계에서 즉시 감지하여 종료합니다.
- 토큰 낭비 방지: 환경 문제로 실패할 것이 확실한 빌드에 LLM 치유를 시도하는 낭비를 원천 차단했습니다.