mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-14 22:17:00 +00:00
fix(pat): close restricted-token paths through workflows, chat, schedules and conversations
A resource restriction was checked on ids in the request, not on what the addressed row pulls in or belongs to. Closed: - Workflow writes for tokens restricted on sources, tools or prompts (a graph names those inside its nodes), and attaching a workflow to an agent unless the token is restricted on workflows too. - Chat for tools-restricted tokens (chat executes tools; rejected at token creation as well), and agent-less chat for tokens restricted on prompts or workflows. - conversation_id on chat: it must belong to the agent being run, or to no agent for agent-less chat. Otherwise the server continued, appended to, or resumed pending tool calls of another agent's conversation. - Schedules for tokens restricted on anything but agents; schedule-id routes for every restricted token. - Conversations and analytics for every restricted token, not only agent-restricted ones. Also: create, first publish and adopt return the agent API key masked to a token without agents:keys; token ids must be canonical UUIDs (urn:uuid: gave a 500); an expired token is reported as expired; token creation takes a per-user advisory lock so the cap cannot be raced; admin revoke-sessions writes a pat_revoked event per token. The UI drops a row whose revoke returns 404 and does not offer a tools restriction next to chat:run.
This commit is contained in:
1 parent
b1ff8f516e
commit
94b5924e36
15 files changed
+393
-64
No files matched your search
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import patService, {
|
||||
AccessTokenApiError,
|
||||
AccessTokenPolicy,
|
||||
AccessTokenScope,
|
||||
CreateAccessTokenResponse,
|
||||
@@ -134,6 +135,13 @@ export default function PersonalAccessTokens() {
|
||||
setTokens((prev) => prev.filter((item) => item.id !== target.id));
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
if (err instanceof AccessTokenApiError && err.status === 404) {
|
||||
// Already revoked elsewhere (another tab, an admin): it is gone, so
|
||||
// drop the stale row instead of reporting a failure.
|
||||
setTokens((prev) => prev.filter((item) => item.id !== target.id));
|
||||
setError(null);
|
||||
return;
|
||||
}
|
||||
console.error('Failed to revoke access token:', err);
|
||||
setError(
|
||||
(err instanceof Error && err.message) ||
|
||||
|
||||
@@ -294,3 +294,14 @@ describe('NO_ESCAPE', () => {
|
||||
expect(NO_ESCAPE).toEqual({ interpolation: { escapeValue: false } });
|
||||
});
|
||||
});
|
||||
|
||||
describe('eligibleFilterFamilies with chat:run', () => {
|
||||
const all = ['agents', 'sources', 'prompts', 'tools', 'workflows'];
|
||||
it('never offers a tools restriction next to chat:run', () => {
|
||||
expect(eligibleFilterFamilies(['tools:write', 'chat:run'], all)).toEqual([
|
||||
'agents',
|
||||
'sources',
|
||||
]);
|
||||
expect(eligibleFilterFamilies(['tools:write'], all)).toEqual(['tools']);
|
||||
});
|
||||
});
|
||||
@@ -75,7 +75,11 @@ export function eligibleFilterFamilies(
|
||||
filterableFamilies: string[],
|
||||
): string[] {
|
||||
const families = new Set(selected.map(scopeFamily));
|
||||
if (families.has('chat')) CHAT_FAMILIES.forEach((f) => families.add(f));
|
||||
const chat = families.has('chat');
|
||||
if (chat) CHAT_FAMILIES.forEach((f) => families.add(f));
|
||||
// Chat executes tools, which cannot be held to an allowlist, so the server
|
||||
// rejects a tools restriction on a token that also has chat:run.
|
||||
if (chat) families.delete('tools');
|
||||
return filterableFamilies.filter((family) => families.has(family));
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user