expxagents 0.30.21 → 0.30.23
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/dashboard/assets/{BufferResource-CNVLxaqR.js → BufferResource-D_4NxDi0.js} +1 -1
- package/dist/dashboard/assets/{CanvasRenderer-CxVnsrzD.js → CanvasRenderer-BvvtfkUO.js} +1 -1
- package/dist/dashboard/assets/{JarvisView-Bk0QwZWW.js → JarvisView-DWUg6uy9.js} +1 -1
- package/dist/dashboard/assets/{RenderTargetSystem-CtHj6v7J.js → RenderTargetSystem-KLqqlDII.js} +1 -1
- package/dist/dashboard/assets/{ThreeBackground-DPSa33_n.js → ThreeBackground-CQg8JfT9.js} +1 -1
- package/dist/dashboard/assets/{WebGLRenderer-C2UGtfFx.js → WebGLRenderer-C-rFQnEK.js} +1 -1
- package/dist/dashboard/assets/{WebGPURenderer-CmDaV5xR.js → WebGPURenderer-BgcywHHz.js} +1 -1
- package/dist/dashboard/assets/{browserAll-DuOXddzq.js → browserAll-DxxBcVq_.js} +1 -1
- package/dist/dashboard/assets/index-ChTJhFG1.js +1203 -0
- package/dist/dashboard/assets/{webworkerAll-BlC_rD-w.js → webworkerAll-CKsuA5y-.js} +1 -1
- package/dist/dashboard/index.html +1 -1
- package/dist/server/api/__tests__/github-oauth-routes.test.d.ts +2 -0
- package/dist/server/api/__tests__/github-oauth-routes.test.d.ts.map +1 -0
- package/dist/server/api/__tests__/github-oauth-routes.test.js +119 -0
- package/dist/server/api/__tests__/github-oauth-routes.test.js.map +1 -0
- package/dist/server/api/__tests__/github-webhook.test.d.ts +2 -0
- package/dist/server/api/__tests__/github-webhook.test.d.ts.map +1 -0
- package/dist/server/api/__tests__/github-webhook.test.js +111 -0
- package/dist/server/api/__tests__/github-webhook.test.js.map +1 -0
- package/dist/server/api/__tests__/log-routes.test.js +8 -1
- package/dist/server/api/__tests__/log-routes.test.js.map +1 -1
- package/dist/server/api/github-oauth-routes.d.ts +9 -0
- package/dist/server/api/github-oauth-routes.d.ts.map +1 -0
- package/dist/server/api/github-oauth-routes.js +174 -0
- package/dist/server/api/github-oauth-routes.js.map +1 -0
- package/dist/server/api/integration-routes.d.ts.map +1 -1
- package/dist/server/api/integration-routes.js +6 -3
- package/dist/server/api/integration-routes.js.map +1 -1
- package/dist/server/api/webhook-routes.d.ts.map +1 -1
- package/dist/server/api/webhook-routes.js +88 -0
- package/dist/server/api/webhook-routes.js.map +1 -1
- package/dist/server/app.d.ts +2 -0
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +18 -2
- package/dist/server/app.js.map +1 -1
- package/dist/server/bridge/chat-handler.d.ts +2 -0
- package/dist/server/bridge/chat-handler.d.ts.map +1 -1
- package/dist/server/bridge/chat-handler.js +75 -0
- package/dist/server/bridge/chat-handler.js.map +1 -1
- package/dist/server/db/migrations.d.ts.map +1 -1
- package/dist/server/db/migrations.js +27 -0
- package/dist/server/db/migrations.js.map +1 -1
- package/dist/server/db/schema.d.ts +1 -1
- package/dist/server/db/schema.d.ts.map +1 -1
- package/dist/server/db/schema.js +21 -0
- package/dist/server/db/schema.js.map +1 -1
- package/dist/server/scheduler/debug-routes.d.ts +10 -0
- package/dist/server/scheduler/debug-routes.d.ts.map +1 -0
- package/dist/server/scheduler/debug-routes.js +69 -0
- package/dist/server/scheduler/debug-routes.js.map +1 -0
- package/dist/server/scheduler/scheduler-service.d.ts +40 -0
- package/dist/server/scheduler/scheduler-service.d.ts.map +1 -1
- package/dist/server/scheduler/scheduler-service.js +209 -0
- package/dist/server/scheduler/scheduler-service.js.map +1 -1
- package/dist/server/services/__tests__/github-action-service.test.d.ts +2 -0
- package/dist/server/services/__tests__/github-action-service.test.d.ts.map +1 -0
- package/dist/server/services/__tests__/github-action-service.test.js +89 -0
- package/dist/server/services/__tests__/github-action-service.test.js.map +1 -0
- package/dist/server/services/__tests__/github-credential-service.test.d.ts +2 -0
- package/dist/server/services/__tests__/github-credential-service.test.d.ts.map +1 -0
- package/dist/server/services/__tests__/github-credential-service.test.js +95 -0
- package/dist/server/services/__tests__/github-credential-service.test.js.map +1 -0
- package/dist/server/services/github-action-service.d.ts +21 -0
- package/dist/server/services/github-action-service.d.ts.map +1 -0
- package/dist/server/services/github-action-service.js +105 -0
- package/dist/server/services/github-action-service.js.map +1 -0
- package/dist/server/services/github-credential-service.d.ts +34 -0
- package/dist/server/services/github-credential-service.d.ts.map +1 -0
- package/dist/server/services/github-credential-service.js +158 -0
- package/dist/server/services/github-credential-service.js.map +1 -0
- package/package.json +1 -1
- package/dist/dashboard/assets/index-CgAs6Rfr.js +0 -1203
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a1 as G,a3 as I,a4 as B,l as _,M as k,W as O,N as A,a9 as m,T as v,as as C,R as E,w as z,a8 as U,v as w}from"./index-
|
|
1
|
+
import{a1 as G,a3 as I,a4 as B,l as _,M as k,W as O,N as A,a9 as m,T as v,as as C,R as E,w as z,a8 as U,v as w}from"./index-ChTJhFG1.js";var M=`in vec2 aPosition;
|
|
2
2
|
out vec2 vTextureCoord;
|
|
3
3
|
|
|
4
4
|
uniform vec4 uInputSize;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>ExpxAgents — Mission Control</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-ChTJhFG1.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-DtbIzZ5n.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-oauth-routes.test.d.ts","sourceRoot":"","sources":["../../../src/api/__tests__/github-oauth-routes.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { buildApp } from '../../app.js';
|
|
3
|
+
describe('github oauth routes', () => {
|
|
4
|
+
let app;
|
|
5
|
+
let cookie;
|
|
6
|
+
beforeEach(async () => {
|
|
7
|
+
app = await buildApp({
|
|
8
|
+
config: {
|
|
9
|
+
jwtSecret: 'test-secret-github-oauth-32chars!!',
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
await app.ready();
|
|
13
|
+
const loginRes = await app.inject({
|
|
14
|
+
method: 'POST',
|
|
15
|
+
url: '/api/auth/login',
|
|
16
|
+
payload: { username: 'admin', password: 'admin' },
|
|
17
|
+
});
|
|
18
|
+
const cookies = loginRes.cookies;
|
|
19
|
+
const access = cookies.find((c) => c.name === 'access_token');
|
|
20
|
+
const refresh = cookies.find((c) => c.name === 'refresh_token');
|
|
21
|
+
cookie = `access_token=${access.value}; refresh_token=${refresh.value}`;
|
|
22
|
+
});
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
vi.unstubAllGlobals();
|
|
25
|
+
vi.restoreAllMocks();
|
|
26
|
+
await app.close();
|
|
27
|
+
});
|
|
28
|
+
it('GET /api/integrations/github/oauth/start — redirects to GitHub', async () => {
|
|
29
|
+
process.env.GITHUB_CLIENT_ID = 'test_client_id';
|
|
30
|
+
const res = await app.inject({
|
|
31
|
+
method: 'GET',
|
|
32
|
+
url: '/api/integrations/github/oauth/start',
|
|
33
|
+
headers: { cookie },
|
|
34
|
+
});
|
|
35
|
+
expect(res.statusCode).toBe(302);
|
|
36
|
+
expect(res.headers.location).toContain('github.com/login/oauth/authorize');
|
|
37
|
+
expect(res.headers.location).toContain('client_id=test_client_id');
|
|
38
|
+
delete process.env.GITHUB_CLIENT_ID;
|
|
39
|
+
});
|
|
40
|
+
it('GET /api/integrations/github/oauth/start — 400 if GITHUB_CLIENT_ID not set', async () => {
|
|
41
|
+
delete process.env.GITHUB_CLIENT_ID;
|
|
42
|
+
const res = await app.inject({
|
|
43
|
+
method: 'GET',
|
|
44
|
+
url: '/api/integrations/github/oauth/start',
|
|
45
|
+
headers: { cookie },
|
|
46
|
+
});
|
|
47
|
+
expect(res.statusCode).toBe(400);
|
|
48
|
+
});
|
|
49
|
+
it('GET /api/integrations/github/oauth/callback — exchanges code for token', async () => {
|
|
50
|
+
process.env.GITHUB_CLIENT_ID = 'test_client_id';
|
|
51
|
+
process.env.GITHUB_CLIENT_SECRET = 'test_client_secret';
|
|
52
|
+
const mockFetch = vi.fn()
|
|
53
|
+
.mockResolvedValueOnce({
|
|
54
|
+
ok: true,
|
|
55
|
+
json: async () => ({
|
|
56
|
+
access_token: 'gho_test_token',
|
|
57
|
+
scope: 'repo,read:org',
|
|
58
|
+
token_type: 'bearer',
|
|
59
|
+
}),
|
|
60
|
+
})
|
|
61
|
+
.mockResolvedValueOnce({
|
|
62
|
+
ok: true,
|
|
63
|
+
json: async () => ({ login: 'octocat', type: 'User' }),
|
|
64
|
+
});
|
|
65
|
+
vi.stubGlobal('fetch', mockFetch);
|
|
66
|
+
// First get the state token from /start
|
|
67
|
+
const startRes = await app.inject({
|
|
68
|
+
method: 'GET',
|
|
69
|
+
url: '/api/integrations/github/oauth/start',
|
|
70
|
+
headers: { cookie },
|
|
71
|
+
});
|
|
72
|
+
const location = startRes.headers.location;
|
|
73
|
+
const stateParam = new URL(location).searchParams.get('state');
|
|
74
|
+
const callbackRes = await app.inject({
|
|
75
|
+
method: 'GET',
|
|
76
|
+
url: `/api/integrations/github/oauth/callback?code=test_code&state=${stateParam}`,
|
|
77
|
+
headers: { cookie },
|
|
78
|
+
});
|
|
79
|
+
expect(callbackRes.statusCode).toBe(302);
|
|
80
|
+
expect(callbackRes.headers.location).toContain('connected=github');
|
|
81
|
+
const db = app.db;
|
|
82
|
+
const row = db.prepare("SELECT * FROM github_installations WHERE id = 'oauth'").get();
|
|
83
|
+
expect(row).toBeDefined();
|
|
84
|
+
expect(row.account_login).toBe('octocat');
|
|
85
|
+
delete process.env.GITHUB_CLIENT_ID;
|
|
86
|
+
delete process.env.GITHUB_CLIENT_SECRET;
|
|
87
|
+
});
|
|
88
|
+
it('GET /api/integrations/github/installations — returns installations list', async () => {
|
|
89
|
+
const res = await app.inject({
|
|
90
|
+
method: 'GET',
|
|
91
|
+
url: '/api/integrations/github/installations',
|
|
92
|
+
headers: { cookie },
|
|
93
|
+
});
|
|
94
|
+
expect(res.statusCode).toBe(200);
|
|
95
|
+
expect(res.json().installations).toBeInstanceOf(Array);
|
|
96
|
+
});
|
|
97
|
+
it('DELETE /api/integrations/github/oauth — revokes and removes oauth', async () => {
|
|
98
|
+
const db = app.db;
|
|
99
|
+
const jwtSecret = 'test-secret-github-oauth-32chars!!';
|
|
100
|
+
const crypto = await import('node:crypto');
|
|
101
|
+
const key = crypto.createHash('sha256').update(jwtSecret).digest();
|
|
102
|
+
const iv = crypto.randomBytes(12);
|
|
103
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv, { authTagLength: 16 });
|
|
104
|
+
const enc = Buffer.concat([cipher.update('gho_fake', 'utf8'), cipher.final()]);
|
|
105
|
+
const authTag = cipher.getAuthTag();
|
|
106
|
+
const stored = Buffer.concat([iv, authTag, enc]).toString('base64');
|
|
107
|
+
db.prepare("INSERT OR REPLACE INTO github_installations (id, type, account_login, account_type, access_token) VALUES ('oauth', 'oauth', 'octocat', 'User', ?)").run(stored);
|
|
108
|
+
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok: true }));
|
|
109
|
+
const res = await app.inject({
|
|
110
|
+
method: 'DELETE',
|
|
111
|
+
url: '/api/integrations/github/oauth',
|
|
112
|
+
headers: { cookie },
|
|
113
|
+
});
|
|
114
|
+
expect(res.statusCode).toBe(200);
|
|
115
|
+
const row = db.prepare("SELECT * FROM github_installations WHERE id = 'oauth'").get();
|
|
116
|
+
expect(row).toBeUndefined();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=github-oauth-routes.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-oauth-routes.test.js","sourceRoot":"","sources":["../../../src/api/__tests__/github-oauth-routes.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-webhook.test.d.ts","sourceRoot":"","sources":["../../../src/api/__tests__/github-webhook.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
+
import { buildApp } from '../../app.js';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import YAML from 'yaml';
|
|
8
|
+
function makeSignature(body, secret) {
|
|
9
|
+
return 'sha256=' + crypto.createHmac('sha256', secret).update(body).digest('hex');
|
|
10
|
+
}
|
|
11
|
+
describe('POST /api/webhooks/github', () => {
|
|
12
|
+
let app;
|
|
13
|
+
let squadsDir;
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
squadsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'squads-'));
|
|
16
|
+
process.env.GITHUB_WEBHOOK_SECRET = 'test-webhook-secret';
|
|
17
|
+
app = await buildApp({ config: { squadsDir } });
|
|
18
|
+
await app.ready();
|
|
19
|
+
});
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
fs.rmSync(squadsDir, { recursive: true });
|
|
22
|
+
delete process.env.GITHUB_WEBHOOK_SECRET;
|
|
23
|
+
vi.restoreAllMocks();
|
|
24
|
+
await app.close();
|
|
25
|
+
});
|
|
26
|
+
it('returns 401 for invalid HMAC signature', async () => {
|
|
27
|
+
const body = JSON.stringify({ ref: 'refs/heads/main' });
|
|
28
|
+
const res = await app.inject({
|
|
29
|
+
method: 'POST',
|
|
30
|
+
url: '/api/webhooks/github',
|
|
31
|
+
headers: {
|
|
32
|
+
'x-github-event': 'push',
|
|
33
|
+
'x-hub-signature-256': 'sha256=invalidsignature',
|
|
34
|
+
'content-type': 'application/json',
|
|
35
|
+
},
|
|
36
|
+
body,
|
|
37
|
+
});
|
|
38
|
+
expect(res.statusCode).toBe(401);
|
|
39
|
+
});
|
|
40
|
+
it('returns 200 with no triggered squads when none match', async () => {
|
|
41
|
+
const body = JSON.stringify({ ref: 'refs/heads/main', repository: { full_name: 'org/repo' } });
|
|
42
|
+
const sig = makeSignature(body, 'test-webhook-secret');
|
|
43
|
+
const res = await app.inject({
|
|
44
|
+
method: 'POST',
|
|
45
|
+
url: '/api/webhooks/github',
|
|
46
|
+
headers: {
|
|
47
|
+
'x-github-event': 'push',
|
|
48
|
+
'x-hub-signature-256': sig,
|
|
49
|
+
'content-type': 'application/json',
|
|
50
|
+
},
|
|
51
|
+
body,
|
|
52
|
+
});
|
|
53
|
+
expect(res.statusCode).toBe(200);
|
|
54
|
+
expect(res.json()).toEqual({ received: true, triggered: [] });
|
|
55
|
+
});
|
|
56
|
+
it('triggers squad matching push event with branch filter', async () => {
|
|
57
|
+
const squadDir = path.join(squadsDir, 'test-squad');
|
|
58
|
+
fs.mkdirSync(squadDir, { recursive: true });
|
|
59
|
+
fs.writeFileSync(path.join(squadDir, 'squad.yaml'), YAML.stringify({
|
|
60
|
+
squad: {
|
|
61
|
+
code: 'test-squad',
|
|
62
|
+
name: 'Test Squad',
|
|
63
|
+
github: {
|
|
64
|
+
triggers: [
|
|
65
|
+
{ event: 'push', branch: 'main', action: 'run_pipeline' }
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}));
|
|
70
|
+
const body = JSON.stringify({ ref: 'refs/heads/main', repository: { full_name: 'org/repo' } });
|
|
71
|
+
const sig = makeSignature(body, 'test-webhook-secret');
|
|
72
|
+
const res = await app.inject({
|
|
73
|
+
method: 'POST',
|
|
74
|
+
url: '/api/webhooks/github',
|
|
75
|
+
headers: {
|
|
76
|
+
'x-github-event': 'push',
|
|
77
|
+
'x-hub-signature-256': sig,
|
|
78
|
+
'content-type': 'application/json',
|
|
79
|
+
},
|
|
80
|
+
body,
|
|
81
|
+
});
|
|
82
|
+
expect(res.statusCode).toBe(200);
|
|
83
|
+
expect(res.json().triggered).toContain('test-squad');
|
|
84
|
+
});
|
|
85
|
+
it('does NOT trigger squad when branch does not match', async () => {
|
|
86
|
+
const squadDir = path.join(squadsDir, 'branch-squad');
|
|
87
|
+
fs.mkdirSync(squadDir, { recursive: true });
|
|
88
|
+
fs.writeFileSync(path.join(squadDir, 'squad.yaml'), YAML.stringify({
|
|
89
|
+
squad: {
|
|
90
|
+
code: 'branch-squad',
|
|
91
|
+
name: 'Branch Squad',
|
|
92
|
+
github: { triggers: [{ event: 'push', branch: 'main', action: 'run_pipeline' }] }
|
|
93
|
+
}
|
|
94
|
+
}));
|
|
95
|
+
const body = JSON.stringify({ ref: 'refs/heads/feature', repository: { full_name: 'org/repo' } });
|
|
96
|
+
const sig = makeSignature(body, 'test-webhook-secret');
|
|
97
|
+
const res = await app.inject({
|
|
98
|
+
method: 'POST',
|
|
99
|
+
url: '/api/webhooks/github',
|
|
100
|
+
headers: {
|
|
101
|
+
'x-github-event': 'push',
|
|
102
|
+
'x-hub-signature-256': sig,
|
|
103
|
+
'content-type': 'application/json',
|
|
104
|
+
},
|
|
105
|
+
body,
|
|
106
|
+
});
|
|
107
|
+
expect(res.statusCode).toBe(200);
|
|
108
|
+
expect(res.json().triggered).toEqual([]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
//# sourceMappingURL=github-webhook.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-webhook.test.js","sourceRoot":"","sources":["../../../src/api/__tests__/github-webhook.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import Database from 'better-sqlite3';
|
|
3
|
+
import { runMigrations, seedDefaultAdmin } from '../../db/migrations.js';
|
|
2
4
|
import { buildApp } from '../../app.js';
|
|
3
5
|
describe('log-routes', () => {
|
|
4
6
|
let app;
|
|
7
|
+
let db;
|
|
5
8
|
beforeEach(async () => {
|
|
6
|
-
|
|
9
|
+
db = new Database(':memory:');
|
|
10
|
+
runMigrations(db);
|
|
11
|
+
await seedDefaultAdmin(db);
|
|
12
|
+
app = await buildApp({ db });
|
|
7
13
|
});
|
|
8
14
|
afterEach(async () => {
|
|
9
15
|
await app.close();
|
|
16
|
+
db.close();
|
|
10
17
|
});
|
|
11
18
|
async function getAuthCookie() {
|
|
12
19
|
const loginRes = await app.inject({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-routes.test.js","sourceRoot":"","sources":["../../../src/api/__tests__/log-routes.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAI,GAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"log-routes.test.js","sourceRoot":"","sources":["../../../src/api/__tests__/log-routes.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAGxC,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAI,GAAoB,CAAC;IACzB,IAAI,EAAqB,CAAC;IAE1B,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC9B,aAAa,CAAC,EAAE,CAAC,CAAC;QAClB,MAAM,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAC3B,GAAG,GAAG,MAAM,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAClB,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,KAAK,UAAU,aAAa;QAC1B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC;YAChC,MAAM,EAAE,MAAM;YACd,GAAG,EAAE,iBAAiB;YACtB,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE;SAClD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC9C,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;IAC1D,CAAC;IAED,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC;YAC3B,MAAM,EAAE,KAAK;YACb,GAAG,EAAE,WAAW;YAChB,OAAO,EAAE,EAAE,MAAM,EAAE;SACpB,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FastifyInstance, FastifyPluginOptions } from 'fastify';
|
|
2
|
+
import type Database from 'better-sqlite3';
|
|
3
|
+
interface GitHubOAuthRoutesOptions extends FastifyPluginOptions {
|
|
4
|
+
db: Database.Database;
|
|
5
|
+
jwtSecret: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function githubOAuthRoutes(app: FastifyInstance, opts: GitHubOAuthRoutesOptions): Promise<void>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=github-oauth-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-oauth-routes.d.ts","sourceRoot":"","sources":["../../src/api/github-oauth-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C,UAAU,wBAAyB,SAAQ,oBAAoB;IAC7D,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,IAAI,CAAC,CA6Of"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { signAccessToken, verifyAccessToken } from '../auth/jwt.js';
|
|
2
|
+
import { GitHubCredentialService } from '../services/github-credential-service.js';
|
|
3
|
+
export async function githubOAuthRoutes(app, opts) {
|
|
4
|
+
const { db, jwtSecret } = opts;
|
|
5
|
+
const credentials = new GitHubCredentialService(db, jwtSecret);
|
|
6
|
+
// GET /api/integrations/github/oauth/start — redirect to GitHub OAuth
|
|
7
|
+
app.get('/api/integrations/github/oauth/start', {
|
|
8
|
+
preHandler: [app.requireAuth],
|
|
9
|
+
}, async (request, reply) => {
|
|
10
|
+
const clientId = process.env.GITHUB_CLIENT_ID;
|
|
11
|
+
if (!clientId) {
|
|
12
|
+
return reply.status(400).send({ error: 'GITHUB_CLIENT_ID not configured' });
|
|
13
|
+
}
|
|
14
|
+
const user = request.user;
|
|
15
|
+
const state = signAccessToken({ userId: user.userId, role: 'oauth-state' }, jwtSecret, '10m');
|
|
16
|
+
const params = new URLSearchParams({
|
|
17
|
+
client_id: clientId,
|
|
18
|
+
scope: 'repo,read:org,workflow',
|
|
19
|
+
state,
|
|
20
|
+
});
|
|
21
|
+
return reply.redirect(`https://github.com/login/oauth/authorize?${params.toString()}`);
|
|
22
|
+
});
|
|
23
|
+
// GET /api/integrations/github/oauth/callback — receive GitHub OAuth code
|
|
24
|
+
app.get('/api/integrations/github/oauth/callback', async (request, reply) => {
|
|
25
|
+
const { code, state, error } = request.query;
|
|
26
|
+
if (error) {
|
|
27
|
+
return reply.redirect(`/settings?tab=integrations&error=${encodeURIComponent(error)}`);
|
|
28
|
+
}
|
|
29
|
+
if (!code || !state) {
|
|
30
|
+
return reply.status(400).send({ error: 'Missing code or state' });
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
verifyAccessToken(state, jwtSecret);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return reply.status(400).send({ error: 'Invalid state parameter' });
|
|
37
|
+
}
|
|
38
|
+
const clientId = process.env.GITHUB_CLIENT_ID;
|
|
39
|
+
const clientSecret = process.env.GITHUB_CLIENT_SECRET;
|
|
40
|
+
if (!clientId || !clientSecret) {
|
|
41
|
+
return reply.status(500).send({ error: 'GitHub OAuth not configured' });
|
|
42
|
+
}
|
|
43
|
+
const tokenRes = await fetch('https://github.com/login/oauth/access_token', {
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: { Accept: 'application/json', 'Content-Type': 'application/json' },
|
|
46
|
+
body: JSON.stringify({ client_id: clientId, client_secret: clientSecret, code }),
|
|
47
|
+
});
|
|
48
|
+
const tokenData = await tokenRes.json();
|
|
49
|
+
if (!tokenData.access_token) {
|
|
50
|
+
return reply.redirect(`/settings?tab=integrations&error=${encodeURIComponent(tokenData.error ?? 'oauth_failed')}`);
|
|
51
|
+
}
|
|
52
|
+
const userRes = await fetch('https://api.github.com/user', {
|
|
53
|
+
headers: { Authorization: `Bearer ${tokenData.access_token}` },
|
|
54
|
+
});
|
|
55
|
+
const userData = await userRes.json();
|
|
56
|
+
await credentials.saveOAuthToken({
|
|
57
|
+
accessToken: tokenData.access_token,
|
|
58
|
+
scope: tokenData.scope ?? '',
|
|
59
|
+
accountLogin: userData.login,
|
|
60
|
+
accountType: userData.type,
|
|
61
|
+
});
|
|
62
|
+
return reply.redirect('/settings?tab=integrations&connected=github');
|
|
63
|
+
});
|
|
64
|
+
// GET /api/integrations/github/app/callback — GitHub App installation callback
|
|
65
|
+
app.get('/api/integrations/github/app/callback', async (request, reply) => {
|
|
66
|
+
const { installation_id, setup_action } = request.query;
|
|
67
|
+
if (!installation_id || setup_action !== 'install') {
|
|
68
|
+
return reply.redirect('/settings?tab=integrations');
|
|
69
|
+
}
|
|
70
|
+
const appId = process.env.GITHUB_APP_ID;
|
|
71
|
+
const privateKey = process.env.GITHUB_APP_PRIVATE_KEY;
|
|
72
|
+
if (!appId || !privateKey) {
|
|
73
|
+
return reply.status(500).send({ error: 'GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY not configured' });
|
|
74
|
+
}
|
|
75
|
+
const appJwt = credentials.makeAppJwt(appId, privateKey);
|
|
76
|
+
const tokenRes = await fetch(`https://api.github.com/app/installations/${installation_id}/access_tokens`, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
headers: {
|
|
79
|
+
Authorization: `Bearer ${appJwt}`,
|
|
80
|
+
Accept: 'application/vnd.github+json',
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
if (!tokenRes.ok) {
|
|
84
|
+
return reply.redirect('/settings?tab=integrations&error=app_token_failed');
|
|
85
|
+
}
|
|
86
|
+
const tokenData = await tokenRes.json();
|
|
87
|
+
const instRes = await fetch(`https://api.github.com/app/installations/${installation_id}`, { headers: { Authorization: `Bearer ${appJwt}`, Accept: 'application/vnd.github+json' } });
|
|
88
|
+
const instData = await instRes.json();
|
|
89
|
+
await credentials.saveAppInstallation({
|
|
90
|
+
installationId: installation_id,
|
|
91
|
+
accessToken: tokenData.token,
|
|
92
|
+
tokenExpiresAt: tokenData.expires_at,
|
|
93
|
+
accountLogin: instData.account.login,
|
|
94
|
+
accountType: instData.account.type,
|
|
95
|
+
});
|
|
96
|
+
return reply.redirect('/settings?tab=integrations&connected=github-app');
|
|
97
|
+
});
|
|
98
|
+
// GET /api/integrations/github/installations — list all installations
|
|
99
|
+
app.get('/api/integrations/github/installations', {
|
|
100
|
+
preHandler: [app.requireAuth],
|
|
101
|
+
}, async (_request, reply) => {
|
|
102
|
+
const installations = await credentials.getInstallations();
|
|
103
|
+
return reply.send({ installations });
|
|
104
|
+
});
|
|
105
|
+
// GET /api/integrations/github/webhooks — list registered webhooks
|
|
106
|
+
app.get('/api/integrations/github/webhooks', {
|
|
107
|
+
preHandler: [app.requireAuth],
|
|
108
|
+
}, async (_request, reply) => {
|
|
109
|
+
const rows = db.prepare('SELECT repo_full_name, webhook_id, squad_code FROM github_webhook_registrations ORDER BY created_at DESC').all();
|
|
110
|
+
return reply.send({ webhooks: rows });
|
|
111
|
+
});
|
|
112
|
+
// DELETE /api/integrations/github/oauth — revoke OAuth
|
|
113
|
+
app.delete('/api/integrations/github/oauth', {
|
|
114
|
+
preHandler: [app.requireAuth],
|
|
115
|
+
}, async (_request, reply) => {
|
|
116
|
+
await credentials.revokeOAuth();
|
|
117
|
+
return reply.send({ ok: true });
|
|
118
|
+
});
|
|
119
|
+
// DELETE /api/integrations/github/app/:installationId — remove App installation
|
|
120
|
+
app.delete('/api/integrations/github/app/:installationId', { preHandler: [app.requireAuth] }, async (request, reply) => {
|
|
121
|
+
await credentials.removeAppInstallation(request.params.installationId);
|
|
122
|
+
return reply.send({ ok: true });
|
|
123
|
+
});
|
|
124
|
+
// POST /api/integrations/github/repos/:owner/:repo/webhook/install
|
|
125
|
+
app.post('/api/integrations/github/repos/:owner/:repo/webhook/install', { preHandler: [app.requireAuth] }, async (request, reply) => {
|
|
126
|
+
const { owner, repo } = request.params;
|
|
127
|
+
const serverUrl = process.env.SERVER_URL;
|
|
128
|
+
const webhookSecret = process.env.GITHUB_WEBHOOK_SECRET;
|
|
129
|
+
if (!serverUrl || !webhookSecret) {
|
|
130
|
+
return reply.status(400).send({ error: 'SERVER_URL and GITHUB_WEBHOOK_SECRET must be set' });
|
|
131
|
+
}
|
|
132
|
+
const token = await credentials.getToken();
|
|
133
|
+
const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/hooks`, {
|
|
134
|
+
method: 'POST',
|
|
135
|
+
headers: {
|
|
136
|
+
Authorization: `Bearer ${token}`,
|
|
137
|
+
Accept: 'application/vnd.github+json',
|
|
138
|
+
'Content-Type': 'application/json',
|
|
139
|
+
},
|
|
140
|
+
body: JSON.stringify({
|
|
141
|
+
name: 'web',
|
|
142
|
+
active: true,
|
|
143
|
+
events: ['push', 'pull_request', 'issues', 'workflow_run'],
|
|
144
|
+
config: {
|
|
145
|
+
url: `${serverUrl}/api/webhooks/github`,
|
|
146
|
+
content_type: 'json',
|
|
147
|
+
secret: webhookSecret,
|
|
148
|
+
},
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
if (!res.ok) {
|
|
152
|
+
const err = await res.json();
|
|
153
|
+
return reply.status(res.status).send({ error: err.message ?? 'Failed to create webhook' });
|
|
154
|
+
}
|
|
155
|
+
const hook = await res.json();
|
|
156
|
+
db.prepare('INSERT INTO github_webhook_registrations (repo_full_name, webhook_id, squad_code) VALUES (?, ?, ?)').run(`${owner}/${repo}`, hook.id, request.body?.squad_code ?? null);
|
|
157
|
+
return reply.send({ ok: true, webhook_id: hook.id });
|
|
158
|
+
});
|
|
159
|
+
// DELETE /api/integrations/github/repos/:owner/:repo/webhook
|
|
160
|
+
app.delete('/api/integrations/github/repos/:owner/:repo/webhook', { preHandler: [app.requireAuth] }, async (request, reply) => {
|
|
161
|
+
const { owner, repo } = request.params;
|
|
162
|
+
const row = db.prepare('SELECT webhook_id FROM github_webhook_registrations WHERE repo_full_name = ?').get(`${owner}/${repo}`);
|
|
163
|
+
if (!row)
|
|
164
|
+
return reply.status(404).send({ error: 'Webhook not registered' });
|
|
165
|
+
const token = await credentials.getToken();
|
|
166
|
+
await fetch(`https://api.github.com/repos/${owner}/${repo}/hooks/${row.webhook_id}`, {
|
|
167
|
+
method: 'DELETE',
|
|
168
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/vnd.github+json' },
|
|
169
|
+
});
|
|
170
|
+
db.prepare('DELETE FROM github_webhook_registrations WHERE repo_full_name = ?').run(`${owner}/${repo}`);
|
|
171
|
+
return reply.send({ ok: true });
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=github-oauth-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-oauth-routes.js","sourceRoot":"","sources":["../../src/api/github-oauth-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-routes.d.ts","sourceRoot":"","sources":["../../src/api/integration-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C,UAAU,wBAAyB,SAAQ,oBAAoB;IAC7D,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACvB;AAUD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC;IACzH,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"integration-routes.d.ts","sourceRoot":"","sources":["../../src/api/integration-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C,UAAU,wBAAyB,SAAQ,oBAAoB;IAC7D,EAAE,EAAE,QAAQ,CAAC,QAAQ,CAAC;CACvB;AAUD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,KAAK,GAAG,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,IAAI,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC;IACzH,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED,eAAO,MAAM,gBAAgB,EAAE,kBAAkB,EAuKhD,CAAC;AAqFF,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAqHf"}
|
|
@@ -44,10 +44,13 @@ export const PROVIDER_CATALOG = [
|
|
|
44
44
|
{ key: 'team_id', label: 'Team ID', type: 'text' },
|
|
45
45
|
{ key: 'default_file_key', label: 'Default File Key', type: 'text' },
|
|
46
46
|
] },
|
|
47
|
-
{ key: 'github', name: 'GitHub', category: 'dev', description: 'Repositórios, issues e
|
|
48
|
-
{ key: 'token', label: 'Personal Access Token', type: 'password',
|
|
47
|
+
{ key: 'github', name: 'GitHub', category: 'dev', description: 'Repositórios, issues, PRs e GitHub Actions', fields: [
|
|
48
|
+
{ key: 'token', label: 'Personal Access Token (PAT)', type: 'password', placeholder: 'ghp_...' },
|
|
49
49
|
{ key: 'org', label: 'Organization', type: 'text', placeholder: 'my-org' },
|
|
50
|
-
{ key: 'default_repo', label: 'Default Repository', type: 'text', placeholder: '
|
|
50
|
+
{ key: 'default_repo', label: 'Default Repository', type: 'text', placeholder: 'owner/repo' },
|
|
51
|
+
{ key: 'oauth_client_id', label: 'OAuth App Client ID', type: 'text', placeholder: 'Iv1.abc...' },
|
|
52
|
+
{ key: 'oauth_client_secret', label: 'OAuth App Client Secret', type: 'password' },
|
|
53
|
+
{ key: 'webhook_secret', label: 'Webhook Secret', type: 'password' },
|
|
51
54
|
] },
|
|
52
55
|
{ key: 'gitlab', name: 'GitLab', category: 'dev', description: 'Repositórios, CI/CD e DevOps', fields: [
|
|
53
56
|
{ key: 'token', label: 'Personal Access Token', type: 'password', required: true, placeholder: 'glpat-...' },
|