Commit Graph

6 Commits

Author SHA1 Message Date
Latte 41749fd7b4 fix: harden get_issue parsing and surface real errors (#27); align CI image publish
get_issue raised 'NoneType' object is not iterable on issues whose
labels/assignees Gitea returns as null or with non-dict elements (the #13
class), which reached clients as an opaque JSON-RPC -32603 with no detail.

- read_tools: skip non-dict label/assignee entries in get_issue_tool
- server: detect a wrapped GiteaNotFoundError via the __cause__ chain and
  return 404 / JSON-RPC -32000 with a clear message; include the exception
  type name in masked internal errors so future masked failures are
  diagnosable without exposing messages or stack traces
- tests: cover non-dict collection elements and the not-found / typed-error
  responses
- ci: rewrite docker.yml to build, smoke-test and push the image to the
  Gitea container registry on merge to main/dev, matching the hiddenden.cafe
  pattern (only REGISTRY_TOKEN required)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 16:51:58 +02:00
Latte f53e1a3a5a feat: add structured logging helpers and instrument get_issue (#14)
docker / test (pull_request) Successful in 29s
test / test (push) Successful in 38s
docker / lint (pull_request) Successful in 39s
lint / lint (push) Successful in 39s
docker / docker-test (pull_request) Successful in 12s
docker / docker-publish (pull_request) Has been skipped
lint / lint (pull_request) Successful in 28s
test / test (pull_request) Successful in 22s
Adds reusable, secret-safe logging helpers to `logging_utils`:
- `log_event(logger, level, event, **context)` emits a named event with a
  sanitized `context` mapping (sensitive keys masked as `***`).
- `log_nullable_field(...)` records whether a parsed field is None plus its
  runtime type, without dumping its contents.
- `sanitize_context(...)` is the shared masking primitive.

The JSON formatter now serializes a record's `context` into the payload.

`get_issue_tool` is instrumented at DEBUG (`get_issue.start`,
`get_issue.payload_shape`, `get_issue.field_check` for labels/assignees/user)
so the nullable-field parsing that caused #13 is diagnosable going forward.

Adds tests for the helpers, the formatter, and the get_issue instrumentation,
and documents the pattern in docs/observability.md.
2026-06-22 15:40:36 +02:00
Latte 478aee9bed fix: tolerate null labels/assignees/user in get_issue (#13)
docker / test (pull_request) Successful in 32s
docker / lint (pull_request) Successful in 39s
lint / lint (pull_request) Successful in 34s
test / test (pull_request) Successful in 32s
docker / docker-publish (pull_request) Has been skipped
test / test (push) Successful in 25s
lint / lint (push) Successful in 27s
docker / docker-test (pull_request) Successful in 11s
Gitea may return JSON null for an issue's `labels`, `assignees`, or
`user` fields. `dict.get(key, [])` returns None when the key is present
with a null value (the default is only used for missing keys), so the
list comprehensions raised `'NoneType' object is not iterable` for
otherwise-valid issues. Coalesce with `or []` / `or {}` so empty/null
collections normalize to empty results.

Adds a regression test covering all three null fields.
2026-06-22 10:43:43 +02:00
Latte b62ed098bf feat: add 13 read tools (PR files/commits, comments, branches, releases, milestones, org/status/languages/topics)
test / test (push) Successful in 1m13s
lint / lint (push) Successful in 1m14s
docker / docker-publish (pull_request) Has been skipped
docker / test (pull_request) Successful in 22s
docker / lint (pull_request) Successful in 29s
lint / lint (pull_request) Successful in 31s
test / test (pull_request) Successful in 21s
docker / docker-test (pull_request) Successful in 23s
Expands the read surface so the MCP can inspect more of Gitea:

- list_pull_request_files, list_pull_request_commits, list_issue_comments
- list_branches, get_branch
- get_release, get_latest_release, list_milestones
- get_commit_status
- list_org_repositories, list_organizations
- get_repo_languages, list_repo_topics

Each: arg schema (extra=forbid; GitRef on branch/sha fields), Gitea client
method with url-encoded path segments, bounded handler, MCP registration
(read-only), server wiring, docs, and parametrized success tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 20:43:03 +02:00
Latte 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
Latte 5969892af3 feat: harden gateway with policy engine, secure tools, and governance docs 2026-02-14 16:06:43 +01:00