You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

69 lines
10 KiB

# tera-logd 의사결정 질문서 구현 대조
**후속 사용자 결정 반영:** 원문 저장 유지(D-01), 관리자 보존기간 변경 허용(D-02), 포트 운영자에게 허용 포트 조회·다운로드만 허용(D-10), 공장초기화 전체 삭제 유지(D-11)가 승인됐습니다. 아래 표는 결정 이전의 질문서 대비 차이 기록이며, 현재 웹 구현은 WEB_LOG_FEATURES.md를 참조하세요.
2026-09-08 · 대상: 2026-07-24 질문서와 현재 tera_Clone_Demo 소스
**판정: 질문서의 권고 기준을 모두 충족하지 않는다.** 질문서에는 선택·승인란이 비어 있다. 권고안을 확정 요구사항으로 간주하지 않았으며, 실제 코드에서 확인한 일치·차이와 시험 증거 부족을 구분했다. 첨부 원문은 수정하지 않았다.
공장초기화는 이후 사용자의 명시 지시인 **기존 데이터 삭제, 기본 계정 terauser/terauser만 재생성**이 우선한다. 질문서 D-11의 로그 보존을 되살리면 최신 지시를 위반한다. 초기화·부팅 이후 새로 발생하는 감사 로그는 생성된다.
## 우선 확인할 차이
1. **원문 저장(D-01)**: 시리얼 RX/TX payload를 base64로 실제 저장한다. metadata-only 권고와 다르며, base64는 암호화가 아니다. `backend/cmd/tera-seriald/main.go:267`의 `recordPayload`, `backend/internal/adapters/mock/store.go`의 `RawUARTPayloadCapture: true`로 확인했다.
2. **365일 보장(D-02, D-13)**: 기본값은 365일이나 API가 1~365일 변경을 허용한다. 용량 부족 시 system/port의 오래된 세그먼트를 기간 만료 전에도 회수할 수 있다. `logstorage.ensureCapacityLocked`, `reclaimOldestLocked`, `validateRetentionDays`가 근거다. 기본값 365일은 최소 365일 보장과 다르다.
3. **쓰기 정책(D-05)**: `logstorage.Store.Append`는 각 레코드에 `file.Sync()`를 호출한다. 질문서의 일반 레코드 배치 원칙과 다르다. 또한 `recordAuditEventLocked`가 `persistAuditLogLocked`의 오류를 무시하므로 모든 변경 명령에 durable audit 성공을 보장한다고 할 수 없다.
4. **검색 인덱스(D-14)**: 실제 인덱스는 `index/log-index-v1.json`이다. 재구축 가능한 인덱스와 checksummed segment는 구현됐으나 질문서의 SQLite WAL 구조와 다르다.
5. **납품 검증(D-21~23)**: 이번 확인 범위에는 승인된 48채널 장기 부하·실제 전원 차단·eMMC 수명 측정 결과가 없다. 호스트 테스트 통과로 이를 대신할 수 없다.
## 23개 항목 대조
| ID | 항목 | 판정 및 확인 내용 |
|---|---|---|
| D-01 | Port Log 원문 | 불일치. RX/TX 원문 저장 기능이 켜진 기본 프로파일과 payload 저장 경로가 있다. metadata-only로 바꿀지는 별도 제품 결정 사항이다. |
| D-02 | 365일 보존 | 불일치. 기본 365일, 설정 범위 1~365일. system/port 용량 회수는 보호기간 고정 보장이 아니다. |
| D-03 | 이벤트율·집계 | 부분 구현. seriald 보고 주기 기본 10초가 있으나 payload는 별도 이벤트로 기록한다. 승인된 events/sec·48채널 용량 산정은 확인하지 못했다. |
| D-04 | 저장 암호화·삭제 | 권고의 제한적 logical wipe 방향과 일부 일치. 로그 JSONL은 평문이며 파일 삭제가 forensic erase를 보장하지 않는다. 보안 책임자 승인 기록은 없다. |
| D-05 | 전원 장애 손실 | 차이 있음. 레코드마다 Sync하며 일반 batching이 아니다. audit 저장 실패를 호출자에게 강제 전파하지 않는 경로가 있다. 실제 power-cut 손실 한계는 미검증이다. |
| D-06 | 분류·schema | 부분 구현. audit/system/port/link, version/sequence/UTC/checksum과 크기 제한 존재. 원문 필드가 포함되며 최종 승인 catalog·migration 계약은 미확인이다. |
| D-07 | 포트별 로그 설정 | 부분 구현. per-port/bulk Read/Send 및 capture 설정과 세션·감사 기록 경로가 존재한다. 모든 설정 조합에서 필수 감사 이벤트가 유지되는지는 별도 시험이 필요하다. |
| D-08 | keyword | 부분 구현. 대소문자를 무시한 literal match와 rule ID가 있다. 원문 저장이 별도로 존재하여 metadata-only 저장 목표를 충족하지 않는다. 청크 경계·장기 부하 기준은 미검증이다. |
| D-09 | 시각·보정 | 부분 구현 및 이번 개선. UTC와 클래스별 증가 sequence가 있다. 첫 time.sync 권한 사용자 로그인 때 PC 시간 자동 적용, 변경 전후 감사 메시지, 이후 세션 발급을 추가했다. trusted-time retention 및 역행·미동기화 전체 정책은 별도 검증 대상이다. |
| D-10 | 권한 | 부분 구현. log.export 등 서버 권한 검사가 존재한다. system/port clear 기능도 있으므로 질문서의 wipe 전용 역할·일반 관리자 삭제 금지 기준과 별도 대조가 필요하다. |
| D-11 | 공장초기화 | 최신 지시에 따라 의도적으로 다름. 예전 로그·인덱스 등 초기화 대상 데이터를 삭제하고 기본 계정만 재생성한다. 질문서 로그 보존은 현재 기준으로 채택하지 않는다. |
| D-12 | cap·floor | 구현 존재. logd가 공통 capacity policy의 클래스 cap과 free-space floor를 사용한다. 실제 이벤트율·365일·업데이트 동시 사용 용량 보장 근거는 부족하다. |
| D-13 | pressure·회수 | 불일치 부분 존재. cap/floor와 오류는 있으나 system/port의 보호기간 이전 회수 경로 및 audit 오류 무시 경로가 있어 권고한 보존·fail-closed 보장과 다르다. |
| D-14 | segment·index | 일부 일치. 4 MiB 기본 segment, 체크섬, 회전, 잘린 active tail 복구, 인덱스 재구축 테스트 존재. SQLite WAL 대신 JSON index를 사용한다. |
| D-15 | IPC·실패 처리 | 부분 구현. 제한 크기의 Unix socket request/response와 timeout 존재. producer 전체의 durable ack·queue overflow·drop metric 보장은 확인하지 못했고 audit 오류 전파 차이가 있다. |
| D-16 | 검색·pagination | 부분 구현. sequence 기반 page와 sparse checkpoint 존재. API/UI 필터 존재. 승인된 365일 데이터셋 검색 SLA·전체 범위 완전성 증거는 부족하다. |
| D-17 | export | 부분 구현. 제한된 행 수·필터와 NDJSON 출력 경로가 있다. 먼저 행 배열을 구성하므로 완전한 저장소 직결 streaming은 아니다. 질문서의 manifest/checksum 패키지 보장은 확인하지 못했다. 원문 제외 기준도 충족하지 않는다. |
| D-18 | Remote Syslog | 부분 구현. UDP/TCP 대상과 alarm delivery 경로가 있다. 현재 대상 검증은 TLS protocol을 지원하지 않는다. 승인된 전송 범위·장애/중복 시험 결과는 별도 확인해야 한다. |
| D-19 | 무결성 | 일부 일치. SHA-256 checksum 및 증가 sequence, 손상 검출이 있다. root 공격에 대한 서명·HMAC·외부 anchor/rollback 보장은 확인하지 못했다. |
| D-20 | packaging·health | 구현 및 일부 실기 확인. 별도 tera-logd 서비스·socket·기동 스크립트, 장비 health 응답 존재. 전체 펌웨어 upgrade/rollback matrix 시험은 미검증이다. |
| D-21 | eMMC 수명 | 미검증. 이번 확인에서 승인된 write/day·write amplification·PRE_EOL/LIFE_TIME 결과를 확보하지 못했다. |
| D-22 | SLA·soak | 미검증. CH18 1포트 CR 응답 확인은 48채널 장기 동시 부하 시험을 대체하지 않는다. |
| D-23 | 납품 증거 | 부분 확보. 호스트 테스트·이번 두 실행파일 해시·실기 설정 확인은 있다. 질문서가 요구하는 전원 차단·장기 soak·전체 traceability 승인 묶음은 없다. |
## 주요 코드 근거
- 원문 수집: `backend/cmd/tera-seriald/main.go`의 `reportStreamEvents`, `recordPayload`; `backend/internal/serial/stream.go`
- 보존·감사·export: `backend/internal/adapters/mock/store.go`의 `validateRetentionDays`, `recordAuditEventLocked`, `StreamLogExport`
- 저장·복구: `backend/internal/logstorage/store.go`의 `Append`, `ensureCapacityLocked`, `writeIndexLocked`, `inspectSegment`
- IPC: `backend/internal/logservice/socket.go`
- 용량: `backend/internal/storage/capacity/governor.go`, `backend/cmd/tera-logd/main.go`
- Syslog: `backend/internal/alarmdelivery/controller.go`의 `normalizeSyslogTarget`
- 초기화: `backend/internal/adapters/mock/factory_reset.go`, `backend/internal/logstorage/factory_reset.go`
- 이번 시간 변경: `backend/internal/adapters/mock/store.go`의 `Login`, `backend/internal/adapters/mock/login_time_test.go`
## 이번 변경과 확인 범위
- 주소 필터 IPv6 탭·추가 화면 제거. 기존 IPv6 URL은 IPv4 화면으로 이동. 네트워크 인터페이스 자체의 IPv6 설정·기존 API 필터 엔진은 변경하지 않았다.
- 첫 관리자 브라우저 로그인 시 PC 시간 동기화. 엄밀히는 API 프로세스 시작 후 최초 1회이며 API 서비스 재시작 후에도 적용한다. 로그인 실패·time.sync 권한 없는 사용자는 시간을 변경하지 못한다. 실패 시 로그인을 막지 않고 다음 관리자 로그인에서 재시도한다.
- PC/브라우저 미접속 상태에서는 PC 시각을 얻을 수 없다. 기존 장비 시간대·NTP 설정은 유지한다.
- 호스트 테스트: API, mock store, systemtime/timesocket, logstorage/logservice, frontend handlers/service 통과.
- 실기: 성공한 관리자 로그인으로 1970년 장비 시각이 현재 PC UTC 시각으로 변경됨; 세션 유지; IPv6 탭 미노출·이전 URL redirect 확인; 12개 서비스 health ok; CH18 CR up 확인.
- 실기 재부팅·공장초기화·전원 차단은 이번 확인에서 실행하지 않았다. 자동 시간 동기화의 새 프로세스 경로를 확인했으며 초기화 상태는 기존 호스트 테스트로 검증했다.
- 배포 API SHA-256: e05b45136b5ea6765289a6aedd6ec6752aca7169329d2e0bf35dd228183ee540
- 배포 Web SHA-256: ace1cada6dc20f38ae91f19b235d72265ed0f2cb1980990cd404149333bf00d6
- release/latest의 두 바이너리도 같은 해시로 갱신했다. 질문서 평가를 이유로 로그 원문·보존 정책을 이번에 임의 변경하지 않았다.