Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
01f8df2
Consume external ansible-config-wizard from deploy-core
c-wri Mar 9, 2026
e3ddb15
refactor(backup): adopt composable restic policy in core inventory
c-wri Mar 9, 2026
abd24b4
docs(backup): explain the composable restic architecture
c-wri Mar 9, 2026
6238930
Guide first-run SSH bootstrap in deploy-core wizard profile
c-wri Mar 9, 2026
a53aa23
Store deploy-core wizard artifacts outside the repo
c-wri Mar 9, 2026
1f43deb
Normalize core repo gitignore coverage
c-wri Mar 9, 2026
f502ba7
Use managed Ansible SSH identities in deploy-core wizard
c-wri Mar 9, 2026
859664f
Publish managed SSH setup commands in deploy-core pause step
c-wri Mar 9, 2026
b1e4d72
Use shared SSH setup action in deploy-core wizard
c-wri Mar 9, 2026
195a746
Clarify ACME email prompt in deploy-core wizard
c-wri Mar 9, 2026
a070879
Wire cli wizard and preflight to Obsidian access modes
c-wri Mar 9, 2026
db63bbc
Streamline private mesh wizard flow for Tailscale planning
c-wri Mar 9, 2026
30f8648
Guide restic destinations through the core wizard
c-wri Mar 9, 2026
9ed2179
Soften core wizard copy and section guidance
c-wri Mar 10, 2026
20128bc
Clarify core wizard field guidance
c-wri Mar 10, 2026
9d0f05d
Clarify Obsidian synced vault prompts
c-wri Mar 10, 2026
35ccd35
Move setup mode selection ahead of numbered steps
c-wri Mar 10, 2026
49bc952
Clarify SSH setup prompts in core wizard profile
c-wri Mar 10, 2026
d28b863
Explain restic known_hosts pinning in backup prompts
c-wri Mar 10, 2026
6148c05
Restructure backup host-key guidance in core wizard
c-wri Mar 10, 2026
b0d4d20
Wire wizard-driven backup destination bootstrap into core
c-wri Mar 10, 2026
ee5d201
Reword backup destination follow-up prompt as handoff
c-wri Mar 10, 2026
6f88c31
Declare backup follow-up choices in core wizard profile
c-wri Mar 10, 2026
345c4a7
Require explicit trust before using scanned backup host keys
c-wri Mar 10, 2026
eb53318
Use guided host-key scanning for backup target pins
c-wri Mar 10, 2026
7af1adb
Merge branch 'main' into feature/cli-wizard
c-wri Mar 10, 2026
549d1f5
Read backup private keys from local files in the CLI wizard
c-wri Mar 10, 2026
a312d8d
Add deploy and prerequisite wizard handoff options
c-wri Mar 10, 2026
7f16449
Prefer local collection checkouts during bootstrap setup
c-wri Mar 10, 2026
1745708
Cache collection installs and reuse existing state
c-wri Mar 10, 2026
75cfb91
Probe SSH interactively before backup bootstrap
c-wri Mar 10, 2026
45f94ed
Harden vault handling and restic preflight validation
c-wri Mar 10, 2026
cbf211c
Prompt for vault access mode in deploy wrappers
c-wri Mar 10, 2026
a583f42
Rename operator entrypoints and simplify lower-level runners
c-wri Mar 10, 2026
8bc939a
Document the wizard-first operator workflow
c-wri Mar 10, 2026
c1aadd1
Adopt phase/stage workflow model in core wizard profile
c-wri Mar 10, 2026
752e8c7
Refactor inventory layout and harden deployment bootstrap
c-wri Mar 10, 2026
2c46cac
Refactor preflight variable loading and tighten Tailscale validation
c-wri Mar 10, 2026
e8229ae
Harden Tailscale MagicDNS planning inputs
c-wri Mar 10, 2026
c25558d
Normalize wizard-generated restic target identifiers
c-wri Mar 10, 2026
8e38272
Validate restic target identifiers during preflight
c-wri Mar 10, 2026
778f7fd
Preserve restic target SFTP ports in wizard output
c-wri Mar 10, 2026
dea07c4
Reduce backup playbook transport overhead
c-wri Mar 10, 2026
934e6d3
Make backup converge performance policy explicit
c-wri Mar 10, 2026
3f72d21
Narrow backup scope to durable restore state
c-wri Mar 10, 2026
1c001ef
Stabilize wizard-generated restic target keys
c-wri Mar 10, 2026
88d9448
Generate Obsidian LiveSync setup URIs in wizard handoff
c-wri Mar 10, 2026
58d8cc1
fix(ci): create vault password placeholder for syntax checks
c-wri Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,29 @@ jobs:
- name: Scaffold local config
run: ./scripts/init-local-config.sh

