@codapult/guard 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/LICENSE +21 -0
- package/README.md +290 -0
- package/dist/adapters/agents/agent-integration.d.ts +9 -0
- package/dist/adapters/agents/agent-integration.js +62 -0
- package/dist/adapters/command.d.ts +21 -0
- package/dist/adapters/command.js +60 -0
- package/dist/adapters/project-checks.d.ts +37 -0
- package/dist/adapters/project-checks.js +149 -0
- package/dist/cli/commands/guard.d.ts +55 -0
- package/dist/cli/commands/guard.js +510 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +75 -0
- package/dist/cli/ui.d.ts +6 -0
- package/dist/cli/ui.js +7 -0
- package/dist/commands/guard.d.ts +2 -0
- package/dist/commands/guard.js +2 -0
- package/dist/core/analysis/doctor.d.ts +12 -0
- package/dist/core/analysis/doctor.js +85 -0
- package/dist/core/analysis/packs.d.ts +21 -0
- package/dist/core/analysis/packs.js +251 -0
- package/dist/core/config.d.ts +6 -0
- package/dist/core/config.js +6 -0
- package/dist/core/discovery/discovery.d.ts +134 -0
- package/dist/core/discovery/discovery.js +816 -0
- package/dist/core/guard.d.ts +189 -0
- package/dist/core/guard.js +936 -0
- package/dist/core/history/history.d.ts +24 -0
- package/dist/core/history/history.js +65 -0
- package/dist/core/output/sarif.d.ts +35 -0
- package/dist/core/output/sarif.js +29 -0
- package/dist/core/policy/schemas.d.ts +272 -0
- package/dist/core/policy/schemas.js +72 -0
- package/dist/core/verification/verify.d.ts +29 -0
- package/dist/core/verification/verify.js +77 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/mcp/prompts.d.ts +2 -0
- package/dist/mcp/prompts.js +54 -0
- package/dist/mcp/resources.d.ts +2 -0
- package/dist/mcp/resources.js +64 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +17 -0
- package/dist/mcp/tools/guard.d.ts +2 -0
- package/dist/mcp/tools/guard.js +375 -0
- package/package.json +117 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface GuardSnapshotSummary {
|
|
2
|
+
revision: string;
|
|
3
|
+
path: string;
|
|
4
|
+
files: number;
|
|
5
|
+
modules: number;
|
|
6
|
+
capabilities: string[];
|
|
7
|
+
cycles: number;
|
|
8
|
+
}
|
|
9
|
+
export interface GuardHistoryDiff {
|
|
10
|
+
from: string;
|
|
11
|
+
to: string;
|
|
12
|
+
addedFiles: string[];
|
|
13
|
+
removedFiles: string[];
|
|
14
|
+
addedDependencies: string[];
|
|
15
|
+
removedDependencies: string[];
|
|
16
|
+
addedCapabilities: string[];
|
|
17
|
+
removedCapabilities: string[];
|
|
18
|
+
cycles: {
|
|
19
|
+
from: number;
|
|
20
|
+
to: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export declare function listGuardSnapshots(root: string): GuardSnapshotSummary[];
|
|
24
|
+
export declare function diffGuardSnapshots(root: string, from: string, to: string): GuardHistoryDiff | undefined;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { GUARD_HISTORY_DIR } from '../guard.js';
|
|
4
|
+
function readSnapshot(root, revision) {
|
|
5
|
+
if (!/^[A-Za-z0-9._-]+$/.test(revision))
|
|
6
|
+
return undefined;
|
|
7
|
+
try {
|
|
8
|
+
return JSON.parse(readFileSync(resolve(root, GUARD_HISTORY_DIR, `${revision}.json`), 'utf8'));
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function listGuardSnapshots(root) {
|
|
15
|
+
const directory = resolve(root, GUARD_HISTORY_DIR);
|
|
16
|
+
if (!existsSync(directory))
|
|
17
|
+
return [];
|
|
18
|
+
return readdirSync(directory)
|
|
19
|
+
.filter((file) => file.endsWith('.json'))
|
|
20
|
+
.sort()
|
|
21
|
+
.flatMap((file) => {
|
|
22
|
+
const revision = file.slice(0, -5);
|
|
23
|
+
const model = readSnapshot(root, revision);
|
|
24
|
+
return model
|
|
25
|
+
? [
|
|
26
|
+
{
|
|
27
|
+
revision,
|
|
28
|
+
path: `${GUARD_HISTORY_DIR}/${file}`,
|
|
29
|
+
files: model.files.length,
|
|
30
|
+
modules: model.modules.length,
|
|
31
|
+
capabilities: Object.keys(model.capabilities).sort(),
|
|
32
|
+
cycles: model.insights.cycles.length,
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
: [];
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export function diffGuardSnapshots(root, from, to) {
|
|
39
|
+
const before = readSnapshot(root, from);
|
|
40
|
+
const after = readSnapshot(root, to);
|
|
41
|
+
if (!before || !after)
|
|
42
|
+
return undefined;
|
|
43
|
+
const difference = (left, right) => right.filter((value) => !left.includes(value)).sort();
|
|
44
|
+
const beforeFiles = before.files.map((file) => file.path);
|
|
45
|
+
const afterFiles = after.files.map((file) => file.path);
|
|
46
|
+
const beforeDependencies = Object.keys({
|
|
47
|
+
...before.project.dependencies,
|
|
48
|
+
...before.project.devDependencies,
|
|
49
|
+
});
|
|
50
|
+
const afterDependencies = Object.keys({
|
|
51
|
+
...after.project.dependencies,
|
|
52
|
+
...after.project.devDependencies,
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
from,
|
|
56
|
+
to,
|
|
57
|
+
addedFiles: difference(beforeFiles, afterFiles),
|
|
58
|
+
removedFiles: difference(afterFiles, beforeFiles),
|
|
59
|
+
addedDependencies: difference(beforeDependencies, afterDependencies),
|
|
60
|
+
removedDependencies: difference(afterDependencies, beforeDependencies),
|
|
61
|
+
addedCapabilities: difference(Object.keys(before.capabilities), Object.keys(after.capabilities)),
|
|
62
|
+
removedCapabilities: difference(Object.keys(after.capabilities), Object.keys(before.capabilities)),
|
|
63
|
+
cycles: { from: before.insights.cycles.length, to: after.insights.cycles.length },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { GuardFinding } from '../guard.js';
|
|
2
|
+
interface SarifResult {
|
|
3
|
+
ruleId: string;
|
|
4
|
+
level: 'error' | 'warning' | 'note';
|
|
5
|
+
message: {
|
|
6
|
+
text: string;
|
|
7
|
+
};
|
|
8
|
+
locations: [
|
|
9
|
+
{
|
|
10
|
+
physicalLocation: {
|
|
11
|
+
artifactLocation: {
|
|
12
|
+
uri: string;
|
|
13
|
+
};
|
|
14
|
+
region: {
|
|
15
|
+
startLine: number;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
];
|
|
20
|
+
}
|
|
21
|
+
export interface SarifLog {
|
|
22
|
+
version: '2.1.0';
|
|
23
|
+
$schema: string;
|
|
24
|
+
runs: [{
|
|
25
|
+
tool: {
|
|
26
|
+
driver: {
|
|
27
|
+
name: string;
|
|
28
|
+
informationUri: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
results: SarifResult[];
|
|
32
|
+
}];
|
|
33
|
+
}
|
|
34
|
+
export declare function guardFindingsToSarif(findings: GuardFinding[]): SarifLog;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function guardFindingsToSarif(findings) {
|
|
2
|
+
return {
|
|
3
|
+
version: '2.1.0',
|
|
4
|
+
$schema: 'https://json.schemastore.org/sarif-2.1.0.json',
|
|
5
|
+
runs: [
|
|
6
|
+
{
|
|
7
|
+
tool: {
|
|
8
|
+
driver: {
|
|
9
|
+
name: 'Codapult Guard',
|
|
10
|
+
informationUri: 'https://codapult.dev/docs/developer-tools/guard',
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
results: findings.map((finding) => ({
|
|
14
|
+
ruleId: finding.ruleId,
|
|
15
|
+
level: finding.severity === 'info' ? 'note' : finding.severity,
|
|
16
|
+
message: { text: finding.message },
|
|
17
|
+
locations: [
|
|
18
|
+
{
|
|
19
|
+
physicalLocation: {
|
|
20
|
+
artifactLocation: { uri: finding.file },
|
|
21
|
+
region: { startLine: finding.line },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
})),
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const guardRuleSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
description: z.ZodString;
|
|
5
|
+
severity: z.ZodEnum<{
|
|
6
|
+
error: "error";
|
|
7
|
+
info: "info";
|
|
8
|
+
warning: "warning";
|
|
9
|
+
}>;
|
|
10
|
+
kind: z.ZodEnum<{
|
|
11
|
+
"client-forbidden-import": "client-forbidden-import";
|
|
12
|
+
"forbidden-import": "forbidden-import";
|
|
13
|
+
}>;
|
|
14
|
+
patterns: z.ZodArray<z.ZodString>;
|
|
15
|
+
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
16
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
17
|
+
active: "active";
|
|
18
|
+
proposed: "proposed";
|
|
19
|
+
}>>;
|
|
20
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
21
|
+
high: "high";
|
|
22
|
+
low: "low";
|
|
23
|
+
medium: "medium";
|
|
24
|
+
}>>;
|
|
25
|
+
evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
|
+
}, z.core.$strip>;
|
|
27
|
+
export declare const guardContractSchema: z.ZodObject<{
|
|
28
|
+
id: z.ZodString;
|
|
29
|
+
statement: z.ZodString;
|
|
30
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
31
|
+
guidance: "guidance";
|
|
32
|
+
"import-boundary": "import-boundary";
|
|
33
|
+
"required-call": "required-call";
|
|
34
|
+
}>>;
|
|
35
|
+
severity: z.ZodOptional<z.ZodEnum<{
|
|
36
|
+
error: "error";
|
|
37
|
+
info: "info";
|
|
38
|
+
warning: "warning";
|
|
39
|
+
}>>;
|
|
40
|
+
scope: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
41
|
+
entrypoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
42
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
43
|
+
guidance: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
44
|
+
references: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
45
|
+
mustImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
46
|
+
mustNotImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
47
|
+
mustCall: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
48
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
49
|
+
active: "active";
|
|
50
|
+
proposed: "proposed";
|
|
51
|
+
}>>;
|
|
52
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
53
|
+
high: "high";
|
|
54
|
+
low: "low";
|
|
55
|
+
medium: "medium";
|
|
56
|
+
}>>;
|
|
57
|
+
evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
58
|
+
}, z.core.$strip>;
|
|
59
|
+
export declare const guardConfigSchema: z.ZodObject<{
|
|
60
|
+
version: z.ZodLiteral<1>;
|
|
61
|
+
rules: z.ZodArray<z.ZodObject<{
|
|
62
|
+
id: z.ZodString;
|
|
63
|
+
description: z.ZodString;
|
|
64
|
+
severity: z.ZodEnum<{
|
|
65
|
+
error: "error";
|
|
66
|
+
info: "info";
|
|
67
|
+
warning: "warning";
|
|
68
|
+
}>;
|
|
69
|
+
kind: z.ZodEnum<{
|
|
70
|
+
"client-forbidden-import": "client-forbidden-import";
|
|
71
|
+
"forbidden-import": "forbidden-import";
|
|
72
|
+
}>;
|
|
73
|
+
patterns: z.ZodArray<z.ZodString>;
|
|
74
|
+
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
75
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
76
|
+
active: "active";
|
|
77
|
+
proposed: "proposed";
|
|
78
|
+
}>>;
|
|
79
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
80
|
+
high: "high";
|
|
81
|
+
low: "low";
|
|
82
|
+
medium: "medium";
|
|
83
|
+
}>>;
|
|
84
|
+
evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
85
|
+
}, z.core.$strip>>;
|
|
86
|
+
contracts: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
87
|
+
id: z.ZodString;
|
|
88
|
+
statement: z.ZodString;
|
|
89
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
90
|
+
guidance: "guidance";
|
|
91
|
+
"import-boundary": "import-boundary";
|
|
92
|
+
"required-call": "required-call";
|
|
93
|
+
}>>;
|
|
94
|
+
severity: z.ZodOptional<z.ZodEnum<{
|
|
95
|
+
error: "error";
|
|
96
|
+
info: "info";
|
|
97
|
+
warning: "warning";
|
|
98
|
+
}>>;
|
|
99
|
+
scope: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
100
|
+
entrypoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
101
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
102
|
+
guidance: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
103
|
+
references: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
104
|
+
mustImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
105
|
+
mustNotImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
106
|
+
mustCall: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
107
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
108
|
+
active: "active";
|
|
109
|
+
proposed: "proposed";
|
|
110
|
+
}>>;
|
|
111
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
112
|
+
high: "high";
|
|
113
|
+
low: "low";
|
|
114
|
+
medium: "medium";
|
|
115
|
+
}>>;
|
|
116
|
+
evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
117
|
+
}, z.core.$strip>>>;
|
|
118
|
+
}, z.core.$strip>;
|
|
119
|
+
export declare const guardContractsFileSchema: z.ZodObject<{
|
|
120
|
+
version: z.ZodLiteral<1>;
|
|
121
|
+
contracts: z.ZodArray<z.ZodObject<{
|
|
122
|
+
id: z.ZodString;
|
|
123
|
+
statement: z.ZodString;
|
|
124
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
125
|
+
guidance: "guidance";
|
|
126
|
+
"import-boundary": "import-boundary";
|
|
127
|
+
"required-call": "required-call";
|
|
128
|
+
}>>;
|
|
129
|
+
severity: z.ZodOptional<z.ZodEnum<{
|
|
130
|
+
error: "error";
|
|
131
|
+
info: "info";
|
|
132
|
+
warning: "warning";
|
|
133
|
+
}>>;
|
|
134
|
+
scope: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
135
|
+
entrypoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
136
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
137
|
+
guidance: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
138
|
+
references: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
139
|
+
mustImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
140
|
+
mustNotImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
141
|
+
mustCall: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
142
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
143
|
+
active: "active";
|
|
144
|
+
proposed: "proposed";
|
|
145
|
+
}>>;
|
|
146
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
147
|
+
high: "high";
|
|
148
|
+
low: "low";
|
|
149
|
+
medium: "medium";
|
|
150
|
+
}>>;
|
|
151
|
+
evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
152
|
+
}, z.core.$strip>>;
|
|
153
|
+
}, z.core.$strip>;
|
|
154
|
+
export declare const guardProposalDecisionSchema: z.ZodObject<{
|
|
155
|
+
id: z.ZodString;
|
|
156
|
+
type: z.ZodEnum<{
|
|
157
|
+
contract: "contract";
|
|
158
|
+
rule: "rule";
|
|
159
|
+
}>;
|
|
160
|
+
decision: z.ZodEnum<{
|
|
161
|
+
approved: "approved";
|
|
162
|
+
rejected: "rejected";
|
|
163
|
+
}>;
|
|
164
|
+
decidedAt: z.ZodString;
|
|
165
|
+
proposalId: z.ZodOptional<z.ZodString>;
|
|
166
|
+
proposalFingerprint: z.ZodOptional<z.ZodString>;
|
|
167
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
168
|
+
}, z.core.$strip>;
|
|
169
|
+
export declare const guardProposalSchema: z.ZodObject<{
|
|
170
|
+
version: z.ZodLiteral<1>;
|
|
171
|
+
generatedAt: z.ZodString;
|
|
172
|
+
proposalId: z.ZodOptional<z.ZodString>;
|
|
173
|
+
projectFingerprint: z.ZodOptional<z.ZodString>;
|
|
174
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
175
|
+
contentFingerprint: z.ZodOptional<z.ZodString>;
|
|
176
|
+
rules: z.ZodArray<z.ZodObject<{
|
|
177
|
+
id: z.ZodString;
|
|
178
|
+
description: z.ZodString;
|
|
179
|
+
severity: z.ZodEnum<{
|
|
180
|
+
error: "error";
|
|
181
|
+
info: "info";
|
|
182
|
+
warning: "warning";
|
|
183
|
+
}>;
|
|
184
|
+
kind: z.ZodEnum<{
|
|
185
|
+
"client-forbidden-import": "client-forbidden-import";
|
|
186
|
+
"forbidden-import": "forbidden-import";
|
|
187
|
+
}>;
|
|
188
|
+
patterns: z.ZodArray<z.ZodString>;
|
|
189
|
+
files: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
190
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
191
|
+
active: "active";
|
|
192
|
+
proposed: "proposed";
|
|
193
|
+
}>>;
|
|
194
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
195
|
+
high: "high";
|
|
196
|
+
low: "low";
|
|
197
|
+
medium: "medium";
|
|
198
|
+
}>>;
|
|
199
|
+
evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
200
|
+
}, z.core.$strip>>;
|
|
201
|
+
contracts: z.ZodArray<z.ZodObject<{
|
|
202
|
+
id: z.ZodString;
|
|
203
|
+
statement: z.ZodString;
|
|
204
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
205
|
+
guidance: "guidance";
|
|
206
|
+
"import-boundary": "import-boundary";
|
|
207
|
+
"required-call": "required-call";
|
|
208
|
+
}>>;
|
|
209
|
+
severity: z.ZodOptional<z.ZodEnum<{
|
|
210
|
+
error: "error";
|
|
211
|
+
info: "info";
|
|
212
|
+
warning: "warning";
|
|
213
|
+
}>>;
|
|
214
|
+
scope: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
215
|
+
entrypoints: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
216
|
+
exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
217
|
+
guidance: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
218
|
+
references: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
219
|
+
mustImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
220
|
+
mustNotImport: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
221
|
+
mustCall: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
222
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
223
|
+
active: "active";
|
|
224
|
+
proposed: "proposed";
|
|
225
|
+
}>>;
|
|
226
|
+
confidence: z.ZodOptional<z.ZodEnum<{
|
|
227
|
+
high: "high";
|
|
228
|
+
low: "low";
|
|
229
|
+
medium: "medium";
|
|
230
|
+
}>>;
|
|
231
|
+
evidence: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
232
|
+
}, z.core.$strip>>;
|
|
233
|
+
questions: z.ZodArray<z.ZodString>;
|
|
234
|
+
decisions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
235
|
+
id: z.ZodString;
|
|
236
|
+
type: z.ZodEnum<{
|
|
237
|
+
contract: "contract";
|
|
238
|
+
rule: "rule";
|
|
239
|
+
}>;
|
|
240
|
+
decision: z.ZodEnum<{
|
|
241
|
+
approved: "approved";
|
|
242
|
+
rejected: "rejected";
|
|
243
|
+
}>;
|
|
244
|
+
decidedAt: z.ZodString;
|
|
245
|
+
proposalId: z.ZodOptional<z.ZodString>;
|
|
246
|
+
proposalFingerprint: z.ZodOptional<z.ZodString>;
|
|
247
|
+
revision: z.ZodOptional<z.ZodNumber>;
|
|
248
|
+
}, z.core.$strip>>>;
|
|
249
|
+
}, z.core.$strip>;
|
|
250
|
+
export declare const guardAgentConfigSchema: z.ZodObject<{
|
|
251
|
+
version: z.ZodLiteral<1>;
|
|
252
|
+
tools: z.ZodEnum<{
|
|
253
|
+
auto: "auto";
|
|
254
|
+
off: "off";
|
|
255
|
+
on: "on";
|
|
256
|
+
}>;
|
|
257
|
+
tooling: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
258
|
+
script: z.ZodString;
|
|
259
|
+
enabled: z.ZodBoolean;
|
|
260
|
+
}, z.core.$strip>>>;
|
|
261
|
+
completionGate: z.ZodObject<{
|
|
262
|
+
enabled: z.ZodBoolean;
|
|
263
|
+
maxIterations: z.ZodNumber;
|
|
264
|
+
projectChecks: z.ZodBoolean;
|
|
265
|
+
checks: z.ZodArray<z.ZodEnum<{
|
|
266
|
+
build: "build";
|
|
267
|
+
lint: "lint";
|
|
268
|
+
test: "test";
|
|
269
|
+
typecheck: "typecheck";
|
|
270
|
+
}>>;
|
|
271
|
+
}, z.core.$strip>;
|
|
272
|
+
}, z.core.$strip>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const severity = z.enum(['error', 'warning', 'info']);
|
|
3
|
+
const status = z.enum(['active', 'proposed']);
|
|
4
|
+
export const guardRuleSchema = z.object({
|
|
5
|
+
id: z.string(),
|
|
6
|
+
description: z.string(),
|
|
7
|
+
severity,
|
|
8
|
+
kind: z.enum(['forbidden-import', 'client-forbidden-import']),
|
|
9
|
+
patterns: z.array(z.string()),
|
|
10
|
+
files: z.array(z.string()).optional(),
|
|
11
|
+
status: status.optional(),
|
|
12
|
+
confidence: z.enum(['high', 'medium', 'low']).optional(),
|
|
13
|
+
evidence: z.array(z.string()).optional(),
|
|
14
|
+
});
|
|
15
|
+
export const guardContractSchema = z.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
statement: z.string(),
|
|
18
|
+
kind: z.enum(['guidance', 'import-boundary', 'required-call']).optional(),
|
|
19
|
+
severity: severity.optional(),
|
|
20
|
+
scope: z.array(z.string()).optional(),
|
|
21
|
+
entrypoints: z.array(z.string()).optional(),
|
|
22
|
+
exclude: z.array(z.string()).optional(),
|
|
23
|
+
guidance: z.array(z.string()).optional(),
|
|
24
|
+
references: z.array(z.string()).optional(),
|
|
25
|
+
mustImport: z.array(z.string()).optional(),
|
|
26
|
+
mustNotImport: z.array(z.string()).optional(),
|
|
27
|
+
mustCall: z.array(z.string()).optional(),
|
|
28
|
+
status: status.optional(),
|
|
29
|
+
confidence: z.enum(['high', 'medium', 'low']).optional(),
|
|
30
|
+
evidence: z.array(z.string()).optional(),
|
|
31
|
+
});
|
|
32
|
+
export const guardConfigSchema = z.object({
|
|
33
|
+
version: z.literal(1),
|
|
34
|
+
rules: z.array(guardRuleSchema),
|
|
35
|
+
contracts: z.array(guardContractSchema).optional(),
|
|
36
|
+
});
|
|
37
|
+
export const guardContractsFileSchema = z.object({
|
|
38
|
+
version: z.literal(1),
|
|
39
|
+
contracts: z.array(guardContractSchema),
|
|
40
|
+
});
|
|
41
|
+
export const guardProposalDecisionSchema = z.object({
|
|
42
|
+
id: z.string(),
|
|
43
|
+
type: z.enum(['rule', 'contract']),
|
|
44
|
+
decision: z.enum(['approved', 'rejected']),
|
|
45
|
+
decidedAt: z.string(),
|
|
46
|
+
proposalId: z.string().optional(),
|
|
47
|
+
proposalFingerprint: z.string().optional(),
|
|
48
|
+
revision: z.number().optional(),
|
|
49
|
+
});
|
|
50
|
+
export const guardProposalSchema = z.object({
|
|
51
|
+
version: z.literal(1),
|
|
52
|
+
generatedAt: z.string(),
|
|
53
|
+
proposalId: z.string().optional(),
|
|
54
|
+
projectFingerprint: z.string().optional(),
|
|
55
|
+
revision: z.number().int().positive().optional(),
|
|
56
|
+
contentFingerprint: z.string().optional(),
|
|
57
|
+
rules: z.array(guardRuleSchema),
|
|
58
|
+
contracts: z.array(guardContractSchema),
|
|
59
|
+
questions: z.array(z.string()),
|
|
60
|
+
decisions: z.array(guardProposalDecisionSchema).optional(),
|
|
61
|
+
});
|
|
62
|
+
export const guardAgentConfigSchema = z.object({
|
|
63
|
+
version: z.literal(1),
|
|
64
|
+
tools: z.enum(['auto', 'on', 'off']),
|
|
65
|
+
tooling: z.record(z.string(), z.object({ script: z.string(), enabled: z.boolean() })).default({}),
|
|
66
|
+
completionGate: z.object({
|
|
67
|
+
enabled: z.boolean(),
|
|
68
|
+
maxIterations: z.number().int().min(1).max(10),
|
|
69
|
+
projectChecks: z.boolean(),
|
|
70
|
+
checks: z.array(z.enum(['lint', 'typecheck', 'test', 'build'])),
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type CommandResult } from '../../adapters/command.js';
|
|
2
|
+
import { type GuardAdapter, type ProjectCheck, type ProjectCheckResults, type ProjectRuntimeDiagnostics } from '../../adapters/project-checks.js';
|
|
3
|
+
import { type GuardToolMode, type GuardContractIssue, type GuardReport } from '../guard.js';
|
|
4
|
+
export type GuardVerificationCheck = ProjectCheck;
|
|
5
|
+
export interface GuardVerificationResult {
|
|
6
|
+
status: 'ok' | 'fail' | 'not-configured';
|
|
7
|
+
outcome: 'pass' | 'fail' | 'warning' | 'needs-review' | 'not-configured';
|
|
8
|
+
tools?: GuardToolMode;
|
|
9
|
+
checks: ProjectCheckResults;
|
|
10
|
+
workspaceChecks: Record<string, ProjectCheckResults>;
|
|
11
|
+
adapters: Partial<Record<GuardAdapter, CommandResult>>;
|
|
12
|
+
runtime: ProjectRuntimeDiagnostics;
|
|
13
|
+
architecture?: GuardReport;
|
|
14
|
+
contractIssues: GuardContractIssue[];
|
|
15
|
+
requirement: {
|
|
16
|
+
status: 'delegated-to-review';
|
|
17
|
+
provided: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function runGuardVerification(root: string, options?: {
|
|
22
|
+
checks?: GuardVerificationCheck[];
|
|
23
|
+
changedOnly?: boolean;
|
|
24
|
+
timeout?: number;
|
|
25
|
+
requirement?: string;
|
|
26
|
+
tools?: GuardToolMode;
|
|
27
|
+
strict?: boolean;
|
|
28
|
+
projectChecks?: boolean;
|
|
29
|
+
}): GuardVerificationResult;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { runProjectAdapters, runProjectChecks, runWorkspaceProjectChecks, inspectProjectRuntime, } from '../../adapters/project-checks.js';
|
|
2
|
+
import { loadBaseline, loadGuardAgentConfig, loadGuardConfig, scanGuard, classifyGuardOutcome, validateGuardContracts, } from '../guard.js';
|
|
3
|
+
import { discoverProject } from '../discovery/discovery.js';
|
|
4
|
+
export function runGuardVerification(root, options = {}) {
|
|
5
|
+
const config = loadGuardConfig(root);
|
|
6
|
+
const requirement = {
|
|
7
|
+
status: 'delegated-to-review',
|
|
8
|
+
provided: Boolean(options.requirement?.trim()),
|
|
9
|
+
message: options.requirement?.trim()
|
|
10
|
+
? 'Requirement text is included in semantic review input; deterministic verify does not judge natural-language acceptance criteria.'
|
|
11
|
+
: 'Requirement satisfaction is evaluated by guard review using the task and diff.',
|
|
12
|
+
};
|
|
13
|
+
const runtime = inspectProjectRuntime(root);
|
|
14
|
+
if (!config)
|
|
15
|
+
return {
|
|
16
|
+
status: 'not-configured',
|
|
17
|
+
outcome: 'not-configured',
|
|
18
|
+
checks: {},
|
|
19
|
+
workspaceChecks: {},
|
|
20
|
+
adapters: {},
|
|
21
|
+
runtime,
|
|
22
|
+
contractIssues: [],
|
|
23
|
+
requirement,
|
|
24
|
+
};
|
|
25
|
+
const agentConfig = loadGuardAgentConfig(root);
|
|
26
|
+
const projectChecks = options.projectChecks ?? agentConfig.completionGate.projectChecks;
|
|
27
|
+
const checks = projectChecks ? (options.checks ?? agentConfig.completionGate.checks) : [];
|
|
28
|
+
const results = runProjectChecks(root, checks, { timeout: options.timeout });
|
|
29
|
+
const workspaceModel = discoverProject(root);
|
|
30
|
+
const workspaceChecks = runWorkspaceProjectChecks(root, workspaceModel.project.workspacePackages ?? [], checks, {
|
|
31
|
+
timeout: options.timeout,
|
|
32
|
+
rootResults: results,
|
|
33
|
+
});
|
|
34
|
+
const toolMode = options.tools ?? agentConfig.tools;
|
|
35
|
+
const adapters = toolMode === 'off'
|
|
36
|
+
? {}
|
|
37
|
+
: runProjectAdapters(root, {
|
|
38
|
+
mode: toolMode,
|
|
39
|
+
timeout: options.timeout,
|
|
40
|
+
tooling: agentConfig.tooling,
|
|
41
|
+
});
|
|
42
|
+
const architecture = scanGuard(root, config, {
|
|
43
|
+
changedOnly: options.changedOnly,
|
|
44
|
+
baseline: loadBaseline(root),
|
|
45
|
+
includeArchitectureInsights: true,
|
|
46
|
+
});
|
|
47
|
+
const contractIssues = validateGuardContracts(root, config.contracts ?? []);
|
|
48
|
+
const commandFailed = Object.values(results).some((result) => result.status === 'failed');
|
|
49
|
+
const workspaceCommandFailed = Object.values(workspaceChecks).some((packageResults) => Object.values(packageResults).some((result) => result.status === 'failed'));
|
|
50
|
+
const adapterFailed = Object.values(adapters).some((result) => result.status === 'failed');
|
|
51
|
+
const missingRequiredTools = options.strict &&
|
|
52
|
+
[...Object.values(results), ...Object.values(adapters)].some((result) => result.status === 'not-configured');
|
|
53
|
+
const architectureFailed = architecture.findings.some((finding) => finding.severity === 'error');
|
|
54
|
+
const architectureWarnings = architecture.findings.some((finding) => finding.severity === 'warning');
|
|
55
|
+
const failed = (projectChecks && !runtime.compatible) ||
|
|
56
|
+
commandFailed ||
|
|
57
|
+
workspaceCommandFailed ||
|
|
58
|
+
adapterFailed ||
|
|
59
|
+
architectureFailed ||
|
|
60
|
+
contractIssues.length > 0 ||
|
|
61
|
+
missingRequiredTools;
|
|
62
|
+
return {
|
|
63
|
+
status: failed ? 'fail' : 'ok',
|
|
64
|
+
outcome: classifyGuardOutcome({
|
|
65
|
+
errors: failed ? 1 : 0,
|
|
66
|
+
warnings: architectureWarnings ? 1 : 0,
|
|
67
|
+
}),
|
|
68
|
+
tools: toolMode,
|
|
69
|
+
checks: results,
|
|
70
|
+
workspaceChecks,
|
|
71
|
+
adapters,
|
|
72
|
+
runtime,
|
|
73
|
+
architecture,
|
|
74
|
+
contractIssues,
|
|
75
|
+
requirement,
|
|
76
|
+
};
|
|
77
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Public, framework-agnostic Guard API. */
|
|
2
|
+
export * from './core/guard.js';
|
|
3
|
+
export * from './core/discovery/discovery.js';
|
|
4
|
+
export { runGuardVerification } from './core/verification/verify.js';
|
|
5
|
+
export type { GuardVerificationCheck, GuardVerificationResult, } from './core/verification/verify.js';
|
|
6
|
+
export * from './core/history/history.js';
|
|
7
|
+
export * from './core/output/sarif.js';
|
|
8
|
+
export * from './core/analysis/doctor.js';
|
|
9
|
+
export * from './core/analysis/packs.js';
|
|
10
|
+
export * from './adapters/project-checks.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Public, framework-agnostic Guard API. */
|
|
2
|
+
export * from './core/guard.js';
|
|
3
|
+
export * from './core/discovery/discovery.js';
|
|
4
|
+
export { runGuardVerification } from './core/verification/verify.js';
|
|
5
|
+
export * from './core/history/history.js';
|
|
6
|
+
export * from './core/output/sarif.js';
|
|
7
|
+
export * from './core/analysis/doctor.js';
|
|
8
|
+
export * from './core/analysis/packs.js';
|
|
9
|
+
export * from './adapters/project-checks.js';
|