@jgamaraalv/ts-dev-kit 3.1.0 → 3.1.2

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.
@@ -12,7 +12,7 @@
12
12
  "name": "ts-dev-kit",
13
13
  "source": "./",
14
14
  "description": "15 specialized agents and 22 skills for TypeScript fullstack development",
15
- "version": "3.1.0",
15
+ "version": "3.1.2",
16
16
  "author": {
17
17
  "name": "jgamaraalv"
18
18
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-dev-kit",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "15 specialized agents and 22 skills for TypeScript fullstack development with Fastify, Next.js, PostgreSQL, Redis, and more.",
5
5
  "author": {
6
6
  "name": "jgamaraalv",
package/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.1.2] - 2026-02-27
9
+
10
+ ### Fixed
11
+
12
+ - `/yolo` firewall script: deduplicate DNS results with `sort -u` in `resolve_domain()` to prevent `ipset add` failure on duplicate IPs (root cause: `marketplace.visualstudio.com` returns the same IP twice)
13
+
14
+ ## [3.1.1] - 2026-02-27
15
+
16
+ ### Fixed
17
+
18
+ - `/yolo` firewall script: add resilient fallback for Docker Desktop environments where `ipset` kernel module is unavailable — falls back to iptables-only rules, `getent` DNS resolution, and direct GitHub domain resolution; full diagnostic log at `/tmp/firewall-init.log`
19
+
8
20
  ## [3.1.0] - 2026-02-27
9
21
 
10
22
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jgamaraalv/ts-dev-kit",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Claude Code plugin: 15 agents + 22 skills for TypeScript fullstack development",
5
5
  "author": "jgamaraalv",
6
6
  "license": "MIT",
@@ -114,7 +114,17 @@ Open the project in VS Code with the devcontainer.
114
114
  1. Verify VS Code is installed (`command -v code`).
115
115
  2. If VS Code is not installed, inform the user:
116
116
 
117
- > **VS Code is required** for devcontainer support. Install it from https://code.visualstudio.com/ and the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers).
117
+ > **VS Code is required** for devcontainer support. Install it from https://code.visualstudio.com/ and re-run `/yolo`.
118
+
119
+ Stop here. Do not proceed.
120
+
121
+ 3. Ensure the Dev Containers extension is installed:
122
+
123
+ ```bash
124
+ code --install-extension ms-vscode-remote.remote-containers
125
+ ```
126
+
127
+ This is idempotent — if already installed, VS Code simply reports it and moves on.
118
128
 
119
129
  **Launch sequence:**
120
130
 
@@ -248,6 +258,8 @@ Key security features:
248
258
  - Localhost and host network allowed
249
259
  - Startup verification: confirms `example.com` is blocked and `api.github.com` is reachable
250
260
  - Docker DNS rules preserved
261
+ - Falls back to iptables-only rules if `ipset` kernel module is unavailable (common on Docker Desktop for Mac)
262
+ - Full diagnostic log at `/tmp/firewall-init.log` for troubleshooting
251
263
 
252
264
  ### Step 5 — Add `.devcontainer` to `.gitignore` (optional)
253
265
 
@@ -57,7 +57,7 @@ Write this file to `.devcontainer/devcontainer.json`:
57
57
  },
58
58
  "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated",
59
59
  "workspaceFolder": "/workspace",
60
- "postStartCommand": "sudo /usr/local/bin/init-firewall.sh",
60
+ "postStartCommand": "sudo /usr/local/bin/init-firewall.sh 2>&1 | tee /tmp/firewall-init.log",
61
61
  "waitFor": "postStartCommand"
62
62
  }
63
63
  ```
@@ -4,153 +4,279 @@ Write this file to `.devcontainer/init-firewall.sh`:
4
4
 
5
5
  ```bash
6
6
  #!/bin/bash
