micro-contracts 0.9.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 +22 -0
- package/README.md +351 -0
- package/dist/cli/templates.d.ts +16 -0
- package/dist/cli/templates.d.ts.map +1 -0
- package/dist/cli/templates.js +377 -0
- package/dist/cli/templates.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +978 -0
- package/dist/cli.js.map +1 -0
- package/dist/generator/dependencyGenerator.d.ts +43 -0
- package/dist/generator/dependencyGenerator.d.ts.map +1 -0
- package/dist/generator/dependencyGenerator.js +159 -0
- package/dist/generator/dependencyGenerator.js.map +1 -0
- package/dist/generator/domainGenerator.d.ts +16 -0
- package/dist/generator/domainGenerator.d.ts.map +1 -0
- package/dist/generator/domainGenerator.js +212 -0
- package/dist/generator/domainGenerator.js.map +1 -0
- package/dist/generator/index.d.ts +37 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +747 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/linter.d.ts +24 -0
- package/dist/generator/linter.d.ts.map +1 -0
- package/dist/generator/linter.js +202 -0
- package/dist/generator/linter.js.map +1 -0
- package/dist/generator/overlayProcessor.d.ts +90 -0
- package/dist/generator/overlayProcessor.d.ts.map +1 -0
- package/dist/generator/overlayProcessor.js +532 -0
- package/dist/generator/overlayProcessor.js.map +1 -0
- package/dist/generator/schemaGenerator.d.ts +10 -0
- package/dist/generator/schemaGenerator.d.ts.map +1 -0
- package/dist/generator/schemaGenerator.js +299 -0
- package/dist/generator/schemaGenerator.js.map +1 -0
- package/dist/generator/templateProcessor.d.ts +178 -0
- package/dist/generator/templateProcessor.d.ts.map +1 -0
- package/dist/generator/templateProcessor.js +607 -0
- package/dist/generator/templateProcessor.js.map +1 -0
- package/dist/generator/typeGenerator.d.ts +9 -0
- package/dist/generator/typeGenerator.d.ts.map +1 -0
- package/dist/generator/typeGenerator.js +395 -0
- package/dist/generator/typeGenerator.js.map +1 -0
- package/dist/guardrails/allowlist.d.ts +45 -0
- package/dist/guardrails/allowlist.d.ts.map +1 -0
- package/dist/guardrails/allowlist.js +261 -0
- package/dist/guardrails/allowlist.js.map +1 -0
- package/dist/guardrails/config.d.ts +40 -0
- package/dist/guardrails/config.d.ts.map +1 -0
- package/dist/guardrails/config.js +174 -0
- package/dist/guardrails/config.js.map +1 -0
- package/dist/guardrails/docs.d.ts +24 -0
- package/dist/guardrails/docs.d.ts.map +1 -0
- package/dist/guardrails/docs.js +138 -0
- package/dist/guardrails/docs.js.map +1 -0
- package/dist/guardrails/drift.d.ts +23 -0
- package/dist/guardrails/drift.d.ts.map +1 -0
- package/dist/guardrails/drift.js +127 -0
- package/dist/guardrails/drift.js.map +1 -0
- package/dist/guardrails/index.d.ts +19 -0
- package/dist/guardrails/index.d.ts.map +1 -0
- package/dist/guardrails/index.js +25 -0
- package/dist/guardrails/index.js.map +1 -0
- package/dist/guardrails/lint.d.ts +20 -0
- package/dist/guardrails/lint.d.ts.map +1 -0
- package/dist/guardrails/lint.js +274 -0
- package/dist/guardrails/lint.js.map +1 -0
- package/dist/guardrails/manifest.d.ts +43 -0
- package/dist/guardrails/manifest.d.ts.map +1 -0
- package/dist/guardrails/manifest.js +231 -0
- package/dist/guardrails/manifest.js.map +1 -0
- package/dist/guardrails/runner.d.ts +31 -0
- package/dist/guardrails/runner.d.ts.map +1 -0
- package/dist/guardrails/runner.js +268 -0
- package/dist/guardrails/runner.js.map +1 -0
- package/dist/guardrails/security.d.ts +31 -0
- package/dist/guardrails/security.d.ts.map +1 -0
- package/dist/guardrails/security.js +181 -0
- package/dist/guardrails/security.js.map +1 -0
- package/dist/guardrails/typecheck.d.ts +15 -0
- package/dist/guardrails/typecheck.d.ts.map +1 -0
- package/dist/guardrails/typecheck.js +104 -0
- package/dist/guardrails/typecheck.js.map +1 -0
- package/dist/guardrails/types.d.ts +196 -0
- package/dist/guardrails/types.d.ts.map +1 -0
- package/dist/guardrails/types.js +8 -0
- package/dist/guardrails/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +489 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +297 -0
- package/dist/types.js.map +1 -0
- package/docs/architecture.svg +226 -0
- package/docs/development-guardrails.md +541 -0
- package/docs/guardrails-concept.svg +252 -0
- package/docs/overlays-deep-dive.md +298 -0
- package/package.json +66 -0
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
# Development Guardrails (AI-ready)
|
|
2
|
+
|
|
3
|
+
This document defines **guardrails for AI-assisted and human development**. The guardrails are designed to prevent "diff explosion", keep contracts authoritative, and make changes **machine-verifiable**.
|
|
4
|
+
|
|
5
|
+
The key idea is to separate the system into two layers:
|
|
6
|
+
|
|
7
|
+
- **Tooling (shipped as code / reusable)**: deterministic checks and generators that run locally and in CI and return a clear pass/fail.
|
|
8
|
+
- **Operations (configured in CI / repo policy)**: GitHub configuration (workflows, branch protection, rulesets, approvals) that **enforces** the tooling and protects the guardrails themselves.
|
|
9
|
+
|
|
10
|
+
> The guardrails must not depend on *who* wrote the change (human/AI). They depend only on *what* changed and whether it satisfies the contract.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
1. [Gate Overview](#gate-overview)
|
|
17
|
+
2. [Available Checks](#available-checks)
|
|
18
|
+
3. [Configuration](#configuration)
|
|
19
|
+
4. [Operations (CI / Repo Policy)](#operations-ci--repo-policy)
|
|
20
|
+
5. [Developer Workflow](#developer-workflow)
|
|
21
|
+
6. [Appendix: CI Configuration](#appendix-ci-configuration)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Gate Overview
|
|
26
|
+
|
|
27
|
+
The following diagram illustrates the overall architecture of the guardrails system:
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
### Gate Summary
|
|
32
|
+
|
|
33
|
+
| Gate | Name | Scope | What it prevents |
|
|
34
|
+
|------|------|-------|------------------|
|
|
35
|
+
| **1** | Change Allowlist | repo-wide | Editing protected/generated areas directly |
|
|
36
|
+
| **2** | OpenAPI Spec Validation | `spec/**` | Invalid specs, bad extensions, breaking changes |
|
|
37
|
+
| **3** | Generated Artifact Integrity | `packages/**`, `*.generated.*` | Hand-editing generated code, drift, tampering |
|
|
38
|
+
| **4** | Code Quality | `server/**`, `frontend/**` | Type errors, lint issues, failing tests |
|
|
39
|
+
| **5** | Doc & Architectural Consistency | `docs/**`, all code | Doc/code mismatch, broken references, architecture drift |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Available Checks
|
|
44
|
+
|
|
45
|
+
Checks are divided into two categories:
|
|
46
|
+
|
|
47
|
+
- **Built-in**: Core checks implemented in `micro-contracts` CLI (allowlist, drift, manifest)
|
|
48
|
+
- **Custom**: User-defined commands in `micro-contracts.guardrails.yaml` (`checks:` section)
|
|
49
|
+
|
|
50
|
+
### Check Command Options
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
micro-contracts check [options]
|
|
54
|
+
|
|
55
|
+
Options:
|
|
56
|
+
--only <checks> Run only specific checks (comma-separated)
|
|
57
|
+
--skip <checks> Skip specific checks (comma-separated)
|
|
58
|
+
--gate <gates> Run checks for specific gates only (comma-separated, 1-5)
|
|
59
|
+
-v, --verbose Enable verbose output (groups by gate)
|
|
60
|
+
--fix Auto-fix issues where possible
|
|
61
|
+
-g, --guardrails <path> Path to guardrails.yaml
|
|
62
|
+
-d, --generated-dir <path> Path to generated files directory (default: "packages/")
|
|
63
|
+
--changed-files <path> Path to file containing list of changed files (for CI)
|
|
64
|
+
--list List available checks with gate assignments
|
|
65
|
+
--list-gates List available gates
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Examples:**
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Run all checks
|
|
72
|
+
micro-contracts check
|
|
73
|
+
|
|
74
|
+
# Run only Gate 1 and 2 checks
|
|
75
|
+
micro-contracts check --gate 1,2
|
|
76
|
+
|
|
77
|
+
# Run Gate 3 checks with verbose output (grouped by gate)
|
|
78
|
+
micro-contracts check --gate 3 -v
|
|
79
|
+
|
|
80
|
+
# Run specific checks by name
|
|
81
|
+
micro-contracts check --only allowlist,drift
|
|
82
|
+
|
|
83
|
+
# List all checks with their gate assignments
|
|
84
|
+
micro-contracts check --list
|
|
85
|
+
|
|
86
|
+
# List available gates
|
|
87
|
+
micro-contracts check --list-gates
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Gate 1: Change Allowlist
|
|
91
|
+
|
|
92
|
+
Prevents unauthorized edits to protected/generated areas.
|
|
93
|
+
|
|
94
|
+
| Check | Type | Description | Local Command | CI Job |
|
|
95
|
+
|-------|------|-------------|---------------|--------|
|
|
96
|
+
| Allowlist | built-in | Block **direct** edits to `packages/**`, `*.generated.*`; require approval for `.github/**` | `micro-contracts check --only allowlist` | `allowlist` |
|
|
97
|
+
|
|
98
|
+
Files are categorized into three groups:
|
|
99
|
+
|
|
100
|
+
| Category | Examples | Who can edit |
|
|
101
|
+
|----------|----------|--------------|
|
|
102
|
+
| `allowed` | `spec/**/*.yaml`, `server/src/**/domains/**` | Anyone (AI or human) |
|
|
103
|
+
| `protected` | `.github/**`, `spec/spectral.yaml`, `server/src/_shared/overlays/**` | Requires CODEOWNERS approval |
|
|
104
|
+
| `generated` | `packages/**`, `*.generated.*` | Only via `generate` command |
|
|
105
|
+
|
|
106
|
+
Protected files include:
|
|
107
|
+
- CI/workflow definitions (`.github/**`) — guardrail bypass prevention
|
|
108
|
+
- Spectral lint rules (`spec/spectral.yaml`) — security rule tampering
|
|
109
|
+
- Shared overlay implementations (`server/src/_shared/overlays/**`) — security logic
|
|
110
|
+
|
|
111
|
+
### Gate 2: OpenAPI Spec Validation
|
|
112
|
+
|
|
113
|
+
Validates OpenAPI specs before generation.
|
|
114
|
+
|
|
115
|
+
| Check | Type | Description | Local Command | CI Job |
|
|
116
|
+
|-------|------|-------------|---------------|--------|
|
|
117
|
+
| Spec lint | custom | OpenAPI schema + micro-contracts extensions (Spectral) | `micro-contracts check --only spec-lint` | `spec-lint` |
|
|
118
|
+
| Breaking changes | custom | API compatibility check (oasdiff) | `micro-contracts check --only spec-breaking` | `spec-breaking` |
|
|
119
|
+
|
|
120
|
+
**Spec lint** — Validates via Spectral ruleset:
|
|
121
|
+
- OpenAPI 3.x structure (required fields, JSON Schema, `$ref` resolution)
|
|
122
|
+
- micro-contracts extensions (`x-micro-contracts-domain`, `x-micro-contracts-method`)
|
|
123
|
+
- Security extensions (`x-auth`, `x-authz`) if required
|
|
124
|
+
|
|
125
|
+
**Breaking changes** — Detects backward-incompatible changes:
|
|
126
|
+
- Removed endpoints or parameters
|
|
127
|
+
- Changed response schemas
|
|
128
|
+
- Modified required fields
|
|
129
|
+
|
|
130
|
+
### Generator
|
|
131
|
+
|
|
132
|
+
Transforms `spec/**` → `packages/**`.
|
|
133
|
+
|
|
134
|
+
| Command | Description |
|
|
135
|
+
|---------|-------------|
|
|
136
|
+
| `micro-contracts generate` | Generate contracts from OpenAPI specs |
|
|
137
|
+
|
|
138
|
+
### Gate 3: Generated Artifact Integrity
|
|
139
|
+
|
|
140
|
+
Ensures generated code matches spec and hasn't been tampered.
|
|
141
|
+
|
|
142
|
+
> **Why commit generated artifacts?** CI re-runs `generate` and compares against committed files to detect tampering or drift. Without committed artifacts, there's no baseline to verify.
|
|
143
|
+
|
|
144
|
+
| Check | Type | Description | Local Command | CI Job |
|
|
145
|
+
|-------|------|-------------|---------------|--------|
|
|
146
|
+
| Drift | built-in | `git diff packages/` must be clean | `micro-contracts check --only drift` | `drift` |
|
|
147
|
+
| Manifest | built-in | SHA-256 hash verification | `micro-contracts check --only manifest` | `manifest` |
|
|
148
|
+
| Package typecheck | custom | Generated packages compile (`tsc`) | `micro-contracts check --only package-typecheck` | `package-typecheck` |
|
|
149
|
+
| Project rules | custom | Project-specific Spectral rules on **generated** spec | `micro-contracts check --only spec-project` | `spec-project` |
|
|
150
|
+
| Published breaking | custom | Breaking changes vs **published** contract (oasdiff) | `micro-contracts check --only spec-breaking-published` | `spec-breaking-published` |
|
|
151
|
+
|
|
152
|
+
> **Why spec checks in Gate 3?** `spec-project` and `spec-breaking-published` validate the **generated/bundled** spec output, not the source. They run after generation to verify the published contract.
|
|
153
|
+
|
|
154
|
+
**Drift check** — After running `generate`, `packages/**` must match committed state:
|
|
155
|
+
```bash
|
|
156
|
+
git diff --exit-code packages/
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Manifest verification** — `packages/.generated-manifest.json` stores:
|
|
160
|
+
- SHA-256 hashes of all generated files
|
|
161
|
+
- Generator version used
|
|
162
|
+
- Source spec file references
|
|
163
|
+
|
|
164
|
+
**Package typecheck** — Generated TypeScript must compile without errors.
|
|
165
|
+
|
|
166
|
+
### Gate 4: Code Quality
|
|
167
|
+
|
|
168
|
+
Validates implementation code quality.
|
|
169
|
+
|
|
170
|
+
| Check | Type | Description | Local Command | CI Job |
|
|
171
|
+
|-------|------|-------------|---------------|--------|
|
|
172
|
+
| TypeScript lint | custom | ESLint rules | `micro-contracts check --only code-lint` | `code-lint` |
|
|
173
|
+
| Type check | custom | TypeScript compilation (`tsc --noEmit`) | `micro-contracts check --only code-typecheck` | `code-typecheck` |
|
|
174
|
+
| Unit tests | custom | Test suite execution | `micro-contracts check --only code-test` | `code-test` |
|
|
175
|
+
| Format check | custom | Prettier formatting | `micro-contracts check --only code-format` | `code-format` |
|
|
176
|
+
|
|
177
|
+
### Gate 5: Doc & Architectural Consistency
|
|
178
|
+
|
|
179
|
+
Ensures documentation and architecture stay in sync.
|
|
180
|
+
|
|
181
|
+
| Check | Type | Description | Local Command | CI Job |
|
|
182
|
+
|-------|------|-------------|---------------|--------|
|
|
183
|
+
| Markdown sync | custom | Code snippets in docs (embedoc) | `micro-contracts check --only docs-sync` | `docs-sync` |
|
|
184
|
+
| Links validity | custom | Broken link detection | `micro-contracts check --only docs-links` | `docs-links` |
|
|
185
|
+
| Architectural integrity | external | Static analysis (CodeQL) | GitHub CodeQL Action | `codeql` |
|
|
186
|
+
|
|
187
|
+
**Architectural integrity (CodeQL)** — Static analysis verifies:
|
|
188
|
+
- HTTP entry points reach security overlays
|
|
189
|
+
- Transaction boundaries are respected
|
|
190
|
+
- Domain symbols resolve correctly
|
|
191
|
+
- No direct HTTP calls outside generated client
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Configuration
|
|
196
|
+
|
|
197
|
+
### micro-contracts.guardrails.yaml
|
|
198
|
+
|
|
199
|
+
<!--@embedoc:code_snippet file="../examples/micro-contracts.guardrails.yaml" lang="yaml" title="micro-contracts.guardrails.yaml (example)"-->
|
|
200
|
+
**micro-contracts.guardrails.yaml (example)**
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
# AI-Driven Development Guardrails Configuration
|
|
204
|
+
#
|
|
205
|
+
# This file defines which files can be modified in normal development PRs.
|
|
206
|
+
# Patterns use gitignore-style matching with glob patterns.
|
|
207
|
+
# Prefix with ! to negate (exclude) a pattern.
|
|
208
|
+
|
|
209
|
+
# Files that can be edited in normal development PRs
|
|
210
|
+
allowed:
|
|
211
|
+
# OpenAPI specs (source of truth)
|
|
212
|
+
- spec/**/openapi/*.yaml
|
|
213
|
+
- spec/**/templates/*.hbs
|
|
214
|
+
|
|
215
|
+
# Domain implementations (human-written)
|
|
216
|
+
- server/src/**/domains/**/*.ts
|
|
217
|
+
- server/src/**/container.ts
|
|
218
|
+
- server/src/server.ts
|
|
219
|
+
|
|
220
|
+
# Module-specific overlays (NOT _shared)
|
|
221
|
+
- server/src/*/overlays/**/*.ts
|
|
222
|
+
- "!server/src/_shared/overlays/**"
|
|
223
|
+
|
|
224
|
+
# Configuration
|
|
225
|
+
- micro-contracts.config.yaml
|
|
226
|
+
- package.json
|
|
227
|
+
- tsconfig.json
|
|
228
|
+
|
|
229
|
+
# Documentation
|
|
230
|
+
- docs/**/*.md
|
|
231
|
+
- README.md
|
|
232
|
+
|
|
233
|
+
# Files that require special approval
|
|
234
|
+
protected:
|
|
235
|
+
# Spectral lint rules
|
|
236
|
+
- spec/spectral.yaml
|
|
237
|
+
- spec/_shared/spectral.yaml
|
|
238
|
+
|
|
239
|
+
# Shared overlay definitions
|
|
240
|
+
- spec/_shared/overlays/**
|
|
241
|
+
|
|
242
|
+
# Shared security overlay implementations
|
|
243
|
+
- server/src/_shared/overlays/**
|
|
244
|
+
|
|
245
|
+
# This guardrails configuration
|
|
246
|
+
- micro-contracts.guardrails.yaml
|
|
247
|
+
|
|
248
|
+
# CI/workflow definitions
|
|
249
|
+
- .github/**
|
|
250
|
+
|
|
251
|
+
# Generated artifacts (committed, but only modified via generate)
|
|
252
|
+
generated:
|
|
253
|
+
# Contract packages
|
|
254
|
+
- packages/**
|
|
255
|
+
|
|
256
|
+
# Generated files
|
|
257
|
+
- "**/*.generated.ts"
|
|
258
|
+
- "**/*.generated.yaml"
|
|
259
|
+
- "**/*.generated.yml"
|
|
260
|
+
|
|
261
|
+
# Check command configurations
|
|
262
|
+
# Define custom commands for each guardrail check
|
|
263
|
+
#
|
|
264
|
+
# Based on guardrails-concept.svg:
|
|
265
|
+
#
|
|
266
|
+
# Gate 1: Change Allowlist
|
|
267
|
+
# - allowlist (built-in): packages/** edit blocked, *.generated.* edit blocked
|
|
268
|
+
#
|
|
269
|
+
# Gate 2: OpenAPI Contract Validation (Spectral)
|
|
270
|
+
# - spec-lint: Schema Validity, x-security Required, x-auth Declaration
|
|
271
|
+
# - spec-breaking: Breaking Changes detection (oasdiff)
|
|
272
|
+
#
|
|
273
|
+
# Gate 3: Generated Artifact Integrity
|
|
274
|
+
# - drift (built-in): git diff packages/**
|
|
275
|
+
# - manifest (built-in): SHA-256 verification
|
|
276
|
+
# - package-typecheck: Generated package type check
|
|
277
|
+
#
|
|
278
|
+
# Gate 4: Code Quality
|
|
279
|
+
# - code-lint: TypeScript Lint (ESLint)
|
|
280
|
+
# - code-typecheck: Type Check (tsc)
|
|
281
|
+
# - code-test: Unit Tests
|
|
282
|
+
#
|
|
283
|
+
# Gate 5: Doc Consistency & Static Analysis
|
|
284
|
+
# - docs-sync: Markdown Sync (embedoc)
|
|
285
|
+
# - docs-links: Links Valid
|
|
286
|
+
# - security (built-in): CodeQL static analysis
|
|
287
|
+
#
|
|
288
|
+
# Placeholders:
|
|
289
|
+
# {files} - space-separated list of target files (auto-detected)
|
|
290
|
+
# {cwd} - current working directory
|
|
291
|
+
|
|
292
|
+
checks:
|
|
293
|
+
# ==========================================
|
|
294
|
+
# Gate 2: OpenAPI Contract Validation
|
|
295
|
+
# ==========================================
|
|
296
|
+
# Schema Validity, x-security Required, x-auth Declaration, Description Check
|
|
297
|
+
spec-lint:
|
|
298
|
+
command: "npx @stoplight/spectral-cli lint {files} --ruleset spec/spectral.yaml"
|
|
299
|
+
gate: 2
|
|
300
|
+
|
|
301
|
+
# Breaking Changes detection (oasdiff)
|
|
302
|
+
# Compare current spec against main branch
|
|
303
|
+
# Uses bundled spec to resolve $refs properly
|
|
304
|
+
#
|
|
305
|
+
# NOTE: Replace the base path with your actual generated spec location:
|
|
306
|
+
# Recommended: main:packages/contract/<module>/docs/openapi.generated.yaml
|
|
307
|
+
# Example below uses: main:examples/packages/... (for this repo's structure)
|
|
308
|
+
spec-breaking:
|
|
309
|
+
command: "bash -c 'npx @redocly/cli bundle spec/core/openapi/core.yaml -o /tmp/current.yaml && git show main:examples/packages/contract/core/docs/openapi.generated.yaml > /tmp/base.yaml 2>/dev/null && oasdiff breaking /tmp/base.yaml /tmp/current.yaml --fail-on ERR || echo \"No base spec found (new file)\"'"
|
|
310
|
+
gate: 2
|
|
311
|
+
|
|
312
|
+
# ==========================================
|
|
313
|
+
# Gate 3: Generated Artifact Integrity
|
|
314
|
+
# ==========================================
|
|
315
|
+
# drift, manifest are built-in checks (gate: 3)
|
|
316
|
+
|
|
317
|
+
# Generated package type check
|
|
318
|
+
package-typecheck:
|
|
319
|
+
command: "cd packages/contract && npx tsc --noEmit"
|
|
320
|
+
gate: 3
|
|
321
|
+
|
|
322
|
+
# ==========================================
|
|
323
|
+
# Gate 4: Code Quality
|
|
324
|
+
# ==========================================
|
|
325
|
+
# TypeScript Lint (ESLint)
|
|
326
|
+
code-lint:
|
|
327
|
+
command: "cd server && npx eslint src/ --ext .ts && cd ../frontend && npx eslint src/ --ext .ts,.tsx"
|
|
328
|
+
gate: 4
|
|
329
|
+
|
|
330
|
+
# Type Check (tsc)
|
|
331
|
+
code-typecheck:
|
|
332
|
+
command: "cd server && npx tsc --noEmit && cd ../frontend && npx tsc --noEmit"
|
|
333
|
+
gate: 4
|
|
334
|
+
|
|
335
|
+
# Unit Tests
|
|
336
|
+
code-test:
|
|
337
|
+
command: "cd server && npm test && cd ../frontend && npm test"
|
|
338
|
+
gate: 4
|
|
339
|
+
enabled: false # Enable when tests are set up
|
|
340
|
+
|
|
341
|
+
# ==========================================
|
|
342
|
+
# Gate 5: Doc Consistency & Static Analysis
|
|
343
|
+
# ==========================================
|
|
344
|
+
# Markdown Sync (embedoc) - regenerate and check for drift
|
|
345
|
+
docs-sync:
|
|
346
|
+
command: "npx embedoc build && git diff --exit-code docs/"
|
|
347
|
+
gate: 5
|
|
348
|
+
enabled: false # Enable when docs/ directory exists
|
|
349
|
+
|
|
350
|
+
# Links Valid - verify documentation references
|
|
351
|
+
docs-links:
|
|
352
|
+
command: "node scripts/verify-doc-consistency.mjs"
|
|
353
|
+
gate: 5
|
|
354
|
+
enabled: false # Enable when scripts/verify-doc-consistency.mjs exists
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
📄 Source: [`micro-contracts.guardrails.yaml`](../examples/micro-contracts.guardrails.yaml) (lines full)
|
|
359
|
+
<!--@embedoc:end-->
|
|
360
|
+
|
|
361
|
+
### Manifest Format
|
|
362
|
+
|
|
363
|
+
The `micro-contracts generate` command creates `packages/.generated-manifest.json`:
|
|
364
|
+
|
|
365
|
+
```json
|
|
366
|
+
{
|
|
367
|
+
"version": "1.0.0",
|
|
368
|
+
"generatedAt": "2024-01-15T10:30:00Z",
|
|
369
|
+
"generatorVersion": "1.2.3",
|
|
370
|
+
"files": {
|
|
371
|
+
"contract/core/schemas/types.ts": {
|
|
372
|
+
"sha256": "a1b2c3d4e5f6...",
|
|
373
|
+
"source": "spec/core/openapi/core.yaml"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Operations (CI / Repo Policy)
|
|
382
|
+
|
|
383
|
+
### Pinned Generator (Supply Chain Boundary)
|
|
384
|
+
|
|
385
|
+
CI must run the generator via **pinned `npx`** to prevent local tampering:
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
npx --yes -p micro-contracts@${MICRO_CONTRACTS_VERSION} micro-contracts generate
|
|
389
|
+
npx --yes -p micro-contracts@${MICRO_CONTRACTS_VERSION} micro-contracts check
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Protecting `.github/**`
|
|
393
|
+
|
|
394
|
+
- Feature branches MUST NOT modify `.github/**`
|
|
395
|
+
- Changes require dedicated "infra PR" with CODEOWNERS approval
|
|
396
|
+
- **Rationale**: CI definition is part of the guardrail
|
|
397
|
+
|
|
398
|
+
### Required Status Checks
|
|
399
|
+
|
|
400
|
+
`main` branch protection must require these **2 job names**:
|
|
401
|
+
|
|
402
|
+
| Job | Gates covered | What it runs |
|
|
403
|
+
|-----|---------------|--------------|
|
|
404
|
+
| `guardrails` | 1–5 | allowlist → spec-lint → spec-breaking → generate → drift → manifest → code checks → docs checks |
|
|
405
|
+
| `codeql` | 5 | Static analysis (CodeQL) |
|
|
406
|
+
|
|
407
|
+
> **Tip**: If you need finer control, split into per-gate jobs (`gate-1`, `gate-2`, etc.) and require each.
|
|
408
|
+
|
|
409
|
+
### CODEOWNERS
|
|
410
|
+
|
|
411
|
+
| Path | Owner | Reason |
|
|
412
|
+
|------|-------|--------|
|
|
413
|
+
| `spec/spectral.yaml` | security/platform | Lint rules |
|
|
414
|
+
| `server/src/_shared/overlays/**` | security/platform | Security logic |
|
|
415
|
+
| `micro-contracts.guardrails.yaml` | security/platform | Guardrail config |
|
|
416
|
+
| `.github/**` | infra/maintainer | CI definitions |
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Developer Workflow
|
|
421
|
+
|
|
422
|
+
### Normal feature PR
|
|
423
|
+
|
|
424
|
+
1. Edit only `allowed` paths
|
|
425
|
+
2. If you change `spec/**`, run `generate`
|
|
426
|
+
3. Run `check` locally
|
|
427
|
+
4. Open PR → CI must pass
|
|
428
|
+
|
|
429
|
+
### Spec change
|
|
430
|
+
|
|
431
|
+
1. Update `spec/**/openapi/*.yaml`
|
|
432
|
+
2. Run `generate` (updates `packages/**`)
|
|
433
|
+
3. Run `check`
|
|
434
|
+
4. If oasdiff reports breaking changes, require explicit review
|
|
435
|
+
|
|
436
|
+
### What the guardrails prevent
|
|
437
|
+
|
|
438
|
+
| Scenario | Gate | Result |
|
|
439
|
+
|----------|------|--------|
|
|
440
|
+
| Edit `spec/**/*.yaml` → regenerate → commit | — | ✅ Allowed |
|
|
441
|
+
| Edit `server/src/**/domains/**` | — | ✅ Allowed |
|
|
442
|
+
| Edit `packages/**/*.ts` directly | 1 | ❌ Blocked |
|
|
443
|
+
| Edit `*.generated.ts` directly | 1 | ❌ Blocked |
|
|
444
|
+
| Edit spec but forget to regenerate | 3 | ❌ Fails drift |
|
|
445
|
+
| Create endpoint without `x-auth` | 2 | ❌ Fails spec-lint |
|
|
446
|
+
|
|
447
|
+
---
|
|
448
|
+
|
|
449
|
+
## Appendix: CI Configuration
|
|
450
|
+
|
|
451
|
+
### CI workflow
|
|
452
|
+
|
|
453
|
+
```yaml
|
|
454
|
+
# .github/workflows/ai-guardrails.yml
|
|
455
|
+
name: ai-guardrails
|
|
456
|
+
on: [pull_request]
|
|
457
|
+
|
|
458
|
+
env:
|
|
459
|
+
MC: npx --yes -p micro-contracts@${{ vars.MICRO_CONTRACTS_VERSION }} micro-contracts
|
|
460
|
+
|
|
461
|
+
jobs:
|
|
462
|
+
guardrails:
|
|
463
|
+
runs-on: ubuntu-latest
|
|
464
|
+
steps:
|
|
465
|
+
- uses: actions/checkout@v4
|
|
466
|
+
with: { fetch-depth: 0 }
|
|
467
|
+
|
|
468
|
+
# Gate 1-2 (pinned)
|
|
469
|
+
- run: ${{ env.MC }} check --gate 1,2
|
|
470
|
+
|
|
471
|
+
# Generator (pinned)
|
|
472
|
+
- run: ${{ env.MC }} generate
|
|
473
|
+
|
|
474
|
+
# Gate 3-5 (pinned)
|
|
475
|
+
- run: ${{ env.MC }} check --gate 3,4,5
|
|
476
|
+
|
|
477
|
+
codeql:
|
|
478
|
+
runs-on: ubuntu-latest
|
|
479
|
+
permissions: { security-events: write }
|
|
480
|
+
steps:
|
|
481
|
+
- uses: actions/checkout@v4
|
|
482
|
+
- uses: github/codeql-action/init@v3
|
|
483
|
+
with: { languages: javascript }
|
|
484
|
+
- run: npm ci && npm run build
|
|
485
|
+
- uses: github/codeql-action/analyze@v3
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
### npm scripts
|
|
489
|
+
|
|
490
|
+
<!--@embedoc:code_snippet file="../examples/package.json" lang="json" start="7" end="46" title="package.json scripts (example)"-->
|
|
491
|
+
**package.json scripts (example)**
|
|
492
|
+
|
|
493
|
+
```json
|
|
494
|
+
"scripts": {
|
|
495
|
+
"generate": "node ../dist/cli.js generate",
|
|
496
|
+
|
|
497
|
+
"check": "node ../dist/cli.js check",
|
|
498
|
+
"check:all": "node ../dist/cli.js check",
|
|
499
|
+
|
|
500
|
+
"check:gate1": "node ../dist/cli.js check --gate 1",
|
|
501
|
+
"check:gate2": "node ../dist/cli.js check --gate 2",
|
|
502
|
+
"check:gate3": "node ../dist/cli.js check --gate 3",
|
|
503
|
+
"check:gate4": "node ../dist/cli.js check --gate 4",
|
|
504
|
+
"check:gate5": "node ../dist/cli.js check --gate 5",
|
|
505
|
+
"check:gate1-2": "node ../dist/cli.js check --gate 1,2",
|
|
506
|
+
"check:gate3-5": "node ../dist/cli.js check --gate 3,4,5",
|
|
507
|
+
|
|
508
|
+
"check:allowlist": "node ../dist/cli.js check --only allowlist",
|
|
509
|
+
"check:spec-lint": "node ../dist/cli.js check --only spec-lint",
|
|
510
|
+
"check:spec-breaking": "node ../dist/cli.js check --only spec-breaking",
|
|
511
|
+
"check:drift": "node ../dist/cli.js check --only drift",
|
|
512
|
+
"check:manifest": "node ../dist/cli.js check --only manifest",
|
|
513
|
+
"check:package-typecheck": "node ../dist/cli.js check --only package-typecheck",
|
|
514
|
+
"check:code-lint": "node ../dist/cli.js check --only code-lint",
|
|
515
|
+
"check:code-typecheck": "node ../dist/cli.js check --only code-typecheck",
|
|
516
|
+
"check:docs-sync": "node ../dist/cli.js check --only docs-sync",
|
|
517
|
+
"check:docs-links": "node ../dist/cli.js check --only docs-links",
|
|
518
|
+
|
|
519
|
+
"lint:openapi": "spectral lint spec/core/openapi/core.yaml spec/billing/openapi/billing.yaml --ruleset spec/spectral.yaml",
|
|
520
|
+
"lint:openapi:generated": "spectral lint packages/contract/core/docs/openapi.generated.yaml packages/contract/billing/docs/openapi.generated.yaml --ruleset spec/spectral.yaml",
|
|
521
|
+
"lint:ts": "eslint server/src frontend/src --ext .ts,.tsx",
|
|
522
|
+
"lint": "npm run lint:openapi && npm run lint:ts",
|
|
523
|
+
|
|
524
|
+
"build": "npm run build:contract && npm run build:server && npm run build:frontend",
|
|
525
|
+
"build:contract": "tsc --noEmit -p packages/contract",
|
|
526
|
+
"build:server": "cd server && npm run build",
|
|
527
|
+
"build:frontend": "cd frontend && npm run build",
|
|
528
|
+
|
|
529
|
+
"dev": "concurrently -n server,frontend -c blue,green \"npm run server:dev\" \"npm run frontend:dev\"",
|
|
530
|
+
"server:install": "cd server && npm install",
|
|
531
|
+
"frontend:install": "cd frontend && npm install",
|
|
532
|
+
"server:dev": "cd server && PORT=3001 npm run dev",
|
|
533
|
+
"frontend:dev": "cd frontend && VITE_API_BASE_URL=http://localhost:3001 npm run dev -- --port 5173",
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
📄 Source: [`package.json`](../examples/package.json) (lines 7-46)
|
|
537
|
+
<!--@embedoc:end-->
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
*Last updated: 2026-01-06*
|