Ajayyy00 Claude Sonnet 4.6 commited on
Commit
0cd6bdd
Β·
1 Parent(s): 1080341

Split architecture: Trainer=backend, Demo=dashboard

Browse files

Dockerfile
- Replaces hard-coded uvicorn CMD with /bin/sh /app/start.sh
- Sets ownership correctly before switching to non-root user

start.sh (new)
- Reads BACKEND_URL env var β†’ writes it into dashboard/js/config.js
- Reads SERVE_DASHBOARD_ONLY env var:
0 / unset β†’ full stack via dashboard_server.py (Trainer Space)
1 β†’ static-only via serve_demo.py (Demo Space)

serve_demo.py (new)
- Minimal FastAPI + StaticFiles server for the Demo space
- Serves dashboard/ on port 7860 with CORS enabled

dashboard/js/config.js (new)
- Sets window.CYBERSOC_BACKEND_URL = '' by default
- Overwritten at container startup by start.sh when BACKEND_URL is set

dashboard/js/api.js
- Reads window.CYBERSOC_BACKEND_URL set by config.js
- _wsUrl() and _httpBase() use the override URL when set,
fall back to same-origin auto-detection when empty

dashboard/index.html
- Loads js/config.js before api.js so the override is available

HF Space setup:
CyberSOC-trainer β†’ no extra env vars (full backend mode)
Demo β†’ SERVE_DASHBOARD_ONLY=1
BACKEND_URL=https://ajay00747-cybersoc-trainer.hf.space

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (6) hide show
  1. Dockerfile +14 -10
  2. dashboard/index.html +1 -0
  3. dashboard/js/api.js +15 -0
  4. dashboard/js/config.js +12 -0
  5. serve_demo.py +43 -0
  6. start.sh +37 -0
Dockerfile CHANGED
@@ -1,19 +1,23 @@
1
  FROM python:3.10-slim
2
 
3
- # Create user with home directory
4
  RUN useradd -m -u 1000 user
5
- USER user
6
- ENV PATH="/home/user/.local/bin:$PATH"
7
 
8
  WORKDIR /app
9
 
10
- # Copy requirements and install
11
- COPY --chown=user ./requirements.txt requirements.txt
12
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
13
 
14
- # Copy all environment files
15
- COPY --chown=user . /app
 
 
 
 
16
 
17
- # The hackathon expects the OpenEnv Server to run on 7860 for Spaces Gradio endpoints
18
- # We will use uvicorn to host the app which complies with the spec
19
- CMD ["uvicorn", "dashboard_server:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
 
1
  FROM python:3.10-slim
2
 
3
+ # Create non-root user
4
  RUN useradd -m -u 1000 user
 
 
5
 
6
  WORKDIR /app
7
 
8
+ # Install dependencies as root so pip cache is shared
9
+ COPY ./requirements.txt requirements.txt
10
  RUN pip install --no-cache-dir --upgrade -r requirements.txt
11
 
12
+ # Copy project files and set ownership
13
+ COPY . /app
14
+ RUN chmod +x /app/start.sh && chown -R user:user /app
15
+
16
+ USER user
17
+ ENV PATH="/home/user/.local/bin:$PATH"
18
 
19
+ # start.sh reads BACKEND_URL and SERVE_DASHBOARD_ONLY env vars:
20
+ # Trainer Space β†’ SERVE_DASHBOARD_ONLY unset β†’ full backend (dashboard_server.py)
21
+ # Demo Space β†’ SERVE_DASHBOARD_ONLY=1 β†’ static dashboard only (serve_demo.py)
22
+ # BACKEND_URL=https://ajay00747-cybersoc-trainer.hf.space
23
+ CMD ["/bin/sh", "/app/start.sh"]
dashboard/index.html CHANGED
@@ -290,6 +290,7 @@
290
  </main><!-- /main-grid -->
291
 
292
  <!-- Scripts (order matters) -->
 
293
  <script src="js/animations.js"></script>
294
  <script src="js/api.js"></script>
295
  <script src="js/graphs.js"></script>
 
290
  </main><!-- /main-grid -->
291
 
292
  <!-- Scripts (order matters) -->
293
+ <script src="js/config.js"></script>
294
  <script src="js/animations.js"></script>
295
  <script src="js/api.js"></script>
296
  <script src="js/graphs.js"></script>
dashboard/js/api.js CHANGED
@@ -49,8 +49,22 @@ const API = (() => {
49
  }
50
  })();
51
 
 
 
 
 
 
 
 
 
 
52
  // ── WebSocket URL ──────────────────────────────────────────────────────────
