@gfargo/doorman 3.9.2 → 3.10.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/dist/bin/run.js +89 -88
- package/dist/bin/run.mjs +89 -88
- package/package.json +1 -1
- package/skills/doorman/SKILL.md +19 -16
- package/skills/doorman/references/cicd.md +9 -7
- package/skills/doorman/references/fastly.md +168 -0
- package/skills/doorman/sync/plugin.json +2 -1
package/package.json
CHANGED
package/skills/doorman/SKILL.md
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: doorman
|
|
3
|
-
description: Manage Vercel and
|
|
3
|
+
description: Manage Vercel, Cloudflare, and Fastly WAF firewall rules as code with the Doorman CLI. Use for any firewall-as-code task — creating rules, IP blocking, rate limiting, bot protection, geo-blocking, syncing local config to providers, validating configurations, exporting documentation, CI/CD automation, or translating rules between provider formats.
|
|
4
4
|
license: MIT
|
|
5
|
-
compatibility: Node.js >= 20. Requires provider API tokens (VERCEL_TOKEN or
|
|
5
|
+
compatibility: Node.js >= 20. Requires provider API tokens (VERCEL_TOKEN, CLOUDFLARE_API_TOKEN, or FASTLY_API_TOKEN). Install globally via npm install -g @gfargo/doorman.
|
|
6
6
|
metadata:
|
|
7
7
|
author: gfargo
|
|
8
|
-
version:
|
|
8
|
+
version: '1.0'
|
|
9
9
|
homepage: https://github.com/gfargo/doorman
|
|
10
|
-
npm:
|
|
10
|
+
npm: '@gfargo/doorman'
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# Doorman — Firewall Rules as Code
|
|
14
14
|
|
|
15
|
-
Doorman is a CLI for managing WAF (Web Application Firewall) rules as code across Vercel and
|
|
15
|
+
Doorman is a CLI for managing WAF (Web Application Firewall) rules as code across Vercel, Cloudflare, and Fastly Next-Gen WAF. Configuration lives in `.doorman.json`, syncs bidirectionally with provider APIs, and integrates into CI/CD pipelines.
|
|
16
16
|
|
|
17
17
|
## Command Quick Reference
|
|
18
18
|
|
|
@@ -44,7 +44,7 @@ doorman export --format markdown # Export as markdown|json|yaml|terraform
|
|
|
44
44
|
doorman remove --name "Old Rule" # Remove rules by name/ID
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
All commands accept `--provider vercel|cloudflare` and `--config <path>`.
|
|
47
|
+
All commands accept `--provider vercel|cloudflare|fastly` and `--config <path>`.
|
|
48
48
|
|
|
49
49
|
## Environment Variables
|
|
50
50
|
|
|
@@ -58,6 +58,10 @@ VERCEL_TEAM_ID=team_xxx
|
|
|
58
58
|
CLOUDFLARE_API_TOKEN=your_token
|
|
59
59
|
CLOUDFLARE_ZONE_ID=zone_xxx
|
|
60
60
|
CLOUDFLARE_ACCOUNT_ID=acc_xxx # optional, enables Lists API for bulk IP management
|
|
61
|
+
|
|
62
|
+
# Fastly Next-Gen WAF (beta)
|
|
63
|
+
FASTLY_API_TOKEN=your_token
|
|
64
|
+
FASTLY_WORKSPACE_ID=workspace_xxx
|
|
61
65
|
```
|
|
62
66
|
|
|
63
67
|
## Config Structure
|
|
@@ -72,7 +76,7 @@ CLOUDFLARE_ACCOUNT_ID=acc_xxx # optional, enables Lists API for bulk IP manage
|
|
|
72
76
|
}
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
For Cloudflare, add `provider` and `providers` fields instead of `projectId`/`teamId`.
|
|
79
|
+
For Cloudflare or Fastly, add `provider` and `providers` fields instead of `projectId`/`teamId`.
|
|
76
80
|
|
|
77
81
|
## Core Workflow
|
|
78
82
|
|
|
@@ -93,9 +97,7 @@ doorman backup && doorman validate && doorman diff && doorman sync && doorman st
|
|
|
93
97
|
{
|
|
94
98
|
"name": "Block Admin",
|
|
95
99
|
"active": true,
|
|
96
|
-
"conditionGroup": [
|
|
97
|
-
{ "conditions": [{ "type": "path", "op": "pre", "value": "/admin" }] }
|
|
98
|
-
],
|
|
100
|
+
"conditionGroup": [{ "conditions": [{ "type": "path", "op": "pre", "value": "/admin" }] }],
|
|
99
101
|
"action": { "mitigate": { "action": "deny" } }
|
|
100
102
|
}
|
|
101
103
|
```
|
|
@@ -112,12 +114,13 @@ doorman backup && doorman validate && doorman diff && doorman sync && doorman st
|
|
|
112
114
|
|
|
113
115
|
Load the relevant reference file for detailed documentation:
|
|
114
116
|
|
|
115
|
-
| Task
|
|
116
|
-
|
|
117
|
-
| Writing rules — full field docs, operators, actions, IP blocking, patterns
|
|
118
|
-
| Cloudflare-specific setup, Lists API, expression translation, limitations
|
|
119
|
-
|
|
|
120
|
-
|
|
|
117
|
+
| Task | Reference |
|
|
118
|
+
| ------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
|
119
|
+
| Writing rules — full field docs, operators, actions, IP blocking, patterns | [references/rules.md](references/rules.md) |
|
|
120
|
+
| Cloudflare-specific setup, Lists API, expression translation, limitations | [references/cloudflare.md](references/cloudflare.md) |
|
|
121
|
+
| Fastly-specific setup, condition/action mapping, rate-limit signal requirement, limitations | [references/fastly.md](references/fastly.md) |
|
|
122
|
+
| Available templates and what they protect against | [references/templates.md](references/templates.md) |
|
|
123
|
+
| CI/CD integration, automation, export formats, validation in pipelines | [references/cicd.md](references/cicd.md) |
|
|
121
124
|
|
|
122
125
|
## Principles
|
|
123
126
|
|
|
@@ -170,6 +170,7 @@ doorman status --format json
|
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
The health score evaluates:
|
|
173
|
+
|
|
173
174
|
- Rule descriptions present
|
|
174
175
|
- ID conventions followed (`rule_` prefix)
|
|
175
176
|
- Operator complexity (penalizes unnecessary regex)
|
|
@@ -210,17 +211,18 @@ doorman sync --provider cloudflare --config .doorman.json
|
|
|
210
211
|
|
|
211
212
|
Global flags available on all commands:
|
|
212
213
|
|
|
213
|
-
| Flag
|
|
214
|
-
|
|
215
|
-
| `--config <path>`
|
|
216
|
-
| `--provider vercel\|cloudflare`
|
|
217
|
-
| `--format json\|table\|yaml\|markdown\|terraform` | Output format (command-dependent)
|
|
218
|
-
| `--verbose`
|
|
219
|
-
| `--output <path>`
|
|
214
|
+
| Flag | Description |
|
|
215
|
+
| ------------------------------------------------- | -------------------------------------------------------------- |
|
|
216
|
+
| `--config <path>` | Path to config file (default: auto-discovered `.doorman.json`) |
|
|
217
|
+
| `--provider vercel\|cloudflare\|fastly` | Override provider detection |
|
|
218
|
+
| `--format json\|table\|yaml\|markdown\|terraform` | Output format (command-dependent) |
|
|
219
|
+
| `--verbose` | Show detailed output |
|
|
220
|
+
| `--output <path>` | Write output to file instead of stdout |
|
|
220
221
|
|
|
221
222
|
## Error Handling in Automation
|
|
222
223
|
|
|
223
224
|
Doorman exit codes:
|
|
225
|
+
|
|
224
226
|
- `0` — success
|
|
225
227
|
- `1` — error (validation failure, API error, config not found)
|
|
226
228
|
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# Fastly Next-Gen WAF Provider Reference
|
|
2
|
+
|
|
3
|
+
Fastly Next-Gen WAF support in Doorman (beta). Manage Next-Gen WAF (formerly Signal Sciences) workspace rules through the same config-as-code workflow. Classic Fastly VCL services are **not** supported — only the Next-Gen WAF's structured rules API.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### Environment Variables
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
FASTLY_API_TOKEN=your_token # Required — Fastly API token
|
|
11
|
+
FASTLY_WORKSPACE_ID=workspace_xxx # Required — Next-Gen WAF workspace to manage rules for
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### API Token Permissions
|
|
15
|
+
|
|
16
|
+
Create a token at https://manage.fastly.com/account/personal/tokens with access to the Next-Gen WAF product for the target workspace.
|
|
17
|
+
|
|
18
|
+
### Config Shape
|
|
19
|
+
|
|
20
|
+
Multi-provider config with explicit provider declaration:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"$schema": "https://doorman.griffen.codes/schema.json",
|
|
25
|
+
"provider": "fastly",
|
|
26
|
+
"providers": {
|
|
27
|
+
"fastly": {
|
|
28
|
+
"workspaceId": "your_workspace_id"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"rules": [],
|
|
32
|
+
"ips": []
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or pass `--provider fastly` to any command to override the default.
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
doorman init --provider fastly # Initialize Fastly config
|
|
42
|
+
doorman validate --provider fastly # Validate against Fastly constraints
|
|
43
|
+
doorman sync --provider fastly # Deploy to Fastly
|
|
44
|
+
doorman download --provider fastly # Pull rules from Fastly
|
|
45
|
+
doorman diff --provider fastly # Compare local vs live
|
|
46
|
+
doorman list --provider fastly # Show deployed rules
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Rule Translation
|
|
50
|
+
|
|
51
|
+
Doorman translates its unified rule format into Fastly's structured `request`-type rules automatically. The translation is bidirectional — `doorman download` pulls Fastly rules back into the unified format.
|
|
52
|
+
|
|
53
|
+
### Field Mapping
|
|
54
|
+
|
|
55
|
+
| Doorman Field | Fastly Condition | Notes |
|
|
56
|
+
| ------------- | -------------------------- | ------------------------------------------------------- |
|
|
57
|
+
| `path` | `path` | |
|
|
58
|
+
| `method` | `method` | |
|
|
59
|
+
| `host` | `domain` | |
|
|
60
|
+
| `user_agent` | `user_agent` | |
|
|
61
|
+
| `ip` | `ip` | |
|
|
62
|
+
| `country` | `country` | Country-level only — no region/city/continent condition |
|
|
63
|
+
| `scheme` | `scheme` | |
|
|
64
|
+
| `header` | `request_header` multival | Requires `key` (the header name) |
|
|
65
|
+
| `query` | `query_parameter` multival | Requires `key` (the parameter name) |
|
|
66
|
+
| `cookie` | `request_cookie` multival | Requires `key` (the cookie name) |
|
|
67
|
+
|
|
68
|
+
Fields with no Fastly equivalent (`region`, `city`, `asn`, `referer`, `port`, `target_path`, `environment`, `ja3_digest`, `ja4_digest`) are dropped with a translation warning rather than silently mistranslated — the rule still syncs with its remaining conditions.
|
|
69
|
+
|
|
70
|
+
### Operator Mapping
|
|
71
|
+
|
|
72
|
+
| Doorman Operator | Fastly Operator | Notes |
|
|
73
|
+
| -------------------------- | ------------------------------------------- | -------------------------------------------------------------- |
|
|
74
|
+
| `eq` | `equals` (or `does_not_equal` if `negated`) | |
|
|
75
|
+
| `contains` | `contains` (or `does_not_contain`) | |
|
|
76
|
+
| `matches` | `matches` (or `does_not_match`) | Regex syntax may need adjustment |
|
|
77
|
+
| `starts_with`, `ends_with` | `like` (or `not_like`) | Fastly's wildcard matching isn't a true prefix/suffix operator |
|
|
78
|
+
| `in` | `in_list` (or `not_in_list`) | |
|
|
79
|
+
| `gt`, `lt` | `greater_equal`, `lesser_equal` | No strict `>`/`<` on Fastly — boundary value also matches |
|
|
80
|
+
|
|
81
|
+
### Action Mapping
|
|
82
|
+
|
|
83
|
+
| Doorman Action | Fastly Action | Notes |
|
|
84
|
+
| --------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `block`, `deny` | `block` | |
|
|
86
|
+
| `allow` | `allow` | |
|
|
87
|
+
| `challenge` | `browser_challenge` | |
|
|
88
|
+
| `redirect` | `redirect` | Uses `redirect_url` + `response_code` |
|
|
89
|
+
| `rate_limit` | Rule `type: rate_limit` + `block_signal` action | See Rate Limiting below |
|
|
90
|
+
| `log` | `allow` (with a warning) | Fastly has no dedicated log-only action; `request_logging` is set at the rule level regardless |
|
|
91
|
+
| `bypass` | `allow` (with a warning) | No equivalent action |
|
|
92
|
+
|
|
93
|
+
## Condition Grouping
|
|
94
|
+
|
|
95
|
+
Fastly's condition model is bounded to two levels — a rule's top-level conditions can be plain, or grouped, but a group's own members can never contain another group. This matches Doorman's flat `group` model exactly:
|
|
96
|
+
|
|
97
|
+
- Conditions sharing a `group` index are AND'd together.
|
|
98
|
+
- Distinct `group` values are OR'd against each other.
|
|
99
|
+
- A single implicit group (the common case) becomes flat top-level conditions.
|
|
100
|
+
|
|
101
|
+
## Rate Limiting
|
|
102
|
+
|
|
103
|
+
Fastly rate-limit rules are a distinct rule type (`type: "rate_limit"`) with their own `rate_limit` block (`threshold`, `interval`, `duration`, a counting `signal`). Doorman's `window` (e.g. `"60s"`, `"5m"`) is rounded to the nearest interval Fastly supports (60s / 600s / 3600s).
|
|
104
|
+
|
|
105
|
+
**Fastly rate-limit rules count requests against a named custom signal that must already exist in the workspace** — Doorman does not create it automatically. Create a signal named `doorman-rate-limit-<rule-id>` before syncing a rate-limit rule, or the sync will be rejected. A translation warning is emitted every time to make this easy to miss less easily.
|
|
106
|
+
|
|
107
|
+
## IP Blocking
|
|
108
|
+
|
|
109
|
+
Fastly has no per-IP-rule resource — Doorman manages two workspace **lists** of type `ip` (`doorman-managed-deny`, `doorman-managed-allow`), each replaced wholesale on sync (the same atomic-replace shape as Cloudflare's ruleset write, not Vercel's per-item writes). `hostname`/`notes` on an IP rule have no Fastly equivalent and are dropped with a warning — only the address is kept.
|
|
110
|
+
|
|
111
|
+
## No Draft/Publish Step
|
|
112
|
+
|
|
113
|
+
Unlike classic Fastly VCL services, Next-Gen WAF rule and list writes take effect immediately — there is no draft-then-activate version to manage. A rule's `enabled` flag is the only gate on whether it's live.
|
|
114
|
+
|
|
115
|
+
## Limitations & Differences
|
|
116
|
+
|
|
117
|
+
| Feature | Vercel | Fastly | Notes |
|
|
118
|
+
| -------------------------- | ----------------------------- | ---------------------- | ------------------------------------------------------------------------- |
|
|
119
|
+
| Geo targeting | Country/city/continent/region | Country only | No sub-country condition field |
|
|
120
|
+
| Rule ordering | Best-effort (insertion order) | None | Next-Gen WAF rules are evaluated independently — `priority` has no effect |
|
|
121
|
+
| Managed/vendor rule groups | CRS (enterprise) | Templated signal rules | Not yet configurable through Doorman for either provider (#183) |
|
|
122
|
+
| Signal/exclusion rules | — | `type: signal` | Not managed by Doorman — see below |
|
|
123
|
+
|
|
124
|
+
Fastly rules of type `signal` or `templated_signal` (which tag or exclude WAF signals rather than allow/block/redirect a request) are skipped entirely by `doorman download`/`fetchConfig` rather than forced into a lossy `UnifiedRule` — they simply don't appear in the local config.
|
|
125
|
+
|
|
126
|
+
## Example: Full Fastly Config
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"$schema": "https://doorman.griffen.codes/schema.json",
|
|
131
|
+
"provider": "fastly",
|
|
132
|
+
"providers": {
|
|
133
|
+
"fastly": {
|
|
134
|
+
"workspaceId": "abc123def456"
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"rules": [
|
|
138
|
+
{
|
|
139
|
+
"id": "rule_block_bots",
|
|
140
|
+
"name": "Block Bad Bots",
|
|
141
|
+
"enabled": true,
|
|
142
|
+
"conditions": [
|
|
143
|
+
{ "field": "user_agent", "operator": "contains", "value": "AhrefsBot", "group": 0 },
|
|
144
|
+
{ "field": "user_agent", "operator": "contains", "value": "SemrushBot", "group": 1 }
|
|
145
|
+
],
|
|
146
|
+
"action": { "type": "block" }
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"id": "rule_admin_header",
|
|
150
|
+
"name": "Require internal header on admin paths",
|
|
151
|
+
"enabled": true,
|
|
152
|
+
"conditions": [
|
|
153
|
+
{ "field": "path", "operator": "starts_with", "value": "/admin", "group": 0 },
|
|
154
|
+
{
|
|
155
|
+
"field": "header",
|
|
156
|
+
"operator": "eq",
|
|
157
|
+
"value": "internal",
|
|
158
|
+
"key": "X-Access-Level",
|
|
159
|
+
"negated": true,
|
|
160
|
+
"group": 0
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"action": { "type": "block" }
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
"ips": [{ "ip": "203.0.113.0/24", "action": "deny" }]
|
|
167
|
+
}
|
|
168
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "security",
|
|
3
|
-
"description": "Web application firewall management as code with Doorman: create rules, block IPs, rate limit, protect against bots, and deploy WAF configs to Vercel and
|
|
3
|
+
"description": "Web application firewall management as code with Doorman: create rules, block IPs, rate limit, protect against bots, and deploy WAF configs to Vercel, Cloudflare, and Fastly.",
|
|
4
4
|
"version": "1.0.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Griffen Fargo",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"waf",
|
|
14
14
|
"vercel",
|
|
15
15
|
"cloudflare",
|
|
16
|
+
"fastly",
|
|
16
17
|
"doorman",
|
|
17
18
|
"iac",
|
|
18
19
|
"rules",
|