watchmyagents 1.4.6 → 1.4.7
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/package.json +1 -1
- package/src/openai-agents.js +12 -1
- package/src/sources/openai-agents-js.js +28 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "watchmyagents",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.7",
|
|
4
4
|
"description": "Security observability + real-time policy enforcement for AI agents. Local-first NDJSON capture with a continuous Watch daemon that auto-uploads anonymized signals, Shield CLI that blocks policy violations live (with policies pulled from Fortress cloud), anonymizer producing signals-only payloads, bidirectional sync with WatchMyAgents Fortress, and one-command install as an always-on launchd/systemd service — closing the recursive Watch→Guardian→Shield security loop.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
package/src/openai-agents.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
attachWmaWatchToAgent,
|
|
41
41
|
adapterMeta,
|
|
42
42
|
} from './sources/openai-agents-js.js';
|
|
43
|
-
import { FortressPolicySource } from './shield/sources/fortress.js';
|
|
43
|
+
import { FortressPolicySource, postDecision } from './shield/sources/fortress.js';
|
|
44
44
|
import { resolveFortressBase } from './fortress/url.js';
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -101,6 +101,7 @@ export function openaiAgents(options = {}) {
|
|
|
101
101
|
// wma-shield gets its ruleset for Anthropic. Requires an agentId to scope
|
|
102
102
|
// the pull, a base URL (option or WMA_FORTRESS_BASE_URL), and WMA_API_KEY.
|
|
103
103
|
let fortressPolicySource = null;
|
|
104
|
+
let fortressDecisionSink = null;
|
|
104
105
|
if (options.policies && options.policies.source === 'fortress') {
|
|
105
106
|
if (!options.agentId) {
|
|
106
107
|
throw new Error(
|
|
@@ -132,6 +133,14 @@ export function openaiAgents(options = {}) {
|
|
|
132
133
|
requireSignedPolicies: options.policies.requireSignedPolicies,
|
|
133
134
|
failMode: options.policies.failMode,
|
|
134
135
|
});
|
|
136
|
+
|
|
137
|
+
// v1.4.7 (#1): ship decisions to the SAME Fortress (the control plane you
|
|
138
|
+
// pull policies from is where the decisions belong). Auto-on; opt out with
|
|
139
|
+
// policies.uploadDecisions === false to keep decisions local-only. The
|
|
140
|
+
// guardrail fires these best-effort, off its hot path.
|
|
141
|
+
if (options.policies.uploadDecisions !== false) {
|
|
142
|
+
fortressDecisionSink = (decision) => postDecision({ apiKey, base, decision });
|
|
143
|
+
}
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
// v1.4 Codex #2 — fail-loud refusal to start in enforce mode without
|
|
@@ -153,6 +162,8 @@ export function openaiAgents(options = {}) {
|
|
|
153
162
|
const sharedOptions = {
|
|
154
163
|
agentId: options.agentId, // v1.4.6: NDJSON path + native_agent_id
|
|
155
164
|
fortressPolicySource, // v1.4.6: live Fortress ruleset (or null)
|
|
165
|
+
fortressDecisionSink, // v1.4.7 #1: ship decisions (or null)
|
|
166
|
+
signalsSalt: options.signalsSalt || process.env.WMA_SIGNALS_SALT, // hash session/input
|
|
156
167
|
policiesPath: options.policiesPath,
|
|
157
168
|
ruleset: options.ruleset,
|
|
158
169
|
logDir: options.logDir,
|
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
import { evaluate, loadPolicies } from '../shield/policy.js';
|
|
55
55
|
import { createContextTracker } from '../shield/context.js';
|
|
56
56
|
import { DecisionLogger } from '../shield/decisions.js';
|
|
57
|
+
import { buildFortressDecisionPayload } from '../shield/upload.js';
|
|
57
58
|
import { Logger } from '../logger.js';
|
|
58
59
|
import { normalizeToolInput } from '../anonymizer.js';
|
|
59
60
|
|
|
@@ -632,6 +633,33 @@ export function wmaToolInputGuardrail(options = {}) {
|
|
|
632
633
|
enforcementDelivered: enforcedBlock ? true : undefined,
|
|
633
634
|
});
|
|
634
635
|
|
|
636
|
+
// 4b. v1.4.7 (#1): ship the decision to Fortress's ingest-decisions when
|
|
637
|
+
// a sink is configured. FIRE-AND-FORGET, off the guardrail's hot path —
|
|
638
|
+
// identical model to the Anthropic shield's fireToFortress(). The NDJSON
|
|
639
|
+
// row above is the durable local record; this live post is best-effort
|
|
640
|
+
// (a failure is swallowed, never blocks the tool call or crashes the
|
|
641
|
+
// guardrail). Payload is anonymized (hashes + decision/rule/provider) so
|
|
642
|
+
// Containment holds. Carries provider='openai-agents' + native_agent_id +
|
|
643
|
+
// enforcement_delivered (the v1.4.6 prereqs) so Fortress attributes it
|
|
644
|
+
// to the right runtime and surfaces degraded enforcement.
|
|
645
|
+
if (options.fortressDecisionSink) {
|
|
646
|
+
try {
|
|
647
|
+
const payload = buildFortressDecisionPayload({
|
|
648
|
+
agentId: loggerAgentId,
|
|
649
|
+
provider: PROVIDER,
|
|
650
|
+
nativeAgentId: loggerAgentId,
|
|
651
|
+
sessionId,
|
|
652
|
+
rawEvent: event,
|
|
653
|
+
normalized: event,
|
|
654
|
+
result,
|
|
655
|
+
decidedInMs,
|
|
656
|
+
signalsSalt: options.signalsSalt,
|
|
657
|
+
enforcementDelivered: enforcedBlock ? true : undefined,
|
|
658
|
+
});
|
|
659
|
+
Promise.resolve(options.fortressDecisionSink(payload)).catch(() => undefined);
|
|
660
|
+
} catch { /* payload build must never break enforcement */ }
|
|
661
|
+
}
|
|
662
|
+
|
|
635
663
|
// 5. Watch log (the event itself, separate from the decision).
|
|
636
664
|
await logger.write(event);
|
|
637
665
|
|