4.1 KiB
StudyCalendar backend
Desenvolvimento
O modo de desenvolvimento é explícito e o servidor embutido escuta apenas loopback:
python -m venv .venv
.venv/bin/pip install -r requirements-dev.txt
APP_ENV=development DATABASE_PATH=/tmp/studycalendar-dev.db .venv/bin/python app.py
A chave aleatória gerada no modo development muda a cada reinício. Defina FLASK_SECRET_KEY se quiser preservar sessões.
Deploy seguro
- Copie as variáveis de
.env.examplepara o gerenciador de segredos do serviço. O arquivo.envé ignorado; nunca grave a chave no repositório. - Gere uma chave exclusiva com
python -c "import secrets; print(secrets.token_urlsafe(48))". - Defina
TRUSTED_HOSTScom os nomes DNS públicos exatos, separados por vírgula. Não use curingas amplos. - Termine TLS em um proxy reverso, mantenha
SESSION_COOKIE_SECURE=true,ENABLE_HSTS=truee exponha somente HTTPS. - Mantenha
ALLOW_REGISTRATION=falsee provisione usuários por um fluxo administrativo controlado, ou habilite cadastro somente quando houver uma decisão explícita de produto e proteção adicional no proxy/WAF. - Execute o web app com
gunicorn --workers 2 --bind 127.0.0.1:8000 app:app. - Execute exatamente uma instância separada de
python scheduler_process.py. ConfigureSCHEDULER_LOCK_PATHem diretório gravável apenas pelo serviço. O lock impede duplicação acidental no mesmo host; em múltiplos hosts, use somente uma unidade/replica do scheduler. - Dê ao usuário do serviço acesso mínimo ao diretório de
DATABASE_PATHe faça backups consistentes do SQLite.
Crie o primeiro usuário de forma interativa, sem expor a senha na linha de comando:
APP_ENV=production FLASK_SECRET_KEY='...' TRUSTED_HOSTS=calendario.seudominio.com DATABASE_PATH=/var/lib/studycalendar/calendario.db \
.venv/bin/flask --app app create-user
Não inicie o scheduler em hooks do Gunicorn nem em cada worker. O processo web nunca inicia tarefas em importação. As rotas web apenas enfileiram sincronizações no SQLite; downloads e parsing são executados pelo scheduler dedicado para não ocupar workers HTTP.
Proxy reverso
TRUSTED_PROXY_COUNT=0 é o padrão seguro e ignora X-Forwarded-*. Altere para o número exato de proxies sob seu controle entre o cliente e Gunicorn. Nunca aceite tráfego direto no Gunicorn quando esse valor for maior que zero. O endereço resultante é usado pelo rate limit de autenticação.
O limitador é local e em memória: não precisa de Redis e é suficiente para uma implantação pequena, mas o limite é aplicado por worker/processo. Para escala horizontal, complemente-o no proxy/WAF sem remover os limites da aplicação.
CSRF e same-origin
O backend não habilita CORS. Navegadores same-origin existentes são validados por Origin/Referer. Clientes de API podem fazer GET /api/auth/csrf, manter o cookie de sessão e enviar o valor retornado no header X-CSRF-Token em POST, PUT, PATCH e DELETE.
Feeds ICS
HTTPS e porta 443 são obrigatórios por padrão. Cada destino e redirect tem DNS validado; endereços não globais IPv4/IPv6 são bloqueados. TLS sempre é verificado, redirects e corpo são limitados, proxies de ambiente são ignorados e o peer conectado é comparado obrigatoriamente ao DNS validado. URLs não são registradas em log.
Para permitir HTTP público em ambiente legado, defina ICS_HTTPS_ONLY=false, reconhecendo a perda de confidencialidade e integridade. Não há opção para desativar verificação TLS.
Banco legado
A antiga migração que atribuía registros sem proprietário ao usuário 1 foi removida. Bancos anteriores ao schema multiusuário devem ser migrados offline com uma associação de proprietário definida pelo operador; a aplicação não inventa ownership.
Testes
.venv/bin/pytest -q
.venv/bin/pip-audit --requirement requirements.txt
Os arquivos requirements*.txt são locks com hashes. Para atualizá-los intencionalmente:
.venv/bin/pip-compile --generate-hashes --output-file=requirements.txt requirements.in
.venv/bin/pip-compile --generate-hashes --output-file=requirements-dev.txt requirements-dev.in