Skill: rebugui/kisa-guideline-hub (version 1.0.1)

--- name: kisa-guideline-hub version: 1.1.0 description: Automatically collect and publish security guidelines and guides from KISA and Boho (보호나라) to Notion. Use when you need to (1) collect new security guidelines, (2) publish guidelines to Notion, (3) manage PDF downloads from KISA/Boho, or (4) run automated guideline collection. Triggered by "가이드라인 발행", "가이드 수집", "KISA 가이드", "보호나라 가이드", "guideline publisher". --- # Guideline Publisher ## Overview Automated system to collect security guidelines from Korean security organizations (KISA, Boho) and publish them to Notion. Unlike regular security news, guidelines are published directly without LLM processing. ## Supported Sources **KISA (한국인터넷진흥원)**: - Security guidelines and best practices - Configuration guides - Policy documents - URL: https://인터넷진흥원.한국/2060207 **Boho (보호나라/KRCERT)**: - Security vulnerability guides - Incident response guides - Technical guidelines - URL: https://www.boho.or.kr - Includes PDF downloads ## Workflow ### 1. Collect Guidelines ```bash cd ~/.openclaw/workspace/skills/security-news-module python3 scripts/publish_guidelines.py --collect ``` This will: - Run KISA crawler (10 guidelines) - Run Boho crawler (11 guidelines, PDF downloads) - Collect PDF files to temp_downloads/ directory - Store articles in processing queue ### 2. Publish to Notion ```bash python3 scripts/publish_guidelines.py --publish ``` This will: - Publish collected guidelines to Notion GUIDE_DATABASE_ID - Upload PDF files to Notion - No LLM processing (direct publishing) - Skip duplicates automatically ### 3. Full Pipeline ```bash python3 scripts/publish_guidelines.py --full ``` Runs both collection and publishing in sequence. ## Notion Database Configuration Guidelines are published to a separate Notion database: **GUIDE_DATABASE_ID**: Set in `.env` as `SECURITY_GUIDE_DATABASE_ID` If not set, defaults to `SECURITY_NEWS_DATABASE_ID` **Notion Properties**: - Title: Guideline name - Category: "KISA 가이드라인" or "보호나라 가이드라인" - URL: Original source URL - Date: Publication date - Files: PDF attachments (Boho only) ## Key Differences from Security News **Guidelines**: - ✅ Direct publishing (no LLM processing) - ✅ PDF file uploads - ✅ Separate Notion database - ✅ KISA + Boho sources **Security News**: - ✅ LLM summary + analysis - ✅ Mermaid diagrams - ✅ Main Notion database - ✅ 9 sources (KRCERT, 데일리시큐, etc.) ## Environment Variables Required in `~/.openclaw/workspace/.env`: ```bash # Notion NOTION_API_KEY=ntn_xxx SECURITY_NEWS_DATABASE_ID=xxx SECURITY_GUIDE_DATABASE_ID=xxx # Optional, defaults to SECURITY_NEWS_DATABASE_ID # GLM API (for security news only) SECURITY_NEWS_GLM_API_KEY=xxx ``` ## File Structure ``` security-news-module/ ├── modules/ │ ├── crawlers/ │ │ ├── kisa.py (KISA guidelines) │ │ └── boho.py (Boho guidelines + PDF) │ ├── publisher_service.py │ └── notion_handler.py (PDF upload support) └── scripts/ └── publish_guidelines.py (This skill's script) ``` ## PDF Downloads Boho crawler automatically downloads PDF files: ``` temp_downloads_boho/ ├── 가이드라인1.pdf ├── 가이드라인2.pdf └── ... ``` PDFs are uploaded to Notion as file blocks. ## Troubleshooting **No guidelines collected**: - Check KISA/Boho websites are accessible - Verify Notion API key and database ID - Check network connectivity **PDF upload fails**: - Verify Notion API supports file uploads - Check file size limits (20MB max) - Ensure temp_downloads/ directory exists **Duplicate guidelines**: - Notion Duplicate_check() prevents duplicates - Based on URL matching - Safe to run multiple times ## Integration with Security News Module This skill is integrated into the Security News Module: ```bash # Run both guidelines and news python3 security_news_aggregator.py --once # Guidelines run first (no LLM, fast) # Then security news (with LLM, slower) ``` ## Cron Scheduling For automated hourly runs: ```bash # Already configured in LaunchAgent # com.openclaw.security-news.plist # Runs every hour automatically ``` ## Resources ### scripts/ - `publish_guidelines.py` - Main script for guideline collection and publishing ### references/ - `schema.md` - Notion database schema for guidelines - `examples.md` - Example guideline publications

