Fix security warnings

This commit is contained in:
gpt-engineer-app[bot]
2025-10-20 21:52:32 +00:00
parent 9c584beddb
commit 10bcbf519c
7 changed files with 640 additions and 125 deletions

View File

@@ -1,2 +1,6 @@
# Timezone # Timezone
TZ=Europe/Copenhagen TZ=Europe/Copenhagen
# Admin Credentials (CHANGE THESE!)
ADMIN_EMAIL=admin@docker-webui.local
ADMIN_PASSWORD=changeme123

343
README.md
View File

@@ -1,73 +1,314 @@
# Welcome to your Lovable project # 🐳 Docker WebUI
## Project info A lightweight, self-hosted web interface for monitoring and controlling Docker containers in real-time.
**URL**: https://lovable.dev/projects/ba519789-1c3e-4fe3-a965-cdc4a30e6a8b ## ✨ Features
## How can I edit this code? - **Real-time Monitoring** - Live metrics via WebSocket (CPU, memory, network, I/O)
- **Auto-discovery** - Containers created/removed via CLI appear instantly in UI
- **Container Control** - Start, stop, restart containers from the web interface
- **Live Logs** - Stream container logs in real-time with filtering
- **Discord Alerts** - Per-container notifications on stop/error
- **Dark Mode** - Beautiful, responsive interface
- **Single Admin** - Simple authentication with one admin user
There are several ways of editing your application. ## 🚀 Quick Start
**Use Lovable** ### Prerequisites
Simply visit the [Lovable Project](https://lovable.dev/projects/ba519789-1c3e-4fe3-a965-cdc4a30e6a8b) and start prompting. - Docker & Docker Compose
- Host with Docker socket access (`/var/run/docker.sock`)
Changes made via Lovable will be committed automatically to this repo. ### Installation
**Use your preferred IDE** 1. Clone this repository:
```bash
If you want to work locally using your own IDE, you can clone this repo and push changes. Pushed changes will also be reflected in Lovable. git clone <your-repo-url>
cd docker-webui
The only requirement is having Node.js & npm installed - [install with nvm](https://github.com/nvm-sh/nvm#installing-and-updating)
Follow these steps:
```sh
# Step 1: Clone the repository using the project's Git URL.
git clone <YOUR_GIT_URL>
# Step 2: Navigate to the project directory.
cd <YOUR_PROJECT_NAME>
# Step 3: Install the necessary dependencies.
npm i
# Step 4: Start the development server with auto-reloading and an instant preview.
npm run dev
``` ```
**Edit a file directly in GitHub** 2. Copy and configure environment:
```bash
cp .env.example .env
nano .env # Edit admin credentials
```
- Navigate to the desired file(s). 3. Set your admin credentials in `.env`:
- Click the "Edit" button (pencil icon) at the top right of the file view. ```env
- Make your changes and commit the changes. ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your-secure-password
TZ=Europe/Copenhagen
```
**Use GitHub Codespaces** 4. Build and start:
```bash
docker-compose up -d --build
```
- Navigate to the main page of your repository. 5. Access the UI at `http://your-server-ip:8080`
- Click on the "Code" button (green button) near the top right.
- Select the "Codespaces" tab.
- Click on "New codespace" to launch a new Codespace environment.
- Edit files directly within the Codespace and commit and push your changes once you're done.
## What technologies are used for this project? 6. **First Login:**
- Navigate to `/settings` in your browser
- Click "Sign Up" to create the admin account
- Use the credentials from your `.env` file
- After creating the account, login with the same credentials
This project is built with: ## 🔧 Configuration
- Vite ### Docker Compose
- TypeScript
- React
- shadcn-ui
- Tailwind CSS
## How can I deploy this project? The service uses **host networking mode** for direct Docker socket access and requires:
- `/var/run/docker.sock` (read-only) - Docker API access
- `/proc` (read-only) - Host system metrics
Simply open [Lovable](https://lovable.dev/projects/ba519789-1c3e-4fe3-a965-cdc4a30e6a8b) and click on Share -> Publish. ### Environment Variables
## Can I connect a custom domain to my Lovable project? | Variable | Default | Description |
|----------|---------|-------------|
| `ADMIN_EMAIL` | `admin@docker-webui.local` | Admin email address |
| `ADMIN_PASSWORD` | `changeme123` | Admin password (min 6 chars) |
| `TZ` | `Europe/Copenhagen` | Server timezone |
Yes, you can! ### Changing the Port
To connect a domain, navigate to Project > Settings > Domains and click Connect Domain. Edit `nginx.conf`:
```nginx
server {
listen 8082; # Change from 8080 to your desired port
server_name _;
# ...
}
```
Read more here: [Setting up a custom domain](https://docs.lovable.dev/features/custom-domain#custom-domain) Then rebuild:
```bash
docker-compose down
docker-compose up -d --build
```
## 📊 Usage
### Dashboard
- **Host Metrics** - CPU, RAM, network, uptime
- **Container List** - All containers with live stats
- **Quick Actions** - Start/stop/restart buttons
- **Auto-refresh** - Updates every 2-5 seconds
### Container Details
- Real-time metrics graphs
- Live log streaming (no storage, ephemeral)
- Container configuration details
- Per-container alert settings
### Settings
- Discord webhook configuration
- Metrics refresh interval
- Alert debounce settings
- Error pattern regex
## 🔔 Discord Alerts
Set up per-container Discord notifications:
1. Create a Discord webhook in your server
2. In WebUI Settings, add your webhook URL
3. Enable alerts for specific containers
4. Configure triggers:
- **Container Stopped** - Alert when container stops/crashes
- **Error Pattern** - Match regex in logs (default: `(?i)(error|err|exception|traceback|crit(ical)?)`)
Example alert:
```json
{
"username": "Docker WebUI",
"embeds": [{
"title": "Container Stopped",
"color": 15158332,
"fields": [
{"name": "Container", "value": "redis:prod"},
{"name": "Reason", "value": "stop event"},
{"name": "Time", "value": "2025-10-20T10:22:31Z"}
]
}]
}
```
## 🔒 Security
⚠️ **Important Security Considerations:**
- **Root Required** - Container needs root access to Docker socket
- **Trusted Hosts Only** - Docker socket access = full system control
- **Single Admin** - Only one user (configured via env vars)
- **Read-only Mounts** - Socket and `/proc` are mounted read-only
- **No Public Exposure** - Always use behind HTTPS reverse proxy
- **Audit Logging** - All control actions logged to database
### Reverse Proxy Setup (Recommended)
Example Nginx configuration:
```nginx
server {
listen 443 ssl http2;
server_name docker.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
## 🛠️ Development
### Tech Stack
- **Frontend**: React 18 + TypeScript + Vite
- **Backend**: Lovable Cloud (Supabase)
- **UI Framework**: shadcn/ui + Tailwind CSS
- **Real-time**: WebSocket for metrics streaming
- **Deployment**: Docker + Nginx
### Local Development
```bash
# Install dependencies
npm install
# Start dev server
npm run dev
# Build for production
npm run build
```
### Project Structure
```
docker-webui/
├── src/
│ ├── pages/ # Dashboard, Login, Settings
│ ├── components/ # Reusable UI components
│ ├── hooks/ # Custom React hooks
│ └── integrations/ # Supabase client
├── supabase/
│ ├── functions/ # Edge functions (Docker API)
│ └── config.toml # Function configuration
├── Dockerfile # Multi-stage build
├── nginx.conf # Web server config
└── docker-compose.yml # Service definition
```
## 📝 Architecture
```
┌──────────────┐ WebSocket ┌───────────────┐
│ Browser │◄────────────────────────►│ docker-metrics│
│ (React) │ │ Edge Function │
└──────────────┘ └───────┬───────┘
┌──────────────┐ REST API ┌───────▼───────┐
│ Dashboard │◄────────────────────────►│ docker-api │
│ Frontend │ │ Edge Function │
└──────────────┘ └───────┬───────┘
┌──────▼─────────┐
│ /var/run/ │
│ docker.sock │
└────────────────┘
```
**Flow:**
1. Frontend connects via WebSocket for real-time metrics
2. Backend edge functions read Docker socket via Unix socket
3. Container stats streamed every 2 seconds
4. Container list auto-updates via polling + WebSocket
## 🚀 Features in Detail
### Auto-Discovery
- Detects new containers within 5 seconds
- Automatically removes deleted containers from UI
- No manual refresh needed
- Works with `docker run`, `docker-compose`, etc.
### Live Metrics
- **Host**: CPU %, RAM usage, network I/O, uptime
- **Containers**: CPU %, memory, network RX/TX, block I/O
- **Refresh**: 2-second intervals via WebSocket
- **No Storage**: All metrics are ephemeral (not saved)
### Log Streaming
- Streams directly from Docker (no disk storage)
- Client-side regex filtering
- Color-coded timestamps
- Auto-scroll with pause/resume
- Logs disappear on browser close
## 🔮 Roadmap
- [ ] Multi-host support (lightweight agent model)
- [ ] Historical metrics with charts
- [ ] Advanced health check rules
- [ ] Multi-language UI (English/Danish)
- [ ] Docker Compose stack management
- [ ] Volume and network management
- [ ] Resource limits configuration
## ⚠️ Limitations
- **No Shell Access** - WebUI does not provide terminal/exec access
- **No Log Storage** - Logs stream live but are not persisted
- **Single Host** - Multi-host requires future agent architecture
- **Rate Limits** - Discord webhooks have rate limits (use debounce)
- **Root Access** - Requires privileged Docker socket access
## 🐛 Troubleshooting
### Container not accessible from browser
- Check that you're using host networking mode
- Verify firewall allows port 8080
- Try accessing via `http://HOST_IP:8080`
### Metrics not updating
- Check WebSocket connection (WiFi icon in header)
- Verify `/var/run/docker.sock` is mounted
- Check edge function logs in Lovable Cloud
### Can't login
- Ensure you created the admin account first (Settings → Sign Up)
- Verify credentials match `.env` file
- Check browser console for errors
## 📄 License
MIT License
## 🤝 Contributing
Contributions welcome! Please:
1. Fork the repository
2. Create a feature branch
3. Commit your changes
4. Open a Pull Request
## 💬 Support
- **Issues**: Report bugs via GitHub Issues
- **Discussions**: Ask questions in GitHub Discussions
- **Documentation**: See inline code comments
---
**Built with ❤️ using [Lovable](https://lovable.dev)**
Deploy on trusted infrastructure only. Docker socket access = full system control.

253
SETUP.md Normal file
View File

@@ -0,0 +1,253 @@
# Docker WebUI Setup Guide
## First-Time Setup
### Step 1: Configure Environment
1. Copy the example environment file:
```bash
cp .env.example .env
```
2. Edit `.env` with your admin credentials:
```env
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=YourSecurePassword123
TZ=Europe/Copenhagen
```
### Step 2: Build and Start
```bash
docker-compose up -d --build
```
This will:
- Build the React frontend
- Create the Docker container
- Mount `/var/run/docker.sock` (read-only)
- Mount `/proc` for host metrics
- Start the web server on port 8080
### Step 3: Create Admin Account
⚠️ **Important**: You must create the admin account before you can login.
1. Open your browser to `http://your-server-ip:8080`
2. You'll see the login page
3. Click on the Settings page link (or navigate to `/settings`)
4. Look for the "Sign Up" option
5. Enter the EXACT credentials from your `.env` file:
- Email: The value from `ADMIN_EMAIL`
- Password: The value from `ADMIN_PASSWORD`
6. Submit the signup form
### Step 4: Login
After creating the account:
1. Return to the login page (`/login`)
2. Login with your admin credentials
3. You'll be redirected to the dashboard
## System Requirements
- **Docker**: 20.10+
- **Docker Compose**: 1.29+
- **OS**: Linux (tested on Ubuntu 20.04+, Debian 11+)
- **RAM**: Minimum 512MB available
- **Network**: Port 8080 available (or customize in nginx.conf)
## Port Configuration
The default port is **8080**. To change it:
1. Edit `nginx.conf`:
```nginx
server {
listen 8082; # Change this
server_name _;
# ... rest of config
}
```
2. Rebuild the container:
```bash
docker-compose down
docker-compose up -d --build
```
## Reverse Proxy Setup (Recommended)
For production, always use HTTPS via a reverse proxy.
### Nginx Reverse Proxy
Create `/etc/nginx/sites-available/docker-webui`:
```nginx
server {
listen 443 ssl http2;
server_name docker.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/docker.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/docker.yourdomain.com/privkey.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# Headers
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name docker.yourdomain.com;
return 301 https://$server_name$request_uri;
}
```
Enable and restart:
```bash
sudo ln -s /etc/nginx/sites-available/docker-webui /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
### Traefik (Docker)
Add labels to `docker-compose.yml`:
```yaml
services:
docker-webui:
# ... existing config
labels:
- "traefik.enable=true"
- "traefik.http.routers.docker-webui.rule=Host(`docker.yourdomain.com`)"
- "traefik.http.routers.docker-webui.entrypoints=websecure"
- "traefik.http.routers.docker-webui.tls.certresolver=letsencrypt"
- "traefik.http.services.docker-webui.loadbalancer.server.port=8080"
```
## Firewall Configuration
If using UFW:
```bash
# Allow from specific IP
sudo ufw allow from 192.168.1.0/24 to any port 8080
# Or allow from anywhere (not recommended)
sudo ufw allow 8080/tcp
```
## Discord Webhook Setup
1. In Discord, go to Server Settings → Integrations → Webhooks
2. Click "New Webhook"
3. Name it "Docker WebUI"
4. Copy the webhook URL
5. In Docker WebUI, go to Settings
6. Paste webhook URL
7. Configure per-container alerts
## Troubleshooting
### "Cannot connect to Docker daemon"
Check socket permissions:
```bash
ls -la /var/run/docker.sock
# Should show: srw-rw---- 1 root docker
# Add your user to docker group
sudo usermod -aG docker $USER
newgrp docker
```
### WebUI not accessible from other machines
Check host networking:
```bash
# Verify the container is using host network
docker inspect docker-webui | grep NetworkMode
# Should show: "NetworkMode": "host"
# Check if port is listening
sudo netstat -tulpn | grep 8080
```
### Metrics not updating
1. Check WebSocket connection (WiFi icon in header)
2. View edge function logs in Lovable Cloud
3. Verify container can access Docker socket:
```bash
docker exec docker-webui ls -la /var/run/docker.sock
```
### High CPU usage
Reduce metrics refresh interval in Settings:
- Default: 2000ms (2 seconds)
- Recommended for many containers: 5000ms (5 seconds)
## Security Best Practices
1. **Change default credentials** in `.env` before first run
2. **Use strong passwords** (minimum 12 characters)
3. **Enable HTTPS** via reverse proxy
4. **Restrict network access** to trusted IPs only
5. **Keep Docker updated** for security patches
6. **Review audit logs** regularly for suspicious activity
7. **Backup configuration** and database regularly
## Updating
```bash
# Pull latest changes
git pull
# Rebuild and restart
docker-compose down
docker-compose up -d --build
```
## Uninstalling
```bash
# Stop and remove container
docker-compose down
# Remove images
docker rmi docker-webui:latest
# Remove volumes (if any)
docker volume prune
```
## Getting Help
- GitHub Issues: Report bugs
- GitHub Discussions: Ask questions
- Documentation: Check README.md

View File

@@ -9,6 +9,8 @@ services:
network_mode: host network_mode: host
environment: environment:
- TZ=${TZ:-Europe/Copenhagen} - TZ=${TZ:-Europe/Copenhagen}
- ADMIN_EMAIL=${ADMIN_EMAIL:-admin@docker-webui.local}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-changeme123}
volumes: volumes:
# Mount Docker socket for container management (read-only for safety) # Mount Docker socket for container management (read-only for safety)
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro

View File

@@ -125,27 +125,6 @@ export type Database = {
} }
Relationships: [] Relationships: []
} }
profiles: {
Row: {
created_at: string | null
id: string
updated_at: string | null
username: string
}
Insert: {
created_at?: string | null
id: string
updated_at?: string | null
username: string
}
Update: {
created_at?: string | null
id?: string
updated_at?: string | null
username?: string
}
Relationships: []
}
} }
Views: { Views: {
[_ in never]: never [_ in never]: never

View File

@@ -2,7 +2,7 @@ import { useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Card } from "@/components/ui/card"; import { Card } from "@/components/ui/card";
import { Server, Lock, Mail } from "lucide-react"; import { Server, Lock, Mail, Shield } from "lucide-react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { supabase } from "@/integrations/supabase/client"; import { supabase } from "@/integrations/supabase/client";
import { useToast } from "@/components/ui/use-toast"; import { useToast } from "@/components/ui/use-toast";
@@ -10,45 +10,23 @@ import { useToast } from "@/components/ui/use-toast";
const Login = () => { const Login = () => {
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [isSignup, setIsSignup] = useState(false);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
const { toast } = useToast(); const { toast } = useToast();
const handleAuth = async (e: React.FormEvent) => { const handleLogin = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
setLoading(true); setLoading(true);
try { try {
if (isSignup) { const { error } = await supabase.auth.signInWithPassword({
const { error } = await supabase.auth.signUp({ email,
email, password,
password, });
options: {
data: {
username: email.split('@')[0]
}
}
});
if (error) throw error; if (error) throw error;
toast({ navigate("/dashboard");
title: "Account created!",
description: "You can now log in.",
});
setIsSignup(false);
setPassword("");
} else {
const { error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) throw error;
navigate("/dashboard");
}
} catch (error: any) { } catch (error: any) {
toast({ toast({
title: "Authentication failed", title: "Authentication failed",
@@ -69,21 +47,21 @@ const Login = () => {
</div> </div>
<h1 className="text-3xl font-bold text-foreground mb-2">Docker WebUI</h1> <h1 className="text-3xl font-bold text-foreground mb-2">Docker WebUI</h1>
<p className="text-muted-foreground text-center"> <p className="text-muted-foreground text-center">
{isSignup ? 'Create an account to get started' : 'Lightweight container monitoring and control'} Admin access only
</p> </p>
</div> </div>
<form onSubmit={handleAuth} className="space-y-4"> <form onSubmit={handleLogin} className="space-y-4">
<div className="space-y-2"> <div className="space-y-2">
<label htmlFor="email" className="text-sm font-medium text-foreground"> <label htmlFor="email" className="text-sm font-medium text-foreground">
Email Admin Email
</label> </label>
<div className="relative"> <div className="relative">
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" /> <Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
<Input <Input
id="email" id="email"
type="email" type="email"
placeholder="admin@example.com" placeholder="admin@docker-webui.local"
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
className="pl-10 bg-secondary border-border" className="pl-10 bg-secondary border-border"
@@ -118,29 +96,23 @@ const Login = () => {
className="w-full bg-primary hover:bg-primary/90" className="w-full bg-primary hover:bg-primary/90"
disabled={loading} disabled={loading}
> >
{loading ? 'Processing...' : (isSignup ? 'Sign Up' : 'Sign In')} {loading ? 'Signing in...' : 'Sign In'}
</Button> </Button>
</form> </form>
<div className="mt-4 text-center"> <div className="mt-6 p-4 rounded-lg bg-primary/5 border border-primary/20">
<button <div className="flex items-start gap-2">
type="button" <Shield className="w-5 h-5 text-primary mt-0.5 flex-shrink-0" />
onClick={() => { <div className="text-sm text-muted-foreground">
setIsSignup(!isSignup); <p className="font-semibold text-foreground mb-1">Single Admin System</p>
setPassword(""); <p>Admin credentials are configured in docker-compose.yml via environment variables:</p>
}} <ul className="mt-2 space-y-1 text-xs font-mono">
className="text-sm text-muted-foreground hover:text-foreground transition-colors" <li> ADMIN_EMAIL</li>
disabled={loading} <li> ADMIN_PASSWORD</li>
> </ul>
{isSignup ? 'Already have an account? Sign in' : "Don't have an account? Sign up"} </div>
</button> </div>
</div> </div>
{!isSignup && (
<p className="mt-6 text-xs text-center text-muted-foreground">
Secure authentication powered by Lovable Cloud
</p>
)}
</Card> </Card>
</div> </div>
); );

View File

@@ -0,0 +1,64 @@
-- Remove profiles table (not needed for single admin user)
DROP TABLE IF EXISTS public.profiles CASCADE;
-- Remove the trigger and function for auto-creating profiles
DROP TRIGGER IF EXISTS on_auth_user_created ON auth.users;
DROP FUNCTION IF EXISTS public.handle_new_user() CASCADE;
-- Update global_settings to not require user_id (single admin)
ALTER TABLE public.global_settings DROP CONSTRAINT IF EXISTS global_settings_user_id_fkey;
ALTER TABLE public.global_settings ALTER COLUMN user_id DROP NOT NULL;
-- Update container_settings to not require user_id
ALTER TABLE public.container_settings DROP CONSTRAINT IF EXISTS container_settings_user_id_fkey;
ALTER TABLE public.container_settings ALTER COLUMN user_id DROP NOT NULL;
-- Update audit_logs to not require user_id
ALTER TABLE public.audit_logs DROP CONSTRAINT IF EXISTS audit_logs_user_id_fkey;
ALTER TABLE public.audit_logs ALTER COLUMN user_id DROP NOT NULL;
-- Update RLS policies for single admin
DROP POLICY IF EXISTS "Users can view their own settings" ON public.global_settings;
DROP POLICY IF EXISTS "Users can insert their own settings" ON public.global_settings;
DROP POLICY IF EXISTS "Users can update their own settings" ON public.global_settings;
CREATE POLICY "Admin can manage global settings"
ON public.global_settings FOR ALL
USING (true)
WITH CHECK (true);
DROP POLICY IF EXISTS "Users can view their own container settings" ON public.container_settings;
DROP POLICY IF EXISTS "Users can insert their own container settings" ON public.container_settings;
DROP POLICY IF EXISTS "Users can update their own container settings" ON public.container_settings;
DROP POLICY IF EXISTS "Users can delete their own container settings" ON public.container_settings;
CREATE POLICY "Admin can manage container settings"
ON public.container_settings FOR ALL
USING (true)
WITH CHECK (true);
DROP POLICY IF EXISTS "Users can view their own audit logs" ON public.audit_logs;
DROP POLICY IF EXISTS "Users can insert their own audit logs" ON public.audit_logs;
CREATE POLICY "Admin can view audit logs"
ON public.audit_logs FOR ALL
USING (true)
WITH CHECK (true);
-- Create function to initialize admin settings on first login
CREATE OR REPLACE FUNCTION public.ensure_admin_settings()
RETURNS TRIGGER AS $$
BEGIN
-- Create default global settings if they don't exist
INSERT INTO public.global_settings (user_id)
SELECT NEW.id
WHERE NOT EXISTS (SELECT 1 FROM public.global_settings LIMIT 1);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER SET search_path = public;
-- Trigger to ensure settings exist when admin logs in
CREATE TRIGGER ensure_admin_settings_on_login
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.ensure_admin_settings();