Skip to content

Commit

Permalink
[ResposeOps] Gemini connector, remove bad variable reference (elastic…
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic authored Oct 8, 2024
1 parent 80a5565 commit 32a478c
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 62 deletions.
2 changes: 1 addition & 1 deletion docs/settings/alert-action-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ For an <<bedrock-action-type,{bedrock} connector>>, specifies the AWS access key
`xpack.actions.preconfigured.<connector-id>.secrets.apikey`::
An API key secret that varies by connector:

`xpack.actions.preconfigured.<connector-id>.secrets.credentialsJSON`::
`xpack.actions.preconfigured.<connector-id>.secrets.credentialsJson`::
For an <<gemini-action-type,{gemini} connector>>, specifies the GCP service account credentials JSON file for authentication.
+
--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ title: Connector secrets properties for a Google Gemini connector
description: Defines secrets for connectors when type is `.gemini`.
type: object
required:
- credentialsJSON
- credentialsJson
properties:
credentialsJSON:
credentialsJson:
type: string
description: The service account credentials JSON file. The service account should have Vertex AI user IAM role assigned to it.
description: The service account credentials JSON file. The service account should have Vertex AI user IAM role assigned to it.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const geminiConnector = {
gcpProjectID: 'test-project',
},
secrets: {
credentialsJSON: JSON.stringify({
credentialsJson: JSON.stringify({
type: 'service_account',
project_id: '',
private_key_id: '',
Expand Down Expand Up @@ -83,6 +83,10 @@ describe('GeminiConnectorFields renders', () => {
);
expect(getAllByTestId('gemini-api-doc')[0]).toBeInTheDocument();
expect(getAllByTestId('gemini-api-model-doc')[0]).toBeInTheDocument();

expect(getAllByTestId('secrets.credentialsJson-input')[0]).toHaveValue(
geminiConnector.secrets.credentialsJson
);
});

describe('Dashboard link', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import GeminiParamsFields from './params';
import { DEFAULT_GEMINI_URL, SUB_ACTION } from '../../../common/gemini/constants';
import { SUB_ACTION } from '../../../common/gemini/constants';
import { I18nProvider } from '@kbn/i18n-react';

const messageVariables = [
Expand Down Expand Up @@ -48,37 +48,9 @@ describe('Gemini Params Fields renders', () => {
};
const editAction = jest.fn();
const errors = {};
const actionConnector = {
secrets: {
credentialsJSON: JSON.stringify({
type: 'service_account',
project_id: '',
private_key_id: '',
private_key: '-----BEGIN PRIVATE KEY----------END PRIVATE KEY-----\n',
client_email: '',
client_id: '',
auth_uri: 'https://accounts.google.com/o/oauth2/auth',
token_uri: 'https://oauth2.googleapis.com/token',
auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
client_x509_cert_url: '',
}),
},
id: 'test',
actionTypeId: '.gemini',
isPreconfigured: false,
isSystemAction: false as const,
isDeprecated: false,
name: 'My Gemini Connector',
config: {
apiUrl: DEFAULT_GEMINI_URL,
gcpRegion: 'us-central-1',
gcpProjectID: 'test-project',
},
};
render(
<GeminiParamsFields
actionParams={actionParams}
actionConnector={actionConnector}
editAction={editAction}
index={0}
messageVariables={messageVariables}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const SECRET = i18n.translate('xpack.stackConnectors.components.gemini.se
});

export const CREDENTIALS_JSON = i18n.translate(
'xpack.stackConnectors.components.gemini.credentialsJSON',
'xpack.stackConnectors.components.gemini.credentialsJson',
{
defaultMessage: 'Credentials JSON',
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,16 @@ export class GeminiConnector extends SubActionConnector<Config, Secrets> {
/** Retrieve access token based on the GCP service account credential json file */
private async getAccessToken(): Promise<string | null> {
// Validate the service account credentials JSON file input
let credentialsJSON;
let credentialsJson;
try {
credentialsJSON = JSON.parse(this.secrets.credentialsJson);
credentialsJson = JSON.parse(this.secrets.credentialsJson);
} catch (error) {
throw new Error(`Failed to parse credentials JSON file: Invalid JSON format`);
}
const accessToken = await getGoogleOAuthJwtAccessToken({
connectorId: this.connector.id,
logger: this.logger,
credentials: credentialsJSON,
credentials: credentialsJson,
connectorTokenClient: this.connectorTokenClient,
});
return accessToken;
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -43196,7 +43196,7 @@
"xpack.stackConnectors.components.gemini.bodyCodeEditorAriaLabel": "Éditeur de code",
"xpack.stackConnectors.components.gemini.bodyFieldLabel": "Corps",
"xpack.stackConnectors.components.gemini.connectorTypeTitle": "Google Gemini",
"xpack.stackConnectors.components.gemini.credentialsJSON": "Informations d'identification JSON",
"xpack.stackConnectors.components.gemini.credentialsJson": "Informations d'identification JSON",
"xpack.stackConnectors.components.gemini.dashboardLink": "Affichez le tableau de bord d'utilisation de {apiProvider} pour le connecteur \"{ connectorName }\"",
"xpack.stackConnectors.components.gemini.defaultModelTextFieldLabel": "Modèle par défaut",
"xpack.stackConnectors.components.gemini.documentation": "documentation",
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -42935,7 +42935,7 @@
"xpack.stackConnectors.components.gemini.bodyCodeEditorAriaLabel": "コードエディター",
"xpack.stackConnectors.components.gemini.bodyFieldLabel": "本文",
"xpack.stackConnectors.components.gemini.connectorTypeTitle": "Google Gemini",
"xpack.stackConnectors.components.gemini.credentialsJSON": "資格情報JSON",
"xpack.stackConnectors.components.gemini.credentialsJson": "資格情報JSON",
"xpack.stackConnectors.components.gemini.dashboardLink": "\"{ connectorName }\"コネクターの{apiProvider}使用状況ダッシュボードを表示",
"xpack.stackConnectors.components.gemini.defaultModelTextFieldLabel": "デフォルトモデル",
"xpack.stackConnectors.components.gemini.documentation": "ドキュメンテーション",
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -42986,7 +42986,7 @@
"xpack.stackConnectors.components.gemini.bodyCodeEditorAriaLabel": "代码编辑器",
"xpack.stackConnectors.components.gemini.bodyFieldLabel": "正文",
"xpack.stackConnectors.components.gemini.connectorTypeTitle": "Google Gemini",
"xpack.stackConnectors.components.gemini.credentialsJSON": "凭据 JSON",
"xpack.stackConnectors.components.gemini.credentialsJson": "凭据 JSON",
"xpack.stackConnectors.components.gemini.dashboardLink": "查看“{ connectorName }”连接器的 {apiProvider} 使用情况仪表板",
"xpack.stackConnectors.components.gemini.defaultModelTextFieldLabel": "默认模型",
"xpack.stackConnectors.components.gemini.documentation": "文档",
Expand Down
1 change: 1 addition & 0 deletions x-pack/test/alerting_api_integration/common/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const enabledActionTypes = [
'.bedrock',
'.cases-webhook',
'.email',
'.gemini',
'.index',
'.opsgenie',
'.pagerduty',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
geminiSuccessResponse,
} from '@kbn/actions-simulators-plugin/server/gemini_simulation';
import { TaskErrorSource } from '@kbn/task-manager-plugin/common';
import { DEFAULT_GEMINI_MODEL } from '@kbn/stack-connectors-plugin/common/gemini/constants';
import { FtrProviderContext } from '../../../../../common/ftr_provider_context';

const connectorTypeId = '.gemini';
Expand All @@ -20,7 +21,7 @@ const defaultConfig = {
gcpProjectID: 'test-project',
};
const secrets = {
credentialsJSON: JSON.stringify({
credentialsJson: JSON.stringify({
type: 'service_account',
project_id: '',
private_key_id: '',
Expand All @@ -39,14 +40,14 @@ export default function geminiTest({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const configService = getService('config');

const createConnector = async (url: string) => {
const createConnector = async (apiUrl: string) => {
const { body } = await supertest
.post('/api/actions/connector')
.set('kbn-xsrf', 'foo')
.send({
name,
connector_type_id: connectorTypeId,
config: { ...defaultConfig, url },
config: { ...defaultConfig, apiUrl },
secrets,
})
.expect(200);
Expand All @@ -62,10 +63,10 @@ export default function geminiTest({ getService }: FtrProviderContext) {
config: configService.get('kbnTestServer.serverArgs'),
},
});
const config = { ...defaultConfig, url: '' };
const config = { ...defaultConfig, apiUrl: '' };

before(async () => {
config.url = await simulator.start();
config.apiUrl = await simulator.start();
});

after(() => {
Expand All @@ -92,7 +93,10 @@ export default function geminiTest({ getService }: FtrProviderContext) {
name,
connector_type_id: connectorTypeId,
is_missing_secrets: false,
config,
config: {
...config,
defaultModel: DEFAULT_GEMINI_MODEL,
},
});
});

Expand All @@ -112,20 +116,20 @@ export default function geminiTest({ getService }: FtrProviderContext) {
statusCode: 400,
error: 'Bad Request',
message:
'error validating action type config: [url, gcpRegion, gcpProjectID]: expected value of type [string] but got [undefined]',
'error validating action type config: [apiUrl]: expected value of type [string] but got [undefined]',
});
});
});

it('should return 400 Bad Request when creating the connector without the project id', async () => {
const testConfig = { gcpRegion: 'us-central-1', url: '' };
const testConfig = { gcpRegion: 'us-central-1', apiUrl: 'https://url.co' };
await supertest
.post('/api/actions/connector')
.set('kbn-xsrf', 'foo')
.send({
name,
connector_type_id: connectorTypeId,
testConfig,
config: testConfig,
secrets,
})
.expect(400)
Expand All @@ -140,14 +144,14 @@ export default function geminiTest({ getService }: FtrProviderContext) {
});

it('should return 400 Bad Request when creating the connector without the region', async () => {
const testConfig = { gcpProjectID: 'test-project', url: '' };
const testConfig = { gcpProjectID: 'test-project', apiUrl: 'https://url.co' };
await supertest
.post('/api/actions/connector')
.set('kbn-xsrf', 'foo')
.send({
name,
connector_type_id: connectorTypeId,
testConfig,
config: testConfig,
secrets,
})
.expect(400)
Expand All @@ -169,7 +173,8 @@ export default function geminiTest({ getService }: FtrProviderContext) {
name,
connector_type_id: connectorTypeId,
config: {
url: 'http://gemini.mynonexistent.com',
...defaultConfig,
apiUrl: 'http://gemini.mynonexistent.com',
},
secrets,
})
Expand All @@ -179,7 +184,7 @@ export default function geminiTest({ getService }: FtrProviderContext) {
statusCode: 400,
error: 'Bad Request',
message:
'error validating action type config: error validating url: target url "http://gemini.mynonexistent.com" is not added to the Kibana config xpack.actions.allowedHosts',
'error validating action type config: Error configuring Google Gemini action: Error: error validating url: target url "http://gemini.mynonexistent.com" is not added to the Kibana config xpack.actions.allowedHosts',
});
});
});
Expand All @@ -199,7 +204,7 @@ export default function geminiTest({ getService }: FtrProviderContext) {
statusCode: 400,
error: 'Bad Request',
message:
'error validating action type secrets: [token]: expected value of type [string] but got [undefined]',
'error validating action type secrets: [credentialsJson]: expected value of type [string] but got [undefined]',
});
});
});
Expand Down Expand Up @@ -257,7 +262,7 @@ export default function geminiTest({ getService }: FtrProviderContext) {
retry: true,
message: 'an error occurred while running the action',
errorSource: TaskErrorSource.FRAMEWORK,
service_message: `Sub action "invalidAction" is not registered. Connector id: ${geminiActionId}. Connector name: Gemini. Connector type: .gemini`,
service_message: `Sub action "invalidAction" is not registered. Connector id: ${geminiActionId}. Connector name: Google Gemini. Connector type: .gemini`,
});
});
});
Expand All @@ -269,27 +274,29 @@ export default function geminiTest({ getService }: FtrProviderContext) {
config: configService.get('kbnTestServer.serverArgs'),
},
});
let url: string;
let apiUrl: string;
let geminiActionId: string;

