@weave_protocol/adapter-msaf 0.1.0 → 0.2.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 +4 -2
- package/dist/middleware.d.ts +1 -0
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +22 -20
- package/dist/middleware.js.map +1 -1
- package/dist/policy.d.ts +8 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +20 -112
- package/dist/policy.js.map +1 -1
- package/dist/types.d.ts +9 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -88,8 +88,10 @@ When the middleware is constructed (or `weave-msaf status` runs), it looks in th
|
|
|
88
88
|
6. `<cwd>/.msaf/WARD.md`
|
|
89
89
|
|
|
90
90
|
First match wins. If nothing is found:
|
|
91
|
-
- Default (
|
|
92
|
-
- `failMode: 'closed'`: constructor throws
|
|
91
|
+
- Default (`failMode: 'open'`): every call is allowed, and a warning is logged
|
|
92
|
+
- `failMode: 'closed'`: the constructor throws
|
|
93
|
+
|
|
94
|
+
A policy that exists but is invalid, or an explicit `wardPath` that doesn't exist, always makes the constructor throw (since 0.2.0). Running without the policy you asked for would be a silent bypass.
|
|
93
95
|
|
|
94
96
|
---
|
|
95
97
|
|
package/dist/middleware.d.ts
CHANGED
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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;IACtD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAS;IAE9B,YAAY,IAAI,GAAE,iBAAsB,EA+BvC;IAED;;OAEG;IACH,QAAQ,IAAI,OAAO,CAElB;IAED;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED;;OAEG;IACH,SAAS,IAAI,UAAU,GAAG,IAAI,CAE7B;IAED;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,oBAAoB,CAMjD;IAED;;;;;;;;OAQG;IACH,kBAAkB,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAyB3F;IAED;;;;;;;;;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,CAMjG;IAED;;;OAGG;IACH,UAAU,IAAI,UAAU,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC,CAE7D;CACF"}
|
package/dist/middleware.js
CHANGED
|
@@ -49,33 +49,35 @@ export class WardMiddleware {
|
|
|
49
49
|
toolMappings;
|
|
50
50
|
onAllow;
|
|
51
51
|
onDeny;
|
|
52
|
+
cwd;
|
|
52
53
|
constructor(opts = {}) {
|
|
53
54
|
this.failClosed = opts.failMode === 'closed';
|
|
54
55
|
this.toolMappings = opts.toolMappings || {};
|
|
55
56
|
this.onAllow = opts.onAllow;
|
|
56
57
|
this.onDeny = opts.onDeny;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
this.resolved = resolveWardForCwd();
|
|
58
|
+
this.cwd = opts.cwd;
|
|
59
|
+
// A policy the caller named explicitly must load; never fall back to
|
|
60
|
+
// running without it.
|
|
61
|
+
if (opts.wardSource !== undefined) {
|
|
62
|
+
this.resolved = loadWardFromSource(opts.wardSource, '<inline>');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (opts.wardPath) {
|
|
66
|
+
if (!existsSync(opts.wardPath)) {
|
|
67
|
+
throw new Error(`WARD.md not found at ${opts.wardPath}`);
|
|
70
68
|
}
|
|
69
|
+
this.resolved = loadWardFromSource(readFileSync(opts.wardPath, 'utf8'), opts.wardPath);
|
|
70
|
+
return;
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
// An invalid WARD.md throws here whatever the fail mode: a typo must not
|
|
73
|
+
// silently switch enforcement off.
|
|
74
|
+
this.resolved = resolveWardForCwd(opts.cwd);
|
|
75
|
+
if (!this.resolved) {
|
|
76
|
+
if (this.failClosed) {
|
|
77
|
+
throw new Error('No WARD.md found ($WEAVE_WARD_PATH, WARD.md, .weave/WARD.md, .msaf/WARD.md) and failMode is closed');
|
|
78
|
+
}
|
|
76
79
|
// eslint-disable-next-line no-console
|
|
77
|
-
console.warn(
|
|
78
|
-
this.resolved = null;
|
|
80
|
+
console.warn('[weave-msaf] No WARD.md found. Running without a policy — no enforcement.');
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
/**
|
|
@@ -105,7 +107,7 @@ export class WardMiddleware {
|
|
|
105
107
|
if (!this.resolved) {
|
|
106
108
|
return { decision: 'allow', reasons: ['No WARD.md loaded'] };
|
|
107
109
|
}
|
|
108
|
-
const result = evaluateCall(this.resolved.policy, call, this.toolMappings);
|
|
110
|
+
const result = evaluateCall(this.resolved.policy, call, this.toolMappings, this.cwd);
|
|
109
111
|
return { ...result, policySource: this.resolved.source };
|
|
110
112
|
}
|
|
111
113
|
/**
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAInD,OAAO,EAKL,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,YAAY,EAAqB,MAAM,aAAa,CAAC;AAErG,+EAA+E;AAC/E,uBAAuB;AACvB,+EAA+E;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,cAAc;IACjB,QAAQ,CAAsB;IACrB,UAAU,CAAU;IACpB,YAAY,CAA8B;IAC1C,OAAO,CAAgC;IACvC,MAAM,CAA+B;
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/policy.d.ts
CHANGED
|
@@ -20,6 +20,13 @@ export interface ResolvedWard {
|
|
|
20
20
|
* 4. <cwd>/.msaf/WARD.md (MSAF convention if user puts config in .msaf/)
|
|
21
21
|
*/
|
|
22
22
|
export declare function resolveWardForCwd(cwd?: string): ResolvedWard | null;
|
|
23
|
+
/** Parse and validate a WARD.md; throws on an invalid policy. */
|
|
23
24
|
export declare function loadWardFromSource(source: string, label?: string): ResolvedWard;
|
|
24
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Decide a tool call with Ward's shared evaluator: the capability, every
|
|
27
|
+
* path and URL argument, and every URL and path in a shell command.
|
|
28
|
+
* (Before 0.2.0 this checked one field per tool and the first URL of a
|
|
29
|
+
* command; see WARD-2026-001.)
|
|
30
|
+
*/
|
|
31
|
+
export declare function evaluateCall(policy: WardPolicy, call: MsafToolCall, customMappings?: Record<string, ToolMapping>, cwd?: string): MsafMiddlewareResult;
|
|
25
32
|
//# sourceMappingURL=policy.d.ts.map
|
package/dist/policy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC3F,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,CAiBlF;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAa,GAAG,YAAY,CAMnF;AAMD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,YAAY,EAClB,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAM,EAChD,GAAG,GAAE,MAAsB,GAC1B,oBAAoB,CAOtB"}
|
package/dist/policy.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { readFileSync, existsSync } from 'node:fs';
|
|
10
10
|
import { join, resolve } from 'node:path';
|
|
11
|
-
import {
|
|
11
|
+
import { parseAndValidate, evaluateToolCall } from '@weave_protocol/ward';
|
|
12
12
|
import { TOOL_MAPPINGS, } from './types.js';
|
|
13
13
|
/**
|
|
14
14
|
* Find a WARD.md by walking the resolution order:
|
|
@@ -29,126 +29,34 @@ export function resolveWardForCwd(cwd = process.cwd()) {
|
|
|
29
29
|
for (const path of candidates) {
|
|
30
30
|
const resolved = resolve(path);
|
|
31
31
|
if (existsSync(resolved)) {
|
|
32
|
-
|
|
33
|
-
const policy = parseWard(source);
|
|
34
|
-
return { policy, source: resolved };
|
|
32
|
+
return loadWardFromSource(readFileSync(resolved, 'utf8'), resolved);
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
return null;
|
|
38
36
|
}
|
|
37
|
+
/** Parse and validate a WARD.md; throws on an invalid policy. */
|
|
39
38
|
export function loadWardFromSource(source, label = '<inline>') {
|
|
40
|
-
|
|
39
|
+
const result = parseAndValidate(source);
|
|
40
|
+
if (!result.valid || !result.policy) {
|
|
41
|
+
throw new Error(`Invalid WARD.md (${label}): ${result.errors.map((e) => e.message).join('; ')}`);
|
|
42
|
+
}
|
|
43
|
+
return { policy: result.policy, source: label };
|
|
41
44
|
}
|
|
42
45
|
// ============================================================================
|
|
43
46
|
// Evaluation
|
|
44
47
|
// ============================================================================
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
}
|
|
48
|
+
/**
|
|
49
|
+
* Decide a tool call with Ward's shared evaluator: the capability, every
|
|
50
|
+
* path and URL argument, and every URL and path in a shell command.
|
|
51
|
+
* (Before 0.2.0 this checked one field per tool and the first URL of a
|
|
52
|
+
* command; see WARD-2026-001.)
|
|
53
|
+
*/
|
|
54
|
+
export function evaluateCall(policy, call, customMappings = {}, cwd = process.cwd()) {
|
|
55
|
+
const { decision, reasons } = evaluateToolCall(policy, call.toolName, call.args, {
|
|
56
|
+
// Custom mappings win on conflict.
|
|
57
|
+
mappings: { ...TOOL_MAPPINGS, ...customMappings },
|
|
58
|
+
cwd,
|
|
59
|
+
});
|
|
98
60
|
return { decision, reasons };
|
|
99
61
|
}
|
|
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
62
|
//# sourceMappingURL=policy.js.map
|
package/dist/policy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAmB,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EACL,aAAa,GAId,MAAM,YAAY,CAAC;AAWpB;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,GAAW,OAAO,CAAC,GAAG,EAAE;IAC3D,MAAM,UAAU,GAAa,EAAE,CAAC;IAEhC,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe;QAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC9E,IAAI,GAAG,EAAE,CAAC;QACR,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;QACtC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;QAChD,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,OAAO,kBAAkB,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,KAAK,GAAG,UAAU;IACnE,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,oBAAoB,KAAK,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;AAClD,CAAC;AAED,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAkB,EAClB,IAAkB,EAClB,cAAc,GAAgC,EAAE,EAChD,GAAG,GAAW,OAAO,CAAC,GAAG,EAAE;IAE3B,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE;QAC/E,mCAAmC;QACnC,QAAQ,EAAE,EAAE,GAAG,aAAa,EAAE,GAAG,cAAc,EAAE;QACjD,GAAG;KACJ,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -77,11 +77,17 @@ export interface MiddlewareOptions {
|
|
|
77
77
|
*/
|
|
78
78
|
toolMappings?: Record<string, ToolMapping>;
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
81
|
-
* - 'open' (default):
|
|
82
|
-
* - 'closed':
|
|
80
|
+
* What to do when no WARD.md is configured or found anywhere:
|
|
81
|
+
* - 'open' (default): warn and run with no policy (every call allowed)
|
|
82
|
+
* - 'closed': throw from the constructor
|
|
83
|
+
*
|
|
84
|
+
* Since 0.2.0, a policy that exists but is invalid, or an explicit
|
|
85
|
+
* wardPath that doesn't exist, always throws: running without the policy
|
|
86
|
+
* you asked for would be a silent bypass.
|
|
83
87
|
*/
|
|
84
88
|
failMode?: 'open' | 'closed';
|
|
89
|
+
/** Working directory used to resolve relative paths. Default: process.cwd() */
|
|
90
|
+
cwd?: string;
|
|
85
91
|
/**
|
|
86
92
|
* Optional callback when a call is allowed. Useful for logging/attestation.
|
|
87
93
|
*/
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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;IAEjC,YACE,QAAQ,EAAE,MAAM,GAAG,kBAAkB,EACrC,OAAO,EAAE,MAAM,EAAE,EACjB,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,EAUtB;CACF;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;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAE7B,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@weave_protocol/adapter-msaf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Weave Protocol adapter for Microsoft Agent Framework - enforces WARD.md policies via the MSAF middleware pipeline",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"build": "tsc",
|
|
13
13
|
"dev": "tsc --watch",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
14
|
+
"prepublishOnly": "npm run build",
|
|
15
|
+
"test": "npm run build && node --test test/*.test.mjs"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"weave-protocol",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"url": "https://github.com/Tyox-all/Weave_Protocol/issues"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@weave_protocol/ward": "^0.
|
|
41
|
+
"@weave_protocol/ward": "^0.2.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/node": "^
|
|
45
|
-
"typescript": "^
|
|
44
|
+
"@types/node": "^26.6.6",
|
|
45
|
+
"typescript": "^7.0.2"
|
|
46
46
|
},
|
|
47
47
|
"engines": {
|
|
48
48
|
"node": ">=18.0.0"
|