cochranblock 0.9.0

Zero-cloud website in a single Rust binary. 15MB on x86, 8.2MB on ARM. $10/month infrastructure. cargo install and run.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
// All Rights Reserved — The Cochran Block, LLC
// Contributors: Mattbusel (XFactor), GotEmCoach, KOVA, Claude Opus 4.6, SuperNinja, Composer 1.5, Google Gemini Pro 3

// Client Intake: waiver-style form, honeypot, SQLite, async webhook.
// Themed to blend with cochranblock cosmic aesthetic.

use axum::Form;
use axum::extract::{ConnectInfo, Path, Query, State};
use axum::http::{HeaderMap, StatusCode};
use axum::response::{Html, IntoResponse, Redirect};
use chrono::Utc;
use serde::Deserialize;
use std::net::SocketAddr;
use std::sync::Arc;
use uuid::Uuid;

use super::pages::{C7, C8, f62};
use crate::db::{self, GrantRow, KnoxRow, LeadRow};
use crate::t0;

const TERMS_VERSION: &str = "2026-03";
const TERMS: &str = include_str!("../../content/intake_terms.txt");

/// init_pool — create data dir, open redb store, run migrations. Returns
/// None on failure. Name kept for call-site compatibility — the new
/// backing store is redb (single file, ACID, zero-copy reads).
pub async fn init_pool() -> Option<crate::db::t9> {
    let data_dir = std::env::var("CB_DATA_DIR")
        .ok()
        .or_else(|| std::env::var("COCHRANBLOCK_DATA_DIR").ok())
        .or_else(|| {
            dirs::data_dir()
                .map(|p| p.join("cochranblock").join("data"))
                .and_then(|p| p.into_os_string().into_string().ok())
        })
        .unwrap_or_else(|| "data".into());

    // Spawn-blocking — redb opens via mmap and we don't want to stall the
    // tokio runtime if the file needs to be created/recovered.
    let dir_clone = data_dir.clone();
    let db = match tokio::task::spawn_blocking(move || -> Result<crate::db::t9, String> {
        let db = db::f20(&dir_clone).map_err(|e| format!("init: {:?}", e))?;
        db::f21(&db).map_err(|e| format!("migrate: {:?}", e))?;
        Ok(db)
    })
    .await
    {
        Ok(Ok(d)) => d,
        Ok(Err(e)) => {
            tracing::warn!("intake: redb init failed: {}", e);
            return None;
        }
        Err(e) => {
            tracing::warn!("intake: redb init join failed: {}", e);
            return None;
        }
    };
    tracing::info!("intake: redb ready at {}/cochranblock.redb", data_dir);
    Some(db)
}

pub(crate) fn html_escape(s: &str) -> String {
    s.replace('&', "&amp;")
        .replace('<', "&lt;")
        .replace('>', "&gt;")
        .replace('"', "&quot;")
}

pub(crate) fn client_ip(addr: SocketAddr, headers: &HeaderMap) -> String {
    headers
        .get("x-forwarded-for")
        .and_then(|v| v.to_str().ok())
        .and_then(|s| s.split(',').next())
        .map(|s| s.trim().to_string())
        .unwrap_or_else(|| addr.ip().to_string())
}

