fix: address code review findings for DNS management

- CRITICAL: Change DNS zones endpoint from GET to POST to avoid
  leaking API token in URL query parameters
- HIGH: Add sync.RWMutex to protect dnsProvider field in Server,
  Deployer, and proxy Manager against concurrent read/write races
- HIGH: Capture old DNS provider reference synchronously before
  launching background cleanup goroutine
- HIGH: Use getDNS()/getDNSProviderLocked() accessors instead of
  direct field reads in all DNS operations
This commit is contained in:
2026-04-02 14:54:15 +03:00
parent c730cfaa45
commit 670948f113
243 changed files with 15971 additions and 535 deletions
@@ -0,0 +1,71 @@
import { a as attr, b as attr_class, c as clsx, h as head, e as escape_html, s as store_get, g as stringify, f as ensure_array_like, u as unsubscribe_stores, i as derived } from "../../chunks/index.js";
import { t } from "../../chunks/index2.js";
import { I as IconDeploy } from "../../chunks/IconDeploy.js";
import { I as IconAlert } from "../../chunks/IconAlert.js";
import { S as SkeletonCard } from "../../chunks/SkeletonCard.js";
import "clsx";
function IconServer($$renderer, $$props) {
const { size = 20, class: c = "" } = $$props;
$$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(c))} aria-hidden="true"><rect width="20" height="8" x="2" y="2" rx="2" ry="2"></rect><rect width="20" height="8" x="2" y="14" rx="2" ry="2"></rect><line x1="6" x2="6.01" y1="6" y2="6"></line><line x1="6" x2="6.01" y1="18" y2="18"></line></svg>`);
}
function IconBox($$renderer, $$props) {
const { size = 20, class: c = "" } = $$props;
$$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(c))} aria-hidden="true"><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"></path><path d="m3.3 7 8.7 5 8.7-5"></path><path d="M12 22V12"></path></svg>`);
}
function IconClock($$renderer, $$props) {
const { size = 20, class: c = "" } = $$props;
$$renderer.push(`<svg xmlns="http://www.w3.org/2000/svg"${attr("width", size)}${attr("height", size)} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"${attr_class(clsx(c))} aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>`);
}
function SystemHealthCard($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
{
$$renderer2.push("<!--[-1-->");
}
$$renderer2.push(`<!--]-->`);
});
}
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
var $$store_subs;
let projects = [];
let instancesByProject = {};
let staleContainers = [];
const totalProjects = derived(() => projects.length);
const totalRunning = derived(() => Object.values(instancesByProject).flat().filter((i) => i.status === "running").length);
const totalFailed = derived(() => Object.values(instancesByProject).flat().filter((i) => i.status === "failed").length);
const totalStale = derived(() => staleContainers.length);
head("1uha8ag", $$renderer2, ($$renderer3) => {
$$renderer3.title(($$renderer4) => {
$$renderer4.push(`<title>${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.title"))} - ${escape_html(store_get($$store_subs ??= {}, "$t", t)("app.name"))}</title>`);
});
});
$$renderer2.push(`<div class="space-y-6"><div class="flex items-center justify-between"><h1 class="text-2xl font-bold text-[var(--text-primary)]">${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.title"))}</h1> <a href="/deploy" class="inline-flex items-center gap-2 rounded-lg bg-[var(--color-brand-600)] px-4 py-2.5 text-sm font-medium text-white shadow-sm transition-all duration-150 hover:bg-[var(--color-brand-700)] active:animate-press">`);
IconDeploy($$renderer2, { size: 16 });
$$renderer2.push(`<!----> ${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.quickDeploy"))}</a></div> <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4"><div class="flex items-center gap-4 rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-5 shadow-[var(--shadow-sm)]"><div class="flex h-12 w-12 items-center justify-center rounded-xl bg-[var(--color-brand-50)] text-[var(--color-brand-600)]">`);
IconBox($$renderer2, { size: 24 });
$$renderer2.push(`<!----></div> <div><p class="text-sm text-[var(--text-secondary)]">${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.totalProjects"))}</p> <p class="mt-0.5 text-2xl font-bold text-[var(--text-primary)]">${escape_html(totalProjects())}</p></div></div> <div class="flex items-center gap-4 rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-5 shadow-[var(--shadow-sm)]"><div class="flex h-12 w-12 items-center justify-center rounded-xl bg-emerald-50 text-emerald-600">`);
IconServer($$renderer2, { size: 24 });
$$renderer2.push(`<!----></div> <div><p class="text-sm text-[var(--text-secondary)]">${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.runningInstances"))}</p> <p class="mt-0.5 text-2xl font-bold text-emerald-600">${escape_html(totalRunning())}</p></div></div> <div class="flex items-center gap-4 rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-5 shadow-[var(--shadow-sm)]"><div${attr_class(`flex h-12 w-12 items-center justify-center rounded-xl ${stringify(totalFailed() > 0 ? "bg-red-50 text-red-600" : "bg-gray-50 text-gray-400")}`)}>`);
IconAlert($$renderer2, { size: 24 });
$$renderer2.push(`<!----></div> <div><p class="text-sm text-[var(--text-secondary)]">${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.failedInstances"))}</p> <p${attr_class(`mt-0.5 text-2xl font-bold ${stringify(totalFailed() > 0 ? "text-red-600" : "text-[var(--text-primary)]")}`)}>${escape_html(totalFailed())}</p></div></div> <a href="/containers/stale" class="flex items-center gap-4 rounded-xl border border-[var(--border-primary)] bg-[var(--surface-card)] p-5 shadow-[var(--shadow-sm)] transition-colors hover:bg-[var(--surface-card-hover)]"><div${attr_class(`flex h-12 w-12 items-center justify-center rounded-xl ${stringify(totalStale() > 0 ? "bg-amber-50 text-amber-600" : "bg-gray-50 text-gray-400")}`)}>`);
IconClock($$renderer2, { size: 24 });
$$renderer2.push(`<!----></div> <div><p class="text-sm text-[var(--text-secondary)]">${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.staleContainers"))}</p> <p${attr_class(`mt-0.5 text-2xl font-bold ${stringify(totalStale() > 0 ? "text-amber-600" : "text-[var(--text-primary)]")}`)}>${escape_html(totalStale())}</p></div></a></div> `);
SystemHealthCard($$renderer2);
$$renderer2.push(`<!----> <div><h2 class="text-lg font-semibold text-[var(--text-primary)]">${escape_html(store_get($$store_subs ??= {}, "$t", t)("dashboard.projects"))}</h2> `);
{
$$renderer2.push("<!--[0-->");
$$renderer2.push(`<div class="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"><!--[-->`);
const each_array = ensure_array_like(Array(3));
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
each_array[$$index];
SkeletonCard($$renderer2);
}
$$renderer2.push(`<!--]--></div>`);
}
$$renderer2.push(`<!--]--></div></div>`);
if ($$store_subs) unsubscribe_stores($$store_subs);
});
}
export {
_page as default
};