@codapult/guard 0.10.0 → 0.11.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 +144 -4
- package/dist/adapters/agents/agent-integration.js +26 -3
- package/dist/cli/commands/guard.d.ts +2 -0
- package/dist/cli/commands/guard.js +77 -11
- package/dist/cli/index.js +2 -0
- package/dist/core/guard.d.ts +28 -1
- package/dist/core/guard.js +37 -0
- package/dist/core/history/runs.d.ts +64 -1
- package/dist/core/history/runs.js +109 -0
- package/dist/core/output/attestation.d.ts +17 -0
- package/dist/core/output/attestation.js +22 -0
- package/dist/core/policy/schemas.d.ts +47 -0
- package/dist/core/policy/schemas.js +67 -0
- package/dist/core/verification/github-actions.d.ts +25 -0
- package/dist/core/verification/github-actions.js +397 -0
- package/dist/core/verification/github-context.d.ts +8 -0
- package/dist/core/verification/github-context.js +41 -0
- package/dist/core/verification/verify.d.ts +23 -4
- package/dist/core/verification/verify.js +601 -47
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp/prompts.js +7 -4
- package/dist/mcp/tools/guard.js +9 -3
- package/docs/extensions.md +79 -0
- package/docs/guard-agent-integration.md +51 -0
- package/docs/guard-ci.yml +202 -0
- package/docs/guard-fixtures.md +127 -0
- package/docs/guard-trusted-pr-attestation.yml +213 -0
- package/docs/guard.md +1125 -0
- package/docs/integrations/README.md +38 -0
- package/docs/integrations/claude-code.md +92 -0
- package/docs/integrations/codex.md +58 -0
- package/docs/integrations/cursor.md +116 -0
- package/docs/integrations/gemini-cli.md +47 -0
- package/docs/integrations/generic.md +41 -0
- package/docs/integrations/github-copilot.md +72 -0
- package/docs/policy-mutations.md +75 -0
- package/docs/releasing.md +58 -0
- package/docs/verify-guard-attestation.mjs +166 -0
- package/package.json +4 -2
package/docs/guard.md
ADDED
|
@@ -0,0 +1,1125 @@
|
|
|
1
|
+
# Codapult Guard: Architecture Guardrails for AI Coding Agents
|
|
2
|
+
|
|
3
|
+
Codapult Guard is local-first architecture guardrail software for AI coding agents and JavaScript
|
|
4
|
+
or TypeScript repositories. It detects architectural drift by observing the existing software
|
|
5
|
+
architecture, recording project memory, and checking code changes against team-approved rules and
|
|
6
|
+
contracts. It also provides bounded project context for AI code review and deterministic checks for
|
|
7
|
+
local development and CI.
|
|
8
|
+
|
|
9
|
+
Guard is not a replacement for ESLint, TypeScript, a test runner, SAST, or a PR review service.
|
|
10
|
+
It is universal at the core and especially useful for Next.js SaaS projects, where server/client
|
|
11
|
+
boundaries, routes, persistence, authentication, billing, jobs, and AI integrations commonly need
|
|
12
|
+
project-specific architectural protection.
|
|
13
|
+
It can run a project's existing commands as an optional completion gate, but its own responsibility
|
|
14
|
+
is architectural memory, project-specific contracts, regression detection, impact context, and
|
|
15
|
+
deterministic evidence.
|
|
16
|
+
|
|
17
|
+
## Contents
|
|
18
|
+
|
|
19
|
+
- [The operating model](#the-operating-model)
|
|
20
|
+
- [Install and initialize](#install-and-initialize)
|
|
21
|
+
- [The generated state](#the-generated-state)
|
|
22
|
+
- [The daily workflow](#the-daily-workflow)
|
|
23
|
+
- [Policy scope and state changes](#policy-scope-and-state-changes)
|
|
24
|
+
- [Command reference](#command-reference)
|
|
25
|
+
- [Rules, contracts, and proposals](#rules-contracts-and-proposals)
|
|
26
|
+
- [What Guard discovers](#what-guard-discovers)
|
|
27
|
+
- [AI-agent and MCP workflow](#ai-agent-and-mcp-workflow)
|
|
28
|
+
- [CI and machine-readable output](#ci-and-machine-readable-output)
|
|
29
|
+
- [Security and data handling](#security-and-data-handling)
|
|
30
|
+
- [Troubleshooting](#troubleshooting)
|
|
31
|
+
- [Implementation boundaries](#implementation-boundaries)
|
|
32
|
+
|
|
33
|
+
## The operating model
|
|
34
|
+
|
|
35
|
+
Guard separates four concerns:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
Facts → Policy → Verification → Decision
|
|
39
|
+
AST contracts changed diff pass / fail
|
|
40
|
+
files rules impact paths warning
|
|
41
|
+
Git baseline project tools needs-review
|
|
42
|
+
graph conventions adapters not-configured
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Facts
|
|
46
|
+
|
|
47
|
+
Facts are discovered from the working tree and are not architectural guesses. Depending on the
|
|
48
|
+
project, the model includes:
|
|
49
|
+
|
|
50
|
+
- files, source files, tests, configs, schemas, dependencies, workspaces, and scripts;
|
|
51
|
+
- TypeScript/JavaScript AST modules, imports, resolved imports, calls, and dependency graph edges;
|
|
52
|
+
- Next.js routes and route methods, React client components, server actions, and API boundaries;
|
|
53
|
+
- detected capabilities such as persistence, identity, payments, email, AI, jobs, storage,
|
|
54
|
+
observability, GraphQL/RPC, i18n, deployment, webhooks, cache, analytics, search, and content;
|
|
55
|
+
- environment references, Git state, changed files, history snapshots, cycles, layer edges,
|
|
56
|
+
hotspots, boundaries, and impact paths;
|
|
57
|
+
- evidence-based patterns and signals. A capability or pattern is reported with evidence and is
|
|
58
|
+
not automatically treated as a mandatory architecture.
|
|
59
|
+
|
|
60
|
+
### Policy
|
|
61
|
+
|
|
62
|
+
Policy is the part the project explicitly accepts. It is stored in Guard state and may contain:
|
|
63
|
+
|
|
64
|
+
- active or proposed rules;
|
|
65
|
+
- contracts describing project-specific boundaries and required calls;
|
|
66
|
+
- conventions and architecture memory generated from observed evidence;
|
|
67
|
+
- a baseline of findings that existed before Guard was enabled.
|
|
68
|
+
- optional scoped budgets for explicitly selected risk boundaries;
|
|
69
|
+
|
|
70
|
+
Guard does not assume that every project must have `UI → actions → services → repositories → DB`.
|
|
71
|
+
That shape may be discovered as evidence, proposed for review, and accepted only by a developer.
|
|
72
|
+
|
|
73
|
+
### Verification and decision
|
|
74
|
+
|
|
75
|
+
Verification evaluates the current working tree or a diff. It can check Guard policy, configured
|
|
76
|
+
project scripts, detected external-tool adapters, runtime compatibility, and contract validity.
|
|
77
|
+
The normalized result is one of:
|
|
78
|
+
|
|
79
|
+
| Outcome | Meaning |
|
|
80
|
+
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
|
|
81
|
+
| `pass` | No blocking Guard or configured verification failure. |
|
|
82
|
+
| `fail` | A blocking finding, invalid contract, failed command, incompatible runtime, or strict missing tool exists. |
|
|
83
|
+
| `warning` | No blocking failure, but warnings were found. |
|
|
84
|
+
| `needs-review` | Deterministic context is ready for semantic AI review. |
|
|
85
|
+
| `not-configured` | The project has not been initialized or the requested state is unavailable. |
|
|
86
|
+
|
|
87
|
+
Command-specific `status` fields may still exist for compatibility with that command. Consumers
|
|
88
|
+
that need one common decision should use `outcome`.
|
|
89
|
+
|
|
90
|
+
## Install and initialize
|
|
91
|
+
|
|
92
|
+
Install Guard as a development dependency so local and CI versions are reproducible:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pnpm add -D @codapult/guard
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Run commands from the project root. Guard finds the nearest directory containing `.git`,
|
|
99
|
+
`package.json`, `tsconfig.json`, or `jsconfig.json`.
|
|
100
|
+
|
|
101
|
+
Initialize once:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
pnpm exec codapult-guard init
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Initialization:
|
|
108
|
+
|
|
109
|
+
1. discovers the current project model;
|
|
110
|
+
2. writes project, architecture, convention, proposal, contract, and agent artifacts;
|
|
111
|
+
3. generates evidence-based proposed rules and contracts;
|
|
112
|
+
4. records current findings in the baseline;
|
|
113
|
+
5. adds generated Guard state to the existing formatter ignore file when supported.
|
|
114
|
+
|
|
115
|
+
Initialization is protected. If a baseline already exists, the command stops instead of silently
|
|
116
|
+
changing project memory. Use `--force` only when intentionally replacing the Guard state:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pnpm exec codapult-guard init --force
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`--force` is a new baseline decision, not a routine refresh operation. Review and commit the
|
|
123
|
+
result deliberately.
|
|
124
|
+
|
|
125
|
+
## The generated state
|
|
126
|
+
|
|
127
|
+
Guard stores its project memory under `.codapult/guard/`:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
.codapult/
|
|
131
|
+
└── guard/
|
|
132
|
+
├── agent.json
|
|
133
|
+
├── architecture.json
|
|
134
|
+
├── baseline.json
|
|
135
|
+
├── baseline-meta.json
|
|
136
|
+
├── cache.json
|
|
137
|
+
├── conventions.json
|
|
138
|
+
├── contracts.json
|
|
139
|
+
├── history/
|
|
140
|
+
├── project.json
|
|
141
|
+
├── proposals.json
|
|
142
|
+
└── rules.json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Guard refuses to create or update state when `.codapult` or `.codapult/guard` is a symbolic link.
|
|
146
|
+
This keeps generated state inside the selected project root.
|
|
147
|
+
|
|
148
|
+
| File | Purpose |
|
|
149
|
+
| -------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
150
|
+
| `project.json` | Persisted discovered project model: files, modules, dependencies, routes, capabilities, patterns, Git data, and insights. |
|
|
151
|
+
| `architecture.json` | Human/agent-readable architecture memory derived from observed project facts. |
|
|
152
|
+
| `conventions.json` | Observed conventions and recurring project patterns. |
|
|
153
|
+
| `rules.json` | Guard rules, optional scoped budgets, and approval policy. Active items are enforced; proposed items are not. |
|
|
154
|
+
| `contracts.json` | Project-specific guidance, import boundaries, and required-call contracts. |
|
|
155
|
+
| `proposals.json` | Evidence, confidence, questions, and approval/rejection history for proposed policy. |
|
|
156
|
+
| `baseline.json` | Fingerprints of accepted pre-existing findings. Baseline suppression is fingerprint-based. |
|
|
157
|
+
| `baseline-meta.json` | Metadata describing the baseline and its project snapshot. |
|
|
158
|
+
| `waivers.json` | Time-bounded, owner-attributed exceptions for active findings. |
|
|
159
|
+
| `agent.json` | Host-facing completion-gate and external-tool policy. It does not execute an LLM. |
|
|
160
|
+
| `cache.json` | Optional discovery cache. Unchanged AST modules can be reused by content hash. |
|
|
161
|
+
| `history/` | Project model snapshots, history diffs, and local verification run manifests. |
|
|
162
|
+
|
|
163
|
+
Discovery is bounded by default to 100,000 files and 25 MiB per file. These limits prevent an
|
|
164
|
+
accidental scan of build artifacts or unusually large inputs from exhausting local resources.
|
|
165
|
+
Use the public discovery API options `maxFiles` and `maxFileBytes` to raise them deliberately after
|
|
166
|
+
configuring the project's ignore boundaries.
|
|
167
|
+
|
|
168
|
+
Keep the policy and memory files under version control when the team wants shared architecture
|
|
169
|
+
guardrails. Treat `cache.json` as disposable implementation cache if the team does not want it
|
|
170
|
+
committed. Never commit secrets; Guard excludes common secret files from review input.
|
|
171
|
+
|
|
172
|
+
## The daily workflow
|
|
173
|
+
|
|
174
|
+
The normal loop is:
|
|
175
|
+
|
|
176
|
+
```text
|
|
177
|
+
init once → edit → check --changed → review → verify → commit / merge
|
|
178
|
+
↘ analyze after structural changes
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### During a task
|
|
182
|
+
|
|
183
|
+
Run the fast architecture gate on changed and untracked source files:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
pnpm exec codapult-guard check --changed
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
This compares new findings with the baseline. It does not require the team to repair every old
|
|
190
|
+
finding immediately.
|
|
191
|
+
|
|
192
|
+
### Before completion or merge
|
|
193
|
+
|
|
194
|
+
Run the unified gate:
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
pnpm exec codapult-guard verify
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
By default, `verify` combines Guard checks with the configured completion-gate checks (`lint`,
|
|
201
|
+
`typecheck`, `test`, and `build`) and detected external adapters. To run only Guard's own checks:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
pnpm exec codapult-guard verify --no-project-checks
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Use `--checks lint,typecheck,test` to select project commands for one invocation. Use
|
|
208
|
+
`--tools auto|on|off` to control external adapters. `auto` is the default and only runs adapters
|
|
209
|
+
whose matching project scripts exist; `on` also reports missing adapters; `off` skips them.
|
|
210
|
+
|
|
211
|
+
### When the project structure changes
|
|
212
|
+
|
|
213
|
+
Refresh persisted project memory without changing the baseline:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
pnpm exec codapult-guard analyze
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Use this after adding a package, moving modules, changing routes/configuration, changing a
|
|
220
|
+
workspace, or introducing a new capability. Do not run `init` after every edit. `check`, `review`,
|
|
221
|
+
`verify`, and refreshed MCP context discover the current working tree themselves.
|
|
222
|
+
|
|
223
|
+
### Periodic maintenance
|
|
224
|
+
|
|
225
|
+
See all current findings, including baseline-suppressed findings:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
pnpm exec codapult-guard audit
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Inspect Guard state and missing artifacts:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
pnpm exec codapult-guard doctor
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Policy scope and state changes
|
|
238
|
+
|
|
239
|
+
Guard keeps one project policy, and each policy item can be scoped to the boundary it protects:
|
|
240
|
+
|
|
241
|
+
| Policy item | Scope controls |
|
|
242
|
+
| ----------- | ---------------------------------------------------------------------- |
|
|
243
|
+
| Rule | `files`, import patterns, and deterministic rule kind |
|
|
244
|
+
| Contract | `scope`, `entrypoints`, import/package constraints, and required calls |
|
|
245
|
+
| Budget | `scope`, metric, limit, severity, and written reason |
|
|
246
|
+
| Baseline | Exact finding fingerprints accepted as legacy debt |
|
|
247
|
+
| Waiver | One active finding fingerprint, owner, reason, and expiry |
|
|
248
|
+
|
|
249
|
+
The normal verification path does not change source code or approved policy. The operations below
|
|
250
|
+
have explicit state-changing behavior:
|
|
251
|
+
|
|
252
|
+
| Operation | Reads | Writes | Policy effect |
|
|
253
|
+
| --------------------------------------------- | --------------------------------- | -------------------------------------------- | ----------------------------------------------- |
|
|
254
|
+
| `check`, `audit`, `review`, `impact` | Project and Guard state | Output only | None |
|
|
255
|
+
| `verify` | Project and Guard state | Local run manifest; runs configured commands | None |
|
|
256
|
+
| `analyze` | Project source and Git state | Derived facts and snapshot | Does not change baseline or policy |
|
|
257
|
+
| `init` | Project source and Git state | Initial Guard state | Creates the initial baseline |
|
|
258
|
+
| `propose` | Project source and policy | Optional proposal file | Proposals are not active policy |
|
|
259
|
+
| `rules approve` / `contracts approve\|reject` | Policy and proposal state | Policy and decision history | Activates rules; activates or rejects contracts |
|
|
260
|
+
| `baseline accept\|remove` | Current findings and baseline | Baseline and decision history | Changes legacy-debt suppression |
|
|
261
|
+
| `waiver add\|renew\|remove` | Current findings and waiver state | Waivers and decision history | Changes a temporary exception |
|
|
262
|
+
|
|
263
|
+
`check` and MCP `codapult_guard_check` scan the full current project unless changed-only mode is
|
|
264
|
+
requested. `check --changed`, `verify --changed`, and MCP `changed_only: true` scope deterministic
|
|
265
|
+
findings to changed files; `review` is changed-only by default and also includes impact evidence.
|
|
266
|
+
`audit` intentionally ignores baseline suppression so maintenance can see the complete current debt.
|
|
267
|
+
|
|
268
|
+
Guard fails closed when `rules.json` or `contracts.json` is malformed: `verify` returns a structured
|
|
269
|
+
failure and CLI checks do not treat corrupted policy as an uninitialized project. Repair the file
|
|
270
|
+
or review the diagnosis before using `init --force`.
|
|
271
|
+
|
|
272
|
+
CLI and MCP expose the same structured error payload for `GUARD_NOT_CONFIGURED`,
|
|
273
|
+
`GUARD_CONFIG_INVALID`, and retryable `GUARD_STATE_BUSY` concurrent-write conflicts.
|
|
274
|
+
Malformed `agent.json`, `proposals.json`, and `baseline.json` are also rejected instead of being
|
|
275
|
+
silently replaced with defaults or an empty state.
|
|
276
|
+
|
|
277
|
+
Guard state writes use a root-level transaction lock with atomic rename. The lock records PID,
|
|
278
|
+
hostname, command, token, and lease metadata. Writers wait with bounded backoff by default; use
|
|
279
|
+
`init --no-wait` or `analyze --no-wait` for an immediate retryable `GUARD_STATE_BUSY` result.
|
|
280
|
+
If the recorded PID is no longer alive, the orphaned lock is recovered. Age alone is used only for
|
|
281
|
+
malformed legacy locks, so a long-running live process is not interrupted.
|
|
282
|
+
|
|
283
|
+
Derived facts are committed as one generation bundle under `state/generations/` and selected by an
|
|
284
|
+
atomic `state/current.json` pointer. The root-level JSON files remain compatibility mirrors. Policy
|
|
285
|
+
writes carry a revision and reject stale writers with `GUARD_STATE_STALE` instead of silently
|
|
286
|
+
overwriting a newer policy.
|
|
287
|
+
|
|
288
|
+
Policy activation also uses a small local transaction journal. If the process stops between writing
|
|
289
|
+
the policy and its proposal decision history, the next Guard read repairs both artifacts from the
|
|
290
|
+
journal before continuing. The journal is local recovery metadata, not a distributed transaction
|
|
291
|
+
system; Git/CI remains the source of truth for collaboration and protected review.
|
|
292
|
+
|
|
293
|
+
Compare persisted project states:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
pnpm exec codapult-guard history
|
|
297
|
+
pnpm exec codapult-guard history-diff <from> <to>
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Command reference
|
|
301
|
+
|
|
302
|
+
All commands return a non-zero exit code when their decision is blocking. Add `--json` where the
|
|
303
|
+
command supports it for automation.
|
|
304
|
+
|
|
305
|
+
| Command | Use |
|
|
306
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------- |
|
|
307
|
+
| `codapult-guard init [--no-wait]` | Create Guard state and establish the initial baseline. Refuses an existing baseline. |
|
|
308
|
+
| `codapult-guard init --force [--no-wait]` | Replace existing Guard state intentionally. |
|
|
309
|
+
| `codapult-guard analyze [--refresh] [--no-wait]` | Refresh persisted discovery, architecture, conventions, and snapshot. Does not alter baseline. |
|
|
310
|
+
| `codapult-guard propose` | Generate evidence-based rules/contracts for review. Does not activate them. |
|
|
311
|
+
| `codapult-guard doctor [--fix-cache]` | Diagnose state; optionally remove the disposable discovery cache. |
|
|
312
|
+
| `codapult-guard history` | List persisted project snapshots. |
|
|
313
|
+
| `codapult-guard runs` | List local verification runs and outcome/latency summary. |
|
|
314
|
+
| `codapult-guard history-diff <from> <to>` | Compare files, modules, dependencies, capabilities, graph edges, and cycles. |
|
|
315
|
+
| `codapult-guard impact <files...>` | Explain direct/transitive dependencies, dependents, capabilities, and relevant contracts. |
|
|
316
|
+
| `codapult-guard policy explain <id>` | Explain an active or proposed rule/contract, its evidence, and approval history. |
|
|
317
|
+
| `codapult-guard check [--changed]` | Enforce active Guard rules/contracts; `--changed` limits findings to changed and untracked files. |
|
|
318
|
+
| `codapult-guard audit` | Run a full current Guard scan without baseline suppression and validate policy definitions. |
|
|
319
|
+
| `codapult-guard review` | Produce a bounded diff + project-context packet for semantic AI review. |
|
|
320
|
+
| `codapult-guard review --base origin/main` | Build the review packet from a PR base ref. |
|
|
321
|
+
| `codapult-guard verify` | Run Guard, project checks, adapters, runtime, and contract verification as configured. |
|
|
322
|
+
| `codapult-guard governance [--json] [--strict]` | Audit declared proposal/approval provenance and links from decisions to verification runs. |
|
|
323
|
+
| `codapult-guard rules approve <ids>` | Activate selected proposed rules. |
|
|
324
|
+
| `codapult-guard rules approve --all` | Activate every proposed rule deliberately. |
|
|
325
|
+
| `codapult-guard contracts approve <ids>` | Activate selected proposed contracts. |
|
|
326
|
+
| `codapult-guard contracts reject <ids>` | Record rejection for selected proposed contracts. |
|
|
327
|
+
| `codapult-guard baseline accept\|remove <ids>` | Add or remove baseline fingerprints; a written reason is required. |
|
|
328
|
+
| `codapult-guard waiver add\|renew\|remove` | Manage owner-attributed, time-bounded exceptions to exact finding fingerprints. |
|
|
329
|
+
| `codapult-guard install-agent <target>` | Add or update a managed Guard instruction block for an AI host. |
|
|
330
|
+
|
|
331
|
+
`codapult-guard review` does not call an LLM. It creates input for one. A review packet includes changed
|
|
332
|
+
files, typed file changes, a bounded/redacted diff, project model, contracts, deterministic
|
|
333
|
+
findings, and review instructions. It also includes directional impact: the changed modules'
|
|
334
|
+
dependencies, transitive dependents, affected capabilities, impact paths, relevant contracts,
|
|
335
|
+
and graph edges. If the Git base is invalid, the packet contains `diffError` and has a failing
|
|
336
|
+
outcome.
|
|
337
|
+
|
|
338
|
+
`changes` distinguishes `added`, `modified`, `deleted`, and `renamed` paths. Deleted and renamed
|
|
339
|
+
paths are still checked against the repository root safely; they are not silently discarded just
|
|
340
|
+
because the old file no longer exists.
|
|
341
|
+
|
|
342
|
+
Manage baseline entries without rebuilding the entire project state:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
pnpm exec codapult-guard baseline list
|
|
346
|
+
pnpm exec codapult-guard baseline accept <fingerprint> --reason "Accepted legacy boundary"
|
|
347
|
+
pnpm exec codapult-guard baseline remove <fingerprint> --reason "Fixed in the current architecture"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Use `--all` only as an explicit decision. `baseline accept --all` accepts all findings from the
|
|
351
|
+
current full scan; `baseline remove --all` removes fingerprints represented by the current scan.
|
|
352
|
+
Each update preserves a decision record in `baseline-meta.json`. A written `--reason` is required
|
|
353
|
+
for every manual baseline add or remove; initialization is the only operation that may create the
|
|
354
|
+
initial baseline without a manual reason.
|
|
355
|
+
|
|
356
|
+
### Fingerprint stability
|
|
357
|
+
|
|
358
|
+
Finding fingerprints intentionally omit line numbers. Formatting, whitespace changes, and moving a
|
|
359
|
+
violation to another line therefore do not recreate the same finding. A fingerprint includes the
|
|
360
|
+
rule or contract identity and the affected file/import identity. Renaming or moving a module can
|
|
361
|
+
therefore produce a new fingerprint; inspect that result and accept it explicitly when the move is
|
|
362
|
+
intentional. Guard does not silently transfer a baseline entry between files.
|
|
363
|
+
|
|
364
|
+
### Temporary waivers
|
|
365
|
+
|
|
366
|
+
Use a waiver for a known, temporary exception to an active rule or contract. Do not use it to
|
|
367
|
+
replace baseline management or to create a broad path-level exemption. A waiver is tied to one
|
|
368
|
+
finding fingerprint and requires an owner, reason, creation time, and expiry time:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
pnpm exec codapult-guard waiver add <fingerprint> \
|
|
372
|
+
--owner platform-team \
|
|
373
|
+
--reason "Migration in progress" \
|
|
374
|
+
--expires 2026-12-28 \
|
|
375
|
+
--issue https://github.com/example/project/issues/123
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Use `waiver list`, `waiver renew`, and `waiver remove` to manage the lifecycle. The default warning
|
|
379
|
+
window is 14 days before expiry. Active waivers suppress only their exact fingerprint and remain
|
|
380
|
+
visible in reports. Expired waivers no longer suppress findings. `check`, `audit`, and `verify`
|
|
381
|
+
reports, review packets, the `codapult_guard_waivers` MCP tool, and the `codapult://guard/waivers` resource
|
|
382
|
+
expose waiver state. Protected policy can require approval outside MCP.
|
|
383
|
+
|
|
384
|
+
Projects may cap the duration of each newly added or renewed waiver without imposing a global
|
|
385
|
+
expiry policy:
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"waiverPolicy": {
|
|
390
|
+
"warningDays": 14,
|
|
391
|
+
"maxDays": 90
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
`maxDays` limits the requested lifetime from the time of the add or renew operation. It is an
|
|
397
|
+
optional governance control; omit it when the project wants explicit, owner-reviewed expiry dates
|
|
398
|
+
without a fixed maximum. Boundary violations reported by Guard remain blocking when their finding
|
|
399
|
+
severity is `error`; warnings and expiry reminders are advisory.
|
|
400
|
+
|
|
401
|
+
`codapult-guard doctor` also reports explicitly downgraded client, import, or package boundaries as
|
|
402
|
+
warnings. It does not change their configured severity; the project owner decides whether the
|
|
403
|
+
boundary should become blocking.
|
|
404
|
+
|
|
405
|
+
### Scoped budgets
|
|
406
|
+
|
|
407
|
+
Budgets are optional policy for a specific risk boundary, not a global file-size rule. They support
|
|
408
|
+
`lines`, `bytes`, and `imports` and require a non-empty scope, limit, severity, and reason:
|
|
409
|
+
|
|
410
|
+
```json
|
|
411
|
+
{
|
|
412
|
+
"budgets": [
|
|
413
|
+
{
|
|
414
|
+
"id": "service-lines",
|
|
415
|
+
"description": "Services must remain reviewable.",
|
|
416
|
+
"metric": "lines",
|
|
417
|
+
"scope": ["src/services"],
|
|
418
|
+
"limit": 300,
|
|
419
|
+
"severity": "warning",
|
|
420
|
+
"reason": "Keep service changes reviewable by one owner.",
|
|
421
|
+
"status": "active"
|
|
422
|
+
}
|
|
423
|
+
]
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Use budgets only where size or dependency count is evidence of a concrete project risk. Do not
|
|
428
|
+
apply them indiscriminately to generated code, schemas, migrations, localization files, or UI
|
|
429
|
+
composition. Explicitly scoped generated files and schemas are supported, but invalid, absolute,
|
|
430
|
+
parent-directory, or nonexistent scopes fail the Guard gate. Guard does not automatically invent
|
|
431
|
+
budgets during `init`.
|
|
432
|
+
|
|
433
|
+
## Rules, contracts, and proposals
|
|
434
|
+
|
|
435
|
+
### Rules
|
|
436
|
+
|
|
437
|
+
Rules are deterministic checks. The current rule kinds are:
|
|
438
|
+
|
|
439
|
+
```json
|
|
440
|
+
{
|
|
441
|
+
"id": "no-client-db",
|
|
442
|
+
"description": "Client modules must not import the database adapter.",
|
|
443
|
+
"severity": "error",
|
|
444
|
+
"kind": "client-forbidden-import",
|
|
445
|
+
"patterns": ["@/lib/db", "drizzle-orm"],
|
|
446
|
+
"files": ["src/components"],
|
|
447
|
+
"status": "active",
|
|
448
|
+
"confidence": "high",
|
|
449
|
+
"evidence": ["src/components/ExistingClient.tsx"]
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Use an existing specialist tool for generic syntax/style/type rules. Guard rules should express
|
|
454
|
+
project-specific boundaries and architectural invariants, not duplicate ESLint or TypeScript.
|
|
455
|
+
|
|
456
|
+
### Contracts
|
|
457
|
+
|
|
458
|
+
Contracts express intent and boundaries that are meaningful in this project. Supported contract
|
|
459
|
+
kinds are:
|
|
460
|
+
|
|
461
|
+
- `guidance`: a statement, optional guidance, and references for an AI reviewer;
|
|
462
|
+
- `import-boundary`: modules must or must not import specified patterns;
|
|
463
|
+
- `required-call`: an entrypoint must call one of the specified functions or patterns.
|
|
464
|
+
|
|
465
|
+
Example:
|
|
466
|
+
|
|
467
|
+
```json
|
|
468
|
+
{
|
|
469
|
+
"id": "server-actions-use-auth",
|
|
470
|
+
"statement": "Every billing server action authenticates the active organization.",
|
|
471
|
+
"kind": "required-call",
|
|
472
|
+
"severity": "error",
|
|
473
|
+
"scope": ["src/lib/actions/billing"],
|
|
474
|
+
"mustCall": ["requireOrganizationMember"],
|
|
475
|
+
"references": ["src/lib/auth/require-organization-member.ts"],
|
|
476
|
+
"status": "active",
|
|
477
|
+
"confidence": "high"
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
Package boundaries use workspace package names discovered from manifests. They are useful in
|
|
482
|
+
monorepos where a relative path rule would be too fragile:
|
|
483
|
+
|
|
484
|
+
```json
|
|
485
|
+
{
|
|
486
|
+
"id": "apps-cannot-import-db-package",
|
|
487
|
+
"statement": "Application packages must not import the database package directly.",
|
|
488
|
+
"kind": "package-boundary",
|
|
489
|
+
"severity": "error",
|
|
490
|
+
"fromPackages": ["@acme/web", "@acme/admin"],
|
|
491
|
+
"mustNotImportPackages": ["@acme/db"],
|
|
492
|
+
"status": "active",
|
|
493
|
+
"confidence": "high"
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
`verify` also returns an impact analysis: changed modules, direct dependencies, transitive
|
|
498
|
+
dependents, affected capabilities, and relevant contracts. This is evidence for review, not an
|
|
499
|
+
automatic claim that every dependent needs modification. `check --changed` includes changed files
|
|
500
|
+
and their transitive dependents so a changed implementation cannot bypass an unchanged entrypoint
|
|
501
|
+
contract.
|
|
502
|
+
|
|
503
|
+
Rule scopes, contract paths, and budget scopes are repository-relative paths. Guard rejects
|
|
504
|
+
absolute paths, `..` traversal, and symlinks that resolve outside the project root. Rule scopes may
|
|
505
|
+
target future files, while contract and budget scopes must still exist. `verify` and `audit` validate
|
|
506
|
+
these paths and policy definitions before scanning. A stale or unsafe policy is a policy problem,
|
|
507
|
+
not a source-code finding, and causes verification to fail.
|
|
508
|
+
|
|
509
|
+
Import-boundary contracts cover static imports, re-exports, and literal dynamic imports. Repeated
|
|
510
|
+
references to the same module are deduplicated into one finding. When TypeScript resolves an alias
|
|
511
|
+
or re-export, findings retain the original import specifier and expose the resolved project file as
|
|
512
|
+
`resolvedPath`, so an agent can repair the actual boundary without losing source context.
|
|
513
|
+
|
|
514
|
+
### Proposals and approval
|
|
515
|
+
|
|
516
|
+
Generate proposals after initialization or a structural change:
|
|
517
|
+
|
|
518
|
+
```bash
|
|
519
|
+
pnpm exec codapult-guard propose --json
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
The proposal includes evidence, confidence, questions, and a freshness marker. Review every
|
|
523
|
+
proposal against the actual code. Activate only the decisions the project wants to preserve:
|
|
524
|
+
|
|
525
|
+
```bash
|
|
526
|
+
pnpm exec codapult-guard rules approve no-client-db
|
|
527
|
+
pnpm exec codapult-guard contracts approve server-actions-use-auth
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Proposals become stale when the project changes. Regenerate them rather than approving a proposal
|
|
531
|
+
based on old evidence. The CLI and MCP proposal paths protect activation and preserve decision
|
|
532
|
+
history; the AI must not activate policy silently.
|
|
533
|
+
|
|
534
|
+
### Approval trust modes
|
|
535
|
+
|
|
536
|
+
The default policy is local mode. `confirm: true` or a CLI approval means that the caller
|
|
537
|
+
explicitly requested the state change; it does not prove that a human made the decision.
|
|
538
|
+
|
|
539
|
+
For agent-driven or protected workflows, configure the policy in `rules.json`:
|
|
540
|
+
|
|
541
|
+
```json
|
|
542
|
+
{
|
|
543
|
+
"approval": {
|
|
544
|
+
"mode": "protected",
|
|
545
|
+
"allowMcpApproval": false,
|
|
546
|
+
"requireDistinctActor": true
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
In protected mode, MCP can inspect and propose policy but cannot approve it. Approval must go
|
|
552
|
+
through the CLI or an external protected review process such as branch protection. Decision
|
|
553
|
+
records include the proposal fingerprint, current commit when available, source (`cli`, `mcp`, or
|
|
554
|
+
`external`), and optional `GUARD_APPROVER` metadata. When `requireDistinctActor` is enabled, CLI
|
|
555
|
+
and permitted MCP approvals require `GUARD_APPROVER`; if the proposal declares `generatedBy` via
|
|
556
|
+
`GUARD_PROPOSER`, Guard rejects the same declared actor approving it. These environment variables
|
|
557
|
+
are declared provenance, not cryptographic identity verification; reviewer permissions belong to
|
|
558
|
+
the host CI/review system.
|
|
559
|
+
|
|
560
|
+
This separation is intentional: Guard checks that an approval matches the current evidence, while
|
|
561
|
+
GitHub or another protected system determines who is authorized to approve it.
|
|
562
|
+
|
|
563
|
+
See [Policy mutation control](policy-mutations.md) for the machine-readable mutation contract and
|
|
564
|
+
the host/CI command boundary that prevents an agent from granting itself a waiver or replacing a
|
|
565
|
+
baseline.
|
|
566
|
+
|
|
567
|
+
### Policy provenance in CI
|
|
568
|
+
|
|
569
|
+
`verify` normally reads policy from the working tree. For pull requests, pass the protected base
|
|
570
|
+
commit:
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
codapult-guard verify --policy-base "$BASE_SHA" --json
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
The base snapshot includes `rules.json`, `contracts.json`, `baseline.json`, `waivers.json`, and
|
|
577
|
+
`agent.json` when present. Guard uses that snapshot for the verdict and records its revision and
|
|
578
|
+
effective fingerprint in the run result and local run manifest. The result also reports whether
|
|
579
|
+
the branch changed the policy relative to the base.
|
|
580
|
+
|
|
581
|
+
Use `--fail-on-policy-change` for a dedicated policy gate. Repository hosting controls such as
|
|
582
|
+
CODEOWNERS and protected branches remain responsible for requiring and authorizing the separate
|
|
583
|
+
review; Guard does not impersonate a reviewer or verify provider credentials.
|
|
584
|
+
|
|
585
|
+
Guard also compares verification-sensitive paths against the base. Built-in paths include CI
|
|
586
|
+
workflows, CODEOWNERS, package manifests and lockfiles, and common formatter, linter, typecheck,
|
|
587
|
+
and test configuration. Add project-specific globs to `protectedPaths` in the base revision's
|
|
588
|
+
`.codapult/guard/rules.json`. The `--fail-on-protected-changes` option requires `--policy-base`
|
|
589
|
+
and fails if a listed non-workflow path changes, or if a changed contracted workflow fails its
|
|
590
|
+
CI integrity checks. JSON output lists the matched paths and reports whether a workflow changed.
|
|
591
|
+
|
|
592
|
+
For an explicit and classified policy surface, configure `policySurface.paths` in that same base
|
|
593
|
+
policy. Each entry has a repository-relative `pattern`, a `kind` (`ci-workflow`, `guard-policy`, `ownership`,
|
|
594
|
+
`dependency-input`, `tool-config`, `ignore-config`, `suppression-source`, or `custom`), and a
|
|
595
|
+
`severity` (`error` or `warning`). Error entries block when `--fail-on-protected-changes` is set;
|
|
596
|
+
warning entries are reported without blocking. The legacy `protectedPaths` list remains supported
|
|
597
|
+
and maps to blocking custom entries. Built-in sensitive paths cannot be downgraded by project
|
|
598
|
+
configuration. Entries and match details are included in the JSON result and receipt.
|
|
599
|
+
|
|
600
|
+
The same option reports added `eslint-disable`, `@ts-ignore`, `@ts-nocheck`, `@ts-expect-error`,
|
|
601
|
+
`biome-ignore`, and `prettier-ignore` markers in the PR diff. Guard identifies markers but leaves
|
|
602
|
+
their semantics to the relevant tool. Changes to or removal of the workflow itself still require
|
|
603
|
+
host-enforced required checks and protected review; a workflow cannot guarantee its own integrity.
|
|
604
|
+
The supplied workflow template also rejects PR changes to package manifests, common npm/pnpm/Yarn/Bun
|
|
605
|
+
lockfiles, package-manager configuration, and workspace install inputs before setting up pnpm or installing
|
|
606
|
+
dependencies. Handle those changes in a separate reviewed PR. This does not replace protecting the
|
|
607
|
+
workflow in repository settings.
|
|
608
|
+
|
|
609
|
+
### Required stages and CI integrity
|
|
610
|
+
|
|
611
|
+
`agent.json` can list required stages in `completionGate.requiredStages`. Supported values are
|
|
612
|
+
`runtime`, `project-checks`, `adapters`, `architecture-policy`, `policy-surface`, `ci-integrity`, and
|
|
613
|
+
`verification-scope`. The compatibility default requires only `architecture-policy`; skipped required
|
|
614
|
+
stages produce `incomplete`, a nonzero CLI exit, and a list in the receipt. Using a base policy
|
|
615
|
+
automatically requires the policy-surface comparison. Declaring a GitHub Actions integrity
|
|
616
|
+
contract automatically requires the CI audit. Verification scope is always required: Guard hashes
|
|
617
|
+
discovered project files and changed paths before running checks, then verifies that the scope
|
|
618
|
+
remained stable through the run.
|
|
619
|
+
|
|
620
|
+
For GitHub Actions, `rules.json` may declare exact workflow paths, a required job, required command
|
|
621
|
+
fragments, expected dependencies, permission ceilings, and whether external actions must use full
|
|
622
|
+
commit SHA pins. Guard reads this contract and the base workflow from the base policy revision for
|
|
623
|
+
PR verification. It compares action refs with that base and classifies additions, removals, or SHA
|
|
624
|
+
changes as `policy-weakened` for separate review, even if the new ref is pinned. It classifies
|
|
625
|
+
missing protections as `policy-weakened` and unreadable or invalid workflow data as `incomplete`.
|
|
626
|
+
It does not evaluate arbitrary GitHub expressions or verify repository settings, so branch
|
|
627
|
+
protection or rulesets must still require the status check from the expected source.
|
|
628
|
+
The audit rejects `pull_request_target` on a contracted verification workflow because Guard cannot
|
|
629
|
+
prove that it never executes untrusted PR content with that event's elevated context.
|
|
630
|
+
Local actions cannot use immutable commit SHA references. If the workflow contract disables
|
|
631
|
+
`requireFullShaActions` to permit them, add each local action's source directory to `protectedPaths`
|
|
632
|
+
in the base policy so a PR cannot change the code being invoked.
|
|
633
|
+
The receipt records the effective Guard invocation and project check commands/arguments, with
|
|
634
|
+
credential-like values redacted.
|
|
635
|
+
|
|
636
|
+
The receipt's `verificationScope` contains SHA-256 hashes and paths for files discovered by Guard,
|
|
637
|
+
plus changed and deleted paths. Its fingerprint binds the inventory to the effective policy and
|
|
638
|
+
Guard version. If a path cannot be hashed or the inventory changes during verification, the
|
|
639
|
+
`verification-scope` stage is incomplete and the overall result cannot pass. The receipt includes
|
|
640
|
+
hashes and paths but no source contents; it is not signed and does not prove who ran Guard.
|
|
641
|
+
|
|
642
|
+
### Exporting and signing a verification attestation
|
|
643
|
+
|
|
644
|
+
`verify --attestation-out <file>` writes a versioned in-toto Statement containing the verification
|
|
645
|
+
receipt. It is emitted only when the result is `pass` and the scope is complete and stable. The
|
|
646
|
+
Statement subject digest is the SHA-256 fingerprint of the verified content and policy scope; its
|
|
647
|
+
predicate embeds the receipt, including per-file digests, policy fingerprint, base commit, Guard
|
|
648
|
+
version, and result. The in-toto `predicateType` URI versions the predicate schema independently
|
|
649
|
+
from the receipt's numeric `version` field. Consumers should reject unsupported versions rather than
|
|
650
|
+
guessing how to interpret them.
|
|
651
|
+
|
|
652
|
+
On GitHub pull request events, the receipt also records `headSha` and `baseSha` from the event
|
|
653
|
+
payload. `mergeSha` is recorded only when `GITHUB_SHA` identifies the checked-out merge result rather
|
|
654
|
+
than the PR head. These commit identifiers describe the hosting event context; the content
|
|
655
|
+
fingerprint remains authoritative for the exact files and policy Guard hashed. The output contains
|
|
656
|
+
paths and hashes, not file contents. The supplied [CI template](guard-ci.yml) exports and uploads
|
|
657
|
+
this unsigned statement alongside the JSON receipt when verification passes.
|
|
658
|
+
|
|
659
|
+
Guard does not sign the Statement. Signing stays in CI so Guard needs no signing key or Sigstore
|
|
660
|
+
dependency. The in-toto Statement format does not require GitHub or Sigstore: another CI system can
|
|
661
|
+
sign or attest the same exported file with its own trusted mechanism. The workflow below is a
|
|
662
|
+
GitHub-specific integration example; its signature verification commands and trust checks apply to
|
|
663
|
+
GitHub artifact attestations. For another CI provider, configure its signer and verifier to bind the
|
|
664
|
+
statement digest to the expected repository, workflow identity, source revision, and Guard receipt.
|
|
665
|
+
|
|
666
|
+
#### Install the trusted GitHub Actions workflow
|
|
667
|
+
|
|
668
|
+
The [trusted PR workflow template](guard-trusted-pr-attestation.yml) independently runs Guard in a
|
|
669
|
+
workflow triggered by completion of the ordinary `Guard` workflow. It does not consume artifacts
|
|
670
|
+
from that run. It first validates that the event identifies exactly one PR and compares the head and
|
|
671
|
+
base repository names. For same-repository PRs, it checks out the PR head, fetches the exact base
|
|
672
|
+
commit, installs a fixed Guard version with lifecycle scripts disabled, runs Guard without project
|
|
673
|
+
checks, checks that the receipt matches the PR head and base SHAs, and signs the statement in a
|
|
674
|
+
separate job.
|
|
675
|
+
|
|
676
|
+
This attestation covers **Guard's architecture and policy verification only**. The template skips
|
|
677
|
+
project checks and does not attest the result of tests, builds, deployments, or other jobs in the
|
|
678
|
+
ordinary workflow. It also does not inspect or require that workflow's conclusion. Keep the normal
|
|
679
|
+
Guard workflow as a required PR check; configure other required checks separately.
|
|
680
|
+
|
|
681
|
+
Requirements:
|
|
682
|
+
|
|
683
|
+
- GitHub Actions is enabled, and the repository or organization policy permits artifact attestations
|
|
684
|
+
and the permissions declared in the template (`id-token: write`, `attestations: write`, and
|
|
685
|
+
`artifact-metadata: write` in the signer job).
|
|
686
|
+
- GitHub artifact attestations are available for public repositories on current GitHub plans. Private
|
|
687
|
+
and internal repositories require GitHub Enterprise Cloud; GitHub Enterprise Server is not
|
|
688
|
+
supported by `actions/attest`. Check the current
|
|
689
|
+
[actions/attest support requirements](https://github.com/actions/attest#readme) for plan changes.
|
|
690
|
+
- The repository has Guard initialized and its protected base revision contains a valid Guard policy.
|
|
691
|
+
- The ordinary pull request workflow is named exactly `Guard` and runs for `pull_request` events. If
|
|
692
|
+
you use a different workflow name, update `workflow_run.workflows` in the template to match it.
|
|
693
|
+
- A Guard release tag is available that records PR context for `workflow_run` events. Configure
|
|
694
|
+
both its exact version and the full commit SHA of that tag; the workflow checks that they match.
|
|
695
|
+
- The trusted workflow builds Guard from that immutable source commit using its committed pnpm
|
|
696
|
+
lockfile with `--frozen-lockfile`. Lifecycle scripts are disabled during dependency installation.
|
|
697
|
+
The lockfile's package versions and integrity values pin the complete dependency graph.
|
|
698
|
+
|
|
699
|
+
Copy the template into the project and commit it on the repository's default branch:
|
|
700
|
+
|
|
701
|
+
```bash
|
|
702
|
+
mkdir -p .github/workflows
|
|
703
|
+
cp node_modules/@codapult/guard/docs/guard-trusted-pr-attestation.yml \
|
|
704
|
+
.github/workflows/guard-trusted-pr-attestation.yml
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
In **Settings → Secrets and variables → Actions → Variables**, create these repository variables:
|
|
708
|
+
|
|
709
|
+
- `CODAPULT_GUARD_VERSION`: the exact release version that includes `workflow_run` receipt support,
|
|
710
|
+
without a `v` prefix or range (for example, `0.10.0`).
|
|
711
|
+
- `CODAPULT_GUARD_COMMIT`: the full 40-character Git commit SHA that the matching `v<version>` tag
|
|
712
|
+
resolves to.
|
|
713
|
+
|
|
714
|
+
Both are non-secret values. The workflow fetches the tag from the public Guard repository, confirms
|
|
715
|
+
that it resolves to the configured SHA and that the package version matches, then installs from the
|
|
716
|
+
Guard repository's frozen pnpm lockfile. If the release tag moves or either value is wrong, the
|
|
717
|
+
workflow stops before installing or running Guard. To obtain the commit SHA for a release, fetch the
|
|
718
|
+
version tag and resolve its commit, for example:
|
|
719
|
+
`git fetch https://github.com/codapult/codapult-guard.git refs/tags/v0.10.0` followed by
|
|
720
|
+
`git rev-parse 'FETCH_HEAD^{commit}'`.
|
|
721
|
+
|
|
722
|
+
Checkout v7 blocks fork PR checkouts in `workflow_run` by default, and this template keeps that
|
|
723
|
+
protection enabled. The context job detects a fork by comparing the PR head and base repository names.
|
|
724
|
+
If the event has no associated PR, it compares the workflow run's head repository with the event's
|
|
725
|
+
base repository; only a clear repository mismatch is treated as an unattached fork. For a detected
|
|
726
|
+
fork, the `verify` and `attest` jobs are skipped before checkout, and a separate read-only job adds a
|
|
727
|
+
summary explaining that no signed attestation was created. This is an expected skip, not a Guard pass:
|
|
728
|
+
the ordinary Guard pull request check remains responsible for its own result. Fork PRs receive no
|
|
729
|
+
trusted attestation unless a future version adds a separately reviewed safe lookup and verification
|
|
730
|
+
path. Missing or ambiguous PR context, missing repository identity, or invalid SHAs fail closed. The
|
|
731
|
+
`verify` job has only `contents: read`, does not run project checks or package lifecycle scripts, and
|
|
732
|
+
does not receive signing permissions or secrets. The separate `attest` job signs only after the
|
|
733
|
+
verifier has passed and the receipt has been matched to the PR. Do not add commands that execute
|
|
734
|
+
files from the PR to the verifier job.
|
|
735
|
+
|
|
736
|
+
The `workflow_run` event only runs a workflow file present on the default branch. It has a different
|
|
737
|
+
trust context from the original PR workflow and can receive more privileges, so keep its permissions
|
|
738
|
+
minimal and protect this workflow file with CODEOWNERS/repository rules. GitHub may omit the PR
|
|
739
|
+
association in some events; an empty association is treated as a fork only when the trusted event
|
|
740
|
+
metadata identifies a different head repository. Otherwise, the context job fails closed and no
|
|
741
|
+
attestation is produced. The ordinary PR workflow can still run, but fork support for signed receipts
|
|
742
|
+
requires a separately reviewed PR lookup design. Never solve this by running PR-controlled scripts
|
|
743
|
+
in the trusted workflow.
|
|
744
|
+
Although this template does not execute project files, Guard still parses attacker-controlled source
|
|
745
|
+
and configuration. Use GitHub-hosted ephemeral runners and keep verifier and signer permissions at
|
|
746
|
+
the template's minimum; parser vulnerabilities remain a residual risk.
|
|
747
|
+
|
|
748
|
+
The template uses `--fail-on-policy-change` and `--fail-on-protected-changes`. A PR that changes
|
|
749
|
+
Guard policy, the trusted workflow, or another protected verification input will therefore receive
|
|
750
|
+
no attestation from this workflow. Review such changes through the repository's protected owner
|
|
751
|
+
process, merge the approved policy, then verify subsequent source PRs against that base.
|
|
752
|
+
|
|
753
|
+
The workflow does not create a required check or status on the PR. GitHub branch protection or a
|
|
754
|
+
ruleset must require the ordinary Guard check and protect both workflow definitions. The attestation
|
|
755
|
+
is additional evidence for consumers that need to verify who ran Guard and which PR content was
|
|
756
|
+
checked; it does not replace host-side merge policy.
|
|
757
|
+
|
|
758
|
+
#### Verify a signed receipt
|
|
759
|
+
|
|
760
|
+
Find the trusted workflow run for the PR in the Actions tab. Download its
|
|
761
|
+
`guard-trusted-pr-attestation` artifact, which contains `guard-verification.intoto.json`. You can
|
|
762
|
+
also download it with GitHub CLI. Install `gh`, authenticate it to GitHub, and use an account that
|
|
763
|
+
can read the repository's workflow runs and pull requests:
|
|
764
|
+
|
|
765
|
+
```bash
|
|
766
|
+
gh run download RUN_ID --repo ORG/REPO \
|
|
767
|
+
--name guard-trusted-pr-attestation \
|
|
768
|
+
--dir .guard-attestation
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
Verify the signature, repository, signer workflow, and protected source ref:
|
|
772
|
+
|
|
773
|
+
```bash
|
|
774
|
+
gh attestation verify .guard-attestation/guard-verification.intoto.json \
|
|
775
|
+
--repo ORG/REPO \
|
|
776
|
+
--signer-workflow ORG/REPO/.github/workflows/guard-trusted-pr-attestation.yml \
|
|
777
|
+
--source-ref refs/heads/main
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
The command above verifies the signed artifact file and its GitHub workflow identity. To also check
|
|
781
|
+
the embedded Guard receipt's schema version, passing outcome, complete and stable scope, scope digest,
|
|
782
|
+
and the exact PR head and base SHAs, copy the bundled consumer script and run it after downloading
|
|
783
|
+
the artifact:
|
|
784
|
+
|
|
785
|
+
```bash
|
|
786
|
+
cp node_modules/@codapult/guard/docs/verify-guard-attestation.mjs .guard-attestation/
|
|
787
|
+
node .guard-attestation/verify-guard-attestation.mjs \
|
|
788
|
+
.guard-attestation/guard-verification.intoto.json \
|
|
789
|
+
--repo ORG/REPO \
|
|
790
|
+
--signer-workflow ORG/REPO/.github/workflows/guard-trusted-pr-attestation.yml \
|
|
791
|
+
--source-ref refs/heads/main \
|
|
792
|
+
--expected-head HEAD_SHA \
|
|
793
|
+
--expected-base BASE_SHA
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
The script calls `gh attestation verify` with the repository, signer workflow, and source-ref
|
|
797
|
+
constraints before inspecting the statement. It exits nonzero if signature verification fails or if
|
|
798
|
+
the embedded statement is unsupported, unsuccessful, incomplete, unstable, or bound to different
|
|
799
|
+
PR SHAs. Obtain the expected head and base values from the current PR; do not copy them from the
|
|
800
|
+
receipt being checked.
|
|
801
|
+
|
|
802
|
+
Replace `ORG/REPO` and `main` with the repository and protected default branch. This command checks
|
|
803
|
+
that the attestation is for the exact downloaded statement file and that the signer identity matches
|
|
804
|
+
the expected workflow and ref. Then compare the embedded receipt with the PR revision you intend to
|
|
805
|
+
accept. Set `EXPECTED_HEAD_SHA` and `EXPECTED_BASE_SHA` to the PR's current head and base commit SHAs
|
|
806
|
+
using the GitHub API:
|
|
807
|
+
|
|
808
|
+
```bash
|
|
809
|
+
EXPECTED_HEAD_SHA=$(gh api repos/ORG/REPO/pulls/PR_NUMBER --jq .head.sha)
|
|
810
|
+
EXPECTED_BASE_SHA=$(gh api repos/ORG/REPO/pulls/PR_NUMBER --jq .base.sha)
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
Replace `ORG/REPO` and `PR_NUMBER`, then run:
|
|
814
|
+
|
|
815
|
+
```bash
|
|
816
|
+
jq -e \
|
|
817
|
+
--arg head "$EXPECTED_HEAD_SHA" \
|
|
818
|
+
--arg base "$EXPECTED_BASE_SHA" \
|
|
819
|
+
'.predicateType == "https://codapult.dev/attestations/guard-verification/v1" and
|
|
820
|
+
.predicate.receipt.outcome == "pass" and
|
|
821
|
+
.predicate.receipt.subject.headSha == $head and
|
|
822
|
+
.predicate.receipt.subject.baseSha == $base and
|
|
823
|
+
.predicate.receipt.verificationScope.complete == true and
|
|
824
|
+
.predicate.receipt.verificationScope.stable == true and
|
|
825
|
+
.subject[0].digest.sha256 == .predicate.receipt.verificationScope.fingerprint' \
|
|
826
|
+
.guard-attestation/guard-verification.intoto.json >/dev/null
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
The comparison must use the exact PR revisions being reviewed. If the PR head or target branch has
|
|
830
|
+
advanced since the workflow ran, require a new trusted workflow run and verify its receipt instead.
|
|
831
|
+
The statement's `mergeSha`, when present, identifies the merge commit checked by Guard; the head and
|
|
832
|
+
base SHA checks above bind the attestation to the PR revisions.
|
|
833
|
+
|
|
834
|
+
For a first setup check, open a test PR from a branch in the same repository, wait for both workflow
|
|
835
|
+
runs to finish, confirm that `guard-trusted-pr-attestation` appears as an artifact on the trusted
|
|
836
|
+
workflow run, download it, and run both verification commands above. The template intentionally
|
|
837
|
+
fails closed when PR context is missing or ambiguous and cannot be identified as an unattached fork,
|
|
838
|
+
when the Guard receipt is not a pass, when its scope is incomplete or unstable, or when the PR SHAs
|
|
839
|
+
do not match the event. A fork that can be identified safely is an expected skip and receives no
|
|
840
|
+
attestation.
|
|
841
|
+
|
|
842
|
+
Signature verification proves which workflow signed the statement and that the statement file was
|
|
843
|
+
not changed after signing. It does not, by itself, prove that arbitrary claims inside the statement
|
|
844
|
+
are true. This template acts as the trusted verifier by re-running Guard before signing. Do not give
|
|
845
|
+
`id-token: write` to a job that executes PR-controlled workflow code and treat its signature as
|
|
846
|
+
trusted verification: a `pull_request` workflow file comes from the PR merge commit. GitHub also
|
|
847
|
+
warns that predicates may be controlled by the workflow that produced them unless signing is done
|
|
848
|
+
by a trusted builder. See GitHub's [guidance on untrusted code checkout](https://docs.github.com/en/actions/reference/security/secure-use#mitigating-the-risks-of-untrusted-code-checkout),
|
|
849
|
+
[workflow_run event details](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#workflow_run),
|
|
850
|
+
the [in-toto Statement spec](https://github.com/in-toto/attestation/blob/main/spec/README.md),
|
|
851
|
+
[GitHub artifact attestations](https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/use-artifact-attestations),
|
|
852
|
+
[actions/attest](https://github.com/actions/attest), and
|
|
853
|
+
[gh attestation verify](https://cli.github.com/manual/gh_attestation_verify).
|
|
854
|
+
|
|
855
|
+
### Governance audit
|
|
856
|
+
|
|
857
|
+
Use the read-only governance audit to inspect whether approval records retain enough declared
|
|
858
|
+
provenance for later review:
|
|
859
|
+
|
|
860
|
+
```bash
|
|
861
|
+
codapult-guard governance --json
|
|
862
|
+
codapult-guard governance --strict
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
The report counts declared proposal authors and approval actors, identifies overlaps, missing
|
|
866
|
+
actors/authors/commits, checks policy fingerprints, and follows retained `decision ID → verification
|
|
867
|
+
run` links. `--strict` exits non-zero when the report contains completeness warnings. The audit
|
|
868
|
+
reports metadata recorded by Guard; it does not prove personal identity, cryptographic signatures,
|
|
869
|
+
a trusted clock, immutable storage, or authorization. Those guarantees belong to Git, CI, branch
|
|
870
|
+
protection, and the review platform.
|
|
871
|
+
|
|
872
|
+
## What Guard discovers
|
|
873
|
+
|
|
874
|
+
Guard is intentionally evidence-driven. It can model a small JavaScript utility, a React app, a
|
|
875
|
+
Next.js App Router SaaS, a Node service, or a workspace without requiring one fixed architecture.
|
|
876
|
+
|
|
877
|
+
The TypeScript AST path uses `ts-morph` where AST semantics are useful. Lightweight file/config/Git
|
|
878
|
+
inspection remains direct code because introducing a large parser for a small fact would add cost
|
|
879
|
+
without improving accuracy. This hybrid boundary is deliberate.
|
|
880
|
+
|
|
881
|
+
The model is useful for questions such as:
|
|
882
|
+
|
|
883
|
+
- Which changed routes, actions, services, repositories, or tests are affected?
|
|
884
|
+
- Which client modules cross a server-only boundary?
|
|
885
|
+
- Which dependencies, environment variables, schemas, or configs are connected to a change?
|
|
886
|
+
- Which capabilities are actually present, and what files provide the evidence?
|
|
887
|
+
- Are there cycles, layer violations, high-fan-out modules, or changed impact paths?
|
|
888
|
+
- Which modules depend on a changed module, and which callers may be affected transitively?
|
|
889
|
+
- How did the project model, module graph, and layer edges change between two saved snapshots?
|
|
890
|
+
|
|
891
|
+
Domain signals for payments, auth, jobs, email, AI, storage, database, deployment, security,
|
|
892
|
+
observability, and other areas are review context by default. They do not become blocking rules
|
|
893
|
+
merely because a package name or filename resembles a domain.
|
|
894
|
+
|
|
895
|
+
## AI-agent and MCP workflow
|
|
896
|
+
|
|
897
|
+
MCP exposes the same Guard model without requiring the host to parse CLI output. The Guard tools
|
|
898
|
+
are:
|
|
899
|
+
|
|
900
|
+
| MCP tool | Purpose | Writes by default? |
|
|
901
|
+
| -------------------------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
902
|
+
| `codapult_guard_context` | Read explicitly separated observations, proposals, active policy, and verification state. | No |
|
|
903
|
+
| `codapult_guard_analyze` | Refresh persisted facts and snapshots without changing policy or baseline. | Requires `confirm: true`. |
|
|
904
|
+
| `codapult_guard_propose` | Generate evidence-based proposals. | No; persistence requires `persist: true` and `confirm: true`. |
|
|
905
|
+
| `codapult_guard_init` | Initialize Guard. | Requires `confirm: true`; force also requires confirmation. |
|
|
906
|
+
| `codapult_guard_proposal_decide` | Approve/reject current proposals. | Requires `confirm: true`; protected mode can forbid MCP approval. |
|
|
907
|
+
| `codapult_guard_check` | Check active Guard policy and changed files. | No |
|
|
908
|
+
| `codapult_guard_review` | Prepare a bounded/redacted semantic review packet. | No |
|
|
909
|
+
| `codapult_guard_verify` | Run the completion gate and return structured results. | Runs configured project commands; does not edit source. |
|
|
910
|
+
| `codapult_guard_governance` | Audit declared approval provenance and decision-to-verification reachability. | No |
|
|
911
|
+
| `codapult_guard_audit` | Full current scan and contract validation. | No |
|
|
912
|
+
| `codapult_guard_waivers` | List or manage owner-attributed, time-bounded exceptions to exact finding fingerprints. | Writes require confirmation and policy approval. |
|
|
913
|
+
| `codapult_guard_impact` | Explain dependencies, transitive dependents, impact paths, capabilities, contracts, and graph edges for files. | No |
|
|
914
|
+
| `codapult_guard_explain` | Explain one rule/contract, its evidence, and suggested next steps. | No |
|
|
915
|
+
| `codapult_guard_next_action` | Return the next bounded Guard action for an agent without changing project state. | No |
|
|
916
|
+
|
|
917
|
+
Every tool accepts an optional `root`. If omitted, the MCP process working directory is used. The
|
|
918
|
+
host should pass a project root when its MCP process is not started there.
|
|
919
|
+
|
|
920
|
+
`codapult_guard_context` keeps four states separate:
|
|
921
|
+
|
|
922
|
+
- `observations`: facts discovered from the current project. They have `status: "observed-only"`
|
|
923
|
+
and are not enforced merely because a pattern is common.
|
|
924
|
+
- `proposals`: rules and contracts suggested from evidence. Only pending items appear in
|
|
925
|
+
`pendingRules` and `pendingContracts`; they have `status: "pending-approval"` and
|
|
926
|
+
`requiresApproval: true`. Decided proposal history is not presented as pending policy.
|
|
927
|
+
- `policy`: active rules and contracts, plus baseline and waiver state. Only this policy is used
|
|
928
|
+
for deterministic enforcement.
|
|
929
|
+
- `verification`: the status of an actual check. Context reads state and returns
|
|
930
|
+
`status: "not-run"` with `findings: null`; call `codapult_guard_check` or
|
|
931
|
+
`codapult_guard_verify` for findings.
|
|
932
|
+
|
|
933
|
+
This distinction prevents an observed convention from being mistaken for an approved rule or a
|
|
934
|
+
context response from being mistaken for a passing verification.
|
|
935
|
+
|
|
936
|
+
### Registering the MCP server
|
|
937
|
+
|
|
938
|
+
Install Guard in the project that the agent will inspect:
|
|
939
|
+
|
|
940
|
+
```bash
|
|
941
|
+
pnpm add -D @codapult/guard
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
Guard exposes a local stdio MCP server through the `codapult-guard` executable:
|
|
945
|
+
|
|
946
|
+
```bash
|
|
947
|
+
pnpm exec codapult-guard mcp-server
|
|
948
|
+
```
|
|
949
|
+
|
|
950
|
+
Register that command in the selected AI host and use the project root as its working directory.
|
|
951
|
+
For example, Cursor can use `.cursor/mcp.json`:
|
|
952
|
+
|
|
953
|
+
```json
|
|
954
|
+
{
|
|
955
|
+
"mcpServers": {
|
|
956
|
+
"codapult-guard": {
|
|
957
|
+
"type": "stdio",
|
|
958
|
+
"command": "pnpm",
|
|
959
|
+
"args": ["exec", "codapult-guard", "mcp-server"],
|
|
960
|
+
"cwd": "${workspaceFolder}"
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
For a client with a generic stdio configuration, use the same command and set `cwd` to the
|
|
967
|
+
repository root. Do not use `@codapult/cli` for standalone Guard projects: that package is the
|
|
968
|
+
Codapult SaaS CLI and is a separate integration. Host-specific setup and instruction files are
|
|
969
|
+
available in [`docs/integrations/`](integrations/README.md).
|
|
970
|
+
|
|
971
|
+
Guard is also discoverable in the official [MCP Registry](https://registry.modelcontextprotocol.io/?q=io.github.codapult%2Fguard)
|
|
972
|
+
as `io.github.codapult/guard`. Registry discovery identifies the published npm-backed server; the
|
|
973
|
+
selected host still needs a local installation and stdio configuration with the project root.
|
|
974
|
+
|
|
975
|
+
After connecting, verify the server by calling `codapult_guard_context` or
|
|
976
|
+
`codapult_guard_audit`. If the MCP process starts outside the repository, pass the absolute
|
|
977
|
+
project path as the tool's `root` argument.
|
|
978
|
+
|
|
979
|
+
Recommended agent sequence:
|
|
980
|
+
|
|
981
|
+
```text
|
|
982
|
+
task complete
|
|
983
|
+
→ codapult_guard_next_action
|
|
984
|
+
→ codapult_guard_context
|
|
985
|
+
→ codapult_guard_review(requirement, diff)
|
|
986
|
+
→ codapult_guard_verify(iteration: 1)
|
|
987
|
+
→ if fail and canRetry: repair, then repeat with iteration + 1
|
|
988
|
+
→ report warnings and unresolved requirements
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
The host agent owns the loop, model call, permissions, and source edits. Guard does not invoke an
|
|
992
|
+
LLM, silently loop, or repair files. `agent.json` supplies policy such as `enabled`,
|
|
993
|
+
`maxIterations`, `projectChecks`, selected checks, and external-tool mode. A host may use the
|
|
994
|
+
managed instruction block:
|
|
995
|
+
|
|
996
|
+
```bash
|
|
997
|
+
pnpm exec codapult-guard install-agent codex
|
|
998
|
+
pnpm exec codapult-guard install-agent cursor
|
|
999
|
+
pnpm exec codapult-guard install-agent all
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
Supported targets are `generic`, `codex`, `cursor`, `claude`, `copilot`, and `gemini`. The managed
|
|
1003
|
+
block is marker-based and updates only its own section. Host-specific MCP registration and
|
|
1004
|
+
completion-hook behavior are documented in the [integration kits](integrations/README.md).
|
|
1005
|
+
|
|
1006
|
+
An agent instruction can be as short as:
|
|
1007
|
+
|
|
1008
|
+
```text
|
|
1009
|
+
Before declaring a task complete, call codapult_guard_next_action, then
|
|
1010
|
+
follow its bounded next step. Normally call codapult_guard_context,
|
|
1011
|
+
codapult_guard_review with the requirement and diff, then codapult_guard_verify.
|
|
1012
|
+
If verification fails and canRetry is true, repair the code and repeat up to
|
|
1013
|
+
completionGate.maxIterations. Report warnings and unresolved requirements.
|
|
1014
|
+
```
|
|
1015
|
+
|
|
1016
|
+
## CI and machine-readable output
|
|
1017
|
+
|
|
1018
|
+
CI should independently run Guard after an AI agent finishes. Do not accept an agent's statement
|
|
1019
|
+
that a finding was fixed; accept the next deterministic result.
|
|
1020
|
+
|
|
1021
|
+
JSON gate output:
|
|
1022
|
+
|
|
1023
|
+
```bash
|
|
1024
|
+
pnpm exec codapult-guard verify --json
|
|
1025
|
+
pnpm exec codapult-guard check --changed --json
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
`verify --json` includes a `run` object with a unique run ID, stage durations, outcome, and the
|
|
1029
|
+
policy gate that determined the result. The same manifest is saved under
|
|
1030
|
+
`.codapult/guard/history/runs/`. Guard keeps this diagnostic record local and does not send traces
|
|
1031
|
+
or source code to a remote service. The manifest includes a compact `verification-receipt` with the
|
|
1032
|
+
checked commit, policy fingerprint/base, decision IDs, check statuses, finding and waiver counts,
|
|
1033
|
+
contract issue IDs, Guard version, and a SHA-256 inventory of verification inputs. It is an
|
|
1034
|
+
explainability artifact, not a signed proof of CI identity. With `--policy-base`, the receipt also distinguishes `baseChangedFiles` from
|
|
1035
|
+
`workingTreeFiles`; this makes a dirty local checkout visible in the machine-readable result.
|
|
1036
|
+
|
|
1037
|
+
SARIF output for GitHub Code Scanning or another SARIF consumer:
|
|
1038
|
+
|
|
1039
|
+
```bash
|
|
1040
|
+
pnpm exec codapult-guard check --changed --sarif > guard-results.sarif
|
|
1041
|
+
```
|
|
1042
|
+
|
|
1043
|
+
The repository includes a copyable consumer workflow at [`docs/guard-ci.yml`](guard-ci.yml). On pull
|
|
1044
|
+
requests it installs dependencies without lifecycle scripts and runs the deterministic Guard gate
|
|
1045
|
+
without executing PR-owned project scripts; trusted pushes can run configured project checks. It uploads SARIF
|
|
1046
|
+
with `github/codeql-action/upload-sarif` and also runs the unified verification gate. Projects
|
|
1047
|
+
using protected or forked pull requests should review their `security-events: write` permissions
|
|
1048
|
+
and artifact policy.
|
|
1049
|
+
|
|
1050
|
+
For maintainers, the fixture and real-PR harnesses are documented in
|
|
1051
|
+
[`guard-fixtures.md`](guard-fixtures.md). The isolated golden flow is run with:
|
|
1052
|
+
|
|
1053
|
+
```bash
|
|
1054
|
+
pnpm test:guard:golden
|
|
1055
|
+
```
|
|
1056
|
+
|
|
1057
|
+
## Security and data handling
|
|
1058
|
+
|
|
1059
|
+
- Guard excludes `.env`, credential/secret-named files, and common private-key extensions from
|
|
1060
|
+
review diffs.
|
|
1061
|
+
- Common credential-shaped values are redacted before a review packet or structured output is
|
|
1062
|
+
returned. Redaction is a defense-in-depth measure, not a guarantee that arbitrary secrets are
|
|
1063
|
+
recognized.
|
|
1064
|
+
- Requirement files must remain inside the detected project root and are size-limited.
|
|
1065
|
+
- Git base refs are validated before being used by review commands.
|
|
1066
|
+
- Project checks and external adapters execute the project's own scripts. Run Guard only in a
|
|
1067
|
+
trusted workspace and review scripts before enabling `tools: auto` or `tools: on`.
|
|
1068
|
+
- MCP roots are local filesystem paths supplied by the host. Run the MCP server with the least
|
|
1069
|
+
filesystem access appropriate for the projects it serves.
|
|
1070
|
+
- Guard does not send source code to a remote service by itself. An AI host may send the review
|
|
1071
|
+
packet to its configured model; apply that host's data-retention and provider policy.
|
|
1072
|
+
|
|
1073
|
+
## Troubleshooting
|
|
1074
|
+
|
|
1075
|
+
### `Guard is not initialized`
|
|
1076
|
+
|
|
1077
|
+
Run `codapult-guard init` from the project root. For MCP, pass the correct `root` or start the server in
|
|
1078
|
+
the project directory.
|
|
1079
|
+
|
|
1080
|
+
### `Guard is already initialized`
|
|
1081
|
+
|
|
1082
|
+
This is intentional protection. Use `codapult-guard analyze` to refresh facts, or use `codapult-guard init --force`
|
|
1083
|
+
only when replacing the baseline is a deliberate decision.
|
|
1084
|
+
|
|
1085
|
+
### Too many findings appear after initialization
|
|
1086
|
+
|
|
1087
|
+
That is the expected baseline boundary: old findings are recorded and suppressed by `check`, while
|
|
1088
|
+
new regressions remain visible. Use `codapult-guard audit` to inspect the complete current state.
|
|
1089
|
+
|
|
1090
|
+
### A proposal is stale
|
|
1091
|
+
|
|
1092
|
+
The code changed after the proposal was generated. Run `codapult-guard propose` again and review the new
|
|
1093
|
+
evidence.
|
|
1094
|
+
|
|
1095
|
+
### Verification says a tool is not configured
|
|
1096
|
+
|
|
1097
|
+
Use `--tools auto` for normal operation, `--tools off` when external adapters are not relevant,
|
|
1098
|
+
or `--strict` when the project requires every selected check/adapter to exist.
|
|
1099
|
+
|
|
1100
|
+
### Review says the diff is truncated or redacted
|
|
1101
|
+
|
|
1102
|
+
This is intentional. Review packets are bounded, and sensitive-looking content is removed before
|
|
1103
|
+
it reaches an AI reviewer. Narrow the change or inspect the source locally if more context is
|
|
1104
|
+
needed.
|
|
1105
|
+
|
|
1106
|
+
### Native fixture checks fail because of Node
|
|
1107
|
+
|
|
1108
|
+
Fixture projects retain their own engine requirements. Use a compatible Node version for the
|
|
1109
|
+
fixture rather than weakening Guard or changing the fixture's production configuration. Guard's
|
|
1110
|
+
runtime diagnostic reports the active and declared versions.
|
|
1111
|
+
|
|
1112
|
+
## Implementation boundaries
|
|
1113
|
+
|
|
1114
|
+
Guard currently provides deterministic discovery, policy checks, project-context packets, contract
|
|
1115
|
+
validation, completion-gate orchestration, MCP exposure, JSON/SARIF output, and host instruction
|
|
1116
|
+
templates. It intentionally does not:
|
|
1117
|
+
|
|
1118
|
+
- call an LLM or choose architectural policy without approval;
|
|
1119
|
+
- replace specialist linters, type checkers, test runners, SAST, dependency scanners, or builds;
|
|
1120
|
+
- silently rewrite source code or automatically reset a baseline;
|
|
1121
|
+
- guarantee semantic correctness from filename/package-name heuristics alone;
|
|
1122
|
+
- implement host-specific agent hooks as runtime dependencies.
|
|
1123
|
+
|
|
1124
|
+
That boundary keeps Guard local-first, model-agnostic, and project-specific while allowing existing
|
|
1125
|
+
tools and AI platforms to remain useful adapters around one shared project model.
|