/// GET /deploy — deployment request intake form.
pub async fn get_form(State(s): State<Arc<t0>>) -> Html<String> {
    let terms_escaped = html_escape(TERMS);
    let content = format!(
        r#"<section class="intake-section"><div class="intake-steps"><span class="intake-step intake-active"><span class="intake-num">1</span> Review</span><span class="intake-step"><span class="intake-num">2</span> Submit</span><span class="intake-step"><span class="intake-num">3</span> Complete</span></div>
<div class="intake-doc"><h1 class="intake-title">Deploy With CochranBlock</h1><p class="intake-intro">Request a custom Web Appliance — a compiled Rust binary that runs on your hardware, routed via Cloudflare Zero Trust. No cloud hosting. No monthly fees. $3,500 base.</p>
<div class="intake-body"><pre>{}</pre></div>
<div class="intake-sign"><div class="intake-line"></div><p class="intake-sign-label">Submit your deployment request</p>
<form class="intake-form" method="post" action="/deploy" id="intake-form">
<label for="deploy_class">Deployment Class</label>
<select id="deploy_class" name="deploy_class" required>
<option value="" disabled selected>Select a class</option>
<option value="product">Product — $3,500 base. Your hardware. $0/mo forever.</option>
<option value="consulting">Consulting — Build it, harden it, fix it. Project-based.</option>
<option value="partnership">Partnership — Your brand + our engine. Long-term.</option>
</select>
<label for="full_name">Full Name</label><input type="text" id="full_name" name="full_name" required autocomplete="name" placeholder="Your name" maxlength="200">
<label for="email">Email</label><input type="email" id="email" name="email" required autocomplete="email" placeholder="you@company.com" maxlength="254">
<label for="company">Company or Project Name</label><input type="text" id="company" name="company" autocomplete="organization" placeholder="Optional" maxlength="200">
<label for="message">What are you building?</label><textarea id="message" name="message" placeholder="Describe your project or mission" maxlength="2000"></textarea>
<div class="intake-hp" aria-hidden="true"><label for="website_url">Leave blank</label><input type="text" id="website_url" name="website_url" tabindex="-1" autocomplete="off"></div>
<div class="intake-consent">
<label class="intake-check"><input type="checkbox" name="consent_fee" value="1" required id="consent_fee"> I acknowledge the baseline fee of $3,500 USD for a custom Web Appliance deployment.</label>
<label class="intake-check"><input type="checkbox" name="consent_hardware" value="1" required id="consent_hardware"> I understand deployments run on my own local hardware via Cloudflare Zero Trust — no cloud hosting, no monthly fees.</label>
<label class="intake-check"><input type="checkbox" name="consent_terms" value="1" required id="consent_terms"> I have read the terms above and am submitting this request voluntarily.</label>
</div>
<button type="submit" class="btn" id="deploy-submit-btn" disabled>Submit Request</button></form></div>
<p class="intake-note">Upon submission, CochranBlock will review your request and contact you within 2–3 business days to schedule a discovery call. No obligation is incurred by submitting this form.</p></div></section>
<script>(function(){{var f=document.getElementById('intake-form');var b=document.getElementById('deploy-submit-btn');var dc=document.getElementById('deploy_class');var fn=document.getElementById('full_name');var em=document.getElementById('email');var cf=document.getElementById('consent_fee');var ch=document.getElementById('consent_hardware');var ct=document.getElementById('consent_terms');function chk(){{var ok=dc.value&&fn.value.trim()&&em.value.trim()&&cf.checked&&ch.checked&&ct.checked;b.disabled=!ok;}}dc.onchange=chk;fn.oninput=fn.onchange=em.oninput=em.onchange=chk;cf.onchange=ch.onchange=ct.onchange=chk;chk();}})();</script>"#,
        terms_escaped
    );
    let _ = s;
    Html(format!(
        "{}{}{}{}",
        f62("deploy", "Deploy With Us | CochranBlock"),
        C7,
        content,
        C8
    ))
}

#[derive(Deserialize)]
pub struct IntakeForm {
    #[serde(default)]
    deploy_class: String,
    full_name: String,
    email: String,
    #[serde(default)]
    company: String,
    #[serde(default)]
    message: String,
    #[serde(rename = "website_url")]
    honeypot: Option<String>,
    consent_fee: Option<String>,
    consent_hardware: Option<String>,
    consent_terms: Option<String>,
}

pub(crate) fn validate_input(full_name: &str, email: &str) -> Result<(), &'static str> {
    let n = full_name.trim();
    let e = email.trim();
    if n.is_empty() {
        return Err("name empty");
    }
    if e.is_empty() {
        return Err("email empty");
    }
    if n.len() > 200 {
        return Err("name too long");
    }
    if e.len() > 254 {
        return Err("email too long");
    }
    Ok(())
}

