Instruction: Create an AUTARCH web template for the 'Ble Scanner' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: ble_scanner.html
Sections: 7
Tabs: 1
Forms/API calls: 0
Has JavaScript: True

Output:
{% extends "base.html" %}
{% block title %}AUTARCH — BLE Scanner{% endblock %}
{% block content %}
<div class="page-header">
    <h1>BLE Scanner</h1>
    <p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
        Bluetooth Low Energy device discovery, service enumeration, and characteristic inspection.
    </p>
</div>

<!-- Tab Bar -->
<div class="tab-bar">
    <button class="tab active" data-tab-group="ble" data-tab="scan" onclick="showTab('ble','scan')">Scan</button>
    <button class="tab" data-tab-group="ble" data-tab="device" onclick="showTab('ble','device')">Device Detail</button>
</div>

<!-- ══ Scan Tab ══ -->
<div class="tab-content active" data-tab-group="ble" data-tab="scan">

    <!-- Scan Controls -->
    <div class="section">
        <h2>BLE Scan</h2>
        <div class="form-row" style="align-items:flex-end">
            <div class="form-group" style="max-width:160px">
                <label>Duration (seconds)</label>
                <input type="number" id="ble-scan-duration" value="10" min="1" max="60">
            </div>
            <div class="form-group" style="flex:0;margin-bottom:16px">
                <button id="btn-ble-scan" class="btn btn-primary" onclick="bleScan()">Scan</button>
            </div>
        </div>
        <div style="display:flex;align-items:center;gap:8px;margin-bottom:12px">
            <span class="status-dot" id="ble-bleak-dot"></span>
            <span id="ble-bleak-status" style="font-size:0.85rem;color:var(--text-secondary)">Checking bleak availability...</span>
        </div>
        <div id="ble-scan-status" class="progress-text"></div>
    </div>

    <!-- Discovered Devices -->
    <div class="section">
        <h2>Discovered Devices</h2>
        <div class="tool-actions">
            <button class="btn btn-small" onclick="bleVulnScan()">Vuln Scan All</button>
            <button class="btn btn-small" onclick="bleSaveScan()">Save Scan</button>
            <button class="btn btn-small" onclick="bleClearDevices()">Clear</button>
        </div>
        <table class="data-table">
            <thead>
                <tr>
                    <th>Address</th>
                    <th>Name</th>
                    <th>RSSI</th>
                    <th>Type</th>
                    <th>Manufacturer</th>
                    <th>Services</th>
                    <th></th>
                </tr>
            </thead>
            <tbody id="ble-devices-body">
                <tr><td colspan="7" class="empty-state">No devices found. Run a scan to discover BLE devices.</td></tr>
            </tbody>
        </table>
    </div>

    <!-- Saved Scans -->
    <div class="section">
        <h2>Saved Scans</h2>
        <div class="tool-actions">
            <button class="btn btn-small" onclick="bleLoadSavedScans()">Refresh</button>
        </div>
        <div id="ble-saved-scans">
            <p class="empty-state" style="padding:12px;font-size:0.85rem">No saved scans.</p>
        </div>
    </div>
</div>

<!-- ══ Device Detail Tab ══ -->
<div class="tab-content" data-tab-group="ble" data-tab="device">

    <!-- Device Selector -->
    <div class="section">
        <h2>Device Connection</h2>
        <div class="form-row" style="align-items:flex-end">
            <div class="form-group" style="flex:2">
                <label>Device</label>
                <select id="ble-device-select">
                    <option value="">-- scan for devices first --</option>
                </select>
            </div>
            <div class="form-group" style="flex:0;margin-bottom:16px">
                <button id="btn-ble-connect" class="btn btn-primary" onclick="bleConnect()">Connect</button>
            </div>
            <div class="form-group" style="flex:0;margin-bottom:16px">
                <button id="btn-ble-disconnect" class="btn btn-stop btn-small" onclick="bleDisconnect()" style="display:none">Disconnect</button>
            </div>
        </div>
        <div id="ble-connect-status" class="progress-text"></div>
    </div>

    <!-- Services Tree -->
    <div class="section">
        <h2>Services &amp; Characteristics</h2>
        <div id="ble-services-tree">
            <p class="empty-state" style="padding:12px;font-size:0.85rem">Connect to a device to view its GATT services.</p>
        </div>
    </div>

    <!-- Proximity Tracking -->
    <div class="section">
        <h2>Proximity Tracking</h2>
        <div class="form-row" style="align-items:flex-end">
            <div class="form-group" style="flex:0;margin-bottom:16px">
                <button id="btn-ble-track" class="btn btn-primary btn-small" onclick="bleStartTracking()">Start Tracking</button>
            </div>
            <div class="form-group" style="flex:0;margin-bottom:16px">
                <button id="btn-ble-track-stop" class="btn btn-stop btn-small" onclick="bleStopTracking()" style="display:none">Stop</button>
            </div>
        </div>
        <div style="display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap">
            <div>
                <div style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:4px">Estimated Distance</div>
                <div id="ble-distance" style="font-size:2rem;font-weight:700;color:var(--accent)">-- m</div>
                <div id="ble-rssi-current" style="font-size:0.85rem;color:var(--text-muted)">RSSI: --</div>
            </div>
            <div style="flex:1;min-width:300px">
                <div style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:4px">RSSI History</div>
                <div id="ble-rssi-chart" style="background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius);height:120px;position:relative;overflow:hidden">
                    <canvas id="ble-rssi-canvas" style="width:100%;height:100%"></canvas>
                </div>
            </div>
        </div>
    </div>

    <!-- Tracking History -->
    <div class="section">
        <h2>Tracking History</h2>
        <div class="tool-actions">
            <button class="btn btn-small" onclick="bleClearHistory()">Clear</button>
            <button class="btn btn-small" onclick="bleExportHistory()">Export</button>
        </div>
        <table class="data-table">
            <thead>
                <tr>
                    <th>Timestamp</th>
                    <th>Address</th>
                    <th>RSSI</th>
                    <th>Distance (m)</th>
                </tr>
            </thead>
            <tbody id="ble-history-body">
                <tr><td colspan="4" class="empty-state">No tracking history.</td></tr>
            </tbody>
        </table>
    </div>
</div>

<script>
/* ── BLE Scanner ── */
function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;'); }

var bleDevices = [];
var bleTrackInterval = null;
var bleTrackHistory = [];
var bleRssiData = [];

/* ── Init ── */
document.addEventListener('DOMContentLoaded', function() {
    bleCheckBleak();
    bleLoadSavedScans();
});

function bleCheckBleak() {
    fetchJSON('/ble/status').then(function(data) {
        var dot = document.getElementById('ble-bleak-dot');
        var txt = document.getElementById('ble-bleak-status');
        if (data.bleak_available) {
            dot.className = 'status-dot active';
            txt.textContent = 'bleak available — ready to scan';
        } else {
            dot.className = 'status-dot inactive';
            txt.textContent = 'bleak not available — install with: pip install bleak';
        }
    }).catch(function() {
        document.getElementById('ble-bleak-dot').className = 'status-dot inactive';
        document.getElementById('ble-bleak-status').textContent = 'Could not check bleak status';
    });
}

/* ── Scan Tab ── */
function bleScan() {
    var duration = parseInt(document.getElementById('ble-scan-duration').value) || 10;
    var btn = document.getElementById('btn-ble-scan');
    setLoading(btn, true);
    document.getElementById('ble-scan-status').textContent = 'Scanning for ' + duration + ' seconds...';
    postJSON('/ble/scan', {duration: duration}).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            document.getElementById('ble-scan-status').textContent = 'Error: ' + data.error;
            return;
        }
        bleDevices = data.devices || [];
        document.getElementById('ble-scan-status').textContent = 'Found ' + bleDevices.length + ' device(s)';
        bleRenderDevices();
        bleUpdateDeviceSelector();
    }).catch(function() { setLoading(btn, false); });
}

function bleRenderDevices() {
    var tbody = document.getElementById('ble-devices-body');
    if (!bleDevices.length) {
        tbody.innerHTML = '<tr><td colspan="7" class="empty-state">No devices found.</td></tr>';
        return;
    }
    var html = '';
    bleDevices.forEach(function(d, i) {
        var rssiColor = d.rssi > -50 ? 'var(--success,#4ade80)' : d.rssi > -70 ? 'var(--warning,#f59e0b)' : 'var(--danger)';
        html += '<tr>'
            + '<td style="font-family:monospace;font-size:0.8rem">' + esc(d.address || '') + '</td>'
            + '<td>' + esc(d.name || 'Unknown') + '</td>'
            + '<td style="color:' + rssiColor + '">' + esc(String(d.rssi || '—')) + ' dBm</td>'
            + '<td>' + esc(d.type || '—') + '</td>'
            + '<td>' + esc(d.manufacturer || '—') + '</td>'
            + '<td>' + (d.services_count || 0) + '</td>'
            + '<td><button class="btn btn-small" onclick="bleInspectDevice(' + i + ')">Inspect</button></td>'
            + '</tr>';
    });
    tbody.innerHTML = html;
}

function bleUpdateDeviceSelector() {
    var sel = document.getElementById('ble-device-select');
    sel.innerHTML = '<option value="">-- select a device --</option>';
    bleDevices.forEach(function(d) {
        var opt = document.createElement('option');
        opt.value = d.address;
        opt.textContent = (d.name || 'Unknown') + ' (' + d.address + ') [' + d.rssi + ' dBm]';
        sel.appendChild(opt);
    });
}

function bleInspectDevice(idx) {
    var d = bleDevices[idx];
    if (!d) return;
    document.getElementById('ble-device-select').value = d.address;
    showTab('ble', 'device');
}

function bleVulnScan() {
    if (!bleDevices.length) return;
    var addresses = bleDevices.map(function(d) { return d.address; });
    document.getElementById('ble-scan-status').textContent = 'Running vulnerability scan on ' + addresses.length + ' device(s)...';
    postJSON('/ble/vuln-scan', {addresses: addresses}).then(function(data) {
        if (data.error) {
            document.getElementById('ble-scan-status').textContent = 'Error: ' + data.error;
            return;
        }
        var vulnCount = (data.vulnerabilities || []).length;
        document.getElementById('ble-scan-status').textContent = 'Vuln scan complete — ' + vulnCount + ' issue(s) found';
        if (vulnCount && data.vulnerabilities) {
            data.vulnerabilities.forEach(function(v) {
                var dev = bleDevices.find(function(d) { return d.address === v.address; });
                if (dev) dev.vuln = v.description;
            });
            bleRenderDevices();
        }
    });
}

function bleSaveScan() {
    if (!bleDevices.length) return;
    postJSON('/ble/save-scan', {devices: bleDevices}).then(function(data) {
        if (data.error) {
            document.getElementById('ble-scan-status').textContent = 'Error: ' + data.error;
            return;
        }
        document.getElementById('ble-scan-status').textContent = 'Scan saved: ' + (data.filename || 'OK');
        bleLoadSavedScans();
    });
}

