buildhive-agent 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +166 -0
  2. package/dist/__tests__/fakes/FakeDockerManager.d.ts +115 -0
  3. package/dist/__tests__/fakes/FakeDockerManager.d.ts.map +1 -0
  4. package/dist/__tests__/fakes/FakeDockerManager.js +203 -0
  5. package/dist/__tests__/fakes/FakeDockerManager.js.map +1 -0
  6. package/dist/acceptanceChecker.d.ts +26 -0
  7. package/dist/acceptanceChecker.d.ts.map +1 -0
  8. package/dist/acceptanceChecker.js +64 -0
  9. package/dist/acceptanceChecker.js.map +1 -0
  10. package/dist/advancedAgent.d.ts +161 -0
  11. package/dist/advancedAgent.d.ts.map +1 -0
  12. package/dist/advancedAgent.js +604 -0
  13. package/dist/advancedAgent.js.map +1 -0
  14. package/dist/agent.d.ts +101 -0
  15. package/dist/agent.d.ts.map +1 -0
  16. package/dist/agent.js +490 -0
  17. package/dist/agent.js.map +1 -0
  18. package/dist/api/jobStatusApi.d.ts +88 -0
  19. package/dist/api/jobStatusApi.d.ts.map +1 -0
  20. package/dist/api/jobStatusApi.js +240 -0
  21. package/dist/api/jobStatusApi.js.map +1 -0
  22. package/dist/autoUpdater.d.ts +135 -0
  23. package/dist/autoUpdater.d.ts.map +1 -0
  24. package/dist/autoUpdater.js +494 -0
  25. package/dist/autoUpdater.js.map +1 -0
  26. package/dist/cacheManager.d.ts +108 -0
  27. package/dist/cacheManager.d.ts.map +1 -0
  28. package/dist/cacheManager.js +300 -0
  29. package/dist/cacheManager.js.map +1 -0
  30. package/dist/cli.d.ts +11 -0
  31. package/dist/cli.d.ts.map +1 -0
  32. package/dist/cli.js +749 -0
  33. package/dist/cli.js.map +1 -0
  34. package/dist/config/index.d.ts +30 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/config/index.js +35 -0
  37. package/dist/config/index.js.map +1 -0
  38. package/dist/config/loader.d.ts +45 -0
  39. package/dist/config/loader.d.ts.map +1 -0
  40. package/dist/config/loader.js +269 -0
  41. package/dist/config/loader.js.map +1 -0
  42. package/dist/config/types.d.ts +193 -0
  43. package/dist/config/types.d.ts.map +1 -0
  44. package/dist/config/types.js +90 -0
  45. package/dist/config/types.js.map +1 -0
  46. package/dist/config/validation.d.ts +28 -0
  47. package/dist/config/validation.d.ts.map +1 -0
  48. package/dist/config/validation.js +397 -0
  49. package/dist/config/validation.js.map +1 -0
  50. package/dist/docker.d.ts +96 -0
  51. package/dist/docker.d.ts.map +1 -0
  52. package/dist/docker.js +411 -0
  53. package/dist/docker.js.map +1 -0
  54. package/dist/enhancedJobExecutor.d.ts +81 -0
  55. package/dist/enhancedJobExecutor.d.ts.map +1 -0
  56. package/dist/enhancedJobExecutor.js +223 -0
  57. package/dist/enhancedJobExecutor.js.map +1 -0
  58. package/dist/executors/executorFactory.d.ts +46 -0
  59. package/dist/executors/executorFactory.d.ts.map +1 -0
  60. package/dist/executors/executorFactory.js +80 -0
  61. package/dist/executors/executorFactory.js.map +1 -0
  62. package/dist/executors/index.d.ts +7 -0
  63. package/dist/executors/index.d.ts.map +1 -0
  64. package/dist/executors/index.js +6 -0
  65. package/dist/executors/index.js.map +1 -0
  66. package/dist/executors/nativeExecutor.d.ts +60 -0
  67. package/dist/executors/nativeExecutor.d.ts.map +1 -0
  68. package/dist/executors/nativeExecutor.js +311 -0
  69. package/dist/executors/nativeExecutor.js.map +1 -0
  70. package/dist/executors/types.d.ts +38 -0
  71. package/dist/executors/types.d.ts.map +1 -0
  72. package/dist/executors/types.js +9 -0
  73. package/dist/executors/types.js.map +1 -0
  74. package/dist/healthMonitor.d.ts +213 -0
  75. package/dist/healthMonitor.d.ts.map +1 -0
  76. package/dist/healthMonitor.js +547 -0
  77. package/dist/healthMonitor.js.map +1 -0
  78. package/dist/index.d.ts +16 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +16 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/jobExecutor.d.ts +117 -0
  83. package/dist/jobExecutor.d.ts.map +1 -0
  84. package/dist/jobExecutor.js +458 -0
  85. package/dist/jobExecutor.js.map +1 -0
  86. package/dist/lifecycleExecutor.d.ts +54 -0
  87. package/dist/lifecycleExecutor.d.ts.map +1 -0
  88. package/dist/lifecycleExecutor.js +230 -0
  89. package/dist/lifecycleExecutor.js.map +1 -0
  90. package/dist/main.d.ts +15 -0
  91. package/dist/main.d.ts.map +1 -0
  92. package/dist/main.js +77 -0
  93. package/dist/main.js.map +1 -0
  94. package/dist/metrics.d.ts +103 -0
  95. package/dist/metrics.d.ts.map +1 -0
  96. package/dist/metrics.js +360 -0
  97. package/dist/metrics.js.map +1 -0
  98. package/dist/recipes/builtinRecipes.d.ts +11 -0
  99. package/dist/recipes/builtinRecipes.d.ts.map +1 -0
  100. package/dist/recipes/builtinRecipes.js +688 -0
  101. package/dist/recipes/builtinRecipes.js.map +1 -0
  102. package/dist/recipes/index.d.ts +18 -0
  103. package/dist/recipes/index.d.ts.map +1 -0
  104. package/dist/recipes/index.js +17 -0
  105. package/dist/recipes/index.js.map +1 -0
  106. package/dist/recipes/recipeRegistry.d.ts +49 -0
  107. package/dist/recipes/recipeRegistry.d.ts.map +1 -0
  108. package/dist/recipes/recipeRegistry.js +264 -0
  109. package/dist/recipes/recipeRegistry.js.map +1 -0
  110. package/dist/recipes/types.d.ts +116 -0
  111. package/dist/recipes/types.d.ts.map +1 -0
  112. package/dist/recipes/types.js +10 -0
  113. package/dist/recipes/types.js.map +1 -0
  114. package/dist/recovery.d.ts +133 -0
  115. package/dist/recovery.d.ts.map +1 -0
  116. package/dist/recovery.js +299 -0
  117. package/dist/recovery.js.map +1 -0
  118. package/dist/registration/apiClient.d.ts +44 -0
  119. package/dist/registration/apiClient.d.ts.map +1 -0
  120. package/dist/registration/apiClient.js +149 -0
  121. package/dist/registration/apiClient.js.map +1 -0
  122. package/dist/registration/index.d.ts +41 -0
  123. package/dist/registration/index.d.ts.map +1 -0
  124. package/dist/registration/index.js +141 -0
  125. package/dist/registration/index.js.map +1 -0
  126. package/dist/registration/machineId.d.ts +30 -0
  127. package/dist/registration/machineId.d.ts.map +1 -0
  128. package/dist/registration/machineId.js +89 -0
  129. package/dist/registration/machineId.js.map +1 -0
  130. package/dist/registration/types.d.ts +32 -0
  131. package/dist/registration/types.d.ts.map +1 -0
  132. package/dist/registration/types.js +9 -0
  133. package/dist/registration/types.js.map +1 -0
  134. package/dist/resourceGovernor.d.ts +57 -0
  135. package/dist/resourceGovernor.d.ts.map +1 -0
  136. package/dist/resourceGovernor.js +125 -0
  137. package/dist/resourceGovernor.js.map +1 -0
  138. package/dist/security/secretManager.d.ts +107 -0
  139. package/dist/security/secretManager.d.ts.map +1 -0
  140. package/dist/security/secretManager.js +361 -0
  141. package/dist/security/secretManager.js.map +1 -0
  142. package/dist/security.d.ts +134 -0
  143. package/dist/security.d.ts.map +1 -0
  144. package/dist/security.js +470 -0
  145. package/dist/security.js.map +1 -0
  146. package/dist/storage/artifactUploader.d.ts +155 -0
  147. package/dist/storage/artifactUploader.d.ts.map +1 -0
  148. package/dist/storage/artifactUploader.js +554 -0
  149. package/dist/storage/artifactUploader.js.map +1 -0
  150. package/dist/types.d.ts +49 -0
  151. package/dist/types.d.ts.map +1 -0
  152. package/dist/types.js +7 -0
  153. package/dist/types.js.map +1 -0
  154. package/dist/utils/capabilities.d.ts +23 -0
  155. package/dist/utils/capabilities.d.ts.map +1 -0
  156. package/dist/utils/capabilities.js +200 -0
  157. package/dist/utils/capabilities.js.map +1 -0
  158. package/dist/utils/logger.d.ts +20 -0
  159. package/dist/utils/logger.d.ts.map +1 -0
  160. package/dist/utils/logger.js +188 -0
  161. package/dist/utils/logger.js.map +1 -0
  162. package/dist/utils/sdkScanner.d.ts +105 -0
  163. package/dist/utils/sdkScanner.d.ts.map +1 -0
  164. package/dist/utils/sdkScanner.js +459 -0
  165. package/dist/utils/sdkScanner.js.map +1 -0
  166. package/dist/websocketClient.d.ts +154 -0
  167. package/dist/websocketClient.d.ts.map +1 -0
  168. package/dist/websocketClient.js +422 -0
  169. package/dist/websocketClient.js.map +1 -0
  170. package/package.json +64 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Job Executor - Docker-based job execution