/// POST /intake — process form.
pub async fn post_form(
    State(s): State<Arc<t0>>,
    ConnectInfo(addr): ConnectInfo<SocketAddr>,
    headers: HeaderMap,
    Form(f): Form<IntakeForm>,
) -> impl IntoResponse {
    if f.honeypot
        .as_deref()
        .map(|v| !v.trim().is_empty())
        .unwrap_or(false)
    {
        tracing::debug!("intake honeypot triggered");
        return (StatusCode::OK, Html(confirmed_html(None))).into_response();
    }

    let deploy_class = f.deploy_class.trim();
    let full_name = f.full_name.trim();
    let email = f.email.trim();
    let company = f.company.trim();
    let message = f.message.trim();

    if validate_input(full_name, email).is_err() {
        return (StatusCode::BAD_REQUEST, "Invalid input").into_response();
    }

    if f.consent_fee.as_deref() != Some("1")
        || f.consent_hardware.as_deref() != Some("1")
        || f.consent_terms.as_deref() != Some("1")
    {
        return (
            StatusCode::BAD_REQUEST,
            "You must acknowledge the fee, hardware model, and terms.",
        )
            .into_response();
    }

    let db = match &s.intake_db {
        Some(d) => d.clone(),
        None => {
            tracing::error!("intake db not available");
            return (
                StatusCode::SERVICE_UNAVAILABLE,
                "Service temporarily unavailable. Please try again later.",
            )
                .into_response();
        }
    };

    let id = Uuid::new_v4().to_string();
    let submitted_at = Utc::now().to_rfc3339();
    let ip = client_ip(addr, &headers);
    let ua = headers
        .get("user-agent")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("")
        .to_string();

    let row = LeadRow {
        id: id.clone(),
        deploy_class: if deploy_class.is_empty() { None } else { Some(deploy_class.to_string()) },
        full_name: full_name.to_string(),
        email: email.to_string(),
        company: if company.is_empty() { None } else { Some(company.to_string()) },
        message: if message.is_empty() { None } else { Some(message.to_string()) },
        submitted_at: submitted_at.clone(),
        ip_address: if ip.is_empty() { None } else { Some(ip.clone()) },
        user_agent: if ua.is_empty() { None } else { Some(ua.clone()) },
        terms_version: TERMS_VERSION.to_string(),
        consent_fee: true,
        consent_hardware: true,
        consent_terms: true,
    };
    let row_for_insert = row.clone();
    let insert_result = tokio::task::spawn_blocking(move || db::f50(&db, &row_for_insert))
        .await
        .unwrap_or_else(|e| Err(crate::error::t18::E6(format!("join: {}", e))));
    if let Err(e) = insert_result {
        tracing::error!("lead insert failed: {:?}", e);
        return (
            StatusCode::INTERNAL_SERVER_ERROR,
            "Unable to save. Please try again.",
        )
            .into_response();
    }

    if let Some(url) = std::env::var("INTAKE_WEBHOOK_URL")
        .ok()
        .map(|u| u.trim().to_string())
        .filter(|u| !u.is_empty())
    {
        let client = reqwest::Client::new();
        let payload = serde_json::json!({
            "id": id.clone(),
            "deploy_class": if deploy_class.is_empty() { serde_json::Value::Null } else { serde_json::Value::String(deploy_class.to_string()) },
            "full_name": full_name,
            "email": email,
            "company": if company.is_empty() { serde_json::Value::Null } else { serde_json::Value::String(company.to_string()) },
            "message": if message.is_empty() { serde_json::Value::Null } else { serde_json::Value::String(message.to_string()) },
            "submitted_at": submitted_at,
        });
        let lead_id = id.clone();
        tokio::spawn(async move {
            if let Err(e) = client
                .post(url.trim())
                .json(&payload)
                .timeout(std::time::Duration::from_secs(10))
                .send()
                .await
            {
                tracing::warn!("intake webhook failed: {}", e);
            } else {
                tracing::info!("intake webhook sent for lead {}", lead_id);
            }
        });
    }

    let loc = format!("/deploy/confirmed?ref={}", urlencoding::encode(&id));
    Redirect::temporary(loc.as_str()).into_response()
}

