private async runJobInContainer()

in app/lib/server/processors/DockerJobExecutor.ts [144:280]


  private async runJobInContainer(
    jobId: string,
    jobData: any,
    credentials: any
  ): Promise<{
    output: string;
    environment: Record<string, string>;
    secrets: Record<string, string>;
  }> {
    console.log(`🐳 Creating Docker container for job ${jobId}`);

    // Use credentials from request (required - no fallback)
    const openaiKey = credentials?.openaiApiKey;

    // (Optional) enforce openaiKey presence if needed:
    // if (!openaiKey) {
    //   throw new Error(
    //     "OpenAI API key is required but not provided in credentials"
    //   );
    // }

    // Use user's Docker configuration
    let imageRef = dockerConfig.image;
    console.log(`🐳 Using Docker image: ${imageRef}`);

    // REMOVE to handle private registry or custom namespace
    // If the default image is "codex-universal-explore:dev"
    if (imageRef === "codex-universal-explore:dev") {
      imageRef = "docker.io/drbh/codex-universal-explore:dev";
    }

    // Check if image exists locally
    try {
      await this.docker.getImage(imageRef).inspect();
      console.log(`✅ Docker image found: ${imageRef}`);
    } catch (error) {
      console.error(`❌ Docker image not found: ${imageRef}`);

      try {
        const pullStream = await this.docker.pull(imageRef);
        await new Promise<void>((resolve, reject) => {
          this.docker.modem.followProgress(
            pullStream,
            (err: Error) => {
              if (err) return reject(err);
              return resolve();
            },
            (event: any) => {
              // (Optional) uncomment to see each pull progress event:
              console.log(event.status, event.progress || "");
            }
          );
        });
        console.log(`✅ Successfully pulled image: ${imageRef}`);
      } catch (pullErr) {
        console.error(
          `❌ Failed to pull image "${imageRef}": ${pullErr.message}`
        );
        throw new Error(
          `Could not pull Docker image "${imageRef}". ` +
            `If it’s on Docker Hub under namespace "drbh", make sure you’ve pushed ` +
            `"${imageRef}". If it’s on a private registry, ensure you’re logged in and the name is correct.`
        );
      }
    }

    // Get repository URL from job data or fall back to server config
    const repositoryUrl = jobData.repository?.url || REPO.URL;
    const repositoryBranch = jobData.repository?.branch || REPO.BRANCH;
    console.log(
      `📂 Repository: ${repositoryUrl} (branch: ${repositoryBranch})`
    );
    console.log(
      `📋 Environment variables: ${
        Object.keys(dockerConfig.environment).length
      } custom variables`
    );
    console.log(
      `🔐 Secrets: ${Object.keys(dockerConfig.secrets).length} custom secrets`
    );

    // Merge base environment with user's custom environment variables
    const baseEnvironment = {
      JOB_ID: jobId,
      REPO_URL: repositoryUrl,
      REPO_BRANCH: repositoryBranch,
      PROMPT: jobData.description,
      ...dockerConfig.environment, // User's custom env vars
    };

    const secrets = {
      OPENAI_API_KEY: openaiKey,
      ...dockerConfig.secrets, // User's custom secrets
    };

    // Convert to array format for Docker
    const environment = [
      ...Object.entries(baseEnvironment).map(
        ([key, value]) => `${key}=${value}`
      ),
      ...Object.entries(secrets).map(([key, value]) => `${key}=${value}`),
    ];

    // Use the user's configured Docker image
    const container = await this.docker.createContainer({
      Image: imageRef,
      Cmd: ["/opt/agents/codex"],
      Env: environment,
      WorkingDir: "/workspace",
      Tty: false,
      AttachStdout: true,
      AttachStderr: true,
      HostConfig: {
        AutoRemove: true,
        Memory: DOCKER.MEMORY_LIMIT,
        CpuShares: DOCKER.CPU_SHARES,
      },
    });

    console.log(`🚀 Starting container for job ${jobId}`);

    // Start container
    await container.start();

    // Get container logs
    const logs = await this.getContainerLogs(container, jobId);
    console.log(
      `📜 Container logs for job ${jobId} (${logs.length} characters)`
    );
    console.log(`📄 Container logs preview:`, logs.substring(0, 500));

    return {
      output: logs,
      environment: baseEnvironment,
      secrets: secrets,
    };
  }