path: references/examples.md
content: # Example Guideline Publications

## Example 1: KISA Guideline

**Source**: KISA (한국인터넷진흥원)
**Title**: "2025년 클라우드 보안 가이드라인"
**Category**: "KISA 가이드라인"
**URL**: https://인터넷진흥원.한국/2060207?page=1
**Date**: 2025-03-09

### Notion Page Structure

```
제목: 2025년 클라우드 보안 가이드라인
카테고리: KISA 가이드라인
날짜: 2025-03-09
URL: https://인터넷진흥원.한국/2060207?page=1

내용:
클라우드 환경에서의 보안 모범 사례를 다룬 가이드라인입니다...
```

### Publishing Command

```bash
cd ~/.openclaw/workspace/skills/security-news-module
python3 ../guideline-publisher/scripts/publish_guidelines.py --full
```

### Expected Output

```
GUIDELINE PUBLISHER
======================================================================

🔄 가이드라인 수집 시작...

KISA...
  ✅ 수집: 1개

📊 총 수집: 1개 가이드라인

🔄 Notion 발행 시작... (1개)

[1/1] 2025년 클라우드 보안 가이드라인...
  ✅ 발행 성공

======================================================================
발행 완료
======================================================================
✅ 성공: 1개
❌ 실패: 0개
📊 성공률: 100.0%
```

---

## Example 2: Boho Guideline (with PDF)

**Source**: Boho (보호나라/KRCERT)
**Title**: "해킹진단도구 활용 방안#5"
**Category**: "보호나라 가이드라인"
**URL**: https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&nttId=xxx
**Date**: 2025-03-09
**Files**: 해킹진단도구_활용방안5.pdf

### Notion Page Structure

```
제목: 해킹진단도구 활용 방안#5
카테고리: 보호나라 가이드라인
날짜: 2025-03-09
URL: https://www.boho.or.kr/kr/bbs/view.do?bbsId=B0000133&nttId=xxx

파일:
📎 해킹진단도구_활용방안5.pdf (다운로드 가능)
```

### PDF Download Process

1. Crawler finds PDF link
2. Downloads to `temp_downloads_boho/해킹진단도구_활용방안5.pdf`
3. Uploads to Notion via file upload API
4. Creates file block in page

---

## Example 3: Multiple Guidelines

**Batch publishing**:

```bash
python3 ../guideline-publisher/scripts/publish_guidelines.py --full
```

### Output

```
KISA...
  ✅ 수집: 10개

Boho...
  ✅ 수집: 11개

📊 총 수집: 21개 가이드라인

🔄 Notion 발행 시작... (21개)

[1/21] 2025년 사이버 위협 대응 가이드라인...
  ✅ 발행 성공

[2/21] 클라우드 보안 구축 가이드...
  ✅ 발행 성공

[3/21] 해킹진단도구 활용 방안#5...
  ✅ 발행 성공 (PDF: 1개)

...

======================================================================
발행 완료
======================================================================
✅ 성공: 21개
❌ 실패: 0개
📊 성공률: 100.0%
```

---

## Common Scenarios

### Scenario 1: First Run

```bash
# No guidelines collected yet
python3 ../guideline-publisher/scripts/publish_guidelines.py --full

# Result: 21 new guidelines published
```

### Scenario 2: Duplicate Prevention

```bash
# Run again immediately
python3 ../guideline-publisher/scripts/publish_guidelines.py --full

# Result: 0 new guidelines (all duplicates)
# KISA...
#   ✅ 수집: 10개 (all duplicates)
# Boho...
#   ✅ 수집: 11개 (all duplicates)
```

### Scenario 3: New Guidelines Available