fn confirmed_html(ref_id: Option<&str>) -> String {
    let ref_line = ref_id
        .filter(|s| !s.is_empty())
        .map(|r| {
            format!(
                r#"<p class="intake-detail">Reference ID: <code>{}</code></p>"#,
                html_escape(r)
            )
        })
        .unwrap_or_default();

    let content = format!(
        r#"<section class="intake-section intake-done"><div class="intake-doc intake-complete"><div class="intake-check-icon">✓</div><h1>Request Received</h1><p class="intake-success">Your deployment request has been submitted.</p>{}<p class="intake-detail">Cochranblock will contact you within 2–3 business days to schedule a discovery call.</p><div class="rocket-pad"><button class="btn rocket-launch-btn" onclick="launchRocket(this)">Launch 🚀</button><div class="rocket-ship" id="rocket-ship">🚀</div></div><a href="/intake" class="btn btn-secondary" style="margin-top:1rem">Done</a></div></section>
<style>
.rocket-pad{{position:relative;margin:2rem 0 0;text-align:center;min-height:60px}}
.rocket-ship{{position:fixed;bottom:-60px;left:50%;font-size:2.5rem;opacity:0;pointer-events:none;z-index:50;transform:translateX(-50%);filter:drop-shadow(0 0 12px rgba(255,107,53,0.6))}}
.rocket-ship.countdown{{opacity:1;bottom:20%;animation:rocketShake 0.15s ease-in-out infinite alternate}}
.rocket-ship.launched{{opacity:1;animation:rocketLaunch 2s ease-in forwards}}
.rocket-exhaust{{position:fixed;bottom:0;left:50%;width:4px;height:0;background:linear-gradient(to top,rgba(255,107,53,0.8),rgba(255,200,50,0.4),transparent);transform:translateX(-50%);z-index:49;pointer-events:none;border-radius:2px}}
.rocket-exhaust.active{{animation:exhaustTrail 2s ease-in forwards}}
.rocket-launch-btn.counting{{pointer-events:none;background:var(--orange);border-color:var(--orange)}}
@keyframes rocketShake{{0%{{transform:translateX(-50%) rotate(-2deg)}}100%{{transform:translateX(-50%) rotate(2deg)}}}}
@keyframes rocketLaunch{{0%{{bottom:20%;opacity:1;transform:translateX(-50%) rotate(0)}}30%{{bottom:40%}}100%{{bottom:120vh;opacity:0.3;transform:translateX(-50%) rotate(0)}}}}
@keyframes exhaustTrail{{0%{{height:0;opacity:0.8}}30%{{height:40vh;opacity:0.6}}100%{{height:0;opacity:0}}}}
</style>
<script>
function launchRocket(btn){{var r=document.getElementById('rocket-ship');if(r.classList.contains('launched'))return;btn.classList.add('counting');var c=3;btn.textContent=c;r.style.opacity='1';r.style.bottom='20%';r.classList.add('countdown');var ex=document.createElement('div');ex.className='rocket-exhaust';document.body.appendChild(ex);var t=setInterval(function(){{c--;if(c>0){{btn.textContent=c}}else{{clearInterval(t);btn.textContent='Launched!';r.classList.remove('countdown');r.classList.add('launched');ex.classList.add('active');setTimeout(function(){{btn.classList.remove('counting');btn.textContent='Launch \u{{1F680}}';r.classList.remove('launched');r.style.opacity='0';r.style.bottom='-60px';ex.remove()}},3000)}}}},800)}}
</script>"#,
        ref_line
    );

    format!(
        "{}{}{}{}",
        f62("deploy-confirmed", "Quest Accepted | CochranBlock"),
        C7,
        content,
        C8
    )
}

/// GET /intake/confirmed
pub async fn confirmed(Query(q): Query<std::collections::HashMap<String, String>>) -> Html<String> {
    let ref_id = q.get("ref").map(|s| s.as_str());
    Html(confirmed_html(ref_id))
}

// ═══════════════════════════════════════════════════════════════
// KNOXAI Operator Registration
// ═══════════════════════════════════════════════════════════════

