Make S1 handoff read-only by default
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02994-7685-7940-bf34-3555b8256018
This commit is contained in:
parent
24b799ec59
commit
40e295e3bd
16 changed files with 637 additions and 46 deletions
15
ansible/playbooks/verify-refresh.yaml
Normal file
15
ansible/playbooks/verify-refresh.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
# verify-refresh.yaml — Install/refresh Goss, run assertions, fetch TAP.
|
||||
#
|
||||
# This is a host-mutating operation. Review the rendered baseline and use it
|
||||
# only when updating the verification surface. Routine verification and the S1
|
||||
# handoff use the read-only verify.yaml playbook.
|
||||
|
||||
- name: Refresh and verify the managed Goss surface
|
||||
hosts: all
|
||||
become: true
|
||||
gather_facts: true
|
||||
vars_files:
|
||||
- ../inventory/group_vars/all.yaml
|
||||
roles:
|
||||
- role: goss
|
||||
|
|
@ -1,17 +1,84 @@
|
|||
---
|
||||
# verify.yaml — Deploy Goss, run baseline assertions, fetch TAP results.
|
||||
# Exit code mirrors Goss: 0 = all pass, non-zero = failures.
|
||||
# verify.yaml — Read-only S1 baseline verification and local TAP collection.
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook ansible/playbooks/verify.yaml -u admin
|
||||
# make verify
|
||||
# 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.
|
||||
|
||||
- hosts: all
|
||||
- name: Verify the installed S1 baseline without changing the host
|
||||
hosts: all
|
||||
become: true
|
||||
gather_facts: true
|
||||
# Same declaration the bootstrap play converges from. Without this the
|
||||
# firewall assertions render empty and silently assert nothing.
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- ../inventory/group_vars/all.yaml
|
||||
roles:
|
||||
- role: goss
|
||||
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 }}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue