specshield 1.0.5 → 1.0.7
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 +687 -90
- package/package.json +1 -1
- package/src/api/contractsClient.js +88 -0
- package/src/cli.js +2 -0
- package/src/commands/contracts.js +561 -0
package/README.md
CHANGED
|
@@ -1,153 +1,742 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SpecShield CLI
|
|
2
2
|
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-

|
|
6
|
-

|
|
3
|
+
[](https://www.npmjs.com/package/specshield)
|
|
4
|
+
[](https://www.npmjs.com/package/specshield)
|
|
5
|
+
[](#license)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
7
|
|
|
8
8
|
Compare OpenAPI and Swagger specs, detect breaking changes, and fail CI before incompatible API changes reach production.
|
|
9
9
|
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [What is SpecShield CLI?](#what-is-specshield-cli)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Local Compare](#local-compare)
|
|
17
|
+
- [Authentication](#authentication)
|
|
18
|
+
- [Generate an API Token](#generate-an-api-token)
|
|
19
|
+
- [Remote Compare](#remote-compare)
|
|
20
|
+
- [Contracts — Consumer-Driven Testing](#contracts--consumer-driven-testing)
|
|
21
|
+
- [Contract File Format](#contract-file-format)
|
|
22
|
+
- [Publish a Contract](#publish-a-contract)
|
|
23
|
+
- [List Contracts](#list-contracts)
|
|
24
|
+
- [Get Latest Contract](#get-latest-contract)
|
|
25
|
+
- [Verify a Contract](#verify-a-contract)
|
|
26
|
+
- [Verification History](#verification-history)
|
|
27
|
+
- [Can I Deploy?](#can-i-deploy)
|
|
28
|
+
- [Full Publish → Verify → Deploy Workflow](#full-publish--verify--deploy-workflow)
|
|
29
|
+
- [Contracts in CI/CD](#contracts-in-cicd)
|
|
30
|
+
- [Config File](#config-file)
|
|
31
|
+
- [All Options](#all-options)
|
|
32
|
+
- [Exit Codes](#exit-codes)
|
|
33
|
+
- [CI/CD — GitHub Actions](#cicd--github-actions)
|
|
34
|
+
- [Support](#support)
|
|
10
35
|
|
|
11
|
-
|
|
36
|
+
---
|
|
12
37
|
|
|
13
|
-
|
|
38
|
+
## What is SpecShield CLI?
|
|
14
39
|
|
|
15
|
-
-
|
|
16
|
-
- ➕ Additions
|
|
17
|
-
- 🔄 Modifications
|
|
40
|
+
SpecShield CLI is a command-line tool for comparing two OpenAPI/Swagger specifications and detecting what changed between them. It classifies changes into:
|
|
18
41
|
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
42
|
+
- **Breaking changes** — removed endpoints, changed required fields, incompatible type changes
|
|
43
|
+
- **Modifications** — changed behavior that may or may not break clients
|
|
44
|
+
- **Additions** — new endpoints or fields
|
|
45
|
+
- **Warnings** — low-severity notices
|
|
46
|
+
|
|
47
|
+
It works in two modes:
|
|
48
|
+
|
|
49
|
+
| Mode | Description |
|
|
50
|
+
|---|---|
|
|
51
|
+
| **Local** | Compares two spec files on your machine. No account needed. |
|
|
52
|
+
| **Remote** | Sends specs to the SpecShield hosted API. Requires an API token. Results are stored in your dashboard. |
|
|
24
53
|
|
|
25
54
|
---
|
|
26
55
|
|
|
27
|
-
##
|
|
56
|
+
## Installation
|
|
28
57
|
|
|
29
|
-
|
|
30
|
-
-
|
|
31
|
-
|
|
32
|
-
- Partner integrations
|
|
33
|
-
- Internal microservices
|
|
58
|
+
```bash
|
|
59
|
+
npm install -g specshield
|
|
60
|
+
```
|
|
34
61
|
|
|
35
|
-
|
|
36
|
-
- ❌ Error-prone
|
|
37
|
-
- ❌ Time-consuming
|
|
38
|
-
- ❌ Not scalable
|
|
62
|
+
Verify the installation:
|
|
39
63
|
|
|
40
|
-
|
|
64
|
+
```bash
|
|
65
|
+
specshield --version
|
|
66
|
+
```
|
|
41
67
|
|
|
42
68
|
---
|
|
43
69
|
|
|
44
|
-
##
|
|
70
|
+
## Local Compare
|
|
71
|
+
|
|
72
|
+
No account or token required for local comparisons.
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
specshield compare base.yaml target.yaml
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Fail CI if breaking changes are found:
|
|
45
79
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
80
|
+
```bash
|
|
81
|
+
specshield compare base.yaml target.yaml --fail-on-breaking
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Output as JSON:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
specshield compare base.yaml target.yaml --json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Save results to a file:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
specshield compare base.yaml target.yaml --output result.json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Ignore specific changes:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
specshield compare base.yaml target.yaml --ignore "DELETE /users removed" --fail-on-breaking
|
|
100
|
+
```
|
|
52
101
|
|
|
53
102
|
---
|
|
54
103
|
|
|
55
|
-
##
|
|
104
|
+
## Authentication
|
|
56
105
|
|
|
57
|
-
|
|
58
|
-
- Support YAML and JSON OpenAPI specs
|
|
59
|
-
- CI/CD-ready with exit codes
|
|
60
|
-
- JSON output for automation
|
|
61
|
-
- `.specshield.yml` config support
|
|
62
|
-
- Ignore list for known changes
|
|
63
|
-
- Future SaaS-ready remote mode
|
|
106
|
+
Remote compare requires a SpecShield account and an API token.
|
|
64
107
|
|
|
65
|
-
|
|
108
|
+
### Sign in to SpecShield
|
|
109
|
+
|
|
110
|
+
1. Go to [https://specshield.io](https://specshield.io)
|
|
111
|
+
2. Sign in with your email/password, GitHub, or Google account
|
|
112
|
+
3. You will land on your account dashboard
|
|
113
|
+
|
|
114
|
+
### Generate an API Token
|
|
115
|
+
|
|
116
|
+
1. From your dashboard, go to **Account → API Keys**
|
|
117
|
+
(direct link: [https://specshield.io/account/keys](https://specshield.io/account/keys))
|
|
118
|
+
2. Click **Generate API Key**
|
|
119
|
+
3. Copy the token — it starts with `ss_` and is shown only once
|
|
120
|
+
4. Store it securely (password manager, secrets vault, or CI/CD secret)
|
|
121
|
+
|
|
122
|
+
### Configure the CLI
|
|
123
|
+
|
|
124
|
+
Run the login command with your token:
|
|
66
125
|
|
|
67
126
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
127
|
+
specshield login --api-key ss_your_token_here
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This validates the token against the SpecShield API and saves it to `~/.specshield/config.json`. You will not need to pass the token on every command after this.
|
|
131
|
+
|
|
132
|
+
**Example output:**
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
✔ Logged in successfully.
|
|
136
|
+
|
|
137
|
+
Customer: Jane Smith
|
|
138
|
+
Plan: FREE
|
|
139
|
+
Config: /Users/jane/.specshield/config.json
|
|
140
|
+
|
|
141
|
+
Run: specshield compare base.yaml target.yaml --remote
|
|
71
142
|
```
|
|
72
143
|
|
|
73
|
-
|
|
144
|
+
### Alternative: Environment Variable
|
|
145
|
+
|
|
146
|
+
If you prefer not to use the stored config (e.g. in CI/CD), set the token as an environment variable:
|
|
74
147
|
|
|
75
|
-
### Basic comparison
|
|
76
148
|
```bash
|
|
77
|
-
|
|
149
|
+
export SPECSHIELD_API_KEY=ss_your_token_here
|
|
150
|
+
specshield compare base.yaml target.yaml --remote
|
|
78
151
|
```
|
|
79
152
|
|
|
80
|
-
|
|
153
|
+
The token resolution order is:
|
|
154
|
+
|
|
155
|
+
1. `--api-key` flag (highest priority)
|
|
156
|
+
2. `SPECSHIELD_API_KEY` environment variable
|
|
157
|
+
3. Stored config (`~/.specshield/config.json`)
|
|
158
|
+
4. `remote.apiKey` in `.specshield.yml`
|
|
159
|
+
|
|
160
|
+
### Log Out
|
|
161
|
+
|
|
162
|
+
To remove the stored token:
|
|
163
|
+
|
|
81
164
|
```bash
|
|
82
|
-
specshield
|
|
165
|
+
specshield logout
|
|
83
166
|
```
|
|
84
167
|
|
|
85
|
-
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Remote Compare
|
|
171
|
+
|
|
172
|
+
Remote compare sends your spec files to the SpecShield hosted API at [https://specshield.io](https://specshield.io). Results are processed server-side and stored in your dashboard for review.
|
|
173
|
+
|
|
174
|
+
**When to use remote mode:**
|
|
175
|
+
- You want comparison history tracked in the SpecShield dashboard
|
|
176
|
+
- Your team shares a centralized view of API drift over time
|
|
177
|
+
- You are on a plan with advanced reporting features
|
|
178
|
+
|
|
179
|
+
### Basic remote compare
|
|
180
|
+
|
|
86
181
|
```bash
|
|
87
|
-
specshield compare base.yaml target.yaml --
|
|
182
|
+
specshield compare base.yaml target.yaml --remote
|
|
88
183
|
```
|
|
89
184
|
|
|
90
|
-
###
|
|
185
|
+
### Remote compare with CI fail on breaking changes
|
|
186
|
+
|
|
91
187
|
```bash
|
|
92
|
-
specshield compare base.yaml target.yaml --
|
|
188
|
+
specshield compare base.yaml target.yaml --remote --fail-on-breaking
|
|
93
189
|
```
|
|
94
190
|
|
|
95
|
-
###
|
|
191
|
+
### Remote compare with JSON output
|
|
192
|
+
|
|
96
193
|
```bash
|
|
97
|
-
specshield compare base.yaml target.yaml --
|
|
194
|
+
specshield compare base.yaml target.yaml --remote --json --output result.json
|
|
98
195
|
```
|
|
99
196
|
|
|
100
|
-
###
|
|
197
|
+
### How authentication works in remote mode
|
|
198
|
+
|
|
199
|
+
The CLI reads your API token (from flag, env var, or stored config) and sends it as an `X-Api-Key` header with each request. If no token is found, the command exits with an error:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
Error: No API key found. Run: specshield login --api-key <KEY>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Contracts — Consumer-Driven Testing
|
|
210
|
+
|
|
211
|
+
SpecShield Contracts lets consumer teams publish API expectations (contracts) to a central registry. Provider teams then verify their service satisfies those contracts before deploying.
|
|
212
|
+
|
|
213
|
+
**Why contract testing?**
|
|
214
|
+
- Catch provider-side regressions before they reach consumers
|
|
215
|
+
- Enforce an agreed-upon API shape across services
|
|
216
|
+
- Gate deployments on verified contracts with `can-i-deploy`
|
|
217
|
+
|
|
218
|
+
All contract commands require an API token. See [Authentication](#authentication).
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
### Contract File Format
|
|
223
|
+
|
|
224
|
+
Create a `.json` file describing the expected API interactions:
|
|
225
|
+
|
|
226
|
+
```json
|
|
227
|
+
{
|
|
228
|
+
"consumer": {
|
|
229
|
+
"name": "checkout-ui",
|
|
230
|
+
"version": "1.2.0"
|
|
231
|
+
},
|
|
232
|
+
"provider": {
|
|
233
|
+
"name": "payment-service"
|
|
234
|
+
},
|
|
235
|
+
"contractName": "create-payment",
|
|
236
|
+
"contractType": "HTTP",
|
|
237
|
+
"interactions": [
|
|
238
|
+
{
|
|
239
|
+
"description": "create payment",
|
|
240
|
+
"request": {
|
|
241
|
+
"method": "POST",
|
|
242
|
+
"path": "/payments",
|
|
243
|
+
"headers": {
|
|
244
|
+
"Content-Type": "application/json"
|
|
245
|
+
},
|
|
246
|
+
"body": {
|
|
247
|
+
"orderId": "ORD-123",
|
|
248
|
+
"amount": 100,
|
|
249
|
+
"currency": "INR"
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"expectedResponse": {
|
|
253
|
+
"status": 201,
|
|
254
|
+
"headers": {
|
|
255
|
+
"Content-Type": "application/json"
|
|
256
|
+
},
|
|
257
|
+
"body": {
|
|
258
|
+
"paymentId": "PAY-123",
|
|
259
|
+
"status": "CREATED"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
],
|
|
264
|
+
"metadata": {
|
|
265
|
+
"generatedBy": "specshield-cli",
|
|
266
|
+
"contractFormatVersion": "1.0"
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The `consumer.name`, `provider.name`, and `contractName` fields are used to identify the contract in the registry. CLI flags (`--consumer`, `--provider`, `--contract-name`) override file values if provided.
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
### Publish a Contract
|
|
276
|
+
|
|
101
277
|
```bash
|
|
102
|
-
specshield
|
|
278
|
+
specshield contracts publish \
|
|
279
|
+
--file ./contracts/create-payment.json \
|
|
280
|
+
--org acme
|
|
103
281
|
```
|
|
104
282
|
|
|
105
|
-
|
|
283
|
+
With all flags explicitly set (flags override file values):
|
|
106
284
|
|
|
107
|
-
|
|
285
|
+
```bash
|
|
286
|
+
specshield contracts publish \
|
|
287
|
+
--file ./contracts/create-payment.json \
|
|
288
|
+
--org acme \
|
|
289
|
+
--consumer checkout-ui \
|
|
290
|
+
--provider payment-service \
|
|
291
|
+
--contract-name create-payment \
|
|
292
|
+
--consumer-version 1.2.0 \
|
|
293
|
+
--tag main
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Example output:**
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
✔ Contract Published Successfully
|
|
300
|
+
─────────────────────────────────────────────────────
|
|
301
|
+
Contract ID : 42
|
|
302
|
+
Contract Name : create-payment
|
|
303
|
+
Consumer : checkout-ui
|
|
304
|
+
Provider : payment-service
|
|
305
|
+
Version : 3
|
|
306
|
+
Status : PUBLISHED
|
|
307
|
+
Content Hash : a3f9c1d2e7b8...
|
|
308
|
+
Published At : 06/04/2026 14:30:00
|
|
309
|
+
|
|
310
|
+
➜ Run: specshield contracts verify --contract-id 42 --base-url http://localhost:8080
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
**Options:**
|
|
314
|
+
|
|
315
|
+
| Flag | Description |
|
|
108
316
|
|---|---|
|
|
109
|
-
| `--
|
|
110
|
-
| `--
|
|
111
|
-
| `--
|
|
112
|
-
| `--
|
|
113
|
-
| `--
|
|
114
|
-
| `--
|
|
115
|
-
| `--
|
|
116
|
-
| `--
|
|
117
|
-
| `--
|
|
317
|
+
| `--file <path>` | Path to contract JSON file (required) |
|
|
318
|
+
| `--org <key>` | Organization key |
|
|
319
|
+
| `--consumer <key>` | Consumer service key (overrides file) |
|
|
320
|
+
| `--provider <key>` | Provider service key (overrides file) |
|
|
321
|
+
| `--consumer-version <ver>` | Consumer version tag |
|
|
322
|
+
| `--contract-name <name>` | Contract name (overrides file) |
|
|
323
|
+
| `--tag <tag>` | Git branch or release tag |
|
|
324
|
+
| `--server <url>` | SpecShield server URL (default: `https://specshield.io`) |
|
|
325
|
+
| `--api-token <token>` | API token |
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
### List Contracts
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
specshield contracts list
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Filter by provider:
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
specshield contracts list --provider payment-service
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Filter by consumer, org, status:
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
specshield contracts list \
|
|
345
|
+
--consumer checkout-ui \
|
|
346
|
+
--provider payment-service \
|
|
347
|
+
--status PUBLISHED
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Output raw JSON:
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
specshield contracts list --json
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Example output:**
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
SpecShield Contract Registry
|
|
360
|
+
─────────────────────────────────────────────────────
|
|
361
|
+
Showing 2 of 2 contracts
|
|
362
|
+
|
|
363
|
+
ID Contract Name Consumer Provider Ver Status Last Verify Published
|
|
364
|
+
── ─────────────── ──────────── ─────────────── ─── ───────── ─────────── ─────────────────────
|
|
365
|
+
42 create-payment checkout-ui payment-service 3 PUBLISHED SUCCESS 06/04/2026 14:30:00
|
|
366
|
+
41 get-order-status order-ui order-service 1 PUBLISHED FAILED 05/04/2026 09:15:00
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
**Options:**
|
|
370
|
+
|
|
371
|
+
| Flag | Description |
|
|
372
|
+
|---|---|
|
|
373
|
+
| `--consumer <key>` | Filter by consumer |
|
|
374
|
+
| `--provider <key>` | Filter by provider |
|
|
375
|
+
| `--org <key>` | Filter by organization |
|
|
376
|
+
| `--status <status>` | Filter by status (`PUBLISHED` / `DEPRECATED`) |
|
|
377
|
+
| `--contract-name <name>` | Filter by contract name |
|
|
378
|
+
| `--page <n>` | Page number (0-based, default: `0`) |
|
|
379
|
+
| `--size <n>` | Page size (default: `20`) |
|
|
380
|
+
| `--json` | Output raw JSON |
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### Get Latest Contract
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
specshield contracts latest \
|
|
388
|
+
--consumer checkout-ui \
|
|
389
|
+
--provider payment-service \
|
|
390
|
+
--contract-name create-payment
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Print the full contract content (interactions, body, etc.):
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
specshield contracts latest \
|
|
397
|
+
--consumer checkout-ui \
|
|
398
|
+
--provider payment-service \
|
|
399
|
+
--json
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
**Options:**
|
|
403
|
+
|
|
404
|
+
| Flag | Description |
|
|
405
|
+
|---|---|
|
|
406
|
+
| `--consumer <key>` | Consumer service key |
|
|
407
|
+
| `--provider <key>` | Provider service key |
|
|
408
|
+
| `--org <key>` | Organization key |
|
|
409
|
+
| `--contract-name <name>` | Contract name |
|
|
410
|
+
| `--json` | Print full contract JSON |
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
### Verify a Contract
|
|
415
|
+
|
|
416
|
+
Run the contract against a live provider. SpecShield replays each interaction against the `--base-url` and compares the response to the expected values.
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
specshield contracts verify \
|
|
420
|
+
--contract-id 42 \
|
|
421
|
+
--base-url http://localhost:8080
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
With version and environment tags:
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
specshield contracts verify \
|
|
428
|
+
--contract-id 42 \
|
|
429
|
+
--base-url https://payment-service.staging.internal \
|
|
430
|
+
--provider-version v2.1.0 \
|
|
431
|
+
--env staging
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
Output raw JSON (for CI parsing):
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
specshield contracts verify \
|
|
438
|
+
--contract-id 42 \
|
|
439
|
+
--base-url http://localhost:8080 \
|
|
440
|
+
--json
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
**Example output (pass):**
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
✔ Verification PASSED (1/1 interactions)
|
|
447
|
+
─────────────────────────────────────────────────────
|
|
448
|
+
Verification ID : 101
|
|
449
|
+
Contract ID : 42
|
|
450
|
+
Status : SUCCESS
|
|
451
|
+
Started At : 06/04/2026 14:35:00
|
|
452
|
+
Completed At : 06/04/2026 14:35:01
|
|
453
|
+
|
|
454
|
+
➜ Run: specshield contracts can-i-deploy --provider payment-service --version v2.1.0
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**Example output (fail):**
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
✖ Verification FAILED (0/1 interactions passed, 1 failed)
|
|
461
|
+
─────────────────────────────────────────────────────
|
|
462
|
+
Verification ID : 102
|
|
463
|
+
Contract ID : 42
|
|
464
|
+
Status : FAILED
|
|
465
|
+
|
|
466
|
+
Mismatches
|
|
467
|
+
─────────────────────────────────────────────────────
|
|
468
|
+
● [create payment] STATUS_CODE_MISMATCH at $.status
|
|
469
|
+
expected: 201 → actual: 200
|
|
470
|
+
Expected status 201 but got 200
|
|
471
|
+
|
|
472
|
+
➜ Run: specshield contracts history --contract-id 42 to inspect previous runs
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
**Exit codes:** `0` = PASSED, `1` = FAILED, `2` = error
|
|
476
|
+
|
|
477
|
+
**Options:**
|
|
478
|
+
|
|
479
|
+
| Flag | Description |
|
|
480
|
+
|---|---|
|
|
481
|
+
| `--contract-id <id>` | Contract ID to verify (required) |
|
|
482
|
+
| `--base-url <url>` | Provider base URL (required, e.g. `http://localhost:8080`) |
|
|
483
|
+
| `--provider-version <ver>` | Provider version tag |
|
|
484
|
+
| `--env <environment>` | Environment label (`staging`, `qa`, `production`) |
|
|
485
|
+
| `--mode <mode>` | `LIVE` or `REPLAY` (default: `LIVE`) |
|
|
486
|
+
| `--json` | Output raw JSON |
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
### Verification History
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
specshield contracts history --contract-id 42
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
**Example output:**
|
|
497
|
+
|
|
498
|
+
```
|
|
499
|
+
Verification History — Contract 42
|
|
500
|
+
─────────────────────────────────────────────────────
|
|
501
|
+
|
|
502
|
+
ID Status Environment Provider Version Mode Completed At
|
|
503
|
+
─── ─────── ─────────── ──────────────── ──── ─────────────────────
|
|
504
|
+
102 FAILED staging v2.1.0 LIVE 06/04/2026 14:35:01
|
|
505
|
+
101 SUCCESS staging v2.0.0 LIVE 05/04/2026 10:00:00
|
|
506
|
+
98 SUCCESS qa v1.9.0 LIVE 01/04/2026 08:30:00
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
**Options:**
|
|
510
|
+
|
|
511
|
+
| Flag | Description |
|
|
512
|
+
|---|---|
|
|
513
|
+
| `--contract-id <id>` | Contract ID (required) |
|
|
514
|
+
| `--json` | Output raw JSON |
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
### Can I Deploy?
|
|
519
|
+
|
|
520
|
+
Check whether a provider version has passing verifications for all associated contracts:
|
|
521
|
+
|
|
522
|
+
```bash
|
|
523
|
+
specshield contracts can-i-deploy \
|
|
524
|
+
--provider payment-service \
|
|
525
|
+
--version v2.1.0
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
Scoped to a specific environment:
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
specshield contracts can-i-deploy \
|
|
532
|
+
--provider payment-service \
|
|
533
|
+
--version v2.1.0 \
|
|
534
|
+
--env production
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Example output (allowed):**
|
|
538
|
+
|
|
539
|
+
```
|
|
540
|
+
✔ PASS: payment-service v2.1.0 is deployable in production
|
|
541
|
+
─────────────────────────────────────────────────────
|
|
542
|
+
|
|
543
|
+
Contract Decisions
|
|
544
|
+
✔ Contract ID 42 — SUCCESS
|
|
545
|
+
All contracts verified
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
**Example output (blocked):**
|
|
549
|
+
|
|
550
|
+
```
|
|
551
|
+
✖ FAIL: payment-service v2.1.0 is NOT deployable in production
|
|
552
|
+
─────────────────────────────────────────────────────
|
|
553
|
+
|
|
554
|
+
Contract Decisions
|
|
555
|
+
✖ Contract ID 43 — FAILED
|
|
556
|
+
Unverified or failed contracts found
|
|
557
|
+
|
|
558
|
+
➜ Run: specshield contracts verify --contract-id 43 --base-url <URL>
|
|
559
|
+
➜ to verify pending contracts before deploying
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
**Exit codes:** `0` = deployable, `1` = blocked, `2` = error
|
|
563
|
+
|
|
564
|
+
**Options:**
|
|
565
|
+
|
|
566
|
+
| Flag | Description |
|
|
567
|
+
|---|---|
|
|
568
|
+
| `--provider <key>` | Provider service key (required) |
|
|
569
|
+
| `--version <ver>` | Provider version to check (required) |
|
|
570
|
+
| `--env <environment>` | Target environment |
|
|
571
|
+
| `--json` | Output raw JSON |
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
### Full Publish → Verify → Deploy Workflow
|
|
576
|
+
|
|
577
|
+
```bash
|
|
578
|
+
# 1. Consumer team publishes a contract
|
|
579
|
+
specshield contracts publish \
|
|
580
|
+
--file ./contracts/create-payment.json \
|
|
581
|
+
--org acme
|
|
582
|
+
|
|
583
|
+
# 2. Provider team starts their service locally
|
|
584
|
+
./gradlew bootRun &
|
|
585
|
+
|
|
586
|
+
# 3. Provider team verifies the contract
|
|
587
|
+
specshield contracts verify \
|
|
588
|
+
--contract-id 42 \
|
|
589
|
+
--base-url http://localhost:8080 \
|
|
590
|
+
--provider-version v2.1.0 \
|
|
591
|
+
--env staging
|
|
592
|
+
|
|
593
|
+
# 4. Gate the deployment
|
|
594
|
+
specshield contracts can-i-deploy \
|
|
595
|
+
--provider payment-service \
|
|
596
|
+
--version v2.1.0 \
|
|
597
|
+
--env staging
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
### Contracts in CI/CD
|
|
603
|
+
|
|
604
|
+
#### GitHub Actions — Publish on consumer change
|
|
605
|
+
|
|
606
|
+
```yaml
|
|
607
|
+
name: Publish Contract
|
|
608
|
+
|
|
609
|
+
on:
|
|
610
|
+
push:
|
|
611
|
+
branches: [main]
|
|
612
|
+
paths:
|
|
613
|
+
- 'contracts/**'
|
|
614
|
+
|
|
615
|
+
jobs:
|
|
616
|
+
publish-contract:
|
|
617
|
+
runs-on: ubuntu-latest
|
|
618
|
+
steps:
|
|
619
|
+
- uses: actions/checkout@v4
|
|
620
|
+
- uses: actions/setup-node@v4
|
|
621
|
+
with:
|
|
622
|
+
node-version: '20'
|
|
623
|
+
- run: npm install -g specshield
|
|
624
|
+
- name: Publish contract
|
|
625
|
+
env:
|
|
626
|
+
SPECSHIELD_API_KEY: ${{ secrets.SPECSHIELD_API_KEY }}
|
|
627
|
+
run: |
|
|
628
|
+
specshield contracts publish \
|
|
629
|
+
--file ./contracts/create-payment.json \
|
|
630
|
+
--org acme \
|
|
631
|
+
--tag ${{ github.ref_name }}
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
#### GitHub Actions — Verify + can-i-deploy on provider change
|
|
635
|
+
|
|
636
|
+
```yaml
|
|
637
|
+
name: Contract Verification
|
|
638
|
+
|
|
639
|
+
on:
|
|
640
|
+
push:
|
|
641
|
+
branches: [main]
|
|
642
|
+
|
|
643
|
+
jobs:
|
|
644
|
+
verify-contracts:
|
|
645
|
+
runs-on: ubuntu-latest
|
|
646
|
+
services:
|
|
647
|
+
payment-service:
|
|
648
|
+
image: myorg/payment-service:${{ github.sha }}
|
|
649
|
+
ports:
|
|
650
|
+
- 8080:8080
|
|
651
|
+
steps:
|
|
652
|
+
- uses: actions/checkout@v4
|
|
653
|
+
- uses: actions/setup-node@v4
|
|
654
|
+
with:
|
|
655
|
+
node-version: '20'
|
|
656
|
+
- run: npm install -g specshield
|
|
657
|
+
|
|
658
|
+
- name: Verify contract
|
|
659
|
+
env:
|
|
660
|
+
SPECSHIELD_API_KEY: ${{ secrets.SPECSHIELD_API_KEY }}
|
|
661
|
+
run: |
|
|
662
|
+
specshield contracts verify \
|
|
663
|
+
--contract-id ${{ vars.PAYMENT_CONTRACT_ID }} \
|
|
664
|
+
--base-url http://localhost:8080 \
|
|
665
|
+
--provider-version ${{ github.sha }} \
|
|
666
|
+
--env staging
|
|
667
|
+
|
|
668
|
+
- name: Can I deploy?
|
|
669
|
+
env:
|
|
670
|
+
SPECSHIELD_API_KEY: ${{ secrets.SPECSHIELD_API_KEY }}
|
|
671
|
+
run: |
|
|
672
|
+
specshield contracts can-i-deploy \
|
|
673
|
+
--provider payment-service \
|
|
674
|
+
--version ${{ github.sha }} \
|
|
675
|
+
--env staging
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
---
|
|
118
679
|
|
|
119
680
|
## Config File
|
|
120
681
|
|
|
121
|
-
Create `.specshield.yml` in your project root:
|
|
682
|
+
Create `.specshield.yml` in your project root to set default behavior:
|
|
122
683
|
|
|
123
684
|
```yaml
|
|
124
|
-
allowBreakingChanges: false
|
|
125
685
|
failOnBreaking: true
|
|
686
|
+
allowBreakingChanges: false
|
|
687
|
+
severity: error
|
|
126
688
|
|
|
127
689
|
ignore:
|
|
128
|
-
- "
|
|
129
|
-
- "
|
|
130
|
-
|
|
131
|
-
severity: error
|
|
690
|
+
- "DELETE /admin removed"
|
|
691
|
+
- "User.internal_id removed"
|
|
132
692
|
|
|
133
693
|
remote:
|
|
134
694
|
enabled: false
|
|
135
|
-
url: "https://
|
|
695
|
+
url: "https://specshield.io/compare"
|
|
136
696
|
timeout: 10000
|
|
697
|
+
apiKey: "" # prefer env var or specshield login instead
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
CLI flags always override config file values.
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
## All Options
|
|
705
|
+
|
|
706
|
+
```bash
|
|
707
|
+
specshield compare <base> <target> [options]
|
|
137
708
|
```
|
|
138
709
|
|
|
139
|
-
|
|
710
|
+
| Option | Description |
|
|
711
|
+
|---|---|
|
|
712
|
+
| `--remote` | Use the SpecShield hosted compare API |
|
|
713
|
+
| `--api-key <key>` | API token for remote mode (overrides env and stored config) |
|
|
714
|
+
| `--remote-url <url>` | Override the hosted API base URL |
|
|
715
|
+
| `--fail-on-breaking` | Exit code 1 if breaking changes are found |
|
|
716
|
+
| `--allow-breaking` | Override fail-on-breaking |
|
|
717
|
+
| `--json` | Output machine-readable JSON |
|
|
718
|
+
| `--output <file>` | Save result to a file |
|
|
719
|
+
| `--ignore <change>` | Ignore a specific change string (repeatable) |
|
|
720
|
+
| `--severity <level>` | Minimum severity: `info` / `warning` / `error` |
|
|
721
|
+
| `--config <path>` | Path to `.specshield.yml` |
|
|
722
|
+
| `--timeout <ms>` | Request timeout for remote mode (default: 10000) |
|
|
723
|
+
|
|
724
|
+
---
|
|
140
725
|
|
|
141
726
|
## Exit Codes
|
|
142
727
|
|
|
143
728
|
| Code | Meaning |
|
|
144
729
|
|---|---|
|
|
145
730
|
| `0` | Success — no blocking issues |
|
|
146
|
-
| `1` | Breaking changes found and `--fail-on-breaking` active |
|
|
147
|
-
| `2` | Invalid input, config error, or runtime error |
|
|
731
|
+
| `1` | Breaking changes found and `--fail-on-breaking` is active |
|
|
732
|
+
| `2` | Invalid input, missing token, config error, or runtime error |
|
|
733
|
+
|
|
734
|
+
---
|
|
148
735
|
|
|
149
736
|
## CI/CD — GitHub Actions
|
|
150
737
|
|
|
738
|
+
### Local compare (no token required)
|
|
739
|
+
|
|
151
740
|
```yaml
|
|
152
741
|
name: API Contract Check
|
|
153
742
|
|
|
@@ -169,7 +758,6 @@ jobs:
|
|
|
169
758
|
|
|
170
759
|
- run: npm install -g specshield
|
|
171
760
|
|
|
172
|
-
# Option A: spec files are committed to the repo
|
|
173
761
|
- name: Get base spec from main branch
|
|
174
762
|
run: git show origin/main:api/openapi.yaml > /tmp/base-spec.yaml
|
|
175
763
|
|
|
@@ -187,22 +775,31 @@ jobs:
|
|
|
187
775
|
path: spec-diff.json
|
|
188
776
|
```
|
|
189
777
|
|
|
190
|
-
|
|
778
|
+
### Remote compare (with SpecShield hosted API)
|
|
191
779
|
|
|
192
|
-
|
|
780
|
+
Add your API token as a GitHub Actions secret named `SPECSHIELD_API_KEY`, then:
|
|
193
781
|
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
782
|
+
```yaml
|
|
783
|
+
- name: Compare specs (remote)
|
|
784
|
+
env:
|
|
785
|
+
SPECSHIELD_API_KEY: ${{ secrets.SPECSHIELD_API_KEY }}
|
|
786
|
+
run: |
|
|
787
|
+
specshield compare /tmp/base-spec.yaml api/openapi.yaml \
|
|
788
|
+
--remote \
|
|
789
|
+
--fail-on-breaking \
|
|
790
|
+
--output spec-diff.json
|
|
198
791
|
```
|
|
199
792
|
|
|
200
|
-
|
|
793
|
+
> **Note:** If your project generates its OpenAPI spec dynamically (e.g. Spring Boot, FastAPI), add a build step before the compare step to generate the spec from your code.
|
|
201
794
|
|
|
202
|
-
|
|
203
|
-
npm test
|
|
204
|
-
```
|
|
795
|
+
---
|
|
205
796
|
|
|
206
797
|
## License
|
|
207
798
|
|
|
208
799
|
MIT © Deepak Satyam
|
|
800
|
+
|
|
801
|
+
---
|
|
802
|
+
|
|
803
|
+
## Support
|
|
804
|
+
|
|
805
|
+
Questions or issues? Reach out at [admin@specshield.io](mailto:admin@specshield.io) or open an issue on GitHub.
|