Config Inspector (סקירת משתני סביבה)
מה זה Config Inspector?
Config Inspector הוא כלי אדמין שמציג תמונת מצב של הקונפיגורציה: אילו משתני סביבה מוגדרים, מה הערך הפעיל שלהם, מה ברירת המחדל בקוד, והאם הערך שונה מברירת המחדל.
הכלי נותן מענה לשאלות שקשה לענות עליהן מול Render Dashboard:
האם המשתנה הזה בכלל מוגדר, או שאנחנו רצים על ברירת מחדל?
מה ברירת המחדל שבקוד, ובמה הערך שברנדר שונה ממנה?
לאיזה שירות שייך המשתנה, ואיפה צריך להגדיר אותו?
אילו משתנים הכרחיים חסרים?
איך נכנסים?
דרך ה-UI: דף Settings ← קטגוריית כלי אדמין ← Config Inspector
ישירות:
GET /admin/config-inspector
הערה
הדף זמין רק לאדמינים (@admin_required ב-webapp/app.py). ערך מוצג ממוסך
(********) רק אם הוא מסווג כרגיש — לפי שם המשתנה או לפי סימון מפורש
sensitive=True; כל שאר הערכים מוצגים כמות שהם. הסיווג מפורט ב-
מיסוך ערכים רגישים, וחשוב לקרוא אותו לפני הוספת משתנה שהוא סוד.
שני עמודים — ולמה
הדף מחולק לשני טאבים, וההפרדה ביניהם אינה קוסמטית אלא נובעת ממגבלה אמיתית.
עמוד 1: שירות ה-Webapp (עם Status וערך פעיל)
העמוד הראשון מציג רק משתנים ששייכים (גם) לשירות ה-Webapp, ורק הם מקבלים עמודות
Status ו-Active Value.
הסיבה: ה-Config Inspector הוא קוד שרץ בתוך תהליך ה-Webapp. כשהוא קורא
os.environ הוא רואה אך ורק את משתני הסביבה של אותו תהליך. הבוט, שרת ה-MCP וה-webserver
הם שירותי Render נפרדים, כל אחד עם ENV משלו — ותהליך ה-Webapp פשוט אינו יכול לראות
אותם.
לכן, אילו היינו מציגים Status למשתנה של הבוט, הוא היה מוצג כ-Default או Missing
גם כשהוא מוגדר מצוין בשירות הבוט. מידע שגוי גרוע מהיעדר מידע — ולכן העמוד הראשון
מסונן, והסינון נאכף בקוד:
# services/config_inspector_service.py — get_config_overview
for definition in self.CONFIG_DEFINITIONS.values():
# עמוד ראשי: רק משתנים ששייכים (גם) לשירות ה-webapp
if "webapp" not in definition.services:
continue
בראש העמוד מוצגים כרטיסי סיכום (סה“כ / שונו מדיפולט / הוגדרו בסביבה / חסרים / ברירת מחדל),
שורת סינון (קטגוריה + סטטוס), פירוט לפי קטגוריות, וטבלת המשתנים המלאה. כפתור
”העתק הכל“ מייצא את השורות המוצגות בפורמט KEY=VALUE (שורות .env).
עמוד 2: שירותים אחרים — Bot / MCP / Webserver
העמוד השני מציג את כל המשתנים שיש להם שירות שאינו webapp — כולל משתנים משותפים שמופיעים גם בעמוד הראשון.
מה מוצג: Key / שירות / Default Value / תיאור.
מה לא מוצג, ולמה: אין כאן ``Status`` ואין ``Active Value`` — מאותה סיבה בדיוק שתוארה למעלה. הערכים חיים בתהליכים אחרים ואינם נגישים מכאן. לערכים בפועל יש לבדוק ב-Render Dashboard של השירות הרלוונטי.
שורה של משתנה שמוגדר גם בוובאפ מסומנת בתגית ”גם Webapp“ — הערך שלה מופיע בעמוד הראשון.
שורת הסינון בעמוד זה היא לפי קטגוריה ולפי שירות (ולא לפי סטטוס — אין כאן סטטוס).
”העתק הכל“ בעמוד זה מעתיק
KEY=<ברירת מחדל>ומציין זאת מפורשות, כדי שלא ייווצר רושם שאלו הערכים החיים.
ארבעת הסטטוסים — ואיך נמנעים מ-”Modified“ שגוי
סטטוס |
מתי מתקבל |
משמעות |
|---|---|---|
|
אין ערך בסביבה ויש ברירת מחדל בקוד — או שהערך בסביבה זהה לברירת המחדל |
רצים על ברירת המחדל. אין מה לעשות |
|
יש ערך בסביבה ו**אין ברירת מחדל בקוד** |
המשתנה הוגדר (למשל ברנדר). זו אינה סטייה — אין דיפולט שממנו אפשר לסטות |
|
יש ערך בסביבה, יש ברירת מחדל, והם שונים |
סטייה אמיתית מברירת המחדל — כאן צריך להסתכל |
|
אין ערך בסביבה, אין ברירת מחדל, והמשתנה מסומן |
משתנה הכרחי חסר. מוצג גם כאזהרה בראש הדף |
הלוגיקה ממומשת ב-ConfigService.determine_status.
אזהרה
הכלל השורשי: ה-default שרשום ב-ConfigDefinition חייב להיות זהה תו-בתו
לברירת המחדל האמיתית בקוד. אחרת מתקבל סטטוס Modified שקרי — משתנה שמוגדר נכון
ייראה כאילו מישהו שינה אותו, ואי אפשר יהיה לסמוך על העמודה הזו.
שתי הטעויות שמייצרות Modified שגוי:
1. דיפולט משוער במקום זה שבקוד. אם הקוד עושה os.getenv("X", "60") אבל בהגדרה
נרשם default="30" — משתנה שמוגדר ל-60 ברנדר יוצג כ-Modified, למרות שהוא זהה
לברירת המחדל בפועל.
2. המצאת דיפולט למשתנה שאין לו דיפולט בקוד. אם בקוד יש os.getenv("TOKEN") בלי
ערך שני, אין ברירת מחדל — וההגדרה צריכה להשאיר default ריק. אז הסטטוס יהיה Set
(נכון), ולא Modified (מטעה).
הבדיקה לפני הוספה — לאתר את ברירת המחדל האמיתית ולהעתיק אותה כמות שהיא:
rg -n -w 'MY_VAR' -t py -g '!tests/**'
-w מחפש את שם המשתנה כמילה שלמה, ולכן תופס גם os.getenv("MY_VAR"), גם
os.getenv('MY_VAR') וגם config.MY_VAR, בלי להיתפס ל-MY_VAR_OTHER.
לאיזה שירות שייך המשתנה? — לבדוק, לא לנחש
השדה services בהגדרה קובע באיזה עמוד המשתנה יופיע. שיוך שגוי מייצר רעש: משתנה
של הוובאפ בלבד שמסומן כשייך לכולם מופיע בעמוד 2 כאילו צריך להגדיר אותו בארבעה מקומות.
חשוב
אל תסיקו את השיוך משם המשתנה. שם שנשמע גלובלי (PUSH_*, UPTIME_*,
MAINTENANCE_*) לא אומר שהמשתנה נצרך בכל השירותים. בסבב ניקוי אחד הוסרו 68 שיוכים
שגויים שנקבעו לפי תחושה.
הנוהל (שלושה צעדים):
למצוא איפה המשתנה נצרך בפועל — חיפוש אחד תופס גם
os.getenv(בכל סוג גרשיים) וגם גישה דרך אובייקט הקונפיג (config.MY_VAR):rg -n -w 'MY_VAR' -t py -g '!tests/**'
לזהות לאיזה שירות שייך הקובץ שנמצא — לפי נקודות הכניסה:
קובץ / תיקייה
שירות
נקודת כניסה
main.py,handlers/,*_handler.pybotmain.pywebapp/webappwebapp/app.pymcp_server/mcpmcp_server/app.pyservices/webserver.pywebserverservices/webserver.pyscripts/scriptsסקריפטים ידניים/CI
קובץ משותף — לפי שרשרת ה-imports. קובץ כמו
database/,services/אוutils.pyאינו שייך לשירות מסוים בפני עצמו: הוא שייך לשירות רק אם הוא נטען בשרשרת ה-imports של אותה נקודת כניסה. משתנה שנצרך רק ב-webapp/app.pyאינו שייך ל-bot/mcp/webserver, נקודה.
טיפ
PORT הוא חריג מוצדק: הוא לא בהכרח מופיע בקוד של השירות, אבל כל שירות web צריך
אותו בפקודת ההרצה. חריגים כאלה — לתעד בהערה ליד ההגדרה.
משתנה שמשרת כמה שירותים — לתעד בכל המקומות
משתנה יכול להיות מוגדר בכמה שירותי Render במקביל (למשל MONGODB_URL). במקרה כזה
מתעדים אותו בכל המקומות הרלוונטיים, כל אחד במקום שלו — ולא בוחרים ”בית“ אחד:
``services`` בהגדרה — כל השירותים, לא רק העיקרי:
"MONGODB_URL": ConfigDefinition( key="MONGODB_URL", services=("webapp", "bot", "mcp", "webserver"), ... )
``docs/environment-variables.rst`` — עמודת ”רכיב“ בטבלה המרכזית חייבת לשקף את אותה רשימת שירותים. השורה הזו היא הרפרנס לאנשי DevOps.
תיאור תואם בשני המקומות — ה-
descriptionשב-ConfigDefinition(מה שמוצג בטבלת ה-Config Inspector) וההסבר שב-environment-variables.rstצריכים לומר את אותו דבר. שני התיאורים נקראים זה לצד זה כשמדבגים תקלת קונפיגורציה, ותיאורים סותרים גרועים מהיעדר תיאור.
מיסוך ערכים רגישים
ערך ממוסך (********) בשני מקרים:
לפי שם המשתנה —
SENSITIVE_PATTERNS(TOKEN,KEY,PASSWORD,SECRET,URI,CREDENTIALS,AUTH,PRIVATE,CERT,DSN,CONNECTION_STRING).לפי סימון מפורש —
sensitive=Trueבהגדרה.
הערה
URL הוסר מהרשימה בכוונה: כתובת ציבורית (WEBAPP_URL, MCP_SERVER_URL)
אינה סוד, ומיסוכה הפך את הדף לחסר תועלת. כתובת שמכילה credentials — למשל
MONGODB_URL בפורמט scheme://user:pass@host — מסומנת sensitive=True
מפורשות, ובנוסף קיים זיהוי אוטומטי של תבנית ה-credentials בתוך URL.
המסקנה המעשית: משתנה חדש שהוא סוד ושמו אינו מכיל אחת מהמילים ברשימה — סמנו ``sensitive=True`` ידנית.
צ’קליסט: הוספת משתנה סביבה חדש
לאתר את הצריכה בפועל —
grepעל שם המשתנה (לאיזה שירות שייך המשתנה? — לבדוק, לא לנחש).להעתיק את ברירת המחדל מהקוד תו-בתו — ואם אין דיפולט, להשאיר ריק כדי לקבל
SetולאModified(ארבעת הסטטוסים — ואיך נמנעים מ-”Modified“ שגוי).לקבוע ``services`` לפי הצריכה שנמצאה — כל השירותים שצורכים, ורק הם.
``sensitive=True`` אם זה סוד ששמו לא נתפס אוטומטית (מיסוך ערכים רגישים).
לעדכן את ``docs/environment-variables.rst`` — שורה בטבלה המרכזית עם עמודת ”רכיב“ תואמת ותיאור זהה. זו חובה לפי ההנחיה שבראש אותו עמוד.
לוודא בדף שהמשתנה מופיע בעמוד הנכון ושהסטטוס הגיוני (משתנה שלא נגעתם בו ברנדר אמור להיות
Default, לאModified).
טסטים: tests/test_config_inspector_service.py.
ראו גם
משתני סביבה - רפרנס — הרפרנס המלא של משתני הסביבה
Cache Inspector (לוח בקרה של Redis) — כלי אדמין מקביל ל-Redis