feat(vuln): code-vuln 연속 스캔 production rollout (JSONL-first, catalog 구동)#64
Conversation
…able 보류) vuln/SAST 연속 스캔 production rollout 준비. PR #59 substrate(JSONL-grain) 위에 JSONL 스케줄 아티팩트 잡으로 먼저 가고 durable SCAN_JOB/SCAN_LEDGER 통합은 human-gated H-track로 연기(storage-projection / secret-default 게이트 회피). - deploy/systemd/user/security-scanner-personal-vuln-{scan,freshness-eval}.{service,timer}: secret unit mirror, JSONL backend(DYNAMO_* 없음), oneshot, securityscanner.slice, scan 일1회 03:30 / eval 6h. 전부 "DRAFT, not for enable" 헤더. - tests/test_vuln_rollout_systemd_units.py: unit 구조 검증(real semgrep 불필요). - docs/adr/20260621-vuln-continuous-scanning-rollout.md: 결정 + 승격 트리거 + durable seam. - docs/runbooks/vuln-rollout-enable-checklist.md: 단일-owner enable 순서/롤백/abort. proof: pytest systemd 47 + vuln/parity/governance 232 passed (semgrep 없이). NOT enabled: 호스트 checkout 66aa165(main보다 뒤), semgrep 미설치, deploy/** allowed_writes 밖 → production enable은 단일-owner 후속 작업. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
draft unit이 참조하던 미존재 CLI를 실제 구현해 production enable 차단 요인 해소. - runtime/vulnerability_scan.py: run_catalog_vulnerability_scan — INCLUDED 카탈로그 read-only 반복, repo별 per-scan_run_id no-clobber JSONL 아티팩트, repo 단위 fetch/scan 오류 격리, semgrep preflight(binary-missing ≠ scanned-clean). - runtime/vulnerability_freshness.py: run_vuln_freshness_eval — 아티팩트 walk + 카탈로그 INCLUDED 집합으로 per-repo recency/coverage gap(테이블 write 없음, report-only). - cli/commands/vulnerability.py: scan-vuln --from-catalog/--artifact-dir 등 + vuln-freshness-eval 서브커맨드. exit 0/2/3(clean/error/preflight-fail). - deploy/systemd/user vuln-scan·freshness-eval.service: ExecStart를 실제 CLI에 맞춤, 카탈로그 read 위해 jsonl override 제거(EnvironmentFile의 dynamo 설정 사용). - tests: catalog scan/freshness/CLI 동작 테스트 추가, unit 테스트 갱신. proof: uv run pytest 1354 passed/4 skipped; fake-semgrep end-to-end로 SARIF→JSONL (redaction 적용) 1 finding 생성; preflight binary-missing 구분 확인. real semgrep·live dynamo 불필요. durable 스키마/secret seam/host 무변경. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 코드 미존재 경고 → 구현 완료(83ede4b, 1354 passed) 반영. - 호스트 실상태 반영: branch codex/ragflow-continuous-idle-freshness @8ed5b9e, 미푸시 커밋 2개(8ed5b9e/b8f6b69) → checkout 전진 전 push/merge 보존 단계 추가. - canonical remote=github(source-security-dev, main=ec98702), host origin=stale 번들 명시. - units가 jsonl-only라는 오기 정정: findings는 --artifact-dir JSONL이나 카탈로그 read는 dynamo(read-only) 필요, jsonl backend override 없음. - precondition --help 플래그를 실제 CLI에 맞춤(scan은 --notification-log 없음, freshness에 있음). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request implements a catalog-driven continuous vulnerability scanning plane (Phases 1 and 2) as a scheduled JSONL artifact job, introducing systemd service/timer units, CLI subcommands, runtime scanning and freshness evaluation logic, and comprehensive tests. The feedback recommends improving the robustness of the catalog scan by catching general exceptions in _scan_one_catalog_repo to prevent a single repository failure from aborting the entire run. Additionally, it is suggested to expand tilde paths in resolve_semgrep_binary to support user-home paths and to add a type hint to the result parameter in _append_freshness_notification.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
gemini-code-assist 리뷰 3건 반영.
- runtime/vulnerability_scan.py(HIGH): _scan_one_catalog_repo가 SemgrepExecutionError
외 예외(clobber ValueError, import/SARIF 오류 등)를 잡지 못해 전체 카탈로그 루프가
중단될 수 있던 문제 수정. clobber 체크를 try 안으로 옮기고 일반 Exception을
per-repo scan-error로 격리("a single repo's failure never aborts the whole pass" 충족).
- runtime/vulnerability_scan.py(MED): resolve_semgrep_binary가 ~ 경로를 처리하도록
Path(binary).expanduser() 적용.
- cli/commands/vulnerability.py(MED): _append_freshness_notification result 인자에
VulnFreshnessResult 타입힌트 + import 추가.
- tests: no-clobber/일반예외가 raise 대신 격리된 scan-error로 보고되는지 검증으로 갱신·추가.
proof: uv run pytest 1356 passed/4 skipped; ruff clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ollowup fix(vuln): PR #64 리뷰 후속 — per-repo 격리 강화 + expanduser + 타입힌트
목적
PR #59 vuln substrate(M1~M3) 위에 code-vuln/SAST 연속 스캔 production 경로를 추가한다. ADR 결정 = JSONL-first(스케줄 아티팩트), durable SCAN_JOB/SCAN_LEDGER 통합은 human-gated H-track로 연기(storage-projection / secret-default 게이트 회피).
변경
runtime/vulnerability_scan.py:run_catalog_vulnerability_scan— INCLUDED 카탈로그 read-only 반복, repo별 per-scan_run_id no-clobber JSONL 아티팩트, repo 단위 fetch/scan 오류 격리, semgrep preflight(binary-missing ≠ scanned-clean).runtime/vulnerability_freshness.py:run_vuln_freshness_eval— 아티팩트 walk + 카탈로그 INCLUDED 집합으로 per-repo recency/coverage gap (테이블 write 없음, report-only).cli/commands/vulnerability.py:scan-vuln --from-catalog/--artifact-dir/...+vuln-freshness-eval서브커맨드. exit 0/2/3(clean/error/preflight-fail).deploy/systemd/user/*vuln-*: 연속 스캔 user units(secret units mirror). rollout draft — 자동 enable 대상 아님.docs/adr/...,docs/runbooks/vuln-rollout-enable-checklist.md: 결정 + 단일-owner enable 체크리스트(turnkey).검증
uv run pytest→ 1355 passed, 4 skipped.범위/안전
security_scanner_personal에 write 안 함(카탈로그 read-only만).deploy/**는 autopilot allowed_writes 밖 → autopilot auto-merge 게이트에서 막히는 게 정상(의도된 단일-owner 리뷰).