{"id":48780369,"url":"https://github.com/dhivijit/dnsctl","last_synced_at":"2026-04-13T14:00:56.804Z","repository":{"id":341227768,"uuid":"1169359230","full_name":"dhivijit/dnsctl","owner":"dhivijit","description":"Secure, version-controlled Cloudflare DNS management","archived":false,"fork":false,"pushed_at":"2026-04-13T12:07:38.000Z","size":849,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-04-13T13:35:54.746Z","etag":null,"topics":["cli","cloudflare","desktop-app","developer-tools","dns-management","gitops","infrastructure-as-code","python"],"latest_commit_sha":null,"homepage":"http://dnsctl.dhivijit.dev/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dhivijit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-28T15:13:22.000Z","updated_at":"2026-04-13T11:55:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"8a560844-1ea9-43cc-8c54-c708ed2cf8f0","html_url":"https://github.com/dhivijit/dnsctl","commit_stats":null,"previous_names":["dhivijit/dnsctl"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/dhivijit/dnsctl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhivijit%2Fdnsctl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhivijit%2Fdnsctl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhivijit%2Fdnsctl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhivijit%2Fdnsctl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dhivijit","download_url":"https://codeload.github.com/dhivijit/dnsctl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dhivijit%2Fdnsctl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31755536,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T13:27:56.013Z","status":"ssl_error","status_checked_at":"2026-04-13T13:21:23.512Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cloudflare","desktop-app","developer-tools","dns-management","gitops","infrastructure-as-code","python"],"created_at":"2026-04-13T14:00:22.159Z","updated_at":"2026-04-13T14:00:56.785Z","avatar_url":"https://github.com/dhivijit.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"dnsctl/icon.png\" alt=\"DNSCTL Icon\" width=\"128\" height=\"128\"\u003e\n\n# DNSCTL\n\n**Secure, version-controlled DNS management for Cloudflare**\n\n[![PyPI version](https://img.shields.io/pypi/v/dnsctl-app)](https://pypi.org/project/dnsctl-app/)\n[![Python](https://img.shields.io/pypi/pyversions/dnsctl-app)](https://pypi.org/project/dnsctl-app/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-blue)](https://github.com/dhivijit/dnsctl/releases)\n\n\u003c/div\u003e\n\nDNSCTL is a local infrastructure tool for managing Cloudflare DNS records safely. It brings a Git-backed state model, drift detection, and a plan/apply workflow to DNS — so you always know what changed, when, and why.\n\nIt ships as both a **CLI** for scripting and automation, and a **GUI** for interactive use — both powered by the same reconciliation engine.\n\n---\n\n## How it works\n\n```\n1. sync     Pull live DNS records from Cloudflare into local state\n2. edit     Add, edit, or delete records locally (no live changes yet)\n3. plan     Preview exactly what will be pushed to Cloudflare\n4. apply    Push the confirmed changes\n5. history  Every change auto-committed to a local Git repo\n```\n\nNo change touches Cloudflare until you explicitly apply it.\n\n---\n\n## ✨ Features\n\n- **Drift Detection** — Spot out-of-band dashboard changes before they cause issues\n- **Plan / Apply Workflow** — Review a diff before any record is touched\n- **Git-Backed History** — Every sync and edit auto-committed; full rollback support\n- **Secure Token Storage** — AES-256-GCM encrypted, key derived via PBKDF2, stored in OS keyring\n- **Session Locking** — Token cached in memory, auto-expires after inactivity\n- **Multi-Account** — Manage multiple Cloudflare accounts; one master password unlocks all\n- **Protected Records** — System-level (NS) and user-defined guards that require `--force` to override\n- **CLI + GUI Parity** — Every feature available in both interfaces\n\n---\n\n## 📦 Installation\n\n### From PyPI (macOS / Linux / Windows)\n\n```bash\npip install dnsctl-app\n```\n\n\u003e Requires Python 3.11+ and Git.\n\u003e On Linux, ensure a keyring backend is available (e.g. `gnome-keyring` or `kwallet`).\n\n### Windows Installer\n\nDownload the bundled installer from the [Releases](https://github.com/dhivijit/dnsctl/releases) page.\nIncludes both CLI (`dnsctl.exe`) and GUI (`dnsctl-g.exe`) with all dependencies — no Python required.\n\n### From Source\n\n```bash\ngit clone https://github.com/dhivijit/dnsctl.git\ncd dnsctl\npip install -e .\n```\n\n---\n\n## 🚀 Quick Start\n\n### 1. Add your Cloudflare account\n\n```bash\ndnsctl login\n```\n\nYou'll be prompted for an account name, your Cloudflare API token, and a master password. The token is encrypted and stored in your OS keyring — never in plaintext.\n\n\n### 2. Unlock your session\n\n```bash\ndnsctl unlock\n```\n\nDecrypts the token into a short-lived session. One password unlocks all your accounts at once.\n\n### 3. Pull your DNS records\n\n```bash\ndnsctl sync\n```\n\n### 4. Make a local change\n\n```bash\ndnsctl add --type A --name staging.example.com --content 1.2.3.4\n```\n\nNothing is sent to Cloudflare yet.\n\n### 5. Review the plan\n\n```bash\ndnsctl plan\n```\n\n### 6. Apply\n\n```bash\ndnsctl apply\n```\n\n---\n\n## 🖥 GUI\n\nLaunch the graphical interface:\n\n```bash\ndnsctl-g\n```\n\n\u003cimg src=\"media/dnsctl-gui.png\" alt=\"DNSCTL GUI showing the record table for dhivijit.dev with type tabs, sync/plan controls, and drift status\" width=\"50%\"\u003e\n\u003cimg src=\"media/dnsctl-gui-plan.png\" alt=\"DNSCTL plan preview dialog showing a detected CNAME modification with apply/close controls\" width=\"46%\"\u003e\n\n\nFeatures:\n\n- Zone selector with drift status indicator\n- Record table with add / edit / delete dialogs\n- Sync, Plan, and Apply controls\n- History viewer and rollback\n- Multi-account switcher\n- Session unlock dialog\n\nThe GUI uses the same reconciliation engine as the CLI — no feature gap between them.\n\n---\n\n## 🧰 CLI Reference\n\n### Authentication\n\n```bash\ndnsctl login              # Add a Cloudflare account (encrypted)\ndnsctl unlock             # Unlock session with master password\ndnsctl lock               # Lock session manually\ndnsctl logout             # Remove stored credentials for current account\n```\n\n### Sync \u0026 Status\n\n```bash\ndnsctl sync [-z ZONE]     # Pull records from Cloudflare\ndnsctl status             # Show accounts, zones, and session state\ndnsctl diff [-z ZONE]     # Show drift between local state and Cloudflare\ndnsctl plan [-z ZONE]     # Preview what apply would push\ndnsctl apply [-z ZONE]    # Push planned changes to Cloudflare\n```\n\n### Record Management\n\n```bash\ndnsctl add  --type A --name sub.example.com --content 1.2.3.4\ndnsctl edit --type A --name sub.example.com --content 5.6.7.8\ndnsctl rm   --type A --name sub.example.com\n```\n\n### Protected Records\n\n```bash\ndnsctl protect   --type A --name example.com --reason \"Critical root record\"\ndnsctl unprotect --type A --name example.com\ndnsctl protected\n```\n\n### History \u0026 Rollback\n\n```bash\ndnsctl log\ndnsctl rollback \u003ccommit_sha\u003e\n```\n\n### Import / Export\n\n```bash\ndnsctl export [-z ZONE] [-o output.json]\ndnsctl import zone.json\n```\n\n### Account Management\n\n```bash\ndnsctl accounts list\ndnsctl accounts switch \u003calias\u003e\ndnsctl accounts remove \u003calias\u003e\n```\n\n---\n\n## 👥 Multi-Account Support\n\nDNSCTL supports multiple Cloudflare accounts side by side, each with isolated zone state.\n\n```bash\n# Add accounts\ndnsctl login                        # prompts for account name + token + password\ndnsctl login --label \"Work\"         # with explicit label\n\n# Switch between accounts\ndnsctl accounts list\ndnsctl accounts switch work\n\n# Remove an account\ndnsctl accounts remove personal\n```\n\nAll accounts share a single master password. Unlocking one automatically unlocks all others in the same session.\n\n---\n\n## 🔐 Security Model\n\n### Token storage\n\n- API token encrypted with **AES-256-GCM**\n- Encryption key derived via **PBKDF2-HMAC-SHA256** (200,000 iterations)\n- Encrypted blob stored in the **OS keyring** (Windows Credential Manager / macOS Keychain / Linux Secret Service)\n- Plaintext token held in memory only for the duration of the session, then discarded\n\n### Session\n\n- Session expires automatically after inactivity (default: 15 minutes)\n- `dnsctl lock` expires the session immediately\n- `dnsctl logout` removes all stored credentials for an account\n\n### Protected records\n\nTwo layers:\n\n1. **System-protected** — NS records are always protected\n2. **User-defined** — mark any record with `dnsctl protect`; requires `--force` to override in apply\n\n---\n\n## 🤝 Contributing\n\nPull requests are welcome. For larger changes, open an issue first to discuss the approach.\n\n```bash\ngit clone https://github.com/dhivijit/dnsctl.git\ncd dnsctl\npip install -e \".[dev]\"\npytest\n```\n\n---\n\n## 📜 License\n\nMIT License — © Dhivijit\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdhivijit%2Fdnsctl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdhivijit%2Fdnsctl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdhivijit%2Fdnsctl/lists"}