Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions deploy/systemd/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,38 @@ for the full schema.

---

## 5b. Optional: verifier auto-triage (Ollama)

`scan-all` can run the Ollama verifier after scanning and record terminal
finding dispositions (false_positive / true_positive). This is **DEFAULT-OFF**
and **trigger-agnostic** — it rides whatever runs `scan-all` (this timer, cron,
or a manual run), so it needs no systemd-specific wiring. Enable it purely via
environment variables:

| Env var | Meaning |
| --- | --- |
| `SECURITY_SCANNER_VERIFY_ARTIFACTS` | `1`/`true`/`yes`/`on` enables verification; unset/`0`/`false` keeps it off. |
| `SECURITY_SCANNER_OLLAMA_HOST` | Ollama-compatible host, e.g. `http://127.0.0.1:11434`. |
| `SECURITY_SCANNER_OLLAMA_MODEL` | Model name. |
| `SECURITY_SCANNER_OLLAMA_TIMEOUT_SECONDS` | Optional HTTP timeout (default 30). |
| `SECURITY_SCANNER_OLLAMA_MIN_CONFIDENCE` | Optional min confidence (default 0.60). |
Comment thread
pureliture marked this conversation as resolved.
| `SECURITY_SCANNER_OLLAMA_API_KEY_ENV` | Optional: name of the env var holding the API key (the token itself stays in that separate env var, never inline). |

Notes:

- The verifier reads only redacted metadata; raw secrets never leave the host.
- It **fails closed**: if Ollama is unreachable or low-confidence, the finding is
left `needs_review` (no disposition written) and the scan still records all
findings — verification never destructively fails a scan. A verifier failure
surfaces only as exit code `2` (alertable; see §6).
- The CLI flag `--verify-artifacts` / `--no-verify-artifacts` overrides the env
default for one-off runs.
- This is a full-sweep triage: newly detected findings are verified on the next
`scan-all` run. Per-change verification in the incremental `scan-worker` path is
out of scope here (separate follow-up).

---

## 6. Exit code semantics for alerting

The service uses `SuccessExitStatus=0 3`, so systemd treats exit codes `0` and
Expand Down
180 changes: 180 additions & 0 deletions docs/workbench/specs/verifier-periodic-wiring/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# design.md — 주기 scan 경로에 Ollama verifier 자동 triage 배선 (FEATURE #3)

> **정정 (실행 중 scope 보정, 사용자 피드백):** 이 repo는 PR/webhook 트리거가 없다(코드에 없음). 변화 감지는 poll(`discover-updates` ls-remote → `SCAN_JOB` → `scan-worker`)이고 systemd는 그걸 주기 실행하는 스케줄러일 뿐이다. 따라서 본 feature의 핵심은 systemd 템플릿 편집이 아니라 **트리거-무관 env-gate**(`SECURITY_SCANNER_VERIFY_ARTIFACTS`)로 scan-all 검증을 켜는 것이다. systemd `.service` 편집은 범위에서 제외하고(어떤 스케줄러로 돌리든 동일), 활성화 절차는 `deploy/systemd/README.md`에 env 표로만 둔다. verification은 full-sweep triage(새 finding은 다음 scan-all에서 검증); 증분 `scan-worker` 즉시검증은 무거운 별도 후속으로 남긴다.


## 1. 개요

`scan-all` 런타임은 이미 `--verify-artifacts` 설정 시 verifier를 실행하고 terminal
disposition을 기록한다. 남은 격차는 주기 실행(systemd)이 이를 켜지 않는다는 점뿐이다.
본 설계는 (1) 기존 verify 플래그를 env-var 기본값으로 노출하고, (2) verifier-enabled
systemd 템플릿 변형과 README를 추가해, 주기 실행이 **public-safe / env-gated /
DEFAULT-OFF / local-first**로 자동 triage를 켜도록 한다. Ollama 다운은 런타임의
fail-closed(=needs_review) 계약 그대로 비파괴 처리된다. 신규 런타임 동작·게이트는 없다.