53
  function _wsUrl() {
 
 
 
 
 
54
  if (typeof window === 'undefined') {
55
  return `ws://localhost:8000/ws/${_sessionId}`;
56
  }
@@ -63,6 +77,7 @@ const API = (() => {
63
 
64
  // HTTP base URL β€” used only by checkConnection() which pings /health over HTTP
65
  function _httpBase() {
 
66
  if (typeof window === 'undefined') return 'http://localhost:8000';
67
  const { protocol, hostname, port } = window.location;
68
  if (protocol === 'file:') return 'http://localhost:8000';
 
49
  }
50
  })();
51
 
52
+ // ── External backend override (set by dashboard/js/config.js in Demo mode) ─
53
+ // config.js sets window.CYBERSOC_BACKEND_URL to the trainer Space URL.
54
+ // Empty string β†’ auto-detect from page origin (default for full-stack mode).
55
+ const _backendOverride = (
56
+ typeof window !== 'undefined' &&
57
+ typeof window.CYBERSOC_BACKEND_URL === 'string' &&
58
+ window.CYBERSOC_BACKEND_URL.trim()
59
+ ) ? window.CYBERSOC_BACKEND_URL.trim().replace(/\/$/, '') : '';
60
+
61
  // ── WebSocket URL ──────────────────────────────────────────────────────────
62
  function _wsUrl() {
63
+ if (_backendOverride) {
64
+ const wsProto = _backendOverride.startsWith('https') ? 'wss:' : 'ws:';
65
+ const host = _backendOverride.replace(/^https?:\/\//, '');
66
+ return `${wsProto}//${host}/ws/${_sessionId}`;
67
+ }
68
  if (typeof window === 'undefined') {
69
  return `ws://localhost:8000/ws/${_sessionId}`;
70
  }
 
77
 
78
  // HTTP base URL β€” used only by checkConnection() which pings /health over HTTP
79
  function _httpBase() {
80
+ if (_backendOverride) return _backendOverride;
81
  if (typeof window === 'undefined') return 'http://localhost:8000';
82
  const { protocol, hostname, port } = window.location;
83
  if (protocol === 'file:') return 'http://localhost:8000';
dashboard/js/config.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // CyberSOC Backend URL Configuration
2
+ // -------------------------------------------------------------
3
+ // Leave as empty string when the dashboard and backend are on
4
+ // the same origin (default for the CyberSOC-upgraded space).
5
+ //
6
+ // Set to the trainer Space URL for standalone Dashboard mode:
7
+ // window.CYBERSOC_BACKEND_URL = 'https://ajay00747-cybersoc-trainer.hf.space';
8
+ //
9
+ // In production this file is overwritten at container startup by
10
+ // start.sh using the BACKEND_URL environment variable.
11
+ // -------------------------------------------------------------
12
+ window.CYBERSOC_BACKEND_URL = '';
serve_demo.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Minimal static file server for the CyberSOC Demo HF Space.
3
+
4
+ Serves the dashboard/ directory on port 7860.
5
+ The BACKEND_URL environment variable is injected into
6
+ dashboard/js/config.js at startup by start.sh before this
7
+ process is launched.
8
+ """
9
+
10
+ import os
11
+ import uvicorn
12
+ from fastapi import FastAPI
13
+ from fastapi.responses import RedirectResponse
14
+ from fastapi.staticfiles import StaticFiles
15
+ from fastapi.middleware.cors import CORSMiddleware
16
+
17
+ app = FastAPI(title="CyberSOC Demo Dashboard")
18
+
19
+ app.add_middleware(
20
+ CORSMiddleware,
21
+ allow_origins=["*"],
22
+ allow_methods=["*"],
23
+ allow_headers=["*"],
24
+ )
25
+
26
+
27
+ @app.get("/")
28
+ def root():
29
+ return RedirectResponse(url="/index.html")
30
+
31
+
32
+ @app.get("/health")
33
+ def health():
34
+ return {"status": "ok", "service": "cybersoc-demo"}
35
+
36
+
37
+ # Serve everything in the dashboard/ folder
38
+ _dashboard_dir = os.path.join(os.path.dirname(__file__), "dashboard")
39
+ app.mount("/", StaticFiles(directory=_dashboard_dir, html=True), name="static")
40
+
41
+
42
+ if __name__ == "__main__":
43
+ uvicorn.run(app, host="0.0.0.0", port=7860)
start.sh ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/sh
2
+ # CyberSOC container startup script
3
+ #
4
+ # Environment variables (set in HF Space settings):
5
+ # BACKEND_URL β€” URL of the CyberSOC trainer Space, e.g.
6
+ # https://ajay00747-cybersoc-trainer.hf.space
7
+ # Leave unset for same-origin (full-stack mode).
8
+ # SERVE_DASHBOARD_ONLY β€” Set to "1" for the Demo space (static files only).
9
+ # Leave unset or "0" for the Trainer space (full API).
10
+ #
11
+ # Demo Space settings:
12
+ # BACKEND_URL = https://ajay00747-cybersoc-trainer.hf.space
13
+ # SERVE_DASHBOARD_ONLY = 1
14
+ #
15
+ # Trainer Space settings:
16
+ # (no extra env vars required)
17
+
18
+ set -e
19
+
20
+ # ── Inject backend URL into config.js ────────────────────────────────────────
21
+ CONFIG_JS="/app/dashboard/js/config.js"
22
+ if [ -n "${BACKEND_URL}" ]; then
23
+ printf "window.CYBERSOC_BACKEND_URL = '%s';\n" "${BACKEND_URL}" > "${CONFIG_JS}"
24
+ echo "[startup] Demo mode β€” backend URL: ${BACKEND_URL}"
25
+ else
26
+ printf "window.CYBERSOC_BACKEND_URL = '';\n" > "${CONFIG_JS}"
27
+ echo "[startup] Full-stack mode β€” backend on same origin"
28
+ fi
29
+
30
+ # ── Launch the correct server ─────────────────────────────────────────────────
31
+ if [ "${SERVE_DASHBOARD_ONLY:-0}" = "1" ]; then
32
+ echo "[startup] Serving dashboard only (serve_demo.py) on port 7860"
33
+ exec python /app/serve_demo.py
34
+ else
35
+ echo "[startup] Serving full stack (dashboard_server.py) on port 7860"
36
+ exec uvicorn dashboard_server:app --host 0.0.0.0 --port 7860
37
+ fi