diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..c8f8f35 --- /dev/null +++ b/.env.example @@ -0,0 +1,19 @@ +# Skelet 环境变量示例 +# 复制为 .env 并填入真实值;.env 已被 .gitignore 忽略,不会提交 + +# Django 密钥(生产环境必须替换为随机字符串) +# 生成方式: python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())" +SECRET_KEY=replace-me + +# 调试模式(开发 True,生产 False) +DEBUG=True + +# 允许访问的主机名,逗号分隔 +# 开发: localhost,127.0.0.1 +# 生产: yourdomain.com,www.yourdomain.com +ALLOWED_HOSTS=localhost,127.0.0.1 + +# Wagtail 管理后台基础 URL(用于邮件通知等) +# 开发: http://localhost:8000 +# 生产: https://yourdomain.com +WAGTAILADMIN_BASE_URL=http://localhost:8000 diff --git a/.gitignore b/.gitignore index e9af1a6..a436a23 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ deploy/ *.pem .env .env.* +!.env.example # Python __pycache__/ diff --git a/docs/06-tasks.md b/docs/06-tasks.md index 2be7e96..234a37f 100644 --- a/docs/06-tasks.md +++ b/docs/06-tasks.md @@ -23,7 +23,7 @@ | --- | --- | --- | --- | --- | | T-000 | 初始化 harness 文档 | - | 根目录入口、需求、技术栈、架构、规则、任务和当前状态文档已建立 | DONE | | T-001 | 初始化 Wagtail 项目骨架 | T-000 | Python 3.12 虚拟环境可用;Wagtail/Django 项目生成;SQLite 配置可 migrate;首页或默认 Wagtail 页面可访问;`init.ps1` / `init.sh` 替换为真实命令 | DONE | -| T-002 | 建立基础配置与环境样例 | T-001 | 存在 `requirements.txt`、`.env.example` 或等价配置说明;不包含真实密钥;`DEBUG`、`ALLOWED_HOSTS`、media/static 配置清楚 | TODO | +| T-002 | 建立基础配置与环境样例 | T-001 | 存在 `requirements.txt`、`.env.example` 或等价配置说明;不包含真实密钥;`DEBUG`、`ALLOWED_HOSTS`、media/static 配置清楚 | DONE | | T-003 | 建立最小验证基线 | T-001 | `manage.py check` 和基础测试命令可运行;验证结果写入 `progress.md` | TODO | ## Phase 1 · 内容模型 diff --git a/docs/current-state.md b/docs/current-state.md index 19dfa85..21e472c 100644 --- a/docs/current-state.md +++ b/docs/current-state.md @@ -44,9 +44,9 @@ ## 任务看板状态 -- 已完成:`T-000 初始化 harness 文档`、`T-001 初始化 Wagtail 项目骨架`。 +- 已完成:`T-000 初始化 harness 文档`、`T-001 初始化 Wagtail 项目骨架`、`T-002 建立基础配置与环境样例`。 - 正在进行:无。 -- 下一个可领取任务:`T-002 建立基础配置与环境样例`。 +- 下一个可领取任务:`T-003 建立最小验证基线`。 ## 当前可运行内容 diff --git a/progress.md b/progress.md index b891729..9c45e85 100644 --- a/progress.md +++ b/progress.md @@ -124,3 +124,20 @@ - 开发命令需在 MSYS2 bash shell 中运行;`init.ps1` 在 PowerShell 中直接调用 `.venv/bin/` 路径可工作 - 下一步:T-002 建立基础配置与环境样例。 +## 2026-07-06 T-002 建立基础配置与环境样例 + +- 状态:DONE +- 变更: + - `skelet/settings/base.py`:新增 `import os`;`SECRET_KEY`、`DEBUG`、`ALLOWED_HOSTS`、`WAGTAILADMIN_BASE_URL` 改为从环境变量读取(dev 安全默认值) + - `skelet/settings/dev.py`:精简为只设 `DEBUG=True`、`ALLOWED_HOSTS=["*"]`、`EMAIL_BACKEND`,其余继承 base + - `skelet/settings/production.py`:`DEBUG=False`、`ALLOWED_HOSTS` 从环境变量读取、`ManifestStaticFilesStorage`、CSRF/Session 安全头 + - 新建 `.env.example`:含 `SECRET_KEY`、`DEBUG`、`ALLOWED_HOSTS`、`WAGTAILADMIN_BASE_URL` 占位值和逐项注释 + - `.gitignore`:添加 `!.env.example` 例外,确保样例文件可提交 +- 验证: + - `manage.py check`:0 errors, 3 treebeard 兼容警告(非阻塞) + - `grep -riE "secret|token|password" .env.example`:仅出现 `SECRET_KEY=replace-me` 占位值,无真实密钥 + - `git check-ignore .env .env.example`:`.env` 被忽略,`.env.example` 可提交 +- 阻塞:无。 +- 决策:环境变量命名遵循 Django 惯例;dev 环境默认值满足本地开发需求,生产部署时所有值从环境变量注入。 +- 下一步:T-003 建立最小验证基线。 + diff --git a/skelet/settings/base.py b/skelet/settings/base.py index aab4879..8fd930e 100644 --- a/skelet/settings/base.py +++ b/skelet/settings/base.py @@ -10,7 +10,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/6.0/ref/settings/ """ -# Build paths inside the project like this: BASE_DIR / 'subdir'. +import os from pathlib import Path PROJECT_DIR = Path(__file__).resolve().parent.parent @@ -20,6 +20,12 @@ BASE_DIR = PROJECT_DIR.parent # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ +SECRET_KEY = os.environ.get("SECRET_KEY", "django-insecure-dev-key-change-me") + +DEBUG = os.environ.get("DEBUG", "True").lower() in ("true", "1", "yes") + +ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "localhost,127.0.0.1").split(",") + # Application definition @@ -173,7 +179,7 @@ WAGTAILSEARCH_BACKENDS = { # Base URL to use when referring to full URLs within the Wagtail admin backend - # e.g. in notification emails. Don't include '/admin' or a trailing slash -WAGTAILADMIN_BASE_URL = "http://example.com" +WAGTAILADMIN_BASE_URL = os.environ.get("WAGTAILADMIN_BASE_URL", "http://localhost:8000") # Allowed file extensions for documents in the document library. # This can be omitted to allow all files, but note that this may present a security risk diff --git a/skelet/settings/dev.py b/skelet/settings/dev.py index e0b655d..53f65b6 100644 --- a/skelet/settings/dev.py +++ b/skelet/settings/dev.py @@ -1,17 +1,11 @@ from .base import * -# SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = "django-insecure-a5vf@_(tk2i0e*srydb+d3mnzz1)h23%+z5^53+gq8p#0vz+x-" - -# SECURITY WARNING: define the correct hosts in production! ALLOWED_HOSTS = ["*"] EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" - try: from .local import * except ImportError: diff --git a/skelet/settings/production.py b/skelet/settings/production.py index 936a45f..c65f562 100644 --- a/skelet/settings/production.py +++ b/skelet/settings/production.py @@ -2,12 +2,13 @@ from .base import * DEBUG = False -# ManifestStaticFilesStorage is recommended in production, to prevent -# outdated JavaScript / CSS assets being served from cache -# (e.g. after a Wagtail upgrade). -# See https://docs.djangoproject.com/en/6.0/ref/contrib/staticfiles/#manifeststaticfilesstorage +ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS", "").split(",") + STORAGES["staticfiles"]["BACKEND"] = "django.contrib.staticfiles.storage.ManifestStaticFilesStorage" +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True + try: from .local import * except ImportError: