100 Commits

Author SHA1 Message Date
Latte b1bc726a95 fix: keep OAuth flow working on read-only container roots
docker / test (push) Successful in 29s
docker / lint (push) Successful in 34s
test / test (push) Successful in 32s
lint / lint (push) Successful in 36s
docker / docker-test (push) Successful in 8s
docker / docker-publish (push) Successful in 6s
The DCR client registry created its storage directory eagerly in __init__,
and DCR_STORAGE_PATH defaulted to /var/lib/aegis-mcp — a path that is neither
created in the image nor mounted as a writable volume. Under the hardened
read-only docker-compose, every /oauth/authorize, /oauth/token, and /register
call hit `mkdir('/var/lib/aegis-mcp')` on a read-only filesystem, raising an
unhandled OSError and returning a bare "Internal Server Error" during login.

- oauth_flow.py: defer the storage-dir mkdir from __init__ to _persist (the
  only write path). authorize/token only read the registry, so they no longer
  require a writable filesystem and stop 500-ing.
- docker/Dockerfile: create and chown /var/lib/aegis-mcp.
- docker-compose.yml + docker/docker-compose.yml: add a persistent
  aegis-mcp-data volume mounted at /var/lib/aegis-mcp so DCR registrations
  survive restarts.
- .env.example: document DCR_STORAGE_PATH and set PUBLIC_BASE_URL to the real
  MCP host.
- README.md: spell out exact values (Gitea host, MCP host, callback URL, MCP
  URL) and add a "required writable volumes" section explaining the cause of
  the login 500.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 16:28:52 +02:00
