feat: harden OAuth state secret validation, DCR file permissions, and policy defaults
docker / test (pull_request) Successful in 24s
lint / lint (pull_request) Successful in 37s
lint / lint (push) Successful in 1m26s
test / test (push) Successful in 1m40s
test / test (pull_request) Successful in 34s
docker / lint (pull_request) Successful in 1m59s
docker / docker-test (pull_request) Successful in 14s
docker / docker-publish (pull_request) Has been skipped

- Enforce 32-char minimum on OAUTH_STATE_SECRET at startup (config.py)
- Write DCR client registry with owner-only (0o600) permissions before atomic replace
- Flip policy.yaml default write action from allow → deny
- Add CLAUDE.md with architecture, commands, and AGENTS.md contract summary
- Add .pre-commit-config.yaml mirroring `make lint` checks
- Update .gitignore: add .venv, .claude, .mypy_cache, .ruff_cache, .coverage.*
- Extend docs: audit log rotation guidance, OAUTH_STATE_SECRET and DCR_STORAGE_PATH notes
- Tests: short-secret rejection, 32-char acceptance, POSIX permission check for DCR store

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 14:13:22 +02:00
parent b275f5c0c2
commit b8217dce8a
11 changed files with 269 additions and 4 deletions
+25
View File
@@ -3,6 +3,8 @@
from __future__ import annotations
import asyncio
import os
import stat
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
@@ -537,6 +539,29 @@ def test_dcr_registry_persists_registered_clients(tmp_path):
assert reloaded.get(response["client_id"]) is not None
@pytest.mark.skipif(
os.name != "posix", reason="POSIX permission bits are not enforced on this platform"
)
def test_dcr_storage_is_written_owner_only(tmp_path):
"""The persisted DCR store must not be readable beyond its owner (0o600)."""
storage_path = tmp_path / "dcr_clients.json"
registry = OAuthClientRegistry(storage_path)
request = OAuthRegistrationRequest.model_validate(
{
"client_name": "perm-client",
"redirect_uris": ["http://127.0.0.1:8080/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code"],
"response_types": ["code"],
}
)
registry.register(request)
mode = stat.S_IMODE(os.stat(storage_path).st_mode)
assert mode == 0o600
# ---------------------------------------------------------------------------
# Config validation tests
# ---------------------------------------------------------------------------