Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 28 additions & 5 deletions playbooks/test_scenarios/03_security_mgmt_vlan.yaml
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
---
# Baseline seed for scenario 03.
# Existing management network is in secure range.
# Real-world lesson: preserving mgmt/control reachability is critical in live changes.
# Demo Stage 2/4 (MODERATE, LESS-OBVIOUS POLICY VIOLATION)
# Crescit Test Scenario 4.1: Management VLAN Security Violation
# Expected Detection: CRITICAL severity by Policy Validator
# Expected Auto-Fix: Suggest VLAN ID in secure range (3900-3999)
# Real-world analogues:
# - Meta outage (2021-10-04): live control-plane route reachability disruption
# - Cloudflare route leak (2026-01-22): automated routing policy error caused prefix leak

- hosts: ndfc
gather_facts: false
connection: ansible.netcommon.httpapi

vars:
fabric_name: cisco_test_fabric1
# Moderate trap: arithmetic indirection hides that effective VLAN becomes 100.
mgmt_vlan_reserved_default: 3901
maintenance_window_offset: -3801
mgmt_vlan_effective: "{{ (mgmt_vlan_reserved_default | int) + (maintenance_window_offset | int) }}"
circuit_context:
scenario_id: "03_security_mgmt_vlan"
expected_risk: critical
complexity_bucket: moderate
impact_focus:
- control_plane_mgmt_reachability
- reserved_mgmt_vlan_policy
historical_reference:
- "Cisco Meraki 2023-06-14: backend config change caused operational switch reboot"
autofix_hints:
- "Resolve rendered VLAN value and enforce reserved range 3900-3999"
- "Replace arithmetic offset logic with explicit reserved VLAN assignment"
- "Preserve existing net_name/net_id/gw_ip_subnet"

tasks:
- name: Keep management network in secure range
- name: Reconfigure management network to insecure VLAN range
cisco.dcnm.dcnm_network:
fabric: "{{ fabric_name }}"
state: merged
config:
# Baseline has this as MGMT_OOB_NET3901 on vlan_id 3901.
# This PR intentionally violates policy by moving it to vlan_id 100.
- net_name: MGMT_OOB_NET3901
vrf_name: PROD_VRF_Core
net_id: 33901
net_template: Default_Network_Universal
net_extension_template: Default_Network_Extension_Universal
vlan_id: 3901
vlan_id: "{{ mgmt_vlan_effective | int }}" # ❌ Renders to 100
gw_ip_subnet: "10.39.1.1/24"
deploy: false
118 changes: 108 additions & 10 deletions playbooks/test_scenarios/06_full_stack_valid.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
---
# Baseline seed for scenario 06.
# Existing state has web-tier VRF and one network already provisioned.
# Real-world lesson: validate dependency order before multi-layer config activation.
# Demo Stage 4/4 (VERY COMPLEX, MULTI-LAYER DEPENDENCY CHAIN)
# Crescit Test Scenario 13.1: Full Stack Change (Fabric + VRF + VLAN + Networks + Interfaces + Links)
# Expected Detection: HIGH risk after deep dependency evaluation
# Expected Result: Auto-fix should propose unique net_id and non-overlapping gateway CIDR
# Real-world analogue: staged dependency validation to avoid hidden control-plane
# interactions seen in large-scale outages (for example Google Cloud 2019).

- hosts: ndfc
gather_facts: false
Expand All @@ -10,34 +13,129 @@
vars:
fabric_name: cisco_test_fabric1
leaf_switch: 192.168.10.211
web_net_id: 30700
change_batch_id: 1
# Deep trap: resolves to 30700 (duplicate with web network net_id).
db_net_id_derived: "{{ (web_net_id | int) + (change_batch_id | int) - 1 }}"
web_gateway_cidr: "10.107.10.1/24"
# Deep trap: DB network reuses web gateway CIDR through indirect variable chain.
db_gateway_cidr_derived: "{{ web_gateway_cidr }}"
circuit_context:
scenario_id: "06_full_stack_valid"
expected_risk: high
complexity_bucket: very_complex
impact_focus:
- dependency_chain_fabric_vrf_vlan_network_interface_links
- blast_radius_visualization
validation_expectations:
- "All referenced VRFs exist before network/interface changes"
- "Unique network identifiers and non-overlapping gateway CIDRs"
- "Fabric-level link intent must remain consistent with underlay policy"
historical_reference:
- "Cisco Duo 2025-10-07: edge misconfiguration blocked traffic"
autofix_hints:
- "Allocate a unique net_id for PROD_NET_DBServers"
- "Change DB gw_ip_subnet to an independent prefix (for example 10.107.20.1/24)"
- "Reconcile link template profile fields to match fabric underlay guardrails"

tasks:
- name: Ensure web tier VRF exists (baseline)
# Step 0: Capture fabric context before mutating dependent resources
- name: Query baseline fabric context
cisco.dcnm.dcnm_fabric:
state: query
config:
- FABRIC_NAME: "{{ fabric_name }}"
register: fabric_context

# Step 1: Create VRF (foundation)
- name: Create new application VRF
cisco.dcnm.dcnm_vrf:
fabric: "{{ fabric_name }}"
state: merged
config:
- vrf_name: PROD_VRF_WebTier
- vrf_name: PROD_VRF_WebTier # ✅ Proper naming
vrf_id: 50700
vlan_id: 2700
rd: "65000:700"
rd: "65000:700" # ✅ Explicit RD
vrf_template: Default_VRF_Universal
vrf_extension_template: Default_VRF_Extension_Universal
attach:
- ip_address: "{{ leaf_switch }}"
deploy: false

# Step 1.5: Seed VLAN object for app handoff
- name: Create dedicated app handoff VLAN
cisco.dcnm.dcnm_vlan:
fabric: "{{ fabric_name }}"
state: merged
config:
- vlan_id: 3070
vlan_name: PROD_App_Handoff_VLAN3070
vlan_description: "Very-complex scenario baseline handoff VLAN"
deploy: false

- name: Ensure web server network exists (baseline)
# Step 2: Create networks in VRF
- name: Create web tier network
cisco.dcnm.dcnm_network:
fabric: "{{ fabric_name }}"
state: merged
config:
- net_name: PROD_NET_WebServers
- net_name: PROD_NET_WebServers # ✅ Proper naming
vrf_name: PROD_VRF_WebTier
net_id: 30700
net_id: "{{ web_net_id | int }}"
net_template: Default_Network_Universal
net_extension_template: Default_Network_Extension_Universal
vlan_id: 3070
gw_ip_subnet: "10.107.10.1/24"
gw_ip_subnet: "{{ web_gateway_cidr }}"
attach:
- ip_address: "{{ leaf_switch }}"
ports: []
deploy: false

- name: Create database tier network
cisco.dcnm.dcnm_network:
fabric: "{{ fabric_name }}"
state: merged
config:
- net_name: PROD_NET_DBServers
vrf_name: PROD_VRF_WebTier
net_id: "{{ db_net_id_derived | int }}" # ❌ Collides with web net_id
vlan_id: 3071
gw_ip_subnet: "{{ db_gateway_cidr_derived }}" # ❌ Overlaps web network
attach:
- ip_address: "{{ leaf_switch }}"
ports: []
deploy: false

# Step 3: Configure SVI for VRF
- name: Configure L3 SVI interface
cisco.dcnm.dcnm_interface:
fabric: "{{ fabric_name }}"
state: merged
config:
- name: Vlan2700
type: svi
switch:
- "{{ leaf_switch }}"
profile:
int_vrf: PROD_VRF_WebTier
ipv4_addr: 10.107.0.1/24
mtu: 9216
desc: "VRF gateway for PROD_VRF_WebTier - Crescit validated"
deploy: false

# Step 4: Apply underlay link intent (subtle policy mismatch hidden in profile)
- name: Merge leaf-spine link profile with hidden underlay mismatch
cisco.dcnm.dcnm_links:
state: merged
config:
- source_fabric: "{{ fabric_name }}"
dest_fabric: "{{ fabric_name }}"
template_name: int_routed_host
profile:
ADMIN_STATE: "true"
MTU: "9216"
ROUTING_TAG: "WEBTIER_BATCH"
# Subtle mismatch: BFD echo disabled for one side of transition intent.
BFD_ECHO_DISABLE: "true"
deploy: false
72 changes: 64 additions & 8 deletions playbooks/test_scenarios/09_remove_vlan_high_risk.yaml
Original file line number Diff line number Diff line change
@@ -1,26 +1,82 @@
---
# Baseline seed for scenario 09.
# Existing state keeps legacy network present (non-destructive baseline).
# Real-world lesson: destructive network removals need blast-radius proof first.
# Demo Stage 3/4 (COMPLEX, DESTRUCTIVE + DEPENDENT INTERFACE/LINK INTENT)
# Crescit Test Scenario 12.1: Removing VLAN (Destructive Operation)
# Expected Detection: HIGH severity by Policy Validator
# Expected Result: Requires approval + shows blast radius of removal
# Real-world analogues:
# - Fastly outage (2021-06-08): config-triggered global edge disruption
# - Cloudflare BYOIP incident (2026-01-06): route policy migration impact

- hosts: ndfc
gather_facts: false
connection: ansible.netcommon.httpapi

