Merge branch 'main' into claude/phase1-infra-implementation-01VHNw75vk54cfUEFXYYtK9P

This commit is contained in:
Alexa Amundson
2025-11-17 20:54:57 -06:00
committed by GitHub
7 changed files with 1837 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
name: Sync Cloudflare DNS
on:
push:
paths:
- 'ops/domains.yaml'
branches:
- main
workflow_dispatch: # Allow manual triggers
jobs:
sync-dns:
name: Sync DNS Records to Cloudflare
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'
- name: Install dependencies
run: |
pip install -r scripts/cloudflare/requirements.txt
- name: Validate domains.yaml
run: |
python -c "import yaml; yaml.safe_load(open('ops/domains.yaml'))"
- name: Sync DNS records (dry run)
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
run: |
python scripts/cloudflare/sync_dns.py --dry-run
- name: Sync DNS records
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
run: |
python scripts/cloudflare/sync_dns.py
- name: Validate DNS configuration
run: |
python scripts/cloudflare/validate_dns.py --domain blackroad.systems --dns-only
continue-on-error: true # Don't fail if DNS hasn't propagated yet
- name: Comment on commit (if manual trigger)
if: github.event_name == 'workflow_dispatch'
uses: actions/github-script@v7
with:
script: |
github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha,
body: '✅ Cloudflare DNS sync completed successfully!'
})

View File

@@ -57,7 +57,12 @@ RAILWAY_ENVIRONMENT_ID=00000000-0000-0000-0000-000000000000
RAILWAY_DOMAIN=your-service.up.railway.app RAILWAY_DOMAIN=your-service.up.railway.app
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ SLACK_WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/XXX/YYY DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/XXX/YYY
# Cloudflare DNS and CDN
CLOUDFLARE_API_TOKEN=cloudflare-api-token-placeholder CLOUDFLARE_API_TOKEN=cloudflare-api-token-placeholder
CLOUDFLARE_ACCOUNT_ID=your-cloudflare-account-id
CLOUDFLARE_ZONE_ID=your-cloudflare-zone-id-for-blackroad-systems
CLOUDFLARE_EMAIL=your-cloudflare-email@example.com
# Optional cloud/API integrations # Optional cloud/API integrations
DIGITAL_OCEAN_API_KEY=your-digital-ocean-api-key DIGITAL_OCEAN_API_KEY=your-digital-ocean-api-key

View File