Latte 84bbff4acb Merge pull request 'fix: prevent path traversal via Gitea ref/sha/base/head parameters' (#18) from fix/gitea-ref-path-traversal into main
docker / test (push) Successful in 30s
docker / lint (push) Successful in 37s
test / test (push) Successful in 33s
docker / docker-test (push) Successful in 13s
lint / lint (push) Successful in 37s
docker / docker-publish (push) Successful in 6s
Reviewed-on: #18
2026-06-14 14:01:58 +00:00
Latte 2d95e89035 fix: prevent path traversal via Gitea ref/sha/base/head parameters
test / test (push) Successful in 20s
lint / lint (push) Successful in 22s
docker / lint (pull_request) Successful in 33s
docker / test (pull_request) Successful in 25s
test / test (pull_request) Successful in 38s
lint / lint (pull_request) Successful in 40s
docker / docker-test (pull_request) Successful in 15s
docker / docker-publish (pull_request) Has been skipped
The ref-like tool arguments (ref, sha, base, head) were only length-limited
and were interpolated unencoded into Gitea API URL paths (get_tree,
get_commit_diff, compare_refs). Because httpx collapses ".." path segments
(RFC 3986), a crafted value such as "../../../../owner/repo/contents/secret"
escaped the declared owner/repo prefix. In service-PAT mode this allowed a
user authorized on one repository to read arbitrary repositories the service
token could reach, and in OAuth mode it bypassed the policy engine's
per-repository rules (which never see ref values).

Two defense layers:
- arguments.py: add _validate_git_ref / GitRef that rejects ".." path
  segments, leading "/", backslashes, null bytes, control chars, whitespace,
  and "?"/"#", while preserving legitimate slash refs (feature/foo, v1.2.3).
  This is what actually closes the traversal.
- gitea_client.py: defense-in-depth urllib.parse.quote() on owner/repo
  (safe="") and ref/sha/base/head/filepath (safe="/") in every repo URL
  builder, mirroring the existing pattern in server.py.

Tests: negative cases for traversal/unsafe chars across all four fields,
positive cases for slash-containing refs, length-bound regression, and a
URL-layer confinement check. Full suite green (176 passed), coverage 85.64%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 15:57:52 +02:00
Latte 90df37366f Merge pull request 'feat: harden OAuth state secret validation, DCR file permissions, and policy defaults' (#17) from feat/retarget-claude-mcp into main
docker / lint (push) Successful in 34s
docker / test (push) Successful in 27s
test / test (push) Successful in 32s
lint / lint (push) Successful in 34s
docker / docker-test (push) Successful in 6s
docker / docker-publish (push) Successful in 5s
Reviewed-on: #17
2026-06-14 12:17:37 +00:00
Latte 6be5ac3608 Merge branch 'main' into feat/retarget-claude-mcp
lint / lint (push) Successful in 39s
test / test (push) Successful in 37s
docker / lint (pull_request) Successful in 37s
docker / test (pull_request) Successful in 27s
docker / docker-test (pull_request) Successful in 11s
lint / lint (pull_request) Successful in 34s
test / test (pull_request) Successful in 32s
docker / docker-publish (pull_request) Has been skipped
2026-06-14 12:14:20 +00:00
Latte b8217dce8a 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>
2026-06-14 14:13:22 +02:00
Latte 6169a45193 Merge pull request 'Feat/retarget claude mcp' (#16) from feat/retarget-claude-mcp into main
docker / test (push) Successful in 13s
docker / lint (push) Successful in 16s
lint / lint (push) Successful in 16s
test / test (push) Successful in 14s
docker / docker-test (push) Successful in 31s
docker / docker-publish (push) Successful in 5s
Reviewed-on: #16
2026-06-13 19:38:46 +00:00
Latte b275f5c0c2 docs: retarget setup to Claude connectors
test / test (push) Has been cancelled
lint / lint (push) Has been cancelled
docker / test (pull_request) Successful in 13s
docker / lint (pull_request) Successful in 2m3s
lint / lint (pull_request) Successful in 16s
test / test (pull_request) Successful in 14s
docker / docker-test (pull_request) Successful in 42s
docker / docker-publish (pull_request) Has been skipped
2026-06-13 21:05:21 +02:00
Latte 541124e92a feat: harden Claude MCP OAuth transport 2026-06-13 21:05:11 +02:00
Latte ed3130ef74 refactor: lifespan handlers, module-level imports, bounded scope cache
Replace deprecated @app.on_event startup/shutdown handlers with a FastAPI
lifespan context manager, move the inline hashlib/time imports in the auth
middleware to module top, and back the unbounded _api_scope_cache with a new
size- and TTL-bounded BoundedTTLCache utility.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 18:39:06 +02:00
Latte 71c993e4cd Use GITEA_TOKEN as service PAT for API calls in OAuth mode
docker / lint (push) Failing after 21s
docker / test (push) Failing after 17s
lint / lint (push) Failing after 22s
test / test (push) Failing after 17s
docker / docker-test (push) Has been skipped
docker / docker-publish (push) Has been skipped
Gitea OIDC access_tokens only carry OIDC scopes and cannot call the
Gitea REST API. Fall back to GITEA_TOKEN (service PAT) for actual tool
execution when configured, while OIDC still handles user identity.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 17:06:28 +00:00
Latte eada6d0f89 Merge pull request 'dev' (#12) from dev into main
docker / lint (push) Failing after 21s
docker / test (push) Failing after 16s
lint / lint (push) Failing after 21s
test / test (push) Failing after 1m12s
docker / docker-test (push) Has been skipped
docker / docker-publish (push) Has been skipped
Reviewed-on: #12
2026-03-04 16:55:31 +00:00
Latte 4e9422d6de Merge pull request 'fix' (#11) from fix into dev
docker / lint (push) Failing after 21s
lint / lint (pull_request) Failing after 22s
test / test (pull_request) Failing after 18s
docker / test (push) Failing after 16s
lint / lint (push) Failing after 22s
test / test (push) Failing after 18s
docker / lint (pull_request) Failing after 21s
docker / test (pull_request) Failing after 16s
docker / docker-test (push) Has been skipped
docker / docker-test (pull_request) Has been skipped
docker / docker-publish (push) Has been skipped
docker / docker-publish (pull_request) Has been skipped
Reviewed-on: #11
2026-03-04 16:55:18 +00:00
Latte bf35a0c712 Enhance OAuth metadata endpoints and update authorization server URLs in responses
test / test (push) Failing after 19s
docker / lint (pull_request) Failing after 21s
lint / lint (pull_request) Failing after 21s
lint / lint (push) Failing after 1m29s
docker / test (pull_request) Failing after 16s
test / test (pull_request) Failing after 18s
docker / docker-test (pull_request) Has been skipped
docker / docker-publish (pull_request) Has been skipped
2026-03-04 16:54:36 +00:00
Latte 0c61a6e0ab Merge pull request 'dev' (#10) from dev into main
docker / lint (push) Successful in 22s
docker / test (push) Successful in 17s
lint / lint (push) Successful in 23s
test / test (push) Successful in 19s
docker / docker-test (push) Successful in 7s
docker / docker-publish (push) Successful in 7s
Reviewed-on: #10
2026-02-27 20:09:00 +00:00
Latte cc86b28794 Merge pull request 'remove openrabbit' (#9) from update/image-build-workflow into dev
docker / docker-test (push) Successful in 7s
docker / docker-test (pull_request) Successful in 8s
docker / docker-publish (push) Successful in 7s
docker / docker-publish (pull_request) Has been skipped
docker / lint (push) Successful in 24s
docker / test (push) Successful in 18s
lint / lint (push) Successful in 24s
test / test (push) Successful in 19s
docker / lint (pull_request) Successful in 23s
lint / lint (pull_request) Successful in 24s
docker / test (pull_request) Successful in 19s
test / test (pull_request) Successful in 20s
Reviewed-on: #9
2026-02-27 20:08:45 +00:00
Latte 3bd09d02b2 remove openrabbit
docker / docker-test (pull_request) Successful in 9s
docker / docker-publish (pull_request) Has been skipped
lint / lint (push) Successful in 25s
test / test (push) Successful in 19s
docker / lint (pull_request) Successful in 23s
docker / test (pull_request) Successful in 18s
lint / lint (pull_request) Successful in 25s
test / test (pull_request) Successful in 19s
2026-02-27 21:08:15 +01:00
Latte f870d03e55 Merge pull request 'dev' (#8) from dev into main
docker / lint (push) Successful in 23s
docker / test (push) Successful in 18s
lint / lint (push) Successful in 22s
test / test (push) Successful in 19s
docker / docker-test (push) Successful in 8s
docker / docker-publish (push) Successful in 7s
Reviewed-on: #8
2026-02-27 19:29:16 +00:00
Latte 822b83e618 Merge pull request 'update/image-build-workflow' (#7) from update/image-build-workflow into dev
docker / docker-publish (push) Successful in 7s
docker / lint (push) Successful in 22s
docker / test (push) Successful in 18s
lint / lint (push) Successful in 24s
test / test (push) Successful in 19s
docker / docker-test (push) Successful in 8s
docker / lint (pull_request) Successful in 1m31s
docker / test (pull_request) Successful in 18s
lint / lint (pull_request) Successful in 24s
test / test (pull_request) Successful in 20s
docker / docker-test (pull_request) Successful in 38s
docker / docker-publish (pull_request) Has been skipped
Reviewed-on: #7
2026-02-27 18:59:23 +00:00
Latte 2f9750dcce Return explicit error for tokens lacking scopes
lint / lint (push) Successful in 24s
test / test (push) Successful in 19s
docker / lint (pull_request) Successful in 23s
docker / test (pull_request) Successful in 18s
lint / lint (pull_request) Successful in 24s
test / test (pull_request) Successful in 20s
docker / docker-test (pull_request) Successful in 39s
docker / docker-publish (pull_request) Has been skipped
2026-02-27 19:55:01 +01:00
Latte 5b4495a0a9 updaAdd AI review workflowste
lint / lint (push) Successful in 23s
test / test (push) Failing after 19s
2026-02-27 19:47:54 +01:00
Latte fc93b8d29e Fix Prometheus metric f-string and add YAML helper
lint / lint (push) Successful in 23s
test / test (push) Failing after 20s
2026-02-27 16:08:17 +01:00
Latte c0357ceb69 Add configurable registry push to Docker workflow
lint / lint (push) Failing after 2m15s
test / test (push) Failing after 11s
2026-02-27 15:50:12 +01:00
Latte fa30153c0d Enhance Docker workflow with gated publish
lint / lint (push) Has been cancelled
test / test (push) Has been cancelled
Expand workflow triggers to push/pull_request on main and dev and to PR
reviews. Run lint/test only for non-review events or when a review is
approved. Add a docker-test job that smoke-tests the built image. Add a
docker-publish job that resolves SHA and stable tags (latest/dev),
builds
the releasable image, and optionally pushes when PUSH_IMAGE=true. Update
docs/deployment.md
2026-02-27 11:02:48 +01:00
Latte c79cc1ab9e Add PUBLIC_BASE_URL and refine OAuth scopes
docker / lint (push) Has been cancelled
docker / test (push) Has been cancelled
docker / docker-build (push) Has been cancelled
lint / lint (push) Has been cancelled
test / test (push) Has been cancelled
2026-02-25 20:49:08 +01:00
Latte 59e1ea53a8 Add OAuth2/OIDC per-user Gitea authentication
docker / lint (push) Has been cancelled
docker / test (push) Has been cancelled
docker / docker-build (push) Has been cancelled
lint / lint (push) Has been cancelled
test / test (push) Has been cancelled
Introduce a GiteaOAuthValidator for JWT and userinfo validation and
fallbacks, add /oauth/token proxy, and thread per-user tokens through
the
request context and automation paths. Update config and .env.example for
OAuth-first mode, add OpenAPI, extensive unit/integration tests,
GitHub/Gitea CI workflows, docs, and lint/test enforcement (>=80% cov).
2026-02-25 16:54:01 +01:00
Latte a00b6a0ba2 update 2026-02-14 18:18:34 +01:00
Latte ecc87cbb65 quick fix 2026-02-14 17:18:30 +01:00
Latte 8504a95a11 feat: add opt-in write access for all token-visible repos 2026-02-14 16:35:03 +01:00
Latte e22a8d37e4 fix: use external proxy network in compose configs 2026-02-14 16:15:21 +01:00
Latte 198fd3905b add readme.md 2026-02-14 16:10:43 +01:00
Latte 5969892af3 feat: harden gateway with policy engine, secure tools, and governance docs 2026-02-14 16:06:43 +01:00
matsv e17d34e6d7 docs: Add documentation site and API reference 2026-02-13 15:12:14 +01:00
Latte d82fe87113 update 2026-02-11 18:16:00 +01:00
Ubuntu dd7bbd1f9a IT WORKS 2026-01-31 16:03:17 +00:00
Ubuntu 3c71d5da0a update 2026-01-31 15:55:22 +00:00
Latte 833eb21c79 quick fix 2026-01-31 14:23:51 +01:00
Latte 0a2a21cc52 feat: scope query param auth to MCP endpoints
Restrict api_key query parameter to /mcp/tools, /mcp/tool/call,
and /mcp/sse only. Updated documentation to reflect query param
usage for ChatGPT UI without header support.
2026-01-29 21:07:37 +01:00
Latte b990c6c527 feat: allow api_key query parameter for ChatGPT UI
ChatGPT UI lacks custom header support for MCP servers. Added
query parameter fallback (?api_key=) alongside Authorization
header to authenticate requests.

Updated tests to cover query param authentication.
2026-01-29 21:03:05 +01:00
Latte 08e9aa1de6 docs: add comprehensive testing guide and test runner
Added:
- run_tests.sh: Automated test runner with coverage reporting
- TESTING.md: Complete testing documentation including:
  - Test suite overview
  - Manual testing procedures
  - CI/CD integration examples
  - Performance testing guidelines
  - Troubleshooting guide

The test suite now has ~85% coverage of core modules with
tests for authentication, server endpoints, and integration flows.
2026-01-29 20:46:50 +01:00
Latte f52e99e328 test: add comprehensive test suite for authentication system
Added three test modules covering:
- test_auth.py: Unit tests for authentication module
  - API key generation and validation
  - Rate limiting
  - Multiple keys support
  - Constant-time comparison

- test_server.py: Server endpoint tests
  - Authentication middleware
  - Protected vs public endpoints
  - Various auth header formats
  - Rate limiting at endpoint level

- test_integration.py: Integration tests
  - Complete authentication flow
  - Key rotation simulation
  - Multiple tool discovery
  - Error message validation

All tests verify functionality without breaking existing features.
2026-01-29 20:45:44 +01:00
Latte de0ae09fc4 fix: update structlog configuration for compatibility
Removed deprecated make_filtering_bound_logger() call that was
causing TypeError. Using structlog.BoundLogger directly instead.
2026-01-29 20:44:17 +01:00
Latte a0605eaa27 fix: change mcp_api_keys to string field to avoid JSON parsing
Pydantic was trying to parse List[str] as JSON from env vars.
Changed to use a string field (mcp_api_keys_raw) and parse manually
in model_validator, then expose as property.

This fixes the JSONDecodeError when reading MCP_API_KEYS from .env
2026-01-29 20:30:28 +01:00
Latte 0945f560ff fix: use model_validator for API keys validation
Changed from field_validator to model_validator to properly access
auth_enabled field during validation. This fixes the SettingsError
when parsing mcp_api_keys from environment variables.

Also improved handling of empty strings and None values.
2026-01-29 20:27:36 +01:00
Latte 0d986eb78b fix: correct Python dependencies path for non-root user in Docker
The builder stage installed dependencies to /root/.local but the final
stage switched to the 'aegis' user who couldn't access /root/.local.

Fixed by copying dependencies to /home/aegis/.local and updating PATH
to point to the correct location.
2026-01-29 20:24:45 +01:00
Latte 9e2ff4cec8 Merge pull request 'feature/authentication-systems' (#1) from feature/authentication-system into main
Reviewed-on: #1
2026-01-29 19:13:08 +00:00
Latte aff91d9386 docs: add implementation summary for authentication system 2026-01-29 20:07:04 +01:00
Latte eeaad748a6 feat: add API key authentication system for ChatGPT Business
Implements comprehensive Bearer token authentication to ensure only
authorized ChatGPT workspaces can access the MCP server.

Core Features:
- API key validation with constant-time comparison
- Multi-key support for rotation grace periods
- Rate limiting (5 failures per IP per 5 min)
- Comprehensive audit logging of all auth attempts
- IP-based failed attempt tracking

Key Management:
- generate_api_key.py: Create secure 64-char keys
- rotate_api_key.py: Guided key rotation with backup
- check_key_age.py: Automated expiration monitoring

Infrastructure:
- Traefik labels for HTTPS and rate limiting
- Security headers (HSTS, CSP, X-Frame-Options)
- Environment-based configuration
- Docker secrets support

Documentation:
- AUTH_SETUP.md: Complete authentication setup guide
- CHATGPT_SETUP.md: ChatGPT Business integration guide
- KEY_ROTATION.md: Key rotation procedures and automation

Security:
- Read-only operations enforced
- No write access to Gitea possible
- All auth attempts logged with correlation IDs
- Failed attempts trigger IP rate limits
- Keys never logged in full (only hints)

Breaking Changes:
- AUTH_ENABLED defaults to true
- MCP_API_KEYS environment variable now required
- Minimum key length: 32 characters (64 recommended)

Migration:
1. Generate API key: make generate-key
2. Add to .env: MCP_API_KEYS=<generated-key>
3. Restart: docker-compose restart aegis-mcp
4. Configure ChatGPT with Authorization header

Closes requirements for ChatGPT Business exclusive access.
2026-01-29 20:05:49 +01:00
Latte a9708b33e2 . 2026-01-29 19:53:36 +01:00
Latte 1bda2013bb Initial commit 2026-01-29 18:36:24 +00:00