```bash
# After 1 week, new guidelines published
python3 ../guideline-publisher/scripts/publish_guidelines.py --full

# Result: 3 new guidelines published
# KISA...
#   ✅ 수집: 2개 (new)
# Boho...
#   ✅ 수집: 1개 (new)
```

---

## Troubleshooting Examples

### Error: Database Not Found

```
❌ Error: Notion database not found
```

**Solution**:
```bash
# Check .env file
grep SECURITY_GUIDE_DATABASE_ID ~/.openclaw/workspace/.env

# Or use default
export SECURITY_GUIDE_DATABASE_ID=$SECURITY_NEWS_DATABASE_ID
```

### Error: PDF Upload Failed

```
[5/21] 해킹진단도구 활용 방안#5...
  ❌ Error: File size exceeds limit
```

**Solution**:
- Notion file upload limit: 20MB
- Split large PDFs or compress them

### Error: Network Timeout

```
KISA...
  ❌ Error: HTTPSConnectionPool timeout
```

**Solution**:
- Check network connectivity
- Retry command
- Check firewall settings

---

## Integration with Cron

### LaunchAgent Configuration

```xml
<!-- ~/Library/LaunchAgents/com.openclaw.guidelines.plist -->
<key>ProgramArguments</key>
<array>
    <string>/usr/bin/python3</string>
    <string>/Users/rebugui/.openclaw/workspace/skills/guideline-publisher/scripts/publish_guidelines.py</string>
    <string>--full</string>
</array>
<key>StartInterval</key>
<integer>86400</integer> <!-- Daily -->
```

### Manual Cron

```bash
# Run daily at 9 AM
0 9 * * * cd ~/.openclaw/workspace/skills/security-news-module && python3 ../guideline-publisher/scripts/publish_guidelines.py --full
```


path: references/schema.md
content: # Notion Database Schema for Guidelines

## Database Properties

**GUIDE_DATABASE_ID**: Notion database ID for guidelines
- Environment variable: `SECURITY_GUIDE_DATABASE_ID`
- Falls back to: `SECURITY_NEWS_DATABASE_ID`

## Required Properties

### Title (title type)
- Guideline name
- Example: "2025년 사이버 위협 대응 가이드라인"

### Category (select type)
- Values:
  - "KISA 가이드라인"
  - "보호나라 가이드라인"

### Date (date type)
- Publication date
- Format: YYYY-MM-DD

### URL (url type)
- Original source URL
- Example: "https://인터넷진흥원.한국/2060207?page=1"

## Optional Properties

### Content (text type)
- Brief description
- Max 2000 characters

### Files (file type)
- PDF attachments
- Boho guidelines only
- Max 20MB per file

## Block Structure

Guideline pages contain:

1. **Content block** (paragraph)
   - Brief description
   - Empty if not available

2. **File blocks** (Boho only)
   - PDF files
   - Uploaded via Notion API

## Example Page

```json
{
  "parent": {
    "database_id": "GUIDE_DATABASE_ID"
  },
  "properties": {
    "제목": {
      "title": [
        {
          "text": {
            "content": "2025년 사이버 위협 대응 가이드라인"
          }
        }
      ]
    },
    "category": {
      "select": {
        "name": "KISA 가이드라인"
      }
    },
    "date": {
      "date": {
        "start": "2025-03-09"
      }
    },
    "url": {
      "url": "https://인터넷진흥원.한국/2060207?page=1"
    }
  }
}
```

## Duplicate Prevention

- Uses `Duplicate_check()` function
- Based on URL matching
- Safe to run multiple times
- Existing pages are skipped

## File Upload Process

1. Download PDF to `temp_downloads_boho/`
2. Upload to Notion via `upload_file_to_notion()`
3. Create file block with `file_upload` type
4. Add to page children blocks

## API Version

- Notion-Version: 2025-09-03
- Supports file uploads via `file_upload` type


path: scripts/publish_guidelines.py
content: #!/usr/bin/env python3
"""
가이드라인 발행 스크립트
KISA, Boho 가이드라인 수집 및 Notion 발행
"""

import sys
from pathlib import Path
import warnings
warnings.filterwarnings('ignore')
import argparse

