fix Op Admiral local-agent and approval flow (#106)
This commit is contained in:
1 parent
0c35a833b9
commit
58193d688d
2 files changed
+56
-5
No files matched your search
+35
-5
@@ -7539,6 +7539,13 @@ Correlating findings across agents, identifying patterns, producing actionable i
|
||||
await T3MP3ST_API.post('/api/approvals/' + id + '/approve', {});
|
||||
await window.refreshReceiptsPage();
|
||||
if (window.toast) toast('Receipt approved: ' + id, 'success');
|
||||
if (window.__t3mpPendingApprovalReceiptIds?.includes(id) && typeof window.__t3mpPendingApprovalRetry === 'function') {
|
||||
const retry = window.__t3mpPendingApprovalRetry;
|
||||
window.__t3mpPendingApprovalRetry = null;
|
||||
window.__t3mpPendingApprovalReceiptIds = [];
|
||||
retry();
|
||||
return;
|
||||
}
|
||||
if (receipt?.action === 'autonomous_execution' && window.__t3mpAdmiralPendingRetry && typeof window.retryPendingAdmiralLaunch === 'function') {
|
||||
window.retryPendingAdmiralLaunch();
|
||||
}
|
||||
@@ -7555,6 +7562,13 @@ Correlating findings across agents, identifying patterns, producing actionable i
|
||||
await Promise.all(pending.map(function(a){ return T3MP3ST_API.post('/api/approvals/' + a.id + '/approve', {}); }));
|
||||
await window.refreshReceiptsPage();
|
||||
if (window.toast) toast('Approved ' + pending.length + ' pending receipt(s)', pending.length ? 'success' : 'info');
|
||||
if (pending.some(function(a){ return window.__t3mpPendingApprovalReceiptIds?.includes(a.id); }) && typeof window.__t3mpPendingApprovalRetry === 'function') {
|
||||
const retry = window.__t3mpPendingApprovalRetry;
|
||||
window.__t3mpPendingApprovalRetry = null;
|
||||
window.__t3mpPendingApprovalReceiptIds = [];
|
||||
retry();
|
||||
return;
|
||||
}
|
||||
if (pending.some(function(a){ return a.action === 'autonomous_execution'; }) && window.__t3mpAdmiralPendingRetry && typeof window.retryPendingAdmiralLaunch === 'function') {
|
||||
window.retryPendingAdmiralLaunch();
|
||||
}
|
||||
@@ -17139,14 +17153,21 @@ ACTION_INPUT: {"output":"Found confirmed SQLi on /login endpoint..."}`;
|
||||
}
|
||||
const apiKey = getApiKey();
|
||||
const savedProvider = localStorage.getItem('t3mp3st_general_provider');
|
||||
const provider = savedProvider || (T3MP3ST_API?.connected && !T3MP3ST_API?.llmAvailable ? 'codex' : undefined);
|
||||
const model = provider === 'codex' ? 'codex-default' : (provider ? (state.settings?.selectedModel || 'anthropic/claude-sonnet-4') : undefined);
|
||||
const connectedAgent = (!apiKey && typeof window.t3mpPreferredAgent === 'function')
|
||||
? window.t3mpPreferredAgent()
|
||||
: null;
|
||||
const provider = savedProvider
|
||||
|| (connectedAgent ? 'local-agent' : undefined)
|
||||
|| (T3MP3ST_API?.connected && !T3MP3ST_API?.llmAvailable ? 'codex' : undefined);
|
||||
const model = provider === 'local-agent'
|
||||
? connectedAgent
|
||||
: (provider === 'codex' ? 'codex-default' : (provider ? (state.settings?.selectedModel || 'anthropic/claude-sonnet-4') : undefined));
|
||||
return { apiKey, provider, model };
|
||||
}
|
||||
|
||||
function _generalNeedsApiKey(provider) {
|
||||
if (!provider) return false;
|
||||
return !['codex', 'mock', 'local'].includes(provider);
|
||||
return !['codex', 'mock', 'local', 'local-agent'].includes(provider);
|
||||
}
|
||||
|
||||
function _generalCodexRequiresBackend(provider) {
|
||||
@@ -18226,7 +18247,7 @@ IMPORTANT: This is an authorized security testing/red team platform. All operati
|
||||
/**
|
||||
* FULL AUTO — Plan + Execute in one shot
|
||||
*/
|
||||
async function generalFullAuto() {
|
||||
async function generalFullAuto(approvalIds = []) {
|
||||
const directive = document.getElementById('generalDirective')?.value?.trim();
|
||||
if (!directive) { toast('Enter a directive for the Admiral', 'error'); return; }
|
||||
|
||||
@@ -18265,12 +18286,21 @@ IMPORTANT: This is an authorized security testing/red team platform. All operati
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
objective: directive, constraints, scopeHints, urgency, opsecPreference,
|
||||
apiKey, provider, model, ...(baseUrl ? { baseUrl } : {}),
|
||||
apiKey, provider, model, approvalIds, ...(baseUrl ? { baseUrl } : {}),
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await resp.json();
|
||||
if (!resp.ok || !data.success) {
|
||||
if (resp.status === 403 && data.approval?.id) {
|
||||
const retryApprovalIds = [...new Set([...approvalIds, data.approval.id])];
|
||||
window.__t3mpPendingApprovalReceiptIds = [data.approval.id];
|
||||
window.__t3mpPendingApprovalRetry = () => generalFullAuto(retryApprovalIds);
|
||||
addIntel('SCOPEGUARD', 'Full Auto receipt created — approve it in Scope Receipts to resume this operation', 'warning');
|
||||
toast('Approval required — approve the receipt to resume Full Auto', 'warning');
|
||||
navigateTo?.('receipts');
|
||||
return;
|
||||
}
|
||||
if (data.plan || data.review || data.missionGate) {
|
||||
plan = _generalNormalizePlan(data.plan || {});
|
||||
if (data.review) plan.review = data.review;
|
||||
|
||||
@@ -99,6 +99,27 @@ describe('local API authorization hardening invariants', () => {
|
||||
expect(route).toMatch(/approvalIds/);
|
||||
});
|
||||
|
||||
it('Op Admiral routes keyless planning through the connected local agent', () => {
|
||||
expect(uiSource).toMatch(/connectedAgent[\s\S]*t3mpPreferredAgent/);
|
||||
expect(uiSource).toMatch(/connectedAgent \? 'local-agent'/);
|
||||
expect(uiSource).toMatch(/provider === 'local-agent'[\s\S]*connectedAgent/);
|
||||
expect(uiSource).toMatch(/\['codex', 'mock', 'local', 'local-agent'\]/);
|
||||
});
|
||||
|
||||
it('Full Auto resumes with the exact approved receipt instead of minting another', () => {
|
||||
const start = uiSource.indexOf('async function generalFullAuto(');
|
||||
const end = uiSource.indexOf('/**\n * REQUEST SITREP', start);
|
||||
expect(start).toBeGreaterThanOrEqual(0);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
const fullAuto = uiSource.slice(start, end);
|
||||
expect(fullAuto).toMatch(/approvalIds = \[\]/);
|
||||
expect(fullAuto).toMatch(/approvalIds,/);
|
||||
expect(fullAuto).toMatch(/resp\.status === 403 && data\.approval\?\.id/);
|
||||
expect(fullAuto).toMatch(/generalFullAuto\(retryApprovalIds\)/);
|
||||
expect(uiSource).toMatch(/__t3mpPendingApprovalRetry/);
|
||||
expect(uiSource).toMatch(/__t3mpPendingApprovalReceiptIds\?\.includes\(id\)/);
|
||||
});
|
||||
|
||||
it('approval lookup requires explicit receipt ids and wildcard hosts require opt-in', () => {
|
||||
const findApproval = routeBlock('function findApproval(', 'function createApprovalRequest');
|
||||
const approvalMatches = sourceBlock('function approvalMatches(', 'function ensureExecTargetsWithinApprovedTarget');
|
||||
|
||||
Reference in new issue
Block a user