-
Notifications
You must be signed in to change notification settings - Fork 3.7k
fix(onedrive): align tools with live Graph API docs, add missing endpoints #5478
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+977
−36
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ba6627f
fix(onedrive): align tools with live Graph API docs, add missing endp…
waleedlatif1 3e3cb9a
fix(onedrive): escape single quotes in search query, document embed l…
waleedlatif1 fb38f29
fix(onedrive): add real pagination continuation to search
waleedlatif1 b6c14ae
fix(onedrive): prevent SSRF/token exfiltration via search pageToken
waleedlatif1 8a0c2c9
fix(onedrive): make search query optional for pageToken-only continua…
waleedlatif1 64d3805
fix(onedrive): fix folder-targeting wiring, OData escaping, and downl…
waleedlatif1 5584abe
fix(onedrive): reuse shared assertGraphNextPageUrl for page-token val…
waleedlatif1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| import { createLogger } from '@sim/logger' | ||
| import type { OneDriveCopyResponse, OneDriveToolParams } from '@/tools/onedrive/types' | ||
| import type { ToolConfig } from '@/tools/types' | ||
|
|
||
| const logger = createLogger('OneDriveCopyTool') | ||
|
|
||
| /** | ||
| * Microsoft Graph processes driveItem copies asynchronously: a successful request returns | ||
| * `202 Accepted` with a `Location` header pointing to a monitor URL, not the copied item itself. | ||
| * See https://learn.microsoft.com/en-us/graph/api/driveitem-copy | ||
| */ | ||
| export const copyTool: ToolConfig<OneDriveToolParams, OneDriveCopyResponse> = { | ||
| id: 'onedrive_copy', | ||
| name: 'Copy OneDrive File', | ||
| description: 'Copy a file or folder to another location within OneDrive', | ||
| version: '1.0', | ||
|
|
||
| oauth: { | ||
| required: true, | ||
| provider: 'onedrive', | ||
| }, | ||
|
|
||
| params: { | ||
| accessToken: { | ||
| type: 'string', | ||
| required: true, | ||
| visibility: 'hidden', | ||
| description: 'The access token for the OneDrive API', | ||
| }, | ||
| fileId: { | ||
| type: 'string', | ||
| required: true, | ||
| visibility: 'user-or-llm', | ||
| description: 'The ID of the file or folder to copy', | ||
| }, | ||
| destinationFolderId: { | ||
| type: 'string', | ||
| required: true, | ||
| visibility: 'user-or-llm', | ||
| description: 'The ID of the destination parent folder', | ||
| }, | ||
| destinationFileName: { | ||
| type: 'string', | ||
| required: false, | ||
| visibility: 'user-or-llm', | ||
| description: 'Optional new name for the copy (defaults to the original name)', | ||
| }, | ||
| }, | ||
|
|
||
| request: { | ||
| url: (params) => | ||
| `https://graph.microsoft.com/v1.0/me/drive/items/${encodeURIComponent(params.fileId || '')}/copy`, | ||
| method: 'POST', | ||
| headers: (params) => ({ | ||
| Authorization: `Bearer ${params.accessToken}`, | ||
| 'Content-Type': 'application/json', | ||
| }), | ||
| body: (params) => ({ | ||
| parentReference: { id: params.destinationFolderId }, | ||
| ...(params.destinationFileName && { name: params.destinationFileName }), | ||
| }), | ||
| }, | ||
|
|
||
| transformResponse: async (response: Response, params?: OneDriveToolParams) => { | ||
| if (response.status !== 202) { | ||
| const data = await response.json().catch(() => ({})) | ||
| throw new Error(data.error?.message || 'Failed to start OneDrive copy') | ||
| } | ||
|
|
||
| const monitorUrl = response.headers.get('location') || undefined | ||
|
|
||
| logger.info('OneDrive copy accepted for async processing', { | ||
| fileId: params?.fileId, | ||
| monitorUrl, | ||
| }) | ||
|
|
||
| return { | ||
| success: true, | ||
| output: { | ||
| sourceFileId: params?.fileId || '', | ||
| name: params?.destinationFileName, | ||
| monitorUrl, | ||
| }, | ||
| } | ||
| }, | ||
|
|
||
| outputs: { | ||
| success: { type: 'boolean', description: 'Whether the copy request was accepted' }, | ||
| sourceFileId: { type: 'string', description: 'The ID of the file or folder that was copied' }, | ||
| name: { type: 'string', description: 'The requested name for the copy, if provided' }, | ||
| monitorUrl: { | ||
| type: 'string', | ||
| description: | ||
| 'URL to poll for the status of the asynchronous copy operation (copy completes in the background)', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| import type { OneDriveShareLinkResponse, OneDriveToolParams } from '@/tools/onedrive/types' | ||
| import type { ToolConfig } from '@/tools/types' | ||
|
|
||
| export const createShareLinkTool: ToolConfig<OneDriveToolParams, OneDriveShareLinkResponse> = { | ||
| id: 'onedrive_create_share_link', | ||
| name: 'Create OneDrive Sharing Link', | ||
| description: 'Create a view or edit sharing link for a OneDrive file or folder', | ||
| version: '1.0', | ||
|
|
||
| oauth: { | ||
| required: true, | ||
| provider: 'onedrive', | ||
| }, | ||
|
|
||
| params: { | ||
| accessToken: { | ||
| type: 'string', | ||
| required: true, | ||
| visibility: 'hidden', | ||
| description: 'The access token for the OneDrive API', | ||
| }, | ||
| fileId: { | ||
| type: 'string', | ||
| required: true, | ||
| visibility: 'user-or-llm', | ||
| description: 'The ID of the file or folder to share', | ||
| }, | ||
| linkType: { | ||
| type: 'string', | ||
| required: false, | ||
| visibility: 'user-or-llm', | ||
| description: 'Type of link to create: "view" (read-only), "edit" (read-write), or "embed"', | ||
| }, | ||
| linkScope: { | ||
| type: 'string', | ||
| required: false, | ||
| visibility: 'user-or-llm', | ||
| description: | ||
| 'Who can use the link: "anonymous" (anyone), "organization" (tenant members), or "users" (specific people)', | ||
| }, | ||
| }, | ||
|
|
||
| request: { | ||
| url: (params) => | ||
| `https://graph.microsoft.com/v1.0/me/drive/items/${encodeURIComponent(params.fileId || '')}/createLink`, | ||
| method: 'POST', | ||
| headers: (params) => ({ | ||
| Authorization: `Bearer ${params.accessToken}`, | ||
| 'Content-Type': 'application/json', | ||
| }), | ||
| body: (params) => ({ | ||
| type: params.linkType || 'view', | ||
| ...(params.linkScope && { scope: params.linkScope }), | ||
| }), | ||
| }, | ||
|
|
||
| transformResponse: async (response: Response) => { | ||
| const data = await response.json() | ||
|
|
||
| return { | ||
| success: true, | ||
| output: { | ||
| link: { | ||
| type: data.link?.type, | ||
| scope: data.link?.scope, | ||
| webUrl: data.link?.webUrl, | ||
| webHtml: data.link?.webHtml, | ||
| }, | ||
| }, | ||
| } | ||
| }, | ||
|
|
||
| outputs: { | ||
| success: { type: 'boolean', description: 'Whether the sharing link was created successfully' }, | ||
| link: { | ||
| type: 'object', | ||
| description: 'The created sharing link, including its type, scope, and URL', | ||
| }, | ||
| }, | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import type { OneDriveGetDriveInfoResponse, OneDriveToolParams } from '@/tools/onedrive/types' | ||
| import type { ToolConfig } from '@/tools/types' | ||
|
|
||
| export const getDriveInfoTool: ToolConfig<OneDriveToolParams, OneDriveGetDriveInfoResponse> = { | ||
| id: 'onedrive_get_drive_info', | ||
| name: 'Get OneDrive Info', | ||
| description: 'Get information about the OneDrive drive, including storage quota', | ||
| version: '1.0', | ||
|
|
||
| oauth: { | ||
| required: true, | ||
| provider: 'onedrive', | ||
| }, | ||
|
|
||
| params: { | ||
| accessToken: { | ||
| type: 'string', | ||
| required: true, | ||
| visibility: 'hidden', | ||
| description: 'The access token for the OneDrive API', | ||
| }, | ||
| }, | ||
|
|
||
| request: { | ||
| url: () => 'https://graph.microsoft.com/v1.0/me/drive', | ||
| method: 'GET', | ||
| headers: (params) => ({ | ||
| Authorization: `Bearer ${params.accessToken}`, | ||
| }), | ||
| }, | ||
|
|
||
| transformResponse: async (response: Response) => { | ||
| const data = await response.json() | ||
|
|
||
| return { | ||
| success: true, | ||
| output: { | ||
| driveId: data.id, | ||
| driveType: data.driveType, | ||
| webUrl: data.webUrl, | ||
| owner: data.owner?.user?.displayName ?? null, | ||
| quota: { | ||
| total: data.quota?.total ?? 0, | ||
| used: data.quota?.used ?? 0, | ||
| remaining: data.quota?.remaining ?? 0, | ||
| deleted: data.quota?.deleted ?? 0, | ||
| state: data.quota?.state ?? 'normal', | ||
| }, | ||
| }, | ||
| } | ||
| }, | ||
|
|
||
| outputs: { | ||
| success: { type: 'boolean', description: 'Whether the drive info was retrieved' }, | ||
| driveId: { type: 'string', description: 'The ID of the drive' }, | ||
| driveType: { type: 'string', description: 'The type of drive (e.g., "personal", "business")' }, | ||
| webUrl: { type: 'string', description: 'URL to the drive in the browser' }, | ||
| owner: { type: 'string', description: 'Display name of the drive owner', optional: true }, | ||
| quota: { | ||
| type: 'object', | ||
| description: 'Storage quota information in bytes (total, used, remaining, deleted, state)', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| import type { | ||
| MicrosoftGraphDriveItem, | ||
| OneDriveGetItemResponse, | ||
| OneDriveToolParams, | ||
| } from '@/tools/onedrive/types' | ||
| import type { ToolConfig } from '@/tools/types' | ||
|
|
||
| export const getItemTool: ToolConfig<OneDriveToolParams, OneDriveGetItemResponse> = { | ||
| id: 'onedrive_get_item', | ||
| name: 'Get OneDrive Item Metadata', | ||
| description: 'Get metadata for a specific OneDrive file or folder by ID, or the drive root', | ||
| version: '1.0', | ||
|
|
||
| oauth: { | ||
| required: true, | ||
| provider: 'onedrive', | ||
| }, | ||
|
|
||
| params: { | ||
| accessToken: { | ||
| type: 'string', | ||
| required: true, | ||
| visibility: 'hidden', | ||
| description: 'The access token for the OneDrive API', | ||
| }, | ||
| fileId: { | ||
| type: 'string', | ||
| required: false, | ||
| visibility: 'user-or-llm', | ||
| description: | ||
| 'The ID of the file or folder to retrieve (e.g., "01BYE5RZ6QN3ZWBTUFOFD3GSPGOHDJD36M"). Leave empty to get the drive root folder', | ||
| }, | ||
| }, | ||
|
|
||
| request: { | ||
| url: (params) => { | ||
| const fileId = params.fileId?.trim() | ||
| const baseUrl = fileId | ||
| ? `https://graph.microsoft.com/v1.0/me/drive/items/${encodeURIComponent(fileId)}` | ||
| : 'https://graph.microsoft.com/v1.0/me/drive/root' | ||
|
|
||
| const url = new URL(baseUrl) | ||
| url.searchParams.append( | ||
| '$select', | ||
| 'id,name,file,folder,webUrl,size,createdDateTime,lastModifiedDateTime,parentReference,@microsoft.graph.downloadUrl' | ||
| ) | ||
| return url.toString() | ||
| }, | ||
| method: 'GET', | ||
| headers: (params) => ({ | ||
| Authorization: `Bearer ${params.accessToken}`, | ||
| }), | ||
| }, | ||
|
|
||
| transformResponse: async (response: Response) => { | ||
| const data: MicrosoftGraphDriveItem = await response.json() | ||
|
|
||
| return { | ||
| success: true, | ||
| output: { | ||
| file: { | ||
| id: data.id, | ||
| name: data.name, | ||
| mimeType: data.file?.mimeType || (data.folder ? 'application/folder' : 'unknown'), | ||
| webViewLink: data.webUrl, | ||
| webContentLink: data['@microsoft.graph.downloadUrl'], | ||
| size: data.size?.toString() || '0', | ||
| createdTime: data.createdDateTime, | ||
| modifiedTime: data.lastModifiedDateTime, | ||
| parents: data.parentReference ? [data.parentReference.id] : [], | ||
| }, | ||
| }, | ||
| } | ||
| }, | ||
|
|
||
| outputs: { | ||
| success: { type: 'boolean', description: 'Whether the item metadata was retrieved' }, | ||
| file: { | ||
| type: 'object', | ||
| description: | ||
| 'The file or folder metadata, including id, name, webViewLink, size, and timestamps', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,23 @@ | ||
| import { copyTool } from '@/tools/onedrive/copy' | ||
| import { createFolderTool } from '@/tools/onedrive/create_folder' | ||
| import { createShareLinkTool } from '@/tools/onedrive/create_share_link' | ||
| import { deleteTool } from '@/tools/onedrive/delete' | ||
| import { downloadTool } from '@/tools/onedrive/download' | ||
| import { getDriveInfoTool } from '@/tools/onedrive/get_drive_info' | ||
| import { getItemTool } from '@/tools/onedrive/get_item' | ||
| import { listTool } from '@/tools/onedrive/list' | ||
| import { moveTool } from '@/tools/onedrive/move' | ||
| import { searchTool } from '@/tools/onedrive/search' | ||
| import { uploadTool } from '@/tools/onedrive/upload' | ||
|
|
||
| export const onedriveCopyTool = copyTool | ||
| export const onedriveCreateFolderTool = createFolderTool | ||
| export const onedriveCreateShareLinkTool = createShareLinkTool | ||
| export const onedriveDeleteTool = deleteTool | ||
| export const onedriveDownloadTool = downloadTool | ||
| export const onedriveGetDriveInfoTool = getDriveInfoTool | ||
| export const onedriveGetItemTool = getItemTool | ||
| export const onedriveListTool = listTool | ||
| export const onedriveMoveTool = moveTool | ||
| export const onedriveSearchTool = searchTool | ||
| export const onedriveUploadTool = uploadTool |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.