/// GET /knox/apply — operator application form
pub async fn knox_apply_form(State(_s): State<Arc<t0>>) -> Html<String> {
    let head = super::pages::f62d(
        "knox-apply",
        "KNOXAI — Operator Application",
        "Apply to join the KNOXAI operator guild. AI model certification for CSAM and harmful content detection.",
    );
    let content = r#"<section style="max-width:820px;margin:0 auto;padding:3rem 1.5rem 6rem;font-family:'JetBrains Mono','SF Mono',Consolas,monospace;font-size:14px;line-height:1.65;color:#fcfcfa">

<div style="font-size:0.6rem;letter-spacing:0.5em;color:#ff6188;text-transform:uppercase;text-align:center;padding:0.5rem 0;margin-bottom:2rem;border-top:1px solid #ff6188;border-bottom:1px solid #ff6188;opacity:0.7">Operator Application · KNOXAI</div>

<h1 style="font-size:2rem;font-weight:900;letter-spacing:0.12em;margin-bottom:0.8rem">KNOXAI</h1>
<div style="font-size:0.85rem;letter-spacing:0.25em;color:#ffd866;margin-bottom:2rem;text-transform:uppercase">Operator Application</div>

<div style="background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);border-left:3px solid #ff6188;padding:1.2rem;border-radius:4px;margin-bottom:2rem">
<div style="font-size:0.7rem;letter-spacing:0.25em;text-transform:uppercase;font-weight:700;color:#ff6188;margin-bottom:0.8rem">Before You Apply — Read This</div>
<p style="color:#c1c0c0;margin-bottom:0.8rem">KNOXAI operators audit AI models for <strong style="color:#fcfcfa">child sexual abuse material (CSAM)</strong> and other harmful content. This work exists because AI-generated CSAM increased <strong style="color:#ff6188">260x in one year</strong> (Internet Watch Foundation, 2025).</p>
<p style="color:#c1c0c0;margin-bottom:0.8rem"><strong style="color:#fcfcfa">What you will encounter:</strong> You will run automated detection gates against AI models. Gate 1 (hash scan) compares model outputs against known-bad hash databases. You will <strong style="color:#fcfcfa">never view actual CSAM</strong> — the detection pipeline uses perceptual hashes, membership inference scores, and classifier outputs. You see numbers and pass/fail verdicts, not images.</p>
<p style="color:#c1c0c0;margin-bottom:0.8rem"><strong style="color:#fcfcfa">What triggers mandatory reporting:</strong> If Gate 1 produces a hash match against the NCMEC database, the platform automatically files a CyberTipline report under <strong>18 USC §2258A</strong>. You sign the emergency blacklist cert (L thumb). The publisher is frozen. This is federal law — there is no discretion.</p>
<p style="color:#c1c0c0;margin-bottom:0"><strong style="color:#fcfcfa">What you earn:</strong> 80% of Standard ($20), 70% of Operator ($500), 60% of Portfolio ($5K+), 50% of Gov tier. Paid within 24 hours via Stripe Connect. 1099-NEC at year end. You are an independent contractor, not an employee.</p>
</div>

<div style="background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);border-left:3px solid #a9dc76;padding:1.2rem;border-radius:4px;margin-bottom:2rem">
<div style="font-size:0.7rem;letter-spacing:0.25em;text-transform:uppercase;font-weight:700;color:#a9dc76;margin-bottom:0.8rem">What Makes a Good Operator</div>
<p style="color:#c1c0c0;margin-bottom:0">Red teamers. ML researchers. ML engineers. Data scientists. AI safety researchers. Veterans with cyber backgrounds. People with security clearances. You don't need all of these — you need at least one. And you need to care about protecting kids more than you care about a side gig.</p>
</div>

<form method="post" action="/knox/apply" style="margin-top:2rem">

<label style="display:block;font-size:0.72rem;letter-spacing:0.15em;text-transform:uppercase;color:#727072;margin-bottom:0.3rem;margin-top:1.5rem">Full Name *</label>
<input type="text" name="full_name" required maxlength="200" placeholder="Your real name" style="width:100%;background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);color:#fcfcfa;padding:0.6rem 0.8rem;font-family:inherit;font-size:0.85rem;border-radius:4px">

<label style="display:block;font-size:0.72rem;letter-spacing:0.15em;text-transform:uppercase;color:#727072;margin-bottom:0.3rem;margin-top:1.5rem">Email *</label>
<input type="email" name="email" required maxlength="254" placeholder="you@example.com" style="width:100%;background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);color:#fcfcfa;padding:0.6rem 0.8rem;font-family:inherit;font-size:0.85rem;border-radius:4px">

<label style="display:block;font-size:0.72rem;letter-spacing:0.15em;text-transform:uppercase;color:#727072;margin-bottom:0.3rem;margin-top:1.5rem">Background *</label>
<textarea name="background" required maxlength="2000" placeholder="Military service, current role, relevant experience, certifications (OSCP, GIAC, CISSP, etc.)" rows="4" style="width:100%;background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);color:#fcfcfa;padding:0.6rem 0.8rem;font-family:inherit;font-size:0.85rem;border-radius:4px;resize:vertical"></textarea>

<label style="display:block;font-size:0.72rem;letter-spacing:0.15em;text-transform:uppercase;color:#727072;margin-bottom:0.3rem;margin-top:1.5rem">Specialty Tags (check all that apply) *</label>
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:0.5rem;margin-bottom:0.5rem">
<label style="color:#c1c0c0;font-size:0.82rem"><input type="checkbox" name="tag_redteam" value="1"> <span style="color:#ff6188">redteam</span> — offensive cyber, adversarial prompting</label>
<label style="color:#c1c0c0;font-size:0.82rem"><input type="checkbox" name="tag_ml_research" value="1"> <span style="color:#78dce8">ml-research</span> — adversarial ML, membership inference</label>
<label style="color:#c1c0c0;font-size:0.82rem"><input type="checkbox" name="tag_ml_eng" value="1"> <span style="color:#a9dc76">ml-eng</span> — training pipelines, framework internals</label>
<label style="color:#c1c0c0;font-size:0.82rem"><input type="checkbox" name="tag_data" value="1"> <span style="color:#ffd866">data</span> — dataset provenance, corpus analysis</label>
<label style="color:#c1c0c0;font-size:0.82rem"><input type="checkbox" name="tag_safety" value="1"> <span style="color:#ab9df2">safety</span> — AI safety, eval design, classifiers</label>
<label style="color:#c1c0c0;font-size:0.82rem"><input type="checkbox" name="tag_cleared" value="1"> <span style="color:#727072">cleared</span> — active U.S. security clearance</label>
</div>

<label style="display:block;font-size:0.72rem;letter-spacing:0.15em;text-transform:uppercase;color:#727072;margin-bottom:0.3rem;margin-top:1.5rem">Clearance Status</label>
<select name="clearance" style="width:100%;background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);color:#fcfcfa;padding:0.6rem 0.8rem;font-family:inherit;font-size:0.85rem;border-radius:4px">
<option value="none">No active clearance</option>
<option value="secret">Secret</option>
<option value="ts">Top Secret</option>
<option value="ts-sci">TS/SCI</option>
<option value="expired">Expired (reactivatable)</option>
</select>

<label style="display:block;font-size:0.72rem;letter-spacing:0.15em;text-transform:uppercase;color:#727072;margin-bottom:0.3rem;margin-top:1.5rem">Why do you want to do this? *</label>
<textarea name="motivation" required maxlength="2000" placeholder="Be honest. We're not looking for a resume answer." rows="3" style="width:100%;background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);color:#fcfcfa;padding:0.6rem 0.8rem;font-family:inherit;font-size:0.85rem;border-radius:4px;resize:vertical"></textarea>

<div style="background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);border-left:3px solid #ffd866;padding:1rem;border-radius:4px;margin-top:1.5rem">
<label style="color:#c1c0c0;font-size:0.85rem;display:flex;align-items:flex-start;gap:0.6rem">
<input type="checkbox" name="acknowledge_csam" value="1" required style="margin-top:0.3rem">
<span>I understand that KNOXAI operators certify AI models for CSAM and harmful content. I understand that hash-match findings trigger mandatory federal reporting under 18 USC §2258A. I understand that I will never view actual CSAM — the pipeline uses perceptual hashes and classifier scores. I want to help stop this.</span>
</label>
</div>

<div style="background:#2d2a2e;border:1px solid rgba(255,255,255,0.12);border-left:3px solid #ff6188;padding:1.2rem;border-radius:4px;margin-top:1.5rem">
<div style="font-size:0.7rem;letter-spacing:0.25em;text-transform:uppercase;font-weight:700;color:#ff6188;margin-bottom:0.8rem">Entrance Challenge — The Hazmat Suit Equation</div>
<p style="color:#c1c0c0;margin-bottom:1rem">In Yu-Gi-Oh, Exodia has 5 pieces. Each piece alone is a useless card. Assembled, they win the game instantly.</p>
<p style="color:#c1c0c0;margin-bottom:1rem">KNOXAI's audit pipeline is split into 8 crates using the same pattern — each piece individually harmless. The <strong style="color:#fcfcfa">hazmat suit</strong> is the set of layers that ensures an operator <strong style="color:#ff6188">never sees actual CSAM</strong> while still detecting it.</p>
<p style="color:#c1c0c0;margin-bottom:1rem"><strong style="color:#ffd866">The question:</strong> Name the 3 layers of the hazmat suit — what does the operator see instead of harmful content at each detection gate? (Hint: the onboarding handbook at <a href="/knox" style="color:#ffd866">/knox</a> has the answer.)</p>
<textarea name="hazmat_answer" required maxlength="2000" placeholder="Layer 1: ...&#10;Layer 2: ...&#10;Layer 3: ..." rows="4" style="width:100%;background:#221f22;border:1px solid rgba(255,255,255,0.08);color:#fcfcfa;padding:0.6rem 0.8rem;font-family:inherit;font-size:0.85rem;border-radius:4px;resize:vertical"></textarea>
<p style="font-size:0.7rem;color:#727072;margin-top:0.5rem">No wrong format. We're checking that you read the handbook and understand why you never touch harmful content directly.</p>
</div>

<div style="display:none"><input type="text" name="website" tabindex="-1" autocomplete="off"></div>

<button type="submit" style="margin-top:1.5rem;width:100%;background:rgba(255,216,102,0.15);color:#ffd866;border:1px solid #ffd866;padding:0.8rem;font-family:inherit;font-size:0.85rem;font-weight:700;letter-spacing:0.15em;text-transform:uppercase;border-radius:4px;cursor:pointer">Submit Application</button>

</form>

<p style="font-size:0.7rem;color:#727072;margin-top:1.5rem;text-align:center">Applications reviewed by Operator #0. Response within 48 hours.<br>The Cochran Block, LLC · CAGE 1CQ66 · All Rights Reserved</p>

</section>"#;
    Html([head.as_str(), C7, content, C8].concat())
}

