Commit Graph
18 Commits
Author SHA1 Message Date
Latte d7cac91175 ci: raise the coverage gate to 90 percent; docs: reconcile OAuth docs with the implementation 2026-10-14 17:53:58 +02:00
Latte 79aa4f7fc0 fix: load ./.env only when private and owned, add --env-file and AEGIS_ENV_FILE (SEC-04) 2026-10-14 17:22:29 +02:00
Latte cf3d2e17d3 fix: fail closed on an unwritable audit log, bound the rate limiter and harden startup
The audit logger is opened at startup (exit 2 on failure) and obtained before
every call, which is refused with audit_unavailable otherwise. Audit records only
take validated path and sudo values and use the request id as correlation id. The
rate limiter evicts idle keys, caps tracked keys, audits the first excess per key
and window and uses the settings passed to the app. FORWARDED_ALLOW_IPS is now a
setting, and startup warns about a missing host allow-list and unavailable OAuth.
2026-10-14 16:24:51 +02:00
Latte e139ae826f docs: regenerate tool inventory after annotation overrides
ci / gitleaks (push) Successful in 8s
ci / docs-check (push) Failing after 35s
ci / lint (push) Successful in 47s
ci / test-mcp (push) Failing after 48s
ci / test-integration (push) Successful in 52s
ci / security (push) Failing after 29s
ci / test-unit (push) Successful in 1m57s
ci / build-and-push (push) Successful in 18s
2026-10-14 16:13:57 +02:00
Latte 7c7cfc05ff docs: rewrite README and docs for the full-access design, generate tool inventory 2026-10-14 16:13:11 +02:00
LatteandClaude Opus 4.8 499bf98d92 ci: build and publish package to Gitea registry on tag
docker / test (push) Successful in 38s
lint / lint (push) Successful in 45s
docker / lint (push) Successful in 44s
test / test (push) Successful in 44s
docker / docker (push) Successful in 40s
docker / lint (pull_request) Successful in 40s
docker / test (pull_request) Successful in 34s
lint / lint (pull_request) Successful in 41s
test / test (pull_request) Successful in 40s
docker / docker (pull_request) Successful in 37s
Add .gitea/workflows/publish.yml: on a v* tag, gate on the existing lint + test
jobs, then build sdist+wheel with uv and publish to the self-hosted Gitea PyPI
registry using least-privilege Actions secrets (GITEA_PACKAGE_USER /
GITEA_PACKAGE_TOKEN). The job fails loudly when the secrets are absent rather
than publishing anonymously, uploads the built artifacts, and leaves a disabled
public-PyPI stub. Public PyPI is intentionally not published in this pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:18:07 +02:00
LatteandClaude Opus 4.8 385b442b6f docs: local vs server quickstart, authz model, packaging
Reframe the README around two transports and add a local stdio quickstart with
uvx/pip and Claude Desktop / Claude Code wiring. New docs: local-quickstart.md
and packaging.md (uv build/publish). Document resource-type-aware authorization
and classified gitea_request in security.md; stdio env vars + audit-log
fallback in configuration.md; local install in deployment.md; core+adapters in
architecture.md. Add the missing root AGENTS.md contract, update CLAUDE.md with
the core/adapter layout, fail-closed invariants, and the branching flow
(HEAD -> feature -> dev -> main). Update roadmap/todo and .env.example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 11:17:01 +02:00
LatteandClaude Opus 4.8 e873d0325b feat: scope list_repositories to the authenticated user in service-PAT mode
docker / test (push) Successful in 28s
docker / lint (push) Successful in 33s
lint / lint (push) Successful in 35s
test / test (push) Successful in 33s
docker / docker-test (push) Successful in 10s
docker / docker-publish (push) Successful in 6s
Previously list_repositories was blocked in service-PAT mode because it has no
repository target for the per-user permission check, so users could not list
their repositories at all (the connector surfaced a generic error).

list_repositories now returns only the repositories the signed-in user owns or
contributes to, instead of everything the bot token can see:
- gitea_client.py: add list_user_repositories(login) — resolves the user id and
  queries /api/v1/repos/search with the uid filter.
- repository.py: list_repositories_tool uses the user-scoped path when a service
  PAT is configured and a user login is present; pure-OAuth mode still uses the
  user's own /user/repos.
- server.py: allow list_repositories through the service-PAT guard (it is scoped
  to the user in the handler); all other tools still require a repository target.
- README.md: document the new user-scoped behavior and its visibility caveat.

Tests: user-scoped client method (uid resolution + unknown user), PAT-mode tool
scoping, and conftest now clears the request context between tests to prevent
contextvar login leakage across files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 17:07:19 +02:00
LatteandClaude Opus 4.8 624a3c79ee fix: surface Gitea auth errors and document the service PAT
docker / test (push) Successful in 25s
test / test (push) Successful in 32s
lint / lint (push) Successful in 33s
docker / docker-publish (push) Successful in 6s
docker / lint (push) Successful in 30s
docker / docker-test (push) Successful in 10s
Two related issues made the connected MCP server return a bare "Internal
server error" for tools that need real Gitea API access (e.g.
list_repositories), while public-repo-by-path reads worked:

1. Gitea OIDC access tokens only carry openid/profile/email and cannot call
   the repository REST API, so pure-OAuth mode fails for most tools. A service
   PAT (GITEA_TOKEN) is required in practice; per-user permission is still
   enforced before each call, so this does not weaken authorization.
2. The tool handlers caught GiteaError broadly and re-raised it as RuntimeError.
   Because GiteaAuthenticationError/GiteaAuthorizationError subclass GiteaError,
   a clean 401/403 was masked as a generic internal error and the server's
   re-authorization guidance never fired.

Changes:
- read_tools.py / repository.py / write_tools.py: re-raise the auth/authz
  subclasses before the broad GiteaError catch so server.py returns actionable
  guidance instead of a generic 500.
- .env.example + README.md: document GITEA_TOKEN as a least-privilege bot PAT,
  explain why it's needed and that OAuth remains authoritative, and note that
  list_repositories is intentionally unavailable in service-PAT mode.
- tests: assert tool handlers propagate auth errors unwrapped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 16:47:10 +02:00
LatteandClaude Opus 4.8 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 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 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 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 8504a95a11 feat: add opt-in write access for all token-visible repos 2026-02-14 16:35:03 +01:00
Latte 198fd3905b add readme.md 2026-02-14 16:10:43 +01:00
Latte d82fe87113 update 2026-02-11 18:16:00 +01:00
Latte a9708b33e2 . 2026-01-29 19:53:36 +01:00
Latte 1bda2013bb Initial commit 2026-01-29 18:36:24 +00:00