@@ -0,0 +1,770 @@
# Cloudflare DNS Migration Guide
## Complete Step-by-Step Guide for BlackRoad Domains
**Version:** 1.0
**Date:** 2025-11-18
**Estimated Time:** 2-4 hours for all domains
**Skill Level:** Intermediate
---
## Overview
This guide walks you through migrating BlackRoad domains from GoDaddy DNS to Cloudflare DNS. The migration provides:
-**Free SSL certificates** (automatic renewal)
-**Global CDN** (faster page loads worldwide)
-**DDoS protection** (automatic threat mitigation)
-**Better DNS performance** (anycast network)
-**Advanced features** (Workers, Zero Trust, edge functions)
-**Superior analytics** (traffic insights, security events)
**What you'll need:**
- Cloudflare account (free tier is sufficient)
- GoDaddy account with domain access
- 2-4 hours of time
- Basic command line familiarity (optional, for automation)
---
## Table of Contents
1. [Pre-Migration Checklist](#pre-migration-checklist)
2. [Phase 1: Set Up Cloudflare Account](#phase-1-set-up-cloudflare-account)
3. [Phase 2: Add Domains to Cloudflare](#phase-2-add-domains-to-cloudflare)
4. [Phase 3: Update Nameservers at GoDaddy](#phase-3-update-nameservers-at-godaddy)
5. [Phase 4: Configure DNS Records](#phase-4-configure-dns-records)
6. [Phase 5: Configure SSL/TLS](#phase-5-configure-ssltls)
7. [Phase 6: Optimize Performance](#phase-6-optimize-performance)
8. [Phase 7: Verify Migration](#phase-7-verify-migration)
9. [Phase 8: Automation Setup (Optional)](#phase-8-automation-setup-optional)
10. [Troubleshooting](#troubleshooting)
11. [Rollback Plan](#rollback-plan)
---
## Pre-Migration Checklist
Before starting, gather this information:
- [ ] **GoDaddy credentials** - Username and password
- [ ] **Current DNS records** - Document existing configuration
- [ ] **Email access** - For Cloudflare verification
- [ ] **Railway hostname** - Your production app URL (e.g., `your-app.up.railway.app`)
- [ ] **Current uptime** - Note if services are running properly
**⚠️ Important Notes:**
- Migration happens with **zero downtime** if done correctly
- DNS propagation takes 5-60 minutes (sometimes up to 24 hours)
- Keep GoDaddy account active (domain registration stays there)
- Only DNS management moves to Cloudflare
---
## Phase 1: Set Up Cloudflare Account
### Step 1.1: Create Cloudflare Account
1. Go to [https://dash.cloudflare.com/sign-up](https://dash.cloudflare.com/sign-up)
2. Enter your email address
3. Create a strong password
4. Verify your email address
### Step 1.2: Two-Factor Authentication (Recommended)
1. Click on your profile (top right)
2. Go to **My Profile****Authentication**
3. Enable **Two-Factor Authentication**
4. Save backup codes in a secure location
### Step 1.3: Get API Token
1. Go to **My Profile****API Tokens**
2. Click **Create Token**
3. Select **Edit zone DNS** template
4. Configure permissions:
- **Zone - DNS - Edit**
- **Zone - Zone - Read**
5. Select **Specific zones** → (you'll add zones in Phase 2)
6. Click **Continue to summary****Create Token**
7. **Copy the token immediately** (you won't see it again!)
8. Save it securely (we'll use it later for automation)
---
## Phase 2: Add Domains to Cloudflare
We'll start with the primary domain (`blackroad.systems`) and then add others.
### Step 2.1: Add blackroad.systems
1. From Cloudflare dashboard, click **Add a site**
2. Enter: `blackroad.systems`
3. Click **Add site**
4. Select **Free plan** → Click **Continue**
5. Cloudflare will scan existing DNS records from GoDaddy
6. Wait 30-60 seconds for scan to complete
### Step 2.2: Review Scanned Records
Cloudflare should detect existing records. Review them:
- ✅ Check for A records pointing to your server
- ✅ Check for CNAME records
- ✅ Check for MX records (email)
- ✅ Check for TXT records (SPF, verification)
**Common issues:**
- Some records might be missing → We'll add them manually later
- TTL values might be high → We'll adjust them
### Step 2.3: Get Nameservers
After scanning, Cloudflare will show 2 nameservers like:
```
aaaa.ns.cloudflare.com
bbbb.ns.cloudflare.com
```
**⚠️ IMPORTANT:** Copy these nameservers! You'll need them in Phase 3.
**Don't click "Done" yet** - we'll do that after updating nameservers at GoDaddy.
---
## Phase 3: Update Nameservers at GoDaddy
**⏰ Estimated Time:** 10 minutes + 5-60 minutes propagation
### Step 3.1: Log in to GoDaddy
1. Go to [https://account.godaddy.com](https://account.godaddy.com)
2. Sign in with your credentials
3. Go to **My Products****Domains**
### Step 3.2: Update Nameservers for blackroad.systems
1. Find `blackroad.systems` in your domain list
2. Click the three dots (...) → **Manage DNS**
3. Scroll down to **Nameservers** section
4. Click **Change** → Select **Enter my own nameservers (advanced)**
5. Remove existing nameservers
6. Add the 2 Cloudflare nameservers from Phase 2, Step 2.3:
```
aaaa.ns.cloudflare.com
bbbb.ns.cloudflare.com
```
7. Click **Save**
8. Confirm the change
**What happens now:**
- GoDaddy will propagate the nameserver change
- This takes 5-60 minutes (sometimes up to 24 hours)
- Your site will continue working during this time
### Step 3.3: Return to Cloudflare
1. Go back to Cloudflare dashboard
2. Click **Done, check nameservers**
3. Cloudflare will start checking for nameserver changes
4. You'll see status: **Pending Nameserver Update**
**⏳ Wait time:** 5-60 minutes for Cloudflare to detect the change
You can check status by:
- Refreshing the Cloudflare dashboard
- Running: `dig NS blackroad.systems` (should show Cloudflare nameservers)
- Using: [https://dnschecker.org](https://dnschecker.org)
---
## Phase 4: Configure DNS Records
Once Cloudflare shows **Active** status, configure DNS records.
### Step 4.1: Verify Existing Records
1. In Cloudflare dashboard, go to **DNS** → **Records**
2. Review scanned records
3. Remove any incorrect or outdated records
### Step 4.2: Add/Update Primary Records
#### Root Domain (blackroad.systems)
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | @ | `your-app.up.railway.app` | ✅ Proxied | Auto |
**Steps:**
1. Click **Add record**
2. Type: **CNAME**
3. Name: **@** (represents root domain)
4. Target: **your-railway-app.up.railway.app** (replace with actual Railway URL)
5. Proxy status: **Proxied** (orange cloud icon)
6. TTL: **Auto**
7. Click **Save**
#### WWW Subdomain
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | www | blackroad.systems | ✅ Proxied | Auto |
**Steps:**
1. Click **Add record**
2. Type: **CNAME**
3. Name: **www**
4. Target: **blackroad.systems**
5. Proxy status: **Proxied**
6. Click **Save**
#### API Subdomain
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | api | `your-app.up.railway.app` | ✅ Proxied | Auto |
#### OS Subdomain
| Type | Name | Target | Proxy | TTL |
|------|------|--------|-------|-----|
| CNAME | os | blackroad.systems | ✅ Proxied | Auto |
### Step 4.3: Configure Email Records (If Applicable)
If you use Google Workspace, G Suite, or custom email:
#### SPF Record
| Type | Name | Content | TTL |
|------|------|---------|-----|
| TXT | @ | `v=spf1 include:_spf.google.com ~all` | Auto |
#### MX Records
| Type | Name | Content | Priority | TTL |
|------|------|---------|----------|-----|
| MX | @ | aspmx.l.google.com | 1 | Auto |
| MX | @ | alt1.aspmx.l.google.com | 5 | Auto |
| MX | @ | alt2.aspmx.l.google.com | 5 | Auto |
### Step 4.4: Verify Records
```bash
# Check DNS resolution
dig blackroad.systems
dig www.blackroad.systems
dig api.blackroad.systems
# Or use Cloudflare dashboard DNS checker
```
---
## Phase 5: Configure SSL/TLS
### Step 5.1: Set Encryption Mode
1. In Cloudflare dashboard, go to **SSL/TLS**
2. Set **Encryption mode** to **Full (strict)**
- This ensures encryption between Cloudflare and Railway
- Railway automatically provides SSL certificates
**⚠️ Important:** Do NOT use "Flexible" mode (insecure)
### Step 5.2: Enable Always Use HTTPS
1. Go to **SSL/TLS** → **Edge Certificates**
2. Enable **Always Use HTTPS**
- This redirects all HTTP traffic to HTTPS
3. Enable **Automatic HTTPS Rewrites**
- Fixes mixed content warnings
### Step 5.3: Enable HSTS (Optional but Recommended)
1. Still in **Edge Certificates**
2. Enable **HTTP Strict Transport Security (HSTS)**
3. Configuration:
- **Max Age:** 6 months (15768000 seconds)
- **Include subdomains:** ✅ Enabled
- **Preload:** ❌ Disabled (enable later when stable)
- **No-Sniff header:** ✅ Enabled
**⚠️ Warning:** HSTS is irreversible for the max-age period. Only enable when confident.
### Step 5.4: Enable TLS 1.3
1. Go to **SSL/TLS** → **Edge Certificates**
2. **Minimum TLS Version:** Set to **TLS 1.2** (or 1.3 if supported)
3. **TLS 1.3:** ✅ Enabled
### Step 5.5: Verify SSL Configuration
1. Visit: `https://blackroad.systems`
2. Click the padlock icon in browser
3. Verify certificate is valid and issued by Cloudflare
4. Check expiry date (should auto-renew)
**Test with SSL Labs:**
```
https://www.ssllabs.com/ssltest/analyze.html?d=blackroad.systems
```
---
## Phase 6: Optimize Performance
### Step 6.1: Configure Caching
1. Go to **Caching** → **Configuration**
2. **Caching Level:** Standard
3. **Browser Cache TTL:** Respect Existing Headers
### Step 6.2: Enable Auto Minify
1. Go to **Speed** → **Optimization**
2. Enable **Auto Minify**:
- ✅ JavaScript
- ✅ CSS
- ✅ HTML
### Step 6.3: Enable Brotli Compression
1. Still in **Speed** → **Optimization**
2. Enable **Brotli** compression (better than gzip)
### Step 6.4: Create Page Rules
1. Go to **Rules** → **Page Rules**
2. Create rule for API bypass:
**Rule 1: API Cache Bypass**
```
URL: *blackroad.systems/api/*
Settings:
- Cache Level: Bypass
```
**Rule 2: WWW Redirect**
```
URL: www.blackroad.systems/*
Settings:
- Forwarding URL: 301 redirect to https://blackroad.systems/$1
```
**Note:** Free plan allows 3 page rules. Use them wisely!
---
## Phase 7: Verify Migration
### Step 7.1: DNS Verification
```bash
# Check DNS propagation
dig blackroad.systems
# Check with multiple tools
dig @8.8.8.8 blackroad.systems
dig @1.1.1.1 blackroad.systems
# Or use online tool
# https://dnschecker.org
```
**Expected results:**
- Should resolve to Cloudflare IP addresses
- CNAME records should point to Railway
- Nameservers should be Cloudflare
### Step 7.2: HTTP/HTTPS Verification
```bash
# Test HTTP → HTTPS redirect
curl -I http://blackroad.systems
# Should return: 301 Moved Permanently
# Location: https://blackroad.systems/
# Test HTTPS
curl -I https://blackroad.systems
# Should return: 200 OK
# Test WWW → apex redirect
curl -I https://www.blackroad.systems
# Should redirect to https://blackroad.systems
```
### Step 7.3: SSL Certificate Check
```bash
# Check SSL certificate
openssl s_client -connect blackroad.systems:443 -servername blackroad.systems
# Look for:
# - Issuer: Cloudflare
# - Valid dates
# - No errors
```
### Step 7.4: Application Functionality
1. Visit `https://blackroad.systems`
2. Test all major features:
- [ ] Page loads correctly
- [ ] No mixed content warnings
- [ ] API calls work
- [ ] Authentication works
- [ ] Static assets load (CSS, JS, images)
### Step 7.5: Automated Validation
```bash
# Use the validation script
cd /path/to/BlackRoad-Operating-System
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
# This checks:
# - DNS resolution
# - SSL certificate validity
# - HTTP accessibility
# - Redirect configuration
```
---
## Phase 8: Automation Setup (Optional)
### Step 8.1: Install Script Dependencies
```bash
# Navigate to project
cd /path/to/BlackRoad-Operating-System
# Install Python dependencies
pip install -r scripts/cloudflare/requirements.txt
```
### Step 8.2: Set Up Environment Variables
```bash
# Create .env file (DO NOT COMMIT)
cat >> .env << EOF
CF_API_TOKEN=your-cloudflare-api-token
CF_ZONE_ID=your-zone-id
EOF
# Or add to shell profile
echo 'export CF_API_TOKEN="your-token"' >> ~/.bashrc
echo 'export CF_ZONE_ID="your-zone-id"' >> ~/.bashrc
source ~/.bashrc
```
### Step 8.3: Update domains.yaml
Edit `ops/domains.yaml` to reflect your Cloudflare configuration:
```yaml
domains:
- name: "blackroad.systems"
type: "root"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "your-actual-railway-app.up.railway.app"
proxied: true
- name: "blackroad.ai"
type: "root"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "blackroad.systems"
proxied: true
```
### Step 8.4: Test Automation
```bash
# Dry run (shows what would change)
python scripts/cloudflare/sync_dns.py --dry-run
# Apply changes
python scripts/cloudflare/sync_dns.py
# Validate
python scripts/cloudflare/validate_dns.py --all
```
### Step 8.5: Set Up GitHub Actions (Optional)
Add secrets to GitHub:
```bash
gh secret set CF_API_TOKEN
gh secret set CF_ZONE_ID
```
Create workflow file (`.github/workflows/sync-cloudflare-dns.yml`):
```yaml
name: Sync Cloudflare DNS
on:
push:
paths:
- 'ops/domains.yaml'
branches:
- main
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.10'
- run: pip install -r scripts/cloudflare/requirements.txt
- run: python scripts/cloudflare/sync_dns.py
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
```
---
## Troubleshooting
### Issue: DNS Not Resolving
**Symptoms:** `dig blackroad.systems` returns no results
**Causes:**
- Nameservers not updated at GoDaddy
- DNS propagation not complete
- Records not configured in Cloudflare
**Solutions:**
1. Check nameservers at GoDaddy
2. Wait 5-60 minutes for propagation
3. Check Cloudflare zone status (should be "Active")
4. Verify DNS records exist in Cloudflare
### Issue: SSL Certificate Errors
**Symptoms:** Browser shows "Not Secure" or certificate warning
**Causes:**
- SSL/TLS mode incorrect
- Railway app doesn't have valid certificate
- Certificate provisioning in progress
**Solutions:**
1. Set SSL/TLS mode to "Full (strict)"
2. Verify Railway app has SSL
3. Wait 5-10 minutes for certificate provisioning
4. Clear browser cache and retry
### Issue: Site Not Loading (403/502 Errors)
**Symptoms:** Site returns 403 Forbidden or 502 Bad Gateway
**Causes:**
- Railway app not running
- Incorrect CNAME target
- Cloudflare firewall blocking
**Solutions:**
1. Check Railway app status and logs
2. Verify CNAME points to correct Railway URL
3. Check Cloudflare firewall rules
4. Disable Cloudflare proxy temporarily (DNS-only) to test
### Issue: Mixed Content Warnings
**Symptoms:** Some assets load as insecure (http://)
**Causes:**
- Hard-coded HTTP URLs in code
- External resources using HTTP
**Solutions:**
1. Enable "Automatic HTTPS Rewrites" in Cloudflare
2. Update hard-coded URLs to HTTPS
3. Use protocol-relative URLs: `//example.com/asset.js`
### Issue: Email Not Working
**Symptoms:** Emails not sending/receiving
**Causes:**
- MX records not migrated
- SPF/DKIM records missing
**Solutions:**
1. Add MX records in Cloudflare (from Phase 4.3)
2. Add SPF TXT record
3. Add DKIM records if using custom email
4. Verify with: `dig MX blackroad.systems`
---
## Rollback Plan
If you need to revert to GoDaddy DNS:
### Quick Rollback
1. Go to GoDaddy → Domains → blackroad.systems
2. Nameservers → Change to **GoDaddy defaults**
3. Wait 5-60 minutes for propagation
4. Site will revert to GoDaddy DNS
**⚠️ Note:** You can keep the Cloudflare account and try again later.
### Gradual Rollback
If experiencing issues but want to keep trying:
1. In Cloudflare, change proxy status to **DNS Only** (gray cloud)
2. This bypasses Cloudflare's proxy but keeps DNS
3. Troubleshoot issues
4. Re-enable proxy when fixed
---
## Next Steps After Migration
### For All Remaining Domains
Repeat the process for:
- blackroad.ai
- blackroad.network
- blackroad.me
- lucidia.earth
- aliceqi.com
- blackroadqi.com
- roadwallet.com
- aliceos.io
- blackroadquantum.com
**Pro tip:** After doing blackroad.systems, the others are easier!
### Monitoring and Maintenance
1. **Set up monitoring:**
- Uptime monitoring (UptimeRobot, Pingdom)
- SSL certificate expiry monitoring
- Performance monitoring (Cloudflare Analytics)
2. **Review quarterly:**
- DNS records (remove unused)
- Page rules and caching
- Security settings
- Analytics and performance
3. **Stay updated:**
- Review Cloudflare changelog
- Test new features in sandbox
- Keep API tokens rotated
---
## Migration Checklist
Use this to track your progress:
### Pre-Migration
- [ ] GoDaddy credentials ready
- [ ] Current DNS records documented
- [ ] Railway hostname confirmed
- [ ] Cloudflare account created
### Cloudflare Setup
- [ ] API token generated and saved
- [ ] Domain added to Cloudflare
- [ ] DNS records scanned
- [ ] Nameservers noted
### GoDaddy Update
- [ ] Nameservers updated at GoDaddy
- [ ] Change confirmed
- [ ] Propagation completed (zone shows "Active")
### DNS Configuration
- [ ] Root domain CNAME added
- [ ] WWW subdomain added
- [ ] API subdomain added
- [ ] OS subdomain added
- [ ] Email records added (if applicable)
### SSL/TLS
- [ ] Encryption mode set to Full (strict)
- [ ] Always Use HTTPS enabled
- [ ] Automatic HTTPS Rewrites enabled
- [ ] HSTS configured (optional)
- [ ] TLS 1.3 enabled
### Performance
- [ ] Auto Minify enabled
- [ ] Brotli compression enabled
- [ ] Page rules configured
- [ ] Caching configured
### Verification
- [ ] DNS resolution verified
- [ ] SSL certificate valid
- [ ] HTTP → HTTPS redirect working
- [ ] WWW → apex redirect working
- [ ] Site accessible and functional
- [ ] API endpoints working
- [ ] Email working (if applicable)
### Automation (Optional)
- [ ] Python dependencies installed
- [ ] Environment variables set
- [ ] domains.yaml updated
- [ ] Automation scripts tested
- [ ] GitHub Actions configured (optional)
---
## Resources
### Documentation
- [Cloudflare DNS Blueprint](../infra/cloudflare/CLOUDFLARE_DNS_BLUEPRINT.md)
- [Scripts README](../scripts/cloudflare/README.md)
- [Domain Configuration](../ops/domains.yaml)
### External Links
- [Cloudflare Dashboard](https://dash.cloudflare.com)
- [Cloudflare API Docs](https://developers.cloudflare.com/api/)
- [DNS Checker Tool](https://dnschecker.org)
- [SSL Labs Test](https://www.ssllabs.com/ssltest/)
- [Railway Dashboard](https://railway.app/dashboard)
### Support
- Cloudflare Community: https://community.cloudflare.com/
- Railway Discord: https://discord.gg/railway
- BlackRoad GitHub Issues: https://github.com/blackboxprogramming/BlackRoad-Operating-System/issues
---
**Congratulations!** 🎉
You've successfully migrated to Cloudflare DNS. Your sites now benefit from:
- Global CDN and faster performance
- Free SSL with auto-renewal
- DDoS protection
- Advanced security features
- Better analytics and insights
**Questions or issues?** Check the troubleshooting section or open a GitHub issue.
---
**Last Updated:** 2025-11-18
**Maintainer:** BlackRoad DevOps Team
**Version:** 1.0

View File

@@ -0,0 +1,313 @@
# Cloudflare DNS Management Scripts
This directory contains automation scripts for managing BlackRoad domains via the Cloudflare API.
## Scripts
### `sync_dns.py`
Synchronizes DNS records from `ops/domains.yaml` to Cloudflare. Handles creating new records and updating existing ones.
**Features:**
- Automated DNS record synchronization
- Dry-run mode to preview changes
- Colored output for easy scanning
- Support for multiple record types (A, CNAME, MX, TXT)
- Automatic proxying configuration
**Usage:**
```bash
# Set environment variables
export CF_API_TOKEN="your-cloudflare-api-token"
export CF_ZONE_ID="your-zone-id"
# Preview changes (dry run)
python scripts/cloudflare/sync_dns.py --dry-run
# Apply changes
python scripts/cloudflare/sync_dns.py
# Or with command-line arguments
python scripts/cloudflare/sync_dns.py \
--token "your-token" \
--zone-id "your-zone-id" \
--zone-name "blackroad.systems"
```
### `validate_dns.py`
Validates DNS configuration and checks propagation status across the internet.
**Features:**
- DNS resolution verification
- SSL certificate validation
- HTTP/HTTPS accessibility testing
- Redirect verification (www → apex, HTTP → HTTPS)
- Support for checking multiple domains
**Usage:**
```bash
# Check single domain (default: blackroad.systems)
python scripts/cloudflare/validate_dns.py
# Check specific domain
python scripts/cloudflare/validate_dns.py --domain blackroad.ai
# Check all BlackRoad domains
python scripts/cloudflare/validate_dns.py --all
# DNS-only check (skip SSL and HTTP)
python scripts/cloudflare/validate_dns.py --dns-only
```
## Installation
### Prerequisites
- Python 3.8 or higher
- Cloudflare account with API token
- Domain(s) added to Cloudflare
### Install Dependencies
```bash
# Install required packages
pip install -r scripts/cloudflare/requirements.txt
# Or install individually
pip install requests pyyaml dnspython colorama
```
## Configuration
### Getting Cloudflare API Token
1. Log in to [Cloudflare Dashboard](https://dash.cloudflare.com)
2. Go to **My Profile****API Tokens**
3. Click **Create Token**
4. Use the **Edit zone DNS** template
5. Select the zones you want to manage
6. Create token and copy it
### Getting Zone ID
1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com)
2. Select your domain (e.g., `blackroad.systems`)
3. Scroll down to **API** section on the right sidebar
4. Copy the **Zone ID**
### Environment Variables
```bash
# Add to your shell profile (~/.bashrc, ~/.zshrc, etc.)
export CF_API_TOKEN="your-cloudflare-api-token-here"
export CF_ZONE_ID="your-zone-id-here"
# Or create a .env file (DO NOT COMMIT THIS)
echo "CF_API_TOKEN=your-token" >> .env
echo "CF_ZONE_ID=your-zone-id" >> .env
source .env
```
## Domain Configuration
DNS records are defined in `ops/domains.yaml`. Example:
```yaml
domains:
- name: "blackroad.systems"
type: "root"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "blackroad-os-production.up.railway.app"
ttl: 1 # Auto
proxied: true
- name: "api.blackroad.systems"
type: "subdomain"
provider: "cloudflare"
mode: "dns"
record:
type: "CNAME"
value: "blackroad-os-production.up.railway.app"
proxied: true
```
## Workflow
### Initial Migration
1. **Add domain to Cloudflare** (manual step via dashboard)
```
- Go to Cloudflare → Add a site
- Enter domain name
- Choose Free plan
- Follow setup wizard
```
2. **Update nameservers at registrar** (GoDaddy, etc.)
```
- Copy nameservers from Cloudflare
- Update at domain registrar
- Wait 5-60 minutes for propagation
```
3. **Configure DNS records**
```bash
# Update ops/domains.yaml with your records
# Preview changes
python scripts/cloudflare/sync_dns.py --dry-run
# Apply changes
python scripts/cloudflare/sync_dns.py
```
4. **Verify configuration**
```bash
# Check DNS propagation
python scripts/cloudflare/validate_dns.py
# Or check specific domain
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
```
### Regular Updates
When updating DNS records:
1. Edit `ops/domains.yaml`
2. Run dry-run to preview: `python scripts/cloudflare/sync_dns.py --dry-run`
3. Apply changes: `python scripts/cloudflare/sync_dns.py`
4. Validate: `python scripts/cloudflare/validate_dns.py`
## Troubleshooting
### DNS Not Resolving
**Problem:** Domain doesn't resolve
**Solutions:**
```bash
# Check DNS with dig
dig blackroad.systems
# Check with validation script
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
# Wait for propagation (5-60 minutes after nameserver change)
```
### API Authentication Errors
**Problem:** `401 Unauthorized` or `403 Forbidden`
**Solutions:**
- Verify API token is correct
- Check token has "Edit DNS" permission for the zone
- Ensure token hasn't expired
- Verify zone ID is correct
### Script Errors
**Problem:** Import errors or missing dependencies
**Solutions:**
```bash
# Install all dependencies
pip install -r scripts/cloudflare/requirements.txt
# Or install missing package
pip install <package-name>
```
### Configuration Drift
**Problem:** Cloudflare records don't match `domains.yaml`
**Solutions:**
```bash
# Run sync to update Cloudflare to match config
python scripts/cloudflare/sync_dns.py
# Or manually update records in Cloudflare dashboard
```
## Security Best Practices
1. **Never commit API tokens**
- Add `.env` to `.gitignore`
- Use environment variables
- Rotate tokens periodically
2. **Use scoped tokens**
- Create tokens with minimum required permissions
- Use zone-specific tokens when possible
- Avoid using Global API Key
3. **Audit regularly**
- Review DNS records monthly
- Check token usage in Cloudflare dashboard
- Remove unused tokens
## Integration with CI/CD
### GitHub Actions Example
```yaml
name: Sync DNS Records
on:
push:
paths:
- 'ops/domains.yaml'
branches:
- main
jobs:
sync-dns:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install dependencies
run: |
pip install -r scripts/cloudflare/requirements.txt
- name: Sync DNS records
env:
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CF_ZONE_ID: ${{ secrets.CF_ZONE_ID }}
run: |
python scripts/cloudflare/sync_dns.py
```
Add secrets to GitHub:
```bash
gh secret set CF_API_TOKEN
gh secret set CF_ZONE_ID
```
## Additional Resources
- [Cloudflare API Documentation](https://developers.cloudflare.com/api/)
- [Cloudflare DNS Documentation](https://developers.cloudflare.com/dns/)
- [DNS Blueprint](../../infra/cloudflare/CLOUDFLARE_DNS_BLUEPRINT.md)
- [Domain Configuration](../../ops/domains.yaml)
## Support
For issues or questions:
- Check the [CLOUDFLARE_DNS_BLUEPRINT.md](../../infra/cloudflare/CLOUDFLARE_DNS_BLUEPRINT.md)
- Review Cloudflare dashboard for zone status
- Check script output for error messages
- Verify API token permissions
---
**Last Updated:** 2025-11-18
**Maintained by:** BlackRoad DevOps Team

View File

@@ -0,0 +1,14 @@
# Cloudflare DNS Management Scripts Requirements
# Install with: pip install -r scripts/cloudflare/requirements.txt
# HTTP client for API requests
requests>=2.31.0
# YAML parsing for domains.yaml
PyYAML>=6.0.1
# DNS resolution verification
dnspython>=2.4.2
# Colored terminal output
colorama>=0.4.6

359
scripts/cloudflare/sync_dns.py Executable file
View File

@@ -0,0 +1,359 @@
#!/usr/bin/env python3
"""
Sync DNS records from ops/domains.yaml to Cloudflare
This script automates the migration and synchronization of DNS records
from the domain configuration file to Cloudflare. It handles:
- Creating new DNS records
- Updating existing DNS records
- Detecting and reporting configuration drift
Usage:
export CF_API_TOKEN="your-cloudflare-api-token"
export CF_ZONE_ID="your-zone-id" # For blackroad.systems
python scripts/cloudflare/sync_dns.py
Or with command-line arguments:
python scripts/cloudflare/sync_dns.py --zone-id <zone_id> --token <token>
Requirements:
pip install requests pyyaml colorama
"""
import os
import sys
import argparse
import yaml
import requests
from typing import Dict, List, Optional
from datetime import datetime
try:
from colorama import init, Fore, Style
init()
HAS_COLOR = True
except ImportError:
HAS_COLOR = False
# Fallback to no colors
class Fore:
GREEN = RED = YELLOW = CYAN = RESET = ""
class Style:
BRIGHT = RESET_ALL = ""
# Configuration
CF_API_BASE = "https://api.cloudflare.com/client/v4"
DOMAINS_FILE = "ops/domains.yaml"
def print_status(message: str, status: str = "info"):
"""Print colored status messages"""
if status == "success":
prefix = f"{Fore.GREEN}{Fore.RESET}"
elif status == "error":
prefix = f"{Fore.RED}{Fore.RESET}"
elif status == "warning":
prefix = f"{Fore.YELLOW}{Fore.RESET}"
else:
prefix = f"{Fore.CYAN}{Fore.RESET}"
print(f"{prefix} {message}")
def get_api_headers(api_token: str) -> Dict[str, str]:
"""Get headers for Cloudflare API requests"""
return {
"Authorization": f"Bearer {api_token}",
"Content-Type": "application/json"
}
def load_domains() -> Dict:
"""Load domain configuration from ops/domains.yaml"""
try:
with open(DOMAINS_FILE) as f:
return yaml.safe_load(f)
except FileNotFoundError:
print_status(f"Error: {DOMAINS_FILE} not found", "error")
sys.exit(1)
except yaml.YAMLError as e:
print_status(f"Error parsing {DOMAINS_FILE}: {e}", "error")
sys.exit(1)
def get_existing_records(zone_id: str, api_token: str) -> List[Dict]:
"""Fetch all DNS records for a zone"""
url = f"{CF_API_BASE}/zones/{zone_id}/dns_records"
headers = get_api_headers(api_token)
all_records = []
page = 1
per_page = 100
while True:
params = {"page": page, "per_page": per_page}
response = requests.get(url, headers=headers, params=params)
if response.status_code != 200:
print_status(f"Error fetching DNS records: {response.text}", "error")
sys.exit(1)
data = response.json()
if not data.get("success"):
print_status(f"API error: {data.get('errors')}", "error")
sys.exit(1)
records = data.get("result", [])
all_records.extend(records)
# Check if there are more pages
result_info = data.get("result_info", {})
if page * per_page >= result_info.get("total_count", 0):
break
page += 1
return all_records
def create_dns_record(zone_id: str, api_token: str, record: Dict) -> Dict:
"""Create a DNS record"""
url = f"{CF_API_BASE}/zones/{zone_id}/dns_records"
headers = get_api_headers(api_token)
response = requests.post(url, headers=headers, json=record)
if response.status_code not in [200, 201]:
print_status(f"Error creating DNS record: {response.text}", "error")
return None
data = response.json()
if not data.get("success"):
print_status(f"API error: {data.get('errors')}", "error")
return None
return data.get("result")
def update_dns_record(zone_id: str, api_token: str, record_id: str, record: Dict) -> Dict:
"""Update a DNS record"""
url = f"{CF_API_BASE}/zones/{zone_id}/dns_records/{record_id}"
headers = get_api_headers(api_token)
response = requests.put(url, headers=headers, json=record)
if response.status_code != 200:
print_status(f"Error updating DNS record: {response.text}", "error")
return None
data = response.json()
if not data.get("success"):
print_status(f"API error: {data.get('errors')}", "error")
return None
return data.get("result")
def normalize_record_name(name: str, zone_name: str) -> str:
"""Normalize record name for comparison
Cloudflare returns full domain names (e.g., 'blackroad.systems' or 'www.blackroad.systems')
while config may use '@' for apex or just subdomain names.
"""
if name == "@":
return zone_name
elif not name.endswith(zone_name):
return f"{name}.{zone_name}"
return name
def records_match(config_record: Dict, cf_record: Dict, zone_name: str) -> bool:
"""Check if a config record matches a Cloudflare record"""
config_name = normalize_record_name(config_record.get("name", ""), zone_name)
cf_name = cf_record.get("name", "")
return (
config_record.get("type") == cf_record.get("type") and
config_name == cf_name and
config_record.get("content") == cf_record.get("content")
)
def sync_records(zone_id: str, api_token: str, zone_name: str, dry_run: bool = False):
"""Sync DNS records from domains.yaml to Cloudflare"""
print_status(f"Starting DNS sync for zone: {zone_name}")
print_status(f"Zone ID: {zone_id}")
if dry_run:
print_status("DRY RUN MODE - No changes will be made", "warning")
# Load configuration
config = load_domains()
# Get existing records from Cloudflare
print_status("Fetching existing DNS records from Cloudflare...")
existing = get_existing_records(zone_id, api_token)
print_status(f"Found {len(existing)} existing DNS records")
# Build index of existing records
existing_index = {}
for record in existing:
key = f"{record['type']}:{record['name']}"
existing_index[key] = record
# Process domains from config
created = 0
updated = 0
skipped = 0
errors = 0
for domain in config.get("domains", []):
# Only process domains configured for Cloudflare DNS mode
if domain.get("provider") != "cloudflare" or domain.get("mode") != "dns":
continue
# Skip if no record config
if "record" not in domain:
print_status(f"Skipping {domain.get('name')}: No record configuration", "warning")
continue
# Extract domain name (handle both root and subdomain)
domain_name = domain.get("name", "")
# Build record data
record_config = domain["record"]
record_type = record_config.get("type", "CNAME")
record_value = record_config.get("value", "")
# Determine record name for Cloudflare
# For root domains matching zone name, use "@"
if domain_name == zone_name:
record_name = "@"
else:
record_name = domain_name
record_data = {
"type": record_type,
"name": record_name,
"content": record_value,
"ttl": record_config.get("ttl", 1), # 1 = Auto
"proxied": record_config.get("proxied", True)
}
# For MX records, add priority
if record_type == "MX":
record_data["priority"] = record_config.get("priority", 10)
# Build key for lookup
full_name = normalize_record_name(record_name, zone_name)
key = f"{record_type}:{full_name}"
# Check if record exists
if key in existing_index:
existing_record = existing_index[key]
# Check if update is needed
needs_update = (
existing_record.get("content") != record_value or
existing_record.get("proxied") != record_data.get("proxied")
)
if needs_update:
print_status(f"Updating: {key} -> {record_value}", "warning")
if not dry_run:
result = update_dns_record(zone_id, api_token, existing_record["id"], record_data)
if result:
updated += 1
print_status(f" Updated successfully", "success")
else:
errors += 1
else:
print_status(f" [DRY RUN] Would update", "info")
updated += 1
else:
print_status(f"Unchanged: {key}", "info")
skipped += 1
else:
# Create new record
print_status(f"Creating: {key} -> {record_value}", "warning")
if not dry_run:
result = create_dns_record(zone_id, api_token, record_data)
if result:
created += 1
print_status(f" Created successfully", "success")
else:
errors += 1
else:
print_status(f" [DRY RUN] Would create", "info")
created += 1
# Summary
print("\n" + "="*60)
print_status("DNS Sync Complete!", "success")
print("="*60)
print(f" {Fore.GREEN}Created:{Fore.RESET} {created}")
print(f" {Fore.YELLOW}Updated:{Fore.RESET} {updated}")
print(f" {Fore.CYAN}Unchanged:{Fore.RESET} {skipped}")
print(f" {Fore.RED}Errors:{Fore.RESET} {errors}")
print("="*60)
if dry_run:
print_status("This was a DRY RUN - no actual changes were made", "warning")
print_status("Run without --dry-run to apply changes", "info")
def main():
"""Main entry point"""
parser = argparse.ArgumentParser(
description="Sync DNS records from ops/domains.yaml to Cloudflare"
)
parser.add_argument(
"--token",
help="Cloudflare API token (or set CF_API_TOKEN env var)"
)
parser.add_argument(
"--zone-id",
help="Cloudflare zone ID (or set CF_ZONE_ID env var)"
)
parser.add_argument(
"--zone-name",
default="blackroad.systems",
help="Zone name (default: blackroad.systems)"
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Show what would be changed without making actual changes"
)
args = parser.parse_args()
# Get credentials
api_token = args.token or os.getenv("CF_API_TOKEN")
zone_id = args.zone_id or os.getenv("CF_ZONE_ID")
if not api_token:
print_status("Error: CF_API_TOKEN environment variable or --token argument required", "error")
print_status("Get your token at: https://dash.cloudflare.com/profile/api-tokens", "info")
sys.exit(1)
if not zone_id:
print_status("Error: CF_ZONE_ID environment variable or --zone-id argument required", "error")
print_status("Find your zone ID in the Cloudflare dashboard", "info")
sys.exit(1)
# Run sync
try:
sync_records(zone_id, api_token, args.zone_name, dry_run=args.dry_run)
except KeyboardInterrupt:
print("\n")
print_status("Interrupted by user", "warning")
sys.exit(1)
except Exception as e:
print_status(f"Unexpected error: {e}", "error")
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,313 @@
#!/usr/bin/env python3
"""
Validate DNS configuration and check propagation status
This script helps verify that DNS records have been properly configured
and propagated across the internet. It performs:
- DNS resolution checks
- SSL certificate validation
- HTTP/HTTPS accessibility tests
- Redirect verification
Usage:
python scripts/cloudflare/validate_dns.py
python scripts/cloudflare/validate_dns.py --domain blackroad.systems
python scripts/cloudflare/validate_dns.py --all # Check all domains
Requirements:
pip install requests dnspython colorama
"""
import argparse
import socket
import ssl
import sys
from datetime import datetime
from typing import List, Dict, Optional
import requests
try:
import dns.resolver
HAS_DNS = True
except ImportError:
HAS_DNS = False
print("Warning: dnspython not installed. Install with: pip install dnspython")
try:
from colorama import init, Fore, Style
init()
except ImportError:
class Fore:
GREEN = RED = YELLOW = CYAN = RESET = ""
class Style:
BRIGHT = RESET_ALL = ""
def print_status(message: str, status: str = "info"):
"""Print colored status messages"""
if status == "success":
prefix = f"{Fore.GREEN}{Fore.RESET}"
elif status == "error":
prefix = f"{Fore.RED}{Fore.RESET}"
elif status == "warning":
prefix = f"{Fore.YELLOW}{Fore.RESET}"
else:
prefix = f"{Fore.CYAN}{Fore.RESET}"
print(f"{prefix} {message}")
def check_dns_resolution(domain: str) -> Dict:
"""Check DNS resolution for a domain"""
result = {
"domain": domain,
"resolved": False,
"ip_addresses": [],
"cname": None,
"error": None
}
if not HAS_DNS:
result["error"] = "dnspython not installed"
return result
try:
resolver = dns.resolver.Resolver()
resolver.timeout = 5
resolver.lifetime = 5
# Try CNAME first
try:
cname_answers = resolver.resolve(domain, 'CNAME')
if cname_answers:
result["cname"] = str(cname_answers[0].target).rstrip('.')
print_status(f" CNAME: {result['cname']}", "info")
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
pass
# Try A record
try:
answers = resolver.resolve(domain, 'A')
result["ip_addresses"] = [str(rdata) for rdata in answers]
result["resolved"] = True
for ip in result["ip_addresses"]:
print_status(f" A: {ip}", "info")
except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN) as e:
result["error"] = str(e)
except Exception as e:
result["error"] = str(e)
return result
def check_ssl_certificate(domain: str) -> Dict:
"""Check SSL certificate for a domain"""
result = {
"domain": domain,
"valid": False,
"issuer": None,
"expires": None,
"days_remaining": None,
"error": None
}
try:
context = ssl.create_default_context()
with socket.create_connection((domain, 443), timeout=10) as sock:
with context.wrap_socket(sock, server_hostname=domain) as ssock:
cert = ssock.getpeercert()
result["issuer"] = dict(x[0] for x in cert['issuer'])
result["expires"] = cert['notAfter']
# Parse expiry date
expire_date = datetime.strptime(cert['notAfter'], '%b %d %H:%M:%S %Y %Z')
days_remaining = (expire_date - datetime.now()).days
result["days_remaining"] = days_remaining
result["valid"] = days_remaining > 0
print_status(f" Issuer: {result['issuer'].get('organizationName', 'Unknown')}", "info")
print_status(f" Expires: {result['expires']} ({days_remaining} days)",
"success" if days_remaining > 30 else "warning")
except Exception as e:
result["error"] = str(e)
return result
def check_http_accessibility(domain: str, check_redirects: bool = True) -> Dict:
"""Check HTTP/HTTPS accessibility and redirects"""
result = {
"domain": domain,
"http_accessible": False,
"https_accessible": False,
"redirects_to_https": False,
"www_redirects": False,
"status_code": None,
"error": None
}
try:
# Check HTTP -> HTTPS redirect
http_response = requests.get(f"http://{domain}", allow_redirects=True, timeout=10)
result["http_accessible"] = True
result["redirects_to_https"] = http_response.url.startswith("https://")
if result["redirects_to_https"]:
print_status(f" HTTP → HTTPS redirect: ✓", "success")
else:
print_status(f" HTTP → HTTPS redirect: ✗", "warning")
except Exception as e:
result["error"] = f"HTTP check failed: {e}"
try:
# Check HTTPS accessibility
https_response = requests.get(f"https://{domain}", timeout=10)
result["https_accessible"] = https_response.status_code == 200
result["status_code"] = https_response.status_code
if result["https_accessible"]:
print_status(f" HTTPS accessible: ✓ (Status: {https_response.status_code})", "success")
else:
print_status(f" HTTPS status: {https_response.status_code}", "warning")
except Exception as e:
if not result["error"]:
result["error"] = f"HTTPS check failed: {e}"
# Check www redirect if requested
if check_redirects and not domain.startswith("www."):
try:
www_response = requests.get(f"https://www.{domain}", allow_redirects=True, timeout=10)
result["www_redirects"] = www_response.url == f"https://{domain}/" or www_response.url == f"https://{domain}"
if result["www_redirects"]:
print_status(f" www → apex redirect: ✓", "success")
else:
print_status(f" www redirect: ✗ (goes to {www_response.url})", "warning")
except Exception as e:
print_status(f" www redirect check failed: {e}", "info")
return result
def validate_domain(domain: str, full_check: bool = True) -> bool:
"""Validate a single domain"""
print(f"\n{'='*60}")
print(f"{Style.BRIGHT}Validating: {domain}{Style.RESET_ALL}")
print(f"{'='*60}")
all_passed = True
# DNS Resolution
print(f"\n{Fore.CYAN}[1/3] DNS Resolution{Fore.RESET}")
dns_result = check_dns_resolution(domain)
if dns_result["resolved"]:
print_status(f"DNS resolved successfully", "success")
else:
print_status(f"DNS resolution failed: {dns_result.get('error', 'Unknown error')}", "error")
all_passed = False
if not full_check:
return all_passed
# SSL Certificate
print(f"\n{Fore.CYAN}[2/3] SSL Certificate{Fore.RESET}")
ssl_result = check_ssl_certificate(domain)
if ssl_result["valid"]:
print_status(f"SSL certificate is valid", "success")
else:
print_status(f"SSL certificate check failed: {ssl_result.get('error', 'Unknown error')}", "error")
all_passed = False
# HTTP Accessibility
print(f"\n{Fore.CYAN}[3/3] HTTP Accessibility{Fore.RESET}")
http_result = check_http_accessibility(domain)
if http_result["https_accessible"]:
print_status(f"Site is accessible via HTTPS", "success")
else:
print_status(f"Site accessibility check failed: {http_result.get('error', 'Unknown error')}", "error")
all_passed = False
# Summary
print(f"\n{'='*60}")
if all_passed:
print_status(f"{domain}: All checks passed! ✓", "success")
else:
print_status(f"{domain}: Some checks failed", "warning")
print(f"{'='*60}")
return all_passed
def main():
"""Main entry point"""
parser = argparse.ArgumentParser(
description="Validate DNS configuration and check propagation status"
)
parser.add_argument(
"--domain",
help="Domain to validate (default: blackroad.systems)"
)
parser.add_argument(
"--all",
action="store_true",
help="Check all BlackRoad domains"
)
parser.add_argument(
"--dns-only",
action="store_true",
help="Only check DNS resolution (skip SSL and HTTP checks)"
)
args = parser.parse_args()
# List of BlackRoad domains
all_domains = [
"blackroad.systems",
"blackroad.ai",
"blackroad.network",
"blackroad.me",
"lucidia.earth",
"aliceqi.com",
"blackroadqi.com",
"roadwallet.com",
"aliceos.io",
"blackroadquantum.com"
]
if args.all:
domains = all_domains
elif args.domain:
domains = [args.domain]
else:
domains = ["blackroad.systems"]
full_check = not args.dns_only
all_passed = True
for domain in domains:
passed = validate_domain(domain, full_check=full_check)
if not passed:
all_passed = False
# Final summary
print(f"\n{'='*60}")
print(f"{Style.BRIGHT}VALIDATION SUMMARY{Style.RESET_ALL}")
print(f"{'='*60}")
print(f"Domains checked: {len(domains)}")
if all_passed:
print_status("All validations passed!", "success")
sys.exit(0)
else:
print_status("Some validations failed", "warning")
sys.exit(1)
if __name__ == "__main__":
main()