-
Notifications
You must be signed in to change notification settings - Fork 862
[New Plugin] Trend AI Guard #1453
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| import { | ||
| HookEventType, | ||
| PluginContext, | ||
| PluginHandler, | ||
| PluginParameters, | ||
| } from '../types'; | ||
| import { post, getText, HttpError } from '../utils'; | ||
| import { VERSION } from './version'; | ||
|
|
||
| export const handler: PluginHandler = async ( | ||
| context: PluginContext, | ||
| parameters: PluginParameters, | ||
| eventType: HookEventType, | ||
| options?: { | ||
| env: Record<string, any>; | ||
| getFromCacheByKey?: (key: string) => Promise<any>; | ||
| putInCacheWithValue?: (key: string, value: any) => Promise<any>; | ||
| } | ||
| ) => { | ||
| let error = null; | ||
| let verdict = true; | ||
| let data = null; | ||
|
|
||
| // Validate required parameters | ||
| if (!parameters.credentials?.v1Url) { | ||
| return { | ||
| error: { message: `'parameters.credentials.v1Url' must be set` }, | ||
| verdict: true, | ||
| data, | ||
| }; | ||
| } | ||
|
|
||
| if (!parameters.credentials?.apiKey) { | ||
| return { | ||
| error: { message: `'parameters.credentials.apiKey' must be set` }, | ||
| verdict: true, | ||
| data, | ||
| }; | ||
| } | ||
|
|
||
| // Extract text from context | ||
| const text = getText(context, eventType); | ||
| if (!text) { | ||
| return { | ||
| error: { message: 'request or response text is empty' }, | ||
| verdict: true, | ||
| data, | ||
| }; | ||
| } | ||
| const applicationName = parameters.applicationName; | ||
|
|
||
| // Validate application name is provided and has correct format | ||
| if (!applicationName) { | ||
| return { | ||
| error: { message: 'Application name is required' }, | ||
| verdict: true, | ||
| data, | ||
| }; | ||
| } | ||
|
|
||
| if (!/^[a-zA-Z0-9_-]+$/.test(applicationName)) { | ||
| return { | ||
| error: { | ||
| message: | ||
| 'Application name must contain only letters, numbers, hyphens, and underscores', | ||
| }, | ||
| verdict: true, | ||
| data, | ||
| }; | ||
| } | ||
|
|
||
| // Prepare request headers | ||
| const headers: Record<string, string> = { | ||
| 'Content-Type': 'application/json', | ||
| Accept: 'application/json', | ||
| Authorization: `Bearer ${parameters.credentials?.apiKey}`, | ||
| 'TMV1-Application-Name': applicationName, | ||
| }; | ||
|
|
||
| // Set Prefer header | ||
| const preferValue = parameters.prefer || 'return=minimal'; | ||
| headers['Prefer'] = preferValue; | ||
|
|
||
| const requestOptions = { headers }; | ||
|
|
||
| // Prepare request payload for applyGuardrails endpoint | ||
| const request = { | ||
| prompt: text, | ||
| }; | ||
|
|
||
| let response; | ||
| try { | ||
| response = await post( | ||
| parameters.credentials?.v1Url, | ||
| request, | ||
| requestOptions, | ||
| parameters.timeout | ||
| ); | ||
| } catch (e) { | ||
| if (e instanceof HttpError) { | ||
| error = { | ||
| message: `API request failed: ${e.message}. body: ${e.response.body}`, | ||
| }; | ||
| } else { | ||
| error = e as Error; | ||
| } | ||
| } | ||
|
|
||
| if (response) { | ||
| data = response; | ||
|
|
||
| if (response.action && response.action === 'Block') { | ||
| verdict = false; | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| error, | ||
| verdict, | ||
| data, | ||
| }; | ||
| }; |
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,50 @@ | ||||||||||||||
| { | ||||||||||||||
| "id": "trend-ai", | ||||||||||||||
| "description": "Trend AI Guard for scanning LLM inputs and outputs", | ||||||||||||||
| "credentials": { | ||||||||||||||
| "type": "object", | ||||||||||||||
| "properties": { | ||||||||||||||
| "v1ApiKey": { | ||||||||||||||
| "type": "string", | ||||||||||||||
| "label": "Trend AI Token", | ||||||||||||||
| "description": "Trend AI Guard token Get setup here (https://docs.trendmicro.com/en-us/documentation/article/trend-vision-one-ai-scanner-ai-guard)", | ||||||||||||||
| "encrypted": true | ||||||||||||||
| }, | ||||||||||||||
| "v1Url": { | ||||||||||||||
| "type": "string", | ||||||||||||||
| "label": "Trend AI URL", | ||||||||||||||
| "description": "Trend AI Guard URL (e.g., https://api.xdr.trendmicro.com/v3.0/aiSecurity/applyGuardrails)" | ||||||||||||||
| } | ||||||||||||||
| }, | ||||||||||||||
| "required": ["v1Url", "apiKey"] | ||||||||||||||
|
||||||||||||||
| "required": ["v1Url", "apiKey"] | |
| "required": ["v1Url", "v1ApiKey"] |
Copilot
AI
Dec 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'required' array is incorrectly nested inside the 'parameters' object. It should be placed at the same level as 'parameters', not inside it, to properly indicate which parameters are required for the function.
| }, | |
| "required": ["applicationName"] | |
| } | |
| } | |
| }, | |
| "required": ["applicationName"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function name 'guard' doesn't match the function ID 'aiGuard' defined in the manifest. For consistency, these should match.