function bleLoadSavedScans() {
    fetchJSON('/ble/saved-scans').then(function(data) {
        var container = document.getElementById('ble-saved-scans');
        var scans = data.scans || [];
        if (!scans.length) {
            container.innerHTML = '<p class="empty-state" style="padding:12px;font-size:0.85rem">No saved scans.</p>';
            return;
        }
        var html = '<table class="data-table"><thead><tr><th>Timestamp</th><th>Devices</th><th></th></tr></thead><tbody>';
        scans.forEach(function(s) {
            html += '<tr>'
                + '<td>' + esc(s.timestamp || '') + '</td>'
                + '<td>' + (s.device_count || 0) + '</td>'
                + '<td><button class="btn btn-small" onclick="bleLoadScan(\'' + esc(s.id || '') + '\')">Load</button></td>'
                + '</tr>';
        });
        html += '</tbody></table>';
        container.innerHTML = html;
    }).catch(function() {});
}

function bleLoadScan(id) {
    fetchJSON('/ble/saved-scans/' + encodeURIComponent(id)).then(function(data) {
        if (data.error) return;
        bleDevices = data.devices || [];
        bleRenderDevices();
        bleUpdateDeviceSelector();
        document.getElementById('ble-scan-status').textContent = 'Loaded saved scan: ' + (data.timestamp || id);
    });
}

function bleClearDevices() {
    bleDevices = [];
    bleRenderDevices();
    bleUpdateDeviceSelector();
    document.getElementById('ble-scan-status').textContent = '';
}

/* ── Device Detail Tab ── */
function bleConnect() {
    var addr = document.getElementById('ble-device-select').value;
    if (!addr) return;
    var btn = document.getElementById('btn-ble-connect');
    setLoading(btn, true);
    document.getElementById('ble-connect-status').textContent = 'Connecting to ' + addr + '...';
    postJSON('/ble/connect', {address: addr}).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            document.getElementById('ble-connect-status').textContent = 'Error: ' + data.error;
            return;
        }
        document.getElementById('ble-connect-status').textContent = 'Connected to ' + addr;
        document.getElementById('btn-ble-disconnect').style.display = '';
        bleRenderServices(data.services || []);
    }).catch(function() { setLoading(btn, false); });
}

function bleDisconnect() {
    var addr = document.getElementById('ble-device-select').value;
    postJSON('/ble/disconnect', {address: addr}).then(function(data) {
        document.getElementById('ble-connect-status').textContent = 'Disconnected';
        document.getElementById('btn-ble-disconnect').style.display = 'none';
        document.getElementById('ble-services-tree').innerHTML = '<p class="empty-state" style="padding:12px;font-size:0.85rem">Connect to a device to view its GATT services.</p>';
    });
}

function bleRenderServices(services) {
    var container = document.getElementById('ble-services-tree');
    if (!services.length) {
        container.innerHTML = '<p class="empty-state" style="padding:12px;font-size:0.85rem">No services found on this device.</p>';
        return;
    }
    var html = '';
    services.forEach(function(svc, si) {
        html += '<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:12px;margin-bottom:8px">';
        html += '<div style="font-weight:600;font-size:0.9rem;margin-bottom:8px">'
            + '<span style="color:var(--accent)">' + esc(svc.uuid || '') + '</span>'
            + (svc.name ? ' <span style="color:var(--text-secondary);font-weight:400">(' + esc(svc.name) + ')</span>' : '')
            + '</div>';
        if (svc.characteristics && svc.characteristics.length) {
            svc.characteristics.forEach(function(ch, ci) {
                var charId = 'ble-char-' + si + '-' + ci;
                html += '<div style="margin-left:16px;padding:8px 0;border-top:1px solid var(--border)">';
                html += '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">';
                html += '<span style="font-family:monospace;font-size:0.8rem">' + esc(ch.uuid || '') + '</span>';
                if (ch.name) html += '<span style="font-size:0.8rem;color:var(--text-secondary)">(' + esc(ch.name) + ')</span>';
                var props = (ch.properties || []).join(', ');
                if (props) html += '<span class="badge" style="background:rgba(99,102,241,0.15);color:var(--accent)">' + esc(props) + '</span>';
                html += '</div>';
                html += '<div style="display:flex;align-items:center;gap:6px;margin-top:6px">';
                html += '<span id="' + charId + '-val" style="font-family:monospace;font-size:0.8rem;color:var(--text-muted)">'
                    + (ch.value ? esc(ch.value) : '(not read)') + '</span>';
                if ((ch.properties || []).indexOf('read') >= 0 || (ch.properties || []).indexOf('Read') >= 0) {
                    html += '<button class="btn btn-small" style="padding:2px 8px;font-size:0.7rem" onclick="bleReadChar(\'' + esc(ch.uuid) + '\',\'' + charId + '\')">Read</button>';
                }
                if ((ch.properties || []).indexOf('write') >= 0 || (ch.properties || []).indexOf('Write') >= 0) {
                    html += '<input type="text" id="' + charId + '-input" placeholder="hex value" style="width:120px;padding:3px 6px;font-size:0.8rem;background:var(--bg-input);border:1px solid var(--border);border-radius:4px;color:var(--text-primary)">';
                    html += '<button class="btn btn-small" style="padding:2px 8px;font-size:0.7rem" onclick="bleWriteChar(\'' + esc(ch.uuid) + '\',\'' + charId + '\')">Write</button>';
                }
                html += '</div>';
                html += '</div>';
            });
        }
        html += '</div>';
    });
    container.innerHTML = html;
}

function bleReadChar(uuid, elemId) {
    var addr = document.getElementById('ble-device-select').value;
    postJSON('/ble/read', {address: addr, characteristic: uuid}).then(function(data) {
        var el = document.getElementById(elemId + '-val');
        if (data.error) { if (el) el.textContent = 'Error: ' + data.error; return; }
        if (el) el.textContent = data.value || '(empty)';
    });
}

function bleWriteChar(uuid, elemId) {
    var addr = document.getElementById('ble-device-select').value;
    var input = document.getElementById(elemId + '-input');
    var val = input ? input.value.trim() : '';
    if (!val) return;
    postJSON('/ble/write', {address: addr, characteristic: uuid, value: val}).then(function(data) {
        var el = document.getElementById(elemId + '-val');
        if (data.error) { if (el) el.textContent = 'Error: ' + data.error; return; }
        if (el) el.textContent = 'Written: ' + val;
    });
}

/* ── Proximity Tracking ── */
function bleStartTracking() {
    var addr = document.getElementById('ble-device-select').value;
    if (!addr) { document.getElementById('ble-connect-status').textContent = 'Select a device first'; return; }
    document.getElementById('btn-ble-track').style.display = 'none';
    document.getElementById('btn-ble-track-stop').style.display = '';
    bleRssiData = [];
    bleTrackInterval = setInterval(function() { bleTrackPoll(addr); }, 1000);
}

function bleStopTracking() {
    if (bleTrackInterval) { clearInterval(bleTrackInterval); bleTrackInterval = null; }
    document.getElementById('btn-ble-track').style.display = '';
    document.getElementById('btn-ble-track-stop').style.display = 'none';
}

function bleTrackPoll(addr) {
    fetchJSON('/ble/rssi?address=' + encodeURIComponent(addr)).then(function(data) {
        if (data.error) return;
        var rssi = data.rssi || -100;
        var distance = bleEstimateDistance(rssi);
        document.getElementById('ble-distance').textContent = distance.toFixed(1) + ' m';
        document.getElementById('ble-rssi-current').textContent = 'RSSI: ' + rssi + ' dBm';

        bleRssiData.push(rssi);
        if (bleRssiData.length > 60) bleRssiData.shift();
        bleDrawRssiChart();

        var entry = {
            timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19),
            address: addr,
            rssi: rssi,
            distance: distance.toFixed(1)
        };
        bleTrackHistory.push(entry);
        bleRenderHistory();
    });
}

function bleEstimateDistance(rssi) {
    /* Approximate using log-distance path loss model, txPower ~ -59 dBm at 1m */
    var txPower = -59;
    if (rssi === 0) return -1;
    var ratio = rssi / txPower;
    if (ratio < 1.0) return Math.pow(ratio, 10);
    return 0.89976 * Math.pow(ratio, 7.7095) + 0.111;
}

function bleDrawRssiChart() {
    var canvas = document.getElementById('ble-rssi-canvas');
    if (!canvas) return;
    var ctx = canvas.getContext('2d');
    var w = canvas.parentElement.offsetWidth;
    var h = canvas.parentElement.offsetHeight;
    canvas.width = w;
    canvas.height = h;
    ctx.clearRect(0, 0, w, h);

    if (bleRssiData.length < 2) return;

    var minR = -100, maxR = -20;
    ctx.strokeStyle = '#6366f1';
    ctx.lineWidth = 2;
    ctx.beginPath();
    for (var i = 0; i < bleRssiData.length; i++) {
        var x = (i / (bleRssiData.length - 1)) * w;
        var y = h - ((bleRssiData[i] - minR) / (maxR - minR)) * h;
        if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
    }
    ctx.stroke();
}

function bleRenderHistory() {
    var tbody = document.getElementById('ble-history-body');
    if (!bleTrackHistory.length) {
        tbody.innerHTML = '<tr><td colspan="4" class="empty-state">No tracking history.</td></tr>';
        return;
    }
    var html = '';
    var start = Math.max(0, bleTrackHistory.length - 50);
    for (var i = bleTrackHistory.length - 1; i >= start; i--) {
        var e = bleTrackHistory[i];
        html += '<tr>'
            + '<td style="font-size:0.8rem">' + esc(e.timestamp) + '</td>'
            + '<td style="font-family:monospace;font-size:0.8rem">' + esc(e.address) + '</td>'
            + '<td>' + esc(String(e.rssi)) + ' dBm</td>'
            + '<td>' + esc(e.distance) + '</td>'
            + '</tr>';
    }
    tbody.innerHTML = html;
}

function bleClearHistory() {
    bleTrackHistory = [];
    bleRenderHistory();
}

function bleExportHistory() {
    var blob = new Blob([JSON.stringify(bleTrackHistory, null, 2)], {type: 'application/json'});
    var a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'ble_tracking_history.json';
    a.click();
}
</script>
{% endblock %}


Instruction: Create an AUTARCH web template for the 'C2 Framework' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: c2_framework.html
Sections: 0
Tabs: 2
Forms/API calls: 11
Has JavaScript: True

Output:
{% extends "base.html" %}
{% block title %}C2 Framework — AUTARCH{% endblock %}
{% block content %}
<div class="page-header">
    <h1>C2 Framework</h1>
    <p class="text-muted">Command & Control — listeners, agents, task queue</p>