7
- set -euo pipefail # Exit on error, undefined vars, and pipeline failures
8
- IFS=$'\n\t' # Stricter word splitting
9
-
10
- # 1. Extract Docker DNS info BEFORE any flushing
11
- DOCKER_DNS_RULES=$(iptables-save -t nat | grep "127\.0\.0\.11" || true)
12
-
13
- # Flush existing rules and delete existing ipsets
14
- iptables -F
15
- iptables -X
16
- iptables -t nat -F
17
- iptables -t nat -X
18
- iptables -t mangle -F
19
- iptables -t mangle -X
20
- ipset destroy allowed-domains 2>/dev/null || true
21
-
22
- # 2. Selectively restore ONLY internal Docker DNS resolution
7
+ set -uo pipefail # Strict vars and pipelines, but handle errors manually
8
+ IFS=$'\n\t'
9
+
10
+ LOG="/tmp/firewall-init.log"
11
+ exec > >(tee -a "$LOG") 2>&1
12
+ echo "=== Firewall init started at $(date -u) ==="
13
+
14
+ # --- Diagnostics -----------------------------------------------------------
15
+ echo "--- Pre-flight checks ---"
16
+ HAVE_IPTABLES=false
17
+ HAVE_IPSET=false
18
+
19
+ if iptables -L -n >/dev/null 2>&1; then
20
+ HAVE_IPTABLES=true
21
+ echo "[OK] iptables is functional"
22
+ else
23
+ echo "[FAIL] iptables is NOT functional — firewall cannot be configured"
24
+ echo "Hint: ensure --cap-add=NET_ADMIN is set in devcontainer.json runArgs"
25
+ exit 1
26
+ fi
27
+
28
+ if ipset list >/dev/null 2>&1 || ipset create _test hash:net 2>/dev/null; then
29
+ ipset destroy _test 2>/dev/null || true
30
+ HAVE_IPSET=true
31
+ echo "[OK] ipset is functional"
32
+ else
33
+ echo "[WARN] ipset is NOT functional — falling back to iptables-only rules"
34
+ fi
35
+
36
+ if command -v dig >/dev/null 2>&1; then
37
+ echo "[OK] dig is available"
38
+ else
39
+ echo "[WARN] dig not found — DNS resolution will use getent"
40
+ fi
41
+
42
+ if command -v aggregate >/dev/null 2>&1; then
43
+ echo "[OK] aggregate is available"
44
+ else
45
+ echo "[WARN] aggregate not found — GitHub CIDRs will be added individually"
46
+ fi
47
+
48
+ # --- Helper: resolve domain to IPs ----------------------------------------
49
+ resolve_domain() {
50
+ local domain="$1"
51
+ local ips=""
52
+ if command -v dig >/dev/null 2>&1; then
53
+ ips=$(dig +noall +answer +short A "$domain" 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort -u)
54
+ fi
55
+ if [ -z "$ips" ] && command -v getent >/dev/null 2>&1; then
56
+ ips=$(getent ahostsv4 "$domain" 2>/dev/null | awk '{print $1}' | sort -u | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$')
57
+ fi
58
+ echo "$ips"
59
+ }
60
+
61
+ # --- 1. Preserve Docker DNS -----------------------------------------------
62
+ echo "--- Preserving Docker DNS rules ---"
63
+ DOCKER_DNS_RULES=$(iptables-save -t nat 2>/dev/null | grep "127\.0\.0\.11" || true)
64
+
65
+ # --- 2. Flush existing rules -----------------------------------------------
66
+ echo "--- Flushing existing rules ---"
67
+ iptables -F || true
68
+ iptables -X || true
69
+ iptables -t nat -F || true
70
+ iptables -t nat -X || true
71
+ iptables -t mangle -F || true
72
+ iptables -t mangle -X || true
73
+ if [ "$HAVE_IPSET" = true ]; then
74
+ ipset destroy allowed-domains 2>/dev/null || true
75
+ fi
76
+
77
+ # --- 3. Restore Docker DNS -------------------------------------------------
23
78
  if [ -n "$DOCKER_DNS_RULES" ]; then
24
79
  echo "Restoring Docker DNS rules..."
25
80
  iptables -t nat -N DOCKER_OUTPUT 2>/dev/null || true
26
81
  iptables -t nat -N DOCKER_POSTROUTING 2>/dev/null || true
27
- echo "$DOCKER_DNS_RULES" | xargs -L 1 iptables -t nat
82
+ echo "$DOCKER_DNS_RULES" | while read -r rule; do
83
+ iptables -t nat $rule 2>/dev/null || true
84
+ done
28
85
  else
29
86
  echo "No Docker DNS rules to restore"
30
87
  fi
31
88
 
32
- # First allow DNS and localhost before any restrictions
33
- # Allow outbound DNS
89
+ # --- 4. Base rules (DNS, SSH, localhost) ------------------------------------
90
+ echo "--- Setting base rules ---"
91
+ # Outbound DNS
34
92
  iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
35
- # Allow inbound DNS responses
93
+ iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT
94
+ # Inbound DNS responses
36
95
  iptables -A INPUT -p udp --sport 53 -j ACCEPT
37
- # Allow outbound SSH
96
+ iptables -A INPUT -p tcp --sport 53 -j ACCEPT
97
+ # Outbound SSH
38
98
  iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
39
- # Allow inbound SSH responses
40
99
  iptables -A INPUT -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT
41
- # Allow localhost
100
+ # Localhost
42
101
  iptables -A INPUT -i lo -j ACCEPT
43
102
  iptables -A OUTPUT -o lo -j ACCEPT
44
103
 
45
- # Create ipset with CIDR support
46
- ipset create allowed-domains hash:net
47
-
48
- # Fetch GitHub meta information and aggregate + add their IP ranges
49
- echo "Fetching GitHub IP ranges..."
50
- gh_ranges=$(curl -s https://api.github.com/meta)
51
- if [ -z "$gh_ranges" ]; then
52
- echo "ERROR: Failed to fetch GitHub IP ranges"
53
- exit 1
104
+ # --- 5. Host network -------------------------------------------------------
105
+ HOST_IP=$(ip route 2>/dev/null | grep default | head -1 | awk '{print $3}')
106
+ if [ -n "$HOST_IP" ]; then
107
+ HOST_NETWORK=$(echo "$HOST_IP" | sed "s/\.[0-9]*$/.0\/16/")
108
+ echo "Host network: $HOST_NETWORK (via $HOST_IP)"
109
+ iptables -A INPUT -s "$HOST_NETWORK" -j ACCEPT
110
+ iptables -A OUTPUT -d "$HOST_NETWORK" -j ACCEPT
111
+ else
112
+ echo "[WARN] Could not detect host IP — allowing RFC1918 ranges for Docker connectivity"
113
+ iptables -A INPUT -s 172.16.0.0/12 -j ACCEPT
114
+ iptables -A OUTPUT -d 172.16.0.0/12 -j ACCEPT
115
+ iptables -A INPUT -s 192.168.0.0/16 -j ACCEPT
116
+ iptables -A OUTPUT -d 192.168.0.0/16 -j ACCEPT
117
+ iptables -A INPUT -s 10.0.0.0/8 -j ACCEPT
118
+ iptables -A OUTPUT -d 10.0.0.0/8 -j ACCEPT
54
119
  fi
55
120
 
56
- if ! echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null; then
57
- echo "ERROR: GitHub API response missing required fields"
58
- exit 1
59
- fi
121
+ # --- 6. Allowed domains ----------------------------------------------------
122
+ ALLOWED_DOMAINS=(
123
+ "registry.npmjs.org"
124
+ "api.anthropic.com"
125
+ "sentry.io"
126
+ "statsig.anthropic.com"
127
+ "statsig.com"
128
+ "marketplace.visualstudio.com"
129
+ "vscode.blob.core.windows.net"
130
+ "update.code.visualstudio.com"
131
+ )
60
132
 
61
- echo "Processing GitHub IPs..."
62
- while read -r cidr; do
63
- if [[ ! "$cidr" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$ ]]; then
64
- echo "ERROR: Invalid CIDR range from GitHub meta: $cidr"
65
- exit 1
66
- fi
67
- echo "Adding GitHub range $cidr"
68
- ipset add allowed-domains "$cidr"
69
- done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]' | aggregate -q)
70
-
71
- # Resolve and add other allowed domains
72
- for domain in \
73
- "registry.npmjs.org" \
74
- "api.anthropic.com" \
75
- "sentry.io" \
76
- "statsig.anthropic.com" \
77
- "statsig.com" \
78
- "marketplace.visualstudio.com" \
79
- "vscode.blob.core.windows.net" \
80
- "update.code.visualstudio.com"; do
81
- echo "Resolving $domain..."
82
- ips=$(dig +noall +answer A "$domain" | awk '$4 == "A" {print $5}')
83
- if [ -z "$ips" ]; then
84
- echo "ERROR: Failed to resolve $domain"
85
- exit 1
133
+ if [ "$HAVE_IPSET" = true ]; then
134
+ # ---- ipset mode (preferred) ----
135
+ echo "--- Building ipset allowlist ---"
136
+ ipset create allowed-domains hash:net
137
+
138
+ # GitHub dynamic IPs
139
+ echo "Fetching GitHub IP ranges..."
140
+ gh_ranges=$(curl -sf --connect-timeout 10 https://api.github.com/meta 2>/dev/null || true)
141
+ if [ -n "$gh_ranges" ] && echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null 2>&1; then
142
+ if command -v aggregate >/dev/null 2>&1; then
143
+ while read -r cidr; do
144
+ [[ "$cidr" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]] && ipset add allowed-domains "$cidr" 2>/dev/null || true
145
+ done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]' | aggregate -q 2>/dev/null)
146
+ else
147
+ while read -r cidr; do
148
+ [[ "$cidr" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]] && ipset add allowed-domains "$cidr" 2>/dev/null || true
149
+ done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]')
150
+ fi
151
+ echo "[OK] GitHub IP ranges added"
152
+ else
153
+ echo "[WARN] Could not fetch GitHub IPs — resolving github.com directly"
154
+ for gh_domain in "github.com" "api.github.com" "raw.githubusercontent.com" "objects.githubusercontent.com"; do
155
+ ips=$(resolve_domain "$gh_domain")
156
+ while read -r ip; do
157
+ [ -n "$ip" ] && ipset add allowed-domains "$ip" 2>/dev/null || true
158
+ done <<< "$ips"
159
+ done
86
160
  fi