before(async () => {
url = await simulator.start();
geminiActionId = await createConnector(url);
apiUrl = await simulator.start();
geminiActionId = await createConnector(apiUrl);
});

after(() => {
simulator.close();
});

it('should invoke AI with assistant AI body argument formatted to gemini expectations', async () => {
// TODO to fix, we need to figure out how to mock the gcp oauth token
// https://github.com/elastic/kibana/issues/195437
it.skip('should invoke AI with assistant AI body argument formatted to gemini expectations', async () => {
const { body } = await supertest
.post(`/api/actions/connector/${geminiActionId}/_execute`)
.set('kbn-xsrf', 'foo')
.send({
params: {
subAction: 'invokeAI',
subActionParams: {
contents: [
messages: [
{
role: 'user',
parts: [
Expand All @@ -315,7 +322,6 @@ export default function geminiTest({ getService }: FtrProviderContext) {
],
},
],
generation_config: { temperature: 0, maxOutputTokens: 8192 },
},
},
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export default function connectorsTests({ loadTestFile, getService }: FtrProvide
loadTestFile(require.resolve('./connector_types/d3security'));
loadTestFile(require.resolve('./connector_types/thehive'));
loadTestFile(require.resolve('./connector_types/bedrock'));
loadTestFile(require.resolve('./connector_types/gemini'));
loadTestFile(require.resolve('./create'));
loadTestFile(require.resolve('./delete'));
loadTestFile(require.resolve('./execute'));
Expand Down

0 comments on commit 32a478c

Please sign in to comment.