Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/control-plane-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Build and Push Images
on:
push:
branches:
- main
- release
paths:
- "web/**"
- "registry/**"
Expand Down
19 changes: 19 additions & 0 deletions web/actions/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ import cronstrue from "cronstrue";
import { startMigration } from "./migrations";
import { inngest } from "@/lib/inngest/client";

function isValidImageReferencePart(reference: string): boolean {
// Allow only characters that are valid in Docker tags/digests and avoid path traversal.
// Tags: letters, digits, underscores, periods and dashes; Digests: "algorithm:hex".
// This regex is intentionally conservative.
const tagPattern = /^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/;
const digestPattern = /^[A-Za-z0-9_+.-]+:[0-9a-fA-F]{32,256}$/;

return reference === "latest" ||
tagPattern.test(reference) ||
digestPattern.test(reference);
}

function parseImageReference(image: string): {
registry: string;
namespace: string;
Expand Down Expand Up @@ -96,6 +108,13 @@ export async function validateDockerImage(
parseImageReference(image);
const reference = digest || tag || "latest";

if (!isValidImageReferencePart(reference)) {
return {
valid: false,
error: "Invalid image tag or digest",
};
}

if (registry === "docker.io") {
const repoPath =
namespace === "library" ? repository : `${namespace}/${repository}`;
Expand Down
99 changes: 0 additions & 99 deletions web/app/(auth)/login/page.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion web/app/(auth)/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export default function RegisterPage() {
</Button>
<p className="text-sm text-muted-foreground">
Already have an account?{" "}
<Link href="/login" className="text-primary hover:underline">
<Link href="/" className="text-primary hover:underline">
Sign in
</Link>
</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"use client";

import { useState } from "react";
import { useCallback, useState } from "react";
import { useRouter } from "next/navigation";
import { toast } from "sonner";
import { useSWRConfig } from "swr";
import { deleteService } from "@/actions/projects";
import { useService } from "@/components/service/service-layout-client";
Expand Down Expand Up @@ -36,6 +37,11 @@ export default function ConfigurationPage() {
const { service, projectSlug, envName, proxyDomain, onUpdate } = useService();
const [isDeleting, setIsDeleting] = useState(false);

const handleConfigSave = useCallback(() => {
onUpdate();
toast.info("Changes saved. Deploy to apply them.");
}, [onUpdate]);

const handleDelete = async () => {
setIsDeleting(true);
try {
Expand All @@ -49,29 +55,29 @@ export default function ConfigurationPage() {

return (
<div className="space-y-6">
<SourceSection service={service} onUpdate={onUpdate} />
<SourceSection service={service} onUpdate={handleConfigSave} />

<ReplicasSection service={service} onUpdate={onUpdate} />
<ReplicasSection service={service} onUpdate={handleConfigSave} />

<VolumesSection service={service} onUpdate={onUpdate} />
<VolumesSection service={service} onUpdate={handleConfigSave} />

<SecretsSection service={service} onUpdate={onUpdate} />
<SecretsSection service={service} onUpdate={handleConfigSave} />

<PortsSection service={service} onUpdate={onUpdate} />
<PortsSection service={service} onUpdate={handleConfigSave} />

<TCPProxySection
service={service}
proxyDomain={proxyDomain}
onUpdate={onUpdate}
onUpdate={handleConfigSave}
/>

<HealthCheckSection service={service} onUpdate={onUpdate} />
<HealthCheckSection service={service} onUpdate={handleConfigSave} />

<ResourceLimitsSection service={service} onUpdate={onUpdate} />
<ResourceLimitsSection service={service} onUpdate={handleConfigSave} />

<StartCommandSection service={service} onUpdate={onUpdate} />
<StartCommandSection service={service} onUpdate={handleConfigSave} />

<ScheduleSection service={service} onUpdate={onUpdate} />
<ScheduleSection service={service} onUpdate={handleConfigSave} />

<div className="space-y-3">
<h2 className="text-xl font-semibold text-destructive">Danger Zone</h2>
Expand Down
Loading