coord-mcp-server 0.27.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coord_mcp_server-0.27.1/.env.example +22 -0
- coord_mcp_server-0.27.1/.github/ISSUE_TEMPLATE/bug_report.yml +85 -0
- coord_mcp_server-0.27.1/.github/ISSUE_TEMPLATE/config.yml +8 -0
- coord_mcp_server-0.27.1/.github/ISSUE_TEMPLATE/feature_request.yml +37 -0
- coord_mcp_server-0.27.1/.github/PULL_REQUEST_TEMPLATE.md +29 -0
- coord_mcp_server-0.27.1/.github/dependabot.yml +46 -0
- coord_mcp_server-0.27.1/.github/workflows/README.md +293 -0
- coord_mcp_server-0.27.1/.github/workflows/ci.yml +124 -0
- coord_mcp_server-0.27.1/.github/workflows/release.yml +257 -0
- coord_mcp_server-0.27.1/.gitignore +28 -0
- coord_mcp_server-0.27.1/Dockerfile +65 -0
- coord_mcp_server-0.27.1/LICENSE +201 -0
- coord_mcp_server-0.27.1/PKG-INFO +446 -0
- coord_mcp_server-0.27.1/README.md +395 -0
- coord_mcp_server-0.27.1/compose.yaml +14 -0
- coord_mcp_server-0.27.1/coordination/__init__.py +14 -0
- coord_mcp_server-0.27.1/coordination/assets.py +360 -0
- coord_mcp_server-0.27.1/coordination/cli.py +252 -0
- coord_mcp_server-0.27.1/coordination/cli_doctor.py +638 -0
- coord_mcp_server-0.27.1/coordination/cli_init.py +444 -0
- coord_mcp_server-0.27.1/coordination/cli_ops.py +482 -0
- coord_mcp_server-0.27.1/coordination/cli_outbox.py +535 -0
- coord_mcp_server-0.27.1/coordination/cli_shared.py +171 -0
- coord_mcp_server-0.27.1/coordination/cli_start.py +195 -0
- coord_mcp_server-0.27.1/coordination/cli_update_notice.py +123 -0
- coord_mcp_server-0.27.1/coordination/cli_upgrade.py +159 -0
- coord_mcp_server-0.27.1/coordination/config.py +95 -0
- coord_mcp_server-0.27.1/coordination/dashboard.py +1477 -0
- coord_mcp_server-0.27.1/coordination/db.py +2772 -0
- coord_mcp_server-0.27.1/coordination/deps.py +10 -0
- coord_mcp_server-0.27.1/coordination/engine.py +311 -0
- coord_mcp_server-0.27.1/coordination/logging.py +147 -0
- coord_mcp_server-0.27.1/coordination/main.py +681 -0
- coord_mcp_server-0.27.1/coordination/mcp_server.py +1019 -0
- coord_mcp_server-0.27.1/coordination/metrics.py +194 -0
- coord_mcp_server-0.27.1/coordination/overlap_symbols.py +486 -0
- coord_mcp_server-0.27.1/coordination/ownership.py +524 -0
- coord_mcp_server-0.27.1/coordination/repo_config.py +44 -0
- coord_mcp_server-0.27.1/coordination/schemas.py +273 -0
- coord_mcp_server-0.27.1/coordination/service.py +1873 -0
- coord_mcp_server-0.27.1/coordination/symbols/__init__.py +218 -0
- coord_mcp_server-0.27.1/coordination/symbols/go_regex.py +180 -0
- coord_mcp_server-0.27.1/coordination/symbols/go_treesitter.py +319 -0
- coord_mcp_server-0.27.1/coordination/symbols/py_regex.py +328 -0
- coord_mcp_server-0.27.1/coordination/symbols/py_treesitter.py +379 -0
- coord_mcp_server-0.27.1/coordination/symbols/ts_regex.py +443 -0
- coord_mcp_server-0.27.1/coordination/symbols/ts_treesitter.py +394 -0
- coord_mcp_server-0.27.1/deploy/k8s/README.md +56 -0
- coord_mcp_server-0.27.1/deploy/k8s/prod/README.md +54 -0
- coord_mcp_server-0.27.1/docs/README.md +17 -0
- coord_mcp_server-0.27.1/docs/api-reference.md +569 -0
- coord_mcp_server-0.27.1/docs/architecture.md +185 -0
- coord_mcp_server-0.27.1/docs/deployment.md +215 -0
- coord_mcp_server-0.27.1/docs/design/multi-namespace.md +597 -0
- coord_mcp_server-0.27.1/docs/design/roadmap.md +97 -0
- coord_mcp_server-0.27.1/docs/design/sub-file-claims.md +383 -0
- coord_mcp_server-0.27.1/docs/getting-started.md +132 -0
- coord_mcp_server-0.27.1/docs/integrations/claude-code.md +121 -0
- coord_mcp_server-0.27.1/docs/integrations/codex-cli.md +110 -0
- coord_mcp_server-0.27.1/docs/quickstart.md +92 -0
- coord_mcp_server-0.27.1/docs/troubleshooting.md +188 -0
- coord_mcp_server-0.27.1/docs/usage-guide.md +454 -0
- coord_mcp_server-0.27.1/pyproject.toml +131 -0
- coord_mcp_server-0.27.1/scripts/auto-rebase.sh +21 -0
- coord_mcp_server-0.27.1/scripts/completions/_coord +79 -0
- coord_mcp_server-0.27.1/scripts/completions/coord.bash +90 -0
- coord_mcp_server-0.27.1/scripts/git-hooks/pre-push +34 -0
- coord_mcp_server-0.27.1/scripts/smoke-test.sh +65 -0
- coord_mcp_server-0.27.1/scripts/worktree-add.sh +26 -0
- coord_mcp_server-0.27.1/templates/.codex/config.toml.example +10 -0
- coord_mcp_server-0.27.1/templates/.coordination/MODULE_GUIDE.md +13 -0
- coord_mcp_server-0.27.1/templates/.coordination/eslint.restricted-imports.example.cjs +21 -0
- coord_mcp_server-0.27.1/templates/.coordination/hooks/pre-push +52 -0
- coord_mcp_server-0.27.1/templates/.coordination/owners.example.yaml +25 -0
- coord_mcp_server-0.27.1/templates/.cursor/mcp.json.example +12 -0
- coord_mcp_server-0.27.1/templates/.cursor/rules/coordination.mdc +21 -0
- coord_mcp_server-0.27.1/templates/.mcp.json.example +12 -0
- coord_mcp_server-0.27.1/templates/AGENTS.md.snippet.md +31 -0
- coord_mcp_server-0.27.1/templates/CLAUDE.md.snippet.md +33 -0
- coord_mcp_server-0.27.1/templates/MERGE_QUEUE.md +26 -0
- coord_mcp_server-0.27.1/templates/README.md +33 -0
- coord_mcp_server-0.27.1/templates/github-coordination-semantic.yml +31 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Core server settings
|
|
2
|
+
COORD_AUTH_TOKEN=change-me
|
|
3
|
+
COORD_DATABASE_PATH=data/coordination.db
|
|
4
|
+
COORD_HOST=0.0.0.0
|
|
5
|
+
COORD_PORT=8080
|
|
6
|
+
COORD_LOG_LEVEL=info
|
|
7
|
+
|
|
8
|
+
# Optional local-only bypass. Prefer leaving this false.
|
|
9
|
+
COORD_ALLOW_INSECURE_NO_AUTH=false
|
|
10
|
+
|
|
11
|
+
# Optional: point at an application repo checkout for better overlap matching.
|
|
12
|
+
# COORD_REPO_ROOT=/absolute/path/to/your-app
|
|
13
|
+
|
|
14
|
+
# Claim sizing and cleanup
|
|
15
|
+
COORD_MAX_CLAIM_FILES=100
|
|
16
|
+
COORD_MAX_CLAIM_RATIO=0.2
|
|
17
|
+
COORD_CLEANUP_INTERVAL_SEC=900
|
|
18
|
+
COORD_DEFAULT_TTL_HOURS=4
|
|
19
|
+
COORD_SHARED_TTL_HOURS=2
|
|
20
|
+
|
|
21
|
+
# MCP bridge defaults
|
|
22
|
+
COORD_API_URL=http://127.0.0.1:8080
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a defect in coord (HTTP API, MCP bridge, dashboard, CLI).
|
|
3
|
+
title: "[bug]: "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for filing a report. Please run `coord doctor` first; it catches the majority of setup issues without needing a maintainer.
|
|
10
|
+
|
|
11
|
+
- type: input
|
|
12
|
+
id: version
|
|
13
|
+
attributes:
|
|
14
|
+
label: coord version
|
|
15
|
+
description: Output of `coord --version` or the tag you installed.
|
|
16
|
+
placeholder: "0.27.0"
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: dropdown
|
|
21
|
+
id: mcp_client
|
|
22
|
+
attributes:
|
|
23
|
+
label: MCP client
|
|
24
|
+
description: Which agent harness are you driving coord with?
|
|
25
|
+
options:
|
|
26
|
+
- Claude Code
|
|
27
|
+
- Codex CLI
|
|
28
|
+
- Cursor
|
|
29
|
+
- Other (describe in steps to reproduce)
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
|
|
33
|
+
- type: input
|
|
34
|
+
id: os
|
|
35
|
+
attributes:
|
|
36
|
+
label: OS
|
|
37
|
+
description: Operating system and version. Include container runtime if applicable.
|
|
38
|
+
placeholder: "macOS 14.5 / Ubuntu 24.04 / Docker 27 on Debian 12"
|
|
39
|
+
validations:
|
|
40
|
+
required: true
|
|
41
|
+
|
|
42
|
+
- type: textarea
|
|
43
|
+
id: steps
|
|
44
|
+
attributes:
|
|
45
|
+
label: Steps to reproduce
|
|
46
|
+
description: Minimal sequence of commands or API calls that triggers the bug.
|
|
47
|
+
placeholder: |
|
|
48
|
+
1. `coord start --background`
|
|
49
|
+
2. From a second shell: `coord init --tool claude --mode local --yes`
|
|
50
|
+
3. ...
|
|
51
|
+
validations:
|
|
52
|
+
required: true
|
|
53
|
+
|
|
54
|
+
- type: textarea
|
|
55
|
+
id: expected
|
|
56
|
+
attributes:
|
|
57
|
+
label: Expected behavior
|
|
58
|
+
description: What did you expect to happen?
|
|
59
|
+
|
|
60
|
+
- type: textarea
|
|
61
|
+
id: actual
|
|
62
|
+
attributes:
|
|
63
|
+
label: Actual behavior
|
|
64
|
+
description: What actually happened? Include exit codes, error messages, or HTTP status.
|
|
65
|
+
validations:
|
|
66
|
+
required: true
|
|
67
|
+
|
|
68
|
+
- type: textarea
|
|
69
|
+
id: logs
|
|
70
|
+
attributes:
|
|
71
|
+
label: Logs
|
|
72
|
+
description: Relevant output from the service log, MCP stderr, or `coord doctor`. Redact any token values before pasting.
|
|
73
|
+
render: shell
|
|
74
|
+
|
|
75
|
+
- type: checkboxes
|
|
76
|
+
id: checks
|
|
77
|
+
attributes:
|
|
78
|
+
label: Have you checked
|
|
79
|
+
options:
|
|
80
|
+
- label: I searched existing issues (open and closed) for a duplicate.
|
|
81
|
+
required: true
|
|
82
|
+
- label: I read `./docs/troubleshooting.md`.
|
|
83
|
+
required: true
|
|
84
|
+
- label: I ran `coord doctor` and reviewed its output.
|
|
85
|
+
required: true
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Setup or runtime troubleshooting
|
|
4
|
+
url: https://github.com/amittell/coord/blob/main/docs/troubleshooting.md
|
|
5
|
+
about: Most setup and runtime issues are covered here. Try this before opening a bug report.
|
|
6
|
+
- name: Report a security vulnerability
|
|
7
|
+
url: https://github.com/amittell/coord/security/advisories/new
|
|
8
|
+
about: Do not file a public issue for security reports. Open a private advisory instead. See SECURITY.md for the policy.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a new capability or behaviour change for coord.
|
|
3
|
+
title: "[feat]: "
|
|
4
|
+
labels: ["enhancement"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Before filing, please skim `./docs/design/roadmap.md` to see whether your idea overlaps something already queued. If it does, comment on the linked issue instead of opening a new one.
|
|
10
|
+
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: problem
|
|
13
|
+
attributes:
|
|
14
|
+
label: Problem you're trying to solve
|
|
15
|
+
description: What's the underlying user need? Describe the friction, not the proposed implementation.
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: solution
|
|
21
|
+
attributes:
|
|
22
|
+
label: Proposed solution
|
|
23
|
+
description: What would the API, MCP tool, dashboard surface, or CLI command look like? Sketch the smallest version that solves the problem.
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: textarea
|
|
28
|
+
id: alternatives
|
|
29
|
+
attributes:
|
|
30
|
+
label: Alternatives considered
|
|
31
|
+
description: What workarounds exist today, and why are they insufficient?
|
|
32
|
+
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: roadmap
|
|
35
|
+
attributes:
|
|
36
|
+
label: Roadmap fit
|
|
37
|
+
description: Optional. If you've checked `./docs/design/roadmap.md`, note any related queued item or explain where this would slot in.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences on what this PR does and why. -->
|
|
4
|
+
|
|
5
|
+
## Changes
|
|
6
|
+
|
|
7
|
+
<!-- Bullet list of files / modules touched and the nature of the change. -->
|
|
8
|
+
|
|
9
|
+
-
|
|
10
|
+
-
|
|
11
|
+
|
|
12
|
+
## Test plan
|
|
13
|
+
|
|
14
|
+
<!-- Commands you ran locally to verify the change. -->
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
make check
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Related issue
|
|
21
|
+
|
|
22
|
+
<!-- Optional. Use `Closes #N` to auto-close on merge. -->
|
|
23
|
+
|
|
24
|
+
## Checklist
|
|
25
|
+
|
|
26
|
+
- [ ] `make check` passes locally (ruff + mypy + pytest)
|
|
27
|
+
- [ ] `CHANGELOG.md` updated under `## [Unreleased]` if the change is user-visible
|
|
28
|
+
- [ ] Any new third-party GitHub Actions are pinned by full commit SHA with a trailing `# vX.Y.Z` comment
|
|
29
|
+
- [ ] No production code / tests / deploy / templates files touched outside the PR's stated scope
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python dependencies declared in the root pyproject.toml. Group
|
|
4
|
+
# patch + minor bumps together so they land as a single PR per week;
|
|
5
|
+
# majors still open as their own PR for focused review.
|
|
6
|
+
- package-ecosystem: "pip"
|
|
7
|
+
directory: "/"
|
|
8
|
+
schedule:
|
|
9
|
+
interval: "weekly"
|
|
10
|
+
day: "monday"
|
|
11
|
+
open-pull-requests-limit: 5
|
|
12
|
+
groups:
|
|
13
|
+
python-minor-and-patch:
|
|
14
|
+
update-types:
|
|
15
|
+
- "minor"
|
|
16
|
+
- "patch"
|
|
17
|
+
|
|
18
|
+
# GitHub Actions used in .github/workflows/. Dependabot is allowed
|
|
19
|
+
# to auto-update action SHAs here, which is the whole point of the
|
|
20
|
+
# pinning discipline. Group patch + minor bumps; majors stay
|
|
21
|
+
# individual.
|
|
22
|
+
- package-ecosystem: "github-actions"
|
|
23
|
+
directory: "/"
|
|
24
|
+
schedule:
|
|
25
|
+
interval: "weekly"
|
|
26
|
+
day: "monday"
|
|
27
|
+
open-pull-requests-limit: 5
|
|
28
|
+
groups:
|
|
29
|
+
actions-minor-and-patch:
|
|
30
|
+
update-types:
|
|
31
|
+
- "minor"
|
|
32
|
+
- "patch"
|
|
33
|
+
|
|
34
|
+
# Dockerfile base image. Container ships via the release workflow,
|
|
35
|
+
# so keep base-image updates visible. Weekly cadence, all bumps in
|
|
36
|
+
# one PR.
|
|
37
|
+
- package-ecosystem: "docker"
|
|
38
|
+
directory: "/"
|
|
39
|
+
schedule:
|
|
40
|
+
interval: "weekly"
|
|
41
|
+
day: "monday"
|
|
42
|
+
open-pull-requests-limit: 2
|
|
43
|
+
groups:
|
|
44
|
+
docker-all:
|
|
45
|
+
patterns:
|
|
46
|
+
- "*"
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# GitHub Actions workflows
|
|
2
|
+
|
|
3
|
+
This directory contains the CI and release automation for `coord`.
|
|
4
|
+
|
|
5
|
+
## `ci.yml`
|
|
6
|
+
|
|
7
|
+
Runs on every push to `main` and every pull request.
|
|
8
|
+
|
|
9
|
+
Jobs:
|
|
10
|
+
|
|
11
|
+
1. `test` (matrix: Ubuntu + Python 3.11, Ubuntu + Python 3.12,
|
|
12
|
+
Ubuntu + Python 3.14, macOS + Python 3.12, Windows + Python 3.12) -
|
|
13
|
+
installs the project with dev extras, runs `ruff check .`, then
|
|
14
|
+
`pytest -q`. All runners use `bash` as the default shell so quoting
|
|
15
|
+
and pipelines behave consistently on Windows (via Git for Windows'
|
|
16
|
+
bash). The 3.14 row matches the Python version shipped in the
|
|
17
|
+
release container (`python:3.14-slim`) so CI exercises what we
|
|
18
|
+
ship; 3.11 is kept as the baseline per `requires-python = ">=3.11"`
|
|
19
|
+
in `pyproject.toml`. 3.14 is Ubuntu-only to avoid tripling runner
|
|
20
|
+
usage for incremental coverage.
|
|
21
|
+
2. `lint-workflows` - runs `actionlint` (via `reviewdog/action-actionlint@v1`)
|
|
22
|
+
over `.github/workflows/` to catch YAML and Actions mistakes.
|
|
23
|
+
3. `type-check` - runs `mypy coordination` against Python 3.12 with a
|
|
24
|
+
permissive starter config (see `[tool.mypy]` in `pyproject.toml`).
|
|
25
|
+
Tests are excluded, missing import stubs are ignored, and strict
|
|
26
|
+
mode is off. The intent is to guard against regressions on the
|
|
27
|
+
production package without blocking PRs on unrelated type-noise.
|
|
28
|
+
Tighten the config in follow-up PRs as the codebase gains annotations.
|
|
29
|
+
4. `docker-build` - depends on `test`; builds the container image with
|
|
30
|
+
`docker/build-push-action@v6` (no push, `load: true`) to prove the
|
|
31
|
+
Dockerfile still works. Uses GitHub Actions cache (`type=gha`).
|
|
32
|
+
|
|
33
|
+
`test`, `lint-workflows`, and `type-check` run in parallel; `docker-build`
|
|
34
|
+
is gated on `test` so a broken test suite does not waste Docker build
|
|
35
|
+
minutes.
|
|
36
|
+
|
|
37
|
+
Concurrency: superseded CI runs on the same ref are cancelled
|
|
38
|
+
(`cancel-in-progress: true`).
|
|
39
|
+
|
|
40
|
+
Permissions: `contents: read` only.
|
|
41
|
+
|
|
42
|
+
## `release.yml`
|
|
43
|
+
|
|
44
|
+
Runs on git tag pushes matching `v*`, and can also be triggered manually
|
|
45
|
+
via `workflow_dispatch`.
|
|
46
|
+
|
|
47
|
+
Jobs:
|
|
48
|
+
|
|
49
|
+
- `publish-image` - builds a multi-arch (`linux/amd64`, `linux/arm64`)
|
|
50
|
+
container image and pushes to `ghcr.io/<owner>/coord`, emits an
|
|
51
|
+
SPDX SBOM plus SLSA provenance attestations (BuildKit-native and
|
|
52
|
+
GitHub-native), signs the image keyless with cosign, and (for real
|
|
53
|
+
tag pushes) creates a GitHub Release with auto-generated notes.
|
|
54
|
+
- `publish-pypi` - on real tag pushes only (skipped on
|
|
55
|
+
`workflow_dispatch`), builds the sdist + wheel, validates that the
|
|
56
|
+
tag matches `pyproject.toml`'s `version` field, and publishes to
|
|
57
|
+
PyPI via OIDC trusted publishing (no API token stored in repo
|
|
58
|
+
secrets). Bootstrap requires a one-time pending-publisher
|
|
59
|
+
registration on PyPI; see "PyPI trusted publishing" below.
|
|
60
|
+
|
|
61
|
+
Tag behaviour:
|
|
62
|
+
|
|
63
|
+
| Trigger | Pushed tags | GitHub Release |
|
|
64
|
+
|---------------------|-------------------------------------|----------------|
|
|
65
|
+
| `push` (git tag) | `:<tag>` and `:latest` | yes |
|
|
66
|
+
| `workflow_dispatch` | `:<inputs.version>` only (no latest)| no |
|
|
67
|
+
|
|
68
|
+
The `workflow_dispatch` path deliberately does not push `:latest` so
|
|
69
|
+
release candidates and ad-hoc rebuilds cannot clobber the production
|
|
70
|
+
`:latest` pointer.
|
|
71
|
+
|
|
72
|
+
Concurrency: release runs are NOT cancelled in flight
|
|
73
|
+
(`cancel-in-progress: false`) so a half-pushed multi-arch image cannot
|
|
74
|
+
be left behind by a second run.
|
|
75
|
+
|
|
76
|
+
### Required permissions
|
|
77
|
+
|
|
78
|
+
Set on the `release.yml` workflow itself:
|
|
79
|
+
|
|
80
|
+
- `contents: write` - `softprops/action-gh-release@v2` needs this to
|
|
81
|
+
create the GitHub Release.
|
|
82
|
+
- `packages: write` - push to GHCR.
|
|
83
|
+
- `id-token: write` - OIDC token for
|
|
84
|
+
`actions/attest-build-provenance@v2`.
|
|
85
|
+
- `attestations: write` - store the attestation on the repo.
|
|
86
|
+
|
|
87
|
+
### Required repository secrets
|
|
88
|
+
|
|
89
|
+
None beyond the default `GITHUB_TOKEN`. GHCR login uses
|
|
90
|
+
`${{ secrets.GITHUB_TOKEN }}` directly.
|
|
91
|
+
|
|
92
|
+
### GitHub Enterprise
|
|
93
|
+
|
|
94
|
+
The release workflow defaults to `ghcr.io/<owner>/coord`, but both the
|
|
95
|
+
registry host and the repo path are overridable through repo or org
|
|
96
|
+
Actions variables (no secret values required):
|
|
97
|
+
|
|
98
|
+
- `IMAGE_REGISTRY` - registry hostname, for example
|
|
99
|
+
`containers.ghe.example.com`. If unset, defaults to `ghcr.io`.
|
|
100
|
+
- `IMAGE_REPO` - path under the registry, for example
|
|
101
|
+
`platform/coord`. If unset, defaults to
|
|
102
|
+
`<github.repository_owner>/coord`.
|
|
103
|
+
|
|
104
|
+
Set them under Settings -> Secrets and variables -> Actions -> Variables.
|
|
105
|
+
The workflow resolves them at runtime and falls back to the GHCR
|
|
106
|
+
defaults when unset, so upstream behavior is preserved.
|
|
107
|
+
|
|
108
|
+
Login continues to use `${{ secrets.GITHUB_TOKEN }}` against the
|
|
109
|
+
configured registry. Some GHE setups require a separate Personal Access
|
|
110
|
+
Token (PAT) with `write:packages` (or the enterprise-equivalent) scope
|
|
111
|
+
if the default `GITHUB_TOKEN` cannot push to your registry; in that
|
|
112
|
+
case, store the PAT as a repo secret and swap `password:` in the
|
|
113
|
+
`docker/login-action` step accordingly. This is a common GHE gotcha
|
|
114
|
+
rather than a hard requirement - try the default token first.
|
|
115
|
+
|
|
116
|
+
`actions/attest-build-provenance@v2` requires **GitHub Enterprise
|
|
117
|
+
Server 3.10 or later** with the attestations feature enabled, OR a
|
|
118
|
+
public repository, OR a private repository owned by an organization
|
|
119
|
+
on a plan that supports attestations. It **does NOT work on personal
|
|
120
|
+
(user-owned) private repositories** - the step fails with
|
|
121
|
+
"Feature not available for user-owned private repositories".
|
|
122
|
+
|
|
123
|
+
In any of those unsupported cases, set the repo or org Actions
|
|
124
|
+
variable `SKIP_ATTESTATION=true` and the provenance step will be
|
|
125
|
+
skipped cleanly. The image push, BuildKit-native SBOM/provenance
|
|
126
|
+
attestations, and cosign signing are all unaffected. This project's
|
|
127
|
+
own `amittell/coord` repo (user-owned private) sets this var.
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
Settings -> Secrets and variables -> Actions -> Variables
|
|
131
|
+
SKIP_ATTESTATION = true
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### SBOM and image attestations
|
|
135
|
+
|
|
136
|
+
Every successful release now emits four independent supply-chain
|
|
137
|
+
signals against the pushed image:
|
|
138
|
+
|
|
139
|
+
1. **BuildKit SBOM attestation** (SPDX JSON) - produced by
|
|
140
|
+
`docker/build-push-action` with `sbom: true`. Attached to the image
|
|
141
|
+
manifest as an OCI referrer and retrievable with
|
|
142
|
+
`docker buildx imagetools inspect <ref> --format '{{json .SBOM}}'`
|
|
143
|
+
or `cosign download sbom <ref>`.
|
|
144
|
+
2. **BuildKit SLSA provenance attestation** (`mode=max`) - produced by
|
|
145
|
+
the same action with `provenance: mode=max`. Includes the full build
|
|
146
|
+
invocation, materials, and builder identity. Inspect with
|
|
147
|
+
`docker buildx imagetools inspect <ref> --format '{{json .Provenance}}'`.
|
|
148
|
+
3. **GitHub-native provenance attestation** - produced by
|
|
149
|
+
`actions/attest-build-provenance@v2` and stored in the repo-level
|
|
150
|
+
attestations store (separate from the OCI-attached BuildKit output).
|
|
151
|
+
Verifiable with `gh attestation verify`.
|
|
152
|
+
4. **Cosign keyless signature** - see below.
|
|
153
|
+
|
|
154
|
+
The BuildKit attestations (1, 2) and the GitHub attestation (3) are
|
|
155
|
+
independent. Keeping both is intentional: the OCI-attached artifacts
|
|
156
|
+
travel with the image across registry mirrors, while the GitHub-stored
|
|
157
|
+
attestation is queryable through the GitHub API without pulling the
|
|
158
|
+
image.
|
|
159
|
+
|
|
160
|
+
### Cosign signing
|
|
161
|
+
|
|
162
|
+
The workflow signs the pushed image with `cosign sign --yes` in
|
|
163
|
+
keyless mode. The signing identity is the workflow's ephemeral OIDC
|
|
164
|
+
token (no long-lived keys), and the signature is anchored in the
|
|
165
|
+
public Rekor transparency log.
|
|
166
|
+
|
|
167
|
+
Verify a signed image against this repository's workflow identity:
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
cosign verify \
|
|
171
|
+
--certificate-identity-regexp '^https://github.com/<owner>/<repo>/\.github/workflows/release\.yml@' \
|
|
172
|
+
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
|
|
173
|
+
ghcr.io/<owner>/coord@sha256:<digest>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Replace `<owner>/<repo>` and the digest to match your fork and target
|
|
177
|
+
image. The `--certificate-identity-regexp` value pins the expected
|
|
178
|
+
signer to this exact workflow file - accept no others.
|
|
179
|
+
|
|
180
|
+
The `cosign-installer` action is pinned by commit SHA
|
|
181
|
+
(`sigstore/cosign-installer@d7543c93...` = v3.10.0) and fetches a
|
|
182
|
+
fixed cosign CLI release (currently v3.0.6) via `cosign-release:`.
|
|
183
|
+
|
|
184
|
+
### Disabling individual signals
|
|
185
|
+
|
|
186
|
+
Each signing or attestation step is gated on a repo or org Actions
|
|
187
|
+
variable so operators can disable any one without editing the
|
|
188
|
+
workflow:
|
|
189
|
+
|
|
190
|
+
| Variable | Effect when set to `true` |
|
|
191
|
+
|----------|---------------------------|
|
|
192
|
+
| `SKIP_ATTESTATION` | Skips `actions/attest-build-provenance`. Required on GHES older than 3.10 or where the attestations feature is disabled. |
|
|
193
|
+
| `SKIP_SIGNING` | Skips both `Install cosign` and `Sign image with cosign (keyless)`. Use on runners that cannot reach the Sigstore public good instance (Fulcio / Rekor). |
|
|
194
|
+
|
|
195
|
+
The BuildKit SBOM and BuildKit provenance attestations are emitted
|
|
196
|
+
unconditionally by the build step and have no skip variable; they are
|
|
197
|
+
produced locally by BuildKit and pushed alongside the image manifest,
|
|
198
|
+
so they do not depend on external services.
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
Settings -> Secrets and variables -> Actions -> Variables
|
|
202
|
+
SKIP_ATTESTATION = true # older GHES without attestations API
|
|
203
|
+
SKIP_SIGNING = true # environments without Sigstore access
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### PyPI trusted publishing
|
|
207
|
+
|
|
208
|
+
The `publish-pypi` job uploads to PyPI without an API token by
|
|
209
|
+
exchanging GitHub's OIDC identity for a short-lived PyPI token at
|
|
210
|
+
publish time. This requires a one-time pending-publisher
|
|
211
|
+
registration on PyPI before the first publish succeeds.
|
|
212
|
+
|
|
213
|
+
Bootstrap steps (one-time, by a project maintainer with PyPI
|
|
214
|
+
account access):
|
|
215
|
+
|
|
216
|
+
1. Sign in at `https://pypi.org`.
|
|
217
|
+
2. Go to "Your account" -> "Publishing" -> "Add a new pending
|
|
218
|
+
publisher" (the form is at
|
|
219
|
+
`https://pypi.org/manage/account/publishing/`).
|
|
220
|
+
3. Fill in:
|
|
221
|
+
- PyPI Project Name: `coord-mcp-server`
|
|
222
|
+
- Owner: `amittell`
|
|
223
|
+
- Repository name: `coord`
|
|
224
|
+
- Workflow name: `release.yml`
|
|
225
|
+
- Environment name: `pypi`
|
|
226
|
+
4. Save. PyPI now trusts this exact workflow file on this exact
|
|
227
|
+
repo to publish under the named project. The next tagged push
|
|
228
|
+
that runs the workflow will create the project on first
|
|
229
|
+
publish.
|
|
230
|
+
|
|
231
|
+
GitHub side: create an environment called `pypi` under Settings
|
|
232
|
+
-> Environments. Optionally add deployment protection rules
|
|
233
|
+
(required reviewers, deployment branches, etc.) -- the
|
|
234
|
+
environment binding alone is enough for OIDC to work.
|
|
235
|
+
|
|
236
|
+
After bootstrap, every `git tag v0.X.Y && git push --tags`
|
|
237
|
+
triggers a build + publish. The workflow refuses to publish if
|
|
238
|
+
the tag version does not match the `version` field in
|
|
239
|
+
`pyproject.toml`, so an accidental tag without a version bump is
|
|
240
|
+
caught at the verification step.
|
|
241
|
+
|
|
242
|
+
To pause PyPI publishing without disabling the whole release:
|
|
243
|
+
remove the pending publisher in PyPI, or change the workflow's
|
|
244
|
+
environment to a name that PyPI does not trust. The `:latest`
|
|
245
|
+
container image and GitHub Release still publish from
|
|
246
|
+
`publish-image`.
|
|
247
|
+
|
|
248
|
+
### Manual trigger (workflow_dispatch)
|
|
249
|
+
|
|
250
|
+
Via the GitHub UI: Actions tab -> `release` -> Run workflow -> supply
|
|
251
|
+
`version` (for example `v0.1.0-rc1`).
|
|
252
|
+
|
|
253
|
+
Via `gh`:
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
gh workflow run release.yml -f version=v0.1.0-rc1
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The resulting image will be pushed as
|
|
260
|
+
`ghcr.io/<owner>/coord:v0.1.0-rc1` and `:latest` will not be touched.
|
|
261
|
+
|
|
262
|
+
## Verification
|
|
263
|
+
|
|
264
|
+
Locally:
|
|
265
|
+
|
|
266
|
+
```
|
|
267
|
+
python -c "import yaml; list(yaml.safe_load_all(open('.github/workflows/ci.yml')))"
|
|
268
|
+
python -c "import yaml; list(yaml.safe_load_all(open('.github/workflows/release.yml')))"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
If you have `actionlint` installed:
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
actionlint .github/workflows/*.yml
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Pinning policy
|
|
278
|
+
|
|
279
|
+
Third-party actions are pinned to a full 40-char commit SHA, with the
|
|
280
|
+
readable version tag preserved in a trailing comment, for example:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
This blocks tag-retargeting supply-chain attacks: the workflow runs the
|
|
287
|
+
exact commit reviewed at pin time, regardless of what the upstream tag
|
|
288
|
+
later points at.
|
|
289
|
+
|
|
290
|
+
Updates are handled by Dependabot (`.github/dependabot.yml`), which
|
|
291
|
+
opens a weekly grouped PR that bumps both the SHA and the trailing
|
|
292
|
+
version comment in lockstep. The same config also keeps `requirements.txt`
|
|
293
|
+
and the Dockerfile base image current.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
# Cancel superseded CI runs on the same ref to save minutes.
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
test:
|
|
19
|
+
name: test (${{ matrix.os }} py${{ matrix.python-version }})
|
|
20
|
+
runs-on: ${{ matrix.os }}
|
|
21
|
+
strategy:
|
|
22
|
+
fail-fast: false
|
|
23
|
+
matrix:
|
|
24
|
+
include:
|
|
25
|
+
- os: ubuntu-latest
|
|
26
|
+
python-version: "3.11"
|
|
27
|
+
- os: ubuntu-latest
|
|
28
|
+
python-version: "3.12"
|
|
29
|
+
- os: ubuntu-latest
|
|
30
|
+
python-version: "3.14"
|
|
31
|
+
- os: macos-latest
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
- os: windows-latest
|
|
34
|
+
python-version: "3.12"
|
|
35
|
+
# Force bash on all runners so quoting and pipelines behave consistently.
|
|
36
|
+
# Windows GHA runners ship Git for Windows' bash at /usr/bin/bash.
|
|
37
|
+
defaults:
|
|
38
|
+
run:
|
|
39
|
+
shell: bash
|
|
40
|
+
steps:
|
|
41
|
+
- name: Check out repository
|
|
42
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
43
|
+
|
|
44
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
45
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
46
|
+
with:
|
|
47
|
+
python-version: ${{ matrix.python-version }}
|
|
48
|
+
cache: pip
|
|
49
|
+
cache-dependency-path: |
|
|
50
|
+
pyproject.toml
|
|
51
|
+
requirements.txt
|
|
52
|
+
|
|
53
|
+
- name: Install project with dev extras
|
|
54
|
+
run: |
|
|
55
|
+
python -m pip install --upgrade pip
|
|
56
|
+
python -m pip install ".[dev]"
|
|
57
|
+
|
|
58
|
+
- name: Lint with ruff
|
|
59
|
+
run: ruff check .
|
|
60
|
+
|
|
61
|
+
- name: Run tests
|
|
62
|
+
run: pytest -q
|
|
63
|
+
|
|
64
|
+
lint-workflows:
|
|
65
|
+
name: lint workflows (actionlint)
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
steps:
|
|
68
|
+
- name: Check out repository
|
|
69
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
70
|
+
|
|
71
|
+
- name: Run actionlint
|
|
72
|
+
uses: reviewdog/action-actionlint@6fb7acc99f4a1008869fa8a0f09cfca740837d9d # v1.72.0
|
|
73
|
+
with:
|
|
74
|
+
reporter: github-check
|
|
75
|
+
level: error
|
|
76
|
+
fail_level: error
|
|
77
|
+
|
|
78
|
+
type-check:
|
|
79
|
+
name: type check (mypy)
|
|
80
|
+
runs-on: ubuntu-latest
|
|
81
|
+
steps:
|
|
82
|
+
- name: Check out repository
|
|
83
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
84
|
+
|
|
85
|
+
- name: Set up Python 3.12
|
|
86
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
87
|
+
with:
|
|
88
|
+
python-version: "3.12"
|
|
89
|
+
cache: pip
|
|
90
|
+
cache-dependency-path: |
|
|
91
|
+
pyproject.toml
|
|
92
|
+
requirements.txt
|
|
93
|
+
|
|
94
|
+
- name: Install project with dev extras
|
|
95
|
+
run: |
|
|
96
|
+
python -m pip install --upgrade pip
|
|
97
|
+
python -m pip install ".[dev]"
|
|
98
|
+
|
|
99
|
+
- name: Run mypy
|
|
100
|
+
run: mypy coordination
|
|
101
|
+
|
|
102
|
+
docker-build:
|
|
103
|
+
name: docker build smoke
|
|
104
|
+
needs: test
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
steps:
|
|
107
|
+
- name: Check out repository
|
|
108
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
109
|
+
|
|
110
|
+
- name: Set up Docker Buildx
|
|
111
|
+
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
|
|
112
|
+
|
|
113
|
+
# Build the image once (amd64 only, no push) to catch Dockerfile
|
|
114
|
+
# regressions on every PR without spending time on multi-arch.
|
|
115
|
+
- name: Build image (no push)
|
|
116
|
+
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
|
|
117
|
+
with:
|
|
118
|
+
context: .
|
|
119
|
+
file: ./Dockerfile
|
|
120
|
+
push: false
|
|
121
|
+
load: true
|
|
122
|
+
tags: coord:ci
|
|
123
|
+
cache-from: type=gha
|
|
124
|
+
cache-to: type=gha,mode=max
|