@postman/postman-plugin 0.3.0 → 0.4.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 +32 -8
- package/dist/hosts/antigravity.js +47 -0
- package/dist/hosts/copilot.js +60 -0
- package/dist/hosts/index.js +3 -1
- package/mcp.pi.json +2 -2
- package/package.json +1 -1
- package/skills/ai-readiness/SKILL.md +40 -44
- package/skills/api-discovery/SKILL.md +64 -145
- package/skills/api-discovery/reference/orbit.md +17 -5
- package/skills/api-documentation/SKILL.md +41 -46
- package/skills/api-engineer/SKILL.md +78 -23
- package/skills/api-mocking/SKILL.md +117 -163
- package/skills/api-monitoring/SKILL.md +52 -129
- package/skills/api-simulation/SKILL.md +130 -178
- package/skills/api-simulation/reference/sim_yaml_schema.md +41 -103
- package/skills/api-testing/SKILL.md +48 -95
- package/skills/bootstrap/SKILL.md +123 -224
- package/skills/ci-integration/SKILL.md +53 -113
- package/skills/collection-schema-v3/SKILL.md +43 -204
- package/skills/collection-schema-v3/reference/http.md +150 -0
- package/skills/datasets/SKILL.md +89 -315
- package/skills/datasets/reference/spreadsheets.md +25 -0
- package/skills/flows/SKILL.md +57 -206
- package/skills/flows/reference/flow_cli_flags.md +3 -2
- package/skills/performance-testing/SKILL.md +46 -62
- package/skills/performance-testing/references/jmeter-import/README.md +113 -0
- package/skills/performance-testing/references/jmeter-import/import-report.md +52 -0
- package/skills/performance-testing/references/jmeter-import/mapping-table.md +97 -0
- package/skills/performance-testing/references/jmeter-import/postman-perf-capabilities.md +56 -0
- package/skills/performance-testing/references/jmeter-import/script-translation.md +98 -0
- package/skills/performance-testing/references/jmeter-import/scripts/groovy_to_js.py +83 -0
- package/skills/performance-testing/references/jmeter-import/scripts/jmx_to_postman.py +1433 -0
- package/skills/postman-mcp-server/SKILL.md +53 -59
- package/skills/postman-mcp-server/references/docs.md +0 -1
- package/skills/postman-mcp-server/references/learn.md +10 -9
- package/skills/postman-mcp-server/references/mock.md +0 -1
- package/skills/postman-mcp-server/references/search.md +0 -1
- package/skills/postman-mcp-server/references/security.md +0 -1
- package/skills/postman-mcp-server/references/setup.md +0 -1
- package/skills/postman-mcp-server/references/sync.md +0 -1
- package/skills/postman-mcp-server/references/test.md +0 -1
- package/skills/variables/SKILL.md +44 -87
- package/skills/webhook-testing/SKILL.md +103 -0
- package/skills/webhook-testing/reference/forwarding.md +10 -0
- package/skills/webhook-testing/reference/outbound_webhooks.md +25 -0
- package/skills/webhook-testing/reference/webhook_scripts.md +163 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Webhook scripts
|
|
2
|
+
|
|
3
|
+
Recipes for the `onEvent` script that `postman webhook scripts set` uploads.
|
|
4
|
+
Each delivery runs the script in a fresh Postman sandbox, with the incoming
|
|
5
|
+
request in `pm.request`. `pm.test` results appear in
|
|
6
|
+
`postman webhook requests describe <webhookId> <requestId>`, and the
|
|
7
|
+
`console.log` output appears with `--verbose`.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
postman webhook scripts set <webhookId> ./webhooks/github-on-event.js --event onEvent
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Contents
|
|
14
|
+
|
|
15
|
+
- [How webhook scripts behave](#how-webhook-scripts-behave)
|
|
16
|
+
- [What a script can use](#what-a-script-can-use)
|
|
17
|
+
- [Asserting on the payload](#asserting-on-the-payload)
|
|
18
|
+
- [Signature checks](#signature-checks): GitHub, Stripe, Slack, any HMAC
|
|
19
|
+
|
|
20
|
+
## How webhook scripts behave
|
|
21
|
+
|
|
22
|
+
- **`onEvent`** runs when a request arrives, before Postman forwards or
|
|
23
|
+
responds. Use it to validate the payload, verify the signature, or modify
|
|
24
|
+
the request. **`onResponse`** runs after Postman has responded to the
|
|
25
|
+
sender. Use it for logging and follow-up work from your local responder
|
|
26
|
+
or the configured forwarding endpoint.
|
|
27
|
+
- **The file in the repo is the only copy you can read.** The CLI has
|
|
28
|
+
`scripts set` but no command that reads a script back, and a second `set`
|
|
29
|
+
replaces the first. Commit the script beside the handler it guards, and set
|
|
30
|
+
it again after you edit it. The file can be JavaScript or TypeScript.
|
|
31
|
+
- **No state carries over between deliveries.** A script can't remember which
|
|
32
|
+
event ids it has already seen, so test duplicate handling in the handler, by
|
|
33
|
+
replaying a request twice.
|
|
34
|
+
- **Secrets come from the linked environment.** Read a signing secret with
|
|
35
|
+
`pm.environment.get` and never write it into the file. An environment is
|
|
36
|
+
linked to a webhook in its settings in the Postman app. See the `variables`
|
|
37
|
+
skill for where a secret belongs.
|
|
38
|
+
- **Results are per delivery.** The console output that `--verbose` shows is
|
|
39
|
+
capped at 25 KB per event.
|
|
40
|
+
- **A script is a test, not your handler's guard.** Postman doesn't document
|
|
41
|
+
that a failing `pm.test` stops the request from being routed. Your handler
|
|
42
|
+
verifies signatures itself, whatever the script reports.
|
|
43
|
+
|
|
44
|
+
## What a script can use
|
|
45
|
+
|
|
46
|
+
| Available | Not available |
|
|
47
|
+
| --- | --- |
|
|
48
|
+
| `pm.request.headers.get(name)`, `pm.request.body.raw` | `pm.globals`, `pm.collectionVariables`, `pm.iterationData` |
|
|
49
|
+
| `pm.test`, `pm.expect` | `pm.execution.setNextRequest`, `pm.visualizer` |
|
|
50
|
+
| `pm.environment.get`, from the environment linked to the webhook | State that lasts beyond one delivery |
|
|
51
|
+
| `require("crypto-js")` and other packages, from the Package Library, npm or JSR | |
|
|
52
|
+
| `pm.execution.runRequest`, to run a saved collection request | |
|
|
53
|
+
|
|
54
|
+
Parse and hash `pm.request.body.raw`. Postman keeps the body exactly as the
|
|
55
|
+
sender sent it, and every signature scheme below is computed over those exact
|
|
56
|
+
bytes. A body that was parsed and serialized again fails the check even when
|
|
57
|
+
the JSON is the same.
|
|
58
|
+
|
|
59
|
+
## Asserting on the payload
|
|
60
|
+
|
|
61
|
+
Write down the contract the handler depends on. A test fails on the first
|
|
62
|
+
delivery that breaks it, instead of when the handler happens to crash.
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
// Just a reference based on expected payload, it can be of a different data type as well.
|
|
66
|
+
const event = JSON.parse(pm.request.body.raw);
|
|
67
|
+
|
|
68
|
+
pm.test("is a JSON event with an id and a type", function () {
|
|
69
|
+
pm.expect(event).to.have.property("id").that.is.a("string");
|
|
70
|
+
pm.expect(event).to.have.property("type").that.is.a("string");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
pm.test("is an event this handler subscribes to", function () {
|
|
74
|
+
pm.expect(["payment_intent.succeeded", "payment_intent.payment_failed"])
|
|
75
|
+
.to.include(event.type);
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Signature checks
|
|
80
|
+
|
|
81
|
+
Postman also has signature-verification presets for Stripe, GitHub and Slack
|
|
82
|
+
in the Postman app. Use a script when you want the check in a file that can be
|
|
83
|
+
reviewed, or when the provider has no preset. Read the secret from the linked
|
|
84
|
+
environment. A secret pasted into the script ends up in the repo and in the
|
|
85
|
+
webhook's configuration.
|
|
86
|
+
|
|
87
|
+
### GitHub
|
|
88
|
+
|
|
89
|
+
`X-Hub-Signature-256` is `sha256=` followed by the hex HMAC-SHA256 of the raw
|
|
90
|
+
body. There's no timestamp, so a replayed delivery still verifies.
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
const CryptoJS = require("crypto-js");
|
|
94
|
+
|
|
95
|
+
const secret = pm.environment.get("github_webhook_secret");
|
|
96
|
+
const expected = "sha256=" +
|
|
97
|
+
CryptoJS.HmacSHA256(pm.request.body.raw, secret).toString(CryptoJS.enc.Hex);
|
|
98
|
+
|
|
99
|
+
pm.test("GitHub signature matches the body", function () {
|
|
100
|
+
pm.expect(pm.request.headers.get("X-Hub-Signature-256")).to.equal(expected);
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Stripe
|
|
105
|
+
|
|
106
|
+
`Stripe-Signature` is `t=<unix seconds>,v1=<hex>[,v1=<hex>…]`. Stripe signs
|
|
107
|
+
`<t>.<raw body>` with the endpoint's whole `whsec_…` secret, prefix included.
|
|
108
|
+
More than one `v1` appears while a secret is being rolled, and any one of them
|
|
109
|
+
can match.
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const CryptoJS = require("crypto-js");
|
|
113
|
+
|
|
114
|
+
const secret = pm.environment.get("stripe_webhook_secret");
|
|
115
|
+
const fields = pm.request.headers.get("Stripe-Signature").split(",");
|
|
116
|
+
const t = fields.find(f => f.startsWith("t=")).slice(2);
|
|
117
|
+
const signatures = fields.filter(f => f.startsWith("v1=")).map(f => f.slice(3));
|
|
118
|
+
const expected = CryptoJS.HmacSHA256(t + "." + pm.request.body.raw, secret)
|
|
119
|
+
.toString(CryptoJS.enc.Hex);
|
|
120
|
+
|
|
121
|
+
pm.test("Stripe signature matches the body", function () {
|
|
122
|
+
pm.expect(signatures).to.include(expected);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
pm.test("Stripe timestamp is within five minutes", function () {
|
|
126
|
+
pm.expect(Math.abs(Date.now() / 1000 - Number(t))).to.be.below(300);
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The timestamp test fails on a replay of anything older than five minutes. That
|
|
131
|
+
failure is expected and doesn't mean the replay is broken.
|
|
132
|
+
|
|
133
|
+
### Slack
|
|
134
|
+
|
|
135
|
+
Slack signs `v0:<X-Slack-Request-Timestamp>:<raw body>` with the app's signing
|
|
136
|
+
secret and sends `X-Slack-Signature: v0=<hex>`.
|
|
137
|
+
|
|
138
|
+
```javascript
|
|
139
|
+
const CryptoJS = require("crypto-js");
|
|
140
|
+
|
|
141
|
+
const secret = pm.environment.get("slack_signing_secret");
|
|
142
|
+
const ts = pm.request.headers.get("X-Slack-Request-Timestamp");
|
|
143
|
+
const expected = "v0=" +
|
|
144
|
+
CryptoJS.HmacSHA256("v0:" + ts + ":" + pm.request.body.raw, secret)
|
|
145
|
+
.toString(CryptoJS.enc.Hex);
|
|
146
|
+
|
|
147
|
+
pm.test("Slack signature matches the body", function () {
|
|
148
|
+
pm.expect(pm.request.headers.get("X-Slack-Signature")).to.equal(expected);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
pm.test("Slack timestamp is within five minutes", function () {
|
|
152
|
+
pm.expect(Math.abs(Date.now() / 1000 - Number(ts))).to.be.below(300);
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Any other HMAC scheme, including your own API's
|
|
157
|
+
|
|
158
|
+
Start from the provider's documentation, or your own if you're checking the
|
|
159
|
+
webhooks your API sends. Find out three things: which header carries the
|
|
160
|
+
signature and any prefix it uses, exactly which bytes are signed (the body
|
|
161
|
+
alone, or a timestamp or id joined to it), and whether the result is hex or
|
|
162
|
+
base64. A mismatch is nearly always one of those three. Use
|
|
163
|
+
`CryptoJS.enc.Base64` in place of `CryptoJS.enc.Hex` for a base64 signature.
|