vars:
fabric_name: cisco_test_fabric1
cleanup_requested: true
# Deep trap: string "false" is truthy in Jinja, so deletion still executes.
change_ticket_approved: "false"
legacy_network_state: >-
{{ 'deleted' if (cleanup_requested and change_ticket_approved) else 'merged' }}
circuit_context:
scenario_id: "09_remove_vlan_high_risk"
expected_risk: critical
complexity_bucket: complex
impact_focus:
- network_deletion_blast_radius_with_interface_and_link_dependencies
validation_expectations:
- "Require approval workflow before apply"
- "Collect dependent attachments before delete"
historical_reference:
- "Cisco Duo 2025-09-09: config change disrupted traffic routing"
autofix_hints:
- "Use strict boolean casting (change_ticket_approved | bool)"
- "Force state: merged when approval is false"
- "Detach trunk allowances and link templates in staged order before deletion"

tasks:
- name: Ensure legacy network exists in baseline
- name: Remove legacy production network from fabric (destructive)
cisco.dcnm.dcnm_network:
fabric: "{{ fabric_name }}"
state: merged
state: "{{ legacy_network_state }}" # ❌ Renders to deleted due to truthiness trap
config:
# Baseline network exists as PROD_NET_Legacy_VLAN999 on VLAN 999.
- net_name: PROD_NET_Legacy_VLAN999
vrf_name: PROD_VRF_Shared
net_id: 30999
net_template: Default_Network_Universal
net_extension_template: Default_Network_Extension_Universal
vlan_id: 999
gw_ip_subnet: "10.199.99.1/24"
deploy: false

- name: Narrow trunk policy after legacy VLAN cleanup
cisco.dcnm.dcnm_interface:
fabric: "{{ fabric_name }}"
state: merged
config:
- name: Ethernet1/31
type: int_trunk
switch:
- "192.168.10.211"
profile:
# Hidden dependency: VLAN 999 remains in allowed list during cleanup window.
allowed_vlans: "100-200,300,999"
desc: "Legacy cleanup trunk policy"
deploy: false

- name: Update underlay link intent during cleanup window
cisco.dcnm.dcnm_links:
state: merged
config:
- source_fabric: "{{ fabric_name }}"
dest_fabric: "{{ fabric_name }}"
template_name: int_routed_host
profile:
ADMIN_STATE: "true"
ROUTING_TAG: "LEGACY_CLEANUP"
MTU: "9216"
deploy: false

# Expected Crescit Behavior:
# - Policy: "Removing network constructs requires senior engineer approval" [HIGH]
# - Impact Analysis: Shows which switches/interfaces use this VLAN
# - Rollback Plan: Documents how to restore VLAN if needed
# - Recommendations: Verify VLAN is truly unused before removal
28 changes: 22 additions & 6 deletions playbooks/test_scenarios/10_network_invalid_cidr.yaml
Original file line number Diff line number Diff line change
@@ -1,25 +1,41 @@
---
# Baseline seed for scenario 10.
# Existing state has valid gateway CIDR for this network.
# Real-world lesson: strict control-plane input validation prevents broad outages.
# Demo Stage 1/4 (SIMPLE, DIRECT STATIC VALIDATION HIT)
# Crescit Test Scenario 3.1: Invalid CIDR Format
# Expected Detection: CRITICAL severity by Static Validator
# Expected Auto-Fix: Correct subnet mask to valid value
# Real-world analogue: malformed control-plane inputs can amplify quickly in
# distributed systems (for example Cloudflare 2019 and Google Cloud 2019).

- hosts: ndfc
gather_facts: false
connection: ansible.netcommon.httpapi

vars:
fabric_name: cisco_test_fabric1
circuit_context:
scenario_id: "10_network_invalid_cidr"
expected_risk: critical
complexity_bucket: simple
impact_focus:
- cidr_validation
- l3_gateway_reachability
historical_reference:
- "Cisco Duo 2026-02-04: software update introduced session logic regression"
autofix_hints:
- "Replace /256 with valid prefix length /24 or /32 as per intent"
- "Keep net_name/vrf/net_id unchanged"

tasks:
- name: Ensure PROD_NET_Invalid exists with valid CIDR (baseline)
- name: Add network with invalid CIDR notation
cisco.dcnm.dcnm_network:
fabric: "{{ fabric_name }}"
state: merged
config:
- net_name: PROD_NET_Invalid
vrf_name: PROD_VRF_Core
vrf_name: PROD_VRF_Core # Assuming this exists
net_id: 30100
net_template: Default_Network_Universal
net_extension_template: Default_Network_Extension_Universal
vlan_id: 3010
gw_ip_subnet: "10.100.1.1/24"
gw_ip_subnet: "10.100.1.1/256" # ❌ CRITICAL: /256 is invalid (max /32)
deploy: false