- name: Create CI vault password placeholder
run: |
umask 177
printf 'ci-test-only\n' > .vault_pass

- name: Install collections
run: ./scripts/install-collections.sh

- name: Syntax check preflight
run: ansible-playbook --syntax-check -i inventories/prod/hosts.yml playbooks/preflight.yml

- name: Smoke test preflight placeholder validation
run: bash tests/smoke/test_preflight_placeholder_scan.sh

- name: Smoke test Tailscale tag validation
run: bash tests/smoke/test_preflight_tailscale_tag_validation.sh

- name: Smoke test builder restic target normalization
run: bash tests/smoke/test_builder_restic_target_name_normalization.sh

- name: Smoke test restic target name preflight validation
run: bash tests/smoke/test_preflight_restic_target_name_validation.sh

- name: Syntax check bootstrap
run: ansible-playbook --syntax-check -i inventories/prod/hosts.yml playbooks/bootstrap.yml

Expand Down
29 changes: 24 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
reports/
# Standard Ansible/operator-local ignores.

# Ansible runtime artifacts
.ansible/
dist/
*.retry

# Python cache from helper scripts or wizard support modules
__pycache__/
*.py[cod]

# Local packaging output
build/
dist/

# Operator-local vault password helpers
.vault_pass
.vault_pass*
vault-pass*
*.vault-password*

# Generated reports
reports/

# Real inventory values stay local; example files are versioned.
inventories/prod/hosts.yml
inventories/prod/group_vars/all.yml
inventories/prod/group_vars/core_hosts.yml
inventories/prod/group_vars/vault.yml
inventories/prod/group_vars/all/main.yml
inventories/prod/group_vars/all/vault.yml
inventories/prod/group_vars/core_hosts/main.yml
inventories/prod/*.bak-*
inventories/prod/group_vars/**/*.bak-*
51 changes: 0 additions & 51 deletions PACKAGE_SUMMARY_AT_HANDOFF.md

This file was deleted.

35 changes: 26 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This repo is the environment-facing deployment layer:

- consume the shared `crownops.deploy_base` collection for fresh-host bootstrap
- consume the shared `crownops.deploy_base` collection for staged post-join SSH lockdown
- consume the shared `crownops.deploy_services` collection for reusable service stacks and host backup automation
- consume the shared `crownops.deploy_services` collection for reusable service stacks and composable host backup automation
- keep inventory, deployment flow, and feature wiring separate from the reusable collections
- let features such as Obsidian be enabled, disabled, or replaced without rewriting the base deployment path

Expand All @@ -19,12 +19,15 @@ This repo should stay thin:

Configuration model:

- `inventories/prod/group_vars/all.yml` is the primary non-secret configuration surface
- `inventories/prod/group_vars/vault.yml` holds secret values only
- `inventories/prod/group_vars/all/main.yml` is the primary non-secret configuration surface
- `inventories/prod/group_vars/all/vault.yml` holds secret values only
- `.vault_pass` is the repo-local default Ansible Vault password file; keep it local, `0600`, and untracked
- backup policy is expressed as `restic_targets`, `restic_backup_jobs`, and `restic_backup_contributions`

Read first:

