# Operational Security Completion Implementation Plan > 참고: 이 문서는 누수감지 시절의 기록(레거시)이며, 현재 시스템은 SHT30 온습도 전용으로 전환되었습니다. > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Turn the v2605 leak monitoring project into a submission-ready and field-operable system with concrete security evidence, operational diagnostics, and review-friendly reports. **Architecture:** Keep the current procedural PHP/Cafe24 structure. Extract reusable operational checks into a small PHP helper, add a login-protected evidence report page, add a Pi-side sanitized evidence collector, and update documentation so security controls map to actual code and captured evidence. **Tech Stack:** PHP 7+/PDO/MySQL on Cafe24, Apache `.htaccess`, Raspberry Pi Python 3, systemd, Markdown documentation. --- ## Origin Source requirements: `docs/superpowers/specs/2026-05-20-operational-security-completion-design.md` This plan intentionally avoids implementing fire detection, power anomaly detection, multi-tenant productization, or HWP binary editing. Those remain outside the current scope. ## File Structure Create: - `php/ops_checks.php` Shared server-side operational/security checks used by setup and evidence pages. - `php/security_evidence.php` Login-protected evidence report page for security review attachments. Supports browser view and Markdown download. - `raspberry_pi/collect_evidence.py` Sanitized Pi-side evidence collector that prints service, network, camera, and API test evidence without exposing secrets. - `docs/OPERATIONS_SECURITY_CHECKLIST.md` Operator checklist for monthly security/operation review. - `docs/SECURITY_EVIDENCE_PACKAGE.md` Submission package index: what to attach, where it comes from, and what it proves. Modify: - `php/setup_wizard.php` Use shared checks and link to `security_evidence.php`. - `php/dashboard.php` Add clearer links/status hints for evidence, SMS failures, and offline state without changing its core flow. - `php/monthly_report.php` Add print-friendly metadata and evidence-oriented summary rows. - `docs/README.md` Link the new evidence and operations checklist docs. - `docs/SECURITY_PLAN_ATTACHMENT_GUIDE.md` Narrow the user-provided items now that code-based evidence is generated locally. - `docs/SOURCE_SECURITY_EVIDENCE.md` Point to the new evidence page and Pi collector. - `CHANGELOG.md` Record the operational/security completion improvements. Verification: - PHP lint for all changed PHP files. - Python compile for Raspberry Pi scripts. - Static secret/stale-value search excluding `_backup`. - Manual browser verification on deployed Cafe24 remains an operator step, documented but not locally provable. --- ## Task 1: Extract Shared Operational Checks **Files:** - Create: `php/ops_checks.php` - Modify: `php/setup_wizard.php` - Test: PHP lint plus manual inclusion through `setup_wizard.php` - [ ] **Step 1: Create `php/ops_checks.php` with reusable checks** Create a small helper that returns normalized check rows. Use this structure: ```php prepare(" SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :table "); $stmt->execute([':table' => $table]); return (int)$stmt->fetchColumn() > 0; } function ops_column_exists(PDO $db, string $table, string $column): bool { $stmt = $db->prepare(" SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = :table AND COLUMN_NAME = :column "); $stmt->execute([':table' => $table, ':column' => $column]); return (int)$stmt->fetchColumn() > 0; } function ops_check(string $category, string $label, bool $ok, string $detail, string $fix = '', string $severity = 'warn', string $evidence = ''): array { return [ 'category' => $category, 'label' => $label, 'ok' => $ok, 'detail' => $detail, 'fix' => $fix, 'severity' => $severity, 'evidence' => $evidence, ]; } function collect_ops_checks(): array { $checks = []; try { $db = get_db(); $checks[] = ops_check('서버', 'DB 연결', true, DB_NAME . ' 연결 성공', '', 'critical', 'setup_wizard.php 또는 security_evidence.php 화면'); $required_tables = ['sensor_log', 'sensor_status', 'sms_log', 'leak_photo', 'leak_incident']; foreach ($required_tables as $table) { $exists = ops_table_exists($db, $table); $checks[] = ops_check( 'DB', "테이블 {$table}", $exists, $exists ? '확인됨' : '누락됨', $table === 'leak_incident' ? 'sql/migration_incident_response.sql 또는 sql/schema_v2605.sql 실행' : 'sql/schema_v2605.sql 실행', $table === 'leak_incident' ? 'critical' : 'warn', 'DB 테이블 목록 또는 설치 점검 화면' ); } if (ops_table_exists($db, 'leak_photo')) { foreach (['sequence_no', 'photo_stage'] as $column) { $exists = ops_column_exists($db, 'leak_photo', $column); $checks[] = ops_check('DB', "사진 타임라인 컬럼 {$column}", $exists, $exists ? '확인됨' : '누락됨', 'sql/migration_photo_timeline.sql 실행', 'warn', 'leak_photo 컬럼 목록'); } } $recent_sms_fail_stmt = $db->query(" SELECT COUNT(*) FROM sms_log WHERE status = 'fail' AND sent_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) "); $recent_sms_fail = (int)$recent_sms_fail_stmt->fetchColumn(); $checks[] = ops_check('SMS', '최근 30일 SMS 실패', $recent_sms_fail === 0, "{$recent_sms_fail}건", 'Cafe24 SMS 계정, 잔액, 발신번호, 수신자 확인', 'warn', 'sms_log 최근 실패 건수'); } catch (Throwable $e) { $checks[] = ops_check('서버', 'DB 연결', false, '연결 실패: ' . $e->getMessage(), 'config.local.php DB 설정 확인', 'critical', 'DB 연결 오류 화면'); } $default_recipients = count(SMS_RECIPIENTS) === 1 && preg_replace('/\D+/', '', SMS_RECIPIENTS[0]) === '01000000000'; $checks[] = ops_check('설정', 'API 키', API_KEY !== 'change-this-api-key', 'API_KEY 운영값 설정 여부', 'config.local.php와 /etc/leak-sensor.env의 API 키를 동일하게 설정', 'critical', 'config.local.php 원문 미공개 설정 확인'); $checks[] = ops_check('설정', '관리자 비밀번호', ADMIN_PASSWORD_HASH !== '', 'ADMIN_PASSWORD_HASH 설정 여부', 'php setup_hash.php "새비밀번호" 실행 후 config.local.php에 반영', 'critical', '관리자 해시 설정 확인'); $checks[] = ops_check('개인정보', 'SMS 수신자', !empty(SMS_RECIPIENTS) && !$default_recipients, count(SMS_RECIPIENTS) . '명 설정', 'config.local.php의 SMS_RECIPIENTS 현행화', 'critical', '수신자 목록 현행화 확인표'); $checks[] = ops_check('파일', '사진 저장 폴더', is_dir(PHOTO_UPLOAD_DIR) && is_writable(PHOTO_UPLOAD_DIR), PHOTO_UPLOAD_DIR, 'uploads/photos 생성 및 쓰기 권한 확인', 'warn', '폴더 권한 화면'); $checks[] = ops_check('파일', '상태 파일 폴더', is_dir(__DIR__ . '/var') && is_writable(__DIR__ . '/var'), __DIR__ . '/var', 'php/var 생성 및 쓰기 권한 확인', 'warn', '폴더 권한 화면'); return $checks; } function ops_failed_count(array $checks): int { return count(array_filter($checks, fn($check) => !$check['ok'])); } ``` - [ ] **Step 2: Replace duplicate setup check functions in `php/setup_wizard.php`** Remove `setup_table_exists()`, `setup_column_exists()`, and `setup_check()` from `setup_wizard.php`. Add: ```php require_once __DIR__ . '/ops_checks.php'; ``` Replace the current manual `$checks` construction with: ```php $checks = collect_ops_checks(); ``` Keep the existing SMS test POST handling unchanged. - [ ] **Step 3: Update setup wizard rendering for new check fields** Where checks render, preserve the existing UI but read the new fields: ```php

