feat: add docs drift check
This commit is contained in:
1 parent
c9e2c481e7
commit
68bd8700dc
10 files changed
+653
-549
No files matched your search
@@ -1,128 +0,0 @@
|
||||
# API Reference
|
||||
|
||||
## Core Endpoints
|
||||
|
||||
- `GET /`: server metadata.
|
||||
- `GET /health`: health probe.
|
||||
- `GET /metrics`: Prometheus metrics (when enabled).
|
||||
|
||||
## OAuth Discovery and Token Exchange
|
||||
|
||||
- `GET /.well-known/oauth-protected-resource`
|
||||
- Returns OAuth protected resource metadata used by MCP clients.
|
||||
- `GET /.well-known/oauth-authorization-server`
|
||||
- Returns OAuth authorization server metadata.
|
||||
- `POST /register`
|
||||
- Registers an OAuth client and persists the client metadata.
|
||||
- `POST /oauth/token`
|
||||
- Proxies OAuth authorization-code token exchange to Gitea.
|
||||
|
||||
## MCP Endpoints
|
||||
|
||||
- `GET /mcp/tools`: list tool definitions.
|
||||
- `GET /mcp` and `POST /mcp`: streamable HTTP transport.
|
||||
- `GET /mcp/sse` and `POST /mcp/sse`: MCP SSE transport alias.
|
||||
- `POST /mcp/tool/call`: direct tool-call endpoint.
|
||||
|
||||
Authentication requirements:
|
||||
|
||||
- MCP tool execution requires `Authorization: Bearer <token>`.
|
||||
- Missing or invalid tokens return `401` with:
|
||||
- `WWW-Authenticate: Bearer resource_metadata="<absolute metadata url>", scope="read:repository"`
|
||||
|
||||
Scope requirements:
|
||||
|
||||
- Read tools require `read:repository`.
|
||||
- Write tools require `write:repository`.
|
||||
- Insufficient scope returns `403`.
|
||||
|
||||
## Automation Endpoints
|
||||
|
||||
- `POST /automation/webhook`: ingest policy-controlled webhook events.
|
||||
- `POST /automation/jobs/run`: run policy-controlled automation jobs.
|
||||
|
||||
## Read Tools
|
||||
|
||||
- `list_repositories`
|
||||
- `get_repository_info` (`owner`, `repo`)
|
||||
- `get_file_tree` (`owner`, `repo`, optional `ref`, `recursive`)
|
||||
- `get_file_contents` (`owner`, `repo`, `filepath`, optional `ref`)
|
||||
- `search_code` (`owner`, `repo`, `query`, optional `ref`, `page`, `limit`)
|
||||
- `list_commits` (`owner`, `repo`, optional `ref`, `page`, `limit`)
|
||||
- `get_commit_diff` (`owner`, `repo`, `sha`)
|
||||
- `compare_refs` (`owner`, `repo`, `base`, `head`)
|
||||
- `list_issues` (`owner`, `repo`, optional `state`, `page`, `limit`, `labels`)
|
||||
- `get_issue` (`owner`, `repo`, `issue_number`)
|
||||
- `list_pull_requests` (`owner`, `repo`, optional `state`, `page`, `limit`)
|
||||
- `get_pull_request` (`owner`, `repo`, `pull_number`)
|
||||
- `list_labels` (`owner`, `repo`, optional `page`, `limit`)
|
||||
- `list_tags` (`owner`, `repo`, optional `page`, `limit`)
|
||||
- `list_releases` (`owner`, `repo`, optional `page`, `limit`)
|
||||
- `list_pull_request_files` (`owner`, `repo`, `pull_number`, optional `page`, `limit`)
|
||||
- `list_pull_request_commits` (`owner`, `repo`, `pull_number`, optional `page`, `limit`)
|
||||
- `list_issue_comments` (`owner`, `repo`, `issue_number`, optional `page`, `limit`)
|
||||
- `list_branches` (`owner`, `repo`, optional `page`, `limit`)
|
||||
- `get_branch` (`owner`, `repo`, `branch`)
|
||||
- `get_release` (`owner`, `repo`, `release_id`)
|
||||
- `get_latest_release` (`owner`, `repo`)
|
||||
- `list_milestones` (`owner`, `repo`, optional `state`, `page`, `limit`)
|
||||
- `get_commit_status` (`owner`, `repo`, `sha`)
|
||||
- `list_org_repositories` (`org`, optional `page`, `limit`)
|
||||
- `list_organizations` (optional `page`, `limit`)
|
||||
- `get_repo_languages` (`owner`, `repo`)
|
||||
- `list_repo_topics` (`owner`, `repo`)
|
||||
|
||||
## Write Tools (Write Mode Required)
|
||||
|
||||
- `create_issue` (`owner`, `repo`, `title`, optional `body`, `labels`, `assignees`, `milestone`)
|
||||
- `update_issue` (`owner`, `repo`, `issue_number`, one or more of `title`, `body`, `state`, `milestone`)
|
||||
- `create_issue_comment` (`owner`, `repo`, `issue_number`, `body`)
|
||||
- `create_pr_comment` (`owner`, `repo`, `pull_number`, `body`)
|
||||
- `add_labels` (`owner`, `repo`, `issue_number`, `labels` by name)
|
||||
- `remove_labels` (`owner`, `repo`, `issue_number`, `labels` by name)
|
||||
- `assign_issue` (`owner`, `repo`, `issue_number`, `assignees`)
|
||||
- `create_label` (`owner`, `repo`, `name`, `color` hex e.g. `#00aabb`, optional `description`, `exclusive`)
|
||||
- `update_label` (`owner`, `repo`, `name`, one or more of `new_name`, `color`, `description`)
|
||||
- `create_pull_request` (`owner`, `repo`, `title`, `head`, `base`, optional `body`)
|
||||
- `create_release` (`owner`, `repo`, `tag_name`, optional `name`, `body`, `draft`, `prerelease`, `target`)
|
||||
- `edit_release` (`owner`, `repo`, `release_id`, one or more of `name`, `body`, `draft`, `prerelease`)
|
||||
- `create_branch` (`owner`, `repo`, `new_branch_name`, optional `old_branch_name`)
|
||||
- `create_milestone` (`owner`, `repo`, `title`, optional `description`, `due_on`)
|
||||
- `edit_issue_comment` (`owner`, `repo`, `comment_id`, `body`)
|
||||
|
||||
Not supported by the dedicated tools by design: merge, branch/label/release deletion,
|
||||
force push, repo/admin management. Endpoints not covered above are reachable through the
|
||||
generic `gitea_request` escape hatch (subject to policy, write-mode, and a sensitive-path
|
||||
denylist) — see [Raw API Dispatch](raw-api.md).
|
||||
|
||||
## Raw API Dispatch
|
||||
|
||||
- `gitea_request` (`method`, `path`, optional `query`, `body`)
|
||||
- Calls an arbitrary Gitea REST endpoint. `GET`/`HEAD` are reads; other methods are
|
||||
writes and require write-mode plus a whitelisted repository. Admin/credential
|
||||
endpoints are blocked unless `RAW_API_ALLOW_SENSITIVE=true`. See
|
||||
[Raw API Dispatch](raw-api.md) for the two-layer policy model and full details.
|
||||
|
||||
Note: `create_issue`, `add_labels`, and `remove_labels` accept label **names**; the
|
||||
server resolves them to Gitea label ids and returns a clear error for unknown labels.
|
||||
|
||||
Note: the `milestone` argument on `create_issue`/`update_issue` accepts either a numeric
|
||||
milestone **id** or a milestone **title** (resolved case-insensitively against open and
|
||||
closed milestones; unknown titles return a clear error). On `update_issue`, `milestone: 0`
|
||||
clears the issue's milestone. Gitea Projects (Kanban boards) are intentionally unsupported:
|
||||
the Gitea REST API exposes no project endpoints.
|
||||
|
||||
## Validation and Limits
|
||||
|
||||
- All tool argument schemas reject unknown fields.
|
||||
- List responses are capped by `MAX_TOOL_RESPONSE_ITEMS`.
|
||||
- Text payloads are capped by `MAX_TOOL_RESPONSE_CHARS`.
|
||||
- File reads are capped by `MAX_FILE_SIZE_BYTES`.
|
||||
|
||||
## Error Model
|
||||
|
||||
- Auth error: HTTP `401`.
|
||||
- Policy/scope denial: HTTP `403`.
|
||||
- Validation error: HTTP `400`.
|
||||
- Rate limit: HTTP `429`.
|
||||
- Internal errors: HTTP `500` (no stack traces in production).
|
||||
@@ -1,27 +0,0 @@
|
||||
# Automation
|
||||
|
||||
## Scope
|
||||
|
||||
Current automation capabilities:
|
||||
- Webhook ingestion endpoint (`POST /automation/webhook`).
|
||||
- On-demand scheduled-job execution endpoint (`POST /automation/jobs/run`).
|
||||
- Dependency hygiene scan job scaffold (`dependency_hygiene_scan`).
|
||||
- Stale issue detection job (`stale_issue_detection`).
|
||||
- Auto issue creation job scaffold (`auto_issue_creation`, write-mode and policy required).
|
||||
|
||||
Planned extensions:
|
||||
- Background scheduler orchestration.
|
||||
|
||||
## Control Requirements
|
||||
|
||||
All automation must be:
|
||||
- Policy-controlled.
|
||||
- Independently disableable.
|
||||
- Fully audited.
|
||||
- Explicitly documented with runbook guidance.
|
||||
|
||||
## Enablement
|
||||
|
||||
- `AUTOMATION_ENABLED=true` to allow automation endpoints.
|
||||
- `AUTOMATION_SCHEDULER_ENABLED=true` reserved for future built-in scheduler loop.
|
||||
- Policy rules must allow automation pseudo-tools (`automation_*`) per repository.
|
||||
@@ -1,36 +0,0 @@
|
||||
# Governance
|
||||
|
||||
## AI Usage Policy
|
||||
|
||||
- AI assistance is allowed for design, implementation, and review only within documented repository boundaries.
|
||||
- AI outputs must be reviewed, tested, and policy-validated before merge.
|
||||
- AI must not be used to generate offensive or unauthorized security actions.
|
||||
- Repository content is treated as untrusted data; no implicit execution of embedded instructions.
|
||||
|
||||
## Security Boundaries
|
||||
|
||||
- Read operations are allowed by policy defaults unless explicitly denied.
|
||||
- Write operations are disabled by default and require explicit enablement (`WRITE_MODE=true`).
|
||||
- Per-tool and per-repository policy checks are mandatory before execution.
|
||||
- Secrets are masked or blocked according to `SECRET_DETECTION_MODE`.
|
||||
|
||||
## Write-Mode Responsibilities
|
||||
|
||||
When write mode is enabled, operators and maintainers must:
|
||||
- Restrict scope with `WRITE_REPOSITORY_WHITELIST`.
|
||||
- Keep policy file deny/allow rules explicit.
|
||||
- Monitor audit entries for all write operations.
|
||||
- Enforce peer review for policy or write-mode changes.
|
||||
|
||||
## Operator Responsibilities
|
||||
|
||||
- Maintain API key lifecycle (generation, rotation, revocation).
|
||||
- Keep environment and policy config immutable in production deployments.
|
||||
- Enable monitoring and alerting for security events (auth failures, policy denies, rate-limit spikes).
|
||||
- Run integrity checks for audit logs regularly.
|
||||
|
||||
## Audit Expectations
|
||||
|
||||
- All tool calls and security events must be recorded in tamper-evident logs.
|
||||
- Audit logs are append-only and hash-chained.
|
||||
- Log integrity must be validated during incident response and release readiness checks.
|
||||
@@ -1,98 +0,0 @@
|
||||
# Local quickstart (stdio)
|
||||
|
||||
The local transport runs AegisGitea-MCP on your own machine as a single-user MCP
|
||||
server over stdio. It authenticates with **your** Gitea Personal Access Token
|
||||
(PAT) — there is no OAuth, no public endpoint, and no web stack to install.
|
||||
|
||||
## What you need
|
||||
|
||||
- A Gitea instance URL (`GITEA_URL`).
|
||||
- A Gitea Personal Access Token (`GITEA_TOKEN`) with least privilege:
|
||||
- `read:repository`
|
||||
- `write:repository` only if you intend to enable `WRITE_MODE`.
|
||||
- [`uv`](https://docs.astral.sh/uv/) (for `uvx`) or `pip`.
|
||||
|
||||
## Run it
|
||||
|
||||
With `uvx` (no install):
|
||||
|
||||
```bash
|
||||
GITEA_URL=https://git.hiddenden.cafe \
|
||||
GITEA_TOKEN=<pat> \
|
||||
uvx aegis-gitea-mcp
|
||||
```
|
||||
|
||||
With pip:
|
||||
|
||||
```bash
|
||||
pip install aegis-gitea-mcp
|
||||
GITEA_URL=https://git.hiddenden.cafe GITEA_TOKEN=<pat> aegis-gitea-mcp
|
||||
```
|
||||
|
||||
A local `.env` file is also supported — drop `GITEA_URL` and `GITEA_TOKEN` in it
|
||||
and just run `aegis-gitea-mcp`.
|
||||
|
||||
If a required variable is missing the server exits with a clear message instead
|
||||
of a traceback.
|
||||
|
||||
## Wire it into a client
|
||||
|
||||
Claude Code:
|
||||
|
||||
```bash
|
||||
claude mcp add aegis-gitea \
|
||||
-e GITEA_URL=https://git.hiddenden.cafe \
|
||||
-e GITEA_TOKEN=<pat> \
|
||||
-- uvx aegis-gitea-mcp
|
||||
```
|
||||
|
||||
Claude Desktop (`claude_desktop_config.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"aegis-gitea": {
|
||||
"command": "uvx",
|
||||
"args": ["aegis-gitea-mcp"],
|
||||
"env": {
|
||||
"GITEA_URL": "https://git.hiddenden.cafe",
|
||||
"GITEA_TOKEN": "<pat>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What still applies locally
|
||||
|
||||
The local adapter is single-user and trusts the PAT owner, so it skips the
|
||||
per-user repository-permission probe used by the public server. Everything else
|
||||
is identical to the server:
|
||||
|
||||
- **Policy engine** (`policy.yaml`) — same allow/deny rules.
|
||||
- **`WRITE_MODE`** — off by default; writes are denied unless explicitly enabled
|
||||
and whitelisted.
|
||||
- **`gitea_request`** full-API escape hatch — same write classifier, known-path
|
||||
gate, and admin/credential denylist.
|
||||
- **Secret sanitization** of tool output.
|
||||
- **Tamper-evident audit log** — written to a per-user path when the container
|
||||
default is not writable:
|
||||
- Windows: `%LOCALAPPDATA%\aegis-gitea-mcp\audit.log`
|
||||
- Linux/macOS: `$XDG_STATE_HOME/aegis-gitea-mcp/audit.log` or
|
||||
`~/.local/state/aegis-gitea-mcp/audit.log`
|
||||
- Override with `AUDIT_LOG_PATH`.
|
||||
|
||||
## Enabling writes locally
|
||||
|
||||
Writes are opt-in, exactly as on the server:
|
||||
|
||||
```bash
|
||||
GITEA_URL=https://git.hiddenden.cafe \
|
||||
GITEA_TOKEN=<pat-with-write-repository> \
|
||||
WRITE_MODE=true \
|
||||
WRITE_REPOSITORY_WHITELIST=acme/app,acme/docs \
|
||||
uvx aegis-gitea-mcp
|
||||
```
|
||||
|
||||
See [configuration.md](configuration.md) for the full variable reference and
|
||||
[write-mode.md](write-mode.md) for the write-mode model.
|
||||
@@ -1,48 +0,0 @@
|
||||
# Observability
|
||||
|
||||
## Logging
|
||||
|
||||
- Structured JSON logs.
|
||||
- Request correlation via `X-Request-ID`.
|
||||
- Security events and policy denials are audit logged.
|
||||
|
||||
### Structured event helpers
|
||||
|
||||
`logging_utils` exposes reusable helpers so endpoints emit consistent,
|
||||
secret-safe structured events instead of ad-hoc inline logging:
|
||||
|
||||
- `log_event(logger, level, event, **context)` — emit a named event with a
|
||||
`context` mapping; keys in `SENSITIVE_CONTEXT_KEYS` (e.g. `token`,
|
||||
`authorization`, `password`) are masked as `***`.
|
||||
- `log_nullable_field(logger, event, field, value)` — record whether a parsed
|
||||
response field is `None` and its runtime type, without dumping its contents.
|
||||
- `sanitize_context(context)` — the masking primitive used by the above.
|
||||
|
||||
The `context` mapping is serialized into the JSON log payload under a `context`
|
||||
key. These run at `DEBUG`, so they are silent unless `LOG_LEVEL=DEBUG`.
|
||||
|
||||
`get_issue` is instrumented with these helpers (`get_issue.start`,
|
||||
`get_issue.payload_shape`, `get_issue.field_check`) to make nullable-field
|
||||
parsing failures diagnosable. The same pattern can be reused for other
|
||||
parsing-heavy endpoints (`get_pull_request`, `list_issues`, `get_commit_diff`).
|
||||
|
||||
## Metrics
|
||||
|
||||
Prometheus-compatible endpoint: `GET /metrics`.
|
||||
|
||||
Current metrics:
|
||||
- `aegis_http_requests_total{method,path,status}`
|
||||
- `aegis_tool_calls_total{tool,status}`
|
||||
- `aegis_tool_duration_seconds_sum{tool}`
|
||||
- `aegis_tool_duration_seconds_count{tool}`
|
||||
|
||||
## Tracing and Correlation
|
||||
|
||||
- Request IDs propagate in response header (`X-Request-ID`).
|
||||
- Tool-level correlation IDs included in MCP responses.
|
||||
|
||||
## Operational Guidance
|
||||
|
||||
- Alert on spikes in 401/403/429 rates.
|
||||
- Alert on repeated `access_denied` and auth-rate-limit events.
|
||||
- Track tool latency trends for incident triage.
|
||||
@@ -1,52 +0,0 @@
|
||||
# Policy Engine
|
||||
|
||||
## Overview
|
||||
|
||||
Aegis uses a YAML policy engine to authorize tool execution before any Gitea API call is made.
|
||||
|
||||
## Behavior Summary
|
||||
|
||||
- Global tool allow/deny supported.
|
||||
- Per-repository tool allow/deny supported.
|
||||
- Optional repository path allow/deny supported.
|
||||
- Write operations are denied by default.
|
||||
- Write operations also require `WRITE_MODE=true` and either:
|
||||
- `WRITE_REPOSITORY_WHITELIST` match, or
|
||||
- `WRITE_ALLOW_ALL_TOKEN_REPOS=true`.
|
||||
|
||||
## Example Configuration
|
||||
|
||||
```yaml
|
||||
defaults:
|
||||
read: allow
|
||||
write: deny
|
||||
|
||||
tools:
|
||||
deny:
|
||||
- search_code
|
||||
|
||||
repositories:
|
||||
acme/service-a:
|
||||
tools:
|
||||
allow:
|
||||
- get_file_contents
|
||||
- list_commits
|
||||
paths:
|
||||
allow:
|
||||
- src/*
|
||||
deny:
|
||||
- src/secrets/*
|
||||
```
|
||||
|
||||
## Failure Behavior
|
||||
|
||||
- Invalid YAML or invalid schema: startup failure (fail closed).
|
||||
- Denied tool call: HTTP `403` + audit `access_denied` entry.
|
||||
- Path traversal attempt in path-scoped tools: denied by validation/policy checks.
|
||||
|
||||
## Operational Guidance
|
||||
|
||||
- Keep policy files version-controlled and code-reviewed.
|
||||
- Prefer explicit deny entries for sensitive tools.
|
||||
- Use repository-specific allow lists for high-risk environments.
|
||||
- Test policy updates in staging before production rollout.
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
# TODO
|
||||
|
||||
## Phase 0 Governance
|
||||
|
||||
- [x] Add `CODE_OF_CONDUCT.md`.
|
||||
- [x] Add governance policy documentation.
|
||||
- [x] Upgrade `AGENTS.md` as authoritative AI contract.
|
||||
|
||||
## Phase 1 Architecture
|
||||
|
||||
- [x] Publish roadmap and threat/security model updates.
|
||||
- [x] Publish phased TODO tracker.
|
||||
|
||||
## Phase 2 Expanded Read Tools
|
||||
|
||||
- [x] Implement `search_code`.
|
||||
- [x] Implement `list_commits`.
|
||||
- [x] Implement `get_commit_diff`.
|
||||
- [x] Implement `compare_refs`.
|
||||
- [x] Implement `list_issues`.
|
||||
- [x] Implement `get_issue`.
|
||||
- [x] Implement `list_pull_requests`.
|
||||
- [x] Implement `get_pull_request`.
|
||||
- [x] Implement `list_labels`.
|
||||
- [x] Implement `list_tags`.
|
||||
- [x] Implement `list_releases`.
|
||||
- [x] Add input validation and response bounds.
|
||||
- [x] Add unit/failure-mode tests.
|
||||
|
||||
## Phase 3 Policy Engine
|
||||
|
||||
- [x] Implement YAML policy loader and validator.
|
||||
- [x] Implement per-tool and per-repo allow/deny.
|
||||
- [x] Implement optional path restrictions.
|
||||
- [x] Enforce default write deny.
|
||||
- [x] Add policy unit tests.
|
||||
|
||||
## Phase 4 Write Mode
|
||||
|
||||
- [x] Implement write tools (`create_issue`, `update_issue`, comments, labels, assignment).
|
||||
- [x] Keep write mode disabled by default.
|
||||
- [x] Enforce repository whitelist.
|
||||
- [x] Ensure no merge/deletion/force-push capabilities.
|
||||
- [x] Add write denial tests.
|
||||
|
||||
## Phase 5 Hardening
|
||||
|
||||
- [x] Add secret detection + mask/block controls.
|
||||
- [x] Add prompt-injection defensive model (data-only handling).
|
||||
- [x] Add tamper-evident audit chaining and validation.
|
||||
- [x] Add per-IP and per-token rate limiting.
|
||||
|
||||
## Phase 6 Automation
|
||||
|
||||
- [x] Implement webhook ingestion pipeline.
|
||||
- [x] Implement on-demand scheduled jobs runner endpoint.
|
||||
- [x] Implement auto issue creation job scaffold from findings.
|
||||
- [x] Implement dependency hygiene scan orchestration scaffold.
|
||||
- [x] Implement stale issue detection automation.
|
||||
- [x] Add automation endpoint tests.
|
||||
|
||||
## Phase 7 Deployment
|
||||
|
||||
- [x] Harden Docker runtime defaults.
|
||||
- [x] Separate dev/prod compose profiles.
|
||||
- [x] Preserve non-root runtime and health checks.
|
||||
|
||||
## Phase 8 Observability
|
||||
|
||||
- [x] Add Prometheus metrics endpoint.
|
||||
- [x] Add structured JSON logging.
|
||||
- [x] Add request ID correlation.
|
||||
- [x] Add tool timing metrics.
|
||||
|
||||
## Phase 9 Testing and Release Readiness
|
||||
|
||||
- [x] Extend unit tests.
|
||||
- [x] Add policy tests.
|
||||
- [x] Add secret detection tests.
|
||||
- [x] Add write-mode denial tests.
|
||||
- [x] Add audit integrity tests.
|
||||
- [ ] Add integration-tagged tests against live Gitea (optional CI stage).
|
||||
- [ ] Final security review sign-off.
|
||||
- [ ] Release checklist execution.
|
||||
|
||||
## Phase 10 Local Package & Safe Full Coverage (0.2.0)
|
||||
|
||||
- [x] Extract transport-agnostic core + shared tool registry.
|
||||
- [x] Lock the core/web boundary with a no-fastapi import test.
|
||||
- [x] Add local stdio adapter (`stdio_app.py`) over the `mcp` SDK.
|
||||
- [x] Restructure packaging: core install + `[server]` extra + console scripts.
|
||||
- [x] Resource-type-aware authorization (repo/org/user/admin/misc), fail-closed.
|
||||
- [x] Classified `gitea_request`: write classifier + known-path gate + denylist.
|
||||
- [x] Authz matrix, write-mode bypass, classifier, and stdio adapter tests.
|
||||
- [x] `.gitea/workflows/publish.yml` (uv build + publish to Gitea registry on tag).
|
||||
- [ ] Make `list_organizations` user-scoped in service-PAT mode (`/users/{login}/orgs`)
|
||||
so it can be allowed instead of denied. (TODO(authz))
|
||||
|
||||
## Release Checklist
|
||||
|
||||
- [ ] `make lint`
|
||||
- [ ] `make test`
|
||||
- [ ] Documentation review complete
|
||||
- [ ] Policy file reviewed for production scope
|
||||
- [ ] Write mode remains disabled unless explicitly approved
|
||||
@@ -1,55 +0,0 @@
|
||||
# Write Mode
|
||||
|
||||
## Threat Model
|
||||
|
||||
Write mode introduces mutation risk (issue/PR changes, metadata updates). Risks include unauthorized action, accidental mass updates, and audit evasion.
|
||||
|
||||
## Default Posture
|
||||
|
||||
- `WRITE_MODE=false` by default.
|
||||
- When enabled, writes require repository whitelist membership by default.
|
||||
- Optional opt-in: `WRITE_ALLOW_ALL_TOKEN_REPOS=true` allows writes to any repo the token can access.
|
||||
- Policy engine remains authoritative and may deny specific write tools.
|
||||
|
||||
## Supported Write Tools
|
||||
|
||||
- `create_issue` (optional `milestone` id or title)
|
||||
- `update_issue` (optional `milestone`; `0` clears it)
|
||||
- `create_issue_comment`
|
||||
- `create_pr_comment`
|
||||
- `edit_issue_comment`
|
||||
- `add_labels`
|
||||
- `remove_labels`
|
||||
- `assign_issue`
|
||||
- `create_label`
|
||||
- `update_label`
|
||||
- `create_pull_request`
|
||||
- `create_release`
|
||||
- `edit_release`
|
||||
- `create_branch`
|
||||
- `create_milestone`
|
||||
|
||||
Not supported (explicitly forbidden): merge actions, branch/label/release deletion,
|
||||
force push, repo/admin management, and repository content writes (file create/edit,
|
||||
commits). Gitea Projects (Kanban boards) are unsupported because the Gitea REST API
|
||||
exposes no project endpoints.
|
||||
|
||||
## Enablement Steps
|
||||
|
||||
1. Set `WRITE_MODE=true`.
|
||||
2. Choose one:
|
||||
- `WRITE_REPOSITORY_WHITELIST=owner/repo,...` (recommended)
|
||||
- `WRITE_ALLOW_ALL_TOKEN_REPOS=true` (broader scope)
|
||||
3. Review policy file for write-tool scope.
|
||||
4. Verify audit logging and alerting before rollout.
|
||||
|
||||
## Safe Operations
|
||||
|
||||
- Start with one repository in whitelist.
|
||||
- Use narrowly scoped bot credentials.
|
||||
- Require peer review for whitelist/policy changes.
|
||||
- Disable write mode during incident response if abuse is suspected.
|
||||
|
||||
## Risk Tradeoffs
|
||||
|
||||
Write mode improves automation and triage speed but increases blast radius. Use least privilege, tight policy, and strong monitoring.
|
||||
Reference in new issue
Block a user