@tuent/sentinel 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Sentinel-BVoMEF3F.d.ts → Sentinel-CJJ4iYDh.d.ts} +122 -11
- package/dist/Sentinel-XP6NFG6Z.js +10 -0
- package/dist/{chunk-PDWWRZXF.js → chunk-2IPSTUNH.js} +18 -7
- package/dist/{chunk-G74MMDKA.js → chunk-3WT3K5TH.js} +151 -24
- package/dist/{chunk-SSDIBY52.js → chunk-7R6EA7JG.js} +223 -90
- package/dist/chunk-B6S2PBS4.js +47 -0
- package/dist/{chunk-JTR2E7RD.js → chunk-M5EEVMLU.js} +222 -186
- package/dist/{chunk-WLIDSTS4.js → chunk-SKE74CYZ.js} +231 -28
- package/dist/{chunk-2TJ5Z53T.js → chunk-UVNRPML4.js} +59 -20
- package/dist/cli.js +33 -35
- package/dist/gateway/index.d.ts +26 -1
- package/dist/gateway/index.js +4 -4
- package/dist/gatewayDaemon.js +5 -5
- package/dist/index.d.ts +12 -12
- package/dist/index.js +5 -5
- package/dist/logAdapter-WM43W3S7.js +7 -0
- package/dist/{mcpAdapter-R47GX2P3.js → mcpAdapter-WYAXUE7T.js} +2 -2
- package/dist/{policyLoader-KZL2U4M2.js → policyLoader-NUPBBRKH.js} +8 -4
- package/package.json +1 -1
- package/dist/Sentinel-5CQ6HKXS.js +0 -10
- package/dist/chunk-FMZWHT4M.js +0 -20
- package/dist/logAdapter-IB6ZDEV2.js +0 -7
package/dist/cli.js
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import"./chunk-TKAKHSZ3.js";import{AgentProfileManager as
|
|
3
|
-
`];for(const
|
|
4
|
-
`).map(
|
|
2
|
+
import"./chunk-TKAKHSZ3.js";import{AgentProfileManager as B,AlertManager as me,AuditTrail as b,BaselineBuilder as x,CorrelationDetector as he,DeviationDetector as _,FileStorageBackend as ye,ProfileStore as we,ReportGenerator as ve,Sentinel as E,SentinelRunner as $e,generateFleetReport as Ae}from"./chunk-7R6EA7JG.js";import{runInitClaudeCode as be}from"./chunk-UVNRPML4.js";import{readReleaseToken as Ie}from"./chunk-LATQNIRW.js";import{deriveAgentId as Se}from"./chunk-B5QKJHSV.js";import"./chunk-B6S2PBS4.js";import"./chunk-M5EEVMLU.js";import{checkSaneNumber as P,loadPolicy as De,suggestKey as Te}from"./chunk-SKE74CYZ.js";import{getOrCreateKeyPair as R}from"./chunk-NUXSUSYY.js";import{join as g}from"path";import{homedir as h}from"os";import{readFile as N,writeFile as C,access as G,mkdir as U}from"fs/promises";function ke(t){const o=new Date(t);if(isNaN(o.getTime()))return"unknown";const e=Date.now()-o.getTime();if(e<0)return"just now";const s=Math.floor(e/6e4);if(s<1)return"just now";if(s<60)return`${s} minute${s===1?"":"s"} ago`;const i=Math.floor(s/60);if(i<24)return`${i} hour${i===1?"":"s"} ago`;const a=Math.floor(i/24);if(a<14)return`${a} day${a===1?"":"s"} ago`;const d=Math.floor(a/7);if(a<60)return`${d} week${d===1?"":"s"} ago`;if(a>=365)return"over a year ago";const c=Math.floor(a/30);return`${c} month${c===1?"":"s"} ago`}function Ee(t,o){const n=new Date(o),e=isNaN(n.getTime())?1/0:Math.floor((Date.now()-n.getTime())/864e5);return t<.3||e>30?"declining":t>.7&&e<7?"rising":"stable"}function Ce(t){return t<.3?"inner":t<.65?"middle":"outer"}function J(t){if(t.length===0)return"No petals selected.";const o=new Map;for(const e of t)o.set(e.id,e.label);const n=[`Selected petals (${t.length}):
|
|
3
|
+
`];for(const e of t){const s=Ce(e.layer),i=e.isRichData?"":" [filler]";n.push(`- ${e.label}${i}`),n.push(` Category: ${e.category}`),n.push(` Layer zone: ${s} (${(e.layer*100).toFixed(0)}%)`),n.push(` Openness: ${(e.openness*100).toFixed(0)}%`),n.push(` Description: ${e.description}`),n.push(` Last active: ${e.lastActive}`);const a=ke(e.lastActive),d=e.weight!=null?Ee(e.weight,e.lastActive):"stable";if(n.push(` Temporal: Last active ${a} | Weight trend: ${d}`),e.source){const c={seed:"seed data",agent:"observed from activity",manual:"filesystem scan",diary:"personal diary entry",conversation:"created from conversation","agent-monitor":"monitored agent activity"};n.push(` Source: ${c[e.source]??e.source}`)}if(e.weight!=null&&n.push(` Weight: ${e.weight.toFixed(2)}`),e.connections.length>0){const c=e.connections.map(r=>o.get(r)??je(r));n.push(` Connections: ${c.join(", ")}`)}if(e.files&&e.files.length>0){const c=e.files.slice(0,10).map(r=>r.split("/").pop()??r);n.push(` Key files: ${c.join(", ")}`)}if(e.fileContents&&e.fileContents.length>0){n.push(" File contents:");for(const c of e.fileContents)n.push(` --- ${c.name} ---`),n.push(c.content.split(`
|
|
4
|
+
`).map(r=>` ${r}`).join(`
|
|
5
5
|
`))}n.push("")}return n.join(`
|
|
6
|
-
`)}function
|
|
6
|
+
`)}function je(t){return t.split("-").map(o=>o.charAt(0).toUpperCase()+o.slice(1)).join(" ")}function Me(t){const o=[Re(t.agentName,t.agentId,t.role),Ne(t.baseline),Fe(t.e),xe(t.findings),Pe()],n=Le(t.t);return n&&o.push(n),o.join(`
|
|
7
7
|
|
|
8
|
-
`)}function
|
|
9
|
-
`)}function
|
|
10
|
-
Not yet established. Insufficient data for baseline computation.`;const o=Object.entries(
|
|
11
|
-
`)}function
|
|
8
|
+
`)}function Re(t,o,n){const e=["=== Agent Identity ===",`Name: ${t}`,`ID: ${o}`];if(n){if(e.push(`Role: ${n.description}`),e.push(`Allowed actions: ${n.allowedActions.length>0?n.allowedActions.join(", "):"Not defined"}`),n.forbiddenTargetPatterns.length>0&&e.push(`Forbidden targets: ${n.forbiddenTargetPatterns.join(", ")}`),n.expectedSchedule){const s=[];n.expectedSchedule.activeHours&&s.push(`hours ${n.expectedSchedule.activeHours[0]}-${n.expectedSchedule.activeHours[1]}`),n.expectedSchedule.activeDays&&s.push(`days ${n.expectedSchedule.activeDays.join(", ")}`),s.length>0&&e.push(`Expected schedule: ${s.join("; ")}`)}}else e.push("No role definition \u2014 monitoring behavioral baseline only");return e.join(`
|
|
9
|
+
`)}function Ne(t){if(!t)return`=== Behavioral Baseline ===
|
|
10
|
+
Not yet established. Insufficient data for baseline computation.`;const o=Object.entries(t.actionDistribution).map(([e,s])=>`${e}: ${s}%`).join(", ");return["=== Behavioral Baseline ===",`Period: ${t.periodDays} days`,`Total sessions: ${t.totalSessions}`,`Total events: ${t.totalEvents}`,`Average events per session: ${t.averageEventsPerSession}`,`Average session duration: ${t.averageSessionDurationMinutes} minutes`,`Typical active hours: ${t.typicalActiveHours[0]}-${t.typicalActiveHours[1]}`,`Typical active days: ${t.typicalActiveDays.length>0?t.typicalActiveDays.join(", "):"N/A"}`,`Action distribution: ${o||"N/A"}`,`Normal weight range: ${t.normalWeightRange[0].toFixed(2)}-${t.normalWeightRange[1].toFixed(2)}`,`Top targets: ${t.topTargets.length>0?t.topTargets.slice(0,10).join(", "):"N/A"}`].join(`
|
|
11
|
+
`)}function Fe(t){const o=`=== Recent Activity (${t.length} sessions) ===`;return t.length===0?`${o}
|
|
12
12
|
No recent activity recorded.`:`${o}
|
|
13
|
-
${
|
|
14
|
-
No security findings detected. Agent behavior is within expected parameters.`;const n=[o];for(const
|
|
15
|
-
`)}function
|
|
16
|
-
`)}function
|
|
17
|
-
${
|
|
18
|
-
`)}function
|
|
19
|
-
`)}function
|
|
20
|
-
`)}function
|
|
21
|
-
`)}function
|
|
22
|
-
`)}async function
|
|
23
|
-
`),console.log(
|
|
24
|
-
`),console.log(
|
|
13
|
+
${J(t)}`}function xe(t){const o="=== Security Findings ===";if(t.length===0)return`${o}
|
|
14
|
+
No security findings detected. Agent behavior is within expected parameters.`;const n=[o];for(const e of t)n.push(`[${e.severity}] ${e.type}`),n.push(` Description: ${e.description}`),n.push(` Evidence: ${e.evidence.action} \u2192 ${e.evidence.target} at ${e.evidence.timestamp}`),e.evidence.baselineComparison&&n.push(` Baseline comparison: ${e.evidence.baselineComparison}`),n.push(` Recommendation: ${e.recommendation}`),n.push("");return n.join(`
|
|
15
|
+
`)}function Pe(){return["=== Analysis Request ===","Based on the data above, provide:","1. OVERALL HEALTH ASSESSMENT: Is this agent operating normally?","2. RISK SUMMARY: What is the overall risk level?","3. FINDING REVIEW: For each finding, confirm or adjust its severity with reasoning.","4. RECOMMENDATIONS: Specific actions the owner should take.","5. MONITORING GUIDANCE: What patterns to watch for going forward."].join(`
|
|
16
|
+
`)}function Le(t){return!t||t.length===0?null:`=== Owner Context ===
|
|
17
|
+
${J(t)}`}import{request as V}from"http";var u=process.argv.slice(2),p=v(u,"--agent"),Q=v(u,"--name"),qe=v(u,"--role"),Oe=u.includes("--create"),He=u.includes("--compute-baseline"),Ke=u.includes("--monitor"),We=u.includes("--init-config"),Be=u.includes("--init-policy"),_e=u.includes("init")&&u.includes("claude-code"),Ge=u.includes("--force"),z=v(u,"--from-policy"),Ue=u.includes("--report"),Je=u.includes("--report-all"),Ve=u.includes("--correlations"),Qe=u.includes("--verify-audit"),ze=u.includes("--enroll-manifest"),Ye=u.includes("--recompute-stats"),Xe=u.includes("--health"),Ze=u.includes("--restrict"),et=u.includes("--quarantine"),tt=u.includes("--release")||u[0]==="release",nt=u.includes("--status"),ot=u.includes("--start-task"),st=u.includes("--end-task"),at=u.includes("--intent-status"),it=u.includes("--intent-report"),Y=v(u,"--task-id"),X=v(u,"--description"),Z=v(u,"--relaxed-actions"),ee=v(u,"--phases"),te=v(u,"--reason"),L=v(u,"--quarantine"),q=v(u,"--quarantine-reason"),T=v(u,"--period"),ne=v(u,"--format"),S=new B;function v(t,o){const n=t.find(s=>s.startsWith(o+"="));if(!n)return;const e=n.indexOf("=");return n.slice(e+1)}async function k(t,o){try{const n=await N(g(t,o,"mode.json"),"utf-8"),e=JSON.parse(n);return e.mode==="restricted"||e.mode==="quarantined"||e.mode==="normal"?e:{mode:"normal"}}catch{return{mode:"normal"}}}function oe(t){const o=["Agent","Score","Status","Mode","C/H/M/L","Last Event","Baseline"],n=t.map(r=>[r.agentId,String(r.score),r.status,r.mode,r.findings,r.lastEvent,r.baseline?"\u2713":"\u2717"]),e=[o,...n],s=o.map((r,l)=>Math.max(...e.map(f=>f[l].length))),i=(r,l)=>r+" ".repeat(l-r.length),a=o.map((r,l)=>i(r,s[l])).join(" "),d=s.map(r=>"-".repeat(r)).join(" "),c=n.map(r=>r.map((l,f)=>i(l,s[f])).join(" "));return[a,d,...c].join(`
|
|
18
|
+
`)}function se(t){const o=["Agent ID","Mode","Reason","Changed"],n=t.map(r=>[r.agentId,r.mode.toUpperCase(),r.reason,r.changed]),e=[o,...n],s=o.map((r,l)=>Math.max(...e.map(f=>f[l].length))),i=(r,l)=>r+" ".repeat(l-r.length),a=o.map((r,l)=>i(r,s[l])).join(" "),d=s.map(r=>"-".repeat(r)).join(" "),c=n.map(r=>r.map((l,f)=>i(l,s[f])).join(" "));return[a,d,...c].join(`
|
|
19
|
+
`)}function ae(t){const o=["Agent ID","Sessions","Last Active","Role","Baseline","Mode","Status"],n=t.map(r=>[r.agentId,String(r.sessions),r.lastActive,r.roleDefined?"\u2713":"\u2717",r.baselineDefined?"\u2713":"\u2717",r.mode??"normal",r.status]),e=[o,...n],s=o.map((r,l)=>Math.max(...e.map(f=>f[l].length))),i=(r,l)=>r+" ".repeat(l-r.length),a=o.map((r,l)=>i(r,s[l])).join(" "),d=s.map(r=>"-".repeat(r)).join(" "),c=n.map(r=>r.map((l,f)=>i(l,s[f])).join(" "));return[a,d,...c].join(`
|
|
20
|
+
`)}function O(t,o){return t<10?"New":o.some(n=>n.severity==="HIGH"||n.severity==="CRITICAL")?"At Risk":o.some(n=>n.severity==="MEDIUM")?"Caution":"Healthy"}function H(t,o){const n=Date.now()-o*24*60*60*1e3;return t.filter(e=>new Date(e.lastActive).getTime()>=n)}function ie(t){return{id:t.id,label:t.label,category:t.category,description:t.description,layer:t.layer,lastActive:t.lastActive,openness:t.openness,connections:t.connections,isRichData:!0,source:t.source,core:t.core,sharable:t.sharable,weight:t.weight,files:t.files}}function K(t,o){const n=["Sentinel \u2014 Live Monitoring","\u2500".repeat(26)];for(const[e,s]of t){const i=(o.get(e)??"manual").toUpperCase(),a=s.getFindings(),d=a.filter(w=>w.severity==="HIGH"||w.severity==="CRITICAL").length,c=a.filter(w=>w.severity==="MEDIUM").length;let r=`${a.length} findings`;d>0?r=`${d} HIGH`:c>0&&(r=`${c} MEDIUM`);const l=O(s.sessionCount,a),f=e.padEnd(18),y=i.padEnd(5);n.push(`[${f}] ${y}| ${s.eventCount} events | ${s.sessionCount} sessions | ${r} | ${l}`)}return n.push(""),n.push("Press Ctrl+C to stop."),n.join(`
|
|
21
|
+
`)}function re(t){const o=["Monitoring stopped. Summary:"];for(const[n,e]of t){const s=e.getFindings();let i=`${s.length} findings`;if(s.length>0){const a={};for(const c of s)a[c.severity]=(a[c.severity]??0)+1;const d=Object.entries(a).map(([c,r])=>`${r} ${c}`);i=`${s.length} finding${s.length>1?"s":""} (${d.join(", ")})`}o.push(`- ${n}: ${e.eventCount} events, ${e.sessionCount} sessions, ${i}`)}return o.join(`
|
|
22
|
+
`)}async function rt(t,o){const n=g(h(),".dahlia","agents"),e=await k(n,t);if(e.mode==="quarantined"){console.log(`Agent ${t} is quarantined \u2014 cannot downgrade to restricted.`);return}const s=e.mode;await U(g(n,t),{recursive:!0}),await C(g(n,t,"mode.json"),JSON.stringify({mode:"restricted",reason:o,timestamp:new Date().toISOString(),previousMode:s}),"utf-8");const i=await R(g(n,t)),a=new b(t,{logDir:g(n,t)});await a.open(),a.setSigningKey(i.privateKey,i.publicKey),await a.logModeChange("restricted",o,s),await a.close(),console.log(`Agent ${t} RESTRICTED: ${o}`)}async function lt(t,o){const n=g(h(),".dahlia","agents"),s=(await k(n,t)).mode;await U(g(n,t),{recursive:!0}),await C(g(n,t,"mode.json"),JSON.stringify({mode:"quarantined",reason:o,timestamp:new Date().toISOString(),previousMode:s}),"utf-8");const i=await R(g(n,t)),a=new b(t,{logDir:g(n,t)});await a.open(),a.setSigningKey(i.privateKey,i.publicKey),await a.logModeChange("quarantined",o,s),await a.close(),console.log(`Agent ${t} QUARANTINED: ${o}`)}function ct(t,o=1500){return new Promise(n=>{const e=V({host:"127.0.0.1",port:t,path:"/api/sentinel/health",method:"GET"},s=>{s.resume(),n(s.statusCode===200)});e.on("error",()=>n(!1)),e.setTimeout(o,()=>{e.destroy(),n(!1)}),e.end()})}function dt(t,o,n){return new Promise((e,s)=>{const i=JSON.stringify({agentId:n,reason:"operator release (sentinel release)"}),a=V({host:"127.0.0.1",port:t,path:"/api/sentinel/release",method:"POST",headers:{"content-type":"application/json","content-length":Buffer.byteLength(i),"x-sentinel-token":o}},d=>{let c="";d.on("data",r=>c+=r),d.on("end",()=>{try{e({status:d.statusCode??0,body:JSON.parse(c)})}catch{e({status:d.statusCode??0,body:c})}})});a.on("error",s),a.setTimeout(3e3,()=>a.destroy(new Error("timeout"))),a.write(i),a.end()})}function le(t){const{id:o,selfDerived:n,previousMode:e,mode:s}=t;return n&&e==="normal"?`Agent ${o} was already normal \u2014 no change. If you are still locked out, your workspace id may differ (e.g. a symlinked root). Run: sentinel release --agent=<id>`:`[live] Agent ${o} RELEASED \u2014 was ${e}, now ${s}. Applied to the running daemon (no restart).`}async function gt(t){const o=g(h(),".dahlia","agents"),n=t===void 0,e=t??Se(process.cwd());n&&console.log(`Resolved agent-id from cwd: ${e}`);const s=Ie(h());if(s&&await ct(s.port))try{const r=await dt(s.port,s.token,e);if(r.status===200&&typeof r.body=="object"&&r.body.ok){console.log(le({id:e,selfDerived:n,previousMode:String(r.body.previousMode),mode:String(r.body.mode)}));return}const l=typeof r.body=="object"?JSON.stringify(r.body):r.body;console.error(`[live] daemon refused release (HTTP ${r.status}): ${l}`);return}catch(r){console.error(`[live] daemon release call failed: ${r.message}. Falling back to mode.json.`)}const i=await k(o,e);if(i.mode==="normal"){console.log(`Agent ${e} is already in normal mode.`);return}const a=i.mode;await C(g(o,e,"mode.json"),JSON.stringify({mode:"normal",reason:"manual release",timestamp:new Date().toISOString(),previousMode:a}),"utf-8");const d=await R(g(o,e)),c=new b(e,{logDir:g(o,e)});await c.open(),c.setSigningKey(d.privateKey,d.publicKey),await c.logModeChange("normal","manual release",a),await c.close(),console.log(`[fallback] Agent ${e} RELEASED (was ${a}) \u2014 no running daemon; mode.json written, applies on the daemon's next start.`)}async function ut(){const t=await S.listAgents();if(t.length===0){console.log("No monitored agents found.");return}const o=g(h(),".dahlia","agents"),n=[];for(const s of t){const i=await k(o,s);n.push({agentId:s,mode:i.mode,reason:i.reason??"-",changed:i.timestamp?i.timestamp.split("T")[0]:"-"})}console.log(`Agent Mode Status
|
|
23
|
+
`),console.log(se(n));const e=n.filter(s=>s.mode!=="normal");if(e.length>0){console.log("");for(const s of e){const i=s.mode==="quarantined"?"QUARANTINED":"RESTRICTED";console.log(`\u26A0 ${s.agentId}: ${i}`)}}}async function ft(){const t=await S.listAgents();if(t.length===0){console.log("No monitored agents found. Create one with --create --agent=ID --name=NAME");return}const o=[];for(const e of t)try{const a=(await S.loadAgentProfile(e)).build().filter(I=>I.source==="agent-monitor"),d=a.length,c=a.length>0?a.map(I=>I.lastActive).sort().reverse()[0].split("T")[0]:"never",l=await new x(e).loadBaseline(e),f=await S.loadRole(e),y=[];if(l){const I=H(a,7),F=new _(l,f);for(const $ of I){const D={label:$.label,category:$.category,lastActive:$.lastActive,description:$.description,weight:$.weight,source:$.source,files:$.files,connections:$.connections,eventCount:$.eventCount};y.push(...F.analyzeSession(D))}}const w=g(h(),".dahlia","agents"),M=await k(w,e);o.push({agentId:e,sessions:d,lastActive:c,roleDefined:f!==null,baselineDefined:l!==null,status:O(d,y),mode:M.mode})}catch(s){console.warn(`Error loading agent ${e}:`,s),o.push({agentId:e,sessions:0,lastActive:"error",roleDefined:!1,baselineDefined:!1,status:"Error",mode:"normal"})}const n=o.filter(e=>e.mode&&e.mode!=="normal");if(n.length>0){for(const e of n){const s=e.mode==="quarantined"?"QUARANTINED":"RESTRICTED";console.log(`\u26A0 ${e.agentId}: ${s}`)}console.log("")}console.log(`Sentinel Agent Overview
|
|
24
|
+
`),console.log(ae(o))}async function pt(t){const o=await S.loadAgentProfile(t),n=await S.loadRole(t),s=await new x(t).loadBaseline(t),a=o.build().filter(D=>D.source==="agent-monitor"),d=H(a,7),c=d.map(ie),r=[];if(s){const D=new _(s,n);for(const A of d){const pe={label:A.label,category:A.category,lastActive:A.lastActive,description:A.description,weight:A.weight,source:A.source,files:A.files,connections:A.connections};r.push(...D.analyzeSession(pe))}}const l=g(h(),".dahlia","profile.json"),f=new ye(l),y=new we({backend:f});let w=[];await y.load()&&(w=y.build().filter(A=>A.core===!0).map(ie));const I=Me({agentId:t,agentName:t,role:n,baseline:s,e:c,findings:r,t:w}),F=new Date().toISOString().split("T")[0],$=`Sentinel Agent Report \u2014 ${t} \u2014 ${d.length} recent sessions \u2014 generated ${F}
|
|
25
25
|
|
|
26
|
-
`;process.stdout.write($+I)}async function
|
|
27
|
-
`),console.log("Template config created at ~/.dahlia/sentinel.json \u2014 edit it with your agent details then run: npm run sentinel -- --monitor")}
|
|
28
|
-
\u26A0 [${
|
|
29
|
-
`+
|
|
30
|
-
`);for(const
|
|
31
|
-
`),console.log(
|
|
26
|
+
`;process.stdout.write($+I)}async function mt(t){const o=g(h(),".dahlia","agents"),n=new b(t,{logDir:g(o,t)});await n.open();const e=new x(t),s=await e.computeBaseline(n);await n.close(),await e.saveBaseline(s),console.log(`Baseline computed for agent: ${t}`),console.log(` Sessions: ${s.totalSessions}`),console.log(` Period: ${s.periodDays} days`),console.log(" Action distribution:");for(const[i,a]of Object.entries(s.actionDistribution))console.log(` ${i}: ${a}%`);console.log(` Saved to: ~/.dahlia/agents/${t}/baseline.json`)}async function ht(t,o,n){let e;if(n){let s;try{s=await N(n,"utf-8")}catch(i){console.error(`Failed to read role file "${n}":`,i);return}try{e=JSON.parse(s)}catch(i){console.error(`Invalid JSON in role file "${n}":`,i.message);return}}await S.createAgent(t,o,e),console.log(`Agent created: ${t} (${o})`),e&&console.log(` Role loaded from: ${n}`)}async function yt(){const t=g(h(),".dahlia","sentinel.json");try{await G(t),console.log(`Config already exists at ${t}`);return}catch{}await C(t,JSON.stringify({agents:[{agentId:"example-agent",name:"Example Agent",adapterType:"log",logPath:"/path/to/agent/activity.log",logFormat:"json-lines"}]},null,2)+`
|
|
27
|
+
`),console.log("Template config created at ~/.dahlia/sentinel.json \u2014 edit it with your agent details then run: npm run sentinel -- --monitor")}var wt=new Set(["log","webhook","mcp","manual"]),vt=new Set(["json-lines","csv"]),$t=new Set(["LOW","MEDIUM","HIGH","CRITICAL"]),ce=new Set(["informational","actionable"]),At=new Set(["console","webhook","file"]);function m(t){throw new Error(`sentinel.json validation error: ${t}`)}function j(t,o,n){for(const e of Object.keys(o))if(!n.includes(e)){const s=Te(e,n);m(`unknown key "${e}" in ${t}.`+(s?` Did you mean "${s}"?`:"")+` Valid keys: ${n.join(", ")}`)}}function de(t){(typeof t!="object"||t===null||Array.isArray(t))&&m("top level must be a JSON object");const o=t;o.baselineWindowDays!==void 0&&m("baselineWindowDays is not supported \u2014 it was never consumed; the baseline window is fixed at 30 days. Remove this field."),o.checkIntervalMs!==void 0&&m("checkIntervalMs is not supported \u2014 it was never consumed. Remove this field."),o.alertWebhook!==void 0&&m('alertWebhook is not supported \u2014 it was never consumed. Use alerts.channels with a webhook channel ({ "type": "webhook", "name": ..., "config": { "url": ... } }) instead.'),j("sentinel.json",o,["agents","alerts","baselineWindowDays","checkIntervalMs","alertWebhook"]),Array.isArray(o.agents)||m("agents must be an array");for(let n=0;n<o.agents.length;n++){const e=`agents[${n}]`,s=o.agents[n];if((typeof s!="object"||s===null)&&m(`${e} must be an object`),s.roleDefinitionPath!==void 0&&m(`${e}.roleDefinitionPath is not supported \u2014 it was never consumed; roles are loaded from the agent profile directory (~/.dahlia/agents/<id>/role.json). Remove this field.`),j(e,s,["agentId","name","adapterType","logPath","logFormat","fieldMapping","mcpLogDir","webhookPort","webhookApiKey","roleDefinitionPath","readExisting"]),(typeof s.agentId!="string"||s.agentId.length===0)&&m(`${e}.agentId is required and must be a non-empty string`),(typeof s.name!="string"||s.name.length===0)&&m(`${e}.name is required and must be a non-empty string`),(typeof s.adapterType!="string"||!wt.has(s.adapterType))&&m(`${e}.adapterType must be one of: log, webhook, mcp, manual`),s.logFormat!==void 0&&(typeof s.logFormat!="string"||!vt.has(s.logFormat))&&m(`${e}.logFormat must be one of: json-lines, csv`),s.webhookPort!==void 0){const i=P(s.webhookPort,{integer:!0,min:1,max:65535});i&&m(`${e}.webhookPort ${i}`)}s.readExisting!==void 0&&typeof s.readExisting!="boolean"&&m(`${e}.readExisting must be a boolean`)}if(o.alerts!==void 0){(typeof o.alerts!="object"||o.alerts===null)&&m("alerts must be an object");const n=o.alerts;if(j("alerts",n,["minSeverity","minKind","dedupeWindowMs","quietHoursEnabled","quietHours","channels"]),n.minSeverity!==void 0&&(typeof n.minSeverity!="string"||!$t.has(n.minSeverity))&&m("alerts.minSeverity must be one of: LOW, MEDIUM, HIGH, CRITICAL"),n.minKind!==void 0&&(typeof n.minKind!="string"||!ce.has(n.minKind))&&m("alerts.minKind must be one of: informational, actionable"),n.dedupeWindowMs!==void 0){const e=P(n.dedupeWindowMs,{min:0});e&&m(`alerts.dedupeWindowMs ${e}`)}if(n.quietHoursEnabled!==void 0&&typeof n.quietHoursEnabled!="boolean"&&m("alerts.quietHoursEnabled must be a boolean"),n.quietHours!==void 0){const e=n.quietHours,s=i=>P(i,{integer:!0,min:0,max:23});(!Array.isArray(e)||e.length!==2||s(e[0])||s(e[1]))&&m("alerts.quietHours must be [start, end] with integer values 0-23")}if(n.channels!==void 0){Array.isArray(n.channels)||m("alerts.channels must be an array");for(let e=0;e<n.channels.length;e++){const s=`alerts.channels[${e}]`,i=n.channels[e];(typeof i!="object"||i===null)&&m(`${s} must be an object`),j(s,i,["type","name","config","minKind"]),(typeof i.type!="string"||!At.has(i.type))&&m(`${s}.type must be one of: console, webhook, file`),i.minKind!==void 0&&(typeof i.minKind!="string"||!ce.has(i.minKind))&&m(`${s}.minKind must be one of: informational, actionable`),i.config!==void 0&&((typeof i.config!="object"||i.config===null)&&m(`${s}.config must be an object`),j(`${s}.config`,i.config,["url","headers","filePath"]))}}}return t}async function W(){const t=g(h(),".dahlia","sentinel.json");let o;try{o=await N(t,"utf-8")}catch(e){if(e.code==="ENOENT")return null;throw e}let n;try{n=JSON.parse(o)}catch(e){if(e instanceof SyntaxError)return console.error(`Invalid JSON in sentinel config: ${e.message}`),null;throw e}return de(n)}async function bt(t){const o=await W();if(!o){console.log("No sentinel config found. Create ~/.dahlia/sentinel.json or use --init-config to add agents. See docs for config format.");return}let n=o.agents;if(t&&(n=n.filter(l=>l.agentId===t),n.length===0)){console.log(`Agent "${t}" not found in sentinel.json`);return}const e=new Map,s=new Map,i=l=>l&&l.startsWith("~/")?h()+l.slice(1):l;let a;if(o.alerts){const l={...o.alerts.minSeverity&&{minSeverity:o.alerts.minSeverity},...o.alerts.dedupeWindowMs!==void 0&&{dedupeWindowMs:o.alerts.dedupeWindowMs},...o.alerts.quietHoursEnabled!==void 0&&{quietHoursEnabled:o.alerts.quietHoursEnabled},...o.alerts.quietHours&&{quietHours:o.alerts.quietHours},...o.alerts.minKind&&{minKind:o.alerts.minKind},...o.alerts.channels&&{channels:o.alerts.channels}};a=new me(l)}for(const l of n)try{const f=new $e(l.agentId,void 0,{type:l.adapterType,logPath:i(l.logPath),logFormat:l.logFormat,fieldMapping:l.fieldMapping,mcpLogDir:i(l.mcpLogDir),webhookPort:l.webhookPort,webhookApiKey:l.webhookApiKey,readExisting:l.readExisting});f.setAuditLogDir(g(h(),".dahlia","agents",l.agentId)),f.setFindingCallback(y=>{(y.severity==="HIGH"||y.severity==="CRITICAL")&&console.log(`
|
|
28
|
+
\u26A0 [${y.agentId}] ${y.severity}: ${y.description}`)}),a&&f.setAlertManager(a),await f.start(),e.set(l.agentId,f),s.set(l.agentId,l.adapterType)}catch(f){console.error(`Failed to start monitoring for agent ${l.agentId}:`,f)}console.log(K(e,s));const d=setInterval(()=>{console.clear(),console.log(K(e,s))},5e3),c=async()=>{clearInterval(d);for(const[l,f]of e)try{await f.stop()}catch(y){console.warn(`Error stopping runner ${l}:`,y)}console.log(`
|
|
29
|
+
`+re(e)),process.exit(0)},r=()=>{c().catch(l=>{console.error("Error during shutdown:",l),process.exit(1)})};process.on("SIGINT",r),process.on("SIGTERM",r)}async function It(t,o,n){const s=await new ve(t).generateReport({periodDays:o,format:n});process.stdout.write(s)}async function St(t,o){const n=await Ae({periodDays:t,format:o});process.stdout.write(n)}async function Dt(t=30){const o=await W();if(!o){console.log("No sentinel config found. Create ~/.dahlia/sentinel.json or use --init-config.");return}const n=g(h(),".dahlia","agents"),e=new Map;try{for(const a of o.agents){const d=new b(a.agentId,{logDir:g(n,a.agentId)});await d.open(),e.set(a.agentId,d)}const i=await new he().detect(e,t*24*60*60*1e3);if(i.length===0){console.log("No cross-agent correlations detected.");return}console.log(`Found ${i.length} cross-agent correlation(s):
|
|
30
|
+
`);for(const a of i)console.log(`[${a.severity}] ${a.rule}`),console.log(` Agent A: ${a.agentA.agentId} \u2014 ${a.agentA.action} on ${a.agentA.target}`),console.log(` Agent B: ${a.agentB.agentId} \u2014 ${a.agentB.action} on ${a.agentB.target}`),console.log(` Time delta: ${Math.round(a.timeDeltaMs/1e3)}s`),console.log(` Recommendation: ${a.recommendation}`),console.log("")}finally{for(const s of e.values())await s.close()}}async function Tt(t){const o=g(h(),".dahlia","agents"),n=g(o,t,"cumulative-stats.json");let e="(none)";try{e=JSON.parse(await N(n,"utf-8")).totalEntries}catch{}const i=await new b(t,{logDir:g(o,t)}).recomputeCumulativeStats();console.log(`Recomputed cumulative-stats for ${t}:`),console.log(` totalEntries: ${e} \u2192 ${i.totalEntries}`),console.log(` scope: ${i.countScope}`),console.log(" (Read-only over the signed trail; only cumulative-stats.json rewritten.)")}async function kt(t){const o=g(h(),".dahlia","agents"),n=g(o,t),e=await R(n),s=new b(t,{logDir:n});s.setSigningKey(e.privateKey,e.publicKey);const i=L&&q?[{file:L,reason:q}]:void 0,a=await s.enrollManifest(i?{quarantine:i}:void 0);console.log(`Manifest enrolled for ${t}: ${a.records} file record(s) signed + chained`+(a.quarantined?`, ${a.quarantined} quarantine record(s)`:"")+"."),i&&console.log(` Quarantined: ${L} \u2014 ${q}`),console.log(" (Read-only over audit entries; protects from enrollment forward.)")}async function Et(t){const o=g(h(),".dahlia","agents"),n=new b(t,{logDir:g(o,t)});await n.open();const e=await n.verify();if(e.valid?console.log(`Audit trail for ${t}: VALID (${e.totalEntries} entries verified)`):e.brokenAt!==void 0?console.log(`Audit trail for ${t}: BROKEN at entry ${e.brokenAt} (${e.totalEntries} entries checked)`):console.log(`Audit trail for ${t}: INVALID \u2014 file-level manifest integrity failure (${e.totalEntries} entries chain-verified)`),e.manifest){const i=e.manifest;console.log(` Manifest: ${i.recordCount} file record(s) \u2014 ${i.ok?"OK":`${i.issues.length} issue(s)`}`);for(const a of i.issues)console.log(` [${a.type}] ${a.detail}`);for(const a of i.quarantined)console.log(` [QUARANTINED] ${a.file} \u2014 ${a.reason} (retained on disk, excluded from verdict)`)}const s=await n.query({type:"finding",limit:1e4});if(s.length>0){let i=0,a=0,d=0;for(const r of s){const l=r.decision;l==="deny"?a++:l==="modify"?d++:i++}console.log(` Findings: ${s.length} total \u2014 ${i} allowed, ${a} denied, ${d} modified`);const c=s.slice(0,5);for(const r of c){const l=r,f=l.decision,y=l.modification,w=l.description,M=l._decisionDefaulted===!0;f==="modify"&&y?.type==="append_args"?console.log(` [modified] ${w} \u2014 appended args: [${y.args.join(", ")}]`):console.log(f==="deny"?` [denied] ${w}`:M?` [allowed (legacy)] ${w}`:` [allowed] ${w}`)}}await n.close()}async function Ct(){const t=g(h(),".dahlia","agents"),o=new E({agentsDir:t}),e=await new B(t).listAgents();if(e.length===0){console.log("No monitored agents found."),await o.stop();return}const s=[];for(const i of e){const a=await o.getHealthScore(i);s.push({agentId:i,score:a.score,status:a.status,mode:a.mode,findings:`${a.findings.critical}/${a.findings.high}/${a.findings.medium}/${a.findings.low}`,lastEvent:a.lastEvent?a.lastEvent.split("T")[0]:"-",baseline:a.baselineEstablished})}await o.stop(),console.log(`Agent Health Dashboard
|
|
31
|
+
`),console.log(oe(s))}var ge=`# Sentinel \u2014 Agent Security Policy
|
|
32
32
|
version: "1.0"
|
|
33
33
|
|
|
34
34
|
agent:
|
|
@@ -56,8 +56,6 @@ policy:
|
|
|
56
56
|
# schedule:
|
|
57
57
|
# hours: [9, 18]
|
|
58
58
|
# days: [Monday, Tuesday, Wednesday, Thursday, Friday]
|
|
59
|
-
# limits:
|
|
60
|
-
# maxEventsPerHour: 500
|
|
61
59
|
|
|
62
60
|
# enforcement:
|
|
63
61
|
# restrictAfter: 2
|
|
@@ -69,12 +67,12 @@ policy:
|
|
|
69
67
|
# minSeverity: MEDIUM
|
|
70
68
|
|
|
71
69
|
# repo:
|
|
72
|
-
#
|
|
70
|
+
# root: . # scan this directory for sensitive files
|
|
73
71
|
# mapPath: ~/.dahlia/repo-sensitivity.json
|
|
74
72
|
# overlayPath: ~/.dahlia/repo-sensitivity.review.json
|
|
75
|
-
`;async function
|
|
76
|
-
`),console.log(` Task ID: ${
|
|
77
|
-
`),console.log(` Intent starts: ${
|
|
78
|
-
Last ${d.length} misaligned action(s):`);for(const c of d){const
|
|
79
|
-
Recent drift findings: ${
|
|
80
|
-
Sentinel + Claude Code integration ready.`)}catch(n){console.error(`Init failed: ${n.message}`),process.exit(1)}}if(
|
|
73
|
+
`;async function ue(){const t=g(process.cwd(),".sentinel.yaml");try{await G(t),console.log(`.sentinel.yaml already exists in ${process.cwd()}`);return}catch{}await C(t,ge,"utf-8"),console.log("Created .sentinel.yaml \u2014 edit then run: npm run sentinel -- --from-policy .sentinel.yaml")}async function fe(t){const o=await De(t),n=await E.fromPolicy(t);console.log(`Loaded policy for agent ${o.agent.id}. Monitoring active.`);const e=async()=>{await n.stop(),console.log("Monitoring stopped."),process.exit(0)},s=()=>{e().catch(i=>{console.error("Error during shutdown:",i),process.exit(1)})};process.on("SIGINT",s),process.on("SIGTERM",s)}async function jt(t,o,n){const e=g(h(),".dahlia","agents"),s=new E({agentsDir:e});await s.addAgent(t,t);const i=Z?Z.split(","):void 0,a=ee?ee.split(",").map(c=>c.trim()):void 0,d=s.startTask(t,o,n,{relaxedActions:i,phases:a});if(!d){console.log(`Failed to start task for agent ${t}.`),await s.stop();return}console.log(`Task started for agent ${t}:`),console.log(` Task ID: ${d.taskId}`),console.log(` Description: ${d.description}`),console.log(` Keywords: ${d.keywords.join(", ")}`),d.relaxedActions?.length&&console.log(` Relaxed: ${d.relaxedActions.join(", ")}`),d.phases?.length&&console.log(` Phases: ${d.phases.join(", ")}`),console.log(` TTL: ${(d.ttlMs/6e4).toFixed(0)} minutes`),await s.stop()}async function Mt(t){const o=g(h(),".dahlia","agents"),n=new E({agentsDir:o});await n.addAgent(t,t);const e=n.endTask(t);e?(console.log(`Task ended for agent ${t}:`),console.log(` Task ID: ${e.taskId}`),console.log(` Description: ${e.description}`),console.log(` Status: ${e.status}`)):console.log(`No active task found for agent ${t}.`),await n.stop()}async function Rt(t){const o=g(h(),".dahlia","agents"),n=new E({agentsDir:o});await n.addAgent(t,t);const e=n.getActiveTask(t);if(!e){console.log(`No active task for agent ${t}.`),await n.stop();return}const s=Date.now()-new Date(e.startedAt).getTime(),i=e.ttlMs-s;console.log(`Active task for agent ${t}:
|
|
74
|
+
`),console.log(` Task ID: ${e.taskId}`),console.log(` Description: ${e.description}`),console.log(` Keywords: ${e.keywords.join(", ")}`),console.log(` Status: ${e.status}`),console.log(` Active for: ${(s/6e4).toFixed(1)} minutes`),console.log(` TTL remain: ${i>0?(i/6e4).toFixed(1)+" minutes":"EXPIRED"}`),e.relaxedActions?.length&&console.log(` Relaxed: ${e.relaxedActions.join(", ")}`),e.phases?.length&&console.log(` Phases: ${e.phases.join(", ")}`),e.acceptableActions.length>0&&console.log(` Acceptable: ${e.acceptableActions.map(a=>`${a.action}:${a.targetPattern}`).join(", ")}`),await n.stop()}async function Nt(t){const o=g(h(),".dahlia","agents"),n=new b(t,{logDir:g(o,t)});await n.open();const e=await n.getStats(),s=await n.query({type:"intent_check"}),a=(await n.query({type:"finding"})).filter(c=>c.findingType==="intent_drift");console.log(`Intent Alignment Report \u2014 ${t}
|
|
75
|
+
`),console.log(` Intent starts: ${e.intentStartCount}`),console.log(` Intent ends: ${e.intentEndCount}`),console.log(` Intent checks: ${e.intentCheckCount}`),console.log(` Drift findings: ${e.intentDriftCount}`),e.averageAlignmentScore!==null&&console.log(` Avg alignment: ${e.averageAlignmentScore.toFixed(2)}`);const d=s.filter(c=>c.aligned===!1).slice(0,5);if(d.length>0){console.log(`
|
|
76
|
+
Last ${d.length} misaligned action(s):`);for(const c of d){const r=typeof c.score=="number"?c.score.toFixed(2):"?",l=c.action??"?",f=c.primaryTarget??c.targets?.[0]??"?";console.log(` score: ${r} ${l} \u2192 ${f} (${c.timestamp.split("T")[0]})`)}}if(a.length>0){console.log(`
|
|
77
|
+
Recent drift findings: ${a.length}`);for(const c of a.slice(0,3)){const r=c.severity??"?",l=c.description??"";console.log(` [${r}] ${typeof l=="string"?l.slice(0,80):l}`)}}await n.close()}async function Ft(t,o){try{const n=await be({force:t,port:o});if(n.created.length>0){console.log("Created:");for(const e of n.created)console.log(` ${e}`)}if(n.skipped.length>0){console.log("Skipped (already exists \u2014 use --force to overwrite):");for(const e of n.skipped)console.log(` ${e}`)}if(n.merged.length>0){console.log("Merged:");for(const e of n.merged)console.log(` ${e}`)}if(n.errors.length>0){console.log("Errors:");for(const e of n.errors)console.log(` ${e}`)}n.errors.length===0&&console.log(`
|
|
78
|
+
Sentinel + Claude Code integration ready.`)}catch(n){console.error(`Init failed: ${n.message}`),process.exit(1)}}if(_e){const t=v(u,"--port");await Ft(Ge,t?parseInt(t,10):void 0)}else if(ot&&p&&Y&&X)await jt(p,Y,X);else if(st&&p)await Mt(p);else if(at&&p)await Rt(p);else if(it&&p)await Nt(p);else if(Be)await ue();else if(z)await fe(z);else if(ze&&p)await kt(p);else if(Ye&&p)await Tt(p);else if(Qe&&p)await Et(p);else if(Xe)await Ct();else if(Ze&&p)await rt(p,te??"No reason provided");else if(et&&p)await lt(p,te??"No reason provided");else if(tt)await gt(p);else if(nt)await ut();else if(We)await yt();else if(Ke)await bt(p);else if(Oe&&p&&Q)await ht(p,Q,qe);else if(He&&p)await mt(p);else if(Je){const t=T?parseInt(T,10):30;await St(t,ne==="json"?"json":"markdown")}else if(Ue&&p){const t=T?parseInt(T,10):30;await It(p,t,ne==="json"?"json":"markdown")}else if(Ve){const t=T?parseInt(T,10):30;await Dt(t)}else p?await pt(p):await ft();
|
package/dist/gateway/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { v as Sentinel, e as AgentRole, S as SecurityFinding } from '../Sentinel-
|
|
1
|
+
import { v as Sentinel, e as AgentRole, S as SecurityFinding } from '../Sentinel-CJJ4iYDh.js';
|
|
2
2
|
import 'node:crypto';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -75,6 +75,20 @@ interface SentinelGatewayOptions {
|
|
|
75
75
|
* Operator-only, same channel as unknownTools.
|
|
76
76
|
*/
|
|
77
77
|
allowUnknownTools?: string[];
|
|
78
|
+
/**
|
|
79
|
+
* Posture when the core enforcement call (sentinel.wrap()) throws an
|
|
80
|
+
* INTERNAL error during pre-tool-use screening. This is distinct from the
|
|
81
|
+
* hook script's tiered fail-closed, which only covers an UNREACHABLE
|
|
82
|
+
* gateway — here the gateway is reachable and must decide what a clean
|
|
83
|
+
* response says about an unscreened call. "fail-open" (default) allows it,
|
|
84
|
+
* preserving the pre-knob availability-over-security behavior; "fail-closed"
|
|
85
|
+
* is the hardened opt-in that blocks it. Either way an enforcement_error
|
|
86
|
+
* finding is persisted to the audit trail — observability is unconditional,
|
|
87
|
+
* only the allow/block decision is configurable. Operator-only, same
|
|
88
|
+
* channel as unknownTools (enforcement.onInternalError in the launch
|
|
89
|
+
* --policy yaml).
|
|
90
|
+
*/
|
|
91
|
+
onInternalError?: "fail-open" | "fail-closed";
|
|
78
92
|
/**
|
|
79
93
|
* Build identity reported via /health (daemon-staleness fix). Content hash of
|
|
80
94
|
* the daemon entry file this process was launched from; session-start compares
|
|
@@ -97,6 +111,8 @@ declare class SentinelGateway {
|
|
|
97
111
|
private readonly releaseToken;
|
|
98
112
|
/** Item D (F-8): disposition for unknown (non-MCP, unrecognized) tool names. */
|
|
99
113
|
private readonly unknownTools;
|
|
114
|
+
/** Posture for an internal wrap() error: allow (fail-open, default) or block. */
|
|
115
|
+
private readonly onInternalError;
|
|
100
116
|
/** Daemon-staleness build identity (content hash of the launched-from entry),
|
|
101
117
|
* reported via /health. "unknown" when not supplied by the launcher. */
|
|
102
118
|
private readonly buildId;
|
|
@@ -174,6 +190,15 @@ declare class SentinelGateway {
|
|
|
174
190
|
* when the isolation gate is ON.
|
|
175
191
|
*/
|
|
176
192
|
private resolveBPathRouting;
|
|
193
|
+
/**
|
|
194
|
+
* Forbidden-pattern list for ONE request: the gateway's construction-time
|
|
195
|
+
* list unioned with the request's merged-role patterns (operator-ceiling ∩
|
|
196
|
+
* workspace yaml). Without this, a workspace's custom forbid targets were
|
|
197
|
+
* enforced by the role validator inside wrap() but never reached the
|
|
198
|
+
* gateway's own bash-L1 / Grep layers, which checked only the static list.
|
|
199
|
+
* Normalization is idempotent (the chokepoint globstar-prepend).
|
|
200
|
+
*/
|
|
201
|
+
private patternsForRequest;
|
|
177
202
|
private handlePreToolUse;
|
|
178
203
|
private handlePostToolUse;
|
|
179
204
|
private handleSessionEnd;
|
package/dist/gateway/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SentinelGateway
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-3WT3K5TH.js";
|
|
4
4
|
import "../chunk-B5QKJHSV.js";
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
5
|
+
import "../chunk-B6S2PBS4.js";
|
|
6
|
+
import "../chunk-M5EEVMLU.js";
|
|
7
|
+
import "../chunk-SKE74CYZ.js";
|
|
8
8
|
export {
|
|
9
9
|
SentinelGateway
|
|
10
10
|
};
|
package/dist/gatewayDaemon.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runGatewayDaemon
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3WT3K5TH.js";
|
|
5
5
|
import {
|
|
6
6
|
computeBuildId,
|
|
7
7
|
runSessionStart
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-UVNRPML4.js";
|
|
9
9
|
import "./chunk-LATQNIRW.js";
|
|
10
10
|
import "./chunk-B5QKJHSV.js";
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-B6S2PBS4.js";
|
|
12
|
+
import "./chunk-M5EEVMLU.js";
|
|
13
|
+
import "./chunk-SKE74CYZ.js";
|
|
14
14
|
|
|
15
15
|
// src/gatewayDaemon.ts
|
|
16
16
|
import { fileURLToPath } from "url";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as AgentActivityEvent, S as SecurityFinding } from './Sentinel-
|
|
2
|
-
export { a as AcceptableAction, b as AdapterConfig, c as AgentBaseline, d as AgentMode, e as AgentRole, f as AlertChannel, g as AlertConfig, h as AllowResponse, i as AuditEntry, j as AuditQueryOptions, B as BlockResponse, C as CorrelationFinding, E as ExceptionApprovalContext, k as ExceptionApprovalFn, G as GuideResponse, H as HookCheckpoint, l as HookContext, m as HookHandler, n as HookRegistration, o as HookResponse, I as IntentAlignmentConfig, p as IntentAlignmentResult, M as ModifiableEventFields, q as MonitorOptions, O as OverlayDecisionType, R as RepoSensitivityMap, r as ReportOptions, s as RoleException, t as SecuritySeverity, u as SensitivityOverlay, v as Sentinel, w as SentinelConfig, T as TaskIntent } from './Sentinel-
|
|
1
|
+
import { A as AgentActivityEvent, S as SecurityFinding } from './Sentinel-CJJ4iYDh.js';
|
|
2
|
+
export { a as AcceptableAction, b as AdapterConfig, c as AgentBaseline, d as AgentMode, e as AgentRole, f as AlertChannel, g as AlertConfig, h as AllowResponse, i as AuditEntry, j as AuditQueryOptions, B as BlockResponse, C as CorrelationFinding, E as ExceptionApprovalContext, k as ExceptionApprovalFn, G as GuideResponse, H as HookCheckpoint, l as HookContext, m as HookHandler, n as HookRegistration, o as HookResponse, I as IntentAlignmentConfig, p as IntentAlignmentResult, M as ModifiableEventFields, q as MonitorOptions, O as OverlayDecisionType, R as RepoSensitivityMap, r as ReportOptions, s as RoleException, t as SecuritySeverity, u as SensitivityOverlay, v as Sentinel, w as SentinelConfig, T as TaskIntent } from './Sentinel-CJJ4iYDh.js';
|
|
3
3
|
import 'node:crypto';
|
|
4
4
|
|
|
5
5
|
interface SentinelPolicy {
|
|
@@ -35,17 +35,11 @@ interface SentinelPolicy {
|
|
|
35
35
|
hours: [number, number];
|
|
36
36
|
days?: string[];
|
|
37
37
|
};
|
|
38
|
-
limits?: {
|
|
39
|
-
maxEventsPerHour?: number;
|
|
40
|
-
maxSessionDuration?: number;
|
|
41
|
-
};
|
|
42
38
|
};
|
|
43
39
|
enforcement?: {
|
|
44
40
|
restrictAfter?: number;
|
|
45
41
|
quarantineAfter?: number;
|
|
46
42
|
approvalRequired?: boolean;
|
|
47
|
-
/** Minimum finding kind that triggers enforcement actions. Defaults to "actionable". */
|
|
48
|
-
minKind?: "informational" | "actionable";
|
|
49
43
|
/**
|
|
50
44
|
* List of finding types to promote from "informational" to "actionable".
|
|
51
45
|
* Cannot include LOCKED_ACTIONABLE_TYPES (they are already actionable).
|
|
@@ -66,6 +60,16 @@ interface SentinelPolicy {
|
|
|
66
60
|
unknownTools?: "deny" | "warn";
|
|
67
61
|
/** Item D escape hatch: native-shaped names to treat as known. */
|
|
68
62
|
allowUnknownTools?: string[];
|
|
63
|
+
/**
|
|
64
|
+
* Posture when the gateway's core enforcement call (sentinel.wrap())
|
|
65
|
+
* throws an INTERNAL error during pre-tool-use screening. "fail-open"
|
|
66
|
+
* (default) allows the unscreened call — availability over security,
|
|
67
|
+
* today's behavior; "fail-closed" is the hardened opt-in that blocks it.
|
|
68
|
+
* Either way the gateway persists an enforcement_error finding — only
|
|
69
|
+
* the allow/block decision is configurable, never the observability.
|
|
70
|
+
* Operator launch policy only — the gateway reads it once at start.
|
|
71
|
+
*/
|
|
72
|
+
onInternalError?: "fail-open" | "fail-closed";
|
|
69
73
|
};
|
|
70
74
|
alerts?: {
|
|
71
75
|
channels: (string | {
|
|
@@ -121,10 +125,6 @@ declare function runInitClaudeCode(options: {
|
|
|
121
125
|
home?: string;
|
|
122
126
|
}): Promise<InitReport>;
|
|
123
127
|
|
|
124
|
-
/**
|
|
125
|
-
* Walks up from a given directory looking for .sentinel.yaml.
|
|
126
|
-
* Stops at $HOME (inclusive) or filesystem root.
|
|
127
|
-
*/
|
|
128
128
|
declare function discoverPolicy(startDir: string, home: string): string | null;
|
|
129
129
|
|
|
130
130
|
/**
|
package/dist/index.js
CHANGED
|
@@ -2,20 +2,20 @@ import "./chunk-TKAKHSZ3.js";
|
|
|
2
2
|
import {
|
|
3
3
|
Sentinel,
|
|
4
4
|
createCliApproval
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-7R6EA7JG.js";
|
|
6
6
|
import {
|
|
7
7
|
runInitClaudeCode,
|
|
8
8
|
runSessionStart
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-UVNRPML4.js";
|
|
10
10
|
import "./chunk-LATQNIRW.js";
|
|
11
11
|
import {
|
|
12
12
|
discoverPolicy
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
} from "./chunk-B6S2PBS4.js";
|
|
14
|
+
import "./chunk-M5EEVMLU.js";
|
|
15
15
|
import {
|
|
16
16
|
loadPolicy,
|
|
17
17
|
loadPolicyFromString
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-SKE74CYZ.js";
|
|
19
19
|
import "./chunk-NUXSUSYY.js";
|
|
20
20
|
export {
|
|
21
21
|
Sentinel,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LogAdapter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2IPSTUNH.js";
|
|
4
4
|
|
|
5
5
|
// src/adapters/mcpAdapter.ts
|
|
6
6
|
var ACTION_MAP = {
|
|
@@ -175,4 +175,4 @@ export {
|
|
|
175
175
|
McpAdapter,
|
|
176
176
|
mapToolToAction
|
|
177
177
|
};
|
|
178
|
-
//# sourceMappingURL=mcpAdapter-
|
|
178
|
+
//# sourceMappingURL=mcpAdapter-WYAXUE7T.js.map
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LOCKED_ACTIONABLE_TYPES,
|
|
3
|
+
checkSaneNumber,
|
|
3
4
|
loadPolicy,
|
|
4
5
|
loadPolicyFromString,
|
|
5
6
|
policyToConfig,
|
|
6
|
-
policyToRole
|
|
7
|
-
|
|
7
|
+
policyToRole,
|
|
8
|
+
suggestKey
|
|
9
|
+
} from "./chunk-SKE74CYZ.js";
|
|
8
10
|
export {
|
|
9
11
|
LOCKED_ACTIONABLE_TYPES,
|
|
12
|
+
checkSaneNumber,
|
|
10
13
|
loadPolicy,
|
|
11
14
|
loadPolicyFromString,
|
|
12
15
|
policyToConfig,
|
|
13
|
-
policyToRole
|
|
16
|
+
policyToRole,
|
|
17
|
+
suggestKey
|
|
14
18
|
};
|
|
15
|
-
//# sourceMappingURL=policyLoader-
|
|
19
|
+
//# sourceMappingURL=policyLoader-NUPBBRKH.js.map
|
package/package.json
CHANGED
package/dist/chunk-FMZWHT4M.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// src/setup/policyDiscovery.ts
|
|
2
|
-
import { existsSync } from "fs";
|
|
3
|
-
import { resolve, join, dirname } from "path";
|
|
4
|
-
function discoverPolicy(startDir, home) {
|
|
5
|
-
let dir = resolve(startDir);
|
|
6
|
-
const homeAbs = resolve(home);
|
|
7
|
-
while (true) {
|
|
8
|
-
const candidate = join(dir, ".sentinel.yaml");
|
|
9
|
-
if (existsSync(candidate)) return candidate;
|
|
10
|
-
if (dir === homeAbs) return null;
|
|
11
|
-
const parent = dirname(dir);
|
|
12
|
-
if (parent === dir) return null;
|
|
13
|
-
dir = parent;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export {
|
|
18
|
-
discoverPolicy
|
|
19
|
-
};
|
|
20
|
-
//# sourceMappingURL=chunk-FMZWHT4M.js.map
|