codekin 0.6.1 → 0.6.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.
- package/dist/assets/index-C8GlUCii.js +182 -0
- package/dist/assets/index-DgeUVGjz.css +1 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/dist/approval-manager.d.ts +7 -2
- package/server/dist/approval-manager.js +11 -3
- package/server/dist/approval-manager.js.map +1 -1
- package/server/dist/claude-process.js +11 -5
- package/server/dist/claude-process.js.map +1 -1
- package/server/dist/session-lifecycle.d.ts +1 -1
- package/server/dist/session-lifecycle.js +28 -11
- package/server/dist/session-lifecycle.js.map +1 -1
- package/server/dist/session-manager.d.ts +1 -1
- package/server/dist/session-manager.js +69 -58
- package/server/dist/session-manager.js.map +1 -1
- package/server/dist/session-naming.js +25 -2
- package/server/dist/session-naming.js.map +1 -1
- package/server/dist/session-persistence.js +1 -0
- package/server/dist/session-persistence.js.map +1 -1
- package/server/dist/session-restart-scheduler.d.ts +3 -0
- package/server/dist/session-restart-scheduler.js +13 -3
- package/server/dist/session-restart-scheduler.js.map +1 -1
- package/server/dist/tsconfig.tsbuildinfo +1 -1
- package/server/dist/types.d.ts +6 -1
- package/server/dist/types.js +0 -1
- package/server/dist/types.js.map +1 -1
- package/server/dist/upload-routes.js +8 -0
- package/server/dist/upload-routes.js.map +1 -1
- package/server/dist/webhook-config.d.ts +9 -0
- package/server/dist/webhook-config.js +41 -3
- package/server/dist/webhook-config.js.map +1 -1
- package/server/dist/webhook-github-setup.d.ts +48 -0
- package/server/dist/webhook-github-setup.js +172 -0
- package/server/dist/webhook-github-setup.js.map +1 -0
- package/server/dist/webhook-setup-routes.d.ts +14 -0
- package/server/dist/webhook-setup-routes.js +233 -0
- package/server/dist/webhook-setup-routes.js.map +1 -0
- package/server/dist/webhook-types.d.ts +65 -0
- package/server/dist/workflow-routes.js +1 -0
- package/server/dist/workflow-routes.js.map +1 -1
- package/server/dist/ws-server.js +2 -0
- package/server/dist/ws-server.js.map +1 -1
- package/dist/assets/index-BNU7FIQx.css +0 -1
- package/dist/assets/index-k7mgzd5O.js +0 -182
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'fs';
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from 'fs';
|
|
2
2
|
import { homedir } from 'os';
|
|
3
|
-
import { join } from 'path';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { randomBytes } from 'crypto';
|
|
4
5
|
const CONFIG_FILE = join(homedir(), '.codekin', 'webhook-config.json');
|
|
5
6
|
/**
|
|
6
7
|
* Load webhook configuration from environment variables and optional config file.
|
|
@@ -12,6 +13,7 @@ export function loadWebhookConfig() {
|
|
|
12
13
|
let maxConcurrentSessions = 3;
|
|
13
14
|
let logLinesToInclude = 200;
|
|
14
15
|
let actorAllowlist = [];
|
|
16
|
+
let secret = '';
|
|
15
17
|
// Try loading config file
|
|
16
18
|
if (existsSync(CONFIG_FILE)) {
|
|
17
19
|
try {
|
|
@@ -26,6 +28,8 @@ export function loadWebhookConfig() {
|
|
|
26
28
|
if (Array.isArray(file.actorAllowlist) && file.actorAllowlist.every(v => typeof v === 'string')) {
|
|
27
29
|
actorAllowlist = file.actorAllowlist;
|
|
28
30
|
}
|
|
31
|
+
if (typeof file.secret === 'string')
|
|
32
|
+
secret = file.secret;
|
|
29
33
|
}
|
|
30
34
|
catch (err) {
|
|
31
35
|
console.warn('[webhook] Failed to parse config file:', err);
|
|
@@ -52,7 +56,10 @@ export function loadWebhookConfig() {
|
|
|
52
56
|
if (envActorAllowlist !== undefined) {
|
|
53
57
|
actorAllowlist = envActorAllowlist.split(',').map(s => s.trim()).filter(Boolean);
|
|
54
58
|
}
|
|
55
|
-
const
|
|
59
|
+
const envSecret = process.env.GITHUB_WEBHOOK_SECRET;
|
|
60
|
+
if (envSecret !== undefined) {
|
|
61
|
+
secret = envSecret;
|
|
62
|
+
}
|
|
56
63
|
return {
|
|
57
64
|
enabled,
|
|
58
65
|
secret,
|
|
@@ -61,4 +68,35 @@ export function loadWebhookConfig() {
|
|
|
61
68
|
actorAllowlist,
|
|
62
69
|
};
|
|
63
70
|
}
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Config persistence for auto-setup
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
/**
|
|
75
|
+
* Generate a cryptographically random webhook secret.
|
|
76
|
+
*/
|
|
77
|
+
export function generateWebhookSecret() {
|
|
78
|
+
return randomBytes(32).toString('hex');
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Persist webhook config updates to the config file (atomic read-merge-write).
|
|
82
|
+
* Only writes fields that are explicitly provided; preserves existing values.
|
|
83
|
+
*/
|
|
84
|
+
export function saveWebhookConfig(updates) {
|
|
85
|
+
let existing = {};
|
|
86
|
+
if (existsSync(CONFIG_FILE)) {
|
|
87
|
+
try {
|
|
88
|
+
existing = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Start fresh if file is corrupt
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const merged = { ...existing, ...updates };
|
|
95
|
+
// Ensure directory exists
|
|
96
|
+
mkdirSync(dirname(CONFIG_FILE), { recursive: true });
|
|
97
|
+
// Atomic write: write to tmp file then rename
|
|
98
|
+
const tmpFile = CONFIG_FILE + '.tmp';
|
|
99
|
+
writeFileSync(tmpFile, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
100
|
+
renameSync(tmpFile, CONFIG_FILE);
|
|
101
|
+
}
|
|
64
102
|
//# sourceMappingURL=webhook-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook-config.js","sourceRoot":"","sources":["../webhook-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"webhook-config.js","sourceRoot":"","sources":["../webhook-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API helpers for webhook discovery and management.
|
|
3
|
+
*
|
|
4
|
+
* Used by the integration health-check and setup-wizard endpoints.
|
|
5
|
+
* Follows the same patterns as webhook-github.ts: injectable ghRunner,
|
|
6
|
+
* graceful degradation, console warnings on failure.
|
|
7
|
+
*/
|
|
8
|
+
import type { GitHubWebhook, GitHubDelivery, SetupPreview } from './webhook-types.js';
|
|
9
|
+
type GhRunner = (args: string[]) => Promise<string>;
|
|
10
|
+
/** @internal Test-only: override the gh CLI runner */
|
|
11
|
+
export declare function _setGhRunner(runner: GhRunner): void;
|
|
12
|
+
/** @internal Test-only: reset to default gh CLI runner */
|
|
13
|
+
export declare function _resetGhRunner(): void;
|
|
14
|
+
/**
|
|
15
|
+
* List all webhooks configured on a GitHub repository.
|
|
16
|
+
* Requires admin access to the repo.
|
|
17
|
+
*/
|
|
18
|
+
export declare function listRepoWebhooks(repo: string): Promise<GitHubWebhook[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Find the Codekin webhook on a repo by matching the configured URL.
|
|
21
|
+
*/
|
|
22
|
+
export declare function findCodekinWebhook(repo: string, webhookUrl: string): Promise<GitHubWebhook | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Fetch recent webhook deliveries for a specific hook.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getWebhookDeliveries(repo: string, hookId: number, count?: number): Promise<GitHubDelivery[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Create a new webhook on a GitHub repository.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createRepoWebhook(repo: string, url: string, secret: string, events: string[]): Promise<GitHubWebhook>;
|
|
31
|
+
/**
|
|
32
|
+
* Update an existing webhook on a GitHub repository.
|
|
33
|
+
*/
|
|
34
|
+
export declare function updateRepoWebhook(repo: string, hookId: number, updates: {
|
|
35
|
+
url?: string;
|
|
36
|
+
events?: string[];
|
|
37
|
+
active?: boolean;
|
|
38
|
+
secret?: string;
|
|
39
|
+
}): Promise<GitHubWebhook>;
|
|
40
|
+
/**
|
|
41
|
+
* Send a ping event to a webhook.
|
|
42
|
+
*/
|
|
43
|
+
export declare function pingWebhook(repo: string, hookId: number): Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* Preview what a webhook setup would do (create vs update vs nothing).
|
|
46
|
+
*/
|
|
47
|
+
export declare function previewWebhookSetup(repo: string, webhookUrl: string): Promise<SetupPreview>;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API helpers for webhook discovery and management.
|
|
3
|
+
*
|
|
4
|
+
* Used by the integration health-check and setup-wizard endpoints.
|
|
5
|
+
* Follows the same patterns as webhook-github.ts: injectable ghRunner,
|
|
6
|
+
* graceful degradation, console warnings on failure.
|
|
7
|
+
*/
|
|
8
|
+
import { execFile } from 'child_process';
|
|
9
|
+
import { promisify } from 'util';
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
const GH_TIMEOUT_MS = 30_000;
|
|
12
|
+
let ghRunner = async (args) => {
|
|
13
|
+
const { stdout } = await execFileAsync('gh', args, { timeout: GH_TIMEOUT_MS });
|
|
14
|
+
return stdout;
|
|
15
|
+
};
|
|
16
|
+
/** @internal Test-only: override the gh CLI runner */
|
|
17
|
+
export function _setGhRunner(runner) {
|
|
18
|
+
ghRunner = runner;
|
|
19
|
+
}
|
|
20
|
+
/** @internal Test-only: reset to default gh CLI runner */
|
|
21
|
+
export function _resetGhRunner() {
|
|
22
|
+
ghRunner = async (args) => {
|
|
23
|
+
const { stdout } = await execFileAsync('gh', args, { timeout: GH_TIMEOUT_MS });
|
|
24
|
+
return stdout;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Phase 1: Discovery
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
/**
|
|
31
|
+
* List all webhooks configured on a GitHub repository.
|
|
32
|
+
* Requires admin access to the repo.
|
|
33
|
+
*/
|
|
34
|
+
export async function listRepoWebhooks(repo) {
|
|
35
|
+
try {
|
|
36
|
+
const raw = await ghRunner(['api', `/repos/${repo}/hooks`, '--paginate']);
|
|
37
|
+
const hooks = JSON.parse(raw);
|
|
38
|
+
return Array.isArray(hooks) ? hooks : [];
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.warn(`listRepoWebhooks: failed for ${repo}:`, err);
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Find the Codekin webhook on a repo by matching the configured URL.
|
|
47
|
+
*/
|
|
48
|
+
export async function findCodekinWebhook(repo, webhookUrl) {
|
|
49
|
+
const hooks = await listRepoWebhooks(repo);
|
|
50
|
+
return hooks.find(h => h.config.url === webhookUrl) ?? null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Fetch recent webhook deliveries for a specific hook.
|
|
54
|
+
*/
|
|
55
|
+
export async function getWebhookDeliveries(repo, hookId, count = 5) {
|
|
56
|
+
try {
|
|
57
|
+
const raw = await ghRunner([
|
|
58
|
+
'api',
|
|
59
|
+
`/repos/${repo}/hooks/${hookId}/deliveries?per_page=${count}`,
|
|
60
|
+
]);
|
|
61
|
+
const deliveries = JSON.parse(raw);
|
|
62
|
+
return Array.isArray(deliveries) ? deliveries : [];
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
console.warn(`getWebhookDeliveries: failed for ${repo} hook ${hookId}:`, err);
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Phase 2: Setup & Management
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
/**
|
|
73
|
+
* Create a new webhook on a GitHub repository.
|
|
74
|
+
*/
|
|
75
|
+
export async function createRepoWebhook(repo, url, secret, events) {
|
|
76
|
+
const body = JSON.stringify({
|
|
77
|
+
name: 'web',
|
|
78
|
+
active: true,
|
|
79
|
+
events,
|
|
80
|
+
config: { url, content_type: 'json', secret, insecure_ssl: '0' },
|
|
81
|
+
});
|
|
82
|
+
const raw = await ghRunnerWithStdin(['api', `/repos/${repo}/hooks`, '--method', 'POST', '--input', '-'], body);
|
|
83
|
+
return JSON.parse(raw);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Update an existing webhook on a GitHub repository.
|
|
87
|
+
*/
|
|
88
|
+
export async function updateRepoWebhook(repo, hookId, updates) {
|
|
89
|
+
const body = {};
|
|
90
|
+
if (updates.events)
|
|
91
|
+
body.events = updates.events;
|
|
92
|
+
if (updates.active !== undefined)
|
|
93
|
+
body.active = updates.active;
|
|
94
|
+
const config = {};
|
|
95
|
+
if (updates.url)
|
|
96
|
+
config.url = updates.url;
|
|
97
|
+
if (updates.secret)
|
|
98
|
+
config.secret = updates.secret;
|
|
99
|
+
if (Object.keys(config).length > 0) {
|
|
100
|
+
config.content_type = 'json';
|
|
101
|
+
config.insecure_ssl = '0';
|
|
102
|
+
body.config = config;
|
|
103
|
+
}
|
|
104
|
+
const raw = await ghRunnerWithStdin(['api', `/repos/${repo}/hooks/${hookId}`, '--method', 'PATCH', '--input', '-'], JSON.stringify(body));
|
|
105
|
+
return JSON.parse(raw);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Send a ping event to a webhook.
|
|
109
|
+
*/
|
|
110
|
+
export async function pingWebhook(repo, hookId) {
|
|
111
|
+
try {
|
|
112
|
+
await ghRunner([
|
|
113
|
+
'api', `/repos/${repo}/hooks/${hookId}/pings`,
|
|
114
|
+
'--method', 'POST',
|
|
115
|
+
]);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
console.warn(`pingWebhook: failed for ${repo} hook ${hookId}:`, err);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Preview what a webhook setup would do (create vs update vs nothing).
|
|
125
|
+
*/
|
|
126
|
+
export async function previewWebhookSetup(repo, webhookUrl) {
|
|
127
|
+
const existing = await findCodekinWebhook(repo, webhookUrl);
|
|
128
|
+
const requiredEvents = ['pull_request', 'workflow_run'];
|
|
129
|
+
if (!existing) {
|
|
130
|
+
return {
|
|
131
|
+
action: 'create',
|
|
132
|
+
proposed: { url: webhookUrl, events: requiredEvents, active: true },
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
const changes = [];
|
|
136
|
+
if (!existing.active)
|
|
137
|
+
changes.push('Activate webhook (currently inactive)');
|
|
138
|
+
const missingEvents = requiredEvents.filter(e => !existing.events.includes(e));
|
|
139
|
+
if (missingEvents.length > 0) {
|
|
140
|
+
changes.push(`Add missing events: ${missingEvents.join(', ')}`);
|
|
141
|
+
}
|
|
142
|
+
if (changes.length === 0) {
|
|
143
|
+
return { action: 'none', existing, proposed: { url: webhookUrl, events: existing.events, active: true } };
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
action: 'update',
|
|
147
|
+
existing,
|
|
148
|
+
proposed: {
|
|
149
|
+
url: webhookUrl,
|
|
150
|
+
events: [...new Set([...existing.events, ...requiredEvents])],
|
|
151
|
+
active: true,
|
|
152
|
+
},
|
|
153
|
+
changes,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Internal: gh runner with stdin support (for POST/PATCH bodies)
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
async function ghRunnerWithStdin(args, stdin) {
|
|
160
|
+
return new Promise((resolve, reject) => {
|
|
161
|
+
const proc = execFile('gh', args, { timeout: GH_TIMEOUT_MS }, (err, stdout) => {
|
|
162
|
+
if (err) {
|
|
163
|
+
reject(err);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
resolve(stdout);
|
|
167
|
+
});
|
|
168
|
+
proc.stdin?.write(stdin);
|
|
169
|
+
proc.stdin?.end();
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=webhook-github-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-github-setup.js","sourceRoot":"","sources":["../webhook-github-setup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST routes for webhook integration health checks and setup.
|
|
3
|
+
*
|
|
4
|
+
* Mounted at the Express app root (routes carry their own /api/ prefixes).
|
|
5
|
+
* Provides health-check, auto-setup, and test-delivery endpoints for the
|
|
6
|
+
* GitHub PR review integration.
|
|
7
|
+
*/
|
|
8
|
+
import { Router } from 'express';
|
|
9
|
+
import type { Request } from 'express';
|
|
10
|
+
import type { FullWebhookConfig } from './webhook-config.js';
|
|
11
|
+
type VerifyFn = (token: string | undefined) => boolean;
|
|
12
|
+
type ExtractFn = (req: Request) => string | undefined;
|
|
13
|
+
export declare function createWebhookSetupRouter(verifyToken: VerifyFn, extractToken: ExtractFn, getConfig: () => FullWebhookConfig): Router;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REST routes for webhook integration health checks and setup.
|
|
3
|
+
*
|
|
4
|
+
* Mounted at the Express app root (routes carry their own /api/ prefixes).
|
|
5
|
+
* Provides health-check, auto-setup, and test-delivery endpoints for the
|
|
6
|
+
* GitHub PR review integration.
|
|
7
|
+
*/
|
|
8
|
+
import { Router } from 'express';
|
|
9
|
+
import { checkGhHealth } from './webhook-github.js';
|
|
10
|
+
import { findCodekinWebhook, getWebhookDeliveries, createRepoWebhook, updateRepoWebhook, pingWebhook, previewWebhookSetup as previewSetup, } from './webhook-github-setup.js';
|
|
11
|
+
import { generateWebhookSecret, saveWebhookConfig } from './webhook-config.js';
|
|
12
|
+
export function createWebhookSetupRouter(verifyToken, extractToken, getConfig) {
|
|
13
|
+
const router = Router();
|
|
14
|
+
const REPO_PATTERN = /^[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+$/;
|
|
15
|
+
// --- Health check endpoint ---
|
|
16
|
+
router.get('/api/integrations/github/pr-review/health', async (req, res) => {
|
|
17
|
+
const token = extractToken(req);
|
|
18
|
+
if (!verifyToken(token))
|
|
19
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
20
|
+
const repo = req.query.repo;
|
|
21
|
+
const webhookUrl = req.query.webhookUrl;
|
|
22
|
+
if (!repo || !webhookUrl) {
|
|
23
|
+
return res.status(400).json({ error: 'Missing required query params: repo, webhookUrl' });
|
|
24
|
+
}
|
|
25
|
+
if (!REPO_PATTERN.test(repo)) {
|
|
26
|
+
return res.status(400).json({ error: 'Invalid repo format. Expected owner/repo.' });
|
|
27
|
+
}
|
|
28
|
+
const config = getConfig();
|
|
29
|
+
const result = {
|
|
30
|
+
overall: 'healthy',
|
|
31
|
+
checks: {
|
|
32
|
+
ghCli: { ok: false, message: '' },
|
|
33
|
+
config: { ok: false, message: '' },
|
|
34
|
+
webhook: { ok: false, message: '' },
|
|
35
|
+
deliveries: { ok: false, message: '' },
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
// Check 1: Config
|
|
39
|
+
const secretSet = config.secret.length > 0;
|
|
40
|
+
if (!config.enabled) {
|
|
41
|
+
result.checks.config = {
|
|
42
|
+
ok: false,
|
|
43
|
+
message: 'Webhooks are disabled. Set GITHUB_WEBHOOK_ENABLED=true to enable.',
|
|
44
|
+
details: { enabled: false, secretSet },
|
|
45
|
+
};
|
|
46
|
+
result.overall = 'unconfigured';
|
|
47
|
+
// Still run other checks for diagnostic value
|
|
48
|
+
}
|
|
49
|
+
else if (!secretSet) {
|
|
50
|
+
result.checks.config = {
|
|
51
|
+
ok: false,
|
|
52
|
+
message: 'No webhook secret configured. Set GITHUB_WEBHOOK_SECRET to secure the endpoint.',
|
|
53
|
+
details: { enabled: true, secretSet: false },
|
|
54
|
+
};
|
|
55
|
+
result.overall = 'unconfigured';
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
result.checks.config = {
|
|
59
|
+
ok: true,
|
|
60
|
+
message: 'Webhooks enabled with secret configured.',
|
|
61
|
+
details: { enabled: true, secretSet: true },
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Check 2: gh CLI
|
|
65
|
+
const ghHealth = await checkGhHealth();
|
|
66
|
+
if (!ghHealth.available) {
|
|
67
|
+
result.checks.ghCli = { ok: false, message: ghHealth.reason || 'gh CLI unavailable' };
|
|
68
|
+
result.checks.webhook = { ok: false, message: 'Skipped — gh CLI unavailable' };
|
|
69
|
+
result.checks.deliveries = { ok: false, message: 'Skipped — gh CLI unavailable' };
|
|
70
|
+
if (result.overall !== 'unconfigured')
|
|
71
|
+
result.overall = 'broken';
|
|
72
|
+
return res.json(result);
|
|
73
|
+
}
|
|
74
|
+
result.checks.ghCli = { ok: true, message: 'gh CLI authenticated and connected.' };
|
|
75
|
+
// Check 3: Webhook exists on GitHub
|
|
76
|
+
const hook = await findCodekinWebhook(repo, webhookUrl);
|
|
77
|
+
if (!hook) {
|
|
78
|
+
result.checks.webhook = { ok: false, message: `No webhook found on ${repo} pointing to this server.` };
|
|
79
|
+
result.checks.deliveries = { ok: false, message: 'Skipped — no webhook found' };
|
|
80
|
+
if (result.overall !== 'unconfigured')
|
|
81
|
+
result.overall = 'broken';
|
|
82
|
+
return res.json(result);
|
|
83
|
+
}
|
|
84
|
+
const requiredEvents = ['pull_request', 'workflow_run'];
|
|
85
|
+
const missingEvents = requiredEvents.filter(e => !hook.events.includes(e));
|
|
86
|
+
if (!hook.active) {
|
|
87
|
+
result.checks.webhook = {
|
|
88
|
+
ok: false,
|
|
89
|
+
message: 'Webhook exists but is inactive.',
|
|
90
|
+
details: { id: hook.id, active: false, events: hook.events, url: hook.config.url },
|
|
91
|
+
};
|
|
92
|
+
if (result.overall === 'healthy')
|
|
93
|
+
result.overall = 'degraded';
|
|
94
|
+
}
|
|
95
|
+
else if (missingEvents.length > 0) {
|
|
96
|
+
result.checks.webhook = {
|
|
97
|
+
ok: false,
|
|
98
|
+
message: `Webhook is missing events: ${missingEvents.join(', ')}.`,
|
|
99
|
+
details: { id: hook.id, active: true, events: hook.events, url: hook.config.url },
|
|
100
|
+
};
|
|
101
|
+
if (result.overall === 'healthy')
|
|
102
|
+
result.overall = 'degraded';
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
result.checks.webhook = {
|
|
106
|
+
ok: true,
|
|
107
|
+
message: 'Webhook active with correct events.',
|
|
108
|
+
details: { id: hook.id, active: true, events: hook.events, url: hook.config.url },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Check 4: Recent deliveries
|
|
112
|
+
const rawDeliveries = await getWebhookDeliveries(repo, hook.id, 5);
|
|
113
|
+
const deliveries = rawDeliveries.map(d => ({
|
|
114
|
+
id: d.id,
|
|
115
|
+
status: d.status,
|
|
116
|
+
statusCode: d.status_code,
|
|
117
|
+
deliveredAt: d.delivered_at,
|
|
118
|
+
event: d.event,
|
|
119
|
+
}));
|
|
120
|
+
if (deliveries.length === 0) {
|
|
121
|
+
result.checks.deliveries = {
|
|
122
|
+
ok: true,
|
|
123
|
+
message: 'No deliveries yet — webhook was recently created or no matching events have occurred.',
|
|
124
|
+
details: { recent: [] },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
const failures = deliveries.filter(d => d.statusCode >= 400 || d.status === 'error');
|
|
129
|
+
if (failures.length > 0) {
|
|
130
|
+
result.checks.deliveries = {
|
|
131
|
+
ok: false,
|
|
132
|
+
message: `${failures.length} of ${deliveries.length} recent deliveries failed.`,
|
|
133
|
+
details: { recent: deliveries },
|
|
134
|
+
};
|
|
135
|
+
if (result.overall === 'healthy')
|
|
136
|
+
result.overall = 'degraded';
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
result.checks.deliveries = {
|
|
140
|
+
ok: true,
|
|
141
|
+
message: `All ${deliveries.length} recent deliveries succeeded.`,
|
|
142
|
+
details: { recent: deliveries },
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
res.json(result);
|
|
147
|
+
});
|
|
148
|
+
// --- Preview setup endpoint ---
|
|
149
|
+
router.post('/api/integrations/github/pr-review/setup', async (req, res) => {
|
|
150
|
+
const token = extractToken(req);
|
|
151
|
+
if (!verifyToken(token))
|
|
152
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
153
|
+
const { repo, webhookUrl, dryRun } = req.body;
|
|
154
|
+
if (!repo || !webhookUrl) {
|
|
155
|
+
return res.status(400).json({ error: 'Missing required fields: repo, webhookUrl' });
|
|
156
|
+
}
|
|
157
|
+
if (!REPO_PATTERN.test(repo)) {
|
|
158
|
+
return res.status(400).json({ error: 'Invalid repo format. Expected owner/repo.' });
|
|
159
|
+
}
|
|
160
|
+
// Preview first
|
|
161
|
+
const preview = await previewSetup(repo, webhookUrl);
|
|
162
|
+
if (dryRun || preview.action === 'none') {
|
|
163
|
+
return res.json({ preview, secretGenerated: false });
|
|
164
|
+
}
|
|
165
|
+
// Ensure server is configured: generate secret if needed, enable if needed
|
|
166
|
+
let config = getConfig();
|
|
167
|
+
let secretGenerated = false;
|
|
168
|
+
const configUpdates = {};
|
|
169
|
+
if (!config.secret) {
|
|
170
|
+
configUpdates.secret = generateWebhookSecret();
|
|
171
|
+
secretGenerated = true;
|
|
172
|
+
}
|
|
173
|
+
if (!config.enabled) {
|
|
174
|
+
configUpdates.enabled = true;
|
|
175
|
+
}
|
|
176
|
+
if (Object.keys(configUpdates).length > 0) {
|
|
177
|
+
saveWebhookConfig(configUpdates);
|
|
178
|
+
config = getConfig();
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
let webhook;
|
|
182
|
+
if (preview.action === 'create') {
|
|
183
|
+
webhook = await createRepoWebhook(repo, webhookUrl, config.secret, preview.proposed.events);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
// update
|
|
187
|
+
webhook = await updateRepoWebhook(repo, preview.existing.id, {
|
|
188
|
+
events: preview.proposed.events,
|
|
189
|
+
active: true,
|
|
190
|
+
secret: secretGenerated ? config.secret : undefined,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
res.json({ preview, webhook, secretGenerated });
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
197
|
+
console.warn(`[webhook-setup] Failed to ${preview.action} webhook on ${repo}:`, err);
|
|
198
|
+
res.status(500).json({ error: `Failed to ${preview.action} webhook: ${message}`, preview });
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
// --- Test delivery endpoint ---
|
|
202
|
+
router.post('/api/integrations/github/pr-review/test', async (req, res) => {
|
|
203
|
+
const token = extractToken(req);
|
|
204
|
+
if (!verifyToken(token))
|
|
205
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
206
|
+
const { repo, webhookUrl } = req.body;
|
|
207
|
+
if (!repo || !webhookUrl) {
|
|
208
|
+
return res.status(400).json({ error: 'Missing required fields: repo, webhookUrl' });
|
|
209
|
+
}
|
|
210
|
+
if (!REPO_PATTERN.test(repo)) {
|
|
211
|
+
return res.status(400).json({ error: 'Invalid repo format. Expected owner/repo.' });
|
|
212
|
+
}
|
|
213
|
+
const hook = await findCodekinWebhook(repo, webhookUrl);
|
|
214
|
+
if (!hook) {
|
|
215
|
+
return res.status(404).json({ error: `No Codekin webhook found on ${repo}` });
|
|
216
|
+
}
|
|
217
|
+
const success = await pingWebhook(repo, hook.id);
|
|
218
|
+
if (!success) {
|
|
219
|
+
return res.json({ success: false, message: 'Ping failed — check GitHub API access and repo permissions.' });
|
|
220
|
+
}
|
|
221
|
+
// Brief pause then fetch latest delivery to confirm receipt
|
|
222
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
223
|
+
const deliveries = await getWebhookDeliveries(repo, hook.id, 1);
|
|
224
|
+
const latest = deliveries[0];
|
|
225
|
+
res.json({
|
|
226
|
+
success: true,
|
|
227
|
+
message: 'Ping sent successfully.',
|
|
228
|
+
delivery: latest ? { id: latest.id, statusCode: latest.status_code, event: latest.event } : undefined,
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
return router;
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=webhook-setup-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-setup-routes.js","sourceRoot":"","sources":["../webhook-setup-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -141,6 +141,71 @@ export interface PullRequestPayload {
|
|
|
141
141
|
login: string;
|
|
142
142
|
};
|
|
143
143
|
}
|
|
144
|
+
export interface GitHubWebhook {
|
|
145
|
+
id: number;
|
|
146
|
+
active: boolean;
|
|
147
|
+
config: {
|
|
148
|
+
url: string;
|
|
149
|
+
content_type: string;
|
|
150
|
+
insecure_ssl?: string;
|
|
151
|
+
};
|
|
152
|
+
events: string[];
|
|
153
|
+
created_at: string;
|
|
154
|
+
updated_at: string;
|
|
155
|
+
}
|
|
156
|
+
export interface GitHubDelivery {
|
|
157
|
+
id: number;
|
|
158
|
+
delivered_at: string;
|
|
159
|
+
status: string;
|
|
160
|
+
status_code: number;
|
|
161
|
+
event: string;
|
|
162
|
+
action: string | null;
|
|
163
|
+
}
|
|
164
|
+
export interface HealthCheckDetail {
|
|
165
|
+
ok: boolean;
|
|
166
|
+
message: string;
|
|
167
|
+
}
|
|
168
|
+
export interface HealthCheckResult {
|
|
169
|
+
overall: 'healthy' | 'degraded' | 'broken' | 'unconfigured';
|
|
170
|
+
checks: {
|
|
171
|
+
ghCli: HealthCheckDetail;
|
|
172
|
+
config: HealthCheckDetail & {
|
|
173
|
+
details?: {
|
|
174
|
+
enabled: boolean;
|
|
175
|
+
secretSet: boolean;
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
webhook: HealthCheckDetail & {
|
|
179
|
+
details?: {
|
|
180
|
+
id: number;
|
|
181
|
+
active: boolean;
|
|
182
|
+
events: string[];
|
|
183
|
+
url: string;
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
deliveries: HealthCheckDetail & {
|
|
187
|
+
details?: {
|
|
188
|
+
recent: Array<{
|
|
189
|
+
id: number;
|
|
190
|
+
status: string;
|
|
191
|
+
statusCode: number;
|
|
192
|
+
deliveredAt: string;
|
|
193
|
+
event: string;
|
|
194
|
+
}>;
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
export interface SetupPreview {
|
|
200
|
+
action: 'create' | 'update' | 'none';
|
|
201
|
+
existing?: GitHubWebhook;
|
|
202
|
+
proposed: {
|
|
203
|
+
url: string;
|
|
204
|
+
events: string[];
|
|
205
|
+
active: boolean;
|
|
206
|
+
};
|
|
207
|
+
changes?: string[];
|
|
208
|
+
}
|
|
144
209
|
export interface PullRequestContext {
|
|
145
210
|
repo: string;
|
|
146
211
|
repoName: string;
|