opencode-talk-bridge 0.2.8__tar.gz → 0.3.0__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.
Files changed (60) hide show
  1. opencode_talk_bridge-0.3.0/.github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  2. opencode_talk_bridge-0.3.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  3. opencode_talk_bridge-0.3.0/.github/ISSUE_TEMPLATE/feature_request.yml +33 -0
  4. opencode_talk_bridge-0.3.0/.github/PULL_REQUEST_TEMPLATE.md +20 -0
  5. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/CHANGELOG.md +23 -1
  6. opencode_talk_bridge-0.3.0/CONTRIBUTING.md +101 -0
  7. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/PKG-INFO +31 -3
  8. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/README.md +30 -2
  9. opencode_talk_bridge-0.3.0/SECURITY.md +51 -0
  10. opencode_talk_bridge-0.3.0/docs/publishing.md +49 -0
  11. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/pyproject.toml +1 -1
  12. opencode_talk_bridge-0.3.0/src/opencode_talk_bridge/__init__.py +15 -0
  13. opencode_talk_bridge-0.3.0/tests/test_version.py +12 -0
  14. opencode_talk_bridge-0.2.8/docs/publishing.md +0 -58
  15. opencode_talk_bridge-0.2.8/src/opencode_talk_bridge/__init__.py +0 -8
  16. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/.env.example +0 -0
  17. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/.github/workflows/ci.yml +0 -0
  18. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/.github/workflows/publish.yml +0 -0
  19. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/.gitignore +0 -0
  20. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/LICENSE +0 -0
  21. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/deploy/com.leiverkus.opencode-talk-bridge.plist +0 -0
  22. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/docs/smoke-test.md +0 -0
  23. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/__main__.py +0 -0
  24. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/allowlist.py +0 -0
  25. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/bridge.py +0 -0
  26. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/commands.py +0 -0
  27. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/config.py +0 -0
  28. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/events.py +0 -0
  29. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/init.py +0 -0
  30. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/messages.py +0 -0
  31. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/opencode.py +0 -0
  32. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/pending.py +0 -0
  33. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/permissions.py +0 -0
  34. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/scheduler.py +0 -0
  35. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/sessions.py +0 -0
  36. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/status.py +0 -0
  37. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/streaming.py +0 -0
  38. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/stt.py +0 -0
  39. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/talk.py +0 -0
  40. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/tts.py +0 -0
  41. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/src/opencode_talk_bridge/webdav.py +0 -0
  42. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/conftest.py +0 -0
  43. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_allowlist.py +0 -0
  44. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_bridge.py +0 -0
  45. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_commands.py +0 -0
  46. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_config.py +0 -0
  47. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_events.py +0 -0
  48. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_init.py +0 -0
  49. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_main.py +0 -0
  50. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_messages.py +0 -0
  51. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_opencode.py +0 -0
  52. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_pending.py +0 -0
  53. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_permissions.py +0 -0
  54. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_scheduler.py +0 -0
  55. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_sessions.py +0 -0
  56. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_status.py +0 -0
  57. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_streaming.py +0 -0
  58. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_talk.py +0 -0
  59. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_voice.py +0 -0
  60. {opencode_talk_bridge-0.2.8 → opencode_talk_bridge-0.3.0}/tests/test_webdav.py +0 -0