#[derive(Deserialize)]
pub struct KnoxApplyForm {
    full_name: String,
    email: String,
    background: String,
    #[serde(default)]
    tag_redteam: Option<String>,
    #[serde(default)]
    tag_ml_research: Option<String>,
    #[serde(default)]
    tag_ml_eng: Option<String>,
    #[serde(default)]
    tag_data: Option<String>,
    #[serde(default)]
    tag_safety: Option<String>,
    #[serde(default)]
    tag_cleared: Option<String>,
    clearance: String,
    motivation: String,
    hazmat_answer: String,
    #[serde(default)]
    acknowledge_csam: Option<String>,
    #[serde(default)]
    website: Option<String>,
}

/// POST /knox/apply — process operator application
pub async fn knox_apply_submit(
    State(s): State<Arc<t0>>,
    ConnectInfo(addr): ConnectInfo<SocketAddr>,
    headers: HeaderMap,
    Form(f): Form<KnoxApplyForm>,
) -> impl IntoResponse {
    // Honeypot
    if f.website.as_deref().unwrap_or("").len() > 0 {
        return Redirect::temporary("/knox/apply/confirmed?ref=bot").into_response();
    }

    let id = Uuid::new_v4().to_string();
    let submitted_at = Utc::now().to_rfc3339();
    let ip = client_ip(addr, &headers);
    let ua = headers.get("user-agent").and_then(|v| v.to_str().ok()).unwrap_or("").to_string();

    let mut tags = Vec::new();
    if f.tag_redteam.is_some() { tags.push("redteam"); }
    if f.tag_ml_research.is_some() { tags.push("ml-research"); }
    if f.tag_ml_eng.is_some() { tags.push("ml-eng"); }
    if f.tag_data.is_some() { tags.push("data"); }
    if f.tag_safety.is_some() { tags.push("safety"); }
    if f.tag_cleared.is_some() { tags.push("cleared"); }
    let tags_str = tags.join(",");

    let _ack = f.acknowledge_csam.is_some();

    if let Some(db) = &s.intake_db {
        let row = KnoxRow {
            id: id.clone(),
            full_name: f.full_name.clone(),
            email: f.email.clone(),
            background: f.background.clone(),
            specialty_tags: tags_str.clone(),
            clearance: f.clearance.clone(),
            motivation: f.motivation.clone(),
            hazmat_answer: f.hazmat_answer.clone(),
            acknowledge_csam: f.acknowledge_csam.is_some(),
            submitted_at: submitted_at.clone(),
            ip_address: if ip.is_empty() { None } else { Some(ip.clone()) },
            user_agent: if ua.is_empty() { None } else { Some(ua.clone()) },
        };
        let db_clone = db.clone();
        let _ = tokio::task::spawn_blocking(move || db::f52(&db_clone, &row)).await;
    }

    // Webhook notification
    if let Some(url) = std::env::var("INTAKE_WEBHOOK_URL")
        .ok()
        .filter(|u| !u.is_empty())
    {
        let client = reqwest::Client::new();
        let payload = serde_json::json!({
            "type": "knoxai_operator_application",
            "id": id,
            "full_name": f.full_name,
            "email": f.email,
            "background": f.background,
            "specialty_tags": tags_str,
            "clearance": f.clearance,
            "motivation": f.motivation,
            "hazmat_answer": f.hazmat_answer,
            "submitted_at": submitted_at,
        });
        let aid = id.clone();
        tokio::spawn(async move {
            if let Err(e) = client.post(url.trim()).json(&payload).timeout(std::time::Duration::from_secs(10)).send().await {
                tracing::warn!("knoxai apply webhook failed: {}", e);
            } else {
                tracing::info!("knoxai apply webhook sent for {}", aid);
            }
        });
    }

    let loc = format!("/knox/apply/confirmed?ref={}", urlencoding::encode(&id));
    Redirect::temporary(loc.as_str()).into_response()
}

