feat: add GitLab Duo and CodeBuddy support, update observability settings
This commit is contained in:
parent
11e6004fcb
commit
abbf8ec86f
21 changed files with 779 additions and 141 deletions
|
|
@ -22,7 +22,11 @@ export async function GET(request, { params }) {
|
|||
|
||||
if (action === "authorize") {
|
||||
const redirectUri = searchParams.get("redirect_uri") || "http://localhost:8080/callback";
|
||||
const authData = generateAuthData(provider, redirectUri);
|
||||
// Collect provider-specific meta params (e.g. gitlab passes baseUrl, clientId, clientSecret)
|
||||
const reservedParams = new Set(["redirect_uri"]);
|
||||
const meta = {};
|
||||
searchParams.forEach((value, key) => { if (!reservedParams.has(key)) meta[key] = value; });
|
||||
const authData = generateAuthData(provider, redirectUri, Object.keys(meta).length ? meta : undefined);
|
||||
return NextResponse.json(authData);
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +39,7 @@ export async function GET(request, { params }) {
|
|||
const authData = generateAuthData(provider, null);
|
||||
|
||||
// Providers that don't use PKCE for device code
|
||||
const noPkceDeviceProviders = ["github", "kiro", "kimi-coding", "kilocode"];
|
||||
const noPkceDeviceProviders = ["github", "kiro", "kimi-coding", "kilocode", "codebuddy"];
|
||||
let deviceData;
|
||||
if (noPkceDeviceProviders.includes(provider)) {
|
||||
deviceData = await requestDeviceCode(provider);
|
||||
|
|
@ -70,7 +74,7 @@ export async function POST(request, { params }) {
|
|||
}
|
||||
|
||||
if (action === "exchange") {
|
||||
const { code, redirectUri, codeVerifier, state } = body;
|
||||
const { code, redirectUri, codeVerifier, state, meta } = body;
|
||||
|
||||
// Cline uses authorization_code without PKCE
|
||||
const noPkceExchangeProviders = ["cline"];
|
||||
|
|
@ -78,8 +82,8 @@ export async function POST(request, { params }) {
|
|||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Exchange code for tokens
|
||||
const tokenData = await exchangeTokens(provider, code, redirectUri, codeVerifier, state);
|
||||
// Exchange code for tokens (meta carries provider-specific params, e.g. gitlab clientId/baseUrl)
|
||||
const tokenData = await exchangeTokens(provider, code, redirectUri, codeVerifier, state, meta);
|
||||
|
||||
// Save to database
|
||||
const connection = await createProviderConnection({
|
||||
|
|
@ -111,7 +115,7 @@ export async function POST(request, { params }) {
|
|||
}
|
||||
|
||||
// Providers that don't use PKCE for device code
|
||||
const noPkceProviders = ["github", "kimi-coding", "kilocode"];
|
||||
const noPkceProviders = ["github", "kimi-coding", "kilocode", "codebuddy"];
|
||||
let result;
|
||||
if (noPkceProviders.includes(provider)) {
|
||||
result = await pollForToken(provider, deviceCode);
|
||||
|
|
|
|||
62
src/app/api/oauth/gitlab/pat/route.js
Normal file
62
src/app/api/oauth/gitlab/pat/route.js
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { createProviderConnection } from "@/models";
|
||||
|
||||
const GITLAB_DEFAULT_BASE = "https://gitlab.com";
|
||||
|
||||
/**
|
||||
* POST /api/oauth/gitlab/pat
|
||||
* Authenticate GitLab Duo with a Personal Access Token (PAT)
|
||||
*/
|
||||
export async function POST(request) {
|
||||
try {
|
||||
let body;
|
||||
try {
|
||||
body = await request.json();
|
||||
} catch {
|
||||
return NextResponse.json({ error: "Invalid request body" }, { status: 400 });
|
||||
}
|
||||
|
||||
const { token, baseUrl } = body;
|
||||
if (!token?.trim()) {
|
||||
return NextResponse.json({ error: "Personal Access Token is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const base = (baseUrl?.trim() || GITLAB_DEFAULT_BASE).replace(/\/$/, "");
|
||||
|
||||
// Verify token by fetching current user
|
||||
const userRes = await fetch(`${base}/api/v4/user`, {
|
||||
headers: { "Private-Token": token.trim(), Accept: "application/json" },
|
||||
});
|
||||
|
||||
if (!userRes.ok) {
|
||||
const err = await userRes.text();
|
||||
return NextResponse.json({ error: `GitLab token verification failed: ${err}` }, { status: 401 });
|
||||
}
|
||||
|
||||
const user = await userRes.json();
|
||||
const email = user.email || user.public_email || "";
|
||||
|
||||
await createProviderConnection({
|
||||
provider: "gitlab",
|
||||
authType: "oauth",
|
||||
accessToken: token.trim(),
|
||||
refreshToken: null,
|
||||
expiresAt: null,
|
||||
email,
|
||||
displayName: user.name || user.username || email,
|
||||
testStatus: "active",
|
||||
providerSpecificData: {
|
||||
username: user.username || "",
|
||||
email,
|
||||
name: user.name || "",
|
||||
baseUrl: base,
|
||||
authKind: "personal_access_token",
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error("GitLab PAT auth error:", error);
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
|
@ -68,6 +68,14 @@ const OAUTH_TEST_CONFIG = {
|
|||
authPrefix: "Bearer ",
|
||||
},
|
||||
cline: { refreshable: true },
|
||||
gitlab: {
|
||||
// Test by hitting the GitLab user API — requires api or read_user scope
|
||||
url: "https://gitlab.com/api/v4/user",
|
||||
method: "GET",
|
||||
authHeader: "Authorization",
|
||||
authPrefix: "Bearer ",
|
||||
},
|
||||
codebuddy: { tokenExists: true },
|
||||
};
|
||||
|
||||
async function probeClineAccessToken(accessToken) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue