app/routes/api.config.docker.tsx (118 lines of code) (raw):
import {
json,
type LoaderFunctionArgs,
type ActionFunctionArgs,
} from "@remix-run/node";
import serverConfig from "~/lib/server/config";
// In-memory storage for Docker configuration (in production, this should be persisted)
let dockerConfig = {
image: process.env.DOCKER_IMAGE || "codex-universal-explore:dev", // Default to local dev image
environment: {} as Record<string, string>,
secrets: {} as Record<string, string>,
};
// GET /api/config/docker - Get Docker configuration
export async function loader({ request }: LoaderFunctionArgs) {
try {
return json(dockerConfig);
} catch (error) {
console.error("Error getting Docker configuration:", error);
return json(
{
error: {
code: "INTERNAL_ERROR",
message: "Failed to get Docker configuration",
},
},
{ status: 500 }
);
}
}
// PUT /api/config/docker - Update Docker configuration
export async function action({ request }: ActionFunctionArgs) {
if (request.method !== "PUT") {
return json({ error: "Method not allowed" }, { status: 405 });
}
try {
const { image, environment, secrets } = await request.json();
// Validate image
if (!image || typeof image !== "string") {
return json(
{
error: {
code: "INVALID_IMAGE",
message: "Docker image is required and must be a string",
},
},
{ status: 400 }
);
}
// Basic Docker image validation (allow registry/image:tag format)
const dockerImagePattern =
/^[a-zA-Z0-9][a-zA-Z0-9_.-]*(?:\/[a-zA-Z0-9][a-zA-Z0-9_.-]*)*(?::[a-zA-Z0-9][a-zA-Z0-9_.-]*)?$/;
if (!dockerImagePattern.test(image)) {
return json(
{
error: {
code: "INVALID_IMAGE_FORMAT",
message:
"Docker image must be in valid format (e.g., registry/image:tag)",
},
},
{ status: 400 }
);
}
// Validate environment variables
if (environment && typeof environment !== "object") {
return json(
{
error: {
code: "INVALID_ENVIRONMENT",
message: "Environment must be an object",
},
},
{ status: 400 }
);
}
// Validate secrets
if (secrets && typeof secrets !== "object") {
return json(
{
error: {
code: "INVALID_SECRETS",
message: "Secrets must be an object",
},
},
{ status: 400 }
);
}
// Update configuration
dockerConfig = {
image,
environment: environment || {},
secrets: secrets || {},
};
console.log(`🐳 Docker configuration updated - Image: ${image}`);
console.log(
`📋 Environment variables: ${Object.keys(dockerConfig.environment).length} variables`
);
console.log(
`🔐 Secrets: ${Object.keys(dockerConfig.secrets).length} secrets`
);
// Return configuration without exposing secret values
return json({
image: dockerConfig.image,
environment: dockerConfig.environment,
secrets: Object.keys(dockerConfig.secrets).reduce(
(acc, key) => {
acc[key] = "***";
return acc;
},
{} as Record<string, string>
),
message: "Docker configuration updated successfully",
});
} catch (error) {
console.error("Error updating Docker configuration:", error);
return json(
{
error: {
code: "INTERNAL_ERROR",
message: "Failed to update Docker configuration",
},
},
{ status: 500 }
);
}
}
// Export the dockerConfig so it can be imported by other modules
export { dockerConfig };