- `docs/QUICKSTART.md`
- `docs/CONFIG_WIZARD_SPEC.md`
- `docs/IMPLEMENTATION_STATUS.md`
- `docs/DEPLOYMENT_SEQUENCE.md`
- `docs/SECRETS_MODEL.md`
Expand All @@ -33,12 +36,17 @@ Read first:

## Preflight

Run preflight before any bootstrap or deploy action:
Use the guided setup flow first. It owns configuration, vault handling, collection install, preflight, bootstrap, site deploy, backup setup, and optional SSH lockdown in one explicit stage sequence:

```bash
./scripts/init-local-config.sh
./scripts/install-collections.sh
ansible-playbook -i inventories/prod/hosts.yml playbooks/preflight.yml
./scripts/setup.sh
```

When you need the lower-level runners directly:

```bash
./scripts/deploy.sh --skip-bootstrap --skip-site --skip-backup
./scripts/ssh-lockdown.sh --phase1-only
```

Behavior:
Expand All @@ -51,12 +59,21 @@ Public repo hygiene:

- tracked files end in `.example`
- real local inventory and vars stay untracked
- `scripts/init-local-config.sh` creates the local working files from examples
- `ansible.cfg` points Ansible at `.vault_pass` by default; the wizard can create that file for you and the lower-level runners will use it automatically when present
- `scripts/setup.sh` is the primary interactive operator entrypoint
- `scripts/deploy.sh` is the lower-level deployment runner for explicit phase execution
- `scripts/ssh-lockdown.sh` is the lower-level staged SSH hardening runner
- on a first run, `scripts/setup.sh` can generate or reuse a managed Ed25519 Ansible key under `~/.ssh/ansible-config-wizard/`, write `ansible_ssh_private_key_file` into local inventory, and either install that key automatically with a one-shot password prompt or pause with exact commands and resume guidance
- for Linux SFTP backup destinations you control, the wizard can prepare the backup prerequisite script and still keep the main setup flow inside `scripts/setup.sh`
- when you already have a backup transport key, point the wizard at the local private key file instead of pasting the key into the terminal
- the Obsidian feature supports two access modes: `public_https` for Traefik + ACME on `443`, and `private_mesh` for VPN or mesh-only reachability without public ingress; preflight rejects a public `5984` firewall rule in `private_mesh`
- the shared wizard implementation lives outside this repo; this repo only carries the profile, templates, and builder hook
- `scripts/init-local-config.sh` remains available as a simple scaffold-from-examples fallback

Quality controls:

- GitHub Actions CI scaffolds example local config, installs collections from GitHub, and syntax-checks the site playbooks
- staged lockdown uses explicit enable and confirm gates plus break-glass support, so a casual deploy run does not remove public SSH
- staged lockdown uses explicit validation-only and `--confirm` paths plus break-glass support, so a casual deploy run does not remove public SSH

Use this before:

Expand Down
4 changes: 4 additions & 0 deletions ansible.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ stdout_callback = default
result_format = yaml
gathering = smart
forks = 10
vault_password_file = .vault_pass

[privilege_escalation]
become = True
become_method = sudo
become_ask_pass = False

[ssh_connection]
pipelining = True
8 changes: 8 additions & 0 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ Current feature set:

`playbooks/backup.yml` uses the `crownops.deploy_services.restic_host_backups` role.

That backup layer is modeled as:

- targets: backup destinations and transport credentials
- jobs: logical host backup policies with schedule and retention
- contributions: feature-specific paths and consistency hooks merged into named jobs
- converge-time performance policy: no fact gathering for the dedicated backup play, SSH pipelining enabled in the repo Ansible config, and package cache reuse controlled through `restic_apt_cache_valid_time`
- restore-first scope policy: back up durable state such as host identity, local markdown workspaces, CouchDB data, and Traefik ACME state, not broad service roots that can be rebuilt from Ansible

`playbooks/lockdown.yml` consumes the reusable `crownops.deploy_base.network_lockdown` role so SSH lockdown policy stays consistent across site repos.

This keeps the site repo thin while still allowing features to evolve independently.
Expand Down
Loading