· ·

조치:
증적:
``` - [ ] **Step 4: Add evidence page link to setup wizard** In the header link area, add a link: ```php 보안 증적 ``` If the header currently has a single link, convert it to a small flex group matching `dashboard.php`. - [ ] **Step 5: Verify PHP syntax** Run: ```powershell php -l php\ops_checks.php php -l php\setup_wizard.php ``` Expected: both commands print `No syntax errors detected`. --- ## Task 2: Add Login-Protected Security Evidence Report **Files:** - Create: `php/security_evidence.php` - Modify: `php/.htaccess` - Test: PHP lint and login-protected manual browser check - [ ] **Step 1: Create `php/security_evidence.php`** Create a login-required report page that uses `collect_ops_checks()` and supports Markdown download using `?format=md`. Core structure: ```php ``` Render the HTML body with: - title: `보안 증적 보고서` - summary card: generated time, `APP_VERSION`, failed count - operational checks table - security control matrix table - download link: `security_evidence.php?format=md` - print button: `window.print()` - [ ] **Step 2: Ensure helper files remain directly blocked** Modify `php/.htaccess` `FilesMatch` to include `ops_checks`: ```apache ``` Do not block `security_evidence.php`; it is a login-protected page. - [ ] **Step 3: Verify PHP syntax** Run: ```powershell php -l php\security_evidence.php ``` Expected: - `security_evidence.php` passes PHP lint. - `.htaccess` is not PHP; do not lint it. Instead visually confirm `ops_checks` is in the `FilesMatch` rule. - [ ] **Step 4: Manual browser test after deployment** Expected behavior: - Unauthenticated `security_evidence.php` redirects to `login.php`. - Authenticated access displays checks and control matrix. - `?format=md` downloads Markdown without secrets. --- ## Task 3: Add Raspberry Pi Evidence Collector **Files:** - Create: `raspberry_pi/collect_evidence.py` - Modify: `docs/INSTALL_PI_SERVER.md` - Test: Python compile and dry-run on development machine - [ ] **Step 1: Create `raspberry_pi/collect_evidence.py`** The script must not print API keys, passwords, or SMS secrets. It should report whether required env vars exist, not their values. Implementation outline: ```python #!/usr/bin/env python3 """Sanitized Raspberry Pi evidence collector for security review attachments.""" import argparse import json import os import shutil import subprocess import time from pathlib import Path ENV_FILE = Path("/etc/leak-sensor.env") def run_command(command, timeout=10): try: result = subprocess.run(command, capture_output=True, text=True, timeout=timeout) return { "command": " ".join(command), "returncode": result.returncode, "stdout": result.stdout.strip()[:4000], "stderr": result.stderr.strip()[:2000], } except Exception as exc: return {"command": " ".join(command), "returncode": -1, "stdout": "", "stderr": str(exc)} def env_presence(): keys = [ "LEAK_API_URL", "LEAK_PHOTO_UPLOAD_URL", "LEAK_API_KEY", "LEAK_DEVICE_ID", "LEAK_DEVICE_LOCATION", "LEAK_CAMERA_ENABLED", "LEAK_PHOTO_TIMELINE_ENABLED", "LEAK_PHOTO_TIMELINE_DELAYS", ] return {key: bool(os.environ.get(key)) for key in keys} def collect(): evidence = { "generated_at": time.strftime("%Y-%m-%d %H:%M:%S"), "hostname": run_command(["hostname"])["stdout"], "env_file_exists": ENV_FILE.exists(), "env_file_permission": run_command(["ls", "-l", str(ENV_FILE)]) if ENV_FILE.exists() else None, "env_presence": env_presence(), "service_status": run_command(["systemctl", "status", "leak-sensor", "--no-pager"], timeout=15), "service_enabled": run_command(["systemctl", "is-enabled", "leak-sensor"], timeout=10), "listening_ports": run_command(["ss", "-lntup"], timeout=10), "camera_tools": { "rpicam-still": shutil.which("rpicam-still") is not None, "libcamera-still": shutil.which("libcamera-still") is not None, }, "recent_logs": run_command(["journalctl", "-u", "leak-sensor", "-n", "80", "--no-pager"], timeout=15), } return evidence def print_markdown(evidence): print("# Raspberry Pi 보안/운영 증적") print() print(f"- 생성시각: {evidence['generated_at']}") print(f"- 호스트명: {evidence['hostname']}") print(f"- 환경파일 존재: {'예' if evidence['env_file_exists'] else '아니오'}") if evidence["env_file_permission"]: print(f"- 환경파일 권한: `{evidence['env_file_permission']['stdout']}`") print() print("## 환경변수 설정 여부") print() print("| 항목 | 설정 여부 |") print("|---|---|") for key, present in evidence["env_presence"].items(): print(f"| {key} | {'설정됨' if present else '미설정'} |") print() print("## 서비스 상태") print() print("```text") print(evidence["service_status"]["stdout"] or evidence["service_status"]["stderr"]) print("```") print() print("## 수신 포트") print() print("```text") print(evidence["listening_ports"]["stdout"] or evidence["listening_ports"]["stderr"]) print("```") def main(): parser = argparse.ArgumentParser() parser.add_argument("--format", choices=["json", "md"], default="md") args = parser.parse_args() evidence = collect() if args.format == "json": print(json.dumps(evidence, ensure_ascii=False, indent=2)) else: print_markdown(evidence) if __name__ == "__main__": main() ``` - [ ] **Step 2: Document Pi evidence command in `docs/INSTALL_PI_SERVER.md`** Add under the Pi final verification section: ```bash cd /home/pi/leak_sensor source venv/bin/activate python3 collect_evidence.py --format md > pi-security-evidence.md ``` Note that the output intentionally does not include raw API keys. - [ ] **Step 3: Verify Python syntax** Run: ```powershell python -m py_compile raspberry_pi\collect_evidence.py ``` Expected: exit code 0 and no output. - [ ] **Step 4: Dry-run on non-Pi development machine** Run: ```powershell python raspberry_pi\collect_evidence.py --format json ``` Expected: - JSON output is produced. - systemd/camera commands may show errors on Windows; this is acceptable if the script does not crash. - No API key value is printed. --- ## Task 4: Improve Report and Dashboard Evidence Quality **Files:** - Modify: `php/monthly_report.php` - Modify: `php/dashboard.php` - Test: PHP lint and visual/manual verification after deployment - [ ] **Step 1: Add report metadata to `php/monthly_report.php`** Add near the existing `$summary` block: ```php $report_generated_at = date('Y-m-d H:i:s'); $report_scope = '누수 감지, 장비 오프라인, SMS, 사진, 사고 대응'; ``` Render above the summary cards: ```php
보고서 생성

