تشغيل self-host¶
الفرق التي تشغّل CVE Radar على خوادم داخلية أو Kubernetes أو Docker تحتاج أكثر من سير العمل الافتراضي للمتصفّح. يغطي هذا الفصل قدرات الإنتاج ضمن نفس كود MIT: سجلات audit منظمة، mount للأسرار، RBAC، تعدد المستأجرين PostgreSQL، مقاييس Prometheus، مرايا airgap، واكتشاف المكدس في Kubernetes.
لا يوجد مستوى enterprise أو قفل ترخيص. متغيرات البيئة تضبط السلوك التشغيلي فقط. للاستكشاف اليومي راجع التشغيل؛ للبيئة الأساسية الإعداد.
flowchart TB
classDef ui fill:#e9edf5,stroke:#00baba,color:#253343
classDef api fill:#f3fcfc,stroke:#008c8c,color:#253343
classDef data fill:#fff7ed,stroke:#eda232,color:#253343
classDef ext fill:#f5f5f5,stroke:#666,color:#253343
subgraph deploy["نشر self-host"]
Browser[SPA المتصفّح]:::ui
API[Express API]:::api
PG[(PostgreSQL اختياري)]:::data
Metrics["GET /metrics"]:::api
Audit[stdout audit JSON]:::ext
end
Browser --> API
API --> PG
API --> Metrics
API --> Audit
API --> Feeds[NVD / OSV / mirrors]:::ext
API --> Notify[Slack / SMTP / webhooks]:::ext
يُظهر المخطط PostgreSQL الاختياري، وscraping Prometheus على /metrics، وسطور audit على stdout، وقنوات الإشعار بعد watch. في airgap تُستبدل المصادر العامة بمرايا محلية (انظر نشر airgap).
سجلات audit¶
CVE Radar يمكنه إخراج سطر JSON واحد لكل حدث audit على stdout لـ ELK أو Loki أو Splunk أو driver json-file في Docker.
| action | متى يُسجَّل |
|---|---|
scan |
بعد كل POST /api/scan (نجاح، فشل جزئي، أو خطأ) |
watch |
بعد كل POST /api/watch |
health |
عند AUDIT_HEALTH=true و GET /api/health?detailed=true |
export |
ليس من جانب الخادم بعد (التصدير في المتصفّح فقط) |
{
"audit": true,
"ts": "2026-06-06T14:30:00.000Z",
"action": "scan",
"ip": "10.0.0.42",
"stack": ["redis", "nginx"],
"duration_ms": 8420,
"sources_failed": ["NVD"],
"result_count": 12,
"mode": "full"
}
اضبط TRUST_PROXY_HOPS خلف reverse proxy. لا تُسجَّل عناوين CVE أو مفاتيح API.
docker logs cve-radar 2>&1 | grep '"audit":true'
الأسرار والإنتاج¶
| env مباشر | env ملف (*_FILE) |
|---|---|
NVD_API_KEY |
NVD_API_KEY_FILE |
GITHUB_TOKEN |
GITHUB_TOKEN_FILE |
DEEPL_API_KEY |
DEEPL_API_KEY_FILE |
ALERT_WEBHOOK_URL |
ALERT_WEBHOOK_URL_FILE |
NOTIFICATION_SLACK_WEBHOOK_URL |
— |
NOTIFICATION_DISCORD_WEBHOOK_URL |
— |
NOTIFICATION_TELEGRAM_BOT_TOKEN |
— |
NOTIFICATION_SMTP_PASS |
mount عبر env file في Compose |
API_SECRET |
API_SECRET_FILE |
API_SECRET_PREVIOUS |
API_SECRET_PREVIOUS_FILE |
في Kubernetes يُفضَّل mount ملفات Secret. راجع docker-compose.secrets.example.yml.
RBAC ومصادقة API¶
مع API_SECRET، كل /api/* ما عدا GET /api/health و GET /api/v1/health يتطلب مفتاح API. API_ROLE:
| الدور | الصلاحيات |
|---|---|
| admin | إعدادات، CRUD مكدسات tenant، scan/watch، translate، meta و history |
| scanner | scan/watch/validate، translate، meta و history |
| viewer | قراءة meta و history — بدون scan |
| auditor | history/trends و meta — بدون scan أو تغيير مكدسات |
الافتراضي admin. viewer على POST /api/scan يحصل 403 { "code": "FORBIDDEN" }. اجمع RBAC مع تعدد المستأجرين على منصات مشتركة.
حزمة تدقيق الأمن¶
لمراجعات المؤسسات وGRC (#259):
| المستند | الغرض |
|---|---|
docs/security/THREAT_MODEL.md |
نموذج تهديد STRIDE-lite |
docs/security/DEPENDENCY_AUDIT.md |
إجراء تدقيق التبعيات |
docs/self-hosted/SECRETS.md |
تدوير API_SECRET + API_SECRET_PREVIOUS بدون انقطاع |
SECURITY.md |
OIDC وSAML عبر federation إلى OIDC (بدون SP أصلي؛ ADR 007) |
إشعارات watch¶
يحتاج مشغّلو self-host غالباً تنبيهات out-of-band عند اكتشاف CVE جديدة في watch المجدول. CVE Radar يرسل إشعارات الخادم بشكل غير متزامن بعد POST /api/watch مع newVulns غير فارغ — دون تغيير استجابة HTTP.
| القناة | env الأساسية |
|---|---|
| Slack | NOTIFICATION_SLACK_WEBHOOK_URL أو legacy ALERT_WEBHOOK_URL |
| Discord | NOTIFICATION_DISCORD_WEBHOOK_URL |
| Telegram | NOTIFICATION_TELEGRAM_BOT_TOKEN, NOTIFICATION_TELEGRAM_CHAT_ID |
| بريد SMTP | NOTIFICATION_SMTP_HOST, FROM, TO; اختياري PORT, USER, PASS |
| webhook عام | NOTIFICATION_WEBHOOK_URL |
| التحكم | env | الافتراضي |
|---|---|---|
| الحد الأدنى للخطورة | NOTIFICATION_MIN_SEVERITY أو ALERT_MIN_SEVERITY |
HIGH |
| نافذة dedup (ms) | NOTIFICATION_DEDUP_MS |
900000 |
| تنسيق Slack | ALERT_WEBHOOK_FORMAT |
slack أو generic |
ALERT_WEBHOOK_URL القديم ما زال يعمل عبر NotificationService. NOTIFICATION_* يدعم mounts *_FILE — أو استخدم env من المنصة أو env file غير مُلتزَم. تحقق: GET /api/health?detailed=true → alerts.webhookConfigured. راجع التنبيهات و NOTIFICATIONS.md.
تعدد المستأجرين (PostgreSQL)¶
DATABASE_URL=postgres://cve_radar:cve_radar@127.0.0.1:5432/cve_radar
تُشغَّل migrations عند أول اتصال pool. تعريفات schema في server/db/schema.ts (Drizzle ORM) للمهاجرة التدريجية؛ استعلامات runtime لـ tenant/stack وscan-history تستخدم Drizzle عبر getDb() (pool pg المشترك).
X-Tenant-Id: arvancloud-sre
| Method | Path | الوصف |
|---|---|---|
POST |
/api/v1/tenants |
إنشاء tenant |
GET |
/api/v1/tenants/stacks |
قائمة المكدسات |
POST |
/api/v1/tenants/stacks |
إنشاء مكدس |
GET |
/api/v1/tenants/stacks/:id |
مكدس بالمعرّف |
PUT |
/api/v1/tenants/stacks/:id |
تحديث |
DELETE |
/api/v1/tenants/stacks/:id |
حذف |
GET |
/api/v1/scans/history |
history للمستأجر |
GET |
/api/v1/scans/trends |
trends للمستأجر |
history و trends محدودة بـ tenant_id. بدون DATABASE_URL يبقى التطبيق single-tenant.
إذا أُرسل X-Tenant-Id بصيغة غير صالحة، يعيد API 400 TENANT_SLUG_INVALID — ولا يعود صامتاً إلى default.
قائمة تعدد المستأجرين¶
| الموضوع | السلوك |
|---|---|
| عزل البيانات | SQL بـ WHERE tenant_id = … للمكدسات والhistory وتفضيلات الإشعار. |
| التحقق من header | slug صالح عند الإرسال؛ slug غير معروف → 404 TENANT_NOT_FOUND. |
| slugs محجوزة | default, system, admin, root, postgres, public ممنوعة عند إنشاء tenant (409 TENANT_SLUG_RESERVED). |
| Auth / RBAC | API_SECRET وOIDC اختياري؛ مسارات admin tenant تتطلب دور admin. |
| حدود المعدل | scan/watch لكل IP + tenant على v1. |
| Audit | سطور audit تتضمن tenant؛ GET /api/v1/audit للمستأجر الحالي فقط. |
| الإشعارات | تفضيلات وwebhooks لكل tenant مع X-Tenant-Id؛ dedup يتضمن slug. |
| مسارات legacy | /api/* بدون إصدار يكتب history تحت default. |
| Health | GET /api/health?detailed=true → database.multiTenant؛ capabilities → features.multiTenant. |
Docker Compose: docker compose --profile postgres up -d مع DATABASE_URL (راجع TENANTS.md).
Prometheus و Grafana¶
GET /metrics. METRICS_ENABLED (افتراضي true)، METRICS_PROTECT للمصادقة.
| المقياس | النوع | الوصف |
|---|---|---|
cve_radar_scans_total |
counter | طلبات scan/watch |
cve_radar_vulns_found |
gauge | من آخر scan ناجح |
cve_radar_scan_duration_seconds |
histogram | مدة المعالج |
cve_radar_source_reachable |
gauge | وصول upstream |
cve_radar_mirror_age_days |
gauge | mirror |
cve_radar_cache_entries_total |
gauge | حجم cache |
لوحة Grafana: docs/self-hosted/grafana/cve-radar-dashboard.json.
sum(rate(cve_radar_scans_total{status="success"}[5m]))
/ sum(rate(cve_radar_scans_total[5m]))
نشر airgap¶
AIRGAPPED=true
NVD_MIRROR_URL=http://internal-mirror/nvd
KEV_MIRROR_URL=http://internal-mirror/kev/catalog.json
# OSV — mirror أو bulk:
OSV_MIRROR_URL=http://internal-mirror/osv
# OSV_BULK_PATH=/data/osv/extracted
# MIRROR_MANIFEST_PATH=/data/mirrors/.mirror-manifest.json
# MIRROR_STALE_DAYS=7
مع OSV_BULK_PATH تقرأ عمليات OSV من JSON محلي (npm run mirrors:sync / make sync-osv-bulk) بدل API query. GitHub و RSS وترجمة خارجية تُتخطى. env mirror مفقود لـ NVD/KEV → fail-closed.
curl -s 'http://localhost:3001/api/health?detailed=true' | jq '.airgap.mirrorHealth'
الشريط الجانبي يعرض تحذير mirror قديم عند تجاوز MIRROR_STALE_DAYS (افتراضي 7). Prometheus: cve_radar_mirror_age_days.
مزامنة المرآة (منطقة الإنترنت)¶
npm run mirrors:sync (أو make mirrors-sync) يحمّل KEV وصفحات NVD 2.0 (MIRROR_NVD_DAYS) و bulk OSV مع manifest و SHA256. اضبط MIRROR_MANIFEST_PATH على المضيف المعزول. RPO/RTO والحجم: docs/self-hosted/AIRGAP.md.
| العلم | التأثير |
|---|---|
MIRROR_SKIP_NVD=true |
KEV + OSV فقط |
MIRROR_SKIP_OSV=true |
NVD + KEV فقط |
MIRROR_SKIP_KEV=true |
NVD + OSV فقط |
CI يتحقق من عينات JSON عبر schemas/airgap/*.json (npm run check:airgap-schemas).
Helm chart¶
المخطط الرسمي: charts/cve-radar/. Deployment و Service و Ingress اختياري و Redis و Postgres اختياري و PVC لـ /app/data و mounts Secret عبر env *_FILE.
helm install cve-radar ./charts/cve-radar -n cve-radar --create-namespace
راجع docs/self-hosted/HELM.md.
Kubernetes Operator (CVEScanStack)¶
Operator v0 يُوازِن موارد CVEScanStack إلى CronJob للوكيل والمراقبة. مجموعة CRD: cve-radar.io/v1alpha1؛ manifests في deploy/k8s/operator/. التشغيل داخل الكلuster: npm run operator:run — docs/self-hosted/OPERATOR.md.
kubectl apply -f deploy/k8s/operator/crd-cvescanstack.yaml
kubectl apply -f deploy/k8s/operator/rbac.yaml
kubectl apply -f deploy/k8s/operator/deployment.yaml
كل CVEScanStack يحدد stack وapiKeySecretRef وtenantId اختياري وجداول cron للاستيراد والمراقبة. #254.
worker مهام المسح (BullMQ)¶
عند ضبط REDIS_URL، شغّل worker منفصلاً بجانب API: npm run worker:run (صورة الإنتاج: node dist-server/server/worker/run.js). يقبل API POST /api/v1/scan/queue؛ يستطلع العملاء GET /api/v1/jobs/:id ويجلبون النتائج المقسمة من GET /api/v1/jobs/:id/results. تنتقل Web UI إلى قائمة + استطلاع عندما يُبلغ /api/capabilities عن features.jobQueue: true. بدون Redis تبقى المسوحات متزامنة (POST /api/v1/scan/stream). #257.
REDIS_URL=redis://127.0.0.1:6379 npm run worker:run
وكيل المسح (Trivy / Grype)¶
POST /api/v1/scans/import لاستيراد JSON من Trivy/Grype. CLI: npm run agent:scan. مثال CronJob: deploy/k8s/agent-scan-cronjob.example.yaml. docs/self-hosted/AGENT.md.
اكتشاف Kubernetes¶
K8S_DISCOVERY_ENABLED=true
# K8S_DISCOVERY_NAMESPACES=production,staging
GET /api/v1/discovery/kubernetes — يتطلب auth في الإنتاج. عند التعطيل 503 K8S_DISCOVERY_DISABLED.
{
"enabled": true,
"images": ["haproxy", "nginx", "redis"],
"tools": ["HAProxy", "Nginx", "Redis"],
"unmapped": ["my-sidecar"]
}
ServiceAccount للقراءة فقط على deployments. اجمع مع عزل tenant.
مرجع سريع¶
| الموضوع | env |
|---|---|
| Audit | AUDIT_HEALTH, TRUST_PROXY_HOPS |
| Secrets | mount *_FILE |
| RBAC | API_SECRET, API_ROLE |
| إشعارات | NOTIFICATION_*, ALERT_WEBHOOK_URL |
| Tenant | DATABASE_URL, X-Tenant-Id |
| Metrics | METRICS_ENABLED, METRICS_PROTECT |
| Airgap | AIRGAPPED, *_MIRROR_URL, OSV_BULK_PATH, MIRROR_MANIFEST_PATH, MIRROR_STALE_DAYS |
| K8s | K8S_DISCOVERY_ENABLED, K8S_DISCOVERY_NAMESPACES |
| Enrichment | EPSS_ENABLED, COMPLIANCE_ENABLED |
نسخة maintainer: docs/self-hosted/.