Harden platform security, reliability, and CI after full audit.

Close deployment IDOR and gate stub payment endpoints, add production
secret validation, health probes, Redis-backed build progress, GitHub
Actions CI, expanded tests, billing/k8s refactors, and ops runbooks.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
keyhan
2026-06-29 20:59:49 +03:30
parent a87bc49393
commit 837f0fa63f
83 changed files with 3953 additions and 1308 deletions
@@ -3,6 +3,7 @@
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useParams } from 'next/navigation';
import api from '@/lib/api';
import { queryKeys } from '@/lib/query-keys';
import { notify } from '@/lib/notify';
import type { Application, Deployment, ResourceUsage, ClusterPublic, ClusterPoolPublic, AppSnapshot, K8sRevisionData, K8sRevision, OptionalServiceCredentials, Invoice } from '@/types';
import { useState, useRef, useCallback, useEffect } from 'react';
@@ -250,7 +251,7 @@ export default function AppDetailPage() {
// ─── Billing & Renewal ──────────────────────────────
const { data: walletData } = useQuery<{ balance: number }>({
queryKey: ['wallet'],
queryKey: queryKeys.walletBalance,
queryFn: () => api.get('/billing/wallet').then((r) => r.data),
});
@@ -271,7 +272,7 @@ export default function AppDetailPage() {
onSuccess: (res) => {
notify.success(res.data.message || 'Application renewed successfully!');
queryClient.invalidateQueries({ queryKey: ['application', appId] });
queryClient.invalidateQueries({ queryKey: ['wallet'] });
queryClient.invalidateQueries({ queryKey: queryKeys.walletBalance });
setShowRenewalModal(false);
setRenewCoupon('');
},
@@ -646,7 +647,7 @@ export default function AppDetailPage() {
queryClient.invalidateQueries({ queryKey: ['resources', appId] });
queryClient.invalidateQueries({ queryKey: ['storage-usage', appId] });
queryClient.invalidateQueries({ queryKey: ['db-storage', appId] });
queryClient.invalidateQueries({ queryKey: ['wallet'] });
queryClient.invalidateQueries({ queryKey: queryKeys.walletBalance });
setShowUpgradeConfirm(false);
setUpgradeCostData(null);
setPendingUpgradePayload(null);
@@ -2134,22 +2135,22 @@ export default function AppDetailPage() {
<div className="overflow-x-auto">
<table className="w-full text-[11px]">
<thead>
<tr className="text-left text-gray-500 border-b border-gray-200">
<th className="pb-1 font-medium">{ad.name}</th>
<th className="pb-1 font-medium">{ad.status}</th>
<th className="pb-1 font-medium">{ad.ready}</th>
<th className="pb-1 font-medium">R</th>
<tr className="text-start text-gray-500 border-b border-gray-200">
<th className="pb-1 font-medium text-start">{ad.name}</th>
<th className="pb-1 font-medium text-start">{ad.status}</th>
<th className="pb-1 font-medium text-start">{ad.ready}</th>
<th className="pb-1 font-medium text-start">{ad.restarts}</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-100">
{w.pods.map((pod) => (
<tr key={pod.name} className="text-gray-700">
<td className="py-1 font-mono truncate max-w-[140px]" title={pod.name}>{pod.name}</td>
<td className="py-1">
<td className="py-1 text-start font-mono truncate max-w-[140px]" dir="ltr" title={pod.name}>{pod.name}</td>
<td className="py-1 text-start">
<span className={`px-1.5 py-0.5 rounded text-[10px] font-medium ${pod.status === 'Running' ? 'bg-green-100 text-green-700' : pod.status === 'Pending' ? 'bg-yellow-100 text-yellow-700' : 'bg-red-100 text-red-700'}`}>{pod.status}</span>
</td>
<td className="py-1">{pod.ready ? <CheckCircle className="w-3.5 h-3.5 text-green-500" /> : <Clock className="w-3.5 h-3.5 text-yellow-500" />}</td>
<td className="py-1">{pod.restarts}</td>
<td className="py-1 text-start">{pod.ready ? <CheckCircle className="w-3.5 h-3.5 text-green-500" /> : <Clock className="w-3.5 h-3.5 text-yellow-500" />}</td>
<td className="py-1 text-start">{pod.restarts}</td>
</tr>
))}
</tbody>