fix(ai-roles): harden model override, role-name uniqueness, id validation, list least-privilege
Follow-up fixes on the agent-roles feature: - ai.service: a cross-driver override to the ollama driver (when the workspace driver is not ollama) now fails with an explicit 503 instead of silently reusing the workspace base URL, which belongs to a different provider. Same-driver ollama and openai/gemini overrides are unchanged. - migration: add a partial unique index on (workspace_id, name) WHERE deleted_at IS NULL so role names are unique per workspace without soft-deleted rows blocking re-creation; map Postgres 23505 to a 409 ConflictException on create/update. - dto: validate the role id as @IsUUID instead of @IsString. - roles list: do not expose instructions/modelConfig to non-admin members. The list endpoint now returns a picker view (id/name/emoji/description/ enabled) to members and the full view only to admins (same gate as the CRUD endpoints). Client IAiRole fields made optional accordingly. Adds tests for the cross-driver-ollama throw, the 23505->409 mapping, and the non-admin picker-view security invariant. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -83,9 +83,20 @@ export class AiService {
|
||||
// driver's own creds (the workspace driver's key would be wrong/absent).
|
||||
if (overrideDriver && overrideDriver !== cfg.driver) {
|
||||
if (overrideDriver === 'ollama') {
|
||||
// Ollama needs no key; baseUrl is taken from the workspace config (it is
|
||||
// the only configurable endpoint for a local model).
|
||||
apiKey = undefined;
|
||||
// Cross-driver override to ollama: the workspace driver is NOT ollama, so
|
||||
// there is no configured ollama endpoint. `cfg.baseUrl` belongs to the
|
||||
// workspace driver (e.g. an OpenAI/OpenRouter gateway) and pointing the
|
||||
// ollama client at it would silently send requests to the wrong server.
|
||||
// Fail explicitly (503) — a dedicated per-driver ollama endpoint is not
|
||||
// supported yet. The same-driver ollama case (handled outside this block)
|
||||
// legitimately reuses the workspace's ollama endpoint and is unaffected.
|
||||
const who = override?.roleName ? ` for role "${override.roleName}"` : '';
|
||||
throw new AiNotConfiguredException(
|
||||
`An ollama model override${who} requires a dedicated ollama endpoint, ` +
|
||||
`which is not supported when the workspace driver is "${cfg.driver}". ` +
|
||||
`Set the role's driver to "${cfg.driver}" or switch the workspace ` +
|
||||
`to ollama.`,
|
||||
);
|
||||
} else {
|
||||
const creds = await this.aiProviderCredentialsRepo.find(
|
||||
workspaceId,
|
||||
|
||||
Reference in New Issue
Block a user