</div>

<div class="tabs">
    <button class="tab active" onclick="switchTab('dashboard')">Dashboard</button>
    <button class="tab" onclick="switchTab('agents')">Agents <span id="agent-badge" class="badge" style="display:none">0</span></button>
    <button class="tab" onclick="switchTab('generate')">Generate</button>
</div>

<!-- Dashboard -->
<div id="tab-dashboard" class="tab-content active">
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem">
        <div class="card">
            <h3>Listeners</h3>
            <div style="display:flex;gap:0.5rem;align-items:end;margin-bottom:1rem">
                <input type="text" id="ls-name" class="form-control" placeholder="name" style="width:120px">
                <input type="number" id="ls-port" class="form-control" placeholder="4444" value="4444" style="width:100px">
                <button class="btn btn-primary btn-sm" onclick="startListener()">Start</button>
            </div>
            <div id="listeners-list"></div>
        </div>
        <div class="card">
            <h3>Active Agents</h3>
            <div id="dash-agents"></div>
        </div>
    </div>
    <div class="card" style="margin-top:1rem">
        <h3>Recent Tasks</h3>
        <div id="dash-tasks"></div>
    </div>
</div>

<!-- Agents -->
<div id="tab-agents" class="tab-content" style="display:none">
    <div id="agent-list"></div>
    <!-- Agent Interaction -->
    <div id="agent-shell" class="card" style="margin-top:1rem;display:none">
        <div style="display:flex;justify-content:space-between;align-items:center">
            <h3>Agent: <span id="shell-agent-id" style="color:var(--accent)"></span></h3>
            <div>
                <button class="btn btn-sm" onclick="agentSysinfo()">Sysinfo</button>
                <button class="btn btn-sm" style="color:var(--danger)" onclick="document.getElementById('agent-shell').style.display='none'">Close</button>
            </div>
        </div>
        <div id="agent-output" style="background:#0a0a0a;color:#0f0;font-family:monospace;font-size:0.8rem;
            padding:1rem;border-radius:var(--radius);height:350px;overflow-y:auto;white-space:pre-wrap;margin:0.5rem 0"></div>
        <div style="display:flex;gap:0.5rem">
            <input type="text" id="agent-cmd" class="form-control" placeholder="Command..." style="font-family:monospace"
                   onkeypress="if(event.key==='Enter')agentExec()">
            <button class="btn btn-primary" onclick="agentExec()">Run</button>
        </div>
    </div>
</div>

<!-- Generate -->
<div id="tab-generate" class="tab-content" style="display:none">
    <div class="card" style="max-width:700px">
        <h3>Generate Agent Payload</h3>
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem">
            <div class="form-group"><label>Callback Host</label>
                <input type="text" id="gen-host" class="form-control" placeholder="your-ip"></div>
            <div class="form-group"><label>Callback Port</label>
                <input type="number" id="gen-port" class="form-control" value="4444"></div>
            <div class="form-group"><label>Agent Type</label>
                <select id="gen-type" class="form-control">
                    <option value="python">Python</option>
                    <option value="bash">Bash</option>
                    <option value="powershell">PowerShell</option>
                </select></div>
            <div class="form-group"><label>Beacon Interval (sec)</label>
                <input type="number" id="gen-interval" class="form-control" value="5"></div>
        </div>
        <div style="display:flex;gap:0.5rem;margin-top:0.5rem">
            <button class="btn btn-primary" onclick="generateAgent()">Generate Agent</button>
            <button class="btn" onclick="getOneliner()">Get One-Liner</button>
        </div>
        <div id="gen-result" style="margin-top:1rem"></div>
    </div>
</div>