# 환경 변수 로드
from dotenv import load_dotenv
env_file = Path.home() / '.openclaw' / 'workspace' / '.env'
load_dotenv(env_file)

# Security News Module 경로 추가 (security-news-feed의 modules 사용)
import os
skill_path = Path(__file__).parent.parent.parent / 'security-news-feed'
sys.path.insert(0, str(skill_path))
os.chdir(str(skill_path))  # working directory 변경

from modules.crawlers.kisa import KISACrawler
from modules.crawlers.boho import BohoCrawler
from modules.publisher_service import PublisherService
from config import GUIDE_DATABASE_ID

print("="*70)
print("GUIDELINE PUBLISHER")
print("="*70)

def collect_guidelines():
    """가이드라인 수집"""
    print("\n🔄 가이드라인 수집 시작...")
    
    crawlers = [
        ("KISA", KISACrawler),
        ("Boho", BohoCrawler),
    ]
    
    all_guidelines = []
    
    for name, crawler_class in crawlers:
        print(f"\n{name}...")
        try:
            crawler = crawler_class()
            result = crawler.run(publisher_service=None)
            
            collected = len(result.get('queue', []))
            print(f"  ✅ 수집: {collected}개")
            
            if collected > 0:
                all_guidelines.extend(result['queue'])
        
        except Exception as e:
            print(f"  ❌ Error: {str(e)[:50]}")
    
    print(f"\n📊 총 수집: {len(all_guidelines)}개 가이드라인")
    return all_guidelines

def publish_guidelines(guidelines):
    """Notion 발행"""
    if not guidelines:
        print("❌ 발행할 가이드라인이 없습니다.")
        return
    
    print(f"\n🔄 Notion 발행 시작... ({len(guidelines)}개)")
    
    # Publisher Service 초기화
    publisher = PublisherService(
        enable_notion=True,
        enable_tistory=False,
        notion_database_id=GUIDE_DATABASE_ID
    )
    
    success_count = 0
    fail_count = 0
    
    for i, guideline in enumerate(guidelines, 1):
        print(f"\n[{i}/{len(guidelines)}] {guideline['title'][:50]}...")
        
        try:
            # Notion 발행 (LLM 없이 바로 발행)
            pub_result = publisher.publish_article(
                title=guideline['title'],
                content=guideline.get('content', '내용 없음'),
                url=guideline['url'],
                date=guideline['posting_date'].strftime('%Y-%m-%d'),
                category=guideline['category'],
                details="",  # 가이드라인은 details 없음
                files=guideline.get('files', []),  # PDF 파일
                database_id=GUIDE_DATABASE_ID
            )
            
            if pub_result.get('notion'):
                success_count += 1
                print("  ✅ 발행 성공")
            else:
                fail_count += 1
                print("  ❌ 발행 실패")
        
        except Exception as e:
            fail_count += 1
            print(f"  ❌ Error: {str(e)[:50]}")
    
    print("\n" + "="*70)
    print("발행 완료")
    print("="*70)
    print(f"✅ 성공: {success_count}개")
    print(f"❌ 실패: {fail_count}개")
    print(f"📊 성공률: {success_count/len(guidelines)*100:.1f}%")

def main():
    parser = argparse.ArgumentParser(description='가이드라인 발행')
    parser.add_argument('--collect', action='store_true', help='가이드라인 수집만')
    parser.add_argument('--publish', action='store_true', help='Notion 발행만')
    parser.add_argument('--full', action='store_true', help='수집 + 발행')
    
    args = parser.parse_args()
    
    if not any([args.collect, args.publish, args.full]):
        parser.print_help()
        return
    
    guidelines = []
    
    if args.collect or args.full:
        guidelines = collect_guidelines()
    
    if args.publish:
        # 발행만 실행할 때는 기존 수집된 데이터 사용
        # (실제로는 DB나 파일에서 로드해야 함)
        print("⚠️ --publish 단독 실행은 아직 구현되지 않았습니다.")
        print("--full을 사용하세요.")
        return
    
    if args.full and guidelines:
        publish_guidelines(guidelines)

if __name__ == '__main__':
    main()


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (HIGH)