## 2. 요구사항 참조

- FR-1~FR-6, NFR-1~NFR-5, AC-1~AC-6 (requirements.md).
- 핵심: env→argparse-default 흡수(FR-1/FR-2/FR-4), systemd 템플릿/README(FR-5/FR-6),
fail-closed 비파괴(NFR-2), DEFAULT-OFF(FR-1).

## 3. 접근 후보와 선택

### 후보 A — env-var 기본값화 + verifier-enabled systemd 변형 (선택)
- `--verify-artifacts`에 `SECURITY_SCANNER_VERIFY_ARTIFACTS` truthy 게이트를 default로 흡수.
- host/model/timeout/min-confidence/config는 이미 `resolve_verifier_config`가 env로 읽음.
- systemd는 env만 설정(EnvironmentFile=- 또는 주석 Environment=)하고 기본은 off 유지.
- 장점: 런타임 신규 코드 최소, 기존 `SECURITY_SCANNER_STORAGE_BACKEND` 컨벤션과 정합,
CLI/systemd 양쪽에서 동일하게 동작, DEFAULT-OFF 자연 보장.
- 단점: boolean env 파싱 헬퍼 1개 신설 필요(선례 없음).

### 후보 B — verifier 전용 systemd 템플릿 파일(별도 .service)만 추가
- env는 손대지 않고, `--verify-artifacts ...`를 inline한 두 번째 `.service` 추가.
- 장점: 런타임 코드 0 변경.
- 단점: CLI에서는 여전히 매번 플래그 수동 입력, env-convention 불일치, 템플릿 수 2배,
inline 플래그에 host/model이 노출되어 운영자 편집 부담. FR-2(명시 플래그 없이 env로 on)
미충족.

### 후보 C — governance gate 신설
- 런타임에 검증 활성화 정책 게이트를 도입.
- 단점: main에 governance 런타임 모듈 부재 → 신규 기계, design 제외(no gating)와 충돌,
YAGNI 위반. **배제.**

**선택: 후보 A.** 런타임 변경을 boolean env 헬퍼 1개로 최소화하면서 CLI·systemd 양쪽에
일관된 env-gated 활성화를 제공하고 DEFAULT-OFF/fail-closed를 그대로 유지한다.

## 4. 아키텍처

```
[systemd .service]
Environment= / EnvironmentFile=- (SECURITY_SCANNER_VERIFY_ARTIFACTS=1,
ExecStart: uv run security-scanner scan-all OLLAMA_HOST/MODEL ...)
|
v
[cli/_args.add_scan_all_verifier_args] (신규/확장)
--verify-artifacts default <- _env_truthy(SECURITY_SCANNER_VERIFY_ARTIFACTS)
--ollama-host/... default <- None (resolve 단계에서 env fallback)
|
v
[cli/commands/scan.cmd_scan_all] (변경 없음)
verifier_config_factory=_scan_all_verifier_config_from_args(args)
|
v
[runtime/scan_all.run_scan_all] (변경 없음)
resolve verifier_config -> per-finding verify -> record disposition
transport 실패 -> needs_review (fail-closed) -> exit 2, 비파괴
|
v
[runtime/verify_artifact.resolve_verifier_config] (변경 없음)
SECURITY_SCANNER_OLLAMA_HOST/MODEL/TIMEOUT_SECONDS/MIN_CONFIDENCE/API_KEY_ENV
```

검증을 켜는 권한은 **env**가 가지고, systemd 템플릿은 그 env를 설정하는 얇은 표면이다.
런타임 로직(`scan_all.py`, `verify_artifact.py`, `client.py`)은 손대지 않는다.

## 5. 구성요소

