Untitled
unknown
plain_text
9 months ago
4.8 kB
6
Indexable
import streamlit as st
import pandas as pd
import re
st.title("🔧 Network Config Compliance Checker")
# --- Upload Config Files ---
uploaded_files = st.file_uploader("📂 Upload Config Files", type=["txt"], accept_multiple_files=True)
# --- Policy Management (unchanged UI) ---
# [Keep the exact same UI code for policy creation as before...]
# --- Core Fix: Block-Based Evaluation Logic ---
def parse_blocks(config_text):
"""Parse config into templates and interfaces with their content."""
templates = {match[0].strip(): match[1]
for match in re.findall(r"(template \S+)(.*?)(?=template \S+|$)", config_text, re.DOTALL)}
interfaces = {match[0].strip(): match[1]
for match in re.findall(r"(interface \S+)(.*?)(?=interface \S+|$)", config_text, re.DOTALL)}
return templates, interfaces
def evaluate_policy(policy, templates, interfaces, general_config):
"""Evaluate a policy with strict dependency scoping."""
results = []
conditions = policy["conditions"]
dependency_chain = {} # Track {keyword: (exists, block_content)}
# Resolve dependencies in order
for cond in conditions:
keyword = cond["keyword"]
dependent_on = cond["dependent_on"]
condition_type = cond["condition"]
# Determine search scope
search_text = general_config # Default to full config
if dependent_on:
# Check if dependency is a resolved template/interface
if dependent_on in dependency_chain:
parent_exists, parent_block = dependency_chain[dependent_on]
if not parent_exists:
# Parent failed - mark condition as failed
dependency_chain[keyword] = (False, None)
continue
search_text = parent_block # Restrict to parent's block
else:
# Check if dependency is a template/interface
if dependent_on.startswith("template "):
search_text = templates.get(dependent_on, "")
elif dependent_on.startswith("interface "):
search_text = interfaces.get(dependent_on, "")
# Evaluate current condition
exists = bool(re.search(keyword, search_text, re.DOTALL))
meets_condition = (
(condition_type == "Exists" and exists) or
(condition_type == "Does Not Exist" and not exists)
)
# Store results for dependencies
dependency_chain[keyword] = (meets_condition, search_text if exists else None)
if not meets_condition:
return False # Entire policy fails if any condition fails
return True # All conditions met
# --- Compliance Check Logic (Revised) ---
if st.button("🚀 Run Compliance Check"):
if not uploaded_files:
st.warning("⚠️ Please upload config files first.")
else:
results = []
for uploaded_file in uploaded_files:
config_text = uploaded_file.read().decode("utf-8")
switch_name = uploaded_file.name.split(".")[0]
# Parse blocks once per file
templates, interfaces = parse_blocks(config_text)
# Evaluate all policies
for policy in st.session_state.advanced_policies:
policy_name = policy["name"]
scope = policy["scope"]
# General config check
if scope in ["General Configuration", "Both"]:
is_compliant = evaluate_policy(policy, templates, interfaces, config_text)
results.append({
"Switch": switch_name,
"Interface": "N/A (General)",
"Policy": policy_name,
"Status": policy["action"] if is_compliant else "Non-Compliant"
})
# Interface config check
if scope in ["Interface Configuration", "Both"]:
for int_name, int_config in interfaces.items():
is_compliant = evaluate_policy(policy, templates, interfaces, int_config)
results.append({
"Switch": switch_name,
"Interface": int_name.split()[1], # Extract interface name
"Policy": policy_name,
"Status": policy["action"] if is_compliant else "Non-Compliant"
})
# Display results
df = pd.DataFrame(results)
st.write(df)
st.download_button("📥 Download Report", df.to_csv(index=False), "compliance_report.csv", "text/csv")Editor is loading...
Leave a Comment