FROM python:3.12-slim WORKDIR /app # ── System deps + Chromium + Terraform + nginx + supervisor ───────────────── ARG TERRAFORM_VERSION=1.14.7 RUN apt-get update && apt-get install -y --no-install-recommends \ curl gcc libffi-dev unzip \ chromium fonts-liberation fonts-dejavu-core fontconfig \ nginx supervisor && \ ARCH=$(dpkg --print-architecture) && \ curl -fsSL "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_${ARCH}.zip" -o /tmp/tf.zip && \ unzip /tmp/tf.zip -d /usr/local/bin/ && rm /tmp/tf.zip && \ rm -rf /var/lib/apt/lists/* # ── Python deps + OCI CLI ─────────────────────────────────────────────────── COPY backend/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt && \ pip install --no-cache-dir oci-cli # ── Backend app ───────────────────────────────────────────────────────────── COPY backend/app.py . COPY backend/cis_reports.py . COPY backend/mcp_cis_server.py . COPY backend/gen_tf_reference.py . # ── Frontend (pre-built React SPA) ───────────────────────────────────────── RUN rm -rf /usr/share/nginx/html/* COPY frontend/dist /usr/share/nginx/html/app # ── Nginx config (proxy to localhost instead of backend hostname) ─────────── RUN printf 'map $uri $empty {\n default "";\n}\n\nserver {\n listen 8080;\n server_name _;\n client_max_body_size 50M;\n absolute_redirect off;\n\n location / {\n root /usr/share/nginx/html/app;\n try_files $uri $uri/ /index.html;\n add_header Cache-Control "no-cache, no-store, must-revalidate" always;\n add_header X-Frame-Options "DENY" always;\n add_header X-Content-Type-Options "nosniff" always;\n add_header X-XSS-Protection "1; mode=block" always;\n add_header Referrer-Policy "strict-origin-when-cross-origin" always;\n add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;\n }\n\n location /api/ {\n proxy_pass http://127.0.0.1:8000/api/;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_read_timeout 900s;\n proxy_send_timeout 900s;\n proxy_connect_timeout 60s;\n add_header X-Frame-Options "SAMEORIGIN" always;\n add_header X-Content-Type-Options "nosniff" always;\n }\n}\n' > /etc/nginx/sites-available/default # ── Supervisord config ────────────────────────────────────────────────────── RUN printf '[supervisord]\nnodaemon=true\nuser=root\nlogfile=/var/log/supervisor/supervisord.log\nlogfile_maxbytes=10MB\n\n[program:backend]\ncommand=runuser -u agent -- uvicorn app:app --host 127.0.0.1 --port 8000 --workers 8\ndirectory=/app\nautostart=true\nautorestart=true\nstdout_logfile=/dev/fd/1\nstdout_logfile_maxbytes=0\nstderr_logfile=/dev/fd/2\nstderr_logfile_maxbytes=0\n\n[program:nginx]\ncommand=nginx -g "daemon off;"\nautostart=true\nautorestart=true\nstdout_logfile=/dev/fd/1\nstdout_logfile_maxbytes=0\nstderr_logfile=/dev/fd/2\nstderr_logfile_maxbytes=0\n' > /etc/supervisor/conf.d/app.conf # ── Non-root user + data dir ──────────────────────────────────────────────── RUN groupadd -r agent && useradd -r -g agent -d /app -s /bin/bash agent && \ mkdir -p /data /var/log/supervisor && chown -R agent:agent /app /data # ── Generate Terraform resource reference ─────────────────────────────────── RUN python gen_tf_reference.py || echo "WARN: tf reference generation skipped" # ── Entrypoint ────────────────────────────────────────────────────────────── RUN printf '#!/bin/bash\nchown -R agent:agent /data 2>/dev/null || true\nexec supervisord -c /etc/supervisor/conf.d/app.conf\n' > /entrypoint.sh && \ chmod +x /entrypoint.sh VOLUME /data EXPOSE 8080 ENTRYPOINT ["/entrypoint.sh"]