### 5.1 `cli/_args.py` (또는 `cli/commands/scan.py`) — env-default 흡수
- 신규 모듈 헬퍼 `_env_truthy(value: str | None) -> bool`: 주어진 문자열 값이
`{"1","true","yes","on"}`(strip+소문자화)이면 True, 미설정/빈/그 외는 False. 호출부에서
`os.environ.get(...)`를 넘긴다(헬퍼는 env를 직접 읽지 않아 테스트가 쉽다). (NFR-5: 최소 헬퍼)
- `--verify-artifacts`를 `action=argparse.BooleanOptionalAction`로 두고
`default=_env_truthy(os.environ.get("SECURITY_SCANNER_VERIFY_ARTIFACTS"))`로 설정.
BooleanOptionalAction은 `--verify-artifacts`/`--no-verify-artifacts` 양방향 override를
주므로 env-on 상태에서도 `--no-verify-artifacts`로 끌 수 있다(FR-4 양방향 충족).
- host/model/timeout/min-confidence/config 플래그는 default=None 유지(이미 resolve 단계가
env fallback). 단 README/help에 env 이름을 문서화.
- 배치 위치: `add_storage_args`가 env를 흡수하는 것과 동일하게, scan-all 파서를 구성하는
곳에 두어 컨벤션 일관성 확보(NFR-4).

### 5.2 `deploy/systemd/security-scanner-scan-all.service` (system-level)
- 기본 `ExecStart`는 현행 유지(검증 off).
- 추가:
- `EnvironmentFile=-/etc/security-scanner/verifier.env` (검증 env 주입 지점, optional)
- 주석 블록: 검증 켜기 = `Environment=SECURITY_SCANNER_VERIFY_ARTIFACTS=1`,
`Environment=SECURITY_SCANNER_OLLAMA_HOST=http://127.0.0.1:11434`,
`Environment=SECURITY_SCANNER_OLLAMA_MODEL=<model>` 또는 대안 ExecStart
`... scan-all --verify-artifacts --ollama-host ... --ollama-model ...`.
- api_key는 `Environment=SECURITY_SCANNER_OLLAMA_API_KEY_ENV=OLLAMA_API_KEY`처럼
**이름만** 노출하고 실제 토큰은 verifier.env/별도 env로.

### 5.3 `deploy/systemd/user/security-scanner-scan-all.service` (user-level)
- 동일 패턴을 `%h` 기준으로: `EnvironmentFile=-%h/.config/security-scanner/verifier.env`
+ 주석 Environment= 예시. 검증 기본 off.

### 5.4 `deploy/systemd/README.md`
- 신규 절: "Enable verifier triage (optional)".
- env 표:

| Env | 의미 | 기본값 |
| --- | --- | --- |
| `SECURITY_SCANNER_VERIFY_ARTIFACTS` | 주기 실행에서 verifier 켜기(truthy) | off |
| `SECURITY_SCANNER_OLLAMA_HOST` | Ollama 호환 endpoint | (없음, on이면 필수) |
| `SECURITY_SCANNER_OLLAMA_MODEL` | 모델 이름 | (없음, on이면 필수) |
| `SECURITY_SCANNER_OLLAMA_TIMEOUT_SECONDS` | HTTP timeout | 30.0 |
| `SECURITY_SCANNER_OLLAMA_MIN_CONFIDENCE` | fail-closed 임계 | 0.60 |
| `SECURITY_SCANNER_OLLAMA_API_KEY_ENV` | 토큰을 읽을 env '이름' | (없음) |

- fail-closed 설명: Ollama/verifier 다운 시 모든 해당 finding은 needs_review로 떨어지고
disposition은 쓰이지 않으며 scan은 finding/summary를 정상 기록한다. exit code 2(alertable)만
발생하고 파괴적 실패는 없다.
- exit code 표에 "검증 실패 포함 시 2" 명시(기존 표 재사용).
- 로컬 Ollama 전제, public-safe placeholder만 노출, 토큰은 EnvironmentFile로.

## 6. 데이터 흐름

