@weave_protocol/adapter-msaf 0.1.0
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/README.md +277 -0
- package/SKILL.md +102 -0
- package/dist/cli.d.ts +16 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +260 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +96 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +164 -0
- package/dist/middleware.js.map +1 -0
- package/dist/policy.d.ts +25 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +154 -0
- package/dist/policy.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +58 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @weave_protocol/adapter-msaf — public API
|
|
3
|
+
*
|
|
4
|
+
* Primary export: WardMiddleware class.
|
|
5
|
+
* Plus: types, policy loader, evaluator.
|
|
6
|
+
*/
|
|
7
|
+
export { WardMiddleware } from './middleware.js';
|
|
8
|
+
export { TOOL_MAPPINGS, WardDeniedError, } from './types.js';
|
|
9
|
+
export type { ToolMapping, MsafToolCall, MsafMiddlewareResult, MiddlewareOptions, } from './types.js';
|
|
10
|
+
export { resolveWardForCwd, loadWardFromSource, evaluateCall, } from './policy.js';
|
|
11
|
+
export type { ResolvedWard } from './policy.js';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EACV,WAAW,EACX,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @weave_protocol/adapter-msaf — public API
|
|
3
|
+
*
|
|
4
|
+
* Primary export: WardMiddleware class.
|
|
5
|
+
* Plus: types, policy loader, evaluator.
|
|
6
|
+
*/
|
|
7
|
+
export { WardMiddleware } from './middleware.js';
|
|
8
|
+
export { TOOL_MAPPINGS, WardDeniedError, } from './types.js';
|
|
9
|
+
export { resolveWardForCwd, loadWardFromSource, evaluateCall, } from './policy.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EACL,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC;AAOpB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,GACb,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARD middleware for the Microsoft Agent Framework.
|
|
3
|
+
*
|
|
4
|
+
* MSAF exposes three middleware types; we provide adapters for two of them:
|
|
5
|
+
*
|
|
6
|
+
* 1. Function middleware — gates individual tool calls. This is the primary
|
|
7
|
+
* WARD enforcement layer. Use `.functionMiddleware()`.
|
|
8
|
+
*
|
|
9
|
+
* 2. Agent middleware — gates whole agent turns. Wraps the entire run.
|
|
10
|
+
* Use `.agentMiddleware()`. Less granular than function middleware but
|
|
11
|
+
* useful for behavioral-limit checks (max iterations, max cost) and
|
|
12
|
+
* for adding session-scoped logging.
|
|
13
|
+
*
|
|
14
|
+
* The user is responsible for registering the returned function with their
|
|
15
|
+
* MSAF agent / chat client. We don't reach into MSAF's internals.
|
|
16
|
+
*
|
|
17
|
+
* Why we don't ship a direct MSAF SDK dependency:
|
|
18
|
+
* MSAF's primary surface is .NET. The Node/TS bindings are evolving and
|
|
19
|
+
* we don't want to pin a specific 1.0.0-rc version. Instead, we expose
|
|
20
|
+
* middleware FUNCTIONS that match MSAF's documented `pre_invoke` and
|
|
21
|
+
* `agent_middleware` signatures. The user wires them in.
|
|
22
|
+
*/
|
|
23
|
+
import { type WardPolicy } from '@weave_protocol/ward';
|
|
24
|
+
import { type MsafToolCall, type MsafMiddlewareResult, type MiddlewareOptions } from './types.js';
|
|
25
|
+
/**
|
|
26
|
+
* The primary entry point. Construct one, register the returned middleware
|
|
27
|
+
* functions with your MSAF agent.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* import { WardMiddleware } from '@weave_protocol/adapter-msaf';
|
|
32
|
+
*
|
|
33
|
+
* const ward = new WardMiddleware({ wardPath: './WARD.md' });
|
|
34
|
+
*
|
|
35
|
+
* // For per-tool gating (primary use):
|
|
36
|
+
* agent.useFunctionMiddleware(ward.functionMiddleware());
|
|
37
|
+
*
|
|
38
|
+
* // For turn-level gating (optional, complementary):
|
|
39
|
+
* agent.useAgentMiddleware(ward.agentMiddleware());
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class WardMiddleware {
|
|
43
|
+
private resolved;
|
|
44
|
+
private readonly failClosed;
|
|
45
|
+
private readonly toolMappings;
|
|
46
|
+
private readonly onAllow?;
|
|
47
|
+
private readonly onDeny?;
|
|
48
|
+
constructor(opts?: MiddlewareOptions);
|
|
49
|
+
/**
|
|
50
|
+
* Returns true if a WARD policy is loaded.
|
|
51
|
+
*/
|
|
52
|
+
isLoaded(): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* The active WARD policy source path (or '<inline>'), if loaded.
|
|
55
|
+
*/
|
|
56
|
+
getPolicySource(): string | null;
|
|
57
|
+
/**
|
|
58
|
+
* The parsed WARD policy object, if loaded.
|
|
59
|
+
*/
|
|
60
|
+
getPolicy(): WardPolicy | null;
|
|
61
|
+
/**
|
|
62
|
+
* Evaluate a tool call against the loaded policy. Pure function — does
|
|
63
|
+
* not throw. Useful for testing and for users who want to run the check
|
|
64
|
+
* manually without going through middleware.
|
|
65
|
+
*/
|
|
66
|
+
evaluate(call: MsafToolCall): MsafMiddlewareResult;
|
|
67
|
+
/**
|
|
68
|
+
* Returns a function middleware compatible with MSAF's function-middleware
|
|
69
|
+
* pre_invoke shape. The returned function:
|
|
70
|
+
* - calls next() if the call is allowed
|
|
71
|
+
* - throws WardDeniedError if the call is denied or requires approval
|
|
72
|
+
*
|
|
73
|
+
* Usage:
|
|
74
|
+
* agent.useFunctionMiddleware(ward.functionMiddleware());
|
|
75
|
+
*/
|
|
76
|
+
functionMiddleware(): (call: MsafToolCall, next: () => Promise<unknown>) => Promise<unknown>;
|
|
77
|
+
/**
|
|
78
|
+
* Returns an agent middleware compatible with MSAF's agent middleware
|
|
79
|
+
* shape. This fires once per turn before any LLM call.
|
|
80
|
+
*
|
|
81
|
+
* The agent middleware is informational only by default — it doesn't gate
|
|
82
|
+
* individual tool calls (that's what functionMiddleware is for). It exists
|
|
83
|
+
* so users who want a turn-level hook (for logging or session tracking)
|
|
84
|
+
* can register one. To enforce behavioral limits (cost, iterations) at the
|
|
85
|
+
* turn level, subclass or wrap this.
|
|
86
|
+
*/
|
|
87
|
+
agentMiddleware(): (ctx: {
|
|
88
|
+
turnIndex?: number;
|
|
89
|
+
}, next: () => Promise<unknown>) => Promise<unknown>;
|
|
90
|
+
/**
|
|
91
|
+
* Backward-compatible: alias for functionMiddleware().
|
|
92
|
+
* MSAF's terminology evolved; we keep both spellings.
|
|
93
|
+
*/
|
|
94
|
+
middleware(): ReturnType<WardMiddleware['functionMiddleware']>;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,KAAK,UAAU,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,EAGvB,MAAM,YAAY,CAAC;AAOpB;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA8B;IAC3D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA8B;gBAE1C,IAAI,GAAE,iBAAsB;IA6BxC;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC;;OAEG;IACH,SAAS,IAAI,UAAU,GAAG,IAAI;IAI9B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,oBAAoB;IAQlD;;;;;;;;OAQG;IACH,kBAAkB,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;IA2B5F;;;;;;;;;OASG;IACH,eAAe,IAAI,CAAC,GAAG,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;IAQlG;;;OAGG;IACH,UAAU,IAAI,UAAU,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;CAG/D"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARD middleware for the Microsoft Agent Framework.
|
|
3
|
+
*
|
|
4
|
+
* MSAF exposes three middleware types; we provide adapters for two of them:
|
|
5
|
+
*
|
|
6
|
+
* 1. Function middleware — gates individual tool calls. This is the primary
|
|
7
|
+
* WARD enforcement layer. Use `.functionMiddleware()`.
|
|
8
|
+
*
|
|
9
|
+
* 2. Agent middleware — gates whole agent turns. Wraps the entire run.
|
|
10
|
+
* Use `.agentMiddleware()`. Less granular than function middleware but
|
|
11
|
+
* useful for behavioral-limit checks (max iterations, max cost) and
|
|
12
|
+
* for adding session-scoped logging.
|
|
13
|
+
*
|
|
14
|
+
* The user is responsible for registering the returned function with their
|
|
15
|
+
* MSAF agent / chat client. We don't reach into MSAF's internals.
|
|
16
|
+
*
|
|
17
|
+
* Why we don't ship a direct MSAF SDK dependency:
|
|
18
|
+
* MSAF's primary surface is .NET. The Node/TS bindings are evolving and
|
|
19
|
+
* we don't want to pin a specific 1.0.0-rc version. Instead, we expose
|
|
20
|
+
* middleware FUNCTIONS that match MSAF's documented `pre_invoke` and
|
|
21
|
+
* `agent_middleware` signatures. The user wires them in.
|
|
22
|
+
*/
|
|
23
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
24
|
+
import { WardDeniedError, } from './types.js';
|
|
25
|
+
import { resolveWardForCwd, loadWardFromSource, evaluateCall } from './policy.js';
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// WardMiddleware class
|
|
28
|
+
// ============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* The primary entry point. Construct one, register the returned middleware
|
|
31
|
+
* functions with your MSAF agent.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* import { WardMiddleware } from '@weave_protocol/adapter-msaf';
|
|
36
|
+
*
|
|
37
|
+
* const ward = new WardMiddleware({ wardPath: './WARD.md' });
|
|
38
|
+
*
|
|
39
|
+
* // For per-tool gating (primary use):
|
|
40
|
+
* agent.useFunctionMiddleware(ward.functionMiddleware());
|
|
41
|
+
*
|
|
42
|
+
* // For turn-level gating (optional, complementary):
|
|
43
|
+
* agent.useAgentMiddleware(ward.agentMiddleware());
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export class WardMiddleware {
|
|
47
|
+
resolved;
|
|
48
|
+
failClosed;
|
|
49
|
+
toolMappings;
|
|
50
|
+
onAllow;
|
|
51
|
+
onDeny;
|
|
52
|
+
constructor(opts = {}) {
|
|
53
|
+
this.failClosed = opts.failMode === 'closed';
|
|
54
|
+
this.toolMappings = opts.toolMappings || {};
|
|
55
|
+
this.onAllow = opts.onAllow;
|
|
56
|
+
this.onDeny = opts.onDeny;
|
|
57
|
+
try {
|
|
58
|
+
if (opts.wardSource) {
|
|
59
|
+
this.resolved = loadWardFromSource(opts.wardSource, '<inline>');
|
|
60
|
+
}
|
|
61
|
+
else if (opts.wardPath) {
|
|
62
|
+
if (!existsSync(opts.wardPath)) {
|
|
63
|
+
throw new Error(`WARD.md not found at ${opts.wardPath}`);
|
|
64
|
+
}
|
|
65
|
+
const src = readFileSync(opts.wardPath, 'utf8');
|
|
66
|
+
this.resolved = loadWardFromSource(src, opts.wardPath);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
this.resolved = resolveWardForCwd();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
if (this.failClosed)
|
|
74
|
+
throw err;
|
|
75
|
+
// Fail-open: log and continue with no policy (every call allowed)
|
|
76
|
+
// eslint-disable-next-line no-console
|
|
77
|
+
console.warn(`[weave-msaf] WARD.md could not be loaded (${err instanceof Error ? err.message : String(err)}). Running in fail-open mode — no enforcement.`);
|
|
78
|
+
this.resolved = null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Returns true if a WARD policy is loaded.
|
|
83
|
+
*/
|
|
84
|
+
isLoaded() {
|
|
85
|
+
return this.resolved !== null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The active WARD policy source path (or '<inline>'), if loaded.
|
|
89
|
+
*/
|
|
90
|
+
getPolicySource() {
|
|
91
|
+
return this.resolved?.source ?? null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The parsed WARD policy object, if loaded.
|
|
95
|
+
*/
|
|
96
|
+
getPolicy() {
|
|
97
|
+
return this.resolved?.policy ?? null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Evaluate a tool call against the loaded policy. Pure function — does
|
|
101
|
+
* not throw. Useful for testing and for users who want to run the check
|
|
102
|
+
* manually without going through middleware.
|
|
103
|
+
*/
|
|
104
|
+
evaluate(call) {
|
|
105
|
+
if (!this.resolved) {
|
|
106
|
+
return { decision: 'allow', reasons: ['No WARD.md loaded'] };
|
|
107
|
+
}
|
|
108
|
+
const result = evaluateCall(this.resolved.policy, call, this.toolMappings);
|
|
109
|
+
return { ...result, policySource: this.resolved.source };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns a function middleware compatible with MSAF's function-middleware
|
|
113
|
+
* pre_invoke shape. The returned function:
|
|
114
|
+
* - calls next() if the call is allowed
|
|
115
|
+
* - throws WardDeniedError if the call is denied or requires approval
|
|
116
|
+
*
|
|
117
|
+
* Usage:
|
|
118
|
+
* agent.useFunctionMiddleware(ward.functionMiddleware());
|
|
119
|
+
*/
|
|
120
|
+
functionMiddleware() {
|
|
121
|
+
return async (call, next) => {
|
|
122
|
+
const result = this.evaluate(call);
|
|
123
|
+
if (result.decision === 'allow') {
|
|
124
|
+
if (this.onAllow)
|
|
125
|
+
await this.onAllow(call, result);
|
|
126
|
+
return next();
|
|
127
|
+
}
|
|
128
|
+
// Denied or requires approval
|
|
129
|
+
if (this.onDeny) {
|
|
130
|
+
const override = await this.onDeny(call, result);
|
|
131
|
+
if (override === true) {
|
|
132
|
+
// User explicitly overrode the WARD decision
|
|
133
|
+
return next();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw new WardDeniedError(result.decision === 'deny' ? 'deny' : 'require_approval', result.reasons, call.toolName, result.policySource);
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Returns an agent middleware compatible with MSAF's agent middleware
|
|
141
|
+
* shape. This fires once per turn before any LLM call.
|
|
142
|
+
*
|
|
143
|
+
* The agent middleware is informational only by default — it doesn't gate
|
|
144
|
+
* individual tool calls (that's what functionMiddleware is for). It exists
|
|
145
|
+
* so users who want a turn-level hook (for logging or session tracking)
|
|
146
|
+
* can register one. To enforce behavioral limits (cost, iterations) at the
|
|
147
|
+
* turn level, subclass or wrap this.
|
|
148
|
+
*/
|
|
149
|
+
agentMiddleware() {
|
|
150
|
+
return async (ctx, next) => {
|
|
151
|
+
// For now, agent middleware is pass-through; future versions can add
|
|
152
|
+
// iteration-counter / cost-tracking enforcement here.
|
|
153
|
+
return next();
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Backward-compatible: alias for functionMiddleware().
|
|
158
|
+
* MSAF's terminology evolved; we keep both spellings.
|
|
159
|
+
*/
|
|
160
|
+
middleware() {
|
|
161
|
+
return this.functionMiddleware();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARD policy loading + evaluation for MSAF middleware.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the Claude Code / Antigravity adapters which read WARD on every
|
|
5
|
+
* hook invocation (because they're spawned as subprocesses), MSAF middleware
|
|
6
|
+
* runs in-process. We load WARD once at middleware construction time and
|
|
7
|
+
* keep the parsed policy in memory for the lifetime of the agent run.
|
|
8
|
+
*/
|
|
9
|
+
import { type WardPolicy } from '@weave_protocol/ward';
|
|
10
|
+
import { type ToolMapping, type MsafToolCall, type MsafMiddlewareResult } from './types.js';
|
|
11
|
+
export interface ResolvedWard {
|
|
12
|
+
policy: WardPolicy;
|
|
13
|
+
source: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Find a WARD.md by walking the resolution order:
|
|
17
|
+
* 1. $WEAVE_WARD_PATH if set
|
|
18
|
+
* 2. <cwd>/WARD.md
|
|
19
|
+
* 3. <cwd>/.weave/WARD.md
|
|
20
|
+
* 4. <cwd>/.msaf/WARD.md (MSAF convention if user puts config in .msaf/)
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveWardForCwd(cwd?: string): ResolvedWard | null;
|
|
23
|
+
export declare function loadWardFromSource(source: string, label?: string): ResolvedWard;
|
|
24
|
+
export declare function evaluateCall(policy: WardPolicy, call: MsafToolCall, customMappings?: Record<string, ToolMapping>): MsafMiddlewareResult;
|
|
25
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAKL,KAAK,UAAU,EAEhB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,YAAY,GAAG,IAAI,CAmBlF;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAa,GAAG,YAAY,CAEnF;AAMD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,YAAY,EAClB,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAM,GAC/C,oBAAoB,CA6DtB"}
|
package/dist/policy.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARD policy loading + evaluation for MSAF middleware.
|
|
3
|
+
*
|
|
4
|
+
* Unlike the Claude Code / Antigravity adapters which read WARD on every
|
|
5
|
+
* hook invocation (because they're spawned as subprocesses), MSAF middleware
|
|
6
|
+
* runs in-process. We load WARD once at middleware construction time and
|
|
7
|
+
* keep the parsed policy in memory for the lifetime of the agent run.
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
10
|
+
import { join, resolve } from 'node:path';
|
|
11
|
+
import { parseWard, checkCapability, checkFilesystem, checkNetwork, } from '@weave_protocol/ward';
|
|
12
|
+
import { TOOL_MAPPINGS, } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Find a WARD.md by walking the resolution order:
|
|
15
|
+
* 1. $WEAVE_WARD_PATH if set
|
|
16
|
+
* 2. <cwd>/WARD.md
|
|
17
|
+
* 3. <cwd>/.weave/WARD.md
|
|
18
|
+
* 4. <cwd>/.msaf/WARD.md (MSAF convention if user puts config in .msaf/)
|
|
19
|
+
*/
|
|
20
|
+
export function resolveWardForCwd(cwd = process.cwd()) {
|
|
21
|
+
const candidates = [];
|
|
22
|
+
if (process.env.WEAVE_WARD_PATH)
|
|
23
|
+
candidates.push(process.env.WEAVE_WARD_PATH);
|
|
24
|
+
if (cwd) {
|
|
25
|
+
candidates.push(join(cwd, 'WARD.md'));
|
|
26
|
+
candidates.push(join(cwd, '.weave', 'WARD.md'));
|
|
27
|
+
candidates.push(join(cwd, '.msaf', 'WARD.md'));
|
|
28
|
+
}
|
|
29
|
+
for (const path of candidates) {
|
|
30
|
+
const resolved = resolve(path);
|
|
31
|
+
if (existsSync(resolved)) {
|
|
32
|
+
const source = readFileSync(resolved, 'utf8');
|
|
33
|
+
const policy = parseWard(source);
|
|
34
|
+
return { policy, source: resolved };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
export function loadWardFromSource(source, label = '<inline>') {
|
|
40
|
+
return { policy: parseWard(source), source: label };
|
|
41
|
+
}
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Evaluation
|
|
44
|
+
// ============================================================================
|
|
45
|
+
export function evaluateCall(policy, call, customMappings = {}) {
|
|
46
|
+
const reasons = [];
|
|
47
|
+
let decision = 'allow';
|
|
48
|
+
// Merge built-in + custom mappings; custom wins on conflict.
|
|
49
|
+
const mapping = customMappings[call.toolName] || TOOL_MAPPINGS[call.toolName] || { capability: call.toolName };
|
|
50
|
+
// 1. Capability check (mapped name + raw name, stricter explicit wins)
|
|
51
|
+
const capByMapping = checkCapability(policy, mapping.capability);
|
|
52
|
+
const capByRaw = checkCapability(policy, call.toolName);
|
|
53
|
+
const cap = mergeCapability(capByMapping, capByRaw);
|
|
54
|
+
if (cap.decision === 'deny') {
|
|
55
|
+
return { decision: 'deny', reasons: [cap.reason] };
|
|
56
|
+
}
|
|
57
|
+
if (cap.decision === 'require_approval') {
|
|
58
|
+
decision = 'require_approval';
|
|
59
|
+
reasons.push(cap.reason);
|
|
60
|
+
}
|
|
61
|
+
// 2. Filesystem check
|
|
62
|
+
if (mapping.pathField && call.args && typeof call.args[mapping.pathField] === 'string') {
|
|
63
|
+
const path = call.args[mapping.pathField];
|
|
64
|
+
const fs = checkFilesystem(policy, mapping.fsOp || 'read', path);
|
|
65
|
+
if (fs.decision === 'deny') {
|
|
66
|
+
return { decision: 'deny', reasons: [fs.reason] };
|
|
67
|
+
}
|
|
68
|
+
if (fs.decision === 'require_approval' && decision !== 'require_approval') {
|
|
69
|
+
decision = 'require_approval';
|
|
70
|
+
reasons.push(fs.reason);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 3. Network check
|
|
74
|
+
if (mapping.urlField && call.args && typeof call.args[mapping.urlField] === 'string') {
|
|
75
|
+
const url = call.args[mapping.urlField];
|
|
76
|
+
const method = call.args.method || 'GET';
|
|
77
|
+
const net = checkNetwork(policy, url, method);
|
|
78
|
+
if (net.decision === 'deny') {
|
|
79
|
+
return { decision: 'deny', reasons: [net.reason] };
|
|
80
|
+
}
|
|
81
|
+
if (net.decision === 'require_approval' && decision !== 'require_approval') {
|
|
82
|
+
decision = 'require_approval';
|
|
83
|
+
reasons.push(net.reason);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 4. Bash command heuristic
|
|
87
|
+
if (mapping.commandField && call.args && typeof call.args[mapping.commandField] === 'string') {
|
|
88
|
+
const command = call.args[mapping.commandField];
|
|
89
|
+
const bashCheck = scanBashCommand(policy, command);
|
|
90
|
+
if (bashCheck.decision === 'deny') {
|
|
91
|
+
return { decision: 'deny', reasons: [bashCheck.reason] };
|
|
92
|
+
}
|
|
93
|
+
if (bashCheck.decision === 'require_approval' && decision !== 'require_approval') {
|
|
94
|
+
decision = 'require_approval';
|
|
95
|
+
reasons.push(bashCheck.reason);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return { decision, reasons };
|
|
99
|
+
}
|
|
100
|
+
function isExplicit(reason) {
|
|
101
|
+
return (reason.includes('is in the allow list') ||
|
|
102
|
+
reason.includes('is in the deny list') ||
|
|
103
|
+
reason.includes('requires human approval'));
|
|
104
|
+
}
|
|
105
|
+
function mergeCapability(a, b) {
|
|
106
|
+
const aExp = isExplicit(a.reason);
|
|
107
|
+
const bExp = isExplicit(b.reason);
|
|
108
|
+
if (aExp && !bExp)
|
|
109
|
+
return a;
|
|
110
|
+
if (bExp && !aExp)
|
|
111
|
+
return b;
|
|
112
|
+
if (a.decision === 'deny' || b.decision === 'deny') {
|
|
113
|
+
return a.decision === 'deny' ? a : b;
|
|
114
|
+
}
|
|
115
|
+
if (a.decision === 'require_approval' || b.decision === 'require_approval') {
|
|
116
|
+
return a.decision === 'require_approval' ? a : b;
|
|
117
|
+
}
|
|
118
|
+
return a;
|
|
119
|
+
}
|
|
120
|
+
function scanBashCommand(policy, command) {
|
|
121
|
+
const urlMatch = command.match(/https?:\/\/[^\s'"`)]+/);
|
|
122
|
+
if (urlMatch) {
|
|
123
|
+
const net = checkNetwork(policy, urlMatch[0], 'GET');
|
|
124
|
+
if (net.decision === 'deny')
|
|
125
|
+
return { decision: 'deny', reason: `bash command targets ${urlMatch[0]}: ${net.reason}` };
|
|
126
|
+
if (net.decision === 'require_approval')
|
|
127
|
+
return { decision: 'require_approval', reason: `bash command targets ${urlMatch[0]}: ${net.reason}` };
|
|
128
|
+
}
|
|
129
|
+
const dangerousPaths = [
|
|
130
|
+
'~/.ssh',
|
|
131
|
+
'~/.aws',
|
|
132
|
+
'~/.config/gcloud',
|
|
133
|
+
'~/.azure', // Azure credentials (relevant for MSAF users)
|
|
134
|
+
'/etc/',
|
|
135
|
+
'/usr/',
|
|
136
|
+
'/.env',
|
|
137
|
+
];
|
|
138
|
+
for (const danger of dangerousPaths) {
|
|
139
|
+
if (command.includes(danger)) {
|
|
140
|
+
let op = 'read';
|
|
141
|
+
if (/(?:^|[\s;|])rm\s/.test(command))
|
|
142
|
+
op = 'delete';
|
|
143
|
+
else if (/>|>>|tee|sed -i/.test(command))
|
|
144
|
+
op = 'write';
|
|
145
|
+
const fs = checkFilesystem(policy, op, danger + (danger.endsWith('/') ? '**' : ''));
|
|
146
|
+
if (fs.decision === 'deny')
|
|
147
|
+
return { decision: 'deny', reason: `bash touches ${danger}: ${fs.reason}` };
|
|
148
|
+
if (fs.decision === 'require_approval')
|
|
149
|
+
return { decision: 'require_approval', reason: `bash touches ${danger}: ${fs.reason}` };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { decision: 'allow', reason: '' };
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the Microsoft Agent Framework adapter.
|
|
3
|
+
*
|
|
4
|
+
* MSAF supports three middleware types (per the v1.0 docs):
|
|
5
|
+
* 1. Agent middleware — wraps full agent runs (once per turn)
|
|
6
|
+
* 2. Function middleware — wraps individual tool calls
|
|
7
|
+
* 3. Chat middleware — wraps raw model requests
|
|
8
|
+
*
|
|
9
|
+
* For WARD enforcement we primarily care about function middleware
|
|
10
|
+
* (since WARD gates tool calls), but we also expose an agent-middleware
|
|
11
|
+
* variant for users who want a turn-level gate.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* A proposed function/tool call that MSAF is about to execute.
|
|
15
|
+
* Shape mirrors what MSAF's function middleware exposes via its context.
|
|
16
|
+
*/
|
|
17
|
+
export interface MsafToolCall {
|
|
18
|
+
toolName: string;
|
|
19
|
+
args: Record<string, unknown>;
|
|
20
|
+
raw?: unknown;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Result of a WARD evaluation for an MSAF middleware.
|
|
24
|
+
*/
|
|
25
|
+
export interface MsafMiddlewareResult {
|
|
26
|
+
decision: 'allow' | 'deny' | 'require_approval';
|
|
27
|
+
reasons: string[];
|
|
28
|
+
policySource?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Standardized error thrown by the middleware when a call is denied.
|
|
32
|
+
* MSAF middleware short-circuits by throwing (or by not calling next()),
|
|
33
|
+
* so we provide a typed error so users can catch and handle it.
|
|
34
|
+
*/
|
|
35
|
+
export declare class WardDeniedError extends Error {
|
|
36
|
+
readonly decision: 'deny' | 'require_approval';
|
|
37
|
+
readonly reasons: string[];
|
|
38
|
+
readonly policySource: string | undefined;
|
|
39
|
+
readonly toolName: string;
|
|
40
|
+
constructor(decision: 'deny' | 'require_approval', reasons: string[], toolName: string, policySource?: string);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Mapping from MSAF tool names to their nature.
|
|
44
|
+
*
|
|
45
|
+
* MSAF tools are user-defined, but several conventions are widely
|
|
46
|
+
* established (especially through the Copilot/Claude Code SDK harness
|
|
47
|
+
* integrations and the local agent runtime which exposes shell/file/
|
|
48
|
+
* messaging tools). The mappings below cover those well-known names.
|
|
49
|
+
*
|
|
50
|
+
* Users can also register custom mappings via MiddlewareOptions.toolMappings.
|
|
51
|
+
*/
|
|
52
|
+
export interface ToolMapping {
|
|
53
|
+
capability: string;
|
|
54
|
+
pathField?: string;
|
|
55
|
+
fsOp?: 'read' | 'write' | 'execute' | 'delete' | 'list';
|
|
56
|
+
urlField?: string;
|
|
57
|
+
commandField?: string;
|
|
58
|
+
}
|
|
59
|
+
export declare const TOOL_MAPPINGS: Record<string, ToolMapping>;
|
|
60
|
+
/**
|
|
61
|
+
* Options when creating a WardMiddleware instance.
|
|
62
|
+
*/
|
|
63
|
+
export interface MiddlewareOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Explicit path to a WARD.md file. If omitted, resolves via:
|
|
66
|
+
* $WEAVE_WARD_PATH → <cwd>/WARD.md → <cwd>/.weave/WARD.md → <cwd>/.msaf/WARD.md
|
|
67
|
+
*/
|
|
68
|
+
wardPath?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Raw WARD.md content (alternative to wardPath). Useful for tests or
|
|
71
|
+
* embedding the policy in code.
|
|
72
|
+
*/
|
|
73
|
+
wardSource?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Custom tool name → capability mappings. Merged on top of the built-in
|
|
76
|
+
* TOOL_MAPPINGS so users can override or add.
|
|
77
|
+
*/
|
|
78
|
+
toolMappings?: Record<string, ToolMapping>;
|
|
79
|
+
/**
|
|
80
|
+
* Fail mode:
|
|
81
|
+
* - 'open' (default): if WARD can't be loaded, allow the call and warn
|
|
82
|
+
* - 'closed': if WARD can't be loaded, deny the call
|
|
83
|
+
*/
|
|
84
|
+
failMode?: 'open' | 'closed';
|
|
85
|
+
/**
|
|
86
|
+
* Optional callback when a call is allowed. Useful for logging/attestation.
|
|
87
|
+
*/
|
|
88
|
+
onAllow?: (call: MsafToolCall, result: MsafMiddlewareResult) => void | Promise<void>;
|
|
89
|
+
/**
|
|
90
|
+
* Optional callback when a call is denied. Useful for alerting.
|
|
91
|
+
* If you return false, the call is allowed despite the WARD decision.
|
|
92
|
+
* (Generally don't do that — but it's available for emergency overrides.)
|
|
93
|
+
*/
|
|
94
|
+
onDeny?: (call: MsafToolCall, result: MsafMiddlewareResult) => boolean | void | Promise<boolean | void>;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,kBAAkB,CAAC;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAgB,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACtD,SAAgB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClC,SAAgB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,SAAgB,QAAQ,EAAE,MAAM,CAAC;gBAG/B,QAAQ,EAAE,MAAM,GAAG,kBAAkB,EACrC,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM;CAWxB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CA4BrD,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAE3C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAE7B;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAErF;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,oBAAoB,KAAK,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;CACzG"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the Microsoft Agent Framework adapter.
|
|
3
|
+
*
|
|
4
|
+
* MSAF supports three middleware types (per the v1.0 docs):
|
|
5
|
+
* 1. Agent middleware — wraps full agent runs (once per turn)
|
|
6
|
+
* 2. Function middleware — wraps individual tool calls
|
|
7
|
+
* 3. Chat middleware — wraps raw model requests
|
|
8
|
+
*
|
|
9
|
+
* For WARD enforcement we primarily care about function middleware
|
|
10
|
+
* (since WARD gates tool calls), but we also expose an agent-middleware
|
|
11
|
+
* variant for users who want a turn-level gate.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Standardized error thrown by the middleware when a call is denied.
|
|
15
|
+
* MSAF middleware short-circuits by throwing (or by not calling next()),
|
|
16
|
+
* so we provide a typed error so users can catch and handle it.
|
|
17
|
+
*/
|
|
18
|
+
export class WardDeniedError extends Error {
|
|
19
|
+
decision;
|
|
20
|
+
reasons;
|
|
21
|
+
policySource;
|
|
22
|
+
toolName;
|
|
23
|
+
constructor(decision, reasons, toolName, policySource) {
|
|
24
|
+
super(`WARD ${decision === 'deny' ? 'denied' : 'requires approval for'} tool '${toolName}': ${reasons.join(' | ')}`);
|
|
25
|
+
this.name = 'WardDeniedError';
|
|
26
|
+
this.decision = decision;
|
|
27
|
+
this.reasons = reasons;
|
|
28
|
+
this.policySource = policySource;
|
|
29
|
+
this.toolName = toolName;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export const TOOL_MAPPINGS = {
|
|
33
|
+
// MSAF local agent runtime tools
|
|
34
|
+
ShellExec: { capability: 'shell_exec', commandField: 'command' },
|
|
35
|
+
Bash: { capability: 'shell_exec', commandField: 'command' },
|
|
36
|
+
FileRead: { capability: 'file_read', pathField: 'path', fsOp: 'read' },
|
|
37
|
+
FileWrite: { capability: 'file_write', pathField: 'path', fsOp: 'write' },
|
|
38
|
+
FileEdit: { capability: 'file_write', pathField: 'path', fsOp: 'write' },
|
|
39
|
+
FileDelete: { capability: 'file_delete', pathField: 'path', fsOp: 'delete' },
|
|
40
|
+
ListDirectory: { capability: 'file_list', pathField: 'path', fsOp: 'list' },
|
|
41
|
+
HttpRequest: { capability: 'http_request', urlField: 'url' },
|
|
42
|
+
WebFetch: { capability: 'http_request', urlField: 'url' },
|
|
43
|
+
// Copilot SDK integration patterns
|
|
44
|
+
RunCommand: { capability: 'shell_exec', commandField: 'command' },
|
|
45
|
+
EditFile: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
|
|
46
|
+
ReadFile: { capability: 'file_read', pathField: 'file_path', fsOp: 'read' },
|
|
47
|
+
// Claude Code SDK integration (via MSAF) - share with adapter-claudecode names
|
|
48
|
+
Bash_via_claude: { capability: 'shell_exec', commandField: 'command' },
|
|
49
|
+
Edit: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
|
|
50
|
+
Write: { capability: 'file_write', pathField: 'file_path', fsOp: 'write' },
|
|
51
|
+
Read: { capability: 'file_read', pathField: 'file_path', fsOp: 'read' },
|
|
52
|
+
// Common workflow/automation tools
|
|
53
|
+
SendEmail: { capability: 'send_email' },
|
|
54
|
+
PostMessage: { capability: 'send_message' },
|
|
55
|
+
CreateIssue: { capability: 'create_issue' },
|
|
56
|
+
Subagent: { capability: 'subagent' },
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=types.js.map
|