3
+ *
4
+ * Handles the execution of CI jobs in isolated Docker containers
5
+ * with security, resource limits, and progress reporting.
6
+ *
7
+ * Requirements: 1.1, 1.2, 4.1, 4.2, 4.3, 4.4, 4.5
8
+ */
9
+ import { AgentConfig } from './config/types.js';
10
+ import { JobSubmissionRequest } from './types.js';
11
+ export interface JobExecutionResult {
12
+ success: boolean;
13
+ exitCode?: number;
14
+ logs?: string;
15
+ errorMessage?: string;
16
+ artifactUrls?: string[];
17
+ }
18
+ export interface JobProgress {
19
+ percentage: number;
20
+ currentStep: string;
21
+ totalSteps?: number;
22
+ currentStepIndex?: number;
23
+ estimatedTimeRemaining?: number;
24
+ }
25
+ export type ProgressCallback = (progress: JobProgress) => void;
26
+ export type LogsCallback = (logs: string) => void;
27
+ export declare class JobExecutor {
28
+ private config;
29
+ private dockerManager;
30
+ private artifactUploader;
31
+ private activeJobs;
32
+ private workspaceRoot;
33
+ constructor(config: AgentConfig);
34
+ /**
35
+ * Execute a job in a Docker container
36
+ */
37
+ executeJob(job: JobSubmissionRequest, progressCallback: ProgressCallback, logsCallback: LogsCallback): Promise<JobExecutionResult>;
38
+ /**
39
+ * Cancel a running job
40
+ */
41
+ cancelJob(jobId: string): Promise<void>;
42
+ /**
43
+ * Clean up resources
44
+ */
45
+ cleanup(): Promise<void>;
46
+ /**
47
+ * Clean up orphaned containers from previous agent crashes.
48
+ */
49
+ cleanupOrphanedContainers(): Promise<number>;
50
+ /**
51
+ * Validate job requirements against agent capabilities
52
+ */
53
+ private validateJobRequirements;
54
+ /**
55
+ * Create workspace directory for job
56
+ */
57
+ private createWorkspace;
58
+ /**
59
+ * Prepare workspace with job context
60
+ */
61
+ private prepareWorkspace;
62
+ /**
63
+ * Build an authenticated clone URL from a plain HTTPS repository URL.
64
+ *
65
+ * Converts https://github.com/user/repo (or https://github.com/user/repo.git)
66
+ * to https://x-access-token:{token}@github.com/user/repo using the
67
+ * x-access-token convention supported by GitHub App installation tokens,
68
+ * fine-grained PATs, and classic PATs.
69
+ *
70
+ * Only HTTPS URLs are rewritten. SSH URLs (git@github.com:...) are returned
71
+ * unchanged because they rely on key-based auth, not token-based.
72
+ *
73
+ * The token is never written to disk or emitted in log lines.
74
+ */
75
+ private buildAuthenticatedCloneUrl;
76
+ /**
77
+ * Execute a git command in the given working directory.
78
+ *
79
+ * @param args - Arguments to pass to the git binary
80
+ * @param cwd - Working directory for the git process
81
+ * @param env - Additional environment variables merged on top of process.env.
82
+ * Use this to pass GIT_ASKPASS, GIT_TERMINAL_PROMPT=0, etc.
83
+ * @param timeoutMs - Maximum time to wait before killing the process (default 5 min)
84
+ */
85
+ private executeGitCommand;
86
+ /**
87
+ * Collect build artifacts from container
88
+ *
89
+ * MVP.4.2.4: Artifacts are copied from container and uploaded to configured storage
90
+ */
91
+ private collectArtifacts;
92
+ /**
93
+ * Clean up job resources
94
+ */
95
+ private cleanupJob;
96
+ /**
97
+ * Clean up old artifacts based on retention policy (MVP.4.2.4)
98
+ *
99
+ * Should be called periodically by the agent to enforce retention policy.
100
+ *
101
+ * @returns Number of artifacts deleted
102
+ */
103
+ cleanupOldArtifacts(): Promise<number>;
104
+ /**
105
+ * Get artifact storage statistics (MVP.4.2.4)
106
+ *
107
+ * @returns Storage statistics
108
+ */
109
+ getArtifactStorageStats(): Promise<{
110
+ type: "local" | "s3";
111
+ totalFiles: number;
112
+ totalSizeBytes: number;
113
+ oldestFileDate?: Date;
114
+ newestFileDate?: Date;
115
+ }>;
116
+ }
117
+ //# sourceMappingURL=jobExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobExecutor.d.ts","sourceRoot":"","sources":["../src/jobExecutor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAQlD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAC;AAC/D,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAElD,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,UAAU,CAA+D;IACjF,OAAO,CAAC,aAAa,CAAS;gBAElB,MAAM,EAAE,WAAW;IAO/B;;OAEG;IACG,UAAU,CACd,GAAG,EAAE,oBAAoB,EACzB,gBAAgB,EAAE,gBAAgB,EAClC,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,kBAAkB,CAAC;IAwJ9B;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB7C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAa9B;;OAEG;IACG,yBAAyB,IAAI,OAAO,CAAC,MAAM,CAAC;IAIlD;;OAEG;YACW,uBAAuB;IA0BrC;;OAEG;YACW,eAAe;IAa7B;;OAEG;YACW,gBAAgB;IAoF9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;IAyCzB;;;;OAIG;YACW,gBAAgB;IAmD9B;;OAEG;YACW,UAAU;IAwBxB;;;;;;OAMG;IACG,mBAAmB,IAAI,OAAO,CAAC,MAAM,CAAC;IAa5C;;;;OAIG;IACG,uBAAuB;;;;;;;CAG9B"}
@@ -0,0 +1,458 @@
1
+ /**
2
+ * Job Executor - Docker-based job execution
3
+ *
4
+ * Handles the execution of CI jobs in isolated Docker containers
5
+ * with security, resource limits, and progress reporting.
6
+ *
7
+ * Requirements: 1.1, 1.2, 4.1, 4.2, 4.3, 4.4, 4.5
8
+ */
9
+ import { DockerManager } from './docker.js';
10
+ import { ArtifactUploader } from './storage/artifactUploader.js';
11
+ import { createLogger } from './utils/logger.js';
12
+ import { promises as fs } from 'fs';
13
+ import { join } from 'path';
14
+ import { spawn } from 'child_process';
15
+ const logger = createLogger('jobExecutor');
16
+ export class JobExecutor {
17
+ config;
18
+ dockerManager;
19
+ artifactUploader;
20
+ activeJobs = new Map();
21
+ workspaceRoot;
22
+ constructor(config) {
23
+ this.config = config;
24
+ this.dockerManager = new DockerManager(config.dockerConfig, config.securityConfig);
25
+ this.artifactUploader = new ArtifactUploader(config.storageConfig);
26
+ this.workspaceRoot = join(process.cwd(), 'workspaces');
27
+ }
28
+ /**
29
+ * Execute a job in a Docker container
30
+ */
31
+ async executeJob(job, progressCallback, logsCallback) {
32
+ const jobId = job.externalId;
33
+ const workDir = await this.createWorkspace(jobId);
34
+ logger.info(`Executing job ${jobId} in workspace: ${workDir}`);
35
+ try {
36
+ // Step 1: Validate job requirements
37
+ progressCallback({
38
+ percentage: 5,
39
+ currentStep: 'Validating job requirements',
40
+ totalSteps: 8,
41
+ currentStepIndex: 1
42
+ });
43
+ await this.validateJobRequirements(job);
44
+ logsCallback(`[INFO] Job requirements validated for ${jobId}`);
45
+ // Step 2: Prepare workspace
46
+ progressCallback({
47
+ percentage: 15,
48
+ currentStep: 'Preparing workspace',
49
+ totalSteps: 8,
50
+ currentStepIndex: 2
51
+ });
52
+ await this.prepareWorkspace(workDir, job);
53
+ logsCallback(`[INFO] Workspace prepared at ${workDir}`);
54
+ // Step 3: Pull Docker image
55
+ progressCallback({
56
+ percentage: 25,
57
+ currentStep: 'Pulling Docker image',
58
+ totalSteps: 8,
59
+ currentStepIndex: 3
60
+ });
61
+ await this.dockerManager.pullImage(job.dockerImage);
62
+ logsCallback(`[INFO] Docker image pulled: ${job.dockerImage}`);
63
+ // Step 4: Create container
64
+ progressCallback({
65
+ percentage: 35,
66
+ currentStep: 'Creating container',
67
+ totalSteps: 8,
68
+ currentStepIndex: 4
69
+ });
70
+ const containerId = await this.dockerManager.createContainer({
71
+ image: job.dockerImage,
72
+ workDir: '/workspace',
73
+ environment: job.environment || {},
74
+ volumeMounts: [
75
+ {
76
+ hostPath: workDir,
77
+ containerPath: '/workspace',
78
+ readOnly: false
79
+ }
80
+ ]
81
+ });
82
+ this.activeJobs.set(jobId, { containerId, workDir });
83
+ logsCallback(`[INFO] Container created: ${containerId}`);
84
+ // Step 5: Start container
85
+ progressCallback({
86
+ percentage: 45,
87
+ currentStep: 'Starting container',
88
+ totalSteps: 8,
89
+ currentStepIndex: 5
90
+ });
91
+ await this.dockerManager.startContainer(containerId);
92
+ logsCallback(`[INFO] Container started: ${containerId}`);
93
+ // Step 6: Execute build command
94
+ progressCallback({
95
+ percentage: 55,
96
+ currentStep: 'Executing build command',
97
+ totalSteps: 8,
98
+ currentStepIndex: 6
99
+ });
100
+ logsCallback(`[INFO] Executing command: ${job.buildCommand}`);
101
+ const executionResult = await this.dockerManager.executeCommand(containerId, job.buildCommand, {
102
+ timeout: this.config.jobTimeoutMinutes * 60 * 1000,
103
+ onOutput: (output) => {
104
+ logsCallback(`[BUILD] ${output}`);
105
+ }
106
+ });
107
+ // Step 7: Collect artifacts
108
+ progressCallback({
109
+ percentage: 85,
110
+ currentStep: 'Collecting artifacts',
111
+ totalSteps: 8,
112
+ currentStepIndex: 7
113
+ });
114
+ const artifactUrls = await this.collectArtifacts(containerId, workDir, job.artifacts || []);
115
+ if (artifactUrls.length > 0) {
116
+ logsCallback(`[INFO] Collected ${artifactUrls.length} artifacts`);
117
+ }
118
+ // Step 8: Cleanup
119
+ progressCallback({
120
+ percentage: 95,
121
+ currentStep: 'Cleaning up',
122
+ totalSteps: 8,
123
+ currentStepIndex: 8
124
+ });
125
+ await this.cleanupJob(jobId);
126
+ logsCallback(`[INFO] Job cleanup completed`);
127
+ // Final progress
128
+ progressCallback({
129
+ percentage: 100,
130
+ currentStep: 'Job completed',
131
+ totalSteps: 8,
132
+ currentStepIndex: 8
133
+ });
134
+ const success = executionResult.exitCode === 0;
135
+ logsCallback(`[INFO] Job ${jobId} ${success ? 'completed successfully' : 'failed'} (exit code: ${executionResult.exitCode})`);
136
+ return {
137
+ success,
138
+ exitCode: executionResult.exitCode,
139
+ logs: executionResult.output,
140
+ artifactUrls
141
+ };
142
+ }
143
+ catch (error) {
144
+ logger.error(`Job execution failed for ${jobId}:`, error);
145
+ logsCallback(`[ERROR] Job execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
146
+ // Cleanup on error
147
+ await this.cleanupJob(jobId);
148
+ return {
149
+ success: false,
150
+ errorMessage: error instanceof Error ? error.message : 'Unknown error'
151
+ };
152
+ }
153
+ }
154
+ /**
155
+ * Cancel a running job
156
+ */
157
+ async cancelJob(jobId) {
158
+ const jobInfo = this.activeJobs.get(jobId);
159
+ if (!jobInfo) {
160
+ logger.warn(`Attempted to cancel non-existent job: ${jobId}`);
161
+ return;
162
+ }
163
+ logger.info(`Cancelling job: ${jobId}`);
164
+ try {
165
+ // Stop the container
166
+ await this.dockerManager.stopContainer(jobInfo.containerId);
167
+ logger.info(`Container stopped for job: ${jobId}`);
168
+ }
169
+ catch (error) {
170
+ logger.error(`Error stopping container for job ${jobId}:`, error);
171
+ }
172
+ // Clean up
173
+ await this.cleanupJob(jobId);
174
+ }
175
+ /**
176
+ * Clean up resources
177
+ */
178
+ async cleanup() {
179
+ logger.info('Cleaning up job executor...');
180
+ // Cancel all active jobs
181
+ const activeJobIds = Array.from(this.activeJobs.keys());
182
+ for (const jobId of activeJobIds) {
183
+ await this.cancelJob(jobId);
184
+ }
185
+ // Clean up Docker manager
186
+ await this.dockerManager.cleanup();
187
+ }
188
+ /**
189
+ * Clean up orphaned containers from previous agent crashes.
190
+ */
191
+ async cleanupOrphanedContainers() {
192
+ return this.dockerManager.cleanupOrphanedContainers();
193
+ }
194
+ /**
195
+ * Validate job requirements against agent capabilities
196
+ */
197
+ async validateJobRequirements(job) {
198
+ // Check repository whitelist/blacklist
199
+ if (this.config.allowedRepositories && this.config.allowedRepositories.length > 0) {
200
+ if (!this.config.allowedRepositories.includes(job.repository)) {
201
+ throw new Error(`Repository ${job.repository} is not in the allowed list`);
202
+ }
203
+ }
204
+ if (this.config.blockedRepositories && this.config.blockedRepositories.includes(job.repository)) {
205
+ throw new Error(`Repository ${job.repository} is blocked`);
206
+ }
207
+ // Default Docker image if not provided
208
+ if (!job.dockerImage || job.dockerImage.trim() === '') {
209
+ job.dockerImage = 'node:20';
210
+ logger.info(`No Docker image specified, defaulting to ${job.dockerImage}`);
211
+ }
212
+ // Validate build command
213
+ if (!job.buildCommand || job.buildCommand.trim() === '') {
214
+ throw new Error('Build command is required');
215
+ }
216
+ logger.info(`Job requirements validated for ${job.externalId}`);
217
+ }
218
+ /**
219
+ * Create workspace directory for job
220
+ */
221
+ async createWorkspace(jobId) {
222
+ const workDir = join(this.workspaceRoot, jobId);
223
+ try {
224
+ await fs.mkdir(workDir, { recursive: true });
225
+ logger.info(`Created workspace: ${workDir}`);
226
+ return workDir;
227
+ }
228
+ catch (error) {
229
+ logger.error(`Failed to create workspace ${workDir}:`, error);
230
+ throw new Error(`Failed to create workspace: ${error instanceof Error ? error.message : 'Unknown error'}`);
231
+ }
232
+ }
233
+ /**
234
+ * Prepare workspace with job context
235
+ */
236
+ async prepareWorkspace(workDir, job) {
237
+ try {
238
+ // Build the clone URL, injecting credentials for private repositories.
239
+ // When a githubToken is present we rewrite the HTTPS URL to embed the
240
+ // x-access-token convention so no interactive credential prompt is needed.
241
+ // The token is intentionally kept out of log lines.
242
+ // Normalize repository to a full URL if it's just owner/repo format
243
+ const repoUrl = job.repository.startsWith('http')
244
+ ? job.repository
245
+ : `https://github.com/${job.repository}.git`;
246
+ const cloneUrl = job.githubToken
247
+ ? this.buildAuthenticatedCloneUrl(repoUrl, job.githubToken)
248
+ : repoUrl;
249
+ // Disable all interactive git prompts so the process fails fast instead
250
+ // of hanging indefinitely when credentials are missing or wrong.
251
+ const gitEnv = {
252
+ GIT_TERMINAL_PROMPT: '0',
253
+ };
254
+ logger.info(`Cloning repository ${job.repository} (branch: ${job.branch}) into ${workDir}${job.githubToken ? ' [token auth]' : ''}`);
255
+ const cloneResult = await this.executeGitCommand([
256
+ 'clone', cloneUrl,
257
+ '--branch', job.branch,
258
+ '--single-branch',
259
+ '--depth', '1',
260
+ '.'
261
+ ], workDir, gitEnv);
262
+ if (cloneResult.exitCode !== 0) {
263
+ // Scrub any embedded token from the error message before surfacing it
264
+ const safeError = job.githubToken
265
+ ? (cloneResult.error || cloneResult.output).replace(job.githubToken, '[REDACTED]')
266
+ : (cloneResult.error || cloneResult.output);
267
+ throw new Error(`Git clone failed: ${safeError}`);
268
+ }
269
+ // Checkout exact commit if specified and differs from branch HEAD
270
+ if (job.commitSha) {
271
+ const checkoutResult = await this.executeGitCommand(['checkout', job.commitSha], workDir, gitEnv);
272
+ if (checkoutResult.exitCode !== 0) {
273
+ logger.warn(`Could not checkout exact commit ${job.commitSha}, using branch HEAD`);
274
+ }
275
+ }
276
+ logger.info(`Repository cloned successfully for job ${job.externalId}`);
277
+ // Create job metadata file
278
+ const jobMetadata = {
279
+ jobId: job.externalId,
280
+ repository: job.repository,
281
+ branch: job.branch,
282
+ commitSha: job.commitSha,
283
+ jobType: job.jobType,
284
+ createdAt: new Date().toISOString()
285
+ };
286
+ await fs.writeFile(join(workDir, '.buildhive-job.json'), JSON.stringify(jobMetadata, null, 2));
287
+ // Create environment file if needed
288
+ if (job.environment && Object.keys(job.environment).length > 0) {
289
+ const envContent = Object.entries(job.environment)
290
+ .map(([key, value]) => `${key}=${value}`)
291
+ .join('\n');
292
+ await fs.writeFile(join(workDir, '.env'), envContent);
293
+ }
294
+ logger.info(`Workspace prepared for job ${job.externalId}`);
295
+ }
296
+ catch (error) {
297
+ logger.error(`Failed to prepare workspace for job ${job.externalId}:`, error);
298
+ throw new Error(`Failed to prepare workspace: ${error instanceof Error ? error.message : 'Unknown error'}`);
299
+ }
300
+ }
301
+ /**
302
+ * Build an authenticated clone URL from a plain HTTPS repository URL.
303
+ *
304
+ * Converts https://github.com/user/repo (or https://github.com/user/repo.git)
305
+ * to https://x-access-token:{token}@github.com/user/repo using the
306
+ * x-access-token convention supported by GitHub App installation tokens,
307
+ * fine-grained PATs, and classic PATs.
308
+ *
309
+ * Only HTTPS URLs are rewritten. SSH URLs (git@github.com:...) are returned
310
+ * unchanged because they rely on key-based auth, not token-based.
311
+ *
312
+ * The token is never written to disk or emitted in log lines.
313
+ */
314
+ buildAuthenticatedCloneUrl(repositoryUrl, token) {
315
+ try {
316
+ const parsed = new URL(repositoryUrl);
317
+ // Only inject credentials into HTTPS URLs
318
+ if (parsed.protocol !== 'https:') {
319
+ return repositoryUrl;
320
+ }
321
+ parsed.username = 'x-access-token';
322
+ parsed.password = token;
323
+ return parsed.toString();
324
+ }
325
+ catch {
326
+ // Malformed URL — return as-is and let git produce the error
327
+ return repositoryUrl;
328
+ }
329
+ }
330
+ /**
331
+ * Execute a git command in the given working directory.
332
+ *
333
+ * @param args - Arguments to pass to the git binary
334
+ * @param cwd - Working directory for the git process
335
+ * @param env - Additional environment variables merged on top of process.env.
336
+ * Use this to pass GIT_ASKPASS, GIT_TERMINAL_PROMPT=0, etc.
337
+ * @param timeoutMs - Maximum time to wait before killing the process (default 5 min)
338
+ */
339
+ executeGitCommand(args, cwd, env, timeoutMs = 300000) {
340
+ return new Promise((resolve) => {
341
+ const mergedEnv = env
342
+ ? { ...process.env, ...env }
343
+ : process.env;
344
+ const proc = spawn('git', args, { cwd, env: mergedEnv });
345
+ let output = '';
346
+ let error = '';
347
+ let killed = false;
348
+ const timer = setTimeout(() => {
349
+ killed = true;
350
+ proc.kill('SIGKILL');
351
+ resolve({ exitCode: 1, output, error: `Git command timed out after ${timeoutMs / 1000}s` });
352
+ }, timeoutMs);
353
+ proc.stdout.on('data', (data) => { output += data.toString(); });
354
+ proc.stderr.on('data', (data) => { error += data.toString(); });
355
+ proc.on('close', (code) => {
356
+ clearTimeout(timer);
357
+ if (!killed) {
358
+ resolve({ exitCode: code ?? 1, output, error });
359
+ }
360
+ });
361
+ proc.on('error', (err) => {
362
+ clearTimeout(timer);
363
+ if (!killed) {
364
+ resolve({ exitCode: 1, output: '', error: err.message });
365
+ }
366
+ });
367
+ });
368
+ }
369
+ /**
370
+ * Collect build artifacts from container
371
+ *
372
+ * MVP.4.2.4: Artifacts are copied from container and uploaded to configured storage
373
+ */
374
+ async collectArtifacts(containerId, workDir, artifactPaths) {
375
+ if (artifactPaths.length === 0) {
376
+ return [];
377
+ }
378
+ const artifactUrls = [];
379
+ try {
380
+ for (const artifactPath of artifactPaths) {
381
+ const localPath = join(workDir, 'artifacts', artifactPath);
382
+ // Step 1: Copy artifact from container to host
383
+ logger.debug(`Copying artifact from container: ${artifactPath}`);
384
+ await this.dockerManager.copyFromContainer(containerId, `/workspace/${artifactPath}`, localPath);
385
+ // Step 2: Upload artifact to configured storage (MVP.4.2.4)
386
+ logger.debug(`Uploading artifact to storage: ${artifactPath}`);
387
+ const result = await this.artifactUploader.uploadArtifact(localPath, artifactPath, {
388
+ deleteAfterUpload: this.config.storageConfig.cleanupAfterUpload
389
+ });
390
+ artifactUrls.push(result.url);
391
+ logger.debug(`Artifact uploaded successfully`, {
392
+ path: artifactPath,
393
+ url: result.url,
394
+ size: result.size
395
+ });
396
+ }
397
+ logger.info(`Collected and uploaded ${artifactUrls.length} artifacts`);
398
+ }
399
+ catch (error) {
400
+ logger.error('Failed to collect artifacts:', error);
401
+ // Don't fail the job if artifact collection fails
402
+ }
403
+ return artifactUrls;
404
+ }
405
+ /**
406
+ * Clean up job resources
407
+ */
408
+ async cleanupJob(jobId) {
409
+ const jobInfo = this.activeJobs.get(jobId);
410
+ if (!jobInfo) {
411
+ return;
412
+ }
413
+ try {
414
+ // Remove and clean up container
415
+ await this.dockerManager.removeContainer(jobInfo.containerId);
416
+ // Clean up workspace unless explicitly told to keep it for debugging
417
+ const keepWorkspace = process.env.BUILDHIVE_KEEP_WORKSPACE === 'true';
418
+ if (!keepWorkspace) {
419
+ await fs.rm(jobInfo.workDir, { recursive: true, force: true });
420
+ logger.info(`Cleaned up workspace: ${jobInfo.workDir}`);
421
+ }
422
+ }
423
+ catch (error) {
424
+ logger.error(`Error during cleanup for job ${jobId}:`, error);
425
+ }
426
+ finally {
427
+ this.activeJobs.delete(jobId);
428
+ }
429
+ }
430
+ /**
431
+ * Clean up old artifacts based on retention policy (MVP.4.2.4)
432
+ *
433
+ * Should be called periodically by the agent to enforce retention policy.
434
+ *
435
+ * @returns Number of artifacts deleted
436
+ */
437
+ async cleanupOldArtifacts() {
438
+ logger.info('Starting artifact retention cleanup');
439
+ try {
440
+ const deletedCount = await this.artifactUploader.cleanupOldArtifacts();
441
+ logger.info(`Artifact retention cleanup complete`, { deletedCount });
442
+ return deletedCount;
443
+ }
444
+ catch (error) {
445
+ logger.error('Artifact retention cleanup failed:', error);
446
+ return 0;
447
+ }
448
+ }
449
+ /**
450
+ * Get artifact storage statistics (MVP.4.2.4)
451
+ *
452
+ * @returns Storage statistics
453
+ */
454
+ async getArtifactStorageStats() {
455
+ return this.artifactUploader.getStorageStats();
456
+ }
457
+ }
458
+ //# sourceMappingURL=jobExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobExecutor.js","sourceRoot":"","sources":["../src/jobExecutor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Lifecycle Executor - Setup/Execute/Teardown job phases
3
+ *
4
+ * Manages the full lifecycle of a job execution:
5
+ * 1. Setup steps run sequentially
6
+ * 2. Main build command executes
7
+ * 3. Teardown steps ALWAYS run (even on failure)
8
+ */
9
+ import { RecipeLifecycleStep } from './recipes/types.js';
10
+ export interface LifecyclePhaseResult {
11
+ phase: 'setup' | 'execute' | 'teardown';
12
+ stepName: string;
13
+ exitCode: number;
14
+ stdout: string;
15
+ stderr: string;
16
+ durationMs: number;
17
+ skipped: boolean;
18
+ error?: string;
19
+ }
20
+ export interface LifecycleResult {
21
+ setupResults: LifecyclePhaseResult[];
22
+ executeResult: LifecyclePhaseResult;
23
+ teardownResults: LifecyclePhaseResult[];
24
+ overallSuccess: boolean;
25
+ totalDurationMs: number;
26
+ }
27
+ export interface LifecycleOptions {
28
+ workDir: string;
29
+ environment?: Record<string, string>;
30
+ onProgress?: (phase: string, step: string, progress: number) => void;
31
+ onLog?: (phase: string, step: string, log: string) => void;
32
+ abortSignal?: AbortSignal;
33
+ }
34
+ export declare class LifecycleExecutor {
35
+ /**
36
+ * Execute full lifecycle: setup -> main command -> teardown
37
+ *
38
+ * CRITICAL BEHAVIORS:
39
+ * 1. Setup steps run sequentially. If a step fails and continueOnError=false,
40
+ * skip remaining setup + main command, but STILL run teardown.
41
+ * 2. Main command runs only if all required setup steps succeed.
42
+ * 3. Teardown ALWAYS runs, even if setup or main command failed.
43
+ * 4. Each step has its own timeout (default 300s).
44
+ * 5. If abortSignal fires, terminate current step and run teardown.
45
+ */
46
+ execute(setupSteps: RecipeLifecycleStep[], mainCommand: string, teardownSteps: RecipeLifecycleStep[], options: LifecycleOptions): Promise<LifecycleResult>;
47
+ /**
48
+ * Execute a single lifecycle step using child_process.spawn.
49
+ */
50
+ private executeStep;
51
+ private skippedResult;
52
+ private isAborted;
53
+ }
54
+ //# sourceMappingURL=lifecycleExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycleExecutor.d.ts","sourceRoot":"","sources":["../src/lifecycleExecutor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAMzD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,oBAAoB,EAAE,CAAC;IACrC,aAAa,EAAE,oBAAoB,CAAC;IACpC,eAAe,EAAE,oBAAoB,EAAE,CAAC;IACxC,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAaD,qBAAa,iBAAiB;IAC5B;;;;;;;;;;OAUG;IACG,OAAO,CACX,UAAU,EAAE,mBAAmB,EAAE,EACjC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,mBAAmB,EAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC;IAqF3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAiInB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,SAAS;CAGlB"}