@siteverb/audit 0.1.0-rc.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 +19 -0
- package/dist/audit.d.ts +3 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +140 -0
- package/dist/audit.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/source-scan.d.ts +9 -0
- package/dist/source-scan.d.ts.map +1 -0
- package/dist/source-scan.js +477 -0
- package/dist/source-scan.js.map +1 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @siteverb/audit
|
|
2
|
+
|
|
3
|
+
Static source-to-contract coverage for Siteverb WebMCP projects.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npx @siteverb/audit --root . --contract siteverb.webmcp.json --output .siteverb/audit.json
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The audit uses Babel's TypeScript parser for JavaScript/TypeScript/JSX/TSX and executable scripts in
|
|
10
|
+
HTML, Vue, and Svelte files. `parse5` extracts declarative forms without regular expressions. It
|
|
11
|
+
understands definitions, inline client registrations, static batches, and local static factories.
|
|
12
|
+
|
|
13
|
+
It blocks raw `document.modelContext.registerTool` calls, state-changing declarative autosubmit,
|
|
14
|
+
unsafe cross-origin exposure, duplicate stable IDs or wire names, contract/source drift, and missing
|
|
15
|
+
contract entries. Dynamic `exposedTo` policy and known third-party registration runtimes require
|
|
16
|
+
review; third-party runtimes become errors under `--strict-external`.
|
|
17
|
+
|
|
18
|
+
Static coverage does not prove runtime behavior. Pair this audit with `@siteverb/runner` in the
|
|
19
|
+
customer-owned GitHub Action.
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAgB,mBAAmB,EAAE,WAAW,EAAc,MAAM,YAAY,CAAC;AAmC7F,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,WAAW,CAAC,CAqHrF"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { isAbsolute, relative, resolve } from 'node:path';
|
|
3
|
+
import { parseProjectContract } from '@siteverb/contracts';
|
|
4
|
+
import { scanProjectSources } from './source-scan.js';
|
|
5
|
+
function duplicateFindings(tools) {
|
|
6
|
+
const findings = [];
|
|
7
|
+
for (const field of ['id', 'name']) {
|
|
8
|
+
const seen = new Map();
|
|
9
|
+
for (const tool of tools) {
|
|
10
|
+
const value = tool[field];
|
|
11
|
+
if (!value)
|
|
12
|
+
continue;
|
|
13
|
+
const previous = seen.get(value);
|
|
14
|
+
if (previous) {
|
|
15
|
+
if (field === 'name' &&
|
|
16
|
+
previous.owner === 'declarative' &&
|
|
17
|
+
tool.owner === 'declarative' &&
|
|
18
|
+
previous.file !== tool.file) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
findings.push({
|
|
22
|
+
code: field === 'id' ? 'duplicate-stable-id' : 'duplicate-wire-name',
|
|
23
|
+
file: tool.file,
|
|
24
|
+
line: tool.line,
|
|
25
|
+
column: tool.column,
|
|
26
|
+
message: `Duplicate source tool ${field} "${value}".`,
|
|
27
|
+
severity: 'error',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
seen.set(value, tool);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return findings;
|
|
36
|
+
}
|
|
37
|
+
export async function auditProject(options) {
|
|
38
|
+
const root = resolve(options.root);
|
|
39
|
+
const contractPath = resolve(root, options.contractPath);
|
|
40
|
+
const relativeContractPath = relative(root, contractPath);
|
|
41
|
+
if (relativeContractPath === '..' ||
|
|
42
|
+
relativeContractPath.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) ||
|
|
43
|
+
isAbsolute(relativeContractPath)) {
|
|
44
|
+
throw new TypeError('The contract must be inside the audited project root.');
|
|
45
|
+
}
|
|
46
|
+
const contract = parseProjectContract(JSON.parse(await readFile(contractPath, 'utf8')));
|
|
47
|
+
const source = await scanProjectSources(root);
|
|
48
|
+
const findings = [
|
|
49
|
+
...source.findings.map((finding) => options.strictExternal && finding.code === 'external-registration-runtime'
|
|
50
|
+
? { ...finding, severity: 'error' }
|
|
51
|
+
: finding),
|
|
52
|
+
...duplicateFindings(source.tools),
|
|
53
|
+
];
|
|
54
|
+
const sourceById = new Map(source.tools.filter((tool) => tool.id).map((tool) => [tool.id, tool]));
|
|
55
|
+
for (const tool of contract.tools) {
|
|
56
|
+
if (tool.registration === 'declarative') {
|
|
57
|
+
const implementations = source.tools.filter((candidate) => candidate.owner === 'declarative' && candidate.name === tool.name);
|
|
58
|
+
if (implementations.length === 0) {
|
|
59
|
+
findings.push({
|
|
60
|
+
code: 'contract-tool-missing-source',
|
|
61
|
+
file: relativeContractPath,
|
|
62
|
+
message: `Declarative contract tool "${tool.id}" has no matching form toolname.`,
|
|
63
|
+
severity: 'error',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
for (const implementation of implementations) {
|
|
67
|
+
if (implementation.autoSubmit && tool.risk !== 'read-only') {
|
|
68
|
+
findings.push({
|
|
69
|
+
code: 'unsafe-declarative-autosubmit',
|
|
70
|
+
file: implementation.file,
|
|
71
|
+
line: implementation.line,
|
|
72
|
+
column: implementation.column,
|
|
73
|
+
message: `State-changing declarative tool "${tool.id}" cannot use toolautosubmit.`,
|
|
74
|
+
severity: 'error',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const implementation = sourceById.get(tool.id);
|
|
81
|
+
if (!implementation) {
|
|
82
|
+
findings.push({
|
|
83
|
+
code: 'contract-tool-missing-source',
|
|
84
|
+
file: relativeContractPath,
|
|
85
|
+
message: `Contract tool "${tool.id}" has no static Siteverb definition in source.`,
|
|
86
|
+
severity: 'error',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else if (implementation.name !== tool.name) {
|
|
90
|
+
findings.push({
|
|
91
|
+
code: 'contract-name-mismatch',
|
|
92
|
+
file: implementation.file,
|
|
93
|
+
line: implementation.line,
|
|
94
|
+
column: implementation.column,
|
|
95
|
+
message: `Source name "${implementation.name ?? 'unknown'}" does not match contract name "${tool.name}" for "${tool.id}".`,
|
|
96
|
+
severity: 'error',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const contractIds = new Set(contract.tools.map((tool) => tool.id));
|
|
101
|
+
const contractDeclarativeNames = new Set(contract.tools.filter((tool) => tool.registration === 'declarative').map((tool) => tool.name));
|
|
102
|
+
for (const tool of source.tools) {
|
|
103
|
+
if (tool.owner === 'siteverb' && tool.id && !contractIds.has(tool.id)) {
|
|
104
|
+
findings.push({
|
|
105
|
+
code: 'source-tool-missing-contract',
|
|
106
|
+
file: tool.file,
|
|
107
|
+
line: tool.line,
|
|
108
|
+
column: tool.column,
|
|
109
|
+
message: `Source tool "${tool.id}" is missing from the portable contract.`,
|
|
110
|
+
severity: 'error',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
if (tool.owner === 'declarative' && tool.name && !contractDeclarativeNames.has(tool.name)) {
|
|
114
|
+
findings.push({
|
|
115
|
+
code: 'source-tool-missing-contract',
|
|
116
|
+
file: tool.file,
|
|
117
|
+
line: tool.line,
|
|
118
|
+
column: tool.column,
|
|
119
|
+
message: `Declarative source tool "${tool.name}" is missing from the portable contract.`,
|
|
120
|
+
severity: 'error',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
findings.sort((left, right) => `${left.file}:${left.line ?? 0}:${left.code}`.localeCompare(`${right.file}:${right.line ?? 0}:${right.code}`));
|
|
125
|
+
return {
|
|
126
|
+
version: 1,
|
|
127
|
+
root: '.',
|
|
128
|
+
contract: relativeContractPath,
|
|
129
|
+
summary: {
|
|
130
|
+
errors: findings.filter((finding) => finding.severity === 'error').length,
|
|
131
|
+
warnings: findings.filter((finding) => finding.severity === 'warning').length,
|
|
132
|
+
filesScanned: source.filesScanned,
|
|
133
|
+
sourceTools: source.tools.length,
|
|
134
|
+
contractTools: contract.tools.length,
|
|
135
|
+
},
|
|
136
|
+
tools: source.tools,
|
|
137
|
+
findings,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import { parseArgs } from 'node:util';
|
|
5
|
+
import { auditProject } from './audit.js';
|
|
6
|
+
const HELP = `Usage: siteverb-audit [options]
|
|
7
|
+
|
|
8
|
+
Options:
|
|
9
|
+
--root <path> Project root (default: current directory)
|
|
10
|
+
--contract <path> Contract relative to root (default: siteverb.webmcp.json)
|
|
11
|
+
--output <path> Optional JSON report path relative to root
|
|
12
|
+
--strict-external Treat known third-party registration runtimes as errors
|
|
13
|
+
--help Show this message
|
|
14
|
+
`;
|
|
15
|
+
const { values } = parseArgs({
|
|
16
|
+
options: {
|
|
17
|
+
root: { type: 'string', default: '.' },
|
|
18
|
+
contract: { type: 'string', default: 'siteverb.webmcp.json' },
|
|
19
|
+
output: { type: 'string' },
|
|
20
|
+
'strict-external': { type: 'boolean', default: false },
|
|
21
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
22
|
+
},
|
|
23
|
+
strict: true,
|
|
24
|
+
});
|
|
25
|
+
if (values.help) {
|
|
26
|
+
process.stdout.write(HELP);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const root = resolve(values.root);
|
|
31
|
+
const report = await auditProject({
|
|
32
|
+
root,
|
|
33
|
+
contractPath: values.contract,
|
|
34
|
+
strictExternal: values['strict-external'],
|
|
35
|
+
});
|
|
36
|
+
for (const finding of report.findings) {
|
|
37
|
+
const location = finding.line ? `:${finding.line}:${finding.column ?? 1}` : '';
|
|
38
|
+
process.stdout.write(`${finding.severity.toUpperCase()} ${finding.code} ${finding.file}${location} ${finding.message}\n`);
|
|
39
|
+
}
|
|
40
|
+
process.stdout.write(`Siteverb audit: ${report.summary.errors} errors, ${report.summary.warnings} warnings, ${report.summary.sourceTools}/${report.summary.contractTools} source/contract tools\n`);
|
|
41
|
+
if (values.output) {
|
|
42
|
+
const output = resolve(root, values.output);
|
|
43
|
+
await mkdir(dirname(output), { recursive: true });
|
|
44
|
+
await writeFile(output, `${JSON.stringify(report, null, 2)}\n`);
|
|
45
|
+
}
|
|
46
|
+
process.exitCode = report.summary.errors > 0 ? 1 : 0;
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
process.stderr.write(`Siteverb audit failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
50
|
+
process.exitCode = 2;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,YAAY,EACV,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AuditFinding, SourceTool } from './types.js';
|
|
2
|
+
interface ScanResult {
|
|
3
|
+
filesScanned: number;
|
|
4
|
+
readonly findings: AuditFinding[];
|
|
5
|
+
readonly tools: SourceTool[];
|
|
6
|
+
}
|
|
7
|
+
export declare function scanProjectSources(root: string, limit?: number): Promise<ScanResult>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=source-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-scan.d.ts","sourceRoot":"","sources":["../src/source-scan.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAyB3D,UAAU,UAAU;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC;CAC9B;AA6dD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAc1F"}
|
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
+
import { relative, resolve } from 'node:path';
|
|
3
|
+
import { parse as parseJavaScript } from '@babel/parser';
|
|
4
|
+
import { parse } from 'parse5';
|
|
5
|
+
const ignoredDirectories = new Set([
|
|
6
|
+
'.git',
|
|
7
|
+
'.next',
|
|
8
|
+
'.output',
|
|
9
|
+
'.siteverb',
|
|
10
|
+
'.svelte-kit',
|
|
11
|
+
'coverage',
|
|
12
|
+
'dist',
|
|
13
|
+
'node_modules',
|
|
14
|
+
]);
|
|
15
|
+
const sourceExtension = /\.(?:[cm]?[jt]sx?)$/i;
|
|
16
|
+
const htmlExtension = /\.(?:html?|astro)$/i;
|
|
17
|
+
const componentExtension = /\.(?:vue|svelte)$/i;
|
|
18
|
+
const externalRuntimes = new Set([
|
|
19
|
+
'@nekuda/webmcp-sdk',
|
|
20
|
+
'@nekuda/webmcp',
|
|
21
|
+
'@agentlane/webmcp',
|
|
22
|
+
'usewebmcp',
|
|
23
|
+
'use-webmcp-tool',
|
|
24
|
+
'@mcp-b/react-webmcp',
|
|
25
|
+
'@mcp-b/webmcp-ts-sdk',
|
|
26
|
+
]);
|
|
27
|
+
function location(node, lineOffset = 0) {
|
|
28
|
+
return {
|
|
29
|
+
line: (node.loc?.start.line ?? 1) + lineOffset,
|
|
30
|
+
column: (node.loc?.start.column ?? 0) + 1,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function literalProperty(object, name) {
|
|
34
|
+
const property = object.properties.find((candidate) => candidate.type === 'ObjectProperty' &&
|
|
35
|
+
((candidate.key.type === 'Identifier' && candidate.key.name === name) ||
|
|
36
|
+
(candidate.key.type === 'StringLiteral' && candidate.key.value === name)));
|
|
37
|
+
return property?.type === 'ObjectProperty' && property.value.type === 'StringLiteral'
|
|
38
|
+
? property.value.value
|
|
39
|
+
: undefined;
|
|
40
|
+
}
|
|
41
|
+
function propertyValue(object, name) {
|
|
42
|
+
const property = object.properties.find((candidate) => candidate.type === 'ObjectProperty' &&
|
|
43
|
+
((candidate.key.type === 'Identifier' && candidate.key.name === name) ||
|
|
44
|
+
(candidate.key.type === 'StringLiteral' && candidate.key.value === name)));
|
|
45
|
+
return property?.type === 'ObjectProperty' ? property.value : undefined;
|
|
46
|
+
}
|
|
47
|
+
function callName(call) {
|
|
48
|
+
return call.callee.type === 'Identifier' ? call.callee.name : undefined;
|
|
49
|
+
}
|
|
50
|
+
function memberPath(node) {
|
|
51
|
+
if (!node)
|
|
52
|
+
return undefined;
|
|
53
|
+
if (node.type === 'Identifier')
|
|
54
|
+
return node.name;
|
|
55
|
+
if (node.type !== 'MemberExpression' && node.type !== 'OptionalMemberExpression')
|
|
56
|
+
return undefined;
|
|
57
|
+
const object = memberPath(node.object);
|
|
58
|
+
const property = !node.computed && node.property.type === 'Identifier'
|
|
59
|
+
? node.property.name
|
|
60
|
+
: node.computed && node.property.type === 'StringLiteral'
|
|
61
|
+
? node.property.value
|
|
62
|
+
: undefined;
|
|
63
|
+
return object && property ? `${object}.${property}` : undefined;
|
|
64
|
+
}
|
|
65
|
+
function walk(node, visit) {
|
|
66
|
+
visit(node);
|
|
67
|
+
for (const value of Object.values(node)) {
|
|
68
|
+
if (Array.isArray(value)) {
|
|
69
|
+
for (const entry of value) {
|
|
70
|
+
if (entry && typeof entry === 'object' && typeof entry.type === 'string') {
|
|
71
|
+
walk(entry, visit);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (value && typeof value === 'object' && typeof value.type === 'string') {
|
|
76
|
+
walk(value, visit);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function isExternalRuntime(moduleName) {
|
|
81
|
+
return externalRuntimes.has(moduleName) || moduleName.startsWith('@mcp-b/');
|
|
82
|
+
}
|
|
83
|
+
function isExternalRuntimeReference(reference) {
|
|
84
|
+
return /(?:@mcp-b\/|@nekuda\/webmcp|@agentlane\/webmcp|usewebmcp|(?:^|\/)latch(?:@|\/|\.|$))/i.test(reference);
|
|
85
|
+
}
|
|
86
|
+
function unwrapExpression(node) {
|
|
87
|
+
if (!node)
|
|
88
|
+
return undefined;
|
|
89
|
+
if (node.type === 'TSAsExpression' ||
|
|
90
|
+
node.type === 'TSSatisfiesExpression' ||
|
|
91
|
+
node.type === 'TypeCastExpression' ||
|
|
92
|
+
node.type === 'TSNonNullExpression' ||
|
|
93
|
+
node.type === 'ParenthesizedExpression') {
|
|
94
|
+
return unwrapExpression(node.expression);
|
|
95
|
+
}
|
|
96
|
+
return node;
|
|
97
|
+
}
|
|
98
|
+
function returnedExpression(node) {
|
|
99
|
+
if (node.type === 'ArrowFunctionExpression' && node.body.type !== 'BlockStatement') {
|
|
100
|
+
return unwrapExpression(node.body);
|
|
101
|
+
}
|
|
102
|
+
const body = node.type === 'FunctionDeclaration' ||
|
|
103
|
+
node.type === 'FunctionExpression' ||
|
|
104
|
+
node.type === 'ArrowFunctionExpression'
|
|
105
|
+
? node.body
|
|
106
|
+
: undefined;
|
|
107
|
+
if (!body || body.type !== 'BlockStatement')
|
|
108
|
+
return undefined;
|
|
109
|
+
const returns = body.body.filter((statement) => statement.type === 'ReturnStatement');
|
|
110
|
+
return returns.length === 1 ? unwrapExpression(returns[0]?.argument) : undefined;
|
|
111
|
+
}
|
|
112
|
+
function scanSource(path, root, sourceText, lineOffset = 0) {
|
|
113
|
+
const file = relative(root, path);
|
|
114
|
+
const findings = [];
|
|
115
|
+
const tools = [];
|
|
116
|
+
let source;
|
|
117
|
+
try {
|
|
118
|
+
source = parseJavaScript(sourceText, {
|
|
119
|
+
sourceType: 'unambiguous',
|
|
120
|
+
sourceFilename: path,
|
|
121
|
+
plugins: ['jsx', 'typescript', 'decorators-legacy', 'importAttributes'],
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return {
|
|
126
|
+
filesScanned: 1,
|
|
127
|
+
findings: [
|
|
128
|
+
{
|
|
129
|
+
code: 'source-parse-failed',
|
|
130
|
+
file,
|
|
131
|
+
line: lineOffset + 1,
|
|
132
|
+
message: 'Source could not be parsed for static WebMCP ownership coverage.',
|
|
133
|
+
severity: 'warning',
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
tools,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const toolDefinitionFunctions = new Set();
|
|
140
|
+
const siteverbClientFactories = new Set();
|
|
141
|
+
const siteverbNamespaces = new Set();
|
|
142
|
+
for (const statement of source.program.body) {
|
|
143
|
+
if (statement.type !== 'ImportDeclaration')
|
|
144
|
+
continue;
|
|
145
|
+
const moduleName = statement.source.value;
|
|
146
|
+
if (isExternalRuntime(moduleName)) {
|
|
147
|
+
findings.push({
|
|
148
|
+
code: 'external-registration-runtime',
|
|
149
|
+
file,
|
|
150
|
+
...location(statement, lineOffset),
|
|
151
|
+
message: `External WebMCP registration runtime "${moduleName}" requires an explicit coexistence or migration decision.`,
|
|
152
|
+
severity: 'warning',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (moduleName !== '@siteverb/webmcp' && moduleName !== '@siteverb/react')
|
|
156
|
+
continue;
|
|
157
|
+
for (const specifier of statement.specifiers) {
|
|
158
|
+
if (specifier.type === 'ImportNamespaceSpecifier') {
|
|
159
|
+
siteverbNamespaces.add(specifier.local.name);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (specifier.type !== 'ImportSpecifier')
|
|
163
|
+
continue;
|
|
164
|
+
const imported = specifier.imported.type === 'Identifier'
|
|
165
|
+
? specifier.imported.name
|
|
166
|
+
: specifier.imported.value;
|
|
167
|
+
if (imported === 'defineTool' ||
|
|
168
|
+
imported === 'useSiteverbTool' ||
|
|
169
|
+
imported === 'useSiteverbTools') {
|
|
170
|
+
toolDefinitionFunctions.add(specifier.local.name);
|
|
171
|
+
}
|
|
172
|
+
if (moduleName === '@siteverb/webmcp' && imported === 'createSiteverb') {
|
|
173
|
+
siteverbClientFactories.add(specifier.local.name);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const staticValues = new Map();
|
|
178
|
+
const staticFactories = new Map();
|
|
179
|
+
const siteverbClients = new Set();
|
|
180
|
+
const addedToolObjects = new Set();
|
|
181
|
+
const isSiteverbFactory = (call) => {
|
|
182
|
+
const name = callName(call);
|
|
183
|
+
const path = memberPath(call.callee);
|
|
184
|
+
return Boolean((name && siteverbClientFactories.has(name)) ||
|
|
185
|
+
(path && [...siteverbNamespaces].some((namespace) => path === `${namespace}.createSiteverb`)));
|
|
186
|
+
};
|
|
187
|
+
const isToolDefinitionCall = (call) => {
|
|
188
|
+
const name = callName(call);
|
|
189
|
+
const path = memberPath(call.callee);
|
|
190
|
+
return Boolean((name && toolDefinitionFunctions.has(name)) ||
|
|
191
|
+
(path &&
|
|
192
|
+
[...siteverbNamespaces].some((namespace) => path === `${namespace}.defineTool` || path === `${namespace}.useSiteverbTool`)));
|
|
193
|
+
};
|
|
194
|
+
walk(source.program, (node) => {
|
|
195
|
+
if (node.type === 'VariableDeclarator' && node.id.type === 'Identifier' && node.init) {
|
|
196
|
+
staticValues.set(node.id.name, node.init);
|
|
197
|
+
if (node.init.type === 'CallExpression' && isSiteverbFactory(node.init)) {
|
|
198
|
+
siteverbClients.add(node.id.name);
|
|
199
|
+
}
|
|
200
|
+
if (node.init.type === 'FunctionExpression' || node.init.type === 'ArrowFunctionExpression') {
|
|
201
|
+
staticFactories.set(node.id.name, node.init);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (node.type === 'FunctionDeclaration' && node.id) {
|
|
205
|
+
staticFactories.set(node.id.name, node);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const resolveToolObjects = (node, seen = new Set()) => {
|
|
209
|
+
const value = unwrapExpression(node);
|
|
210
|
+
if (!value)
|
|
211
|
+
return [];
|
|
212
|
+
if (value.type === 'ObjectExpression')
|
|
213
|
+
return [value];
|
|
214
|
+
if (value.type === 'ArrayExpression') {
|
|
215
|
+
return value.elements.flatMap((element) => element && element.type !== 'SpreadElement'
|
|
216
|
+
? resolveToolObjects(element, new Set(seen))
|
|
217
|
+
: []);
|
|
218
|
+
}
|
|
219
|
+
if (value.type === 'Identifier') {
|
|
220
|
+
if (seen.has(value.name))
|
|
221
|
+
return [];
|
|
222
|
+
seen.add(value.name);
|
|
223
|
+
return resolveToolObjects(staticValues.get(value.name), seen);
|
|
224
|
+
}
|
|
225
|
+
if (value.type === 'CallExpression') {
|
|
226
|
+
if (isToolDefinitionCall(value)) {
|
|
227
|
+
const first = value.arguments[0];
|
|
228
|
+
return first && first.type !== 'SpreadElement' ? resolveToolObjects(first, seen) : [];
|
|
229
|
+
}
|
|
230
|
+
const factoryName = callName(value);
|
|
231
|
+
if (!factoryName || seen.has(factoryName))
|
|
232
|
+
return [];
|
|
233
|
+
const factory = staticFactories.get(factoryName);
|
|
234
|
+
if (!factory)
|
|
235
|
+
return [];
|
|
236
|
+
seen.add(factoryName);
|
|
237
|
+
return resolveToolObjects(returnedExpression(factory), seen);
|
|
238
|
+
}
|
|
239
|
+
return [];
|
|
240
|
+
};
|
|
241
|
+
const addTool = (object) => {
|
|
242
|
+
if (addedToolObjects.has(object))
|
|
243
|
+
return;
|
|
244
|
+
addedToolObjects.add(object);
|
|
245
|
+
const position = location(object, lineOffset);
|
|
246
|
+
const id = literalProperty(object, 'id');
|
|
247
|
+
const wireName = literalProperty(object, 'name');
|
|
248
|
+
tools.push({
|
|
249
|
+
file,
|
|
250
|
+
...position,
|
|
251
|
+
...(id ? { id } : {}),
|
|
252
|
+
...(wireName ? { name: wireName } : {}),
|
|
253
|
+
owner: 'siteverb',
|
|
254
|
+
});
|
|
255
|
+
if (!id || !wireName) {
|
|
256
|
+
findings.push({
|
|
257
|
+
code: 'dynamic-tool-metadata',
|
|
258
|
+
file,
|
|
259
|
+
...position,
|
|
260
|
+
message: 'Siteverb tool id and name must be static string literals for source coverage.',
|
|
261
|
+
severity: 'warning',
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
const staticObject = (node) => {
|
|
266
|
+
const value = unwrapExpression(node);
|
|
267
|
+
if (!value)
|
|
268
|
+
return undefined;
|
|
269
|
+
if (value.type === 'ObjectExpression')
|
|
270
|
+
return value;
|
|
271
|
+
if (value.type !== 'Identifier')
|
|
272
|
+
return undefined;
|
|
273
|
+
const resolved = unwrapExpression(staticValues.get(value.name));
|
|
274
|
+
return resolved?.type === 'ObjectExpression' ? resolved : undefined;
|
|
275
|
+
};
|
|
276
|
+
const isSafeExposureOrigin = (value) => {
|
|
277
|
+
try {
|
|
278
|
+
const url = new URL(value);
|
|
279
|
+
const isLoopback = url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '[::1]';
|
|
280
|
+
return (url.origin === value &&
|
|
281
|
+
(url.protocol === 'https:' || (url.protocol === 'http:' && isLoopback)));
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
const inspectExposure = (call) => {
|
|
288
|
+
const optionsArgument = call.arguments[1];
|
|
289
|
+
const options = optionsArgument && optionsArgument.type !== 'SpreadElement'
|
|
290
|
+
? staticObject(optionsArgument)
|
|
291
|
+
: undefined;
|
|
292
|
+
if (!options) {
|
|
293
|
+
if (optionsArgument) {
|
|
294
|
+
findings.push({
|
|
295
|
+
code: 'dynamic-origin-exposure',
|
|
296
|
+
file,
|
|
297
|
+
...location(call, lineOffset),
|
|
298
|
+
message: 'Dynamic Siteverb registration options require manual exposedTo review.',
|
|
299
|
+
severity: 'warning',
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const exposedTo = propertyValue(options, 'exposedTo');
|
|
305
|
+
if (!exposedTo)
|
|
306
|
+
return;
|
|
307
|
+
const resolved = unwrapExpression(exposedTo.type === 'Identifier' ? staticValues.get(exposedTo.name) : exposedTo);
|
|
308
|
+
if (resolved?.type !== 'ArrayExpression' ||
|
|
309
|
+
resolved.elements.some((element) => element?.type !== 'StringLiteral')) {
|
|
310
|
+
findings.push({
|
|
311
|
+
code: 'dynamic-origin-exposure',
|
|
312
|
+
file,
|
|
313
|
+
...location(exposedTo, lineOffset),
|
|
314
|
+
message: 'Siteverb exposedTo must use reviewed static origin literals for source coverage.',
|
|
315
|
+
severity: 'warning',
|
|
316
|
+
});
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
for (const element of resolved.elements) {
|
|
320
|
+
if (element?.type !== 'StringLiteral' || isSafeExposureOrigin(element.value))
|
|
321
|
+
continue;
|
|
322
|
+
findings.push({
|
|
323
|
+
code: 'unsafe-origin-exposure',
|
|
324
|
+
file,
|
|
325
|
+
...location(element, lineOffset),
|
|
326
|
+
message: `Siteverb exposedTo value "${element.value}" is not an exact secure origin.`,
|
|
327
|
+
severity: 'error',
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
walk(source.program, (node) => {
|
|
332
|
+
if (node.type !== 'CallExpression')
|
|
333
|
+
return;
|
|
334
|
+
const calleePath = memberPath(node.callee);
|
|
335
|
+
if (calleePath && /^(?:document|navigator)\.modelContext\.registerTool$/.test(calleePath)) {
|
|
336
|
+
findings.push({
|
|
337
|
+
code: 'raw-native-registration',
|
|
338
|
+
file,
|
|
339
|
+
...location(node, lineOffset),
|
|
340
|
+
message: 'Raw native registration bypasses Siteverb callback coverage.',
|
|
341
|
+
severity: 'error',
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
if (isToolDefinitionCall(node)) {
|
|
345
|
+
const first = node.arguments[0];
|
|
346
|
+
const position = location(node, lineOffset);
|
|
347
|
+
const objects = first && first.type !== 'SpreadElement' ? resolveToolObjects(first) : [];
|
|
348
|
+
if (objects.length === 0) {
|
|
349
|
+
findings.push({
|
|
350
|
+
code: 'dynamic-tool-metadata',
|
|
351
|
+
file,
|
|
352
|
+
...position,
|
|
353
|
+
message: 'Siteverb tool definitions must resolve to static objects for source coverage.',
|
|
354
|
+
severity: 'warning',
|
|
355
|
+
});
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
objects.forEach(addTool);
|
|
359
|
+
inspectExposure(node);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const registrationPath = memberPath(node.callee);
|
|
363
|
+
const registrationMethod = registrationPath?.split('.').at(-1);
|
|
364
|
+
const clientName = registrationPath?.split('.').at(-2);
|
|
365
|
+
const directFactoryClient = node.callee.type === 'MemberExpression' &&
|
|
366
|
+
node.callee.object.type === 'CallExpression' &&
|
|
367
|
+
isSiteverbFactory(node.callee.object);
|
|
368
|
+
if ((registrationMethod !== 'registerTool' && registrationMethod !== 'registerTools') ||
|
|
369
|
+
(!directFactoryClient && (!clientName || !siteverbClients.has(clientName)))) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const first = node.arguments[0];
|
|
373
|
+
const objects = first && first.type !== 'SpreadElement' ? resolveToolObjects(first) : [];
|
|
374
|
+
if (objects.length === 0) {
|
|
375
|
+
findings.push({
|
|
376
|
+
code: 'dynamic-tool-metadata',
|
|
377
|
+
file,
|
|
378
|
+
...location(node, lineOffset),
|
|
379
|
+
message: 'Siteverb registrations must resolve to static tool objects for source coverage.',
|
|
380
|
+
severity: 'warning',
|
|
381
|
+
});
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
objects.forEach(addTool);
|
|
385
|
+
inspectExposure(node);
|
|
386
|
+
});
|
|
387
|
+
return { filesScanned: 1, findings, tools };
|
|
388
|
+
}
|
|
389
|
+
function attribute(node, name) {
|
|
390
|
+
return node.attrs.find((candidate) => candidate.name === name)?.value;
|
|
391
|
+
}
|
|
392
|
+
function hasAttribute(node, name) {
|
|
393
|
+
return node.attrs.some((candidate) => candidate.name === name);
|
|
394
|
+
}
|
|
395
|
+
function scanMarkup(path, root, sourceText) {
|
|
396
|
+
const file = relative(root, path);
|
|
397
|
+
const tools = [];
|
|
398
|
+
const findings = [];
|
|
399
|
+
const document = parse(sourceText, { sourceCodeLocationInfo: true });
|
|
400
|
+
const visit = (node) => {
|
|
401
|
+
if ('tagName' in node && node.tagName === 'form') {
|
|
402
|
+
const name = attribute(node, 'toolname');
|
|
403
|
+
if (name) {
|
|
404
|
+
const start = node.sourceCodeLocation?.startTag;
|
|
405
|
+
tools.push({
|
|
406
|
+
file,
|
|
407
|
+
line: start?.startLine ?? 1,
|
|
408
|
+
column: start?.startCol ?? 1,
|
|
409
|
+
name,
|
|
410
|
+
...(hasAttribute(node, 'toolautosubmit') ? { autoSubmit: true } : {}),
|
|
411
|
+
owner: 'declarative',
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if ('tagName' in node && node.tagName === 'script') {
|
|
416
|
+
const sourceReference = attribute(node, 'src');
|
|
417
|
+
if (sourceReference && isExternalRuntimeReference(sourceReference)) {
|
|
418
|
+
const start = node.sourceCodeLocation?.startTag;
|
|
419
|
+
findings.push({
|
|
420
|
+
code: 'external-registration-runtime',
|
|
421
|
+
file,
|
|
422
|
+
line: start?.startLine ?? 1,
|
|
423
|
+
column: start?.startCol ?? 1,
|
|
424
|
+
message: `External WebMCP registration runtime "${sourceReference}" requires an explicit coexistence or migration decision.`,
|
|
425
|
+
severity: 'warning',
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
const type = attribute(node, 'type')?.toLowerCase();
|
|
429
|
+
if (!sourceReference && (!type || type === 'module' || /javascript|typescript/.test(type))) {
|
|
430
|
+
for (const child of node.childNodes) {
|
|
431
|
+
if (!('value' in child) || !child.value.trim())
|
|
432
|
+
continue;
|
|
433
|
+
const scriptLocation = child.sourceCodeLocation;
|
|
434
|
+
const scanned = scanSource(path, root, child.value, (scriptLocation?.startLine ?? 1) - 1);
|
|
435
|
+
findings.push(...scanned.findings);
|
|
436
|
+
tools.push(...scanned.tools);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if ('childNodes' in node)
|
|
441
|
+
node.childNodes.forEach(visit);
|
|
442
|
+
};
|
|
443
|
+
visit(document);
|
|
444
|
+
return { filesScanned: 1, findings, tools };
|
|
445
|
+
}
|
|
446
|
+
async function collectFiles(directory, output, limit) {
|
|
447
|
+
if (output.length >= limit)
|
|
448
|
+
throw new Error(`Source audit exceeded the ${limit}-file safety limit.`);
|
|
449
|
+
const entries = await readdir(directory, { withFileTypes: true });
|
|
450
|
+
for (const entry of entries) {
|
|
451
|
+
if (entry.isSymbolicLink() || ignoredDirectories.has(entry.name))
|
|
452
|
+
continue;
|
|
453
|
+
const path = resolve(directory, entry.name);
|
|
454
|
+
if (entry.isDirectory())
|
|
455
|
+
await collectFiles(path, output, limit);
|
|
456
|
+
else if (sourceExtension.test(entry.name) ||
|
|
457
|
+
htmlExtension.test(entry.name) ||
|
|
458
|
+
componentExtension.test(entry.name))
|
|
459
|
+
output.push(path);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
export async function scanProjectSources(root, limit = 10_000) {
|
|
463
|
+
const paths = [];
|
|
464
|
+
await collectFiles(root, paths, limit);
|
|
465
|
+
const result = { filesScanned: 0, findings: [], tools: [] };
|
|
466
|
+
for (const path of paths) {
|
|
467
|
+
const source = await readFile(path, 'utf8');
|
|
468
|
+
const scanned = sourceExtension.test(path)
|
|
469
|
+
? scanSource(path, root, source)
|
|
470
|
+
: scanMarkup(path, root, source);
|
|
471
|
+
result.filesScanned += scanned.filesScanned;
|
|
472
|
+
result.findings.push(...scanned.findings);
|
|
473
|
+
result.tools.push(...scanned.tools);
|
|
474
|
+
}
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
//# sourceMappingURL=source-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-scan.js","sourceRoot":"","sources":["../src/source-scan.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type AuditFindingCode = 'contract-name-mismatch' | 'contract-tool-missing-source' | 'duplicate-stable-id' | 'duplicate-wire-name' | 'dynamic-origin-exposure' | 'dynamic-tool-metadata' | 'external-registration-runtime' | 'raw-native-registration' | 'source-parse-failed' | 'source-tool-missing-contract' | 'unsafe-declarative-autosubmit' | 'unsafe-origin-exposure';
|
|
2
|
+
export interface AuditFinding {
|
|
3
|
+
readonly code: AuditFindingCode;
|
|
4
|
+
readonly column?: number;
|
|
5
|
+
readonly file: string;
|
|
6
|
+
readonly line?: number;
|
|
7
|
+
readonly message: string;
|
|
8
|
+
readonly severity: 'error' | 'warning';
|
|
9
|
+
}
|
|
10
|
+
export interface SourceTool {
|
|
11
|
+
readonly autoSubmit?: boolean;
|
|
12
|
+
readonly column: number;
|
|
13
|
+
readonly file: string;
|
|
14
|
+
readonly id?: string;
|
|
15
|
+
readonly line: number;
|
|
16
|
+
readonly name?: string;
|
|
17
|
+
readonly owner: 'siteverb' | 'declarative';
|
|
18
|
+
}
|
|
19
|
+
export interface AuditReport {
|
|
20
|
+
readonly version: 1;
|
|
21
|
+
readonly root: string;
|
|
22
|
+
readonly contract: string;
|
|
23
|
+
readonly summary: {
|
|
24
|
+
readonly errors: number;
|
|
25
|
+
readonly warnings: number;
|
|
26
|
+
readonly filesScanned: number;
|
|
27
|
+
readonly sourceTools: number;
|
|
28
|
+
readonly contractTools: number;
|
|
29
|
+
};
|
|
30
|
+
readonly tools: readonly SourceTool[];
|
|
31
|
+
readonly findings: readonly AuditFinding[];
|
|
32
|
+
}
|
|
33
|
+
export interface AuditProjectOptions {
|
|
34
|
+
readonly contractPath: string;
|
|
35
|
+
readonly root: string;
|
|
36
|
+
readonly strictExternal?: boolean;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GACxB,wBAAwB,GACxB,8BAA8B,GAC9B,qBAAqB,GACrB,qBAAqB,GACrB,yBAAyB,GACzB,uBAAuB,GACvB,+BAA+B,GAC/B,yBAAyB,GACzB,qBAAqB,GACrB,8BAA8B,GAC9B,+BAA+B,GAC/B,wBAAwB,CAAC;AAE7B,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,CAAC;CAC5C;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;QAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;KAChC,CAAC;IACF,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@siteverb/audit",
|
|
3
|
+
"version": "0.1.0-rc.0",
|
|
4
|
+
"description": "Static coverage audit for Siteverb and WebMCP registration paths.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"bin": {
|
|
12
|
+
"siteverb-audit": "dist/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./package.json": "./package.json"
|
|
20
|
+
},
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=22"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -p tsconfig.build.json",
|
|
28
|
+
"package:check": "publint && attw --pack . --profile esm-only",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [
|
|
33
|
+
"webmcp",
|
|
34
|
+
"static-analysis",
|
|
35
|
+
"typescript",
|
|
36
|
+
"ci"
|
|
37
|
+
],
|
|
38
|
+
"license": "Apache-2.0",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/siteverb/siteverb.git",
|
|
42
|
+
"directory": "packages/audit"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public",
|
|
46
|
+
"provenance": true
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@siteverb/contracts": "^0.1.0-rc.0",
|
|
50
|
+
"@babel/parser": "^7.28.4",
|
|
51
|
+
"@babel/types": "^7.28.4",
|
|
52
|
+
"parse5": "^8.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|