87
161
 
88
- while read -r ip; do
89
- if [[ ! "$ip" =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
90
- echo "ERROR: Invalid IP from DNS for $domain: $ip"
91
- exit 1
162
+ # Other allowed domains
163
+ for domain in "${ALLOWED_DOMAINS[@]}"; do
164
+ echo "Resolving $domain..."
165
+ ips=$(resolve_domain "$domain")
166
+ if [ -z "$ips" ]; then
167
+ echo "[WARN] Failed to resolve $domain — skipping"
168
+ continue
92
169
  fi
93
- echo "Adding $ip for $domain"
94
- ipset add allowed-domains "$ip"
95
- done < <(echo "$ips")
96
- done
97
-
98
- # Get host IP from default route
99
- HOST_IP=$(ip route | grep default | cut -d" " -f3)
100
- if [ -z "$HOST_IP" ]; then
101
- echo "ERROR: Failed to detect host IP"
102
- exit 1
103
- fi
170
+ while read -r ip; do
171
+ [ -n "$ip" ] && ipset add allowed-domains "$ip" 2>/dev/null || true
172
+ done <<< "$ips"
173
+ done
174
+
175
+ # Apply ipset match rule
176
+ iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT
104
177
 
105
- HOST_NETWORK=$(echo "$HOST_IP" | sed "s/\.[0-9]*$/.0\/24/")
106
- echo "Host network detected as: $HOST_NETWORK"
178
+ else
179
+ # ---- iptables-only mode (fallback) ----
180
+ echo "--- Building iptables allowlist (no ipset) ---"
181
+
182
+ # GitHub IPs
183
+ echo "Fetching GitHub IP ranges..."
184
+ gh_ranges=$(curl -sf --connect-timeout 10 https://api.github.com/meta 2>/dev/null || true)
185
+ if [ -n "$gh_ranges" ] && echo "$gh_ranges" | jq -e '.web and .api and .git' >/dev/null 2>&1; then
186
+ while read -r cidr; do
187
+ [[ "$cidr" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]] && \
188
+ iptables -A OUTPUT -d "$cidr" -j ACCEPT 2>/dev/null || true
189
+ done < <(echo "$gh_ranges" | jq -r '(.web + .api + .git)[]')
190
+ echo "[OK] GitHub IP ranges added via iptables"
191
+ else
192
+ echo "[WARN] Could not fetch GitHub IPs — resolving github.com directly"
193
+ for gh_domain in "github.com" "api.github.com" "raw.githubusercontent.com" "objects.githubusercontent.com"; do
194
+ ips=$(resolve_domain "$gh_domain")
195
+ while read -r ip; do
196
+ [ -n "$ip" ] && iptables -A OUTPUT -d "$ip" -j ACCEPT 2>/dev/null || true
197
+ done <<< "$ips"
198
+ done
199
+ fi
107
200
 
108
- # Set up remaining iptables rules
109
- iptables -A INPUT -s "$HOST_NETWORK" -j ACCEPT
110
- iptables -A OUTPUT -d "$HOST_NETWORK" -j ACCEPT
201
+ # Other allowed domains
202
+ for domain in "${ALLOWED_DOMAINS[@]}"; do
203
+ echo "Resolving $domain..."
204
+ ips=$(resolve_domain "$domain")
205
+ if [ -z "$ips" ]; then
206
+ echo "[WARN] Failed to resolve $domain — skipping"
207
+ continue
208
+ fi
209
+ while read -r ip; do
210
+ [ -n "$ip" ] && iptables -A OUTPUT -d "$ip" -j ACCEPT 2>/dev/null || true
211
+ done <<< "$ips"
212
+ done
213
+ fi
111
214
 
112
- # Set default policies to DROP first
215
+ # --- 7. Default-deny policies ----------------------------------------------
216
+ echo "--- Applying default-deny policies ---"
113
217
  iptables -P INPUT DROP
114
218
  iptables -P FORWARD DROP
115
219
  iptables -P OUTPUT DROP
116
220
 
117
- # First allow established connections for already approved traffic
221
+ # Allow established connections
118
222
  iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
119
223
  iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
120
224
 
121
- # Then allow only specific outbound traffic to allowed domains
122
- iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT
123
-
124
- # Explicitly REJECT all other outbound traffic for immediate feedback
225
+ # Reject everything else with immediate feedback
125
226
  iptables -A OUTPUT -j REJECT --reject-with icmp-admin-prohibited
126
227
 
127
- echo "Firewall configuration complete"
128
- echo "Verifying firewall rules..."
228
+ # --- 8. Verification -------------------------------------------------------
229
+ echo "--- Verifying firewall ---"
230
+ VERIFIED=true
231
+
129
232
  if curl --connect-timeout 5 https://example.com >/dev/null 2>&1; then
130
- echo "ERROR: Firewall verification failed - was able to reach https://example.com"
131
- exit 1
233
+ echo "[FAIL] Firewall verification failed reached https://example.com (should be blocked)"
234
+ VERIFIED=false
132
235
  else
133
- echo "Firewall verification passed - unable to reach https://example.com as expected"
236
+ echo "[OK] https://example.com is blocked as expected"
134
237
  fi
135
238
 
136
- # Verify GitHub API access
137
- if ! curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1; then
138
- echo "ERROR: Firewall verification failed - unable to reach https://api.github.com"
139
- exit 1
239
+ if curl --connect-timeout 5 https://api.github.com/zen >/dev/null 2>&1; then
240
+ echo "[OK] https://api.github.com is reachable as expected"
140
241
  else
141
- echo "Firewall verification passed - able to reach https://api.github.com as expected"
242
+ echo "[WARN] https://api.github.com is not reachable — GitHub IPs may have changed"
243
+ echo " Claude Code will still work, but git operations may fail"
142
244
  fi
245
+
246
+ if [ "$VERIFIED" = false ]; then
247
+ echo "=== FIREWALL VERIFICATION FAILED ==="
248
+ exit 1
249
+ fi
250
+
251
+ echo "=== Firewall configured successfully ==="
252
+ echo "Mode: $([ "$HAVE_IPSET" = true ] && echo 'ipset' || echo 'iptables-only')"
253
+ echo "Log: $LOG"
143
254
  ```
144
255
 
256
+ ## Key improvements over the original
257
+
258
+ | Issue | Original behavior | Improved behavior |
259
+ |-------|-------------------|-------------------|
260
+ | Duplicate IPs from DNS | `ipset add` fatal error (exit 1) | Deduplicates via `sort -u` + `ipset add ... \|\| true` |
261
+ | `ipset` not available | Fatal crash | Falls back to iptables-only rules |
262
+ | `aggregate` not available | Fatal crash | Adds CIDRs individually without aggregation |
263
+ | `dig` not available | Fatal crash | Falls back to `getent ahostsv4` |
264
+ | GitHub API unreachable | Fatal crash | Resolves github.com/api.github.com directly |
265
+ | Domain resolution fails | Fatal crash | Skips domain with warning, continues |
266
+ | Host IP detection fails | Fatal crash | Allows all RFC1918 ranges as fallback |
267
+ | Docker DNS restore fails | Silent + potential crash | Handles per-rule with `|| true` |
268
+ | No diagnostic output | Blind exit code 1 | Full log at `/tmp/firewall-init.log` |
269
+ | GitHub unreachable after setup | Fatal crash | Warning only (Claude API is the critical path) |
270
+
145
271
  ## Firewall rules summary
146
272
 
147
273
  | Rule | Direction | Purpose |
148
274
  |------|-----------|---------|
149
- | DNS (UDP 53) | Outbound | Domain name resolution |
275
+ | DNS (UDP/TCP 53) | Outbound | Domain name resolution |
150
276
  | SSH (TCP 22) | Outbound | Git over SSH |
151
277
  | Localhost | Both | Container-internal communication |
152
278
  | Host network | Both | Docker host ↔ container communication |
153
- | GitHub IPs | Outbound | Git operations, GitHub API (dynamically fetched from api.github.com/meta) |
279
+ | GitHub IPs | Outbound | Git operations, GitHub API (dynamically fetched or resolved) |
154
280
  | npm registry | Outbound | Package installation |
155
281
  | api.anthropic.com | Outbound | Claude API calls |
156
282
  | sentry.io | Outbound | Error reporting |
@@ -161,7 +287,7 @@ fi
161
287
  ## Verification on startup
162
288
 
163
289
  The script verifies the firewall by:
164
- 1. Confirming `https://example.com` is **blocked** (should fail)
165
- 2. Confirming `https://api.github.com` is **reachable** (should succeed)
290
+ 1. Confirming `https://example.com` is **blocked** (must fail — otherwise exit 1)
291
+ 2. Confirming `https://api.github.com` is **reachable** (warning only if it fails)
166
292
 
167
- If either check fails, the script exits with an error and the container will not start.
293
+ All output is logged to `/tmp/firewall-init.log` for debugging.