Skip to content

Commit 3fadb68

Browse files
elai-shalevclaude
andauthored
feat(x2a): K8s jobs real implementation - framework + init (#2273)
* First draft: Real Job creation * job template is able to git pull * Working full init job including git * After rebase * init phase coomplete, skeleton for other phases * With fixes tests, yarn full * app-config reset * rbac * reverting aap and rbac to main * fix: correct Artifact[] type after rebase conflict resolution Changed Map<string, string[]> to Map<string, Artifact[]> in listJobsForProject and listJobsForModule methods. Updated artifact queries to select all fields and use mapRowToArtifact for proper type mapping. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * code dulication * prettier * after review --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent e16baff commit 3fadb68

14 files changed

Lines changed: 743 additions & 247 deletions

workspaces/x2a/app-config.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ permission:
120120
admin:
121121
users:
122122
- name: user:default/mareklibra
123+
- name: user:default/elai-shalev
123124

124125
# X2A Configuration
125126
x2a:
@@ -146,12 +147,12 @@ x2a:
146147
llm:
147148
# LLM_MODEL is required - defaults to anthropic.claude-v2 if not set
148149
LLM_MODEL: ${LLM_MODEL:-anthropic.claude-v2}
149-
# Example for AWS Bedrock with IAM credentials:
150-
AWS_REGION: ${AWS_REGION}
151-
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
152-
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
153150
# Example for AWS Bedrock with bearer token:
154-
# AWS_BEARER_TOKEN_BEDROCK: ${AWS_BEARER_TOKEN_BEDROCK}
151+
AWS_REGION: ${AWS_REGION}
152+
AWS_BEARER_TOKEN_BEDROCK: ${AWS_BEARER_TOKEN_BEDROCK}
153+
# Example for AWS Bedrock with IAM credentials:
154+
#AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
155+
#AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
155156
# Example for OpenAI:
156157
# OPENAI_API_KEY: ${OPENAI_API_KEY}
157158
# OPENAI_MODEL: ${OPENAI_MODEL}

workspaces/x2a/plugins/x2a-backend/config.d.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ export interface X2AConfig {
3636
};
3737
};
3838
};
39+
git?: {
40+
author?: {
41+
name: string;
42+
email: string;
43+
};
44+
};
3945
credentials: {
4046
llm: Record<string, string>;
4147
aap?: {
@@ -94,6 +100,53 @@ export interface Config {
94100
};
95101
};
96102
};
103+
/**
104+
* Git configuration for X2A migrations
105+
*/
106+
git?: {
107+
/**
108+
* Git commit author configuration for migration artifacts
109+
* @visibility backend
110+
*/
111+
author?: {
112+
/**
113+
* Git commit author name (e.g., "X2A Migration Bot")
114+
* Default: "X2A Migration Bot"
115+
* @visibility backend
116+
*/
117+
name?: string;
118+
/**
119+
* Git commit author email (e.g., "x2a-bot@redhat.com")
120+
* Default: "x2a-bot@redhat.com"
121+
* @visibility backend
122+
*/
123+
email?: string;
124+
};
125+
/**
126+
* Source repository configuration
127+
* @visibility backend
128+
*/
129+
sourceRepo?: {
130+
/**
131+
* Fallback token for source repository authentication.
132+
* Used when the UI doesn't provide a token in the /run request.
133+
* @visibility secret
134+
*/
135+
token?: string;
136+
};
137+
/**
138+
* Target repository configuration
139+
* @visibility backend
140+
*/
141+
targetRepo?: {
142+
/**
143+
* Fallback token for target repository authentication.
144+
* Used when the UI doesn't provide a token in the /run request.
145+
* @visibility secret
146+
*/
147+
token?: string;
148+
};
149+
};
97150
/**
98151
* Credentials configuration for X2A
99152
*/

workspaces/x2a/plugins/x2a-backend/src/plugin.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ const getX2aDatabaseServiceMock = (): typeof x2aDatabaseServiceRef.T => ({
118118
updateJob: jest.fn().mockRejectedValue(new NotAllowedError('mock error')),
119119
getJobWithLog: jest.fn().mockRejectedValue(new NotAllowedError('mock error')),
120120
getJobLogs: jest.fn().mockRejectedValue(new NotAllowedError('mock error')),
121+
listJobsForProject: jest
122+
.fn()
123+
.mockRejectedValue(new NotAllowedError('mock error')),
124+
listJobsForModule: jest
125+
.fn()
126+
.mockRejectedValue(new NotAllowedError('mock error')),
121127
});
122128

123129
const getKubeServiceMock = () =>

workspaces/x2a/plugins/x2a-backend/src/plugin.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const x2APlugin = createBackendPlugin({
3838
logger: coreServices.logger,
3939
discoveryApi: coreServices.discovery,
4040
permissionsSvc: coreServices.permissions,
41+
config: coreServices.rootConfig,
4142
x2aDatabase: x2aDatabaseServiceRef,
4243
kubeService: kubeServiceRef,
4344
},
@@ -50,6 +51,7 @@ export const x2APlugin = createBackendPlugin({
5051
httpAuth,
5152
database,
5253
kubeService,
54+
config,
5355
}) {
5456
await migrate(database);
5557

@@ -61,6 +63,7 @@ export const x2APlugin = createBackendPlugin({
6163
permissionsSvc,
6264
x2aDatabase,
6365
kubeService,
66+
config,
6467
}),
6568
);
6669
},

workspaces/x2a/plugins/x2a-backend/src/router.test.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ const mockProject2: ProjectsPostRequest = {
5050
name: 'Another Project',
5151
description: 'Another Description',
5252
abbreviation: 'AP',
53-
sourceRepoUrl: 'https://github.com/source/repo',
54-
targetRepoUrl: 'https://github.com/target/repo',
53+
sourceRepoUrl: 'https://github.com/source/repo2',
54+
targetRepoUrl: 'https://github.com/target/repo2',
5555
sourceRepoBranch: 'main',
5656
targetRepoBranch: 'main',
5757
};
@@ -162,6 +162,25 @@ async function createApp(
162162
getBaseUrl: jest.fn().mockResolvedValue('http://localhost:7007/api/x2a'),
163163
getExternalBaseUrl: jest.fn().mockResolvedValue('http://localhost:7007'),
164164
},
165+
config: mockServices.rootConfig({
166+
data: {
167+
x2a: {
168+
kubernetes: {
169+
namespace: 'test-namespace',
170+
image: 'test-image',
171+
imageTag: 'test',
172+
ttlSecondsAfterFinished: 86400,
173+
resources: {
174+
requests: { cpu: '100m', memory: '128Mi' },
175+
limits: { cpu: '200m', memory: '256Mi' },
176+
},
177+
},
178+
credentials: {
179+
llm: { LLM_MODEL: 'test-model' },
180+
},
181+
},
182+
},
183+
}),
165184
x2aDatabase,
166185
kubeService: {
167186
createProjectSecret: jest.fn().mockResolvedValue(undefined),

0 commit comments

Comments
 (0)