@flink-app/github-app-plugin 0.12.1-alpha.38
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/CHANGELOG.md +209 -0
- package/LICENSE +21 -0
- package/README.md +667 -0
- package/SECURITY.md +498 -0
- package/dist/GitHubAppInternalContext.d.ts +44 -0
- package/dist/GitHubAppInternalContext.js +2 -0
- package/dist/GitHubAppPlugin.d.ts +45 -0
- package/dist/GitHubAppPlugin.js +367 -0
- package/dist/GitHubAppPluginContext.d.ts +242 -0
- package/dist/GitHubAppPluginContext.js +2 -0
- package/dist/GitHubAppPluginOptions.d.ts +369 -0
- package/dist/GitHubAppPluginOptions.js +2 -0
- package/dist/handlers/InitiateInstallation.d.ts +32 -0
- package/dist/handlers/InitiateInstallation.js +66 -0
- package/dist/handlers/InstallationCallback.d.ts +42 -0
- package/dist/handlers/InstallationCallback.js +248 -0
- package/dist/handlers/UninstallHandler.d.ts +37 -0
- package/dist/handlers/UninstallHandler.js +153 -0
- package/dist/handlers/WebhookHandler.d.ts +54 -0
- package/dist/handlers/WebhookHandler.js +157 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +23 -0
- package/dist/repos/GitHubAppSessionRepo.d.ts +24 -0
- package/dist/repos/GitHubAppSessionRepo.js +32 -0
- package/dist/repos/GitHubInstallationRepo.d.ts +53 -0
- package/dist/repos/GitHubInstallationRepo.js +83 -0
- package/dist/repos/GitHubWebhookEventRepo.d.ts +29 -0
- package/dist/repos/GitHubWebhookEventRepo.js +42 -0
- package/dist/schemas/GitHubAppSession.d.ts +13 -0
- package/dist/schemas/GitHubAppSession.js +2 -0
- package/dist/schemas/GitHubInstallation.d.ts +28 -0
- package/dist/schemas/GitHubInstallation.js +2 -0
- package/dist/schemas/InstallationCallbackRequest.d.ts +10 -0
- package/dist/schemas/InstallationCallbackRequest.js +2 -0
- package/dist/schemas/WebhookEvent.d.ts +16 -0
- package/dist/schemas/WebhookEvent.js +2 -0
- package/dist/schemas/WebhookPayload.d.ts +35 -0
- package/dist/schemas/WebhookPayload.js +2 -0
- package/dist/services/GitHubAPIClient.d.ts +143 -0
- package/dist/services/GitHubAPIClient.js +167 -0
- package/dist/services/GitHubAuthService.d.ts +85 -0
- package/dist/services/GitHubAuthService.js +160 -0
- package/dist/services/WebhookValidator.d.ts +93 -0
- package/dist/services/WebhookValidator.js +123 -0
- package/dist/utils/error-utils.d.ts +67 -0
- package/dist/utils/error-utils.js +121 -0
- package/dist/utils/jwt-utils.d.ts +35 -0
- package/dist/utils/jwt-utils.js +67 -0
- package/dist/utils/state-utils.d.ts +38 -0
- package/dist/utils/state-utils.js +74 -0
- package/dist/utils/token-cache-utils.d.ts +47 -0
- package/dist/utils/token-cache-utils.js +74 -0
- package/dist/utils/webhook-signature-utils.d.ts +22 -0
- package/dist/utils/webhook-signature-utils.js +57 -0
- package/examples/basic-installation.ts +246 -0
- package/examples/create-issue.ts +392 -0
- package/examples/error-handling.ts +396 -0
- package/examples/multi-event-webhook.ts +367 -0
- package/examples/organization-installation.ts +316 -0
- package/examples/repository-access.ts +480 -0
- package/examples/webhook-handling.ts +343 -0
- package/examples/with-jwt-auth.ts +319 -0
- package/package.json +41 -0
- package/spec/core-utilities.spec.ts +243 -0
- package/spec/handlers.spec.ts +216 -0
- package/spec/helpers/reporter.ts +41 -0
- package/spec/integration-and-security.spec.ts +483 -0
- package/spec/plugin-core.spec.ts +258 -0
- package/spec/project-setup.spec.ts +56 -0
- package/spec/repos-and-schemas.spec.ts +288 -0
- package/spec/services.spec.ts +108 -0
- package/spec/support/jasmine.json +7 -0
- package/src/GitHubAppPlugin.ts +411 -0
- package/src/GitHubAppPluginContext.ts +254 -0
- package/src/GitHubAppPluginOptions.ts +412 -0
- package/src/handlers/InstallationCallback.ts +292 -0
- package/src/handlers/WebhookHandler.ts +179 -0
- package/src/index.ts +29 -0
- package/src/repos/GitHubAppSessionRepo.ts +36 -0
- package/src/repos/GitHubInstallationRepo.ts +95 -0
- package/src/repos/GitHubWebhookEventRepo.ts +48 -0
- package/src/schemas/GitHubAppSession.ts +13 -0
- package/src/schemas/GitHubInstallation.ts +28 -0
- package/src/schemas/InstallationCallbackRequest.ts +10 -0
- package/src/schemas/WebhookEvent.ts +16 -0
- package/src/schemas/WebhookPayload.ts +35 -0
- package/src/services/GitHubAPIClient.ts +244 -0
- package/src/services/GitHubAuthService.ts +188 -0
- package/src/services/WebhookValidator.ts +159 -0
- package/src/utils/error-utils.ts +148 -0
- package/src/utils/jwt-utils.ts +64 -0
- package/src/utils/state-utils.ts +72 -0
- package/src/utils/token-cache-utils.ts +89 -0
- package/src/utils/webhook-signature-utils.ts +57 -0
- package/tsconfig.dist.json +4 -0
- package/tsconfig.json +24 -0
package/SECURITY.md
ADDED
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
# Security Considerations
|
|
2
|
+
|
|
3
|
+
This document outlines the security measures, best practices, and considerations when using the GitHub App Plugin.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Private Key Management](#private-key-management)
|
|
8
|
+
- [JWT Signing Security](#jwt-signing-security)
|
|
9
|
+
- [Webhook Signature Validation](#webhook-signature-validation)
|
|
10
|
+
- [CSRF Protection](#csrf-protection)
|
|
11
|
+
- [Token Caching Security](#token-caching-security)
|
|
12
|
+
- [HTTPS Requirements](#https-requirements)
|
|
13
|
+
- [Secrets Management](#secrets-management)
|
|
14
|
+
- [Security Checklist](#security-checklist)
|
|
15
|
+
- [Reporting Security Issues](#reporting-security-issues)
|
|
16
|
+
|
|
17
|
+
## Private Key Management
|
|
18
|
+
|
|
19
|
+
### Storage
|
|
20
|
+
|
|
21
|
+
**Environment Variables (Required for Production):**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# .env
|
|
25
|
+
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
|
|
26
|
+
MIIEpAIBAAKCAQEA...
|
|
27
|
+
...
|
|
28
|
+
-----END RSA PRIVATE KEY-----"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**DO NOT:**
|
|
32
|
+
- Commit private keys to version control
|
|
33
|
+
- Store keys in application code
|
|
34
|
+
- Share keys via email or messaging
|
|
35
|
+
- Store keys in plain text files in production
|
|
36
|
+
- Include keys in client-side code
|
|
37
|
+
|
|
38
|
+
**DO:**
|
|
39
|
+
- Store keys in environment variables
|
|
40
|
+
- Use secret management services (AWS Secrets Manager, Azure Key Vault, etc.)
|
|
41
|
+
- Rotate keys periodically (recommended: every 90 days)
|
|
42
|
+
- Use different keys for different environments (dev, staging, prod)
|
|
43
|
+
- Restrict access to keys using IAM policies
|
|
44
|
+
|
|
45
|
+
### PEM Format
|
|
46
|
+
|
|
47
|
+
The plugin automatically detects and supports both PEM formats:
|
|
48
|
+
|
|
49
|
+
**PKCS#1 Format:**
|
|
50
|
+
```
|
|
51
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
52
|
+
MIIEpAIBAAKCAQEA...
|
|
53
|
+
-----END RSA PRIVATE KEY-----
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**PKCS#8 Format:**
|
|
57
|
+
```
|
|
58
|
+
-----BEGIN PRIVATE KEY-----
|
|
59
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBK...
|
|
60
|
+
-----END PRIVATE KEY-----
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Key Validation
|
|
64
|
+
|
|
65
|
+
The plugin validates the private key on initialization:
|
|
66
|
+
|
|
67
|
+
- Checks PEM format (BEGIN/END markers)
|
|
68
|
+
- Verifies key can sign JWTs
|
|
69
|
+
- Tests signature generation
|
|
70
|
+
- Fails fast with clear error messages
|
|
71
|
+
|
|
72
|
+
### Key Rotation
|
|
73
|
+
|
|
74
|
+
To rotate your GitHub App private key:
|
|
75
|
+
|
|
76
|
+
1. Generate new private key in GitHub App settings
|
|
77
|
+
2. Download new key
|
|
78
|
+
3. Update environment variable with new key
|
|
79
|
+
4. Restart application
|
|
80
|
+
5. Revoke old key in GitHub App settings
|
|
81
|
+
6. Monitor for errors
|
|
82
|
+
|
|
83
|
+
## JWT Signing Security
|
|
84
|
+
|
|
85
|
+
### Algorithm
|
|
86
|
+
|
|
87
|
+
The plugin uses **RS256** (RSA Signature with SHA-256) for JWT signing:
|
|
88
|
+
|
|
89
|
+
- Industry standard algorithm
|
|
90
|
+
- Asymmetric encryption (private key signs, public key verifies)
|
|
91
|
+
- More secure than symmetric algorithms (HS256)
|
|
92
|
+
- GitHub requires RS256 for GitHub Apps
|
|
93
|
+
|
|
94
|
+
### JWT Structure
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
{
|
|
98
|
+
iat: <timestamp>, // Issued at time
|
|
99
|
+
exp: <timestamp + 600>, // Expires at time (10 minutes)
|
|
100
|
+
iss: <appId> // Issuer (GitHub App ID)
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Token Expiration
|
|
105
|
+
|
|
106
|
+
- JWTs expire after **10 minutes** (600 seconds)
|
|
107
|
+
- Short expiration reduces risk of token compromise
|
|
108
|
+
- Tokens are only used to obtain installation access tokens
|
|
109
|
+
- Installation access tokens are cached separately
|
|
110
|
+
|
|
111
|
+
### Best Practices
|
|
112
|
+
|
|
113
|
+
- Never expose JWTs to client-side code
|
|
114
|
+
- Validate JWT expiration before use
|
|
115
|
+
- Use HTTPS for all API calls
|
|
116
|
+
- Monitor JWT generation errors
|
|
117
|
+
- Implement rate limiting on authentication endpoints
|
|
118
|
+
|
|
119
|
+
## Webhook Signature Validation
|
|
120
|
+
|
|
121
|
+
### HMAC-SHA256
|
|
122
|
+
|
|
123
|
+
The plugin validates webhook signatures using HMAC-SHA256:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// Signature generation (by GitHub)
|
|
127
|
+
signature = HMAC-SHA256(secret, payload)
|
|
128
|
+
|
|
129
|
+
// Signature validation (by plugin)
|
|
130
|
+
expectedSignature = HMAC-SHA256(webhookSecret, rawBody)
|
|
131
|
+
isValid = constantTimeCompare(signature, expectedSignature)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Constant-Time Comparison
|
|
135
|
+
|
|
136
|
+
The plugin uses `crypto.timingSafeEqual()` for signature comparison:
|
|
137
|
+
|
|
138
|
+
- Prevents timing attacks
|
|
139
|
+
- Ensures comparison takes same time for valid and invalid signatures
|
|
140
|
+
- Required for security-critical comparisons
|
|
141
|
+
|
|
142
|
+
**Vulnerable Code (DO NOT USE):**
|
|
143
|
+
```typescript
|
|
144
|
+
// Timing attack vulnerable
|
|
145
|
+
if (signature === expectedSignature) { ... }
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Secure Code (USED BY PLUGIN):**
|
|
149
|
+
```typescript
|
|
150
|
+
// Timing attack resistant
|
|
151
|
+
if (crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) { ... }
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Signature Header
|
|
155
|
+
|
|
156
|
+
Webhooks include `X-Hub-Signature-256` header:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
X-Hub-Signature-256: sha256=<signature>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The plugin:
|
|
163
|
+
1. Extracts signature from header
|
|
164
|
+
2. Reads raw request body (before JSON parsing)
|
|
165
|
+
3. Computes expected signature using webhook secret
|
|
166
|
+
4. Compares using constant-time comparison
|
|
167
|
+
5. Rejects webhook if signatures don't match (401 status)
|
|
168
|
+
|
|
169
|
+
### Webhook Secret
|
|
170
|
+
|
|
171
|
+
**Generate Secure Webhook Secret:**
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
# Generate random 32-byte secret
|
|
175
|
+
openssl rand -hex 32
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Store in Environment Variables:**
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
GITHUB_WEBHOOK_SECRET=your-webhook-secret-here
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Configure in GitHub App:**
|
|
185
|
+
|
|
186
|
+
1. Go to GitHub App settings
|
|
187
|
+
2. Find "Webhook secret" field
|
|
188
|
+
3. Enter the same secret used in plugin configuration
|
|
189
|
+
4. Save changes
|
|
190
|
+
|
|
191
|
+
## CSRF Protection
|
|
192
|
+
|
|
193
|
+
### State Parameter
|
|
194
|
+
|
|
195
|
+
The plugin implements CSRF protection using state parameter:
|
|
196
|
+
|
|
197
|
+
**Flow:**
|
|
198
|
+
|
|
199
|
+
1. User initiates installation
|
|
200
|
+
2. Plugin generates cryptographically secure state (32 bytes)
|
|
201
|
+
3. Plugin stores state in session (MongoDB) with TTL
|
|
202
|
+
4. Plugin redirects to GitHub with state parameter
|
|
203
|
+
5. GitHub redirects back with state parameter
|
|
204
|
+
6. Plugin validates state using constant-time comparison
|
|
205
|
+
7. Plugin deletes session (one-time use)
|
|
206
|
+
|
|
207
|
+
**State Generation:**
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
// Cryptographically secure random generation
|
|
211
|
+
const state = crypto.randomBytes(32).toString('hex');
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Session Management
|
|
215
|
+
|
|
216
|
+
**Session Schema:**
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
{
|
|
220
|
+
sessionId: string; // Unique session ID
|
|
221
|
+
state: string; // CSRF state parameter
|
|
222
|
+
userId?: string; // Optional user ID
|
|
223
|
+
createdAt: Date; // Session creation time
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
**Session TTL:**
|
|
228
|
+
|
|
229
|
+
- Default: **10 minutes** (600 seconds)
|
|
230
|
+
- Configurable via `sessionTTL` option
|
|
231
|
+
- Automatic cleanup via MongoDB TTL index
|
|
232
|
+
- One-time use: deleted after successful callback
|
|
233
|
+
|
|
234
|
+
### State Validation
|
|
235
|
+
|
|
236
|
+
**Validation Steps:**
|
|
237
|
+
|
|
238
|
+
1. Extract state from query parameter
|
|
239
|
+
2. Find session in database
|
|
240
|
+
3. Compare state using constant-time comparison
|
|
241
|
+
4. Check session hasn't expired
|
|
242
|
+
5. Delete session (prevent replay attacks)
|
|
243
|
+
|
|
244
|
+
**Security Properties:**
|
|
245
|
+
|
|
246
|
+
- One-time use (session deleted after validation)
|
|
247
|
+
- Time-limited (TTL expiration)
|
|
248
|
+
- Constant-time comparison (timing attack resistant)
|
|
249
|
+
- Unpredictable (32-byte random value)
|
|
250
|
+
|
|
251
|
+
## Token Caching Security
|
|
252
|
+
|
|
253
|
+
### In-Memory Only
|
|
254
|
+
|
|
255
|
+
Installation access tokens are cached **in-memory only**:
|
|
256
|
+
|
|
257
|
+
**DO:**
|
|
258
|
+
- Cache tokens in memory for performance
|
|
259
|
+
- Clear cache periodically
|
|
260
|
+
- Limit cache size
|
|
261
|
+
|
|
262
|
+
**DO NOT:**
|
|
263
|
+
- Store tokens in database
|
|
264
|
+
- Log tokens to files
|
|
265
|
+
- Send tokens to client
|
|
266
|
+
- Store tokens in browser storage
|
|
267
|
+
|
|
268
|
+
### Cache Structure
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// In-memory cache (Map)
|
|
272
|
+
{
|
|
273
|
+
[installationId]: {
|
|
274
|
+
token: string,
|
|
275
|
+
expiresAt: number // Unix timestamp
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Token Expiration
|
|
281
|
+
|
|
282
|
+
- Installation access tokens expire after **60 minutes**
|
|
283
|
+
- Plugin caches tokens for **55 minutes** (5-minute safety margin)
|
|
284
|
+
- Automatic refresh when expired
|
|
285
|
+
- Manual cache clearing via `clearTokenCache()`
|
|
286
|
+
|
|
287
|
+
### Cache Clearing
|
|
288
|
+
|
|
289
|
+
**When to Clear Cache:**
|
|
290
|
+
|
|
291
|
+
- Application shutdown
|
|
292
|
+
- Security incident
|
|
293
|
+
- Force token refresh
|
|
294
|
+
- Memory pressure
|
|
295
|
+
|
|
296
|
+
**How to Clear Cache:**
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
ctx.plugins.githubApp.clearTokenCache();
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Token Security
|
|
303
|
+
|
|
304
|
+
- Tokens never exposed to client
|
|
305
|
+
- Tokens automatically expire
|
|
306
|
+
- Tokens scoped to installation
|
|
307
|
+
- Tokens revoked if installation deleted
|
|
308
|
+
|
|
309
|
+
## HTTPS Requirements
|
|
310
|
+
|
|
311
|
+
### Production Requirements
|
|
312
|
+
|
|
313
|
+
**All endpoints MUST use HTTPS in production:**
|
|
314
|
+
|
|
315
|
+
- GitHub App callback URL
|
|
316
|
+
- Webhook URL
|
|
317
|
+
- API calls to GitHub
|
|
318
|
+
- All client-facing endpoints
|
|
319
|
+
|
|
320
|
+
### Why HTTPS is Required
|
|
321
|
+
|
|
322
|
+
- Prevents man-in-the-middle attacks
|
|
323
|
+
- Protects tokens in transit
|
|
324
|
+
- Required by GitHub for OAuth and webhooks
|
|
325
|
+
- Industry best practice
|
|
326
|
+
|
|
327
|
+
### Development
|
|
328
|
+
|
|
329
|
+
For local development, you can use:
|
|
330
|
+
|
|
331
|
+
- ngrok for HTTPS tunneling
|
|
332
|
+
- localhost with self-signed certificates
|
|
333
|
+
- Development-only HTTP (not recommended)
|
|
334
|
+
|
|
335
|
+
**ngrok Example:**
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
ngrok http 3000
|
|
339
|
+
# Use ngrok URL for GitHub App callback and webhook URLs
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Secrets Management
|
|
343
|
+
|
|
344
|
+
### Environment Variables
|
|
345
|
+
|
|
346
|
+
**Required Secrets:**
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
GITHUB_APP_ID=123456
|
|
350
|
+
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----..."
|
|
351
|
+
GITHUB_WEBHOOK_SECRET=your-webhook-secret
|
|
352
|
+
GITHUB_APP_CLIENT_ID=Iv1.abc123
|
|
353
|
+
GITHUB_APP_CLIENT_SECRET=your-client-secret
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Production Best Practices
|
|
357
|
+
|
|
358
|
+
**Use Secret Management Services:**
|
|
359
|
+
|
|
360
|
+
- **AWS Secrets Manager** - Rotate secrets automatically
|
|
361
|
+
- **Azure Key Vault** - Centralized secret management
|
|
362
|
+
- **Google Secret Manager** - GCP native solution
|
|
363
|
+
- **HashiCorp Vault** - Open-source option
|
|
364
|
+
|
|
365
|
+
**DO NOT:**
|
|
366
|
+
- Commit secrets to version control
|
|
367
|
+
- Share secrets via email or chat
|
|
368
|
+
- Store secrets in plain text files
|
|
369
|
+
- Include secrets in error messages
|
|
370
|
+
- Log secrets to console or files
|
|
371
|
+
|
|
372
|
+
**DO:**
|
|
373
|
+
- Use environment variables
|
|
374
|
+
- Rotate secrets regularly
|
|
375
|
+
- Use different secrets per environment
|
|
376
|
+
- Implement least privilege access
|
|
377
|
+
- Monitor secret access
|
|
378
|
+
|
|
379
|
+
### .gitignore
|
|
380
|
+
|
|
381
|
+
Ensure your `.gitignore` includes:
|
|
382
|
+
|
|
383
|
+
```gitignore
|
|
384
|
+
.env
|
|
385
|
+
.env.local
|
|
386
|
+
.env.*.local
|
|
387
|
+
*.pem
|
|
388
|
+
*.key
|
|
389
|
+
secrets/
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Secret Rotation
|
|
393
|
+
|
|
394
|
+
**Regular Rotation Schedule:**
|
|
395
|
+
|
|
396
|
+
- Private key: Every 90 days
|
|
397
|
+
- Webhook secret: Every 90 days
|
|
398
|
+
- Client secret: Every 90 days
|
|
399
|
+
|
|
400
|
+
**Emergency Rotation:**
|
|
401
|
+
|
|
402
|
+
- Immediately if compromised
|
|
403
|
+
- After security incident
|
|
404
|
+
- After employee departure
|
|
405
|
+
- After third-party breach
|
|
406
|
+
|
|
407
|
+
## Security Checklist
|
|
408
|
+
|
|
409
|
+
### Pre-Deployment
|
|
410
|
+
|
|
411
|
+
- [ ] All secrets stored in environment variables
|
|
412
|
+
- [ ] No secrets committed to version control
|
|
413
|
+
- [ ] HTTPS enabled for all endpoints
|
|
414
|
+
- [ ] Webhook signature validation enabled
|
|
415
|
+
- [ ] CSRF protection enabled
|
|
416
|
+
- [ ] Private key validated on startup
|
|
417
|
+
- [ ] Token caching configured properly
|
|
418
|
+
- [ ] Session TTL configured appropriately
|
|
419
|
+
- [ ] MongoDB connection secured with authentication
|
|
420
|
+
- [ ] Error messages don't expose sensitive information
|
|
421
|
+
|
|
422
|
+
### Production
|
|
423
|
+
|
|
424
|
+
- [ ] Webhook secret is cryptographically secure
|
|
425
|
+
- [ ] Private key rotated within 90 days
|
|
426
|
+
- [ ] HTTPS certificates are valid and not expired
|
|
427
|
+
- [ ] Rate limiting configured
|
|
428
|
+
- [ ] Monitoring and alerting configured
|
|
429
|
+
- [ ] Logs don't contain secrets
|
|
430
|
+
- [ ] IAM policies restrict secret access
|
|
431
|
+
- [ ] Backup and disaster recovery plan in place
|
|
432
|
+
|
|
433
|
+
### Monitoring
|
|
434
|
+
|
|
435
|
+
- [ ] Monitor webhook signature failures
|
|
436
|
+
- [ ] Monitor JWT generation errors
|
|
437
|
+
- [ ] Monitor token cache hit rate
|
|
438
|
+
- [ ] Monitor installation creation/deletion
|
|
439
|
+
- [ ] Alert on repeated authentication failures
|
|
440
|
+
- [ ] Alert on unexpected webhook deliveries
|
|
441
|
+
|
|
442
|
+
### Incident Response
|
|
443
|
+
|
|
444
|
+
- [ ] Rotate all secrets immediately
|
|
445
|
+
- [ ] Clear token cache
|
|
446
|
+
- [ ] Review audit logs
|
|
447
|
+
- [ ] Identify compromised installations
|
|
448
|
+
- [ ] Notify affected users
|
|
449
|
+
- [ ] Document incident and lessons learned
|
|
450
|
+
|
|
451
|
+
## Reporting Security Issues
|
|
452
|
+
|
|
453
|
+
If you discover a security vulnerability in this plugin, please report it responsibly:
|
|
454
|
+
|
|
455
|
+
**DO NOT:**
|
|
456
|
+
- Open public GitHub issues for security vulnerabilities
|
|
457
|
+
- Disclose vulnerabilities publicly before patch is available
|
|
458
|
+
- Exploit vulnerabilities in production systems
|
|
459
|
+
|
|
460
|
+
**DO:**
|
|
461
|
+
- Email security concerns to: [Your security email]
|
|
462
|
+
- Provide detailed reproduction steps
|
|
463
|
+
- Wait for response before public disclosure
|
|
464
|
+
- Follow responsible disclosure practices
|
|
465
|
+
|
|
466
|
+
**Expected Response Time:**
|
|
467
|
+
|
|
468
|
+
- Initial response: Within 48 hours
|
|
469
|
+
- Status update: Within 1 week
|
|
470
|
+
- Patch release: Varies based on severity
|
|
471
|
+
|
|
472
|
+
### Security Updates
|
|
473
|
+
|
|
474
|
+
Subscribe to security updates:
|
|
475
|
+
|
|
476
|
+
- Watch GitHub repository for security advisories
|
|
477
|
+
- Follow release notes for security patches
|
|
478
|
+
- Enable GitHub Dependabot alerts
|
|
479
|
+
|
|
480
|
+
## Additional Resources
|
|
481
|
+
|
|
482
|
+
- [GitHub App Security Best Practices](https://docs.github.com/en/developers/apps/getting-started-with-apps/best-practices-for-creating-a-github-app)
|
|
483
|
+
- [Webhook Security](https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks)
|
|
484
|
+
- [JWT Best Practices](https://tools.ietf.org/html/rfc8725)
|
|
485
|
+
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
|
486
|
+
- [MongoDB Security Checklist](https://docs.mongodb.com/manual/administration/security-checklist/)
|
|
487
|
+
|
|
488
|
+
## Conclusion
|
|
489
|
+
|
|
490
|
+
Security is a shared responsibility. This plugin implements industry best practices for GitHub App integration, but you must also:
|
|
491
|
+
|
|
492
|
+
- Follow the guidelines in this document
|
|
493
|
+
- Keep dependencies up to date
|
|
494
|
+
- Monitor your application
|
|
495
|
+
- Rotate secrets regularly
|
|
496
|
+
- Respond quickly to incidents
|
|
497
|
+
|
|
498
|
+
If you have questions about security, please reach out through the appropriate channels.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FlinkContext } from "@flink-app/flink";
|
|
2
|
+
import { GitHubAuthService } from "./services/GitHubAuthService";
|
|
3
|
+
import { WebhookValidator } from "./services/WebhookValidator";
|
|
4
|
+
import GitHubAppSessionRepo from "./repos/GitHubAppSessionRepo";
|
|
5
|
+
import GitHubInstallationRepo from "./repos/GitHubInstallationRepo";
|
|
6
|
+
import GitHubWebhookEventRepo from "./repos/GitHubWebhookEventRepo";
|
|
7
|
+
import { GitHubAppPluginOptions } from "./GitHubAppPluginOptions";
|
|
8
|
+
/**
|
|
9
|
+
* Internal context interface with private methods and services
|
|
10
|
+
*
|
|
11
|
+
* This interface extends the base FlinkContext with GitHub App Plugin-specific
|
|
12
|
+
* repositories, services, and configuration. It's used internally by handlers,
|
|
13
|
+
* services, and the plugin itself.
|
|
14
|
+
*/
|
|
15
|
+
export interface GitHubAppInternalContext extends FlinkContext {
|
|
16
|
+
/**
|
|
17
|
+
* GitHub App Session Repository
|
|
18
|
+
* Manages temporary installation sessions for CSRF protection
|
|
19
|
+
*/
|
|
20
|
+
repos: FlinkContext['repos'] & {
|
|
21
|
+
githubAppSessionRepo: GitHubAppSessionRepo;
|
|
22
|
+
githubInstallationRepo: GitHubInstallationRepo;
|
|
23
|
+
githubWebhookEventRepo?: GitHubWebhookEventRepo;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Internal plugin state and services
|
|
27
|
+
*/
|
|
28
|
+
_githubAppInternal: {
|
|
29
|
+
/**
|
|
30
|
+
* GitHub Authentication Service
|
|
31
|
+
* Handles JWT generation and installation token management
|
|
32
|
+
*/
|
|
33
|
+
authService: GitHubAuthService;
|
|
34
|
+
/**
|
|
35
|
+
* Webhook Validator
|
|
36
|
+
* Validates webhook signatures and parses payloads
|
|
37
|
+
*/
|
|
38
|
+
webhookValidator: WebhookValidator;
|
|
39
|
+
/**
|
|
40
|
+
* Plugin configuration options
|
|
41
|
+
*/
|
|
42
|
+
options: GitHubAppPluginOptions;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { FlinkPlugin } from "@flink-app/flink";
|
|
2
|
+
import { GitHubAppPluginOptions } from "./GitHubAppPluginOptions";
|
|
3
|
+
/**
|
|
4
|
+
* GitHub App Plugin Factory Function
|
|
5
|
+
*
|
|
6
|
+
* Creates a Flink plugin for GitHub App integration with:
|
|
7
|
+
* - Installation management
|
|
8
|
+
* - JWT-based authentication with private key signing
|
|
9
|
+
* - Installation access token management with automatic refresh and caching
|
|
10
|
+
* - Webhook integration with signature validation
|
|
11
|
+
* - GitHub API client wrapper
|
|
12
|
+
*
|
|
13
|
+
* @param options - GitHub App plugin configuration options
|
|
14
|
+
* @returns FlinkPlugin instance
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { githubAppPlugin } from '@flink-app/github-app-plugin';
|
|
19
|
+
*
|
|
20
|
+
* const app = new FlinkApp({
|
|
21
|
+
* plugins: [
|
|
22
|
+
* githubAppPlugin({
|
|
23
|
+
* appId: process.env.GITHUB_APP_ID!,
|
|
24
|
+
* privateKey: process.env.GITHUB_APP_PRIVATE_KEY!,
|
|
25
|
+
* webhookSecret: process.env.GITHUB_WEBHOOK_SECRET!,
|
|
26
|
+
* clientId: process.env.GITHUB_APP_CLIENT_ID!,
|
|
27
|
+
* clientSecret: process.env.GITHUB_APP_CLIENT_SECRET!,
|
|
28
|
+
* onInstallationSuccess: async ({ installationId, repositories, account }, ctx) => {
|
|
29
|
+
* const userId = getLoggedInUserId(req); // App-defined function
|
|
30
|
+
* return {
|
|
31
|
+
* userId,
|
|
32
|
+
* redirectUrl: '/dashboard/repos'
|
|
33
|
+
* };
|
|
34
|
+
* },
|
|
35
|
+
* onWebhookEvent: async ({ event, payload, installationId }, ctx) => {
|
|
36
|
+
* if (event === 'push') {
|
|
37
|
+
* // Process push event
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* })
|
|
41
|
+
* ]
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function githubAppPlugin(options: GitHubAppPluginOptions): FlinkPlugin;
|