{"id":51831347,"url":"https://github.com/askb/ha-gitops","last_synced_at":"2026-07-22T15:33:57.885Z","repository":{"id":370391547,"uuid":"1294533298","full_name":"askb/ha-gitops","owner":"askb","description":"PR-gated GitHub backup add-on for Home Assistant — every config change is a reviewable PR, validated by CI before merge. GitOps for your smart home.","archived":false,"fork":false,"pushed_at":"2026-07-09T03:28:17.000Z","size":37,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-09T04:21:49.715Z","etag":null,"topics":["backup","github-actions","gitops","home-assistant","home-automation","homeassistant-addon"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/askb.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-07-09T01:58:59.000Z","updated_at":"2026-07-09T03:28:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/askb/ha-gitops","commit_stats":null,"previous_names":["askb/ha-gitops-backup"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/askb/ha-gitops","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askb%2Fha-gitops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askb%2Fha-gitops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askb%2Fha-gitops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askb%2Fha-gitops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/askb","download_url":"https://codeload.github.com/askb/ha-gitops/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/askb%2Fha-gitops/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35768236,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-22T02:00:06.236Z","response_time":124,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["backup","github-actions","gitops","home-assistant","home-automation","homeassistant-addon"],"created_at":"2026-07-22T15:33:55.627Z","updated_at":"2026-07-22T15:33:57.872Z","avatar_url":"https://github.com/askb.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HA GitOps — Home Assistant Add-on\n\n**PR-gated GitHub backup for your Home Assistant config.** Nothing force-pushes,\nevery change is a reviewable pull request, and CI validates your config against\npinned Home Assistant versions *before* it can merge.\n\n[![Add repository to my Home Assistant](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Faskb%2Fha-gitops)\n\n[![GitHub Release](https://img.shields.io/github/v/release/askb/ha-gitops?label=release)](https://github.com/askb/ha-gitops/releases/latest)\n[![Downloads](https://img.shields.io/github/downloads/askb/ha-gitops/total?label=downloads)](https://github.com/askb/ha-gitops/releases)\n[![License](https://img.shields.io/github/license/askb/ha-gitops)](LICENSE)\n\n## Why another config-backup add-on?\n\nMost config-sync tools upload your files straight onto a branch — some even\nforce-push. That gives you a *copy*, not *control*. This add-on treats your\nconfig like production infrastructure:\n\n| | Direct-push sync tools | GitOps Config Backup |\n|---|---|---|\n| Changes land on main | Immediately, sometimes force-pushed | **Never** — every drift becomes a PR |\n| Review before accept | No | **Yes** — diff, comment, merge (or close) |\n| CI validation | No | **Yes** — HA version-matrix check **+ smoke boot** (config must actually start) gate the merge |\n| Bidirectional | Usually one-way upload | **Yes** — merged PRs flow back on the next run |\n| Secrets safety | gitignore defaults | gitignore defaults **+ CI runs with stub secrets only** |\n\n## How it works\n\n```mermaid\nflowchart LR\n    subgraph HA[\"🏠 Home Assistant box\"]\n        CFG[(\"/config\")]\n        ADDON[\"GitOps Backup add-on\u003cbr/\u003etwo-way sync, every run:\u003cbr/\u003e⬇ pull merged → ⬆ push drift\"]\n        CFG -- \"① local edits\u003cbr/\u003e(UI, HA upgrades)\" --\u003e ADDON\n        ADDON -- \"⑤ merged changes\u003cbr/\u003eapplied to /config\" --\u003e CFG\n    end\n\n    subgraph GH[\"☁️ GitHub\"]\n        BR[\"auto-backup/… branch\"]\n        PR{{\"Pull Request\"}}\n        subgraph CI[\"CI gate — must pass\"]\n            LINT[\"yamllint\"]\n            CHECK[\"HA config check\u003cbr/\u003epinned + stable matrix\"]\n            BOOT[\"HA smoke boot\u003cbr/\u003econtainer must start\"]\n        end\n        MAIN[(\"main\")]\n    end\n\n    YOU((\"👤 You / dev\u003cbr/\u003eauthor \u0026 review\"))\n\n    ADDON -- \"② drift → branch + PR\" --\u003e BR\n    BR --\u003e PR\n    YOU -- \"② or: submit config\u003cbr/\u003echange PR yourself\" --\u003e PR\n    PR --\u003e LINT \u0026 CHECK \u0026 BOOT\n    LINT \u0026 CHECK \u0026 BOOT --\u003e YOU\n    YOU -- \"③ merge\" --\u003e MAIN\n    MAIN -- \"④ pull --rebase\u003cbr/\u003eon the next run\" --\u003e ADDON\n\n    classDef box fill:#1c3a5e,stroke:#7fb3ff,color:#ffffff\n    classDef addon fill:#0d7a5f,stroke:#34c39a,color:#ffffff\n    classDef gate fill:#7a3b0d,stroke:#ffb066,color:#ffffff\n    classDef human fill:#5e1c4a,stroke:#ff7fd4,color:#ffffff\n    classDef store fill:#333d3a,stroke:#9aa5a1,color:#ffffff\n    class ADDON addon\n    class LINT,CHECK,BOOT gate\n    class YOU human\n    class CFG,MAIN,BR,PR store\n```\n\n**The loop, numbered:** ① you edit via the HA UI (or an upgrade changes files) →\n② the add-on turns that drift into a PR — or you open a config PR yourself →\n③ CI gates it, you merge → ④ the add-on's next run pulls merged `main` →\n⑤ and applies it to `/config`. Both directions go through the same run:\nit **pulls first, then pushes drift**, so box and repo converge on `main`.\n\n1. **Daily (configurable) run** on your Home Assistant box:\n   stash local drift → `pull --rebase` from `origin/main` (picks up PRs you\n   merged) → re-apply → if the live config changed, commit to a dated\n   `auto-backup/…` branch and **open a PR** via the GitHub API.\n2. **CI on the PR** (template workflows included): yamllint + full\n   `frenck/action-home-assistant` validation against a pinned HA version (with\n   a `stable` early-warning leg) **+ a smoke boot** — the pinned HA Core\n   container starts with your config and must answer HTTP with no\n   `Invalid config` — upgrade breakage surfaces in CI, not on your Pi.\n3. **You merge** (from your phone, if you like). The next add-on run rebases the\n   merged state back onto the box.\n\n## Install\n\n1. Add this repository to your Add-on store (badge above), install\n   **GitOps Config Backup**.\n2. Create a GitHub repo (private recommended) and a fine-grained PAT with\n   *Contents: read/write* and *Pull requests: read/write* on it.\n3. Configure the add-on:\n\n```yaml\ngithub_repo: you/your-ha-config\ngithub_token: github_pat_…\nbase_branch: main\nbranch_prefix: auto-backup\ninterval_hours: 24\nrun_at_start: false\ndry_run: true        # start with a dry run, check the log, then set false\nsignoff: true\n```\n\n4. Copy `template/workflows/validate-ha-config.yaml` into\n   `.github/workflows/` of your config repo, and add a stub line for every\n   `!secret` key you use (CI never sees real secrets).\n5. (Recommended) Protect `main` in the repo settings: require the\n   *HA Config Validation* check.\n\nFirst run bootstraps the git repo in `/config` (seeding a Home Assistant\n`.gitignore` covering `secrets.yaml`, `.storage/`, databases, logs) and pushes\nthe initial import; every run after that only ever opens PRs.\n\n## Status sensor (optional)\n\nThe add-on writes `.gitops_backup_status` (`status:detail:extra`) to your config\ndir. Expose it in HA:\n\n```yaml\ncommand_line:\n  - sensor:\n      name: GitOps Backup Status\n      command: \"cat /config/.gitops_backup_status 2\u003e/dev/null || echo 'unknown'\"\n      scan_interval: 3600\n```\n\n## Deploying merged changes back to the box\n\nMerged PRs are picked up automatically on the next scheduled run. To apply\nimmediately:\n\n```bash\nssh root@\u003cHA_IP\u003e 'cd /homeassistant \u0026\u0026 git fetch origin \u0026\u0026 git reset --hard origin/main'\nssh root@\u003cHA_IP\u003e 'ha core restart'\n```\n\n## Options\n\n| Option | Default | Description |\n|--------|---------|-------------|\n| `github_repo` | — | `owner/repo` to back up into (required) |\n| `github_token` | — | Fine-grained PAT (required) |\n| `base_branch` | `main` | Branch PRs target |\n| `branch_prefix` | `auto-backup` | Prefix for backup branches |\n| `interval_hours` | `24` | Hours between runs (1–168) |\n| `run_at_start` | `false` | Also run when the add-on starts |\n| `dry_run` | `false` | Log what would change; push nothing |\n| `commit_name` / `commit_email` | see config | Commit author |\n| `signoff` | `true` | Add `Signed-off-by` (DCO) to commits |\n\n## Security notes\n\n- The token lives in the add-on options (Supervisor-encrypted), never in git.\n- The seeded `.gitignore` excludes `secrets.yaml`, `.storage/`, `.cloud/`,\n  databases, logs, and the add-on's own status/log files (committing status\n  files creates a PR-per-day feedback loop — learned the hard way).\n- CI validates with **stub** secrets; your real `secrets.yaml` never leaves the box.\n- Nothing in this add-on ever force-pushes or writes to your base branch after\n  the initial bootstrap import.\n- **This is change tracking, not disaster recovery** — pair it with HA's\n  native encrypted backups + the Google Drive Backup add-on for full system\n  state (`secrets.yaml`, `.storage/`, databases, add-ons). See the add-on\n  DOCS for the full \"what is backed up where\" table and where secrets belong.\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faskb%2Fha-gitops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faskb%2Fha-gitops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faskb%2Fha-gitops/lists"}