Skip to content

feat(auth): in-memory and Redis OAuth token storage#233

Merged
saidsef merged 15 commits into
mainfrom
feat/oauth-memory-redis-token-store
May 13, 2026
Merged

feat(auth): in-memory and Redis OAuth token storage#233
saidsef merged 15 commits into
mainfrom
feat/oauth-memory-redis-token-store

Conversation

@saidsef
Copy link
Copy Markdown
Owner

@saidsef saidsef commented May 10, 2026

Summary

  • Switches OAuth token storage from disk (FileTreeStore) to in-process MemoryStore by default - required for K8s pods with readOnlyRootFilesystem: true
  • When REDIS_HOST_PORT is set, RedisStore is used instead; accepts bare host:port or a full URI (redis:// plaintext, rediss:// TLS)
  • Password can be embedded in the URI or supplied via REDIS_PASSWORD; database defaults to 0 or is read from the /db path component in the URI
  • K8s deployment updated: REDIS_HOST_PORT via ConfigMap and REDIS_PASSWORD via Secret (both optional)
  • redis>=5.0.0 added to dependencies; requirements.txt regenerated so Docker builds include it
  • All imports moved to module level; README architecture diagram and docstrings updated

Test plan

  • Start server without REDIS_HOST_PORT - confirm MemoryStore is used (no disk writes)
  • Start server with REDIS_HOST_PORT=redis://localhost:6379 - confirm OAuth state lands in Redis
  • Start server with REDIS_HOST_PORT=rediss://localhost:6380 - confirm TLS connection (ssl=True)
  • Set REDIS_HOST_DB=abc - confirm server refuses to start with a clear error
  • Restart server in memory-only mode - confirm stale client_ids require re-auth (expected, documented)
  • Run in Docker with --read-only --tmpfs /tmp - confirm no filesystem writes

… writes

Replaces the default FileTreeStore (disk-based) with a MemoryStore (default)
or RedisStore (when REDIS_HOST_PORT is set) so no OAuth token state is ever
written to the filesystem — a security requirement for K8s deployments.
@saidsef saidsef added enhancement New feature or request security labels May 10, 2026
@saidsef saidsef self-assigned this May 10, 2026
@codacy-production
Copy link
Copy Markdown

codacy-production Bot commented May 10, 2026

Up to standards ✅

🟢 Issues 4 minor

Results:
4 new issues

Category Results
Documentation 3 minor
CodeStyle 1 minor

View in Codacy

🟢 Metrics 35 complexity

Metric Results
Complexity 35

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 10, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
pip/redis 7.4.0 UnknownUnknown
pip/redis 7.4.0 UnknownUnknown

Scanned Files

  • requirements.txt
  • uv.lock

github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
- Safe REDIS_HOST_DB parse: ValueError at module load with a clear message
  instead of a bare int() crash
- Add REDIS_PASSWORD env var for Redis AUTH, wired into RedisStore constructor
- Move MemoryStore import to top level; parse host/port explicitly so
  build_token_store() doesn't rely on URL string manipulation
- Document REDIS_PASSWORD in README, CLAUDE.md, and K8s manifest
  (Secret-backed, optional: true)
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
REDIS_HOST_PORT now accepts a full URI (redis:// or rediss://) in addition
to bare host:port. When rediss:// is provided, the Redis client is
constructed with ssl=True — bypassing key_value's URL parser which ignores
the scheme. Password and db can be embedded in the URI or fall back to
REDIS_HOST_DB / REDIS_PASSWORD env vars.
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
Add the auth layer (APIKeyVerifier / GitHub OAuth2), MemoryStore,
and RedisStore (with TLS) to the README ASCII diagram.
@saidsef saidsef changed the title feat(auth): in-memory and Redis OAuth token storage (no disk writes) feat(auth): in-memory and Redis OAuth token storage May 10, 2026
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
Move token store (MemoryStore / RedisStore) to a right-hand branch off
the Auth Layer box so the main vertical flow to PRIssueAnalyser is
unbroken — the previous layout left a floating | and v after the Redis
box with no visible connection back to the flow.
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
redis>=5.0.0 was added to pyproject.toml and uv.lock but requirements.txt
was never regenerated. The Dockerfile installs deps from requirements.txt,
so redis was absent from the Docker image, causing a ModuleNotFoundError
at runtime when REDIS_HOST_PORT is set.
The database index can be embedded directly in REDIS_HOST_PORT as a URI
path component (redis://host:6379/1), making a separate REDIS_HOST_DB
fallback redundant. Bare host:port or URIs without a /db path default to
database 0.
@saidsef saidsef force-pushed the feat/oauth-memory-redis-token-store branch from c302cbd to a01e1dd Compare May 10, 2026 15:31
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
Also adds em-dash style guideline to the MCP server prompt.
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
- Add blank line after h1 heading in README.md (MD022)
- Convert _PermissiveGitHubProvider docstring to NumPy style (D203, D212, D205)
- Convert resolve_token Raises section to NumPy style (D406, D407, D413)
github-actions[bot]
github-actions Bot previously approved these changes May 10, 2026
…Redis deployments

Wrap RedisStore with PrefixCollectionsWrapper using a 12-char SHA-256 hash
of GITHUB_OAUTH_BASE_URL as the collection prefix. Two server instances that
share the same Redis instance (e.g. personal and company deployments) now
write to fully isolated keyspaces, preventing one server's OAuth session
from overwriting or colliding with the other's JTI mappings, upstream tokens,
and client registrations.
github-actions[bot]
github-actions Bot previously approved these changes May 11, 2026
Extract _build_redis_client() helper to reduce build_token_store()
cyclomatic complexity below the limit of 8. Fix D212 and D205 docstring
violations in build_token_store() and get_oauth_verifier().
github-actions[bot]
github-actions Bot previously approved these changes May 11, 2026
Add _derive_jwt_signing_key() that automatically derives a deterministic
JWT signing key from GITHUB_OAUTH_CLIENT_SECRET when JWT_SIGNING_KEY is
not explicitly set. This ensures all pods in a multi-replica deployment
share the same signing key, preventing token validation failures caused
by divergent derived keys. An explicit JWT_SIGNING_KEY env var can still
be provided as an override.
github-actions[bot]
github-actions Bot previously approved these changes May 11, 2026
…B validation

- Add tests/test_auth.py with 15 tests covering _build_redis_client URI
  parsing (host:port, redis://, rediss://, db path, password precedence,
  invalid db raises) and build_token_store backend selection (MemoryStore
  default, RedisStore construction, PrefixCollectionsWrapper applied/skipped,
  prefix stability and isolation)
- _build_redis_client now raises ValueError for non-integer db path instead
  of silently defaulting to 0, matching the documented test plan behaviour
- Fix resolve_token docstring: move summary onto opening line (D212) and
  add blank line before body (D205)
github-actions[bot]
github-actions Bot previously approved these changes May 13, 2026
…clusion

- Extract _parse_redis_db() from _build_redis_client() to bring cyclomatic
  complexity from 9 to 6 (limit is 8)
- Switch multi-line docstrings in auth.py to D213 style (summary on second
  line) for build_token_store, _derive_jwt_signing_key, and resolve_token
- Add blank line before class docstrings in tests (D203)
- Add [tool.bandit] exclude_dirs=["tests"] to pyproject.toml so assert
  statements and test-fixture strings are not flagged as security issues
- Suppress ANN annotations for test helpers in per-file-ignores
- Update CLAUDE.md: document D213+D203 as the enforced convention (Codacy),
  note ruff ignores both conflicting pairs, update Testing section
@saidsef saidsef merged commit ef0233d into main May 13, 2026
6 checks passed
@saidsef saidsef deleted the feat/oauth-memory-redis-token-store branch May 13, 2026 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request security

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant