feat(docker-watcher): phase 12 - hardening

Blue-green zero-downtime deploys, promote flow validation.
Dual auth: local (bcrypt + JWT) and OAuth2/OIDC (any provider).
Auth middleware, login page, auth settings UI.
Structured logging (slog JSON), config export to YAML.
Graceful shutdown with deploy draining.
Multi-stage Dockerfile and production docker-compose.yml.
Swap phase order: Volumes & Env before UI Polish.
This commit is contained in:
2026-03-27 23:20:56 +03:00
parent 5558396bb7
commit 32de5b26a8
30 changed files with 2134 additions and 143 deletions
+33 -4
View File
@@ -22,13 +22,26 @@ class ApiError extends Error {
}
}
function getAuthToken(): string | null {
if (typeof localStorage !== 'undefined') {
return localStorage.getItem('auth_token');
}
return null;
}
async function request<T>(path: string, init?: RequestInit): Promise<T> {
const token = getAuthToken();
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...(init?.headers as Record<string, string>)
};
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
const res = await fetch(path, {
...init,
headers: {
'Content-Type': 'application/json',
...init?.headers
}
headers
});
const envelope: ApiEnvelope<T> = await res.json();
@@ -208,4 +221,20 @@ export function regenerateWebhookUrl(): Promise<{ url: string }> {
return post<{ url: string }>('/api/settings/webhook-url/regenerate');
}
// ── Auth ─────────────────────────────────────────────────────────────
export function login(username: string, password: string): Promise<{ token: string; expires_at: string }> {
return post<{ token: string; expires_at: string }>('/api/auth/login', { username, password });
}
export function getCurrentUser(): Promise<{ id: string; username: string; email: string; role: string }> {
return get<{ id: string; username: string; email: string; role: string }>('/api/auth/me');
}
// ── Config Export ────────────────────────────────────────────────────
export function exportConfigUrl(): string {
return '/api/config/export';
}
export { ApiError };