refactor: centralize deployment settings in top-level config.py - #345
Merged
Conversation
Load and validate deployment settings once at startup via a pydantic-settings `Settings` eager singleton (`settings = Settings()`). Replace scattered os.environ reads across mongo/, model/, and app.py with `config.settings`, and delete mongo/config.py plus the ad-hoc setup_smtp() startup check (its SMTP cross-field rule moves into a model_validator). Two deliberate behavior changes: - SUBMISSION_TMP_DIR default now uses tempfile.mkdtemp(suffix= 'noj-submissions'), keeping a persistent directory (the old TemporaryDirectory(...).name kept no reference and was GC-deleted) and fixing the 'noj-submisisons' typo. - FLASK_DEBUG renamed to DEBUG (bool, default False); its only consumer is MinioClient's secure=not DEBUG. Tests that mutated os.environ for these vars now patch the singleton.
as535364
requested review from
Bogay and
Copilot
and removed request for
Copilot
July 20, 2026 10:47
Contributor
There was a problem hiding this comment.
Pull request overview
This PR centralizes previously scattered environment-variable reads into a single top-level config.py using pydantic-settings (Settings + import-time singleton settings), and updates runtime modules/tests to consistently read configuration from config.settings.
Changes:
- Introduce
config.Settings(pydantic-settings) and a module-levelsettings = Settings()singleton, with cross-field SMTP validation and typed parsing. - Migrate config consumers (Mongo engine/utils/user/submission, SMTP utils, app startup logging) to read from
settings, and removemongo/config.py. - Update tests to avoid runtime
os.environmutation by patchingsettings/ constructingSettings()in isolation; addtests/test_config.py.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
config.py |
New centralized typed settings model and import-time singleton. |
app.py |
Remove setup_smtp(); emit startup SMTP logs based on settings. |
mongo/config.py |
Removed legacy env-var module for MinIO/FLASK_DEBUG. |
mongo/engine.py |
Read MONGO_HOST from settings. |
mongo/utils.py |
Switch TESTING/Redis/MinIO config reads to settings. |
mongo/user.py |
Switch JWT config reads to settings (keeping JWT_EXP as days). |
mongo/submission.py |
Use settings.SUBMISSION_TMP_DIR for submission tmp path. |
model/utils/smtp.py |
Read SMTP configuration via settings. |
tests/conftest.py |
Patch settings (MinIO creds, DEBUG, TESTING) instead of env/module globals. |
tests/test_config.py |
New unit tests for defaults, parsing, SMTP cross-field validation, tmp dir behavior. |
tests/test_copycat.py |
Patch settings.TESTING instead of deleting TESTING env var. |
tests/test_mongo_utils.py |
Patch settings.REDIS_PORT instead of env var. |
tests/test_smtp.py |
Patch settings.SMTP_SERVER instead of env var. |
tests/unittest/submission/test_target_sandbox.py |
Use autouse fixture to isolate DB/config and set settings.TESTING. |
pyproject.toml |
Add pydantic-settings dependency. |
poetry.lock |
Lock updated to include pydantic-settings and transitive deps. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| SMTP_NOREPLY: Optional[str] = None | ||
| SMTP_NOREPLY_PASSWORD: Optional[str] = None | ||
|
|
||
| SUBMISSION_TMP_DIR: str = None # type: ignore[assignment] |
Member
Author
There was a problem hiding this comment.
已改用 Field(default_factory=...),原本的 before-validator 和 type: ignore 一併移除,行為不變(env 有設時 factory 不會執行):7488795
Addresses Copilot review: the str-annotated field had a None default with a type: ignore. default_factory keeps the same behavior (mkdtemp only when the env var is unset) without the type mismatch.
mkdtemp(suffix=...) appends the suffix, so endswith is the precise assertion; a substring check would also pass on prefixed paths.
Bogay
requested changes
Jul 20, 2026
The old-TemporaryDirectory rationale only made sense at migration time; the behavior change is documented in the PR description.
as535364
added a commit
that referenced
this pull request
Jul 20, 2026
…ting (ADR-0005) RUNNER_REGISTRATION_TOKEN moves from a live env accessor in dispatch/config.py to a field on the centralized Settings (top-level config.py, #345), loaded and validated once at startup. Unset/empty still means registration disabled (fail closed); rotating the shared secret now takes a restart, per-runner revocation stays immediate. dispatch/config.py is renamed to dispatch/params.py and now holds only the spec §13 protocol parameters — the dispatch module no longer reads settings of its own.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #343.
把散在各模組的環境變數讀取集中到頂層
config.py,用 pydantic-settings 的Settings在 import 時一次載入並驗證,之後程式一律讀config.settings。搬遷的有MINIO_*(原mongo/config.py,已刪)、MONGO_HOST、JWT_*、TESTING、REDIS_*、SUBMISSION_TMP_DIR、SMTP_*。原本setup_smtp()裡「SMTP_SERVER有設但SMTP_NOREPLY未設就擋啟動」的規則搬進Settings的 model_validator,函式本身移除;啟動時那兩條 info log 改由create_app依 settings 判斷後照舊輸出。行為凍結,除了兩個刻意的變更:
SUBMISSION_TMP_DIR預設值改用tempfile.mkdtemp()。舊寫法TemporaryDirectory(...).name沒有把物件留住,GC 一回收目錄就被刪掉。順手修了noj-submisisons這個 typo。FLASK_DEBUG改名DEBUG。外部部署沒有任何地方設這個變數,唯一消費者是mongo/utils.py給 MinIO client 的secure=。另外三件事需要說明。typed settings 會讓無效的值(像
DEBUG=garbage、REDIS_PORT='')在啟動時就直接失敗;原本的程式碼會默默吃下這種值,等真正用到才爆,或根本不會爆。變數沒設仍然不擋啟動,只有設了無效值才會擋。issue 的測試清單漏了tests/test_copycat.py:它在 runtime 改TESTINGenv,讀取點搬到 settings 後delenv變成 no-op,背景執行緒不會啟動,測試會 hang 死,所以一併遷移。migrations/__init__.py的MONGO_HOST讀取刻意不動,它不在 issue 的搬遷清單內,migration script 也是獨立執行的。測試方面新增
tests/test_config.py(21 個案例:各欄位預設值、SMTP cross-field 驗證、TESTING寬鬆解析、SUBMISSION_TMP_DIR覆寫優先),原本 runtime 改os.environ的測試都改成monkeypatch.setattr(settings, ...)。全套件 509 passed、yapf diff 乾淨。新依賴:pydantic-settings 2.14.2。