Reference

14. JAM Full E2E 평가 리포트

test-cli/security-cli를 붙인 full E2E 결과, toolchain 실패와 보안 보완 효과

Source: docs/14-jam-full-e2e-evaluation.md

14. JAM Full E2E 평가 리포트

0. v0.40.0 / Metrics v14 재검증 (2026-07-15)

아래 §1~§7은 v0.10.6 당시의 역사적 기준선이다. 2026-07-15에는 같은 fixed-SHA 16개 코퍼스를 test-cli v0.3.0·security-cli v0.3.0·spec-cli v0.2.0과 v0.40.0 릴리즈 후보로 다시 측정했다. 원본을 수정하지 않은 .git 제외 복사본에서 full 점수를 비교하고, 별도로 .git을 보존한 복사본에서 security-only 성능을 검증했다. companion의 공개 릴리즈 바이너리로 최종 smoke를 반복해 동일 계약을 확인했다.

이번 재검증에서 반영한 수정:

실행 예:

SECURITY_CLI_HOME=/tmp/security-cli-home \
  jam full "$project" \
    --out "/tmp/jam-v14-improved-results/$(basename "$project")" \
    --json --sarif --quiet \
    --test-cli /tmp/test-cli-improved \
    --security-cli /tmp/security-cli-improved \
    --full-timeout 600s

0.1 결과와 이전 v0.40 pre-fix 비교

샘플이전 Full공개 릴리스 Fullscore 상태decisionTestSecurity
c-how2heap-stress51/D51/Dfinalfailfailed/no evidencefailed
c-linenoise-best61/D62/Dfinalfailfailed/no evidenceok
cpp-fmt-best91/A69/Cfinalfailfailed/no evidenceok
cpp-fuzzer-test-suite-stress50/D47/Fprovisionalincompletefailed/no evidencefailed
cs-dvcsharp-stress49/F44/Fprovisionalincompleteerrorfailed
cs-stateless-best85/B87/Bprovisionalincompleteerrorok
go-cleanhttp-best91/A92/Afinalpassokok
govwa-stress48/F48/Fprovisionalincompleteerrorfailed
java-dvja-stress51/D51/Dprovisionalincompleteerrorfailed
java-gs-rest-best67/C67/Cprovisionalincompletefailed/no evidenceerror (Maven 429)
js-nodegoat-stress50/D50/Dprovisionalincompleteerrorfailed
py-itsdangerous-best49/F49/Ffinalfailfailedfailed
py-pygoat-stress46/F46/Fprovisionalincompleteerrorfailed
rust-hyperfine-best83/B85/Bfinalpass102/102, quality 87/Bok
rust-rustlings-stress86/B81/Bfinalpass13/13, quality 62/Dok
ts-is-best89/B91/Aprovisionalincompleteerrorok

최종 열은 GitHub에 공개된 세 companion의 Linux amd64 자산을 내려받아 SHA256SUMS를 검증한 뒤 측정했다. test-cli v0.3.0(f4e0cf1), security-cli v0.3.0(3c70df3), spec-cli v0.2.0(726ca1a)을 사용했고, security-cli v0.3.0 자체로 격리 설치한 Trivy 0.72.0·Gitleaks 8.30.1·OSV-Scanner 2.4.0과 fresh DB를 사용했다. 같은 공개 바이너리를 522시간 stale DB 환경에서 실행하면 SEC-TOOLCHAIN=40/failed로 내려가 go-cleanhttp-best가 84/B가 됐다. 이는 환경 차이를 조용히 숨기는 점수 변동이 아니라 freshness gate가 의도대로 작동한 결과다.

spec 공개 바이너리는 REQ-CALC-001을 참조하는 통과 Go 테스트 fixture로 별도 통합 smoke를 수행했다. JAM은 spec-report.json·spec-trace.json·spec-summary.json 세 파일을 모두 보존하고 Functional (external) 100, SPEC-TRACE-GATE 100/ok, 최종 100/A·decision=pass로 판정했다.

계약·완전성 변화:

항목pre-fix수정 후
exit 0 / 1 / 41 / 4 / 113 / 4 / 9
실제 test/report.json2/164/16
실제 security report16/1616/16
decision-grade (usable=true)구분 불가7/16
Gitleaks 범위 증적없음worktree 16/16
전체 순차 실행시간약 112초85초