@@ -0,0 +1,49 @@
1
+ name: Bug report
2
+ description: Something doesn't work as expected
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for the report! **Do not paste secrets** — app passwords, tokens,
9
+ or full `.env` contents. For security vulnerabilities use
10
+ [private reporting](../../security/advisories/new) instead (see SECURITY.md).
11
+ - type: textarea
12
+ id: what-happened
13
+ attributes:
14
+ label: What happened?
15
+ description: What did you do, what did you expect, what happened instead?
16
+ placeholder: Steps to reproduce, expected vs actual behaviour.
17
+ validations:
18
+ required: true
19
+ - type: input
20
+ id: bridge-version
21
+ attributes:
22
+ label: opencode-talk-bridge version
23
+ description: "Output of `opencode-talk-bridge --help` header or `pip show opencode-talk-bridge`."
24
+ placeholder: "0.3.0"
25
+ validations:
26
+ required: true
27
+ - type: input
28
+ id: opencode-version
29
+ attributes:
30
+ label: OpenCode version
31
+ description: "`opencode --version`"
32
+ placeholder: "1.15.11"
33
+ validations:
34
+ required: true
35
+ - type: input
36
+ id: environment
37
+ attributes:
38
+ label: OS / Python / Nextcloud
39
+ placeholder: "macOS 15, Python 3.12, Nextcloud 30 / Talk 20"
40
+ validations:
41
+ required: false
42
+ - type: textarea
43
+ id: logs
44
+ attributes:
45
+ label: Relevant logs
46
+ description: "Run with `LOG_LEVEL=DEBUG`. Redact tokens, paths, and message contents you don't want public."
47
+ render: text
48
+ validations:
49
+ required: false
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/leiverkus/opencode-talk-bridge/security/advisories/new
5
+ about: Report security issues privately — do NOT open a public issue. See SECURITY.md.
6
+ - name: Question / discussion
7
+ url: https://github.com/leiverkus/opencode-talk-bridge/discussions
8
+ about: For usage questions and ideas (if Discussions is enabled).
@@ -0,0 +1,33 @@
1
+ name: Feature request
2
+ description: Suggest an improvement or new capability
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem / motivation
9
+ description: What are you trying to do that's hard or impossible today?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed solution
16
+ description: What would you like to see? A new command, config option, behaviour?
17
+ validations:
18
+ required: false
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: Alternatives considered
23
+ validations:
24
+ required: false
25
+ - type: checkboxes
26
+ id: scope
27
+ attributes:
28
+ label: Scope check
29
+ options:
30
+ - label: "This is about the bridge itself (not OpenCode, Nextcloud, or nextcloud-talk-core)."
31
+ required: true
32
+ - label: "It does not weaken the allowlist / permission model (or I've explained why that's safe)."
33
+ required: true
@@ -0,0 +1,20 @@
1
+ <!-- Thanks for contributing! Keep PRs focused; see CONTRIBUTING.md. -->
2
+
3
+ ## What & why
4
+
5
+ <!-- What does this change, and why? Link any issue: Fixes #123 -->
6
+
7
+ ## Checklist
8
+
9
+ - [ ] `ruff check src tests` and `ruff format --check src tests` pass
10
+ - [ ] `pytest` passes; new behaviour has tests (both sides mocked, no live calls)
11
+ - [ ] CHANGELOG "Unreleased" updated if user-facing
12
+ - [ ] Docs / `.env.example` updated if config, commands, or behaviour changed
13
+
14
+ ## Security model
15
+
16
+ <!-- Required if this touches the allowlist, permission/question flow, or what
17
+ gets posted to Talk. Otherwise write "n/a". -->
18
+
19
+ - [ ] Does not let the bridge act on a message without an allowlist check
20
+ - [ ] Does not post secrets or raw OpenCode/Nextcloud responses into Talk
@@ -6,6 +6,27 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.0] - 2026-06-01
10
+
11
+ v1 candidate — documentation, security, and stability hygiene (no behaviour
12
+ changes). Still `0.x` / Beta until a live smoke test on a real instance.
13
+
14
+ ### Added
15
+ - `SECURITY.md` — private vulnerability reporting, scope, and response policy.
16
+ - README **Stability** section: the SemVer public contract from `1.0.0` (CLI
17
+ flags, `.env` keys, Talk commands, status JSON, forward-compatible migrations).
18
+ - `CONTRIBUTING.md`: the live smoke test is now a **required gate before a stable
19
+ release**, plus a pre-1.0 checklist (incl. flipping the classifier).
20
+ - Issue forms (`bug_report`, `feature_request`), an issue-template `config`
21
+ routing security reports to private advisories, and a PR template.
22
+
23
+ ### Changed
24
+ - `__version__` is derived from package metadata — single source of truth in
25
+ `pyproject.toml` (no second bump in `__init__.py`).
26
+ - Clarified OpenCode compatibility: **tested against 1.15.11**, expected
27
+ compatible with the 1.15+ HTTP API.
28
+ - Refreshed `docs/publishing.md` for the live (post-first-publish) state.
29
+
9
30
  ## [0.2.8] - 2026-06-01
10
31
 
11
32
  ### Docs
@@ -170,7 +191,8 @@ Initial release.
170
191
  - `nextcloud-talk-core`, pinned to the `core-v1.0.0` git tag.