<style>
.badge{display:inline-block;background:var(--danger);color:#fff;border-radius:10px;padding:0 6px;font-size:0.7rem;margin-left:4px;vertical-align:top}
.agent-status-active{color:#22c55e}.agent-status-stale{color:#f59e0b}.agent-status-dead{color:var(--danger)}
.spinner-inline{display:inline-block;width:14px;height:14px;border:2px solid var(--border);border-top-color:var(--accent);border-radius:50%;animation:spin 0.8s linear infinite;vertical-align:middle;margin-right:6px}
@keyframes spin{to{transform:rotate(360deg)}}
</style>

<script>
let currentAgentId=null;
let refreshTimer=null;

function switchTab(name){
    document.querySelectorAll('.tab').forEach((t,i)=>t.classList.toggle('active',['dashboard','agents','generate'][i]===name));
    document.querySelectorAll('.tab-content').forEach(c=>c.style.display='none');
    document.getElementById('tab-'+name).style.display='block';
    if(name==='dashboard'||name==='agents') refreshDashboard();
}

function refreshDashboard(){
    fetch('/c2/listeners').then(r=>r.json()).then(d=>{
        const list=document.getElementById('listeners-list');
        const ls=d.listeners||[];
        list.innerHTML=ls.length?ls.map(l=>`<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 0;border-bottom:1px solid var(--border)">
            <div><strong>${esc(l.name)}</strong> — ${l.host}:${l.port} (${l.connections} conn)</div>
            <button class="btn btn-sm" style="color:var(--danger)" onclick="stopListener('${esc(l.name)}')">Stop</button>
        </div>`).join(''):'<div style="color:var(--text-muted);font-size:0.85rem">No listeners running</div>';
    });

    fetch('/c2/agents').then(r=>r.json()).then(d=>{
        const agents=d.agents||[];
        const badge=document.getElementById('agent-badge');
        if(agents.length){badge.style.display='';badge.textContent=agents.length}
        else{badge.style.display='none'}

        document.getElementById('dash-agents').innerHTML=agents.length?agents.map(a=>
            `<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 0;border-bottom:1px solid var(--border);cursor:pointer" onclick="interactAgent('${a.id}')">
                <div><span class="agent-status-${a.status}">&#x25cf;</span> <strong>${esc(a.id)}</strong>
                    — ${esc(a.user)}@${esc(a.hostname)} (${esc(a.os)})</div>
                <span style="font-size:0.75rem;color:var(--text-muted)">${esc(a.remote_addr)}</span>
            </div>`).join(''):'<div style="color:var(--text-muted);font-size:0.85rem">No agents connected</div>';

        document.getElementById('agent-list').innerHTML=agents.length?agents.map(a=>
            `<div class="card" style="margin-bottom:0.5rem">
                <div style="display:flex;justify-content:space-between;align-items:center">
                    <div><span class="agent-status-${a.status}">&#x25cf;</span>
                        <strong>${esc(a.id)}</strong> — ${esc(a.user)}@${esc(a.hostname)}</div>
                    <div style="display:flex;gap:0.5rem;align-items:center">
                        <span style="font-size:0.75rem;color:var(--text-muted)">${esc(a.os)} ${esc(a.arch)} | ${esc(a.remote_addr)}</span>
                        <button class="btn btn-sm btn-primary" onclick="interactAgent('${a.id}')">Interact</button>
                        <button class="btn btn-sm" style="color:var(--danger)" onclick="removeAgent('${a.id}')">Remove</button>
                    </div>
                </div>
            </div>`).join(''):'';
    });

    fetch('/c2/tasks').then(r=>r.json()).then(d=>{
        const tasks=(d.tasks||[]).slice(0,20);
        document.getElementById('dash-tasks').innerHTML=tasks.length?
            '<table class="data-table"><thead><tr><th>Task</th><th>Agent</th><th>Type</th><th>Status</th><th>Time</th></tr></thead><tbody>'+
            tasks.map(t=>`<tr><td style="font-family:monospace;font-size:0.8rem">${t.id}</td><td>${t.agent_id}</td><td>${t.type}</td>
                <td style="color:${t.status==='completed'?'#22c55e':t.status==='failed'?'var(--danger)':'var(--text-muted)'}">${t.status}</td>
                <td style="font-size:0.75rem">${(t.created_at||'').slice(11,19)}</td></tr>`).join('')+'</tbody></table>'
            :'<div style="color:var(--text-muted);font-size:0.85rem">No tasks</div>';
    });
}

function startListener(){
    const name=document.getElementById('ls-name').value.trim()||'default';
    const port=+document.getElementById('ls-port').value||4444;
    fetch('/c2/listeners',{method:'POST',headers:{'Content-Type':'application/json'},
        body:JSON.stringify({name,port})})
    .then(r=>r.json()).then(d=>{
        if(!d.ok) alert(d.error);
        refreshDashboard();
    });
}

function stopListener(name){
    fetch('/c2/listeners/'+encodeURIComponent(name),{method:'DELETE'})
    .then(r=>r.json()).then(()=>refreshDashboard());
}

function removeAgent(id){
    if(!confirm('Remove agent '+id+'?')) return;
    fetch('/c2/agents/'+id,{method:'DELETE'}).then(r=>r.json()).then(()=>refreshDashboard());
}

function interactAgent(id){
    currentAgentId=id;
    document.getElementById('agent-shell').style.display='';
    document.getElementById('shell-agent-id').textContent=id;
    document.getElementById('agent-output').textContent='Connected to agent '+id+'\n';
    document.getElementById('agent-cmd').focus();
    switchTab('agents');
}

function agentExec(){
    if(!currentAgentId) return;
    const input=document.getElementById('agent-cmd');
    const cmd=input.value.trim();
    if(!cmd) return;
    input.value='';
    const out=document.getElementById('agent-output');
    out.textContent+='> '+cmd+'\n';
    fetch('/c2/agents/'+currentAgentId+'/exec',{method:'POST',headers:{'Content-Type':'application/json'},
        body:JSON.stringify({command:cmd})})
    .then(r=>r.json()).then(d=>{
        if(!d.ok){out.textContent+='[error] '+d.error+'\n';return}
        pollTask(d.task_id);
    });
}

function agentSysinfo(){
    if(!currentAgentId) return;
    fetch('/c2/agents/'+currentAgentId+'/exec',{method:'POST',headers:{'Content-Type':'application/json'},
        body:JSON.stringify({command:navigator.platform.includes('Win')?'systeminfo':'uname -a && whoami && id'})})
    .then(r=>r.json()).then(d=>{if(d.ok) pollTask(d.task_id)});
}

function pollTask(taskId){
    const out=document.getElementById('agent-output');
    let attempts=0;
    const poll=setInterval(()=>{
        fetch('/c2/tasks/'+taskId).then(r=>r.json()).then(d=>{
            if(d.status==='completed'||d.status==='failed'){
                clearInterval(poll);
                if(d.result){
                    const stdout=d.result.stdout||'';
                    const stderr=d.result.stderr||'';
                    if(stdout) out.textContent+=stdout+(stdout.endsWith('\n')?'':'\n');
                    if(stderr) out.textContent+='[stderr] '+stderr+'\n';
                    if(d.result.error) out.textContent+='[error] '+d.result.error+'\n';
                }
                out.scrollTop=out.scrollHeight;
            }
            if(++attempts>30){clearInterval(poll);out.textContent+='[timeout]\n'}
        });
    },1000);
}

function generateAgent(){
    const payload={host:document.getElementById('gen-host').value.trim(),
        port:+document.getElementById('gen-port').value,
        type:document.getElementById('gen-type').value,
        interval:+document.getElementById('gen-interval').value};
    fetch('/c2/generate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
    .then(r=>r.json()).then(d=>{
        const div=document.getElementById('gen-result');
        if(!d.ok){div.innerHTML='Error: '+esc(d.error);return}
        div.innerHTML=`<div style="margin-bottom:0.5rem"><strong>Agent ID:</strong> ${d.agent_id} | <strong>File:</strong> ${esc(d.filename)}</div>
            <pre style="background:#0a0a0a;color:#ccc;padding:1rem;border-radius:var(--radius);max-height:300px;overflow:auto;font-size:0.75rem">${esc(d.code)}</pre>
            <button class="btn btn-sm" onclick="navigator.clipboard.writeText(document.querySelector('#gen-result pre').textContent)">Copy to Clipboard</button>`;
    });
}

function getOneliner(){
    const payload={host:document.getElementById('gen-host').value.trim(),
        port:+document.getElementById('gen-port').value,
        type:document.getElementById('gen-type').value};
    fetch('/c2/oneliner',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
    .then(r=>r.json()).then(d=>{
        const div=document.getElementById('gen-result');
        if(!d.ok){div.innerHTML='Error: '+esc(d.error);return}
        div.innerHTML=`<div style="margin-bottom:0.5rem"><strong>One-Liner (${d.type}):</strong></div>
            <pre style="background:#0a0a0a;color:#0f0;padding:1rem;border-radius:var(--radius);font-size:0.8rem;word-break:break-all">${esc(d.oneliner)}</pre>
            <button class="btn btn-sm" onclick="navigator.clipboard.writeText('${esc(d.oneliner).replace(/'/g,"\\'")}')">Copy</button>`;
    });
}

refreshDashboard();
if(!refreshTimer) refreshTimer=setInterval(refreshDashboard,10000);

function esc(s){return s?String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;'):''}
</script>
{% endblock %}


Instruction: Create an AUTARCH web template for the 'Category' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: category.html
Sections: 1
Tabs: 0
Forms/API calls: 0
Has JavaScript: False

Output:
{% extends "base.html" %}
{% block title %}{{ cat_name }} - AUTARCH{% endblock %}

{% block content %}

{{ cat_name }}

{% if modules %}

Modules

    {% for name, info in modules.items() %}

{{ name }}

{{ info.description }}

v{{ info.version }} by {{ info.author }}

    {% endfor %}

{% else %}

No modules in this category.

{% endif %}
{% endblock %}


Instruction: Create an AUTARCH web template for the 'Cloud Scan' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: cloud_scan.html
Sections: 4
Tabs: 2
Forms/API calls: 0
Has JavaScript: True

Output:
{% extends "base.html" %}
{% block title %}AUTARCH — Cloud Security{% endblock %}

{% block content %}
<div class="page-header">
    <h1>Cloud Security Scanner</h1>
    <p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
        Discover exposed cloud storage buckets, misconfigured services, and enumerate subdomains.
    </p>
</div>

<!-- Tab Bar -->
<div class="tab-bar">
    <button class="tab active" data-tab-group="cloud" data-tab="buckets" onclick="showTab('cloud','buckets')">Buckets</button>
    <button class="tab" data-tab-group="cloud" data-tab="services" onclick="showTab('cloud','services')">Services</button>
    <button class="tab" data-tab-group="cloud" data-tab="subdomains" onclick="showTab('cloud','subdomains')">Subdomains</button>
</div>

<!-- ==================== BUCKETS TAB ==================== -->
<div class="tab-content active" data-tab-group="cloud" data-tab="buckets">

<div class="section">
    <h2>Bucket Discovery</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Search for publicly accessible cloud storage buckets by keyword or company name.
    </p>
    <div class="form-row" style="margin-bottom:12px">
        <div class="form-group">
            <label>Keyword / Company Name</label>
            <input type="text" id="cloud-bucket-keyword" placeholder="e.g. acme-corp, staging, backups">
        </div>
    </div>
    <div style="margin-bottom:12px">
        <span style="font-size:0.85rem;color:var(--text-secondary);margin-right:12px">Providers:</span>
        <label style="margin-right:12px;font-size:0.85rem;color:var(--text-primary);cursor:pointer">
            <input type="checkbox" id="cloud-prov-aws" checked style="margin-right:4px"> AWS S3
        </label>
        <label style="margin-right:12px;font-size:0.85rem;color:var(--text-primary);cursor:pointer">
            <input type="checkbox" id="cloud-prov-gcs" checked style="margin-right:4px"> Google Cloud Storage
        </label>
        <label style="margin-right:12px;font-size:0.85rem;color:var(--text-primary);cursor:pointer">
            <input type="checkbox" id="cloud-prov-azure" checked style="margin-right:4px"> Azure Blob
        </label>
    </div>
    <div class="tool-actions" style="margin-bottom:12px">
        <button id="btn-bucket-scan" class="btn btn-primary" onclick="cloudBucketScan()">Scan Buckets</button>
        <span id="cloud-bucket-status" style="font-size:0.8rem;color:var(--text-muted);margin-left:12px"></span>
    </div>
    <table class="data-table">
        <thead><tr><th>Bucket Name</th><th>Provider</th><th>Status</th><th>Public</th><th>Listable</th></tr></thead>
        <tbody id="cloud-bucket-results">
            <tr><td colspan="5" class="empty-state">Enter a keyword and click Scan to discover buckets.</td></tr>
        </tbody>
    </table>
</div>

</div>

<!-- ==================== SERVICES TAB ==================== -->
<div class="tab-content" data-tab-group="cloud" data-tab="services">

<div class="section">
    <h2>Exposed Services Scanner</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px">
        Probe a target URL for commonly exposed cloud services, admin panels, and metadata endpoints.
    </p>
    <div class="input-row">
        <input type="text" id="cloud-svc-url" placeholder="Target URL (e.g. https://example.com)">
        <button id="btn-svc-scan" class="btn btn-primary" onclick="cloudServiceScan()">Scan Services</button>
    </div>
    <table class="data-table" style="margin-bottom:20px">
        <thead><tr><th>Path</th><th>Service</th><th>Status</th><th>Sensitive</th></tr></thead>
        <tbody id="cloud-svc-results">
            <tr><td colspan="4" class="empty-state">Enter a target URL and scan for exposed services.</td></tr>
        </tbody>
    </table>
</div>

<div class="section">
    <h2>Cloud Metadata SSRF Check</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px">
        Test for accessible cloud metadata endpoints (IMDS) that may be reachable via SSRF.
    </p>
    <div class="input-row">
        <input type="text" id="cloud-ssrf-url" placeholder="Target URL with SSRF vector">
        <button id="btn-ssrf-check" class="btn btn-warning" onclick="cloudSSRFCheck()">Check SSRF</button>
    </div>
    <pre class="output-panel" id="cloud-ssrf-output" style="min-height:0"></pre>
</div>

</div>

<!-- ==================== SUBDOMAINS TAB ==================== -->
<div class="tab-content" data-tab-group="cloud" data-tab="subdomains">

<div class="section">
    <h2>Subdomain Enumeration</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:8px">
        Enumerate subdomains for a target domain and identify cloud provider hints.
    </p>
    <div class="input-row">
        <input type="text" id="cloud-sub-domain" placeholder="Target domain (e.g. example.com)">
        <button id="btn-sub-enum" class="btn btn-primary" onclick="cloudSubdomainEnum()">Enumerate</button>
    </div>
    <span id="cloud-sub-status" style="font-size:0.8rem;color:var(--text-muted)"></span>
    <table class="data-table" style="margin-top:12px">
        <thead><tr><th>Subdomain</th><th>IP Address</th><th>Cloud Provider</th></tr></thead>
        <tbody id="cloud-sub-results">
            <tr><td colspan="3" class="empty-state">Enter a domain and click Enumerate to discover subdomains.</td></tr>
        </tbody>
    </table>
</div>

</div>

<script>
function esc(s) { return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;'); }

/* ── Buckets ── */
var _bucketPoll = null;

function cloudBucketScan() {
    var keyword = document.getElementById('cloud-bucket-keyword').value.trim();
    if (!keyword) return;
    var providers = [];
    if (document.getElementById('cloud-prov-aws').checked) providers.push('aws');
    if (document.getElementById('cloud-prov-gcs').checked) providers.push('gcs');
    if (document.getElementById('cloud-prov-azure').checked) providers.push('azure');
    if (!providers.length) { alert('Select at least one provider.'); return; }

    var btn = document.getElementById('btn-bucket-scan');
    setLoading(btn, true);
    document.getElementById('cloud-bucket-status').textContent = 'Scanning...';
    document.getElementById('cloud-bucket-results').innerHTML = '<tr><td colspan="5" class="empty-state">Scanning...</td></tr>';

    postJSON('/cloud/buckets/scan', {keyword: keyword, providers: providers}).then(function(data) {
        if (data.error) {
            setLoading(btn, false);
            document.getElementById('cloud-bucket-status').textContent = 'Error';
            renderOutput('cloud-bucket-results', data.error);
            return;
        }
        if (data.job_id) {
            cloudPollBuckets(data.job_id);
        } else {
            setLoading(btn, false);
            cloudRenderBuckets(data.results || []);
        }
    }).catch(function() {
        setLoading(btn, false);
        document.getElementById('cloud-bucket-status').textContent = 'Request failed';
    });
}

function cloudPollBuckets(jobId) {
    if (_bucketPoll) clearInterval(_bucketPoll);
    _bucketPoll = setInterval(function() {
        fetchJSON('/cloud/buckets/status/' + jobId).then(function(data) {
            if (data.status === 'running') {
                document.getElementById('cloud-bucket-status').textContent = 'Scanning... (' + (data.checked || 0) + ' checked)';
                if (data.partial) cloudRenderBuckets(data.partial);
            } else {
                clearInterval(_bucketPoll);
                _bucketPoll = null;
                setLoading(document.getElementById('btn-bucket-scan'), false);
                document.getElementById('cloud-bucket-status').textContent = 'Done (' + (data.total || 0) + ' found)';
                cloudRenderBuckets(data.results || []);
            }
        }).catch(function() {
            clearInterval(_bucketPoll);
            _bucketPoll = null;
            setLoading(document.getElementById('btn-bucket-scan'), false);
            document.getElementById('cloud-bucket-status').textContent = 'Poll error';
        });
    }, 2000);
}

function cloudRenderBuckets(results) {
    var tb = document.getElementById('cloud-bucket-results');
    if (!results.length) {
        tb.innerHTML = '<tr><td colspan="5" class="empty-state">No buckets found.</td></tr>';
        return;
    }
    var html = '';
    results.forEach(function(r) {
        var statusBadge = r.status === 'exists' ? '<span class="badge badge-pass">Exists</span>'
                        : r.status === 'not_found' ? '<span class="badge badge-info">Not Found</span>'
                        : '<span class="badge badge-medium">' + esc(r.status) + '</span>';
        html += '<tr><td style="font-family:monospace">' + esc(r.name) + '</td>'
            + '<td>' + esc(r.provider) + '</td>'
            + '<td>' + statusBadge + '</td>'
            + '<td>' + (r.public ? '<span class="badge badge-fail">PUBLIC</span>' : '<span class="badge badge-pass">Private</span>') + '</td>'
            + '<td>' + (r.listable ? '<span class="badge badge-fail">YES</span>' : '--') + '</td></tr>';
    });
    tb.innerHTML = html;
}

/* ── Services ── */
function cloudServiceScan() {
    var url = document.getElementById('cloud-svc-url').value.trim();
    if (!url) return;
    var btn = document.getElementById('btn-svc-scan');
    setLoading(btn, true);
    postJSON('/cloud/services/scan', {url: url}).then(function(data) {
        setLoading(btn, false);
        var tb = document.getElementById('cloud-svc-results');
        if (data.error) {
            tb.innerHTML = '<tr><td colspan="4" class="empty-state">Error: ' + esc(data.error) + '</td></tr>';
            return;
        }
        var results = data.results || [];
        if (!results.length) {
            tb.innerHTML = '<tr><td colspan="4" class="empty-state">No exposed services detected.</td></tr>';
            return;
        }
        var html = '';
        results.forEach(function(r) {
            var sensitiveBadge = r.sensitive ? '<span class="badge badge-fail">SENSITIVE</span>' : '--';
            html += '<tr><td style="font-family:monospace;font-size:0.85rem">' + esc(r.path) + '</td>'
                + '<td>' + esc(r.name) + '</td>'
                + '<td><span class="badge badge-' + (r.status < 400 ? 'pass' : 'info') + '">' + r.status + '</span></td>'
                + '<td>' + sensitiveBadge + '</td></tr>';
        });
        tb.innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

/* ── SSRF ── */
function cloudSSRFCheck() {
    var url = document.getElementById('cloud-ssrf-url').value.trim();
    if (!url) return;
    var btn = document.getElementById('btn-ssrf-check');
    setLoading(btn, true);
    postJSON('/cloud/ssrf/check', {url: url}).then(function(data) {
        setLoading(btn, false);
        renderOutput('cloud-ssrf-output', data.output || data.error || 'No result');
    }).catch(function() { setLoading(btn, false); });
}

/* ── Subdomains ── */
function cloudSubdomainEnum() {
    var domain = document.getElementById('cloud-sub-domain').value.trim();
    if (!domain) return;
    var btn = document.getElementById('btn-sub-enum');
    setLoading(btn, true);
    document.getElementById('cloud-sub-status').textContent = 'Enumerating...';
    postJSON('/cloud/subdomains/enumerate', {domain: domain}).then(function(data) {
        setLoading(btn, false);
        var tb = document.getElementById('cloud-sub-results');
        if (data.error) {
            document.getElementById('cloud-sub-status').textContent = 'Error';
            tb.innerHTML = '<tr><td colspan="3" class="empty-state">Error: ' + esc(data.error) + '</td></tr>';
            return;
        }
        var results = data.results || [];
        document.getElementById('cloud-sub-status').textContent = results.length + ' subdomains found';
        if (!results.length) {
            tb.innerHTML = '<tr><td colspan="3" class="empty-state">No subdomains found.</td></tr>';
            return;
        }
        var html = '';
        results.forEach(function(r) {
            var provHint = r.cloud_provider ? '<span class="badge badge-info">' + esc(r.cloud_provider) + '</span>' : '--';
            html += '<tr><td style="font-family:monospace">' + esc(r.subdomain) + '</td>'
                + '<td style="font-family:monospace">' + esc(r.ip || '--') + '</td>'
                + '<td>' + provHint + '</td></tr>';
        });
        tb.innerHTML = html;
    }).catch(function() {
        setLoading(btn, false);
        document.getElementById('cloud-sub-status').textContent = 'Request failed';
    });
}
</script>
{% endblock %}


Instruction: Create an AUTARCH web template for the 'Container Sec' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: container_sec.html
Sections: 13
Tabs: 2
Forms/API calls: 0
Has JavaScript: True

Output:
{% extends "base.html" %}
{% block title %}AUTARCH — Container Security{% endblock %}

{% block content %}
<div class="page-header">
    <h1>Container Security</h1>
    <p style="margin:0;font-size:0.85rem;color:var(--text-secondary)">
        Docker auditing, Kubernetes assessment, container image scanning, escape detection, and Dockerfile linting.
    </p>
</div>

<!-- Tool Status -->
<div class="section" style="padding:12px 16px;display:flex;gap:24px;align-items:center;flex-wrap:wrap">
    <span id="cs-docker-status" style="font-size:0.85rem;color:var(--text-muted)">Docker: checking...</span>
    <span id="cs-kubectl-status" style="font-size:0.85rem;color:var(--text-muted)">kubectl: checking...</span>
    <button class="btn btn-small" onclick="csCheckStatus()" style="margin-left:auto">Refresh Status</button>
</div>

<!-- Tab Bar -->
<div class="tab-bar">
    <button class="tab active" data-tab-group="cs" data-tab="docker" onclick="showTab('cs','docker')">Docker</button>
    <button class="tab" data-tab-group="cs" data-tab="k8s" onclick="showTab('cs','k8s')">Kubernetes</button>
    <button class="tab" data-tab-group="cs" data-tab="imgscan" onclick="showTab('cs','imgscan')">Image Scan</button>
</div>

<!-- ==================== DOCKER TAB ==================== -->
<div class="tab-content active" data-tab-group="cs" data-tab="docker">

<!-- Docker Host Audit -->
<div class="section">
    <h2>Docker Host Audit</h2>
    <div class="tool-actions">
        <button id="btn-docker-audit" class="btn btn-primary" onclick="csDockerAudit()">Audit Docker Host</button>
    </div>
    <table class="data-table">
        <thead><tr><th>Check</th><th>Severity</th><th>Status</th><th>Detail</th></tr></thead>
        <tbody id="cs-docker-audit-results">
            <tr><td colspan="4" class="empty-state">Click "Audit Docker Host" to check daemon configuration and security.</td></tr>
        </tbody>
    </table>
</div>

<!-- Containers -->
<div class="section">
    <h2>Containers</h2>
    <div class="tool-actions">
        <button id="btn-list-containers" class="btn btn-small" onclick="csListContainers()">Refresh Containers</button>
    </div>
    <table class="data-table">
        <thead><tr><th>Name</th><th>Image</th><th>Status</th><th>Ports</th><th style="width:180px">Actions</th></tr></thead>
        <tbody id="cs-containers-list">
            <tr><td colspan="5" class="empty-state">Click "Refresh Containers" to list Docker containers.</td></tr>
        </tbody>
    </table>
</div>

<!-- Container Audit Results -->
<div class="section" id="cs-container-audit-section" style="display:none">
    <h2>Container Audit — <span id="cs-container-audit-name"></span></h2>
    <div style="display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap">
        <div class="score-display">
            <div class="score-value" id="cs-container-score">--</div>
            <div class="score-label">Security Score</div>
        </div>
        <div style="flex:1;min-width:300px">
            <table class="data-table">
                <thead><tr><th>Check</th><th>Status</th><th>Detail</th></tr></thead>
                <tbody id="cs-container-audit-results"></tbody>
            </table>
        </div>
    </div>
</div>

<!-- Escape Vector Results -->
<div class="section" id="cs-escape-section" style="display:none">
    <h2>Escape Vectors — <span id="cs-escape-name"></span></h2>
    <div style="display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap;margin-bottom:12px">
        <div class="score-display">
            <div class="score-value" id="cs-escape-score" style="color:var(--danger)">--</div>
            <div class="score-label">Risk Score</div>
        </div>
        <div style="font-size:0.85rem;color:var(--text-secondary)">
            <div>Total vectors: <span id="cs-escape-total">0</span></div>
            <div>Exploitable: <span id="cs-escape-exploitable" style="color:var(--danger)">0</span></div>
        </div>
    </div>
    <table class="data-table">
        <thead><tr><th>Vector</th><th>Risk</th><th>Exploitable</th><th>Detail</th></tr></thead>
        <tbody id="cs-escape-results"></tbody>
    </table>
</div>

</div><!-- /docker tab -->

<!-- ==================== KUBERNETES TAB ==================== -->
<div class="tab-content" data-tab-group="cs" data-tab="k8s">

<!-- Namespace Selector -->
<div class="section">
    <h2>Kubernetes Cluster</h2>
    <div class="form-row" style="align-items:flex-end;gap:12px;margin-bottom:12px">
        <div class="form-group" style="min-width:200px">
            <label>Namespace</label>
            <select id="cs-k8s-ns" style="width:100%;padding:6px 10px;background:var(--bg-input);border:1px solid var(--border);border-radius:var(--radius);color:var(--text-primary)">
                <option value="default">default</option>
            </select>
        </div>
        <button class="btn btn-small" onclick="csLoadNamespaces()">Refresh Namespaces</button>
    </div>
</div>

<!-- Pods -->
<div class="section">
    <h2>Pods</h2>
    <div class="tool-actions">
        <button id="btn-k8s-pods" class="btn btn-small" onclick="csK8sPods()">List Pods</button>
    </div>
    <table class="data-table">
        <thead><tr><th>Name</th><th>Status</th><th>Containers</th><th>Node</th><th>Restarts</th><th style="width:100px">Actions</th></tr></thead>
        <tbody id="cs-k8s-pods-list">
            <tr><td colspan="6" class="empty-state">Select a namespace and click "List Pods".</td></tr>
        </tbody>
    </table>
</div>

<!-- K8s Audit Tools -->
<div class="section">
    <h2>Cluster Security Checks</h2>
    <div class="tool-grid">
        <div class="tool-card">
            <h4>RBAC Audit</h4>
            <p>Check for overly permissive bindings and wildcard permissions</p>
            <button id="btn-k8s-rbac" class="btn btn-small" onclick="csK8sRBAC()">Run RBAC Audit</button>
            <div id="cs-k8s-rbac-results" style="margin-top:8px"></div>
        </div>
        <div class="tool-card">
            <h4>Secrets Check</h4>
            <p>Find exposed and unencrypted secrets in the namespace</p>
            <button id="btn-k8s-secrets" class="btn btn-small" onclick="csK8sSecrets()">Check Secrets</button>
            <div id="cs-k8s-secrets-results" style="margin-top:8px"></div>
        </div>
        <div class="tool-card">
            <h4>Network Policies</h4>
            <p>Verify NetworkPolicies exist and find unprotected pods</p>
            <button id="btn-k8s-netpol" class="btn btn-small" onclick="csK8sNetPolicies()">Check Policies</button>
            <div id="cs-k8s-netpol-results" style="margin-top:8px"></div>
        </div>
    </div>
</div>

<!-- K8s Pod Audit Results -->
<div class="section" id="cs-k8s-pod-audit-section" style="display:none">
    <h2>Pod Audit — <span id="cs-k8s-pod-audit-name"></span></h2>
    <div style="display:flex;gap:24px;align-items:flex-start;flex-wrap:wrap">
        <div class="score-display">
            <div class="score-value" id="cs-k8s-pod-score">--</div>
            <div class="score-label">Security Score</div>
        </div>
        <div style="flex:1;min-width:300px">
            <table class="data-table">
                <thead><tr><th>Check</th><th>Status</th><th>Detail</th></tr></thead>
                <tbody id="cs-k8s-pod-audit-results"></tbody>
            </table>
        </div>
    </div>
</div>

</div><!-- /k8s tab -->

<!-- ==================== IMAGE SCAN TAB ==================== -->
<div class="tab-content" data-tab-group="cs" data-tab="imgscan">

<!-- Image Scan -->
<div class="section">
    <h2>Image Vulnerability Scan</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Scan container images for known CVEs using Trivy or Grype.
    </p>
    <div class="form-row" style="align-items:flex-end;gap:12px;margin-bottom:12px">
        <div class="form-group" style="flex:1">
            <label>Image Name</label>
            <input type="text" id="cs-scan-image" placeholder="e.g., nginx:latest, ubuntu:22.04, myapp:v1.2">
        </div>
        <button id="btn-scan-image" class="btn btn-primary" onclick="csScanImage()">Scan Image</button>
    </div>
    <!-- Severity Summary -->
    <div id="cs-scan-summary" style="display:none;margin-bottom:16px">
        <div style="display:flex;gap:16px;flex-wrap:wrap">
            <div style="text-align:center;padding:8px 16px;background:var(--bg-card);border-radius:var(--radius);border-left:3px solid #dc2626">
                <div style="font-size:1.4rem;font-weight:700;color:#dc2626" id="cs-sum-critical">0</div>
                <div style="font-size:0.75rem;color:var(--text-muted)">Critical</div>
            </div>
            <div style="text-align:center;padding:8px 16px;background:var(--bg-card);border-radius:var(--radius);border-left:3px solid #f97316">
                <div style="font-size:1.4rem;font-weight:700;color:#f97316" id="cs-sum-high">0</div>
                <div style="font-size:0.75rem;color:var(--text-muted)">High</div>
            </div>
            <div style="text-align:center;padding:8px 16px;background:var(--bg-card);border-radius:var(--radius);border-left:3px solid #eab308">
                <div style="font-size:1.4rem;font-weight:700;color:#eab308" id="cs-sum-medium">0</div>
                <div style="font-size:0.75rem;color:var(--text-muted)">Medium</div>
            </div>
            <div style="text-align:center;padding:8px 16px;background:var(--bg-card);border-radius:var(--radius);border-left:3px solid #3b82f6">
                <div style="font-size:1.4rem;font-weight:700;color:#3b82f6" id="cs-sum-low">0</div>
                <div style="font-size:0.75rem;color:var(--text-muted)">Low</div>
            </div>
            <div style="text-align:center;padding:8px 16px;background:var(--bg-card);border-radius:var(--radius)">
                <div style="font-size:1.4rem;font-weight:700;color:var(--text-primary)" id="cs-sum-total">0</div>
                <div style="font-size:0.75rem;color:var(--text-muted)">Total</div>
            </div>
        </div>
    </div>
    <table class="data-table">
        <thead><tr><th>Severity</th><th>CVE</th><th>Package</th><th>Installed</th><th>Fixed</th></tr></thead>
        <tbody id="cs-scan-results">
            <tr><td colspan="5" class="empty-state">Enter an image name and click "Scan Image" to find vulnerabilities.</td></tr>
        </tbody>
    </table>
</div>

<!-- Local Images -->
<div class="section">
    <h2>Local Images</h2>
    <div class="tool-actions">
        <button id="btn-list-images" class="btn btn-small" onclick="csListImages()">Refresh Images</button>
    </div>
    <table class="data-table">
        <thead><tr><th>Repository</th><th>Tag</th><th>Size</th><th>Created</th><th style="width:80px">Actions</th></tr></thead>
        <tbody id="cs-images-list">
            <tr><td colspan="5" class="empty-state">Click "Refresh Images" to list local Docker images.</td></tr>
        </tbody>
    </table>
</div>

<!-- Dockerfile Lint -->
<div class="section">
    <h2>Dockerfile Lint</h2>
    <p style="font-size:0.8rem;color:var(--text-muted);margin-bottom:12px">
        Paste Dockerfile content below to check for security issues.
    </p>
    <textarea id="cs-dockerfile-content" rows="12"
        style="width:100%;font-family:monospace;font-size:0.85rem;padding:12px;background:var(--bg-input);color:var(--text-primary);border:1px solid var(--border);border-radius:var(--radius);resize:vertical"
        placeholder="FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl
COPY . /app
CMD [&quot;/app/start.sh&quot;]"></textarea>
    <div class="tool-actions" style="margin-top:8px">
        <button id="btn-lint-dockerfile" class="btn btn-primary" onclick="csLintDockerfile()">Lint Dockerfile</button>
        <span id="cs-lint-count" style="font-size:0.8rem;color:var(--text-muted);margin-left:12px"></span>
    </div>
    <table class="data-table" style="margin-top:12px">
        <thead><tr><th>Rule</th><th>Severity</th><th>Line</th><th>Issue</th><th>Detail</th></tr></thead>
        <tbody id="cs-lint-results">
            <tr><td colspan="5" class="empty-state">Paste a Dockerfile and click "Lint Dockerfile" to check for issues.</td></tr>
        </tbody>
    </table>
</div>

</div><!-- /imgscan tab -->

<!-- ==================== EXPORT ==================== -->
<div class="section" style="margin-top:24px;padding:12px 16px;display:flex;gap:12px;align-items:center">
    <button class="btn btn-small" onclick="csExport()">Export Results (JSON)</button>
    <span id="cs-export-msg" style="font-size:0.8rem;color:var(--text-muted)"></span>
</div>

<script>
/* ── Container Security JS ─────────────────────────────────────────────── */

var csPrefix = '/container-sec';

/* ── Status ── */
function csCheckStatus() {
    fetchJSON(csPrefix + '/status').then(function(data) {
        var dk = data.docker || {};
        var kc = data.kubectl || {};
        var dkEl = document.getElementById('cs-docker-status');
        var kcEl = document.getElementById('cs-kubectl-status');
        if (dk.installed) {
            dkEl.innerHTML = '<span style="color:var(--success)">Docker: ' + escapeHtml(dk.version || 'installed') + '</span>';
        } else {
            dkEl.innerHTML = '<span style="color:var(--danger)">Docker: not found</span>';
        }
        if (kc.installed) {
            var ctx = kc.context ? ' (' + escapeHtml(kc.context) + ')' : '';
            kcEl.innerHTML = '<span style="color:var(--success)">kubectl: installed' + ctx + '</span>';
        } else {
            kcEl.innerHTML = '<span style="color:var(--danger)">kubectl: not found</span>';
        }
    });
}
csCheckStatus();

/* ── Severity badge helper ── */
function csSevBadge(sev) {
    var colors = {
        'critical': '#dc2626', 'high': '#f97316', 'medium': '#eab308',
        'low': '#3b82f6', 'info': '#22c55e'
    };
    var s = (sev || 'info').toLowerCase();
    var c = colors[s] || '#6b7280';
    return '<span style="display:inline-block;padding:2px 8px;border-radius:4px;font-size:0.75rem;font-weight:600;background:' + c + '22;color:' + c + ';border:1px solid ' + c + '44">' + escapeHtml(s.toUpperCase()) + '</span>';
}

function csStatusBadge(status) {
    if (status === 'pass') return '<span class="badge badge-pass">PASS</span>';
    if (status === 'fail') return '<span class="badge badge-fail">FAIL</span>';
    return '<span class="badge">' + escapeHtml(status || 'INFO') + '</span>';
}

/* ── Docker Host Audit ── */
function csDockerAudit() {
    var btn = document.getElementById('btn-docker-audit');
    setLoading(btn, true);
    postJSON(csPrefix + '/docker/audit', {}).then(function(data) {
        setLoading(btn, false);
        if (data.error) { document.getElementById('cs-docker-audit-results').innerHTML = '<tr><td colspan="4">' + escapeHtml(data.error) + '</td></tr>'; return; }
        var html = '';
        (data.findings || []).forEach(function(f) {
            html += '<tr><td>' + escapeHtml(f.check) + '</td><td>' + csSevBadge(f.severity)
                + '</td><td>' + csStatusBadge(f.status) + '</td><td style="font-size:0.85rem">'
                + escapeHtml(f.detail || '') + '</td></tr>';
        });
        document.getElementById('cs-docker-audit-results').innerHTML = html || '<tr><td colspan="4">No findings.</td></tr>';
    }).catch(function() { setLoading(btn, false); });
}

/* ── Containers ── */
function csListContainers() {
    var btn = document.getElementById('btn-list-containers');
    setLoading(btn, true);
    fetchJSON(csPrefix + '/docker/containers').then(function(data) {
        setLoading(btn, false);
        var html = '';
        (data.containers || []).forEach(function(c) {
            html += '<tr><td>' + escapeHtml(c.name) + '</td><td style="font-size:0.85rem">'
                + escapeHtml(c.image) + '</td><td>' + escapeHtml(c.status) + '</td><td style="font-size:0.8rem">'
                + escapeHtml(c.ports || 'none') + '</td><td>'
                + '<button class="btn btn-small" style="margin-right:4px" onclick="csAuditContainer(\'' + escapeHtml(c.id) + '\',\'' + escapeHtml(c.name) + '\')">Audit</button>'
                + '<button class="btn btn-small btn-danger" onclick="csEscapeCheck(\'' + escapeHtml(c.id) + '\',\'' + escapeHtml(c.name) + '\')">Escape</button>'
                + '</td></tr>';
        });
        document.getElementById('cs-containers-list').innerHTML = html || '<tr><td colspan="5" class="empty-state">No containers found.</td></tr>';
    }).catch(function() { setLoading(btn, false); });
}

/* ── Container Audit ── */
function csAuditContainer(id, name) {
    document.getElementById('cs-container-audit-section').style.display = '';
    document.getElementById('cs-container-audit-name').textContent = name || id;
    document.getElementById('cs-container-score').textContent = '...';
    document.getElementById('cs-container-audit-results').innerHTML = '<tr><td colspan="3">Auditing...</td></tr>';

    postJSON(csPrefix + '/docker/containers/' + encodeURIComponent(id) + '/audit', {}).then(function(data) {
        if (data.error) {
            document.getElementById('cs-container-audit-results').innerHTML = '<tr><td colspan="3">' + escapeHtml(data.error) + '</td></tr>';
            return;
        }
        var scoreEl = document.getElementById('cs-container-score');
        scoreEl.textContent = data.score + '%';
        scoreEl.style.color = data.score >= 80 ? 'var(--success)' : data.score >= 50 ? 'var(--warning)' : 'var(--danger)';

        var html = '';
        (data.findings || []).forEach(function(f) {
            html += '<tr><td>' + escapeHtml(f.check) + '</td><td>'
                + csStatusBadge(f.status) + '</td><td style="font-size:0.85rem">'
                + escapeHtml(f.detail || '') + '</td></tr>';
        });
        document.getElementById('cs-container-audit-results').innerHTML = html || '<tr><td colspan="3">No findings.</td></tr>';
        document.getElementById('cs-container-audit-section').scrollIntoView({behavior: 'smooth'});
    });
}

/* ── Escape Check ── */
function csEscapeCheck(id, name) {
    document.getElementById('cs-escape-section').style.display = '';
    document.getElementById('cs-escape-name').textContent = name || id;
    document.getElementById('cs-escape-score').textContent = '...';
    document.getElementById('cs-escape-results').innerHTML = '<tr><td colspan="4">Checking...</td></tr>';

    postJSON(csPrefix + '/docker/containers/' + encodeURIComponent(id) + '/escape', {}).then(function(data) {
        if (data.error) {
            document.getElementById('cs-escape-results').innerHTML = '<tr><td colspan="4">' + escapeHtml(data.error) + '</td></tr>';
            return;
        }
        document.getElementById('cs-escape-score').textContent = data.risk_score;
        document.getElementById('cs-escape-total').textContent = data.total_vectors;
        document.getElementById('cs-escape-exploitable').textContent = data.exploitable;

        var html = '';
        if (!data.vectors || data.vectors.length === 0) {
            html = '<tr><td colspan="4" class="empty-state">No escape vectors detected. Container appears well-configured.</td></tr>';
        } else {
            data.vectors.forEach(function(v) {
                html += '<tr><td>' + escapeHtml(v.vector) + '</td><td>'
                    + csSevBadge(v.risk) + '</td><td>'
                    + (v.exploitable ? '<span style="color:var(--danger);font-weight:600">YES</span>' : '<span style="color:var(--text-muted)">No</span>')
                    + '</td><td style="font-size:0.85rem">' + escapeHtml(v.detail) + '</td></tr>';
            });
        }
        document.getElementById('cs-escape-results').innerHTML = html;
        document.getElementById('cs-escape-section').scrollIntoView({behavior: 'smooth'});
    });
}

/* ── Kubernetes: Namespaces ── */
function csLoadNamespaces() {
    fetchJSON(csPrefix + '/k8s/namespaces').then(function(data) {
        var sel = document.getElementById('cs-k8s-ns');
        var current = sel.value;
        sel.innerHTML = '';
        (data.namespaces || []).forEach(function(ns) {
            var opt = document.createElement('option');
            opt.value = ns.name;
            opt.textContent = ns.name;
            if (ns.name === current) opt.selected = true;
            sel.appendChild(opt);
        });
        if (sel.options.length === 0) {
            var opt = document.createElement('option');
            opt.value = 'default';
            opt.textContent = 'default';
            sel.appendChild(opt);
        }
    });
}

function csGetNS() {
    return document.getElementById('cs-k8s-ns').value || 'default';
}

/* ── Kubernetes: Pods ── */
function csK8sPods() {
    var btn = document.getElementById('btn-k8s-pods');
    setLoading(btn, true);
    fetchJSON(csPrefix + '/k8s/pods?namespace=' + encodeURIComponent(csGetNS())).then(function(data) {
        setLoading(btn, false);
        var html = '';
        (data.pods || []).forEach(function(p) {
            var statusColor = p.status === 'Running' ? 'var(--success)' : p.status === 'Pending' ? 'var(--warning)' : 'var(--danger)';
            html += '<tr><td>' + escapeHtml(p.name) + '</td>'
                + '<td><span style="color:' + statusColor + '">' + escapeHtml(p.status) + '</span></td>'
                + '<td style="font-size:0.85rem">' + escapeHtml((p.containers || []).join(', ')) + '</td>'
                + '<td style="font-size:0.85rem">' + escapeHtml(p.node || '-') + '</td>'
                + '<td>' + (p.restart_count || 0) + '</td>'
                + '<td><button class="btn btn-small" onclick="csK8sPodAudit(\'' + escapeHtml(p.name) + '\')">Audit</button></td>'
                + '</tr>';
        });
        document.getElementById('cs-k8s-pods-list').innerHTML = html || '<tr><td colspan="6" class="empty-state">No pods found in this namespace.</td></tr>';
    }).catch(function() { setLoading(btn, false); });
}

/* ── Kubernetes: Pod Audit ── */
function csK8sPodAudit(podName) {
    var sec = document.getElementById('cs-k8s-pod-audit-section');
    sec.style.display = '';
    document.getElementById('cs-k8s-pod-audit-name').textContent = podName;
    document.getElementById('cs-k8s-pod-score').textContent = '...';
    document.getElementById('cs-k8s-pod-audit-results').innerHTML = '<tr><td colspan="3">Auditing...</td></tr>';

    postJSON(csPrefix + '/k8s/pods/' + encodeURIComponent(podName) + '/audit', {namespace: csGetNS()}).then(function(data) {
        if (data.error) {
            document.getElementById('cs-k8s-pod-audit-results').innerHTML = '<tr><td colspan="3">' + escapeHtml(data.error) + '</td></tr>';
            return;
        }
        var scoreEl = document.getElementById('cs-k8s-pod-score');
        scoreEl.textContent = data.score + '%';
        scoreEl.style.color = data.score >= 80 ? 'var(--success)' : data.score >= 50 ? 'var(--warning)' : 'var(--danger)';

        var html = '';
        (data.findings || []).forEach(function(f) {
            html += '<tr><td>' + escapeHtml(f.check) + '</td><td>'
                + csStatusBadge(f.status) + '</td><td style="font-size:0.85rem">'
                + escapeHtml(f.detail || '') + '</td></tr>';
        });
        document.getElementById('cs-k8s-pod-audit-results').innerHTML = html || '<tr><td colspan="3">No findings.</td></tr>';
        sec.scrollIntoView({behavior: 'smooth'});
    });
}

/* ── Kubernetes: RBAC ── */
function csK8sRBAC() {
    var btn = document.getElementById('btn-k8s-rbac');
    setLoading(btn, true);
    postJSON(csPrefix + '/k8s/rbac', {namespace: csGetNS()}).then(function(data) {
        setLoading(btn, false);
        var el = document.getElementById('cs-k8s-rbac-results');
        if (data.error) { el.innerHTML = '<pre class="output-panel">' + escapeHtml(data.error) + '</pre>'; return; }
        if (!data.findings || data.findings.length === 0) {
            el.innerHTML = '<pre class="output-panel" style="color:var(--success)">No RBAC issues found.</pre>';
            return;
        }
        var html = '<div style="max-height:300px;overflow-y:auto">';
        data.findings.forEach(function(f) {
            html += '<div style="padding:6px 0;border-bottom:1px solid var(--border);font-size:0.85rem">'
                + csSevBadge(f.severity) + ' <strong>' + escapeHtml(f.type) + '</strong>'
                + (f.binding ? ' &mdash; ' + escapeHtml(f.binding) : '')
                + '<div style="color:var(--text-secondary);margin-top:2px">' + escapeHtml(f.detail) + '</div>'
                + '</div>';
        });
        html += '</div>';
        el.innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

/* ── Kubernetes: Secrets ── */
function csK8sSecrets() {
    var btn = document.getElementById('btn-k8s-secrets');
    setLoading(btn, true);
    postJSON(csPrefix + '/k8s/secrets', {namespace: csGetNS()}).then(function(data) {
        setLoading(btn, false);
        var el = document.getElementById('cs-k8s-secrets-results');
        if (data.error) { el.innerHTML = '<pre class="output-panel">' + escapeHtml(data.error) + '</pre>'; return; }
        if (!data.findings || data.findings.length === 0) {
            el.innerHTML = '<pre class="output-panel" style="color:var(--success)">No secrets issues found.</pre>';
            return;
        }
        var html = '<div style="max-height:300px;overflow-y:auto">';
        data.findings.forEach(function(f) {
            html += '<div style="padding:6px 0;border-bottom:1px solid var(--border);font-size:0.85rem">'
                + csSevBadge(f.severity) + ' <strong>' + escapeHtml(f.name) + '</strong>'
                + ' <span style="color:var(--text-muted)">(' + escapeHtml(f.type) + ')</span>'
                + '<div style="color:var(--text-secondary);margin-top:2px">' + escapeHtml(f.detail) + '</div>'
                + '</div>';
        });
        html += '</div>';
        el.innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

/* ── Kubernetes: Network Policies ── */
function csK8sNetPolicies() {
    var btn = document.getElementById('btn-k8s-netpol');
    setLoading(btn, true);
    postJSON(csPrefix + '/k8s/network', {namespace: csGetNS()}).then(function(data) {
        setLoading(btn, false);
        var el = document.getElementById('cs-k8s-netpol-results');
        if (data.error) { el.innerHTML = '<pre class="output-panel">' + escapeHtml(data.error) + '</pre>'; return; }
        var html = '<div style="font-size:0.85rem">';
        html += '<div style="margin-bottom:6px">Policies: <strong>' + (data.policy_count || 0) + '</strong></div>';
        if (data.unprotected_pods && data.unprotected_pods.length > 0) {
            html += '<div style="color:var(--warning);margin-bottom:6px">Unprotected pods: ' + escapeHtml(data.unprotected_pods.join(', ')) + '</div>';
        }
        if (data.findings) {
            data.findings.forEach(function(f) {
                html += '<div style="padding:4px 0">' + csSevBadge(f.severity) + ' ' + escapeHtml(f.detail) + '</div>';
            });
        }
        if (!data.findings || data.findings.length === 0) {
            html += '<div style="color:var(--success)">All pods covered by NetworkPolicies.</div>';
        }
        html += '</div>';
        el.innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

/* ── Image Scan ── */
function csScanImage() {
    var input = document.getElementById('cs-scan-image');
    var name = input.value.trim();
    if (!name) return;
    var btn = document.getElementById('btn-scan-image');
    setLoading(btn, true);
    document.getElementById('cs-scan-results').innerHTML = '<tr><td colspan="5">Scanning ' + escapeHtml(name) + '... (this may take a minute)</td></tr>';
    document.getElementById('cs-scan-summary').style.display = 'none';

    postJSON(csPrefix + '/docker/images/scan', {image_name: name}).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            document.getElementById('cs-scan-results').innerHTML = '<tr><td colspan="5">' + escapeHtml(data.error) + '</td></tr>';
            return;
        }
        // Summary
        var s = data.summary || {};
        document.getElementById('cs-sum-critical').textContent = s.CRITICAL || 0;
        document.getElementById('cs-sum-high').textContent = s.HIGH || 0;
        document.getElementById('cs-sum-medium').textContent = s.MEDIUM || 0;
        document.getElementById('cs-sum-low').textContent = s.LOW || 0;
        document.getElementById('cs-sum-total').textContent = data.total || 0;
        document.getElementById('cs-scan-summary').style.display = '';

        // Vulnerabilities table
        var vulns = data.vulnerabilities || [];
        if (vulns.length === 0) {
            document.getElementById('cs-scan-results').innerHTML = '<tr><td colspan="5" class="empty-state" style="color:var(--success)">No vulnerabilities found.</td></tr>';
            return;
        }
        var html = '';
        vulns.forEach(function(v) {
            html += '<tr><td>' + csSevBadge(v.severity) + '</td>'
                + '<td style="font-size:0.85rem">' + escapeHtml(v.cve) + '</td>'
                + '<td style="font-size:0.85rem">' + escapeHtml(v.package) + '</td>'
                + '<td style="font-size:0.85rem">' + escapeHtml(v.installed_version) + '</td>'
                + '<td style="font-size:0.85rem;color:var(--success)">' + escapeHtml(v.fixed_version || 'n/a') + '</td>'
                + '</tr>';
        });
        document.getElementById('cs-scan-results').innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

/* ── Local Images ── */
function csListImages() {
    var btn = document.getElementById('btn-list-images');
    setLoading(btn, true);
    fetchJSON(csPrefix + '/docker/images').then(function(data) {
        setLoading(btn, false);
        var html = '';
        (data.images || []).forEach(function(img) {
            var fullName = img.repo + ':' + img.tag;
            html += '<tr><td>' + escapeHtml(img.repo) + '</td>'
                + '<td>' + escapeHtml(img.tag) + '</td>'
                + '<td style="font-size:0.85rem">' + escapeHtml(img.size) + '</td>'
                + '<td style="font-size:0.85rem">' + escapeHtml(img.created) + '</td>'
                + '<td><button class="btn btn-small" onclick="csScanFromList(\'' + escapeHtml(fullName) + '\')">Scan</button></td>'
                + '</tr>';
        });
        document.getElementById('cs-images-list').innerHTML = html || '<tr><td colspan="5" class="empty-state">No local images found.</td></tr>';
    }).catch(function() { setLoading(btn, false); });
}

function csScanFromList(name) {
    document.getElementById('cs-scan-image').value = name;
    csScanImage();
    window.scrollTo({top: 0, behavior: 'smooth'});
}

/* ── Dockerfile Lint ── */
function csLintDockerfile() {
    var content = document.getElementById('cs-dockerfile-content').value;
    if (!content.trim()) return;
    var btn = document.getElementById('btn-lint-dockerfile');
    setLoading(btn, true);
    postJSON(csPrefix + '/docker/lint', {content: content}).then(function(data) {
        setLoading(btn, false);
        if (data.error) {
            document.getElementById('cs-lint-results').innerHTML = '<tr><td colspan="5">' + escapeHtml(data.error) + '</td></tr>';
            return;
        }
        var count = data.total || 0;
        document.getElementById('cs-lint-count').textContent = count + ' issue' + (count !== 1 ? 's' : '') + ' found';
        document.getElementById('cs-lint-count').style.color = count === 0 ? 'var(--success)' : 'var(--warning)';

        var findings = data.findings || [];
        if (findings.length === 0) {
            document.getElementById('cs-lint-results').innerHTML = '<tr><td colspan="5" class="empty-state" style="color:var(--success)">No issues found. Dockerfile looks good.</td></tr>';
            return;
        }
        var html = '';
        findings.forEach(function(f) {
            html += '<tr><td style="font-family:monospace;font-size:0.8rem">' + escapeHtml(f.rule || '') + '</td>'
                + '<td>' + csSevBadge(f.severity) + '</td>'
                + '<td>' + (f.line ? f.line : '-') + '</td>'
                + '<td>' + escapeHtml(f.title || '') + '</td>'
                + '<td style="font-size:0.85rem">' + escapeHtml(f.detail || '') + '</td>'
                + '</tr>';
        });
        document.getElementById('cs-lint-results').innerHTML = html;
    }).catch(function() { setLoading(btn, false); });
}

/* ── Export ── */
function csExport() {
    fetchJSON(csPrefix + '/export?format=json').then(function(data) {
        var msg = document.getElementById('cs-export-msg');
        if (data.success) {
            msg.textContent = 'Exported to: ' + (data.path || 'file');
            msg.style.color = 'var(--success)';
        } else {
            msg.textContent = data.error || 'Export failed';
            msg.style.color = 'var(--danger)';
        }
    });
}
</script>
{% endblock %}


Instruction: Create an AUTARCH web template for the 'Counter' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: counter.html
Sections: 4
Tabs: 0
Forms/API calls: 0
Has JavaScript: False

Output:
{% extends "base.html" %}
{% block title %}Counter Intelligence - AUTARCH{% endblock %}

{% block content %}
<div class="page-header">
    <h1>Counter Intelligence</h1>
</div>

<!-- Full Threat Scan -->
<div class="section">
    <h2>Full Threat Scan</h2>
    <div class="tool-actions">
        <button id="btn-scan" class="btn btn-primary" onclick="runCounterScan()">Run Scan</button>
    </div>
    <div id="scan-summary" style="font-size:0.9rem;color:var(--text-secondary);margin-bottom:8px"></div>
    <div id="scan-results">
        <div class="empty-state">Click "Run Scan" to check for threats.</div>
    </div>
</div>

<!-- Quick Checks -->
<div class="section">
    <h2>Quick Checks</h2>
    <div class="tool-grid">
        <div class="tool-card">
            <h4>Suspicious Processes</h4>
            <p>Scan for known malicious process names</p>
            <button class="btn btn-small" onclick="runCounterCheck('processes')">Run</button>
            <pre class="output-panel tool-result" id="counter-result-processes"></pre>
        </div>
        <div class="tool-card">
            <h4>Network Analysis</h4>
            <p>Check for suspicious connections</p>
            <button class="btn btn-small" onclick="runCounterCheck('network')">Run</button>
            <pre class="output-panel tool-result" id="counter-result-network"></pre>
        </div>
        <div class="tool-card">
            <h4>Login Anomalies</h4>
            <p>Quick failed login check</p>
            <button class="btn btn-small" onclick="runCounterCheck('logins')">Run</button>
            <pre class="output-panel tool-result" id="counter-result-logins"></pre>
        </div>
        <div class="tool-card">
            <h4>File Integrity</h4>
            <p>Check recently modified critical files</p>
            <button class="btn btn-small" onclick="runCounterCheck('integrity')">Run</button>
            <pre class="output-panel tool-result" id="counter-result-integrity"></pre>
        </div>
        <div class="tool-card">
            <h4>Scheduled Tasks</h4>
            <p>Check cron jobs for suspicious commands</p>
            <button class="btn btn-small" onclick="runCounterCheck('tasks')">Run</button>
            <pre class="output-panel tool-result" id="counter-result-tasks"></pre>
        </div>
        <div class="tool-card">
            <h4>Rootkit Detection</h4>
            <p>Basic rootkit and hidden process checks</p>
            <button class="btn btn-small" onclick="runCounterCheck('rootkits')">Run</button>
            <pre class="output-panel tool-result" id="counter-result-rootkits"></pre>
        </div>
    </div>
</div>

<!-- Login Analysis -->
<div class="section">
    <h2>Login Analysis</h2>
    <p style="font-size:0.85rem;color:var(--text-secondary);margin-bottom:12px">Detailed failed login analysis with GeoIP enrichment (top 15 IPs)</p>
    <div class="tool-actions">
        <button id="btn-logins" class="btn btn-primary" onclick="loadLogins()">Analyze Logins</button>
    </div>
    <div id="login-results">
        <div class="empty-state">Click "Analyze Logins" to view failed login attempts.</div>
    </div>
</div>

{% if modules %}
<div class="section">
    <h2>Counter Modules</h2>
    <ul class="module-list">
    {% for name, info in modules.items() %}
        <li class="module-item">
            <div>
                <div class="module-name">{{ name }}</div>
                <div class="module-desc">{{ info.description }}</div>
            </div>
            <div class="module-meta">v{{ info.version }}</div>
        </li>
    {% endfor %}
    </ul>
</div>
{% endif %}
{% endblock %}


Instruction: Create an AUTARCH web template for the 'Dashboard' page. It should extend base.html, have a page header, and use AUTARCH's CSS variables and UI patterns (sections, tab bars, data tables, buttons).

Input:
Template: dashboard.html
Sections: 2
Tabs: 0
Forms/API calls: 0
Has JavaScript: False

Output:
{% extends "base.html" %}
{% block title %}Dashboard - AUTARCH{% endblock %}

{% block content %}

Dashboard

Modules

{{ modules.get('total', 0) }}

LLM Backend

{{ llm_backend }}

Hostname

{{ system.hostname }}

Uptime

{{ system.uptime }}

Defense

System hardening, audits, monitoring

        {{ modules.get('defense', 0) }} modules

Offense

Penetration testing, Metasploit

        {{ modules.get('offense', 0) }} modules

Counter

Threat hunting, anomaly detection

        {{ modules.get('counter', 0) }} modules

Analyze

Forensics, file analysis

        {{ modules.get('analyze', 0) }} modules

OSINT

Reconnaissance, username search

        {{ modules.get('osint', 0) }} modules

Simulate

Attack simulation, red team

        {{ modules.get('simulate', 0) }} modules

Hardware

ADB, Fastboot, ESP32 flashing

        {{ modules.get('hardware', 0) }} modules

System Tools

Tool	Status

        {% for tool, available in tools.items() %}

            {{ tool }}
            {{ 'Available' if available else 'Not found' }}

        {% endfor %}

System Info

Platform	{{ system.platform }}

Architecture	{{ system.arch }}

Python	{{ system.python }}

IP	{{ system.ip }}

UPnP	{{ 'Enabled' if upnp_enabled else 'Disabled' }}

{% endblock %}