이전 schema v1은 미측정 test를 합성에서 제외한 A/B 숫자도 최종 점수처럼 보였다. 예를 들어 cpp-fmt-best의 91/A와 ts-is-best의 89/B는 test evidence가 없었다. schema v2는 전자는 명시적인 no-test 품질 실패 68/C로, 후자는 89/B 잠정값(usable=false)으로 구분한다. Rust 두 샘플은 nextest JUnit 복구로 실제 테스트 수와 canonical quality가 합성되어 모두 최종 pass가 됐다.

진단 숫자만 놓고 보면 8개 언어군 모두 best 샘플이 대응 stress 샘플보다 높았다(8/8). 평균은 best 75.3, stress 52.3으로 23.0점 차이다. 다만 incomplete 9개는 포트폴리오 순위에 사용할 수 없으므로 이 값은 방향성 점검일 뿐 독립 타당화 결과가 아니다.

0.2 Git 이력 성능과 범위

.git을 보존한 16개 복사본에서 security-only를 실행했을 때 Gitleaks working-tree 실행은 16/16 성공했고 합계 5.712초(최대 0.673초)였다. pre-fix의 암묵적 history 실행은 결과가 남은 13개만 합계 2,547.343초(최대 362.515초)였다. 즉 기본 adapter 시간은 비교 가능한 결과 기준 400배 이상 줄었고 저장소 이력 크기에 좌우되던 fleet tail을 제거했다.

--security-history smoke test는 scanners[].mode=history를 기록하며 정상 pass했다. 따라서 일상 포트폴리오 측정과 전체 이력 secret 감사를 의도적으로 분리할 수 있다.

0.3 남은 해석 한계

평가일: 2026-06-11 · 도구: jam v0.10.6 · Metrics Spec: v2.3.4 · 지표 세트: jam-full

이 문서는 13-e2e-sample-evaluation.md의 16개 샘플 코퍼스에 test-clisecurity-cli를 붙여 실행한 full E2E 결과다. 원본 샘플 저장소는 수정하지 않고 /tmp/jam-e2e-samples-v106-toolchain 복사본에서 테스트/빌드 산출물을 만들었다.

1. 실행 환경

설치·준비한 toolchain:

실행:

go build -o /tmp/jam-toolchain-v106 ./cmd/jam
go build -o /tmp/test-cli-jam-full /home/vtopia/git/test-cli/cmd/test-cli
go build -o /tmp/security-cli-jam-full /home/vtopia/git/security-cli/cmd/security-cli

SECURITY_CLI_HOME=/tmp/security-cli-tools-jam-full \
  /tmp/security-cli-jam-full tools update-db

rsync -a --delete --exclude='.git' --exclude='node_modules' \
  --exclude='target' --exclude='.pytest_cache' --exclude='coverage' \
  /home/vtopia/git/samples/ /tmp/jam-e2e-samples-v106-toolchain/

for project in /tmp/jam-e2e-samples-v106-toolchain/*; do
  PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH" \
  NODE_PATH="$(npm root -g)" \
  SECURITY_CLI_HOME=/tmp/security-cli-tools-jam-full \
    /tmp/jam-toolchain-v106 full "$project" \
      --quiet \
      --json \
      --sarif \
      --test-cli /tmp/test-cli-jam-full \
      --security-cli /tmp/security-cli-jam-full \
      --full-timeout 600s \
      --out "/tmp/jam-full-samples-v106-toolchain/$(basename "$project")"
done

2. 종합 결과

샘플exitFullLiteTestTest statusSecuritySecurity status
go-cleanhttp-best083/B10062ok70ok
govwa-stress149/F970ok0failed
ts-is-best175/C990failed100ok
js-nodegoat-stress148/F960failed0failed
py-itsdangerous-best150/D990failed0failed
py-pygoat-stress149/F980ok0failed
java-gs-rest-best450/D1000failed0error
java-dvja-stress450/D1000failed0error
cs-stateless-best174/C970failed100ok
cs-dvcsharp-stress158/D980failed37failed
rust-hyperfine-best081/B9660ok70ok
rust-rustlings-stress077/C9420ok100ok
c-linenoise-best171/C920failed100ok
c-how2heap-stress160/D970failed45failed
cpp-fmt-best174/C980failed100ok
cpp-fuzzer-test-suite-stress167/C980failed70failed

해석:

산출물 생성률:

3. Security 결과

샘플FindingsPolicy failuresCriticalHighMediumLowCategory
go-cleanhttp-best20000200sca:20
govwa-stress1265051201iac:2, sca:124
ts-is-best000000-
js-nodegoat-stress262155271289314iac:1, sca:260, secret:1
py-itsdangerous-best22505152sca:22
py-pygoat-stress1959721768414iac:8, sca:185, secret:2
java-gs-rest-best------Maven Central 429
java-dvja-stress------Maven Central 429
cs-stateless-best000000-
cs-dvcsharp-stress12101101iac:3, secret:9
rust-hyperfine-best600060sca:6
rust-rustlings-stress000000-
c-linenoise-best000000-
c-how2heap-stress740412iac:7
cpp-fmt-best000000-
cpp-fuzzer-test-suite-stress110100secret:1

검증된 점:

4. Test 결과

test-cli는 16개 중 6개에서 report를 생성했다.

샘플Test status요약
go-cleanhttp-bestokGo test 7개, 라인 커버리지 41.1%
govwa-stressok테스트 0개, 라인 커버리지 0.0%
py-pygoat-stressok테스트 0개, 라인 커버리지 0.0%
rust-hyperfine-bestok테스트 count는 0으로 집계, 라인 커버리지 92.7%
rust-rustlings-stressok테스트 count는 0으로 집계, 라인 커버리지 31.4%
py-itsdangerous-bestfailed5개 collection error: project package/dev dependency 미설치
C/C++ 샘플failedtest-cli 지원 언어 범위 밖이거나 테스트 artifact 없음
ts-is-bestfailedJest가 현재 소스/transform 설정으로 실행 실패, 산출물 총량 0
js-nodegoat-stressfailedJest가 test 없는 config 파일을 suite로 수집, 산출물 총량 0
Java 샘플failed루트가 multi-project 예제 구조라 기본 mvn test jacoco:report로 산출물 없음
C# 샘플failedcs-stateless-best는 루트 solution의 net10 예제가 .NET 8 SDK와 불일치, cs-dvcsharp-stress는 test artifact 없음

v0.10.6에서 test-cli가 정상 실행 후 "no test results or coverage were produced"를 반환하는 경우를 infrastructure error가 아니라 test component quality failure로 분류한다. 따라서 C/C++처럼 테스트 증거가 없는 프로젝트도 full 리포트는 완성되고 exit 1로 게이트된다. timeout, 실행 파일 없음, JSON 파싱 실패, security report 미생성은 계속 exit 4 인프라 실패다.

5. Java 보안 오류

Java 두 샘플은 security report를 생성하지 못했다. 원인은 Trivy가 Maven dependency metadata를 가져오는 중 Maven Central 429를 받은 것이다.

대표 오류:

remote Maven repository returned 429 Too Many Requests for https://repo.maven.apache.org/...
The repository blocks all subsequent requests from this IP until the block clears.
To avoid this, populate the local Maven cache before scanning.

이는 JAM 문제가 아니라 외부 SCA 스캐너의 네트워크/레포지토리 제한이다. CI에서는 ~/.m2 캐시를 준비하거나, 보안 스캔을 lockfile/offline DB 중심으로 제한해야 안정적이다.

6. 개선 반영

이번 full E2E로 다음을 반영했다.

7. 다음 작업

  1. Java SCA 안정화: Maven cache 사전 준비 또는 security-cli에 offline/lockfile-only profile 추가.
  2. test-cli 개선: project dependency bootstrap, empty JUnit <testsuites> 처리, Rust nextest JUnit export, C/C++ artifact ingest 경로 보강.
  3. C# full 측정: .NET 10 SDK 설치 경로 또는 solution/test-project 선택 옵션을 test-cli config로 제공.
  4. full E2E CI: security-only job과 test-enabled job을 분리하고, toolchain image를 캐시한다.