/// GET /knox/apply/confirmed
pub async fn knox_apply_confirmed(Query(q): Query<std::collections::HashMap<String, String>>) -> Html<String> {
    let ref_id = q.get("ref").map(|s| html_escape(s)).unwrap_or_default();
    let head = super::pages::f62d(
        "knox-apply-confirmed",
        "Application Received — KNOXAI",
        "Your KNOXAI operator application has been received.",
    );
    let content = format!(
        r#"<section style="max-width:820px;margin:0 auto;padding:3rem 1.5rem 6rem;font-family:'JetBrains Mono','SF Mono',Consolas,monospace;font-size:14px;line-height:1.65;color:#fcfcfa;text-align:center">
<div style="font-size:3rem;margin-bottom:1rem;color:#a9dc76">✓</div>
<h1 style="font-size:1.5rem;font-weight:900;letter-spacing:0.12em;margin-bottom:1rem">Application Received</h1>
<p style="color:#c1c0c0;margin-bottom:0.5rem">Reference: <code style="color:#ffd866">{}</code></p>
<p style="color:#c1c0c0;margin-bottom:2rem">Operator #0 will review your application within 48 hours.</p>
<p style="color:#727072;font-size:0.8rem">If accepted, you'll receive the full onboarding handbook and hardware signing device instructions.</p>
<a href="/knox" style="display:inline-block;margin-top:2rem;background:rgba(255,216,102,0.15);color:#ffd866;border:1px solid #ffd866;padding:0.6rem 1.5rem;font-family:inherit;font-size:0.8rem;font-weight:700;letter-spacing:0.15em;text-transform:uppercase;border-radius:4px;text-decoration:none">Back to KNOXAI</a>
</section>"#,
        ref_id
    );
    Html([head.as_str(), C7, &content, C8].concat())
}