icebox-gov 0.2.6

Runtime governance for autonomous offensive security — the single seam every human operator, REST client, and LLM agent must pass through before anything touches a target.
Documentation
import { useState, useEffect } from 'react'

interface ApprovalRequest {
  id: number;
  module: string;
  target: string;
  reason: string;
  status: string;
}

interface AuditRecord {
  at: number;
  target: string;
  module: string;
  decision: string | object;
}

interface ModuleItem {
  name: string;
  kind: string;
  description: string;
}

interface JobItem {
  id: number;
  module: string;
  target: string;
  status: string;
  elapsed_secs: number;
}

function App() {
  const [approvals, setApprovals] = useState<ApprovalRequest[]>([])
  const [audits, setAudits] = useState<AuditRecord[]>([])
  const [modules, setModules] = useState<ModuleItem[]>([])
  const [jobs, setJobs] = useState<JobItem[]>([])
  const [mode, setMode] = useState<string>('freezer')
  const [isChangingMode, setIsChangingMode] = useState(false)
  const API_BASE = 'http://127.0.0.1:8443/api/v1'

  const fetchData = async () => {
    try {
      const appRes = await fetch(`${API_BASE}/approvals`)
      if (appRes.ok) {
        const appData = await appRes.json()
        setApprovals(appData.filter((a: ApprovalRequest) => a.status === 'Pending'))
      }
      const audRes = await fetch(`${API_BASE}/audit?n=20`)
      if (audRes.ok) {
        const audData = await audRes.json()
        setAudits(audData)
      }
      const modRes = await fetch(`${API_BASE}/modules`)
      if (modRes.ok) {
        setModules(await modRes.json())
      }
      const jobsRes = await fetch(`${API_BASE}/jobs`)
      if (jobsRes.ok) {
        setJobs(await jobsRes.json())
      }
      if (!isChangingMode) {
        const modeRes = await fetch(`${API_BASE}/mode`)
        if (modeRes.ok) {
          const modeData = await modeRes.json()
          setMode(modeData.mode)
        }
      }
    } catch (e) {
      console.error('Failed to fetch ICEBOX data:', e)
    }
  }

  useEffect(() => {
    fetchData()
    const interval = setInterval(fetchData, 2000)
    return () => clearInterval(interval)
  }, [])

  const handleApprove = async (id: number) => {
    try {
      await fetch(`${API_BASE}/approvals/${id}/approve`, { method: 'POST' })
      fetchData()
    } catch (e) {
      console.error(e)
    }
  }

  const handleDeny = async (id: number) => {
    try {
      await fetch(`${API_BASE}/approvals/${id}/deny`, { method: 'POST' })
      fetchData()
    } catch (e) {
      console.error(e)
    }
  }

  const formatDecision = (decision: string | object) => {
    if (typeof decision === 'string') return decision;
    if (decision && typeof decision === 'object') {
      const keys = Object.keys(decision);
      return keys[0] || 'Unknown';
    }
    return 'Unknown';
  }

  const handleModeChange = async (newMode: string) => {
    setIsChangingMode(true)
    setMode(newMode)
    try {
      await fetch(`${API_BASE}/mode`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ mode: newMode })
      })
      fetchData()
    } catch (e) {
      console.error(e)
    } finally {
      setIsChangingMode(false)
    }
  }

  return (
    <div className="p-8 max-w-4xl mx-auto">
      <header className="header flex justify-between items-center">
        <div className="flex items-center gap-4">
          <svg width="40" height="40" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
            <circle cx="50" cy="54" r="40" fill="#0E1620" />
            <circle cx="50" cy="54" r="40" stroke="#C9DCE6" strokeWidth="6" />
            <circle cx="50" cy="54" r="28" stroke="#C9DCE6" strokeWidth="6" />
            <circle cx="50" cy="54" r="16" stroke="#C9DCE6" strokeWidth="6" />
            <circle cx="50" cy="54" r="13" fill="#2E8C93" />
            <path d="M50 54 L38 0 L62 0 Z" fill="#0E1620" />
            <path d="M50 54 L44 14 L56 14 Z" fill="#E8542A" />
            <rect x="47" y="4" width="6" height="8" fill="#E8542A" />
          </svg>
          <h1 className="m-0">ICEBOX</h1>
        </div>
        
        <div className="flex items-center gap-2">
          <div className="mono text-slate-steel" style={{ fontSize: '0.875rem', marginRight: '1rem' }}>Restriction Mode:</div>
          <div className="flex bg-seam-black" style={{ border: '1px solid var(--slate-steel)', borderRadius: '4px', overflow: 'hidden' }}>
            <button 
              className={`button m-0 ${mode === 'fridge' ? 'bg-signal-teal text-seam-black' : 'bg-seam-black text-slate-steel'}`}
              style={{ border: 'none', borderRadius: 0 }}
              onClick={() => handleModeChange('fridge')}
              disabled={isChangingMode}
            >
              FRIDGE
            </button>
            <button 
              className={`button m-0 ${mode === 'freezer' ? 'bg-signal-teal text-seam-black' : 'bg-seam-black text-slate-steel'}`}
              style={{ border: 'none', borderLeft: '1px solid var(--slate-steel)', borderRadius: 0 }}
              onClick={() => handleModeChange('freezer')}
              disabled={isChangingMode}
            >
              FREEZER
            </button>
            <button 
              className={`button m-0 ${mode === 'deep_freezer' ? 'bg-signal-teal text-seam-black' : 'bg-seam-black text-slate-steel'}`}
              style={{ border: 'none', borderLeft: '1px solid var(--slate-steel)', borderRadius: 0 }}
              onClick={() => handleModeChange('deep_freezer')}
              disabled={isChangingMode}
            >
              DEEP FREEZER
            </button>
          </div>
        </div>
      </header>

      <div className="flex gap-8 flex-col lg:flex-row">
        <div className="w-full">
          <h2 className="text-core-ice">Pending Approvals</h2>
          {approvals.length === 0 ? (
            <div className="card text-slate-steel text-center py-8">
              No pending approvals. Queue is clear.
            </div>
          ) : (
            approvals.map(approval => (
              <div key={approval.id} className="card">
                <div className="flex justify-between items-center" style={{ marginBottom: '1rem' }}>
                  <span className="badge blocked">Requires Approval</span>
                  <span className="mono text-slate-steel">ID: {approval.id}</span>
                </div>
                <div className="mono" style={{ marginBottom: '0.5rem' }}>
                  <span className="text-slate-steel">Module:</span> {approval.module}
                </div>
                <div className="mono" style={{ marginBottom: '0.5rem' }}>
                  <span className="text-slate-steel">Target:</span> {approval.target}
                </div>
                <div style={{ marginBottom: '1.5rem', color: 'var(--core-ice)' }}>
                  {approval.reason}
                </div>
                <div className="flex gap-4">
                  <button className="button primary" onClick={() => handleApprove(approval.id)}>Approve</button>
                  <button className="button danger" onClick={() => handleDeny(approval.id)}>Deny</button>
                </div>
              </div>
            ))
          )}

          <h2 className="text-core-ice mt-8" style={{ marginTop: '2rem' }}>Loaded Weapons</h2>
          <div className="card">
            {modules.length === 0 ? (
              <div className="text-slate-steel text-center py-4">No modules loaded.</div>
            ) : (
              <div className="grid gap-2" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '0.5rem' }}>
                {modules.map(mod => (
                  <div key={mod.name} className="p-2 flex flex-col gap-1" style={{ border: '1px solid var(--slate-steel)', borderRadius: '2px' }}>
                    <div className="flex justify-between items-center">
                      <span className="mono font-bold">{mod.name}</span>
                    </div>
                    <span className="badge" style={{ alignSelf: 'flex-start', backgroundColor: 'var(--slate-steel)', color: 'var(--frost-white)' }}>{mod.kind}</span>
                  </div>
                ))}
              </div>
            )}
          </div>
        </div>

        <div className="w-full">
          <h2 className="text-core-ice">Audit Log</h2>
          <div className="card max-h-[600px] overflow-y-auto">
            {audits.map((audit, idx) => {
              const decisionStr = formatDecision(audit.decision).toLowerCase()
              const isAllowed = decisionStr === 'allow' || decisionStr === 'auto_approve'
              const date = new Date(audit.at * 1000)
              
              return (
                <div key={`${audit.at}-${idx}`} className="flex justify-between items-center" style={{ borderBottom: '1px solid var(--slate-steel)', padding: '0.75rem 0' }}>
                  <div>
                    <span className="mono text-slate-steel" style={{ marginRight: '1rem' }}>
                      {date.getHours().toString().padStart(2, '0')}:{date.getMinutes().toString().padStart(2, '0')}:{date.getSeconds().toString().padStart(2, '0')}
                    </span>
                    <span className="mono">{audit.module}</span>
                    <span className="text-slate-steel" style={{ margin: '0 0.5rem' }}>→</span>
                    <span className="mono text-core-ice">{audit.target}</span>
                  </div>
                  {isAllowed ? (
                    <span className="badge allowed">Cleared</span>
                  ) : decisionStr.includes('requireapproval') || decisionStr.includes('require_approval') ? (
                    <span className="badge pending text-hazard-orange">Pending</span>
                  ) : (
                    <span className="badge blocked">Blocked</span>
                  )}
                </div>
              )
            })}
            {audits.length === 0 && (
              <div className="text-slate-steel text-center py-4">No audit events yet.</div>
            )}
          </div>
          
          <h2 className="text-core-ice mt-8" style={{ marginTop: '2rem' }}>Active Tasks</h2>
          <div className="card max-h-[300px] overflow-y-auto">
            {jobs.length === 0 ? (
              <div className="text-slate-steel text-center py-4">No active tasks running.</div>
            ) : (
              jobs.map(job => (
                <div key={job.id} className="flex justify-between items-center" style={{ borderBottom: '1px solid var(--slate-steel)', padding: '0.75rem 0' }}>
                  <div>
                    <span className="mono text-slate-steel" style={{ marginRight: '1rem' }}>ID: {job.id}</span>
                    <span className="mono font-bold text-signal-teal">{job.module}</span>
                    <span className="text-slate-steel" style={{ margin: '0 0.5rem' }}>on</span>
                    <span className="mono text-core-ice">{job.target}</span>
                  </div>
                  <div className="flex items-center gap-4">
                    <span className="mono text-slate-steel">{job.elapsed_secs}s</span>
                    <span className={`badge ${job.status === 'Running' ? 'allowed' : 'text-slate-steel'}`}>{job.status}</span>
                  </div>
                </div>
              ))
            )}
          </div>
        </div>
      </div>
    </div>
  )
}

export default App