feat: implement WP-0002 — Goss test suite, verify playbook, and ADR-002
- goss/baseline.yaml: assertions for all spec/server-baseline.yaml items
(packages, services, SSH config, UFW rules, admin user, fail2ban, HISTCONTROL)
- goss/vars/baseline-vars.yaml: parameterised ports and paths
- ansible/roles/goss/: installs Goss binary (v0.4.9), deploys tests,
runs assertions in TAP format, fetches report to reports/
- ansible/playbooks/verify.yaml: playbook wrapping the goss role
- Makefile: add 'make verify' target; update 'make status' with hint
- docs/adr/ADR-002: formal repo boundary — railiance-hosts vs railiance-bootstrap
- workplans/RAIL-HO-WP-0002: registered workstream 8fed53c2, T03–T06 done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 12:38:48 +01:00
|
|
|
---
|
2026-08-23 12:41:23 +02:00
|
|
|
# verify.yaml — Read-only S1 baseline verification and local TAP collection.
|
feat: implement WP-0002 — Goss test suite, verify playbook, and ADR-002
- goss/baseline.yaml: assertions for all spec/server-baseline.yaml items
(packages, services, SSH config, UFW rules, admin user, fail2ban, HISTCONTROL)
- goss/vars/baseline-vars.yaml: parameterised ports and paths
- ansible/roles/goss/: installs Goss binary (v0.4.9), deploys tests,
runs assertions in TAP format, fetches report to reports/
- ansible/playbooks/verify.yaml: playbook wrapping the goss role
- Makefile: add 'make verify' target; update 'make status' with hint
- docs/adr/ADR-002: formal repo boundary — railiance-hosts vs railiance-bootstrap
- workplans/RAIL-HO-WP-0002: registered workstream 8fed53c2, T03–T06 done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 12:38:48 +01:00
|
|
|
#
|
2026-08-23 12:41:23 +02:00
|
|
|
# This playbook must not install, template, enable, restart, or otherwise
|
|
|
|
|
# mutate a managed host. scripts/handoff_contract.py enforces the allowed
|
|
|
|
|
# module and command surface before scripts/s1_handoff.py contacts a host.
|
|
|
|
|
# Use verify-refresh.yaml only after reviewing and approving host changes.
|
feat: implement WP-0002 — Goss test suite, verify playbook, and ADR-002
- goss/baseline.yaml: assertions for all spec/server-baseline.yaml items
(packages, services, SSH config, UFW rules, admin user, fail2ban, HISTCONTROL)
- goss/vars/baseline-vars.yaml: parameterised ports and paths
- ansible/roles/goss/: installs Goss binary (v0.4.9), deploys tests,
runs assertions in TAP format, fetches report to reports/
- ansible/playbooks/verify.yaml: playbook wrapping the goss role
- Makefile: add 'make verify' target; update 'make status' with hint
- docs/adr/ADR-002: formal repo boundary — railiance-hosts vs railiance-bootstrap
- workplans/RAIL-HO-WP-0002: registered workstream 8fed53c2, T03–T06 done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 12:38:48 +01:00
|
|
|
|
2026-08-23 12:41:23 +02:00
|
|
|
- name: Verify the installed S1 baseline without changing the host
|
|
|
|
|
hosts: all
|
feat: implement WP-0002 — Goss test suite, verify playbook, and ADR-002
- goss/baseline.yaml: assertions for all spec/server-baseline.yaml items
(packages, services, SSH config, UFW rules, admin user, fail2ban, HISTCONTROL)
- goss/vars/baseline-vars.yaml: parameterised ports and paths
- ansible/roles/goss/: installs Goss binary (v0.4.9), deploys tests,
runs assertions in TAP format, fetches report to reports/
- ansible/playbooks/verify.yaml: playbook wrapping the goss role
- Makefile: add 'make verify' target; update 'make status' with hint
- docs/adr/ADR-002: formal repo boundary — railiance-hosts vs railiance-bootstrap
- workplans/RAIL-HO-WP-0002: registered workstream 8fed53c2, T03–T06 done
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 12:38:48 +01:00
|
|
|
become: true
|
2026-08-23 12:41:23 +02:00
|
|
|
gather_facts: false
|
2026-08-12 03:28:35 +02:00
|
|
|
vars_files:
|
|
|
|
|
- ../inventory/group_vars/all.yaml
|
2026-08-23 12:41:23 +02:00
|
|
|
vars:
|
|
|
|
|
goss_bin: /usr/local/bin/goss
|
|
|
|
|
goss_config: /etc/goss/baseline.yaml
|
|
|
|
|
expected_goss_baseline: >-
|
|
|
|
|
{{ lookup('ansible.builtin.template',
|
|
|
|
|
playbook_dir ~ '/../../goss/baseline.yaml.j2',
|
|
|
|
|
keep_trailing_newline=true) }}
|
|
|
|
|
expected_goss_sha256: "{{ expected_goss_baseline | hash('sha256') }}"
|
|
|
|
|
report_stamp: "{{ now(utc=true, fmt='%Y%m%dT%H%M%SZ') }}"
|
|
|
|
|
|
|
|
|
|
tasks:
|
|
|
|
|
- name: Inspect the installed Goss executable
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
path: "{{ goss_bin }}"
|
|
|
|
|
register: installed_goss
|
|
|
|
|
|
|
|
|
|
- name: Inspect the installed baseline digest
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
path: "{{ goss_config }}"
|
|
|
|
|
checksum_algorithm: sha256
|
|
|
|
|
register: installed_baseline
|
|
|
|
|
|
|
|
|
|
- name: Require the exact source-rendered verification surface
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
that:
|
|
|
|
|
- installed_goss.stat.exists | default(false)
|
|
|
|
|
- installed_goss.stat.executable | default(false)
|
|
|
|
|
- installed_baseline.stat.exists | default(false)
|
|
|
|
|
- installed_baseline.stat.checksum | default('') == expected_goss_sha256
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
{{ inventory_hostname }} has no usable Goss surface or its baseline is
|
|
|
|
|
stale. Review changes, then run verify-refresh for this host before
|
|
|
|
|
retrying the read-only handoff gate.
|
|
|
|
|
|
|
|
|
|
- name: Run the installed baseline assertions
|
|
|
|
|
ansible.builtin.command:
|
|
|
|
|
argv:
|
|
|
|
|
- "{{ goss_bin }}"
|
|
|
|
|
- -g
|
|
|
|
|
- "{{ goss_config }}"
|
|
|
|
|
- validate
|
|
|
|
|
- --format
|
|
|
|
|
- tap
|
|
|
|
|
register: goss_result
|
|
|
|
|
changed_when: false
|
|
|
|
|
failed_when: false
|
|
|
|
|
|
|
|
|
|
- name: Ensure the controller reports directory exists
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: "{{ playbook_dir }}/../../reports"
|
|
|
|
|
state: directory
|
|
|
|
|
mode: "0755"
|
|
|
|
|
delegate_to: localhost
|
|
|
|
|
become: false
|
|
|
|
|
|
|
|
|
|
- name: Record TAP evidence on the controller
|
|
|
|
|
ansible.builtin.copy:
|
|
|
|
|
content: "{{ goss_result.stdout }}\n"
|
|
|
|
|
dest: >-
|
|
|
|
|
{{ playbook_dir }}/../../reports/goss-{{ inventory_hostname }}-{{ report_stamp }}.tap
|
|
|
|
|
mode: "0644"
|
|
|
|
|
delegate_to: localhost
|
|
|
|
|
become: false
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
|
|
|
|
- name: Fail closed on a baseline assertion failure
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
that:
|
|
|
|
|
- goss_result.rc == 0
|
|
|
|
|
fail_msg: "Goss baseline failed on {{ inventory_hostname }}"
|