범위:

``` This makes printed/PDF reports usable as evidence. - [ ] **Step 2: Extend monthly CSV with evidence metadata** Before existing CSV rows, add: ```php fputcsv($out, ['generated_at', $report_generated_at]); fputcsv($out, ['scope', $report_scope]); ``` Expected CSV begins with month, generated time, and scope. - [ ] **Step 3: Add dashboard link to evidence page** In `php/dashboard.php` header links, add: ```php 보안 증적 ``` Keep existing `setup_wizard.php`, `monthly_report.php`, and logout links. - [ ] **Step 4: Add a short evidence hint near dashboard diagnostics** In the operational diagnostics section, add one concise sentence: ```php

보안대책서 첨부용 점검표는 상단의 보안 증적 화면에서 내려받을 수 있습니다.

``` - [ ] **Step 5: Verify PHP syntax** Run: ```powershell php -l php\monthly_report.php php -l php\dashboard.php ``` Expected: both commands print `No syntax errors detected`. --- ## Task 5: Finalize Documentation Package **Files:** - Create: `docs/OPERATIONS_SECURITY_CHECKLIST.md` - Create: `docs/SECURITY_EVIDENCE_PACKAGE.md` - Modify: `docs/README.md` - Modify: `docs/SECURITY_PLAN_ATTACHMENT_GUIDE.md` - Modify: `docs/SOURCE_SECURITY_EVIDENCE.md` - Modify: `CHANGELOG.md` - Test: Markdown link/path sanity checks - [ ] **Step 1: Create `docs/OPERATIONS_SECURITY_CHECKLIST.md`** Include this structure: ```markdown # 운영·보안 점검 체크리스트 ## 월간 점검 | 점검 항목 | 기준 | 증적 | |---|---|---| | 대시보드 로그인 | 관리자만 접근 가능 | 로그인 화면, 접근통제 확인 | | 설치 점검 | 확인 필요 항목 없음 또는 조치 계획 존재 | setup_wizard.php 캡처 | | 보안 증적 | 점검 결과와 보안통제 매트릭스 확인 | security_evidence.php 캡처 또는 MD 다운로드 | | Pi 서비스 | leak-sensor active 상태 | collect_evidence.py 결과 | | SMS 발송 | 최근 실패 건수 확인 | monthly_report.php 또는 sms_log | | 사진 저장 | 사진 타임라인 확인 | dashboard.php 캡처 | | 백업 | DB/사진/설정 백업 확인 | 백업 파일 목록 | | 보관기간 | 사진/로그 기간 초과분 정리 | 삭제/정리 기록 | ## 사고 발생 시 1. 대시보드에서 사고 상태와 사진 타임라인을 확인한다. 2. SMS 수신 여부와 `sms_log` 실패 여부를 확인한다. 3. 현장 조치 후 사고 상태를 `조치 완료` 또는 `오탐`으로 기록한다. 4. 월간 보고서에 사고 처리 내역이 반영됐는지 확인한다. ``` - [ ] **Step 2: Create `docs/SECURITY_EVIDENCE_PACKAGE.md`** Include: ```markdown # 보안대책서 첨부자료 패키지 ## 필수 첨부 | 첨부자료 | 생성 위치 | 증명하는 것 | |---|---|---| | 보안 증적 보고서 | `php/security_evidence.php?format=md` | 보안통제와 운영 점검 연결 | | 설치 점검 화면 | `php/setup_wizard.php` | DB/권한/SMS/설정 상태 | | 대시보드 화면 | `php/dashboard.php` | 현재 위험, 사고, 사진, 장비 상태 | | 월간 보고서 | `php/monthly_report.php` | SMS/사진/사고 처리 현황 | | Pi 증적 보고서 | `raspberry_pi/collect_evidence.py --format md` | Pi 서비스, 포트, 환경파일 상태 | | HTTPS 접속 화면 | 운영 도메인 브라우저 | 전송구간 보호 적용 | ## 제출 전 마스킹 - API 키 원문 제거 - DB 비밀번호 제거 - SMS secure key 제거 - 관리자 비밀번호 원문 제거 - 담당자 휴대전화번호는 필요 시 뒷자리 마스킹 ``` - [ ] **Step 3: Update `docs/README.md`** Add the new documents under folder structure: ```text OPERATIONS_SECURITY_CHECKLIST.md # 월간 운영·보안 점검표 SECURITY_EVIDENCE_PACKAGE.md # 보안대책서 첨부자료 패키지 ``` Add an operations section that points to: - `setup_wizard.php` - `security_evidence.php` - `monthly_report.php` - `raspberry_pi/collect_evidence.py` - [ ] **Step 4: Update security guide docs** In `docs/SECURITY_PLAN_ATTACHMENT_GUIDE.md`, add that API/source evidence is generated by: ```text php/security_evidence.php raspberry_pi/collect_evidence.py docs/SOURCE_SECURITY_EVIDENCE.md ``` In `docs/SOURCE_SECURITY_EVIDENCE.md`, add: ```text 운영 서버 반영 후 `security_evidence.php?format=md`를 내려받으면 코드 기반 보안통제와 운영 점검 결과를 하나의 증적 파일로 보관할 수 있다. ``` - [ ] **Step 5: Update `CHANGELOG.md`** Add under v2605: ```markdown - 보안대책서 첨부용 증적 보고서 계획과 운영·보안 체크리스트를 추가했습니다. - Pi 증적 수집 스크립트 계획을 추가해 API 키 원문 없이 서비스/포트/환경파일 상태를 확인할 수 있게 했습니다. ``` - [ ] **Step 6: Verify Markdown paths** Run: ```powershell Get-ChildItem docs -Recurse -File | Where-Object { $_.Extension -eq '.md' } | Select-String -Pattern 'security_evidence.php|collect_evidence.py|OPERATIONS_SECURITY_CHECKLIST|SECURITY_EVIDENCE_PACKAGE' ``` Expected: new docs and links appear in README/security docs. --- ## Task 6: Full Verification Pass **Files:** - All changed PHP, Python, Markdown files - [ ] **Step 1: Run PHP lint** Run: ```powershell $files = @( 'php\config.php', 'php\ops_checks.php', 'php\setup_wizard.php', 'php\security_evidence.php', 'php\dashboard.php', 'php\monthly_report.php', 'php\api\sensor_data.php', 'php\api\photo_upload.php', 'php\login.php', 'php\sms_send.php', 'php\incidents.php', 'php\cron_heartbeat.php' ) foreach ($file in $files) { php -l $file } ``` Expected: every file reports `No syntax errors detected`. - [ ] **Step 2: Run Python compile checks** Run: ```powershell python -m py_compile raspberry_pi\config.py raspberry_pi\leak_sensor.py raspberry_pi\test_connection.py raspberry_pi\collect_evidence.py scripts\generate_security_plan_images.py ``` Expected: exit code 0 and no output. - [ ] **Step 3: Search for stale secrets and legacy values** Run: ```powershell Get-ChildItem -Recurse -File | Where-Object { $_.FullName -notlike '*\_backup\*' } | Select-String -Pattern '' -CaseSensitive:$false ``` Expected: no matches outside intentional documentation examples. - [ ] **Step 4: Confirm no Python cache remains** If `py_compile` creates cache files, remove them after verifying the resolved path is inside the workspace: ```powershell $target = Resolve-Path -LiteralPath 'raspberry_pi\__pycache__' -ErrorAction SilentlyContinue if ($target) { $workspace = (Resolve-Path -LiteralPath '.').Path if ($target.Path.StartsWith($workspace)) { Remove-Item -LiteralPath $target.Path -Recurse -Force } } ``` - [ ] **Step 5: Manual deployment verification checklist** After uploading to Cafe24 and Pi: - Visit `login.php`; verify login is required. - Visit `setup_wizard.php`; capture the result. - Visit `security_evidence.php`; capture the result. - Download `security_evidence.php?format=md`; confirm no secrets are present. - Visit `dashboard.php`; confirm evidence link and diagnostics. - Visit `monthly_report.php`; print/PDF preview includes generated time and scope. - Run `python3 collect_evidence.py --format md` on Pi; confirm no API key is printed. - Run `python3 test_connection.py` on Pi; confirm unsigned request is rejected and signed request succeeds. Expected: these items produce the minimum security evidence package. --- ## Task 7: Completion Notes **Files:** - Modify: `docs/SECURITY_PLAN_PASS_READINESS.md` - Modify: `docs/SECURITY_PLAN_HWP_REVIEW.md` - [ ] **Step 1: Point final security docs to the new evidence outputs** In `docs/SECURITY_PLAN_PASS_READINESS.md`, add references to: - `php/security_evidence.php` - `php/security_evidence.php?format=md` - `raspberry_pi/collect_evidence.py --format md` - `docs/SECURITY_EVIDENCE_PACKAGE.md` - [ ] **Step 2: Clarify remaining user-provided evidence** Keep the remaining user-provided list short: ```text 1. 실제 서버 도메인과 HTTPS 화면 2. Pi 네트워크 분리 또는 방화벽 정책 확인 3. 설치 위치 사진과 자산 정보 4. 백업 주기와 담당자 5. SMS 수신자 현행화 확인 ``` - [ ] **Step 3: Verify final docs contain no over-claim** Search: ```powershell Select-String -Path docs\SECURITY_PLAN_*.md,docs\SOURCE_SECURITY_EVIDENCE.md -Pattern '국정원.*통과|완벽|보장|반드시 통과' ``` Expected: no text claims guaranteed approval. --- ## Coverage Map | Requirement | Implemented by | |---|---| | 심사 대응 패키지 | Tasks 1, 2, 5, 7 | | 코드 기반 보안근거 | Tasks 2, 5, 7 | | 운영 실패 가시화 | Tasks 1, 3, 4 | | 대시보드/보고서 증적 품질 | Task 4 | | 자동 증적 생성 | Tasks 2, 3 | | 확장 범위 분리 | Task 7 plus existing security docs | | 비밀값 미노출 | Tasks 2, 3, 6 | ## Execution Notes - This workspace currently has no `.git` directory, so commit steps are skipped in this workspace. - Do not put real API keys, DB passwords, SMS secure keys, or administrator passwords into Markdown. - If a deployed Cafe24 behavior cannot be verified locally, document it as an operator evidence requirement instead of claiming it as verified.