Dmitry Beresnev commited on
Commit ·
c376717
1
Parent(s): 2a70ca5
add auth form, fix dockerfile and supervisord conf
Browse files- Dockerfile +6 -0
- app.py +71 -0
- supervisord.conf +1 -1
Dockerfile
CHANGED
|
@@ -44,6 +44,9 @@ ENV OPENCLAW_CUSTOM_BASE_URL=https://researchengineering-agi.hf.space/v1
|
|
| 44 |
ENV OPENCLAW_CUSTOM_MODEL_ID=deepseek-chat
|
| 45 |
ENV OPENCLAW_CUSTOM_PROVIDER_ID=researchengineering-agi-hf-space
|
| 46 |
ENV OPENCLAW_CUSTOM_COMPATIBILITY=anthropic
|
|
|
|
|
|
|
|
|
|
| 47 |
ENV OPENCLAW_GATEWAY_BIND=lan
|
| 48 |
ENV OPENCLAW_BOOTSTRAP_ONBOARD=1
|
| 49 |
ENV OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw
|
|
@@ -51,6 +54,9 @@ ENV OPENCLAW_ALLOWED_ORIGINS=https://researchengineering-agi-assistant.hf.space,
|
|
| 51 |
ENV OPENCLAW_TRUSTED_PROXIES=127.0.0.1,::1
|
| 52 |
ENV OPENCLAW_CONTROL_UI_ALLOW_INSECURE_AUTH=1
|
| 53 |
ENV OPENCLAW_CONTROL_UI_DISABLE_DEVICE_AUTH=1
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
RUN mkdir -p /app/vault /app/.openclaw/state
|
| 56 |
|
|
|
|
| 44 |
ENV OPENCLAW_CUSTOM_MODEL_ID=deepseek-chat
|
| 45 |
ENV OPENCLAW_CUSTOM_PROVIDER_ID=researchengineering-agi-hf-space
|
| 46 |
ENV OPENCLAW_CUSTOM_COMPATIBILITY=anthropic
|
| 47 |
+
ENV OPENCLAW_CUSTOM_API_KEY=
|
| 48 |
+
ENV OPENCLAW_CUSTOM_API_KEY_OPTIONAL=1
|
| 49 |
+
ENV OPENCLAW_CUSTOM_API_KEY_PLACEHOLDER=no-key
|
| 50 |
ENV OPENCLAW_GATEWAY_BIND=lan
|
| 51 |
ENV OPENCLAW_BOOTSTRAP_ONBOARD=1
|
| 52 |
ENV OPENCLAW_CONTROL_UI_BASE_PATH=/openclaw
|
|
|
|
| 54 |
ENV OPENCLAW_TRUSTED_PROXIES=127.0.0.1,::1
|
| 55 |
ENV OPENCLAW_CONTROL_UI_ALLOW_INSECURE_AUTH=1
|
| 56 |
ENV OPENCLAW_CONTROL_UI_DISABLE_DEVICE_AUTH=1
|
| 57 |
+
ENV STREAMLIT_AUTH_ENABLED=1
|
| 58 |
+
ENV STREAMLIT_AUTH_USERNAME=
|
| 59 |
+
ENV STREAMLIT_AUTH_PASSWORD=
|
| 60 |
|
| 61 |
RUN mkdir -p /app/vault /app/.openclaw/state
|
| 62 |
|
app.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import json
|
|
|
|
| 2 |
import os
|
| 3 |
import re
|
| 4 |
import shutil
|
|
@@ -46,6 +47,9 @@ STREAMLIT_ERR_LOG_PATH = Path("/tmp/streamlit.err.log")
|
|
| 46 |
STREAMLIT_LOG_PATH = Path("/tmp/streamlit.log")
|
| 47 |
CADDY_ERR_LOG_PATH = Path("/tmp/caddy.err.log")
|
| 48 |
CADDY_LOG_PATH = Path("/tmp/caddy.log")
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
|
| 51 |
def resolve_openclaw_bin() -> str | None:
|
|
@@ -516,10 +520,77 @@ def render_backtest_visuals(result, data: pd.DataFrame, params: dict) -> None:
|
|
| 516 |
st.dataframe(result.trades, use_container_width=True)
|
| 517 |
|
| 518 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 519 |
st.set_page_config(page_title="OpenClaw Control Center", layout="wide")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 520 |
st.title("OpenClaw Control Center")
|
| 521 |
st.caption("Manage gateway runtime, config, environment, and test calls from one UI.")
|
| 522 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
init_state()
|
| 524 |
pull_logs()
|
| 525 |
|
|
|
|
| 1 |
import json
|
| 2 |
+
import hmac
|
| 3 |
import os
|
| 4 |
import re
|
| 5 |
import shutil
|
|
|
|
| 47 |
STREAMLIT_LOG_PATH = Path("/tmp/streamlit.log")
|
| 48 |
CADDY_ERR_LOG_PATH = Path("/tmp/caddy.err.log")
|
| 49 |
CADDY_LOG_PATH = Path("/tmp/caddy.log")
|
| 50 |
+
STREAMLIT_AUTH_ENABLED = os.getenv("STREAMLIT_AUTH_ENABLED", "1") == "1"
|
| 51 |
+
STREAMLIT_AUTH_USERNAME = os.getenv("STREAMLIT_AUTH_USERNAME", "").strip()
|
| 52 |
+
STREAMLIT_AUTH_PASSWORD = os.getenv("STREAMLIT_AUTH_PASSWORD", "").strip()
|
| 53 |
|
| 54 |
|
| 55 |
def resolve_openclaw_bin() -> str | None:
|
|
|
|
| 520 |
st.dataframe(result.trades, use_container_width=True)
|
| 521 |
|
| 522 |
|
| 523 |
+
def login_enabled() -> bool:
|
| 524 |
+
return STREAMLIT_AUTH_ENABLED
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
def has_login_credentials() -> bool:
|
| 528 |
+
return bool(STREAMLIT_AUTH_USERNAME and STREAMLIT_AUTH_PASSWORD)
|
| 529 |
+
|
| 530 |
+
|
| 531 |
+
def validate_login(username: str, password: str) -> bool:
|
| 532 |
+
return hmac.compare_digest(username, STREAMLIT_AUTH_USERNAME) and hmac.compare_digest(
|
| 533 |
+
password, STREAMLIT_AUTH_PASSWORD
|
| 534 |
+
)
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
def render_login_form() -> None:
|
| 538 |
+
st.markdown(
|
| 539 |
+
"""
|
| 540 |
+
<style>
|
| 541 |
+
.auth-wrap {display:flex; justify-content:center; margin-top:4vh;}
|
| 542 |
+
.auth-card {
|
| 543 |
+
width: 420px; max-width: 92vw; padding: 1.1rem 1.2rem 1rem 1.2rem;
|
| 544 |
+
border-radius: 14px; border: 1px solid #d8dee9; background: #ffffff;
|
| 545 |
+
box-shadow: 0 8px 24px rgba(16, 24, 40, 0.08);
|
| 546 |
+
}
|
| 547 |
+
.auth-title {font-size:1.2rem; font-weight:700; color:#0f172a; margin-bottom:.25rem;}
|
| 548 |
+
.auth-sub {font-size:.92rem; color:#475467; margin-bottom:.8rem;}
|
| 549 |
+
</style>
|
| 550 |
+
<div class="auth-wrap">
|
| 551 |
+
<div class="auth-card">
|
| 552 |
+
<div class="auth-title">OpenClaw Control Login</div>
|
| 553 |
+
<div class="auth-sub">Sign in to access the control center.</div>
|
| 554 |
+
</div>
|
| 555 |
+
</div>
|
| 556 |
+
""",
|
| 557 |
+
unsafe_allow_html=True,
|
| 558 |
+
)
|
| 559 |
+
with st.form("streamlit_auth_form", clear_on_submit=False):
|
| 560 |
+
username = st.text_input("Username")
|
| 561 |
+
password = st.text_input("Password", type="password")
|
| 562 |
+
submit = st.form_submit_button("Sign in", use_container_width=True)
|
| 563 |
+
if submit:
|
| 564 |
+
if validate_login(username.strip(), password):
|
| 565 |
+
st.session_state["authenticated"] = True
|
| 566 |
+
st.rerun()
|
| 567 |
+
st.error("Invalid username or password.")
|
| 568 |
+
|
| 569 |
+
|
| 570 |
st.set_page_config(page_title="OpenClaw Control Center", layout="wide")
|
| 571 |
+
st.session_state.setdefault("authenticated", False)
|
| 572 |
+
|
| 573 |
+
if login_enabled():
|
| 574 |
+
if not has_login_credentials():
|
| 575 |
+
st.error(
|
| 576 |
+
"UI auth is enabled, but credentials are missing. "
|
| 577 |
+
"Set `STREAMLIT_AUTH_USERNAME` and `STREAMLIT_AUTH_PASSWORD` in Hugging Face Secrets."
|
| 578 |
+
)
|
| 579 |
+
st.stop()
|
| 580 |
+
if not st.session_state.get("authenticated", False):
|
| 581 |
+
render_login_form()
|
| 582 |
+
st.stop()
|
| 583 |
+
|
| 584 |
st.title("OpenClaw Control Center")
|
| 585 |
st.caption("Manage gateway runtime, config, environment, and test calls from one UI.")
|
| 586 |
|
| 587 |
+
if login_enabled():
|
| 588 |
+
with st.sidebar:
|
| 589 |
+
st.success("Authenticated")
|
| 590 |
+
if st.button("Sign out", use_container_width=True):
|
| 591 |
+
st.session_state["authenticated"] = False
|
| 592 |
+
st.rerun()
|
| 593 |
+
|
| 594 |
init_state()
|
| 595 |
pull_logs()
|
| 596 |
|
supervisord.conf
CHANGED
|
@@ -5,7 +5,7 @@ pidfile=/tmp/supervisord.pid
|
|
| 5 |
user=root
|
| 6 |
|
| 7 |
[program:openclaw]
|
| 8 |
-
command=/bin/sh -lc "GATEWAY_BIND=${OPENCLAW_GATEWAY_BIND:-lan}; AUTH_FILE_MAIN=/app/.openclaw/state/agents/main/agent/auth-profiles.json;
|
| 9 |
autorestart=true
|
| 10 |
startsecs=5
|
| 11 |
startretries=20
|
|
|
|
| 5 |
user=root
|
| 6 |
|
| 7 |
[program:openclaw]
|
| 8 |
+
command=/bin/sh -lc "GATEWAY_BIND=${OPENCLAW_GATEWAY_BIND:-lan}; AUTH_FILE_MAIN=/app/.openclaw/state/agents/main/agent/auth-profiles.json; API_KEY_RAW=${OPENCLAW_CUSTOM_API_KEY:-${CUSTOM_API_KEY:-}}; API_KEY=\"$API_KEY_RAW\"; if [ -z \"$API_KEY\" ] && [ \"${OPENCLAW_CUSTOM_API_KEY_OPTIONAL:-1}\" = \"1\" ]; then API_KEY=\"${OPENCLAW_CUSTOM_API_KEY_PLACEHOLDER:-no-key}\"; echo '[onboard] using placeholder custom API key'; fi; if [ \"${OPENCLAW_BOOTSTRAP_ONBOARD:-1}\" = \"1\" ] && [ ! -s \"$AUTH_FILE_MAIN\" ]; then if [ -n \"$API_KEY\" ]; then echo '[onboard] bootstrapping custom provider with API key'; openclaw onboard --non-interactive --mode local --auth-choice custom-api-key --custom-base-url \"${OPENCLAW_CUSTOM_BASE_URL}\" --custom-model-id \"${OPENCLAW_CUSTOM_MODEL_ID}\" --custom-provider-id \"${OPENCLAW_CUSTOM_PROVIDER_ID:-researchengineering-agi-hf-space}\" --custom-compatibility \"${OPENCLAW_CUSTOM_COMPATIBILITY:-anthropic}\" --custom-api-key \"$API_KEY\" --secret-input-mode plaintext --gateway-port 18789 --gateway-bind \"$GATEWAY_BIND\" --skip-skills --accept-risk || true; else echo '[onboard] skipped: no API key or placeholder'; fi; fi; python /app/scripts/bootstrap_gateway_token.py; exec openclaw gateway run --port 18789 --bind \"$GATEWAY_BIND\" --allow-unconfigured --dev"
|
| 9 |
autorestart=true
|
| 10 |
startsecs=5
|
| 11 |
startretries=20
|