fix(auth): classify services by service_type, not name heuristics
Coolify exposes the template slug on `service_type`; the list endpoint returns only summaries, so the auth list handler now fetches each service individually to classify it reliably. Users can name auth services anything (e.g. "my-login") and they still show up as auth providers. Made-with: Cursor
This commit is contained in:
@@ -70,18 +70,23 @@ export async function GET(
|
||||
|
||||
try {
|
||||
const all = await listServicesInProject(ws.coolify_project_uuid);
|
||||
// Coolify returns all services — we narrow to ones whose name
|
||||
// contains an auth-provider slug. We also return the full list so
|
||||
// callers can see non-auth services without a separate endpoint.
|
||||
// Coolify's list endpoint only returns summaries (no service_type) so
|
||||
// we fetch each service individually to classify it by template slug.
|
||||
// This is O(n) in services-per-workspace — acceptable at single-digit
|
||||
// scales — and avoids name-based heuristics that break on custom names.
|
||||
const detailed = await Promise.all(all.map(s => getService(s.uuid).catch(() => s)));
|
||||
return NextResponse.json({
|
||||
workspace: { slug: ws.slug, coolifyProjectUuid: ws.coolify_project_uuid },
|
||||
providers: all
|
||||
.filter(s => AUTH_PROVIDER_SLUGS.has(deriveTypeFromName(s.name)))
|
||||
providers: detailed
|
||||
.filter(s => {
|
||||
const t = resolveProviderSlug(s);
|
||||
return !!t && AUTH_PROVIDER_SLUGS.has(t);
|
||||
})
|
||||
.map(s => ({
|
||||
uuid: s.uuid,
|
||||
name: s.name,
|
||||
status: s.status ?? null,
|
||||
provider: deriveTypeFromName(s.name),
|
||||
provider: resolveProviderSlug(s),
|
||||
projectUuid: projectUuidOf(s),
|
||||
})),
|
||||
allowedProviders: Object.keys(AUTH_PROVIDERS),
|
||||
@@ -159,14 +164,15 @@ export async function POST(
|
||||
}
|
||||
|
||||
/**
|
||||
* Coolify names services "{type}-{random-suffix}" when auto-named. We
|
||||
* recover the provider slug by stripping the trailing `-\w+` if any
|
||||
* and matching against our allowlist. Falls back to empty string.
|
||||
* Authoritative: Coolify stores the template slug on `service_type`.
|
||||
* Fall back to a name-prefix match so services created before that field
|
||||
* existed still classify correctly.
|
||||
*/
|
||||
function deriveTypeFromName(name: string): string {
|
||||
function resolveProviderSlug(svc: { name: string; service_type?: string }): string {
|
||||
if (svc.service_type && AUTH_PROVIDER_SLUGS.has(svc.service_type)) return svc.service_type;
|
||||
const candidates = Object.values(AUTH_PROVIDERS).sort((a, b) => b.length - a.length);
|
||||
for (const slug of candidates) {
|
||||
if (name === slug || name.startsWith(`${slug}-`) || name.startsWith(`${slug}_`)) {
|
||||
if (svc.name === slug || svc.name.startsWith(`${slug}-`) || svc.name.startsWith(`${slug}_`)) {
|
||||
return slug;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,6 +560,8 @@ export interface CoolifyService {
|
||||
uuid: string;
|
||||
name: string;
|
||||
status?: string;
|
||||
/** Coolify template slug the service was provisioned from, e.g. "pocketbase". */
|
||||
service_type?: string;
|
||||
project_uuid?: string;
|
||||
environment_id?: number;
|
||||
environment?: { id?: number; project_uuid?: string; project?: { uuid?: string } };
|
||||
|
||||
Reference in New Issue
Block a user