07. CLI와 설정
현재 구현 상태 (v0.46.0 / metrics v14.5.0):
scan(--set lite|full/--out/--fail-under/--json/--sarif/--strict/--quiet/--include-generated/--exclude/--only/--config),lite,full,diff,assurance verdict,assurance evidence,version,metrics,explain구현됨. Go/TS/JS/Python/Java/C#/Rust와 C/C++ 제한 지원이 동작한다. v13은 production/test/documentation/configuration/generated 역할과 카테고리×언어 eligible CLOC를 점수 계약으로 기록한다.jam.yaml은version/exclude/suppress/score.fail_under/metrics.<ID>.warning|violation|critical/arch.layers·arch.rules(ARCH-09)/full.weights(lint/spec 포함) 지원(자체 YAML 서브셋 파서 — 외부 의존성 0 유지). 인라인 억제 주석(jam:ignore <ID> -- 사유) 동작.--component에lint/spec(둘 다 opt-in) 추가. 미구현:jam init,jam languages,--lang/--csv-bom/--jobs/--verbose, 인라인 억제 건수의 HYG 집계.
1. 명령 구조
jam scan [path] # 기본은 jam-lite. path 기본값 = 현재 디렉터리
jam lite [path] # jam scan --set lite alias
jam full [path] # jam scan --set full alias
jam diff old.csv new.csv
jam assurance verdict --policy security-policy.json [--review security-review.json]
jam assurance evidence --plan control-plan.json
jam metrics # 내장 메트릭 레지스트리 출력
jam explain <metric> # 메트릭 설명·근거·임계값 출력 (예: jam explain CPLX-02)
jam version
v1 이후 후보: jam languages, jam init, jam serve(로컬 HTML 뷰어).
assurance의 입력·상태·감사 경계는 17-security-assurance.md를 따른다.
2. jam scan 플래그
| 플래그 | 기본 | 설명 | |||
|---|---|---|---|---|---|
--out DIR | . | 출력 디렉터리 (jam-report.md, jam-detail.csv, jam-run.json, 옵션 JSON/SARIF; full은 추가 산출물 생성) | |||
--config FILE | jam.yaml 자동 탐색 | 설정 파일 경로 | |||
--set lite|full | lite | 측정 세트. full은 jam-lite 뒤에 test-cli/security-cli를 호출 | |||
--fail-under N | (없음) | 현재 세트의 종합 점수 N 미만이면 exit 1 | |||
--exclude GLOB | 추가 제외 패턴 (반복 가능) | ||||
--include-generated | false | 자동 생성 파일도 분석·감사 출력에 포함. role은 generated라 production 점수에는 미산입 | |||
--json | false | jam-result.json 추가 생성 | |||
--sarif | false | jam.sarif(SARIF 2.1.0) 추가 생성 | |||
--strict | false | production source 스킵·파스 실패, analyzer 오류·config 경고·억제 정책 문제가 있으면 산출물 작성 후 exit 3. test/docs/config 전용 스킵·파스는 감사만 기록 | |||
--quiet | false | 한 줄 요약만 출력 | |||
--only CAT[,CAT] | 전체 | 특정 카테고리만 (예: --only SEC,ARCH) | |||
--component all|test|security|lint|spec | all | full 모드에서 실행할 외부 컴포넌트. all=test,security(하위호환). lint/spec은 opt-in(예: all,lint 또는 spec). 콤마 구분 | |||
--skip-test | false | full 모드에서 test-cli 생략 | |||
--skip-security | false | full 모드에서 security-cli 생략 | |||
--skip-lint | false | full 모드에서 lint 컴포넌트 생략 | |||
--test-cli PATH | 자동 탐색 | full 모드에서 사용할 test-cli 실행 파일 | |||
--test-baseline FILE | test-cli report@2 baseline 비교 | ||||
--test-history FILE | test-cli 추세/flaky 분석용 이전 report@2. 반복 가능 | ||||
--test-diff-base REF | test-cli changed-line coverage용 Git ref | ||||
--test-fail-on-regression | false | --test-baseline 비교가 회귀하면 test gate 실패 | |||
--test-fail-on-flaky | false | 최소 2개 --test-history와 현재 런에서 flaky가 확인되면 실패 | |||
--test-fail-diff-coverage PCT | changed-line coverage가 PCT 미만이면 실패. --test-diff-base 필수 | ||||
--security-cli PATH | 자동 탐색 | full 모드에서 사용할 security-cli 실행 파일 | |||
--security-profile NAME | ci | full 모드에서 security-cli에 넘길 profile | |||
--security-baseline FILE | security-cli fingerprint baseline 비교 | ||||
--security-fail-on-new | false | baseline에 없던 security finding이 있으면 실패 | |||
--security-history | false | security-cli/Gitleaks 전체 Git 이력 검사. 기본은 시간 상한이 예측 가능한 working tree 검사 | |||
--lint-cli tool=path[,...] | PATH | --component lint에서 린터 실행 파일 재정의(예: ruff=/usr/bin/ruff) | |||
--spec-cli PATH | 자동 탐색 | --component spec에서 사용할 외부 spec-cli 실행 파일 재정의 | |||
--spec-requirements PATH | spec-cli 기본 | 요구사항 문서 경로를 spec-cli에 전달 | |||
--spec-trace-baseline FILE | spec trace diagnostic suppression baseline | ||||
--spec-trace-fail-on LEVEL | spec-cli 기본 error | `none | info | warning | error` 중 trace gate 임계 |
--full-timeout DUR | 30m | full 모드 외부 컴포넌트별 타임아웃 |
콘솔에는 01-vision-and-scope.md 시나리오 A의 요약 박스만 출력. 상세는 파일로.
스캔 범위는 먼저 루트와 하위 디렉터리의 .gitignore를 적용한 뒤, 내장 기본 제외 디렉터리와 jam.yaml/--exclude 규칙을 적용한다. 기본 제외 디렉터리는 node_modules, bower_components, .pnpm-store, .yarn, .next, .nuxt, .svelte-kit, .venv, venv, env, .tox, .nox, __pycache__, __pypackages__, target, vendor, dist, build, coverage, out, .cache 등이다. 패키지 lockfile(package-lock.json, pnpm-lock.yaml, poetry.lock, go.sum 등)은 생성 파일로 기록하고 기본 분석에서는 제외한다.
분석 대상으로 발견된 파일은 다시 점수 역할로 분류된다. production만 점수의 CLOC·debt 모집단이며 test/testdata/fixture/mock, 문서, 설정, 생성 파일 finding은 CSV/SARIF에 보존하되 score_exclusion 사유와 debt_counted=0을 기록한다. 지원표 밖 언어도 unsupported_language로 같은 방식으로 보존한다. 따라서 테스트나 README를 추가해 production 점수를 희석할 수 없다. --only 밖 카테고리 finding은 unselected_category이며, 제한 점수는 동일 --only 범위끼리만 비교한다.
미구현 플래그 후보: --lang ko|en, --csv-bom, --jobs N, --verbose.
2.5 jam diff 플래그
jam diff OLD.csv NEW.csv는 두 jam-detail.csv를 finding_id 기준으로 비교해 added/fixed/unchanged finding과 counted debt 증감을 출력한다. 기본으로 각 CSV 옆의 jam-run.json을 검증하여 도구·Metrics Spec·정책·스캔 범위가 같고 두 측정이 완전할 때만 비교한다.
| 플래그 | 기본 | 설명 |
|---|---|---|
--fail-on-added | false | 새 finding이 --min-severity 이상이면 exit 1 |
--min-severity LEVEL | warning | info/warning/violation/critical |
--limit N | 20 | added/fixed 섹션별 최대 출력 건수 |
--quiet | false | 한 줄 요약만 출력 |
--allow-incompatible | false | 구버전 baseline 등 매니페스트 검증을 신중하게 우회 |
CI 예:
jam scan . --out out/new
jam diff --fail-on-added --min-severity warning out/baseline/jam-detail.csv out/new/jam-detail.csv
2.6 jam full
jam full PATH는 jam scan PATH --set full과 같다. full 모드는 다음 순서로 실행한다.
- jam-lite 스캔:
jam-report.md,jam-detail.csv,jam-run.json, 옵션 JSON/SARIF 생성. test-cli run PATH --format json --output-dir <out>/test실행. baseline/history/diff 플래그가 있으면 그대로 전달.security-cli scan PATH --profile <profile> --format json --output-dir <out>/security실행. schema 1의 scanner coverage가 complete인지 검증.--component spec이면 spec-cli를 실행하고 report/trace/summary 원자 계약을 검증.jam-full-report.md,jam-full.json생성.
부분 full 실행:
jam full . --component security # jam-lite + security-cli만 합성
jam full . --skip-test # jam-lite + security-cli만 합성
jam full . --component test # jam-lite + test-cli만 합성
jam full . --component test --test-baseline baseline/report.json --test-fail-on-regression
jam full . --component test --test-history run-1.json --test-history run-2.json --test-fail-on-flaky
jam full . --component test --test-diff-base origin/main --test-fail-diff-coverage 80
jam full . --component security --security-baseline baseline/security.json --security-fail-on-new
jam full . --component spec --spec-trace-fail-on warning
부분 full에서는 선택된 컴포넌트의 기본 가중치만 합산한 뒤 1.0으로 재정규화한다. 예를 들어 --component security는 jam-lite 0.50, security 0.25를 0.667/0.333으로 재정규화한다.
외부 도구 탐색 순서:
--test-cli/--security-cli/--spec-cli- PATH
- 개발 환경 fallback:
~/git/test-cli,~/git/security-cli,~/git/cli/security-cli,~/git/spec-cli
3. jam.yaml 설정 파일
원칙: 설정 없이도 잘 동작(convention over configuration). 현재 설정은 제외/억제 규칙, fail-under 게이트, 레지스트리 기반 jam-lite 메트릭 임계값 오버라이드, jam-full 컴포넌트/하위 지표 조정용이다.
version: 1
# 수백 개 저장소에 동일한 --config 파일을 배포할 때의 정책 식별자.
# 실제 전체 설정 SHA-256도 jam-run.json에 함께 기록되므로
# ID/version을 바꾸지 않고 내용만 변경해도 비교 불일치가 검출된다.
policy:
id: engineering/portfolio
version: "3"
# 분석 범위
exclude:
- "vendor/**"
- "**/*_test.go" # 분석·감사 출력에서도 테스트를 완전히 제외하려는 경우
score:
fail_under: 70 # CLI --fail-under와 동일, CLI가 우선
# 메트릭별 임계값 오버라이드. warning/violation/critical 중 필요한 것만 지정.
# 레지스트리에 숫자 임계값이 있는 메트릭(SIZE-01, CPLX-01, ARCH-03 등)에 적용.
metrics:
CPLX-01:
warning: 12
violation: 20
critical: 35
SIZE-01:
warning: 800
violation: 1500
# 프로젝트 프로파일 (opt-in): "application"일 때만 SIZE-05(사변적 일반화) 측정.
# 라이브러리 공개 API 오탐 방지를 위해 기본은 미측정.
profile: application
# 변경 이력 지표 (CPLX-06, CHURN-01..04, opt-in — git 저장소 + 아래 설정 필요.
# 이력은 환경 의존적이라 모두 info 등급·점수 미산입)
churn:
enabled: true
# 아키텍처 레이어 규칙 (ARCH-09, opt-in — 선언 없으면 미측정)
arch:
layers:
domain:
- "internal/domain/**"
infra:
- "internal/infra/**"
- "internal/db/**"
rules:
- deny: domain -> infra
reason: "도메인 계층은 인프라 세부구현을 몰라야 함(DIP)"
# jam-full 컴포넌트/하위 지표 override
full:
weights:
jam-lite: 0.45
test: 0.30
security: 0.25
lint: 0.15
spec: 0.15
metrics:
TEST-DENSITY:
weight: 0.18
cap: 80
TEST-SOURCE-COV:
weight: 0.12
cap: 90
SEC-TOOLCHAIN:
weight: 0.20
SEC-CVSS:
floor: 20
# 개별 finding 억제 (false positive 관리)
suppress:
- finding: SEC-01-f01c44aa # finding_id로 지정 (안정적 해시)
reason: "테스트용 더미 키" # reason 필수 — 억제도 감사 가능해야 함
owner: security-team
ticket: SEC-42
expires: 2026-12-31
- metric: RES-02
path: "src/legacy/**"
reason: "v2에서 재작성 예정"
설정 해석 규칙
- 우선순위: CLI 플래그 >
jam.yaml> 내장 기본값. exclude와--exclude는.gitignore스타일 glob을 사용한다./로 시작하면 스캔 루트 기준,/가 없으면 basename 기준으로 어느 깊이에서나 매칭된다.suppress된 finding은 CSV에 남고 원본severity/message를 보존하며debt_counted=0이 된다. 억제 source/reason/owner/ticket/expires는 별도 컬럼과 SARIF suppression으로 기록된다.expires는YYYY-MM-DD. 만료된 규칙은 finding을 숨기지 않고integrity=incomplete를 만든다. reason 미기재 규칙/인라인 억제도 같이 사용 실패로 기록된다.- 포트폴리오 표준 스캔은 중앙 정책 파일을 배포하고 모든 저장소에서
jam scan --config /path/to/portfolio-jam.yaml --strict ...를 사용한다.jam-run.jsonpolicy/configuration/comparison hash로 로컬 변조와 CLI 범위 차이를 검출한다. - 알 수 없는 최상위 키와
score하위 키는 경고 후 무시(버전 간 호환). 단, 경고는 런 매니페스트를incomplete로 만들고--strict에서 exit 3을 반환하여 중앙 정책의 오타를 묵인하지 않는다. metrics하위의 알 수 없는 metric ID, 알 수 없는 threshold 키, 숫자가 아닌 값은 설정 오류(exit 2)로 처리한다. 잘못 쓴 품질 게이트가 조용히 통과하지 않게 하기 위함이다.full.weights.jam-lite/test/security/lint/spec는 jam-full 컴포넌트 기본 가중치 override이며, 선택된 component set은 합 1.0으로 재정규화한다.full.metrics.<ID>.weight는 jam-full 하위 지표 가중치 override다.floor/cap은 하위 지표 점수 하한/상한 override이며 0~100 정수만 허용한다.arch.layers는 레이어 이름 → glob 패턴 목록(선언 순서가 매핑 동률 시 우선순위).arch.rules는- deny: from -> to항목 목록으로reason을 권장하며(없으면 경고), 존재하지 않는 레이어를 참조하는 규칙은 경고 후 무시된다. 둘 다 선언하지 않으면 ARCH-09는 평가되지 않는다(기존 프로젝트 점수 불변).- 아직 지원하지 않는 설정 후보: score grade caps/TDR,
generated패턴, DUP 최소 토큰, 메트릭별 enable/disable.
인라인 억제 주석
소스 주석으로도 억제 가능 (린터 관례 준수):
db.Query(q) // jam:ignore SEC-02 -- 내부 고정 쿼리
-- 사유 부분이 없으면 경고와 suppression issue를 남기고 --strict에서 exit 3으로 처리한다.
4. 콘솔 UX
- 현재 콘솔은 ASCII 요약 박스와 산출물 경로를 출력한다.
- 후속 후보: 파일 수 기반 진행률, 색상(NO_COLOR 존중), 더 자세한 해결 힌트.
5. 종료 코드
| code | 의미 |
|---|---|
| 0 | 측정 성공, 품질 게이트 통과 |
| 1 | 품질 게이트 실패 또는 assurance fail/gap·열린 예외 |
| 2 | 명령/설정/스캔/리포트 작성 실패 |
| 3 | scan --strict 또는 assurance에서 불완전 측정/증거 |
| 4 | full 모드 외부 컴포넌트 측정 불가 |
production 코드가 없어 jam-lite가 N/A인 실행은 --fail-under를 통과할 수 없으며 exit 1을 반환한다. 숫자 0/F로 해석하지 않고 not_assessed 상태를 산출물에 유지한다.