Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
a890511
chore: pin the core dependency to a tag instead of tracking main (#25)
fylorn Sep 23, 2026
a90e9f3
feat!: forward what can be forwarded, convert only what must be (#26)
fylorn Sep 23, 2026
ca7647c
refactor: take the circuit-breaker registry and metric labels back fr…
fylorn Sep 23, 2026
a6678cf
refactor: redact PII with core's guard engine, and restore tool argum…
fylorn Sep 23, 2026
437a671
feat: inspect the tool calls an upstream returns (#29)
fylorn Sep 23, 2026
038796b
build: keep only line tables in dev and test builds (#30)
fylorn Sep 24, 2026
05f52e8
feat: one circuit-breaker state machine, and hidden characters in req…
fylorn Sep 24, 2026
8a76395
fix: make the integration suite pass again (#32)
fylorn Sep 24, 2026
6482690
test: fix the two flaky integration tests (#33)
fylorn Sep 24, 2026
9f46116
fix: bill a Chat stream whose caller did not ask for usage (#34)
fylorn Sep 24, 2026
3c35ab8
fix: a request the upstream refuses no longer fails over or trips bre…
fylorn Sep 24, 2026
234fcce
Merge main (v1.1.0) into dev
fylorn Sep 24, 2026
82f8061
docs: cut releases from a release branch, and keep the tag's headings…
fylorn Sep 24, 2026
bd57b5d
ci: run checks on pull requests into dev, including the integration s…
fylorn Sep 24, 2026
c1b2085
fix: bill cached input at cache prices, estimate missing usage, strip…
fylorn Sep 24, 2026
ad5b75b
refactor: take back what only this side used from core (#41)
fylorn Sep 24, 2026
3a617f3
feat(gateway): take official hosts, output fallback and error shapes …
fylorn Sep 24, 2026
ed1c8b5
feat(gateway): accept Gemini clients, and the Responses API over a We…
fylorn Sep 24, 2026
28d4387
test: count the probes that miss before the streaming cache hit (#44)
fylorn Sep 24, 2026
d3f36fc
refactor(server): move the catalog's SQL into repositories (#45)
fylorn Sep 24, 2026
83e9bcc
refactor(server): move the dashboard, limits and log-forwarding handl…
fylorn Sep 24, 2026
9b5b326
refactor(server): move the MCP handlers' SQL into repositories (#50)
fylorn Sep 24, 2026
86beb82
refactor(gateway): run the request guards on core's tw-guard engines …
fylorn Sep 24, 2026
1c80b83
refactor(server): move the identity handlers' SQL into repositories (…
fylorn Sep 24, 2026
c25b44f
fix(mcp): revoking a default connection no longer fails with a 500 (#51)
fylorn Sep 24, 2026
dbce845
test: leave the cancelled stream after it has started, not on a timer…
fylorn Sep 24, 2026
c3d2d57
refactor(server): move the access handlers' SQL into repositories (#48)
fylorn Sep 24, 2026
d92c2d1
fix(settings): read security.totp_required as a boolean, and seed aut…
fylorn Sep 24, 2026
7e95183
feat(gateway): record a client that leaves before its response exists…
fylorn Sep 24, 2026
367df3c
feat(auth): enforce the TOTP requirement (#55)
fylorn Sep 24, 2026
443de8d
feat(gateway): keep the last response on a Responses WebSocket (#56)
fylorn Sep 24, 2026
6890c72
Merge main (v2.0.0) into dev
fylorn Sep 24, 2026
d4f6d5a
docs(release): CI runs the integration suite on the release PR (#58)
fylorn Sep 24, 2026
ef3de87
docs(contributing): point vulnerability reports at the organization's…
fylorn Sep 25, 2026
c4f8b1c
docs(readme): current description of ThinkWatch Lite and ThinkWatch C…
fylorn Sep 25, 2026
f259962
feat(providers): authenticate Bedrock with an API key (#61)
fylorn Sep 28, 2026
78f9ab5
test: hold the early-cancel client once its key is known, not on a ti…
fylorn Sep 28, 2026
1b752f2
feat(providers): list Bedrock's models, and let the route editor take…
fylorn Sep 28, 2026
1f08421
fix(bedrock): refuse keys that will not decrypt, and keep instance-ro…
fylorn Sep 28, 2026
e480bfd
refactor(bedrock): use core's shared tw-bedrock, and core v0.55.0 (#65)
fylorn Sep 29, 2026
e1e7999
docs(readme): rewrite both READMEs to be short and accurate (#66)
fylorn Sep 30, 2026
af9eb81
Merge main (v2.1.0) into dev
fylorn Sep 30, 2026
ed6dd39
docs(readme): 37 MCP templates, what the setup wizard does, body reda…
fylorn Sep 30, 2026
9afcc08
fix(rbac): make the seeded team_manager work at team scope (#69)
fylorn Sep 30, 2026
fa3a5b9
fix(rbac): require gateway use, and count only grants that give it (#70)
fylorn Sep 30, 2026
a1eed6f
Merge main (v2.2.0) into dev
fylorn Sep 30, 2026
da88b09
Merge main (sponsor line) into dev
fylorn Oct 2, 2026
1a399e7
Allow clippy::double_must_use on the async_trait BlobStore (#73)
fylorn Oct 2, 2026
8d8d96f
Unify the request guards with thinkwatch-core's rule model (#72)
fylorn Oct 3, 2026
2baa123
Fix what the pre-release review of the guard unification found (#75)
fylorn Oct 3, 2026
33c22dc
Merge main (v3.0.0) into dev
fylorn Oct 3, 2026
dcc8616
Merge main (README: ThinkWatch Lite for individual developers) into dev
fylorn Oct 4, 2026
6b73344
Merge main (v3.1.0) into dev
fylorn Oct 5, 2026
03c393c
Usage limits: token limits refuse, key limits count on the key, Retry…
fylorn Oct 5, 2026
4075855
fix(redis): connect over TLS for rediss:// URLs (#82)
fylorn Oct 5, 2026
33234ee
Concurrent startup, body retention on restart, and Helm network polic…
fylorn Oct 5, 2026
b7a34e1
Merge main (v3.2.0) into dev
fylorn Oct 5, 2026
2ce6471
chore(deps): update rust crate rand to v0.10.1 [security] (#77)
renovate[bot] Oct 6, 2026
0682864
chore(deps): update rust crate xxhash-rust to v0.8.16 [security] (#78)
renovate[bot] Oct 6, 2026
1fbe7bd
chore(deps): take the Renovate dashboard upgrades (#85)
fylorn Oct 6, 2026
2e23fd9
chore(deps): pnpm 12, and ClickHouse row validation on (#86)
fylorn Oct 6, 2026
977cab0
ci: save Rust caches only on pushes, and let releases read CI's image…
fylorn Oct 8, 2026
2aad4be
build(deps): thinkwatch-core v0.65.0
fylorn Oct 8, 2026
8fb28d3
fix(deploy): pull the images from ghcr.io/thinkwatchproject
fylorn Oct 8, 2026
61079a9
fix(docker): let the web build read the workspace version
fylorn Oct 8, 2026
f81829e
fix(audit): keep a ClickHouse batch that fails while it is sent
fylorn Oct 8, 2026
f17da63
fix(logs): compare times, not text, in the log lists' time range
fylorn Oct 8, 2026
60b947d
chore(release): tag 3.2.1
fylorn Oct 8, 2026
4f3498a
fix(auth): accept each TOTP code once
fylorn Oct 8, 2026
afcd60e
test(auth): hold the dummy hash a login for an unknown address verifies
fylorn Oct 8, 2026
65cb3d6
fix(console): a failed ClickHouse read is an error or a warning, not …
fylorn Oct 8, 2026
c438e09
test(clickhouse): a new log-table column must come with a default
fylorn Oct 8, 2026
dd65d42
build(deps): brace-expansion 2.1.7 and 5.0.12, ip-address 10.7.3
fylorn Oct 8, 2026
4f5c5d9
chore(release): 3.2.1 notes for TOTP replay, ClickHouse read failures…
fylorn Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 44 additions & 31 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

services:
postgres:
image: postgres:18-alpine
image: postgres:18-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
Expand All @@ -30,7 +30,7 @@ jobs:
--health-timeout 5s
--health-retries 5
redis:
image: redis:8-alpine
image: redis:8-alpine@sha256:3811787313eba226a2ef38658c6ccb91cd5e110edc89c37767de373120a0e5a0
ports:
- 6379:6379
options: >-
Expand All @@ -46,7 +46,7 @@ jobs:
ENCRYPTION_KEY: 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# The default ubuntu-latest runner ships with ~14GB free, which
# the workspace compile + 40+ test-binary link step regularly
Expand All @@ -59,9 +59,17 @@ jobs:
/opt/hostedtoolcache/CodeQL /usr/local/.ghcup
df -h /

- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
- uses: dtolnay/rust-toolchain@89b12181fb390509a0842a86cc55eeb8eb928c1d # stable
with:
toolchain: stable
# Save only on pushes (dev, main). A PR can read its own caches, its
# base branch's and the default branch's, never another PR's, so a cache
# saved on a PR serves only a later push to that same PR, while taking as
# much of the repository's 10 GB cache quota as dev's and evicting it.
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
save-if: ${{ github.event_name == 'push' }}
- uses: taiki-e/install-action@183e4297cca2404691e9380e1307288dced5c82a # v2.87.25
with:
tool: cargo-nextest

Expand Down Expand Up @@ -89,7 +97,7 @@ jobs:

services:
postgres:
image: postgres:18-alpine
image: postgres:18-alpine@sha256:77f585114c32fbca283dc835b0596f4e52b51b4c6662d7810b2f4084f60a1873
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
Expand All @@ -106,7 +114,7 @@ jobs:
--health-timeout 5s
--health-retries 10
redis:
image: redis:8-alpine
image: redis:8-alpine@sha256:3811787313eba226a2ef38658c6ccb91cd5e110edc89c37767de373120a0e5a0
ports:
- 6379:6379
options: >-
Expand All @@ -115,7 +123,7 @@ jobs:
--health-timeout 5s
--health-retries 10
clickhouse:
image: clickhouse/clickhouse-server:26.3-alpine
image: clickhouse/clickhouse-server:26.8-alpine@sha256:652d6997949183f3493f8ff601149e3df4d476be829f0d02b9861454d040c410
env:
CLICKHOUSE_USER: default
CLICKHOUSE_PASSWORD: chtest
Expand All @@ -142,7 +150,7 @@ jobs:
TEST_CLICKHOUSE_PASSWORD: chtest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

# Same disk pressure as the unit job: the server plus 50-odd test
# binaries do not fit in the runner's default free space.
Expand All @@ -152,9 +160,14 @@ jobs:
/opt/hostedtoolcache/CodeQL /usr/local/.ghcup
df -h /

- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: taiki-e/install-action@v2
- uses: dtolnay/rust-toolchain@89b12181fb390509a0842a86cc55eeb8eb928c1d # stable
with:
toolchain: stable
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
with:
# See the `rust` job.
save-if: ${{ github.event_name == 'push' }}
- uses: taiki-e/install-action@183e4297cca2404691e9380e1307288dced5c82a # v2.87.25
with:
tool: cargo-nextest

Expand All @@ -171,13 +184,13 @@ jobs:
run:
working-directory: web
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
with:
# Pinned — matches `packageManager` in web/package.json.
# Bump together with that field, never alone.
version: 11.0.0
- uses: actions/setup-node@v4
version: 12.9.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: pnpm
Expand Down Expand Up @@ -221,30 +234,30 @@ jobs:
matrix:
platform: [linux/amd64, linux/arm64]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set image prefix
run: echo "IMAGE_PREFIX=ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ${{ env.IMAGE_PREFIX }}/think-watch-server

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
file: deploy/docker/Dockerfile.server
Expand All @@ -261,7 +274,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: server-digest-${{ strategy.job-index }}
path: ${{ runner.temp }}/digests
Expand All @@ -281,21 +294,21 @@ jobs:
run: echo "IMAGE_PREFIX=ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV

- name: Download digests
uses: actions/download-artifact@v4
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
pattern: server-digest-*
merge-multiple: true
path: ${{ runner.temp }}/digests

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

# **Tagged by commit SHA only. `:latest` belongs to release.yml.**
#
Expand Down Expand Up @@ -337,26 +350,26 @@ jobs:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Set image prefix
run: echo "IMAGE_PREFIX=ghcr.io/$(echo '${{ github.repository_owner }}' | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4.4.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Build and push web image
uses: docker/build-push-action@v6
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
file: deploy/docker/Dockerfile.web
Expand Down
39 changes: 22 additions & 17 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Reclaim runner disk
# `Dockerfile.server` links the entire workspace under LTO +
Expand All @@ -63,10 +63,10 @@ jobs:
df -h /

- name: Set up Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand All @@ -75,7 +75,7 @@ jobs:
- name: Resolve image name + platform pair
id: meta
# `platform_pair` is the platform name munged for use as an
# artifact suffix — `actions/upload-artifact@v4` rejects `/`.
# artifact suffix — `actions/upload-artifact` rejects `/`.
# `image` lowercases the owner because GHCR is case-sensitive
# on path segments and the Helm values default to lowercase.
run: |
Expand All @@ -87,7 +87,7 @@ jobs:

- name: Build & push by digest
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
file: deploy/docker/Dockerfile.${{ matrix.component }}
Expand All @@ -104,8 +104,13 @@ jobs:
org.opencontainers.image.version=${{ github.ref_name }}
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.licenses=BUSL-1.1
cache-from: type=gha,scope=${{ matrix.component }}-${{ steps.meta.outputs.platform_pair }}
cache-to: type=gha,scope=${{ matrix.component }}-${{ steps.meta.outputs.platform_pair }},mode=max
# Read the caches CI saves on main, never write. A tag run can read
# its own caches and the default branch's (main) only, and the tag
# points at a commit whose main push CI has just built from the same
# Dockerfile, so these scopes are CI's (`server-<platform>`, and `web`
# for both platforms). A cache written here would be filed under the
# tag, where no later run can read it.
cache-from: type=gha,scope=${{ matrix.component == 'web' && 'web' || format('server-{0}', matrix.platform) }}

- name: Export digest
run: |
Expand All @@ -114,7 +119,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}"

- name: Upload digest
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: digests-${{ matrix.component }}-${{ steps.meta.outputs.platform_pair }}
path: ${{ runner.temp }}/digests/*
Expand All @@ -135,17 +140,17 @@ jobs:
component: [server, web]
steps:
- name: Download digests
uses: actions/download-artifact@v4
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ${{ runner.temp }}/digests
pattern: digests-${{ matrix.component }}-*
merge-multiple: true

- name: Set up Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1

- name: Log in to GHCR
uses: docker/login-action@v3
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down Expand Up @@ -201,8 +206,8 @@ jobs:
name: Helm chart
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: azure/setup-helm@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: latest
- name: Resolve version
Expand All @@ -220,7 +225,7 @@ jobs:
--app-version "${{ steps.meta.outputs.version }}" \
--destination .
- name: Upload chart artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: helm-chart
path: think-watch-*.tgz
Expand All @@ -234,9 +239,9 @@ jobs:
needs: [merge-manifests, package-helm]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Download Helm chart artifact
uses: actions/download-artifact@v4
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: helm-chart
path: .
Expand Down Expand Up @@ -290,7 +295,7 @@ jobs:
esac
echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT"
- name: Create release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
with:
tag_name: ${{ github.ref_name }}
name: ThinkWatch ${{ github.ref_name }}
Expand Down
Loading
Loading