1. timer → `.service` 활성화 → systemd가 env(또는 EnvironmentFile) 로드.
2. `uv run security-scanner scan-all` 실행 → 파서가
`SECURITY_SCANNER_VERIFY_ARTIFACTS`를 읽어 `args.verify_artifacts` 결정.
3. on이면 `_scan_all_verifier_config_from_args`가 `resolve_verifier_config` 호출 →
host/model/timeout/min_confidence/api_key_env를 env에서 채움.
4. `run_scan_all`이 fetch→scan→finding마다 `verifier.verify`→terminal verdict면
`record_verifier_disposition`로 disposition 기록.
5. transport 실패면 `needs_review`(비파괴) + public-safe failure 항목 → exit 2.
6. notification log summary에 `verification` 요약(attempted/terminal/needs_review/
dispositions_written/failed/failures) 기록.

## 7. 에러 처리

- Ollama 다운/timeout/HTTP 오류: `OllamaChatVerifier.verify`가 `needs_review`로 변환
(fail-closed). disposition 미기록, finding/summary 정상 기록, exit 2. (NFR-2)
- 검증 on인데 host/model 미해결: `resolve_verifier_config`가 `ValueError` →
`run_scan_all`이 `verifier_config_failure`(exit 2)로 public-safe 보고. raw 경로/디테일은
`_public_safe_exception`으로 클래스명만 노출.
- disposition store 미가용/비-writer: 기존 `_verifier_store_unavailable_summary` /
writer-unavailable 분기로 public-safe failure 처리(변경 없음).
- truthy env 오기입(`maybe`, `2` 등): `_env_truthy`가 False로 해석 → 안전하게 off.
README에 허용 값 명시.

## 8. 테스트 전략

- 단위(`tests/test_cli_scan_all.py` 확장):
- `_env_truthy` 케이스 테이블(`1/true/TRUE/yes/on` → True; 미설정/빈/`0/false/no/off/maybe`
→ False).
- env-on → verifier 호출됨 + disposition 기록(monkeypatch.setenv
`SECURITY_SCANNER_VERIFY_ARTIFACTS`, `..._OLLAMA_HOST/MODEL`, OllamaChatVerifier 패치).
- 명시 `--verify-artifacts` 미지정 + env-off → verifier 미호출(기존
`test_scan_all_default_does_not_call_verifier` 유지/보강, AC-1).
- env-on + Ollama 다운(transport가 예외) → exit 2, finding/summary 기록, 모든 해당 finding
needs_review(AC-3, NFR-2). 기존 `..._surfaces_public_safe_failures` 패턴 재사용.
- env-on + host 미설정 → `verifier_config_failure` exit 2(AC-5). 기존
`..._verifier_config_failure_writes_fatal_and_summary` 패턴 재사용.
- 플래그 우선순위: env-off인데 `--verify-artifacts` 명시 → on(AC-4).
- 문서 검증(수동/lint): 두 `.service`와 README가 raw secret/토큰을 포함하지 않고 env 표/
fail-closed/exit 2를 포함(AC-6).

## 9. 마일스톤

- M1: `_env_truthy` 헬퍼 + `--verify-artifacts` env-default 흡수 + 단위 테스트(AC-1/2/4).
- M2: fail-closed/exit 2/config-failure 회귀 테스트 정리(AC-3/5).
- M3: system/user `.service` 템플릿에 검증 env 주석/EnvironmentFile 추가(AC-6).
- M4: README 검증 절(env 표·fail-closed·exit 2·로컬 Ollama·시크릿 취급) 추가(AC-6).

## 10. 열린 질문

- `disposition_store_factory`와 `store_factory`가 같은 DynamoDB store를 두 번 생성하는
현행 동작이 주기 실행에서 연결 비용을 키우는가? 본 feature 범위 밖이며 별도 최적화 후보로 둔다.
- truthy env 허용 토큰 집합을 다른 향후 boolean env(있다면)와 공유할지 — 현재는 단일 사용처라
로컬 헬퍼로 충분(YAGNI). 사용처가 늘면 공용화 검토.
- 검증을 켠 주기 실행의 Ollama 호출 부하 상한을 timer 빈도/`timeout_seconds` 외에 추가로 둘지 —
현재는 문서 경고로 충분, 신규 동시성/배치 제어는 범위 밖.
Loading
Loading