Commit Graph
1372 Commits
Author SHA1 Message Date
mesh-tools dd462a80e2 Keep the gate silent until it holds the seat, and carry today's state over once when it first does (issue 1347) 2026-10-20 00:29:19 +00:00
mesh-tools a390bb40f8 Take a stray key out of the gate's reads (issue 1346) 2026-10-20 00:19:29 +00:00
mesh-tools 09f0b0d5ab Move the delivery module to the gate: mesh-delivery-gate claims the seat with its own buckets and reads (issue 1346) 2026-10-20 00:19:19 +00:00
jochen b9104454f9 Read the grant file on keycloak's moved path, so a consumer not moved is still made (issue 1332)
mesh/merge-gate head b9104454f9a5 merged into trunk 954f84ea19b5 — pass: builds keycloak, sent nowhere; no bus step; 1 wait(s) for a person; every machine …
mesh/repo-check head b9104454f9a5 merged into trunk 954f84ea19b5 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivering: 0 machine step(s) passed
mesh-mail-web, grafana and car-hunter are not moved, so keycloak wanted nothing for them: it never
made mesh_novox_mail_web, and held mesh_ace_grafana and mesh_ace_carhunt for retirement. Keycloak's
moved spec now asks for the grant file's consumers too (WithGrants: true), and the moved harness
reads MESH_RECEIVES exactly as the grant path does and as postgres's moved harness already did.
2026-10-20 00:30:45 +02:00
jochen 73a10fafc7 Pull keycloak's moved-path harness into movedHarness, and test it reads the grant file (issue 1332)
Adds the failing unit tests for keycloak's provider on the moved path: a grant-file consumer not
moved should still be made and never held for retirement, and the moved harness should read
MESH_RECEIVES as the grant path does. All three fail on an assertion against today's code, which
wants nothing from the grant file on this path.
2026-10-20 00:30:10 +02:00
jochen 9f3a8ee391 Follow real links instead of building them, and check the CSP on every answer (issue 1268)
mesh/merge-gate head 9f3a8ee39101 merged into trunk 66aa204f6779 — pass: builds mesh-mail, new: modules/mesh-mail-web → novox; no bus step; every machine c…
mesh/repo-check head 9f3a8ee39101 merged into trunk 66aa204f6779 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2026-10-19 23:18:53 +02:00
jochen cad6194447 Keep the HTTP endpoint's own state, so status and health stop claiming to serve once it has failed (issue 1283) 2026-10-19 23:18:51 +02:00
jochen 3fd1b47fe7 Bounce once through this origin before sign-in, so a Strict cookie is not lost crossing from Keycloak or another site (issue 1263) 2026-10-19 23:18:48 +02:00
jochen 5b57422523 Report an unknown ask through a small interface, not *testing.T directly (issue 1285)
A failed subtest fails its parent, so TestHarnessFailsTheTestWhenTheBundleAsksSomethingUnknown could never
pass the way it was written (try 2's finding). The player now reports through askFailer (Helper, Errorf);
every other test keeps passing its own *testing.T, which satisfies it already. That one test gives a
recorder instead, and asserts it holds exactly one message naming seat:mail-store.accounts, and that
mail-webclient.status's own answer shows the ask got an error back. Checked: no other integration test uses
the same deliberate-subtest-failure pattern (grepped t.Run).
2026-10-19 22:53:18 +02:00
jochen 523d7846cd Fix mesh-mail-web's manifest: operators is type list, the listen word names its port number (issue 1262)
The controller refused the manifest: config.operators declared type "array" (not one of the controller's
five types, novox/hq ADR 0348 §4 — the word is "list"), and the bundle's env word MESH_MAIL_WEB_LISTEN said
${port:web} (a bundle's word takes the port NUMBER a listens entry gives, novox/hq ADR 0192; mesh-controller
internal/catalogue/port_into.go portsFilledInto matches it against listens[].Port, never an endpoint's
label). Fixed to type "list" and ${port:8099} (the listens entry's own port). main.go and the integration
harness already read/write a plain port number, so neither needed a change. manifest_test.go now asserts
both: config.operators.Type == "list", and the listen word equals ${port:<the listens entry's port>};
confirmed each independently fails against the old values before this fix.
2026-10-19 22:47:56 +02:00
jochen 502cda34cb Add design 59 milestone 1's acceptance tests on the runtime player (issue 1268)
Four scenarios, entered only through HTTP with Host mail.<node>.internal as a browser would, against the
built mesh-mail-web, a stand-in identity provider (auth_test.go's own fakeIssuer, reused) and a real account
bucket holding granted account a and ungranted account c: sign-in redirects, 403s and the session cookie's
attributes; the 404 for another host; browsing and a send followed to sent, only the five mail verbs asked,
account c never shown, paging by date, no database or extra writable directory; a mail's script and remote
image shown as text, an attachment downloaded with nosniff, and the CSP on every answer.

Build tag integration; compiles under go vet -tags integration ./...; never run here.
2026-10-19 22:42:27 +02:00
jochen c996121e9d Add the runtime player and stand-in mail-store for a bundle's integration test (issue 1285)
Plays the SDK's own runtime protocol (initialize, tools/list, tools/call, the bundle's mesh/ask and
mesh/state.<verb>) against mesh-mail-web's real built binary, from stdio.go and state.go's own source. The
account bucket is a real JetStream key-value bucket (mesh-mail_accounts, named as mesh-mail's own
acceptance_integration_test.go names a module's state); its fixture (accountBucketValue/accountBucketFolder)
is accounts.go's own, itself copied from mesh-mail's mirror.go AccountValue (issue 1255, 1264).

Build tag integration; compiles under go vet -tags integration ./...; never run here (go test -tags
integration is this batch's hard rule) — the lead's try runs it.
2026-10-19 22:38:36 +02:00
jochen f863e852c9 Add the write page and a send's state, behind issue 1284's form token (issue 1267)
Wires 1284's per-session token into the real write form and its real POST /send; adds tests for 1284/AC1-AC4
against that real page and handler, beside this issue's own AC1-AC4.
2026-10-19 22:29:41 +02:00
jochen 58b337770d Show a mail as escaped text and serve its attachments as downloads (issue 1266) 2026-10-19 22:26:47 +02:00
jochen ff1886ac62 Add the search page, by mail-store.search's own argument names (issue 1265) 2026-10-19 22:24:52 +02:00
jochen 28fdbbd346 Show every granted account, its state and its folders' counts (issue 1264)
Accounts bucket fixture (accountBucketValue/accountBucketFolder) copied from mesh-mail's own
modules/mesh-mail/cmd/mesh-mail/mirror.go AccountValue/AccountFolderValue (issue 1255); mesh-mail-web is its
own Go module, so this is a copy, not an import.
2026-10-19 22:22:52 +02:00
jochen 3ee80c98ab Bind every changing form's token to its session (issue 1284) 2026-10-19 22:18:03 +02:00
jochen 8e0ef84060 Sign in through Keycloak: code flow with PKCE, verified ID token, 12-hour session (issue 1263)
Library choice: golang.org/x/oauth2 for the code exchange, github.com/coreos/go-oidc/v3 for the ID token's
verification (issuer, audience, expiry, signature from the issuer's JWKS).
2026-10-19 22:16:15 +02:00
jochen 68c141849f Serve mesh-mail-web's HTTP endpoint: internal host check, CSP, open (issue 1283) 2026-10-19 22:09:49 +02:00
jochen a9ad306693 Add the module mesh-mail-web, with its status verb (issue 1262) 2026-10-19 22:07:36 +02:00
jochen a3e9985c15 Keep each account's newest mails in a bucket, bounded past 81 accounts (issue 1282) 2026-10-19 21:56:04 +02:00
jochen 08200bc178 Keep each account's state in a bucket (issue 1255) 2026-10-19 21:50:12 +02:00
jochen a9ff48e200 Answer a send's state only to its caller (issue 1261) 2026-10-19 21:44:12 +02:00
jschoubben a76910a0c0 Say only the merge tool's two out of date refusals a warning, and never step a severity down (issue 1275, ADR 0442's cases)
mesh/merge-gate head a76910a0c036 merged into trunk 9efdd87a73a9 — pass: builds mesh-delivery → novox; no bus step; every machine composes with the change …
mesh/repo-check head a76910a0c036 merged into trunk 9efdd87a73a9 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2026-10-19 20:51:58 +02:00
jschoubben dc86203d29 Say a refusal for an out of date verdict a warning for ten minutes, urgent after (issue 1275, operator's amendment, AC6) 2026-10-19 20:51:58 +02:00
jschoubben 301cd2287f Answer gitea_commit_statuses in the bus test's runtime, and say a held, refused member once (issue 1275, review round 1)
mesh/merge-gate head 301cd2287f5f merged into trunk eda55ceb9e1b — pass: builds mesh-delivery → novox; no bus step; every machine composes with the change …
mesh/repo-check head 301cd2287f5f merged into trunk eda55ceb9e1b — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2026-10-19 20:38:48 +02:00
jschoubben 524e3405e5 Ask a group's Approve only when every member may merge, and withdraw the ask when a required status turns (issue 1275)
mesh/merge-gate head 524e3405e517 merged into trunk eda55ceb9e1b — pass: builds mesh-delivery → novox; no bus step; every machine composes with the change …
mesh/repo-check head 524e3405e517 merged into trunk eda55ceb9e1b — fail: its merge-check.sh failed: --- FAIL: TestAGroupOfTwoWithGreenChecksGetsOneAskAndOn…
mesh/delivery superseded: a newer head of the same pull request
An Approve given hours after its ask must not rest on a check made at the ask: a required status
that turns not a success while the ask waits takes the ask back, and its late answer merges nothing.
2026-10-19 20:32:22 +02:00
jschoubben 6e6d1f3e47 Merge a group whole or not at all: re-read every required status first, stop at the first refusal, say a held or half merged group urgent (issue 1275, 1276)
An approved group was merged member by member, each on its own, so a refusal of the first
did not stop the second. A group now merges in one pass in its order, after every member's
required statuses are read again at its head, and a held or half merged group stays raised.
A refusal naming the member's own repository check as missing asks that check (issue 1276).
2026-10-19 20:32:15 +02:00
mesh-tools eda55ceb9e Merge pull request 'Give the forge bridge a merge commit's trees in one call, and each open pull request's head branch (design 47 R3c, issue 1234)' (#374) from feat/delivery-parts into main 2026-10-19 18:22:09 +00:00
jochen 5c1ff4bb15 mesh-mail: dedup-archive picks the same copy in both stores when a message-id also sits in a second non-archive folder (issue 1248, review round 1 finding 1)
mesh/merge-gate head 5c1ff4bb152b merged into trunk b767aac8e072 — pass: builds mesh-mail → novox; no bus step; every machine composes with the change as i…
mesh/repo-check head 5c1ff4bb152b merged into trunk b767aac8e072 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2026-10-19 15:33:36 +02:00
jochen 280aeb2f47 Answer each gmail mail once when no folder is named, keeping archived mail (issue 1248) 2026-10-19 15:30:44 +02:00
jochen 920199862e mesh-mail: group-by-sender and order-by sender compare addresses case-insensitively in Postgres too, and a sender's shown name and address are its newest mail's, deterministically (issue 1230, review finding 6)
mesh/merge-gate head 920199862e18 merged into trunk 7bb588ca1bfb — pass: builds mesh-mail → novox; no bus step; every machine composes with the change as i…
mesh/repo-check head 920199862e18 merged into trunk 7bb588ca1bfb — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2026-10-19 15:09:44 +02:00
jochen 8dd2a42448 mesh-mail: mail_search's order defaults to descending when left out, matching its own schema text, and AC1's no-filter test proves ordering, limit and grant isolation together (issue 1232, review findings 5 and 7) 2026-10-19 15:05:23 +02:00
jochen d1a9056a1c mesh-mail: mail_search gains words/words-any, a word found in subject or body, since subject-words and body-words together only ever meant and (issue 1229, review finding 3; also proves AC9's type-or-name independently and AC2+unread combined) 2026-10-19 15:02:40 +02:00
jochen a3476a7bf2 mesh-mail: from-someone-i-wrote-to recognises gmail's Sent folder name too, and stays scoped to one account (issue 1231, review findings 1 and 2) 2026-10-19 14:57:26 +02:00
jochen 1c3158e098 mesh-mail: mail_search's address filter never treats % or _ as a wildcard, so a literal domain filter does not leak every mail in Postgres (issue 1228, review finding 4) 2026-10-19 14:52:36 +02:00
jschoubben 75957fc3c0 Hash the root tree from the root's entries, since the forge names the commit (issue 1234)
mesh/repo-check head 75957fc3c006 merged into trunk e8c3448797c7 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/merge-gate head 75957fc3c006 merged into trunk e8c3448797c7 — pass: group feat/delivery-parts composed: every machine composes with the change as it d…
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792433168676870614 (novox/mesh-catalog at eda55ceb into main,…
mesh/delivery-group group feat/delivery-parts delivered: every member is delivered
The listing's top sha is the commit's, not the root tree's (seen live, novox/mesh-delivery at 7f61817), so
gitea_commit_trees now computes the root tree as git does, from the entries without a slash. The query keys
recursive and per_page stay in the allow-list: read flags only.
2026-10-19 14:52:29 +02:00
jschoubben ea83746297 Give the forge bridge a merge commit's trees in one call, and a pull request's head branch (issue 1234)
gitea_commit_trees reads the commit's recursive tree listing and answers the root tree and the
tree of every directory holding a module.json; a cut listing fails loudly. gitea_open_pulls
entries gain head. The query keys recursive and per_page join the allow-list, read flags only.
mesh-delivery decodes open pulls with json.Unmarshal into a struct (cmd/mesh-delivery/ports.go:405-410),
which ignores the added key.
2026-10-19 14:50:19 +02:00
jochen b60ee706d4 mesh-mail: mail_search's tool makes the query optional and offers every filter and order-by (one schema for mail_search and mail-store.search), validated before the index is ever asked (issue 1232) 2026-10-19 14:46:58 +02:00
jochen 4a60deb4a8 mesh-mail: mail_search finds a thread's replies and mail from someone the operator wrote to, so a reply or a known correspondent's junk mail can be found (issue 1231) 2026-10-19 14:39:59 +02:00
jochen fc10031d22 mesh-mail: mail_search orders by date, sender, subject or size and groups by sender, so the newest, the largest or who writes most can be answered (issue 1230)
Query's From becomes a list, OR'd (1228/AC11's several domains), since 1230's order-by needs it to test the
ascending-order criterion end to end; To and Cc stay single, no criterion asking for more.
2026-10-19 14:36:53 +02:00
jochen 2985122856 mesh-mail: mail_search's Query gains subject/body words, attachment type/name and read/unread, so a word in one field, an attachment or a flag can filter mails (issue 1229) 2026-10-19 14:29:15 +02:00
jochen 20342f2172 mesh-mail: mail_search's Query gains from, to, cc and a date range, so a sender, a recipient or a date can filter mails without query words (issue 1228) 2026-10-19 14:22:14 +02:00
mesh-tools 7bb588ca1b Merge pull request 'mesh-mail sends an approved mail from its own sender process, and tells a failed send once (ADR 0436, ADR 0438; issues 1172, 1193-1199)' (#371) from feat/mail-sender into main 2026-10-19 11:36:51 +00:00
jochen a2c0c58677 mesh-mail: a redelivery of a message whose send already finished (sent, failed, refused or not proven) is a repeat, terminated without recording, emitting or telling anything again (operator-approved change to ADR 0436 clause 10; issue 1196)
mesh/merge-gate head a2c0c586772b merged into trunk c441d83ba753 — pass: builds mesh-mail → novox; no bus step; every machine composes with the change as i…
mesh/repo-check head a2c0c586772b merged into trunk c441d83ba753 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2026-10-19 13:29:31 +02:00
jschoubben e601e88e95 Keep two values of each issue in the tracker's bucket, since the log holds them all (issue 1221)
mesh/merge-gate head e601e88e95dd merged into trunk fb8e677cd849 — pass: builds mesh-issues → novox; no bus step; every machine composes with the change as…
mesh/repo-check head e601e88e95dd merged into trunk fb8e677cd849 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2026-10-19 12:38:55 +02:00
jschoubben 5aca005cb7 Shorten the router's burst window in the test bundle so the desk is sent within seconds (issue 1218, check finding 1)
mesh/repo-check head 5aca005cb741 merged into trunk b4527d9091e9 beside mesh-controller#394@3e7f34d0 — pass: its merge-check.sh passed, each part in its to…
mesh/merge-gate head 5aca005cb741 merged into trunk b4527d9091e9 — pass: group feat/delivery-seat-by-claim composed: every machine composes with the change…
mesh/delivery delivered
mesh/delivery-group group feat/delivery-seat-by-claim delivered: every member is delivered
2026-10-19 12:15:47 +02:00
jschoubben 9f9e9fc9d3 Shorten the router's start grace in the test bundle so the bus tests stay in seconds (issue 1218, review round 1 finding 2) 2026-10-19 12:05:07 +02:00
jschoubben f737418bb3 Keep a module's condition open when the controller's conditions are read (issue 1217, review round 1 finding 1) 2026-10-19 12:04:58 +02:00
jschoubben 5b235a6e80 Prove over the bus that a condition on the one subject reaches the desk (issue 1218) 2026-10-19 11:59:49 +02:00