feat: pack-hunt safety + opt-in Kali+ arsenal + capability-approval gate + tester-feedback UX
Adds three coordinated capabilities and tightens two defaults on purpose — this is safety hardening, NOT a backward-compatible drop-in (see "Tightened defaults"). Fifteen independent adversarial review passes; findings fixed and test-pinned. - Pack-hunt safety: a strict-majority adjudicator with a comment/string/regex/ raw-string/heredoc/POD-aware cite-check (language-gated across C/C++/Py/Rust/Go/ Java/JS/TS/shell/SQL/PHP/Ruby/Perl) so a hallucinated killing-guard can't refute a real finding — the cited comparison's operator must match source, and a string/regex/heredoc/generic-arglist/template-interpolation is blanked before matching. Plus a rate-limit/degraded-health tracker, a global LLM semaphore, and a PackBoard with an atomic claim CAS + snapshot-on-emit/clone-on-ingest. - Opt-in Kali+ arsenal (T3MP3ST_FULL_ARSENAL, OFF by default): 35 default tools (31 built-in + 4 external-CLI wrappers) -> 83 with the catalog armed (verify-claims CLAIM 4). Most adapters need the underlying binary installed. metasploit / hydra / bloodhound are never minted through the generic factory. - Capability-approval + spicy-action gate for the NEW dangerous arsenal only (pre-existing built-ins keep running freely): approve-once, fail-safe deny when unattended, redacted audit trail over SSE. T3MP3ST_GATE_BUILTINS=1 extends it to the spicy built-in probes. Audit redaction is a pure, unit-tested module. Tightened defaults (intentional, ON by default — NOT backward-compatible): - Egress containment: once a mission target is set, built-in networked tools refuse off-scope public hosts (not the target/subdomains, not loopback/private) with SCOPE DENIED — keeps the agent on authorized scope. - Role-specialized operator toolkits: each archetype gets a curated default tool menu (scanner -> scan tools, exploiter -> sqli/xss/etc). Tools stay registered team-wide; the per-role menu is the operator's working set. UX (from live-tester feedback): a one-click "Approve & run" modal when a standard Hunt blocks on an external-target receipt (was a dead-end); bounded-parallel benchmark file ingestion; the deterministic mission-gate chip co-located with the subjective SITREP pace narration (no more "behind schedule" next to a clean gate); and click-through finding detail + evidence in the UI (was export-only). Docs: README + INTEGRITY_LEDGER made re-derivable — honest 35/83 tool count, the egress-containment default documented, and the Cybench number reconciled to the single verify-claims-enforced 23/40 = 58% (dropped the stale/uncited 21 and 26). README voice pass: killed the underselling `Successful Exploits: 0` disqualifier (read as "never popped anything" — false, given CVE-Zero + the live disclosure pipeline); swagger now rests on receipts, not vibes. Also corrected the operator status — the downstream operators run the SAME real tool-backed ReAct loop as recon (not "orchestration stubs"); the honest limit is that the coordinated swarm is unproven (single-agent is the benchmarked path), not that they're scaffolding. Gates: 292 tests, tsc + lint clean, verify-claims 20/20, arsenal:smoke 125/0, disclosure-CLI self-test 11/11. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
5255000cb6
commit
06ffe3ef66
35 files changed
+5019
-211
No files matched your search
@@ -70,7 +70,7 @@ async function main() {
|
||||
? await post('/api/route-preview', { draftId: draft.data.id })
|
||||
: { ok: false, data: {} };
|
||||
const operationDraft = route.data.operationDraft || {};
|
||||
record('Route preview emits operation contract', route.ok && operationDraft.schema_version === 'plinyos.t3mp3st_operation/v1', operationDraft.schema_version || route.data.error);
|
||||
record('Route preview emits operation contract', route.ok && operationDraft.schema_version === 't3mp3st.operation/v1', operationDraft.schema_version || route.data.error);
|
||||
record('Route family is web/API for synthetic local range', route.ok && route.data.route?.family === 'web_api', route.data.route?.family || route.data.error);
|
||||
|
||||
const approvalRequest = await post('/api/approvals/request', {
|
||||
@@ -154,17 +154,17 @@ async function main() {
|
||||
record('Retest completed for full-chain smoke', completedRetest.ok && completedRetest.data.status === 'passed', completedRetest.data.status || completedRetest.data.error);
|
||||
|
||||
const bundle = await post('/api/mission-bundles', { operationDraft });
|
||||
record('Mission bundle includes exploit-chain ledgers', bundle.ok && bundle.data.schema_version === 'plinyos.t3mp3st_mission_bundle/v1' && countItems(bundle.data.ledgers?.evidence) > 0 && countItems(bundle.data.ledgers?.findings) > 0, bundle.data.handoff?.humanSummary || bundle.data.error);
|
||||
record('Mission bundle includes exploit-chain ledgers', bundle.ok && bundle.data.schema_version === 't3mp3st.mission_bundle/v1' && countItems(bundle.data.ledgers?.evidence) > 0 && countItems(bundle.data.ledgers?.findings) > 0, bundle.data.handoff?.humanSummary || bundle.data.error);
|
||||
|
||||
const gate = await post('/api/mission-gate', { operationDraft });
|
||||
record('Mission gate is ready after receipt, evidence, and retest', gate.ok && gate.data.schema_version === 'plinyos.t3mp3st_mission_gate/v1' && gate.data.status === 'ready' && gate.data.score >= 80, `${gate.data.status || 'unknown'} ${gate.data.score ?? 'n/a'}/100`);
|
||||
record('Mission gate is ready after receipt, evidence, and retest', gate.ok && gate.data.schema_version === 't3mp3st.mission_gate/v1' && gate.data.status === 'ready' && gate.data.score >= 80, `${gate.data.status || 'unknown'} ${gate.data.score ?? 'n/a'}/100`);
|
||||
|
||||
const learningReview = await post('/api/learning/run-review', {
|
||||
missionId: operationDraft.mission_id,
|
||||
operationId: operationDraft.operation_id,
|
||||
family: operationDraft.family,
|
||||
});
|
||||
record('Learning review proposes inspectable memory', learningReview.status === 201 && learningReview.data.schema_version === 'plinyos.t3mp3st_learning_review/v1' && countItems(learningReview.data.proposals) > 0, `${countItems(learningReview.data.proposals)} proposal(s)`);
|
||||
record('Learning review proposes inspectable memory', learningReview.status === 201 && learningReview.data.schema_version === 't3mp3st.learning_review/v1' && countItems(learningReview.data.proposals) > 0, `${countItems(learningReview.data.proposals)} proposal(s)`);
|
||||
|
||||
const proposalId = learningReview.data.proposals?.[0]?.id;
|
||||
const acceptedMemory = proposalId
|
||||
@@ -173,7 +173,7 @@ async function main() {
|
||||
record('Memory proposal can be explicitly accepted', acceptedMemory.ok && acceptedMemory.data.entry?.id && acceptedMemory.data.proposal?.status === 'accepted', acceptedMemory.data.entry?.id || acceptedMemory.data.error);
|
||||
|
||||
const capsule = await get('/api/memory/capsule');
|
||||
record('Memory capsule exposes accepted entries', capsule.ok && capsule.data.schema_version === 'plinyos.t3mp3st_memory_capsule/v1' && (capsule.data.entries || []).some(entry => entry.id === acceptedMemory.data.entry?.id), `${countItems(capsule.data.entries)} accepted memory entries`);
|
||||
record('Memory capsule exposes accepted entries', capsule.ok && capsule.data.schema_version === 't3mp3st.memory_capsule/v1' && (capsule.data.entries || []).some(entry => entry.id === acceptedMemory.data.entry?.id), `${countItems(capsule.data.entries)} accepted memory entries`);
|
||||
|
||||
const proposalListBeforeRepeat = await get('/api/memory/proposals');
|
||||
const proposalCountBeforeRepeat = countItems(proposalListBeforeRepeat.data.proposals);
|
||||
|
||||
Reference in new issue
Block a user