171
192
  - `httpx >= 0.27`.
172
193
 
173
- [Unreleased]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.8...HEAD
194
+ [Unreleased]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.3.0...HEAD
195
+ [0.3.0]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.8...v0.3.0
174
196
  [0.2.8]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.7...v0.2.8
175
197
  [0.2.7]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.6...v0.2.7
176
198
  [0.2.6]: https://github.com/leiverkus/opencode-talk-bridge/compare/v0.2.5...v0.2.6
@@ -0,0 +1,101 @@
1
+ # Contributing & maintaining
2
+
3
+ ## Dev setup
4
+
5
+ ```bash
6
+ git clone https://github.com/leiverkus/opencode-talk-bridge.git
7
+ cd opencode-talk-bridge
8
+ python3 -m venv .venv && source .venv/bin/activate
9
+ pip install -e ".[dev]" # editable install + ruff/pytest
10
+ ```
11
+
12
+ ## Checks (what CI runs)
13
+
14
+ ```bash
15
+ ruff check src tests # lint
16
+ ruff format --check src tests # formatting (drop --check to apply)
17
+ pytest # tests + coverage (pytest-cov)
18
+ ```
19
+
20
+ All tests mock both sides (Talk via `nextcloud-talk-core`/httpx, OpenCode via
21
+ mocked REST + a fake SSE stream) — **no live calls**. CI runs the matrix on
22
+ Python 3.10–3.13. Please keep new code covered and the suite green.
23
+
24
+ ## Layout
25
+
26
+ ```
27
+ src/opencode_talk_bridge/
28
+ __main__.py CLI (--init / --check / run), signals
29
+ config.py env/.env config (mandatory allowlist lives here)
30
+ opencode.py OpenCode HTTP + SSE client
31
+ talk.py Nextcloud Talk gateway (poll/send/edit/share, raw actorId)
32
+ webdav.py WebDAV upload/download for attachments
33
+ bridge.py orchestration: poll loop, SSE dispatch, prompt workers
34
+ pending.py one pending interaction per conversation (perm/question/select)
35
+ streaming.py live message-edit streaming
36
+ events.py typed SSE event classification
37
+ permissions.py / commands.py / sessions.py / status.py / scheduler.py
38
+ stt.py / tts.py voice (optional)
39
+ messages.py i18n catalog (de/en)
40
+ ```
41
+
42
+ ## Conventions
43
+
44
+ - **Code comments in English.** Ruff line length 110; rules in `pyproject.toml`.
45
+ - The **`ALLOWED_USERS` allowlist is mandatory** — never add a path that lets
46
+ the bridge act on a message without checking `actor_id`/`actor_type`.
47
+ - **Never post raw OpenCode HTTP responses or secrets into Talk.** HTTP errors
48
+ (`OpenCodeError`) get a generic user message; details go to the log only.
49
+ - Verify external API assumptions against a live `opencode serve` (`/doc`
50
+ OpenAPI) rather than guessing — see `docs/smoke-test.md`.
51
+
52
+ ## Cutting a release
53
+
54
+ Releases publish to PyPI automatically via Trusted Publishing on a version tag
55
+ (`.github/workflows/publish.yml`). One command set:
56
+
57
+ ```bash
58
+ # 1. bump the version in ONE place — pyproject.toml -> version = "X.Y.Z".
59
+ # (__version__ is read from the installed metadata; no second edit needed.)
60
+ # 2. move the CHANGELOG "Unreleased" items under "## [X.Y.Z] - <date>" and add
61
+ # the compare links at the bottom.
62
+ # 3. ship it:
63
+ git commit -am "Release X.Y.Z: <summary>"
64
+ git tag -a vX.Y.Z -m "opencode-talk-bridge X.Y.Z"
65
+ git push origin main && git push origin vX.Y.Z # -> publish.yml builds + publishes to PyPI
66
+ gh release create vX.Y.Z --title "vX.Y.Z — <title>" --notes "<notes>"
67
+ ```
68
+
69
+ The publish workflow **guards** that the tag matches `pyproject.toml` and runs
70
+ `twine check`, so a version mismatch fails fast and never reaches PyPI. How
71
+ Trusted Publishing is wired up is documented in
72
+ [`docs/publishing.md`](docs/publishing.md).
73
+
74
+ ### Live smoke test (required before a *stable* release)
75
+
76
+ The automated suite is entirely mocked. Before tagging a stable release
77
+ (`1.0.0` or any later non-pre-release), complete
78
+ [`docs/smoke-test.md`](docs/smoke-test.md) against a **real** Nextcloud Talk
79
+ instance + `opencode serve`, and record the OpenCode version you tested. A
80
+ `0.x` or `-rc` release may ship without it, but the install/feature surface it
81
+ exercises (allowlist on real `actorId`, permission flow, streaming) is only
82
+ verifiable live.
83
+
84
+ ### Pre-1.0 checklist
85
+
86
+ When promoting to `1.0.0`:
87
+
88
+ 1. The live smoke test above has passed on a real instance.
89
+ 2. Bump the classifier `Development Status :: 4 - Beta` →
90
+ `5 - Production/Stable` in `pyproject.toml` (do this **only** at `1.0.0`, not
91
+ while still on `0.x`).
92
+ 3. Re-read the [Stability](README.md#stability) contract — anything you are not
93
+ prepared to keep stable must change *before* `1.0.0`, not after.
94
+ 4. Consider a `1.0.0rc1` (or a final `0.x`) used live for a while first, then
95
+ `1.0.0`.
96
+
97
+ ## Reporting
98
+
99
+ Issues and PRs welcome. For anything touching the security model (allowlist,
100
+ permission flow, what gets posted to Talk), please call it out explicitly in the
101
+ PR description.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencode-talk-bridge
3
- Version: 0.2.8
3
+ Version: 0.3.0
4
4
  Summary: Drive a local OpenCode instance from Nextcloud Talk via polling — a self-hosted chat bridge for a coding agent.
5
5
  Project-URL: Homepage, https://github.com/leiverkus/opencode-talk-bridge
6
6
  Project-URL: Repository, https://github.com/leiverkus/opencode-talk-bridge
@@ -77,7 +77,8 @@ Nextcloud Talk ──long-poll──▶ bridge ──HTTP──▶ opencode
77
77
  - Python ≥ 3.10, macOS or Linux.
78
78
  - A Nextcloud account with **Talk** and an **app password**
79
79
  (Settings → Security → App passwords) — not your login password.
80
- - A running `opencode serve` (OpenCode 1.15). Default endpoint
80
+ - A running `opencode serve`. **Tested against OpenCode 1.15.11**; expected
81
+ compatible with the OpenCode 1.15+ HTTP API until it changes. Default endpoint
81
82
  `http://127.0.0.1:4096`.
82
83
 
83
84
  ## Install
@@ -264,16 +265,43 @@ instance as semi-trusted infrastructure. The trust boundary and mitigations:
264
265
  - **Local-only OpenCode.** Keep `opencode serve` bound to `127.0.0.1`. If you
265
266
  expose it, secure it with `OPENCODE_USERNAME`/`OPENCODE_PASSWORD`.
266
267
 
268
+ To report a vulnerability, see [SECURITY.md](SECURITY.md) (please don't open a
269
+ public issue).
270
+
271
+ ## Stability
272
+
273
+ This project follows [SemVer](https://semver.org/). **From `1.0.0`**, the
274
+ following are the stable public contract — breaking changes to them only happen
275
+ on a major bump:
276
+
277
+ - **CLI:** the `opencode-talk-bridge` command and its flags (`--init`,
278
+ `--check`, `--env-file`).
279
+ - **Configuration:** the documented `.env` keys (see [`.env.example`](.env.example))
280
+ and their meaning.
281
+ - **Talk commands:** the slash-command names (`/new`, `/sessions`, …).
282
+ - **Status file:** the JSON schema and its `state` values.
283
+ - **State store:** SQLite migrations stay forward-compatible — upgrading never
284
+ requires deleting your database.
285
+
286
+ **Not** covered (may change in any release): the Python module/API layout,
287
+ exact wording of bot replies and log lines (the i18n strings), and which
288
+ OpenCode/Nextcloud versions are supported.
289
+
290
+ Pre-`1.0.0` (the current `0.x` line) these may still change between minor
291
+ versions; pin a version you have tested.
292
+
267
293
  ## Development
268
294
 
269
295
  ```bash
296
+ pip install -e ".[dev]"
270
297
  ruff check src tests
271
298
  ruff format --check src tests
272
299
  pytest
273
300
  ```
274
301
 
275
302
  All tests use mocked HTTP for both Talk and OpenCode — no live calls. CI runs
276
- the matrix on Python 3.10–3.13.
303
+ the matrix on Python 3.10–3.13. Dev setup, conventions, and the (one-command)
304
+ release process are in [CONTRIBUTING.md](CONTRIBUTING.md).
277
305
 
278
306
  ## Changelog
279
307
 
@@ -46,7 +46,8 @@ Nextcloud Talk ──long-poll──▶ bridge ──HTTP──▶ opencode
46
46
  - Python ≥ 3.10, macOS or Linux.
47
47
  - A Nextcloud account with **Talk** and an **app password**
48
48
  (Settings → Security → App passwords) — not your login password.
49
- - A running `opencode serve` (OpenCode 1.15). Default endpoint
49
+ - A running `opencode serve`. **Tested against OpenCode 1.15.11**; expected
50
+ compatible with the OpenCode 1.15+ HTTP API until it changes. Default endpoint
50
51
  `http://127.0.0.1:4096`.
51
52
 
52
53
  ## Install
@@ -233,16 +234,43 @@ instance as semi-trusted infrastructure. The trust boundary and mitigations:
233
234
  - **Local-only OpenCode.** Keep `opencode serve` bound to `127.0.0.1`. If you
234
235
  expose it, secure it with `OPENCODE_USERNAME`/`OPENCODE_PASSWORD`.
235
236
 
237
+ To report a vulnerability, see [SECURITY.md](SECURITY.md) (please don't open a
238
+ public issue).
239
+
240
+ ## Stability
241
+
242
+ This project follows [SemVer](https://semver.org/). **From `1.0.0`**, the
243
+ following are the stable public contract — breaking changes to them only happen
244
+ on a major bump:
245
+
246
+ - **CLI:** the `opencode-talk-bridge` command and its flags (`--init`,
247
+ `--check`, `--env-file`).
248
+ - **Configuration:** the documented `.env` keys (see [`.env.example`](.env.example))
249
+ and their meaning.
250
+ - **Talk commands:** the slash-command names (`/new`, `/sessions`, …).
251
+ - **Status file:** the JSON schema and its `state` values.
252
+ - **State store:** SQLite migrations stay forward-compatible — upgrading never
253
+ requires deleting your database.
254
+
255
+ **Not** covered (may change in any release): the Python module/API layout,
256
+ exact wording of bot replies and log lines (the i18n strings), and which
257
+ OpenCode/Nextcloud versions are supported.
258
+
259
+ Pre-`1.0.0` (the current `0.x` line) these may still change between minor
260
+ versions; pin a version you have tested.
261
+
236
262
  ## Development
237
263
 
238
264
  ```bash
265
+ pip install -e ".[dev]"
239
266
  ruff check src tests
240
267
  ruff format --check src tests
241
268
  pytest
242
269
  ```
243
270
 
244
271
  All tests use mocked HTTP for both Talk and OpenCode — no live calls. CI runs
245
- the matrix on Python 3.10–3.13.
272
+ the matrix on Python 3.10–3.13. Dev setup, conventions, and the (one-command)
273
+ release process are in [CONTRIBUTING.md](CONTRIBUTING.md).
246
274
 
247
275
  ## Changelog
248
276
 
@@ -0,0 +1,51 @@
1
+ # Security Policy
2
+
3
+ `opencode-talk-bridge` runs AI coding-agent actions (file writes, shell commands
4
+ via OpenCode) on your machine, triggered by chat messages in a Nextcloud Talk
5
+ instance you may not administer. Security is therefore a primary concern — see
6
+ the [threat model](README.md#threat-model) for the trust boundary and built-in
7
+ mitigations (mandatory allowlist on stable user id, permission prompts, no secret
8
+ or server-text leakage into chat).
9
+
10
+ ## Reporting a vulnerability
11
+
12
+ **Please do not open a public issue for security problems.**
13
+
14
+ Use GitHub's private vulnerability reporting:
15
+ [**Report a vulnerability**](https://github.com/leiverkus/opencode-talk-bridge/security/advisories/new)
16
+ (Security tab → "Report a vulnerability"). This opens a private advisory visible
17
+ only to you and the maintainer.
18
+
19
+ If private reporting is unavailable, open a minimal public issue asking the
20
+ maintainer to open a private channel — **without** technical details.
21
+
22
+ Please include: affected version, a description, reproduction steps, and the
23
+ impact you see. A proof of concept is helpful but not required.
24
+
25
+ ## Scope
26
+
27
+ **In scope** — the bridge's own security model:
28
+ - allowlist bypass (acting on a message from a non-allowlisted `actorId`/`actorType`),
29
+ - the permission/question approval flow being skippable or spoofable,
30
+ - leakage of secrets or raw OpenCode/Nextcloud responses into a Talk message,
31
+ - the `.env` / app password handling, the status file, or the SQLite store
32
+ exposing credentials.
33
+
34
+ **Out of scope** — issues in dependencies or the surrounding system:
35
+ - OpenCode itself, Nextcloud / Talk, or `nextcloud-talk-core`,
36
+ - you exposing `opencode serve` on a public interface (keep it on `127.0.0.1`),
37
+ - misconfiguration (e.g. an over-broad `ALLOWED_USERS`, a shared bot account).
38
+
39
+ Report those to the respective upstream projects.
40
+
41
+ ## Supported versions
42
+
43
+ This is a young project; only the **latest released version** receives security
44
+ fixes. Pin a version you trust and upgrade promptly when an advisory is published.
45
+
46
+ ## Response
47
+
48
+ Best effort by a small maintainer team. Expect an acknowledgement within about a
49
+ week, and a fix or mitigation as soon as practical for confirmed, in-scope
50
+ issues. Fixes ship as a new release with a CHANGELOG entry; credit is given
51
+ unless you prefer otherwise.
@@ -0,0 +1,49 @@
1
+ # Publishing to PyPI
2
+
3
+ Releases publish automatically to [PyPI](https://pypi.org/project/opencode-talk-bridge/)
4
+ by [`.github/workflows/publish.yml`](../.github/workflows/publish.yml) on every
5
+ `vX.Y.Z` tag, using **Trusted Publishing (OIDC)** — no API token is stored in the
6
+ repository.
7
+
8
+ The canonical "how to cut a release" steps live in
9
+ [CONTRIBUTING.md](../CONTRIBUTING.md#cutting-a-release). This file documents how
10
+ the publishing is *wired up*.
11
+
12
+ ## How it works
13
+
14
+ On a tag push the workflow:
15
+
16
+ 1. **guards** that the tag (`vX.Y.Z`) matches the `pyproject.toml` version —
17
+ fails fast on a mismatch, so nothing wrong reaches PyPI;
18
+ 2. builds the sdist + wheel and runs `twine check` (validates the README renders
19
+ on the PyPI page);
20
+ 3. publishes via OIDC to the `pypi` GitHub environment — no secrets.
21
+
22
+ `__version__` is read from the installed package metadata, so the version has a
23
+ single source of truth: `pyproject.toml`.
24
+
25
+ ## Trusted Publisher configuration (already set up)
26
+
27
+ The PyPI project is configured with a Trusted Publisher pointing at this repo:
28
+
29
+ | Field | Value |
30
+ | --- | --- |
31
+ | PyPI Project Name | `opencode-talk-bridge` |
32
+ | Owner | `leiverkus` |
33
+ | Repository name | `opencode-talk-bridge` |
34
+ | Workflow name | `publish.yml` |
35
+ | Environment name | `pypi` |
36
+
37
+ To reconfigure (e.g. transfer ownership), edit it under PyPI → the project →
38
+ *Manage → Publishing*. If you rename the workflow file or the `pypi` environment,
39
+ update this Trusted Publisher to match, or OIDC will reject the publish.
40
+
41
+ (Optional) In GitHub → Settings → Environments, give the `pypi` environment a
42
+ required-reviewer rule so each publish needs a human approval.
43
+
44
+ ## Local dry run
45
+
46
+ ```bash
47
+ python -m build
48
+ python -m twine check dist/*
49
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "opencode-talk-bridge"
7
- version = "0.2.8"
7
+ version = "0.3.0"
8
8
  description = "Drive a local OpenCode instance from Nextcloud Talk via polling — a self-hosted chat bridge for a coding agent."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,15 @@
1
+ """opencode-talk-bridge: drive a local OpenCode instance from Nextcloud Talk.
2
+
3
+ A polling bridge (no webhooks) that forwards allowlisted Talk messages to a
4
+ local `opencode serve` HTTP API and posts the agent's replies back into the
5
+ conversation. See README.md for the threat model and the status-file contract.
6
+ """
7
+
8
+ from importlib.metadata import PackageNotFoundError
9
+ from importlib.metadata import version as _version
10
+
11
+ try:
12
+ # Single source of truth: the version declared in pyproject.toml.
13
+ __version__ = _version("opencode-talk-bridge")
14
+ except PackageNotFoundError: # running from a raw checkout without an install
15
+ __version__ = "0.0.0+unknown"
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.metadata import version
4
+
5
+ import opencode_talk_bridge
6
+
7
+
8
+ def test_version_resolves_from_metadata():
9
+ # __version__ is derived from the installed distribution metadata
10
+ # (single source of truth = pyproject.toml), not a hardcoded literal.
11
+ assert opencode_talk_bridge.__version__ == version("opencode-talk-bridge")
12
+ assert opencode_talk_bridge.__version__ != "0.0.0+unknown" # not the fallback
@@ -1,58 +0,0 @@
1
- # Publishing to PyPI
2
-
3
- Releases are published automatically by
4
- [`.github/workflows/publish.yml`](../.github/workflows/publish.yml) on every
5
- `vX.Y.Z` tag, using **PyPI Trusted Publishing (OIDC)** — no API token is stored
6
- in the repository.
7
-
8
- ## One-time PyPI setup (do this once)
9
-
10
- Because the project does not exist on PyPI yet, register a **pending publisher**;
11
- the first tagged build will create the project and publish it.
12
-
13
- 1. Create / sign in to a [PyPI](https://pypi.org/) account.
14
- 2. Go to **Account settings → Publishing →
15
- [Add a pending publisher](https://pypi.org/manage/account/publishing/)**.
16
- 3. Fill in exactly:
17
- | Field | Value |
18
- | --- | --- |
19
- | PyPI Project Name | `opencode-talk-bridge` |
20
- | Owner | `leiverkus` |
21
- | Repository name | `opencode-talk-bridge` |
22
- | Workflow name | `publish.yml` |
23
- | Environment name | `pypi` |
24
- 4. Save.
25
-
26
- (Optional) In GitHub → Settings → Environments, create an environment named
27
- `pypi` and add a required-reviewer protection rule, so a human approves each
28
- publish.
29
-
30
- ## Cutting a release
31
-
32
- Same flow as before — the tag now also triggers the PyPI publish:
33
-
34
- ```bash
35
- # bump version in pyproject.toml and src/opencode_talk_bridge/__init__.py,
36
- # update CHANGELOG, commit, then:
37
- git tag -a vX.Y.Z -m "opencode-talk-bridge X.Y.Z"
38
- git push origin main && git push origin vX.Y.Z
39
- gh release create vX.Y.Z --title "…" --notes "…" # GitHub release (separate)
40
- ```
41
-
42
- On the tag push, the workflow:
43
- 1. **guards** that the tag matches the `pyproject.toml` version (fails fast on a mismatch),
44
- 2. builds the sdist + wheel and runs `twine check`,
45
- 3. publishes to PyPI via OIDC (no secrets).
46
-
47
- After the **first** successful publish, `uv tool install opencode-talk-bridge`
48
- (or `pipx install opencode-talk-bridge`) works without a git URL — update the
49
- README install command accordingly.
50
-
51
- ## Local dry run
52
-
53
- ```bash
54
- python -m build
55
- python -m twine check dist/*
56
- ```
57
-
58
- `twine check` validates that the README renders on the PyPI page.
@@ -1,8 +0,0 @@
1
- """opencode-talk-bridge: drive a local OpenCode instance from Nextcloud Talk.
2
-
3
- A polling bridge (no webhooks) that forwards allowlisted Talk messages to a
4
- local `opencode serve` HTTP API and posts the agent's replies back into the
5
- conversation. See README.md for the threat model and the status-file contract.
6
- """
7
-
8
- __version__ = "0.2.8"