@intentsolutionsio/vercel-pack 1.0.0 → 1.0.3
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 +1 -1
- package/README.md +67 -44
- package/package.json +4 -4
- package/skills/vercel-advanced-troubleshooting/SKILL.md +185 -195
- package/skills/vercel-advanced-troubleshooting/references/errors.md +11 -0
- package/skills/vercel-advanced-troubleshooting/references/evidence-collection-framework.md +34 -0
- package/skills/vercel-advanced-troubleshooting/references/examples.md +11 -0
- package/skills/vercel-advanced-troubleshooting/references/systematic-isolation.md +56 -0
- package/skills/vercel-advanced-troubleshooting/references/timing-analysis.md +35 -0
- package/skills/vercel-architecture-variants/SKILL.md +227 -216
- package/skills/vercel-architecture-variants/references/errors.md +11 -0
- package/skills/vercel-architecture-variants/references/examples.md +12 -0
- package/skills/vercel-architecture-variants/references/variant-a-monolith-(simple).md +44 -0
- package/skills/vercel-architecture-variants/references/variant-b-service-layer-(moderate).md +72 -0
- package/skills/vercel-architecture-variants/references/variant-c-microservice-(complex).md +81 -0
- package/skills/vercel-ci-integration/SKILL.md +183 -73
- package/skills/vercel-ci-integration/references/errors.md +10 -0
- package/skills/vercel-ci-integration/references/examples.md +36 -0
- package/skills/vercel-ci-integration/references/implementation.md +54 -0
- package/skills/vercel-common-errors/SKILL.md +164 -60
- package/skills/vercel-common-errors/references/errors.md +53 -0
- package/skills/vercel-common-errors/references/examples.md +23 -0
- package/skills/vercel-cost-tuning/SKILL.md +158 -145
- package/skills/vercel-cost-tuning/references/cost-estimation.md +34 -0
- package/skills/vercel-cost-tuning/references/cost-reduction-strategies.md +40 -0
- package/skills/vercel-cost-tuning/references/errors.md +11 -0
- package/skills/vercel-cost-tuning/references/examples.md +15 -0
- package/skills/vercel-data-handling/SKILL.md +202 -155
- package/skills/vercel-data-handling/references/errors.md +11 -0
- package/skills/vercel-data-handling/references/examples.md +27 -0
- package/skills/vercel-data-handling/references/implementation.md +223 -0
- package/skills/vercel-debug-bundle/SKILL.md +163 -67
- package/skills/vercel-debug-bundle/references/errors.md +12 -0
- package/skills/vercel-debug-bundle/references/examples.md +24 -0
- package/skills/vercel-debug-bundle/references/implementation.md +54 -0
- package/skills/vercel-deploy-integration/SKILL.md +163 -156
- package/skills/vercel-deploy-integration/references/errors.md +11 -0
- package/skills/vercel-deploy-integration/references/examples.md +21 -0
- package/skills/vercel-deploy-integration/references/google-cloud-run.md +36 -0
- package/skills/vercel-deploy-integration/references/vercel-deployment.md +35 -0
- package/skills/vercel-deploy-preview/SKILL.md +164 -39
- package/skills/vercel-edge-functions/SKILL.md +185 -37
- package/skills/vercel-enterprise-rbac/SKILL.md +185 -170
- package/skills/vercel-enterprise-rbac/references/errors.md +11 -0
- package/skills/vercel-enterprise-rbac/references/examples.md +12 -0
- package/skills/vercel-enterprise-rbac/references/role-implementation.md +33 -0
- package/skills/vercel-enterprise-rbac/references/sso-integration.md +35 -0
- package/skills/vercel-hello-world/SKILL.md +141 -55
- package/skills/vercel-incident-runbook/SKILL.md +186 -138
- package/skills/vercel-incident-runbook/references/errors.md +11 -0
- package/skills/vercel-incident-runbook/references/examples.md +10 -0
- package/skills/vercel-incident-runbook/references/immediate-actions-by-error-type.md +41 -0
- package/skills/vercel-install-auth/SKILL.md +130 -53
- package/skills/vercel-known-pitfalls/SKILL.md +235 -233
- package/skills/vercel-known-pitfalls/references/errors.md +11 -0
- package/skills/vercel-known-pitfalls/references/examples.md +12 -0
- package/skills/vercel-load-scale/SKILL.md +197 -204
- package/skills/vercel-load-scale/references/capacity-planning.md +47 -0
- package/skills/vercel-load-scale/references/errors.md +11 -0
- package/skills/vercel-load-scale/references/examples.md +26 -0
- package/skills/vercel-load-scale/references/load-testing-with-k6.md +59 -0
- package/skills/vercel-load-scale/references/scaling-patterns.md +65 -0
- package/skills/vercel-local-dev-loop/SKILL.md +159 -71
- package/skills/vercel-local-dev-loop/references/errors.md +11 -0
- package/skills/vercel-local-dev-loop/references/examples.md +21 -0
- package/skills/vercel-local-dev-loop/references/implementation.md +60 -0
- package/skills/vercel-migration-deep-dive/SKILL.md +202 -187
- package/skills/vercel-migration-deep-dive/references/errors.md +11 -0
- package/skills/vercel-migration-deep-dive/references/examples.md +12 -0
- package/skills/vercel-migration-deep-dive/references/implementation-plan.md +80 -0
- package/skills/vercel-migration-deep-dive/references/pre-migration-assessment.md +39 -0
- package/skills/vercel-multi-env-setup/SKILL.md +167 -164
- package/skills/vercel-multi-env-setup/references/configuration-structure.md +59 -0
- package/skills/vercel-multi-env-setup/references/errors.md +11 -0
- package/skills/vercel-multi-env-setup/references/examples.md +11 -0
- package/skills/vercel-observability/SKILL.md +205 -195
- package/skills/vercel-observability/references/alert-configuration.md +40 -0
- package/skills/vercel-observability/references/errors.md +11 -0
- package/skills/vercel-observability/references/examples.md +13 -0
- package/skills/vercel-observability/references/metrics-collection.md +65 -0
- package/skills/vercel-performance-tuning/SKILL.md +212 -156
- package/skills/vercel-performance-tuning/references/caching-strategy.md +49 -0
- package/skills/vercel-performance-tuning/references/errors.md +11 -0
- package/skills/vercel-performance-tuning/references/examples.md +13 -0
- package/skills/vercel-policy-guardrails/SKILL.md +276 -193
- package/skills/vercel-policy-guardrails/references/errors.md +11 -0
- package/skills/vercel-policy-guardrails/references/eslint-rules.md +46 -0
- package/skills/vercel-policy-guardrails/references/examples.md +10 -0
- package/skills/vercel-prod-checklist/SKILL.md +219 -94
- package/skills/vercel-prod-checklist/references/errors.md +11 -0
- package/skills/vercel-prod-checklist/references/examples.md +25 -0
- package/skills/vercel-prod-checklist/references/implementation.md +60 -0
- package/skills/vercel-rate-limits/SKILL.md +187 -100
- package/skills/vercel-rate-limits/references/errors.md +11 -0
- package/skills/vercel-rate-limits/references/examples.md +46 -0
- package/skills/vercel-rate-limits/references/implementation.md +66 -0
- package/skills/vercel-reference-architecture/SKILL.md +226 -180
- package/skills/vercel-reference-architecture/references/errors.md +11 -0
- package/skills/vercel-reference-architecture/references/examples.md +13 -0
- package/skills/vercel-reference-architecture/references/key-components.md +65 -0
- package/skills/vercel-reference-architecture/references/project-structure.md +40 -0
- package/skills/vercel-reliability-patterns/SKILL.md +272 -211
- package/skills/vercel-reliability-patterns/references/circuit-breaker.md +36 -0
- package/skills/vercel-reliability-patterns/references/dead-letter-queue.md +48 -0
- package/skills/vercel-reliability-patterns/references/errors.md +11 -0
- package/skills/vercel-reliability-patterns/references/examples.md +11 -0
- package/skills/vercel-reliability-patterns/references/idempotency-keys.md +36 -0
- package/skills/vercel-sdk-patterns/SKILL.md +264 -92
- package/skills/vercel-sdk-patterns/references/errors.md +11 -0
- package/skills/vercel-sdk-patterns/references/examples.md +45 -0
- package/skills/vercel-sdk-patterns/references/implementation.md +67 -0
- package/skills/vercel-security-basics/SKILL.md +186 -96
- package/skills/vercel-security-basics/references/errors.md +10 -0
- package/skills/vercel-security-basics/references/examples.md +70 -0
- package/skills/vercel-security-basics/references/implementation.md +39 -0
- package/skills/vercel-upgrade-migration/SKILL.md +167 -67
- package/skills/vercel-upgrade-migration/references/errors.md +10 -0
- package/skills/vercel-upgrade-migration/references/examples.md +51 -0
- package/skills/vercel-upgrade-migration/references/implementation.md +29 -0
- package/skills/vercel-webhooks-events/SKILL.md +208 -132
- package/skills/vercel-webhooks-events/references/errors.md +11 -0
- package/skills/vercel-webhooks-events/references/event-handler-pattern.md +37 -0
- package/skills/vercel-webhooks-events/references/examples.md +16 -0
- package/skills/vercel-webhooks-events/references/signature-verification.md +33 -0
|
@@ -1,257 +1,340 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vercel-policy-guardrails
|
|
3
|
-
description:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
description: 'Implement lint rules, CI policy checks, and automated guardrails for
|
|
4
|
+
Vercel projects.
|
|
5
|
+
|
|
6
|
+
Use when setting up code quality rules, preventing secret exposure,
|
|
7
|
+
|
|
8
|
+
or enforcing deployment policies for Vercel applications.
|
|
9
|
+
|
|
7
10
|
Trigger with phrases like "vercel policy", "vercel lint",
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
"vercel guardrails", "vercel best practices check", "vercel secret scan".
|
|
13
|
+
|
|
14
|
+
'
|
|
15
|
+
allowed-tools: Read, Write, Edit, Bash(npx:*), Bash(npm:*)
|
|
10
16
|
version: 1.0.0
|
|
11
17
|
license: MIT
|
|
12
18
|
author: Jeremy Longshore <jeremy@intentsolutions.io>
|
|
19
|
+
tags:
|
|
20
|
+
- saas
|
|
21
|
+
- vercel
|
|
22
|
+
- policy
|
|
23
|
+
- linting
|
|
24
|
+
- security
|
|
25
|
+
compatibility: Designed for Claude Code, also compatible with Codex and OpenClaw
|
|
13
26
|
---
|
|
14
|
-
|
|
15
|
-
# Vercel Policy & Guardrails
|
|
27
|
+
# Vercel Policy Guardrails
|
|
16
28
|
|
|
17
29
|
## Overview
|
|
18
|
-
|
|
30
|
+
|
|
31
|
+
Protect against common Vercel failure modes with automated guardrails: ESLint rules preventing secret exposure in client bundles, pre-commit hooks scanning for credentials, CI checks validating vercel.json and edge runtime compatibility, and runtime middleware enforcing auth on protected routes.
|
|
19
32
|
|
|
20
33
|
## Prerequisites
|
|
34
|
+
|
|
21
35
|
- ESLint configured in project
|
|
22
|
-
-
|
|
23
|
-
- CI/CD pipeline
|
|
36
|
+
- Git hooks infrastructure (husky or lefthook)
|
|
37
|
+
- CI/CD pipeline (GitHub Actions or similar)
|
|
24
38
|
- TypeScript for type enforcement
|
|
25
39
|
|
|
26
|
-
##
|
|
40
|
+
## Instructions
|
|
27
41
|
|
|
28
|
-
###
|
|
29
|
-
```javascript
|
|
30
|
-
// eslint-plugin-vercel/rules/no-hardcoded-keys.js
|
|
31
|
-
module.exports = {
|
|
32
|
-
meta: {
|
|
33
|
-
type: 'problem',
|
|
34
|
-
docs: {
|
|
35
|
-
description: 'Disallow hardcoded Vercel API keys',
|
|
36
|
-
},
|
|
37
|
-
fixable: 'code',
|
|
38
|
-
},
|
|
39
|
-
create(context) {
|
|
40
|
-
return {
|
|
41
|
-
Literal(node) {
|
|
42
|
-
if (typeof node.value === 'string') {
|
|
43
|
-
if (node.value.match(/^sk_(live|test)_[a-zA-Z0-9]{24,}/)) {
|
|
44
|
-
context.report({
|
|
45
|
-
node,
|
|
46
|
-
message: 'Hardcoded Vercel API key detected',
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
```
|
|
42
|
+
### Step 1: ESLint Rules — Prevent Secret Exposure
|
|
55
43
|
|
|
56
|
-
### ESLint Configuration
|
|
57
44
|
```javascript
|
|
58
|
-
// .eslintrc.js
|
|
45
|
+
// .eslintrc.js — custom rules for Vercel projects
|
|
59
46
|
module.exports = {
|
|
60
|
-
plugins: ['vercel'],
|
|
61
47
|
rules: {
|
|
62
|
-
|
|
63
|
-
'
|
|
64
|
-
|
|
48
|
+
// Prevent using NEXT_PUBLIC_ prefix for sensitive variables
|
|
49
|
+
'no-restricted-syntax': [
|
|
50
|
+
'error',
|
|
51
|
+
{
|
|
52
|
+
selector: 'MemberExpression[object.property.name="env"][property.name=/^NEXT_PUBLIC_(SECRET|KEY|TOKEN|PASSWORD|PRIVATE)/]',
|
|
53
|
+
message: 'Do not prefix secrets with NEXT_PUBLIC_ — they will be exposed in the client bundle',
|
|
54
|
+
},
|
|
55
|
+
],
|
|
65
56
|
},
|
|
57
|
+
overrides: [
|
|
58
|
+
{
|
|
59
|
+
// Edge runtime files — prevent Node.js API usage
|
|
60
|
+
files: ['**/edge-*.ts', '**/middleware.ts'],
|
|
61
|
+
rules: {
|
|
62
|
+
'no-restricted-imports': [
|
|
63
|
+
'error',
|
|
64
|
+
{
|
|
65
|
+
paths: [
|
|
66
|
+
{ name: 'fs', message: 'fs is not available in Edge Runtime. Use fetch or Vercel Blob.' },
|
|
67
|
+
{ name: 'path', message: 'path is not available in Edge Runtime. Use URL API.' },
|
|
68
|
+
{ name: 'crypto', message: 'Use globalThis.crypto (Web Crypto API) in Edge Runtime.' },
|
|
69
|
+
{ name: 'child_process', message: 'child_process is not available in Edge Runtime.' },
|
|
70
|
+
{ name: 'net', message: 'net is not available in Edge Runtime.' },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
],
|
|
66
77
|
};
|
|
67
78
|
```
|
|
68
79
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
```yaml
|
|
72
|
-
# .pre-commit-config.yaml
|
|
73
|
-
repos:
|
|
74
|
-
- repo: local
|
|
75
|
-
hooks:
|
|
76
|
-
- id: vercel-secrets-check
|
|
77
|
-
name: Check for Vercel secrets
|
|
78
|
-
entry: bash -c 'git diff --cached --name-only | xargs grep -l "sk_live_" && exit 1 || exit 0'
|
|
79
|
-
language: system
|
|
80
|
-
pass_filenames: false
|
|
81
|
-
|
|
82
|
-
- id: vercel-config-validate
|
|
83
|
-
name: Validate Vercel configuration
|
|
84
|
-
entry: node scripts/validate-vercel-config.js
|
|
85
|
-
language: node
|
|
86
|
-
files: '\.vercel\.json$'
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
## TypeScript Strict Patterns
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
// Enforce typed configuration
|
|
93
|
-
interface VercelStrictConfig {
|
|
94
|
-
apiKey: string; // Required
|
|
95
|
-
environment: 'development' | 'staging' | 'production'; // Enum
|
|
96
|
-
timeout: number; // Required number, not optional
|
|
97
|
-
retries: number;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Disallow any in Vercel code
|
|
101
|
-
// @ts-expect-error - Using any is forbidden
|
|
102
|
-
const client = new Client({ apiKey: any });
|
|
103
|
-
|
|
104
|
-
// Prefer this
|
|
105
|
-
const client = new VercelClient(config satisfies VercelStrictConfig);
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
## Architecture Decision Records
|
|
109
|
-
|
|
110
|
-
### ADR Template
|
|
111
|
-
```markdown
|
|
112
|
-
# ADR-001: Vercel Client Initialization
|
|
113
|
-
|
|
114
|
-
## Status
|
|
115
|
-
Accepted
|
|
80
|
+
### Step 2: Pre-Commit Hook — Credential Scanning
|
|
116
81
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
We will use the singleton pattern with lazy initialization.
|
|
122
|
-
|
|
123
|
-
## Consequences
|
|
124
|
-
- Pro: Single client instance, connection reuse
|
|
125
|
-
- Pro: Easy to mock in tests
|
|
126
|
-
- Con: Global state requires careful lifecycle management
|
|
127
|
-
|
|
128
|
-
## Enforcement
|
|
129
|
-
- ESLint rule: vercel/use-singleton-client
|
|
130
|
-
- CI check: grep for "new VercelClient(" outside allowed files
|
|
82
|
+
```bash
|
|
83
|
+
# Install husky
|
|
84
|
+
npm install --save-dev husky
|
|
85
|
+
npx husky init
|
|
131
86
|
```
|
|
132
87
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
88
|
+
```bash
|
|
89
|
+
#!/usr/bin/env bash
|
|
90
|
+
# .husky/pre-commit
|
|
91
|
+
set -euo pipefail
|
|
92
|
+
|
|
93
|
+
# Scan staged files for credentials
|
|
94
|
+
PATTERNS=(
|
|
95
|
+
'VERCEL_TOKEN\s*[:=]\s*\S+'
|
|
96
|
+
'vercel_[a-zA-Z]*_token\s*[:=]\s*\S+'
|
|
97
|
+
'sk_live_[a-zA-Z0-9]+'
|
|
98
|
+
'NEXT_PUBLIC_.*SECRET'
|
|
99
|
+
'api\.vercel\.com.*Bearer\s+[a-zA-Z0-9]+'
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
103
|
+
FOUND=0
|
|
104
|
+
|
|
105
|
+
for file in $STAGED_FILES; do
|
|
106
|
+
for pattern in "${PATTERNS[@]}"; do
|
|
107
|
+
if grep -qEi "$pattern" "$file" 2>/dev/null; then
|
|
108
|
+
echo "ERROR: Potential credential found in $file"
|
|
109
|
+
echo " Pattern: $pattern"
|
|
110
|
+
FOUND=1
|
|
111
|
+
fi
|
|
112
|
+
done
|
|
113
|
+
done
|
|
114
|
+
|
|
115
|
+
if [ $FOUND -ne 0 ]; then
|
|
116
|
+
echo ""
|
|
117
|
+
echo "Commit blocked: Remove credentials and use environment variables."
|
|
118
|
+
echo "See: vercel env add <KEY> <environment>"
|
|
119
|
+
exit 1
|
|
120
|
+
fi
|
|
157
121
|
```
|
|
158
122
|
|
|
159
|
-
|
|
123
|
+
### Step 3: CI Policy Check — vercel.json Validation
|
|
160
124
|
|
|
161
125
|
```yaml
|
|
162
126
|
# .github/workflows/vercel-policy.yml
|
|
163
|
-
name: Vercel Policy
|
|
164
|
-
|
|
165
|
-
on: [push, pull_request]
|
|
127
|
+
name: Vercel Policy Checks
|
|
128
|
+
on: [pull_request]
|
|
166
129
|
|
|
167
130
|
jobs:
|
|
168
131
|
policy:
|
|
169
132
|
runs-on: ubuntu-latest
|
|
170
133
|
steps:
|
|
171
134
|
- uses: actions/checkout@v4
|
|
135
|
+
- uses: actions/setup-node@v4
|
|
136
|
+
with: { node-version: 20 }
|
|
172
137
|
|
|
173
|
-
- name:
|
|
138
|
+
- name: Validate vercel.json schema
|
|
174
139
|
run: |
|
|
175
|
-
if
|
|
176
|
-
|
|
177
|
-
|
|
140
|
+
if [ -f vercel.json ]; then
|
|
141
|
+
node -e "
|
|
142
|
+
const config = require('./vercel.json');
|
|
143
|
+
const errors = [];
|
|
144
|
+
|
|
145
|
+
// Check for deprecated builds property
|
|
146
|
+
if (config.builds) {
|
|
147
|
+
errors.push('vercel.json uses deprecated \"builds\" property — use \"functions\" instead');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Check compressHTML (iOS Safari issue)
|
|
151
|
+
if (config.compressHTML === true) {
|
|
152
|
+
errors.push('compressHTML should be disabled — causes iOS Safari rendering issues');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Check for hardcoded secrets in headers
|
|
156
|
+
const headerStr = JSON.stringify(config.headers ?? []);
|
|
157
|
+
if (/Bearer\s+[a-zA-Z0-9]{20,}/.test(headerStr)) {
|
|
158
|
+
errors.push('Hardcoded token found in vercel.json headers');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (errors.length > 0) {
|
|
162
|
+
console.error('Policy violations:');
|
|
163
|
+
errors.forEach(e => console.error(' - ' + e));
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
console.log('vercel.json policy checks passed');
|
|
167
|
+
"
|
|
178
168
|
fi
|
|
179
169
|
|
|
180
|
-
- name:
|
|
170
|
+
- name: Check edge runtime compatibility
|
|
181
171
|
run: |
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
172
|
+
# Find files with edge runtime declaration
|
|
173
|
+
for file in $(grep -rl "runtime.*=.*'edge'" src/ api/ 2>/dev/null || true); do
|
|
174
|
+
echo "Checking edge compatibility: $file"
|
|
175
|
+
# Check for Node.js-only imports
|
|
176
|
+
if grep -E "require\(['\"]fs['\"]|from ['\"]fs['\"]|from ['\"]path['\"]|from ['\"]crypto['\"]" "$file"; then
|
|
177
|
+
echo "ERROR: $file uses Node.js APIs incompatible with Edge Runtime"
|
|
178
|
+
exit 1
|
|
179
|
+
fi
|
|
180
|
+
done
|
|
181
|
+
echo "Edge runtime compatibility checks passed"
|
|
182
|
+
|
|
183
|
+
- name: Check bundle size budget
|
|
184
|
+
run: |
|
|
185
|
+
npm ci
|
|
186
|
+
npm run build
|
|
187
|
+
# Check output size
|
|
188
|
+
TOTAL=$(du -sb .next/ 2>/dev/null | cut -f1 || echo 0)
|
|
189
|
+
MAX=$((250 * 1024 * 1024)) # 250MB
|
|
190
|
+
if [ "$TOTAL" -gt "$MAX" ]; then
|
|
191
|
+
echo "ERROR: Build output ($TOTAL bytes) exceeds budget ($MAX bytes)"
|
|
192
|
+
exit 1
|
|
193
|
+
fi
|
|
194
|
+
echo "Bundle size within budget: $TOTAL bytes"
|
|
186
195
|
```
|
|
187
196
|
|
|
188
|
-
|
|
197
|
+
### Step 4: Env Var Documentation Guard
|
|
189
198
|
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
```bash
|
|
200
|
+
#!/usr/bin/env bash
|
|
201
|
+
# scripts/check-env-docs.sh — ensure .env.example stays in sync
|
|
202
|
+
set -euo pipefail
|
|
203
|
+
|
|
204
|
+
# Extract env vars used in code
|
|
205
|
+
CODE_VARS=$(grep -roh 'process\.env\.\w\+' src/ api/ 2>/dev/null \
|
|
206
|
+
| sed 's/process\.env\.//' \
|
|
207
|
+
| sort -u)
|
|
208
|
+
|
|
209
|
+
# Extract vars documented in .env.example
|
|
210
|
+
if [ ! -f .env.example ]; then
|
|
211
|
+
echo "ERROR: .env.example file missing"
|
|
212
|
+
exit 1
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
DOC_VARS=$(grep -oE '^\w+=' .env.example | sed 's/=//' | sort -u)
|
|
216
|
+
|
|
217
|
+
# Find undocumented vars
|
|
218
|
+
MISSING=$(comm -23 <(echo "$CODE_VARS") <(echo "$DOC_VARS"))
|
|
219
|
+
if [ -n "$MISSING" ]; then
|
|
220
|
+
echo "ERROR: Undocumented environment variables:"
|
|
221
|
+
echo "$MISSING" | sed 's/^/ /'
|
|
222
|
+
echo "Add these to .env.example"
|
|
223
|
+
exit 1
|
|
224
|
+
fi
|
|
225
|
+
|
|
226
|
+
echo "All environment variables documented"
|
|
227
|
+
```
|
|
201
228
|
|
|
202
|
-
|
|
203
|
-
function guardRateLimits(requestsInWindow: number): void {
|
|
204
|
-
const limit = parseInt(process.env.VERCEL_RATE_LIMIT || '100');
|
|
229
|
+
### Step 5: Runtime Auth Middleware Guard
|
|
205
230
|
|
|
206
|
-
|
|
207
|
-
|
|
231
|
+
```typescript
|
|
232
|
+
// middleware.ts — enforce that protected routes always require auth
|
|
233
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
234
|
+
|
|
235
|
+
// Routes that MUST require authentication
|
|
236
|
+
const PROTECTED_PATTERNS = [
|
|
237
|
+
/^\/api\/admin/,
|
|
238
|
+
/^\/api\/users/,
|
|
239
|
+
/^\/dashboard/,
|
|
240
|
+
/^\/settings/,
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
// Routes explicitly allowed without auth
|
|
244
|
+
const PUBLIC_PATTERNS = [
|
|
245
|
+
/^\/api\/health/,
|
|
246
|
+
/^\/api\/webhooks/,
|
|
247
|
+
/^\/$/, // homepage
|
|
248
|
+
/^\/login/,
|
|
249
|
+
/^\/signup/,
|
|
250
|
+
];
|
|
251
|
+
|
|
252
|
+
export function middleware(request: NextRequest) {
|
|
253
|
+
const { pathname } = request.nextUrl;
|
|
254
|
+
|
|
255
|
+
const isProtected = PROTECTED_PATTERNS.some(p => p.test(pathname));
|
|
256
|
+
const isPublic = PUBLIC_PATTERNS.some(p => p.test(pathname));
|
|
257
|
+
|
|
258
|
+
if (isProtected && !isPublic) {
|
|
259
|
+
const token = request.cookies.get('session')?.value;
|
|
260
|
+
if (!token) {
|
|
261
|
+
if (pathname.startsWith('/api/')) {
|
|
262
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
263
|
+
}
|
|
264
|
+
return NextResponse.redirect(new URL('/login', request.url));
|
|
265
|
+
}
|
|
208
266
|
}
|
|
209
267
|
|
|
210
|
-
|
|
211
|
-
throw new Error('Vercel rate limit exceeded - request blocked');
|
|
212
|
-
}
|
|
268
|
+
return NextResponse.next();
|
|
213
269
|
}
|
|
214
|
-
```
|
|
215
270
|
|
|
216
|
-
|
|
271
|
+
export const config = {
|
|
272
|
+
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
|
|
273
|
+
};
|
|
274
|
+
```
|
|
217
275
|
|
|
218
|
-
### Step
|
|
219
|
-
Implement custom lint rules for Vercel patterns.
|
|
276
|
+
### Step 6: Deployment Freeze Guard
|
|
220
277
|
|
|
221
|
-
|
|
222
|
-
|
|
278
|
+
```bash
|
|
279
|
+
#!/usr/bin/env bash
|
|
280
|
+
# scripts/check-deploy-freeze.sh — prevent production deploys during freeze windows
|
|
281
|
+
set -euo pipefail
|
|
282
|
+
|
|
283
|
+
# Check if we're in a deployment freeze window
|
|
284
|
+
HOUR=$(date -u +%H)
|
|
285
|
+
DAY=$(date -u +%u) # 1=Monday, 7=Sunday
|
|
286
|
+
|
|
287
|
+
# No deploys on weekends
|
|
288
|
+
if [ "$DAY" -gt 5 ]; then
|
|
289
|
+
echo "BLOCKED: No production deploys on weekends"
|
|
290
|
+
exit 1
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
# No deploys after 4pm UTC (Friday especially)
|
|
294
|
+
if [ "$DAY" -eq 5 ] && [ "$HOUR" -ge 16 ]; then
|
|
295
|
+
echo "BLOCKED: No production deploys after 4pm UTC on Fridays"
|
|
296
|
+
exit 1
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
echo "Deploy allowed"
|
|
300
|
+
```
|
|
223
301
|
|
|
224
|
-
|
|
225
|
-
Implement policy-as-code in CI pipeline.
|
|
302
|
+
## Guardrails Summary
|
|
226
303
|
|
|
227
|
-
|
|
228
|
-
|
|
304
|
+
| Guardrail | Enforcement Point | Prevents |
|
|
305
|
+
|-----------|-------------------|----------|
|
|
306
|
+
| Secret prefix lint | ESLint (editor + CI) | Client bundle secret exposure |
|
|
307
|
+
| Edge runtime lint | ESLint (editor + CI) | Node.js APIs in edge functions |
|
|
308
|
+
| Credential scan | Pre-commit hook | Secrets in version control |
|
|
309
|
+
| vercel.json validation | CI | Deprecated config, hardcoded tokens |
|
|
310
|
+
| Env var documentation | CI | Missing .env.example entries |
|
|
311
|
+
| Auth middleware | Runtime | Unprotected routes |
|
|
312
|
+
| Deploy freeze | CI | Weekend/late deploys |
|
|
229
313
|
|
|
230
314
|
## Output
|
|
231
|
-
- ESLint plugin with Vercel rules
|
|
232
|
-
- Pre-commit hooks blocking secrets
|
|
233
|
-
- CI policy checks passing
|
|
234
|
-
- Runtime guardrails active
|
|
235
315
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
| Policy false positive | Regex too broad | Narrow pattern match |
|
|
242
|
-
| Guardrail triggered | Actual issue | Fix or whitelist |
|
|
316
|
+
- ESLint rules preventing secret exposure and edge runtime violations
|
|
317
|
+
- Pre-commit hooks blocking credentials from entering git
|
|
318
|
+
- CI policy checks validating configuration and compatibility
|
|
319
|
+
- Runtime middleware enforcing authentication on protected routes
|
|
320
|
+
- Deployment freeze windows preventing risky deploys
|
|
243
321
|
|
|
244
|
-
##
|
|
322
|
+
## Error Handling
|
|
245
323
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
324
|
+
| Error | Cause | Solution |
|
|
325
|
+
|-------|-------|----------|
|
|
326
|
+
| ESLint rule false positive | Variable name matches pattern | Add `// eslint-disable-next-line` with justification |
|
|
327
|
+
| Pre-commit hook blocks valid commit | Pattern too broad | Narrow the regex or add allowlist |
|
|
328
|
+
| CI edge check false positive | Dead import | Remove unused import |
|
|
329
|
+
| Deploy freeze too restrictive | Urgent hotfix needed | Use `--force` flag with team approval |
|
|
250
330
|
|
|
251
331
|
## Resources
|
|
252
|
-
|
|
253
|
-
- [
|
|
254
|
-
- [
|
|
332
|
+
|
|
333
|
+
- [ESLint Custom Rules](https://eslint.org/docs/latest/extend/plugins)
|
|
334
|
+
- [Husky Documentation](https://typicode.github.io/husky/)
|
|
335
|
+
- [Vercel Project Configuration](https://vercel.com/docs/project-configuration)
|
|
336
|
+
- [Edge Runtime API](https://vercel.com/docs/functions/runtimes/edge)
|
|
255
337
|
|
|
256
338
|
## Next Steps
|
|
257
|
-
|
|
339
|
+
|
|
340
|
+
For architecture variants, see `vercel-architecture-variants`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Error Handling Reference
|
|
2
|
+
|
|
3
|
+
| Issue | Cause | Solution |
|
|
4
|
+
|-------|-------|----------|
|
|
5
|
+
| ESLint rule not firing | Wrong config | Check plugin registration |
|
|
6
|
+
| Pre-commit skipped | --no-verify | Enforce in CI |
|
|
7
|
+
| Policy false positive | Regex too broad | Narrow pattern match |
|
|
8
|
+
| Guardrail triggered | Actual issue | Fix or whitelist |
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
*[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Eslint Rules
|
|
2
|
+
|
|
3
|
+
## ESLint Rules
|
|
4
|
+
|
|
5
|
+
### Custom Vercel Plugin
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
// eslint-plugin-vercel/rules/no-hardcoded-keys.js
|
|
9
|
+
module.exports = {
|
|
10
|
+
meta: {
|
|
11
|
+
type: 'problem',
|
|
12
|
+
docs: {
|
|
13
|
+
description: 'Disallow hardcoded Vercel API keys',
|
|
14
|
+
},
|
|
15
|
+
fixable: 'code',
|
|
16
|
+
},
|
|
17
|
+
create(context) {
|
|
18
|
+
return {
|
|
19
|
+
Literal(node) {
|
|
20
|
+
if (typeof node.value === 'string') {
|
|
21
|
+
if (node.value.match(/^sk_(live|test)_[a-zA-Z0-9]{24,}/)) {
|
|
22
|
+
context.report({
|
|
23
|
+
node,
|
|
24
|
+
message: 'Hardcoded Vercel API key detected',
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### ESLint Configuration
|
|
35
|
+
|
|
36
|
+
```javascript
|
|
37
|
+
// .eslintrc.js
|
|
38
|
+
module.exports = {
|
|
39
|
+
plugins: ['vercel'],
|
|
40
|
+
rules: {
|
|
41
|
+
'vercel/no-hardcoded-keys': 'error',
|
|
42
|
+
'vercel/require-error-handling': 'warn',
|
|
43
|
+
'vercel/use-typed-client': 'warn',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
```
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
## Examples
|
|
2
|
+
|
|
3
|
+
### Quick ESLint Check
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx eslint --plugin vercel --rule 'vercel/no-hardcoded-keys: error' src/
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
*[Tons of Skills](https://tonsofskills.com) by [Intent Solutions](https://intentsolutions.io) | [jeremylongshore.com](https://jeremylongshore.com)*
|