Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
185 commits
Select commit Hold shift + click to select a range
a498fbe
fix(plugin): main-thread callers run inline; Tauri-command evals go t…
Sep 27, 2026
f98c7d3
feat(bridge): try_list_window_labels + eval_webview_resolved; determi…
Sep 27, 2026
95b747b
fix(eval): private eval state, exact-window watch, busy UI != closed …
Sep 27, 2026
c65f69e
style(tools): pub items in the private tools module (clippy::redundan…
Sep 27, 2026
76a3d61
hardening(0.9): CI/release supply chain, init symlink safety, watchdo…
Sep 27, 2026
c3ae9a8
fix(js-bridge): hostile-page hardening + slow IPC calls no longer stu…
Sep 27, 2026
c141cab
Merge remote-tracking branch 'origin/hardening-0.9' into release/0.9-…
Sep 27, 2026
a22c83b
feat!: 0.9 API sweep — #[non_exhaustive] output types, constructors, …
Sep 27, 2026
611d38a
fix(database): SQLite authorizer for query_db; hardened, fully-budget…
Sep 27, 2026
a2eb841
Merge remote-tracking branch 'origin/sweep-0.9' into release/0.9-prep
Sep 27, 2026
50c698a
fix(recording,trace): shared drain watermark; trace owns its recordin…
Sep 27, 2026
e72246e
fix: network-boundary, ASI and honesty findings from the pre-audit re…
Sep 27, 2026
0d59759
release: prepare 0.9.0 — changelog, migration guide, version bump
Sep 27, 2026
7b131af
fix(plugin): gate lexically_normalize behind the sqlite feature (dead…
Sep 27, 2026
8cc7623
fix(js-bridge): find_elements no longer calls a valid selector "inval…
Sep 27, 2026
be75c90
feat(eval): fail fast when the page reloads under an in-flight eval
Sep 27, 2026
e837e86
feat(invoke_command): per-call timeout_ms; aborted calls are not timings
Sep 27, 2026
88b3339
test(victauri-test): hold the "closed" port bound so CI cannot reuse it
Sep 27, 2026
5c8e4f3
fix(authz): refuse non-string actions and non-object args before the …
runyourempire Sep 27, 2026
09971ce
fix(inspectable): record the IPC key Tauri invokes each argument by
runyourempire Sep 27, 2026
8206c6d
fix(codegen): generated tests survive hostile recordings
runyourempire Sep 27, 2026
e14fdc9
fix(victauri-test): check()/uncheck() work on React inputs; stale ref…
runyourempire Sep 27, 2026
a7736ed
fix(query_db): charge the result budget per raw cell; cap result widt…
runyourempire Sep 27, 2026
7b8b620
fix(eval): no parse-watchdog race, page-nonce reload detection, leak-…
runyourempire Sep 27, 2026
07319d3
fix(recorder): generation-scoped, atomic stop/import; IpcCall carries…
runyourempire Sep 27, 2026
f26f6bd
fix(introspection): bound CommandTimings to 1024 distinct commands
runyourempire Sep 27, 2026
29047d1
fix(bridge): a timed-out main-thread call never runs later; trusted i…
runyourempire Sep 27, 2026
ce76d31
fix(mcp): bound blocking DB/probe work, isolate handler panics, no bu…
runyourempire Sep 27, 2026
e94115b
fix(recording): sequence-keyed drain, recording-scoped reads, window-…
runyourempire Sep 27, 2026
a24b517
fix(discovery): exact, own-user, in-process liveness on Windows; brid…
runyourempire Sep 27, 2026
d0366a1
fix(release,ci,docs): tokenless verify before publish; honest gates a…
runyourempire Sep 27, 2026
c4bab9a
fix(cli): the stdio bridge's HTTP timeout outlasts a tool call's own …
runyourempire Sep 27, 2026
9c6ad55
fix(bridge): snapshot, logs and eval results hold up against hostile …
runyourempire Sep 27, 2026
ff86cf2
fix(authz): unknown string actions keep their helpful parse error; di…
runyourempire Sep 27, 2026
20f8fc4
Merge lane B: recording/drain/trace/replay fixes (C5 C6 C13 C14 C15a/…
runyourempire Sep 27, 2026
baa312d
fix(eval): the auto-return scanner never drops a statement
runyourempire Sep 27, 2026
976e0af
test(demo-app): describe the parse check that replaced the 750ms watc…
runyourempire Sep 27, 2026
802fd56
Merge lane C: page-facing JS bridge hardening + ASI scanner (V-1 V-2 …
runyourempire Sep 27, 2026
03deed1
fix(server): header/body deadlines, connection cap, browser-request g…
runyourempire Sep 27, 2026
bbeab15
Merge lane A: eval lifecycle (C1/V-5 C2/N2 C3 C4/V-13 C7 C9 C15c/d V-…
runyourempire Sep 27, 2026
c0783c4
test: end-to-end N1 proof over the real server; slot test drains a li…
runyourempire Sep 27, 2026
6f09f30
fix(discovery): per-user discovery root on Unix; every reader scans t…
runyourempire Sep 27, 2026
2f1d4cb
test: align stale expectations with the capability gate and the F6 no…
runyourempire Sep 27, 2026
64ed5ed
fix(mcp): name InitializeResult, not the ServerInfo alias rmcp 3.4 de…
runyourempire Sep 27, 2026
dc1db6a
fix(eval): the unserializable-result message had runs of source inden…
runyourempire Sep 27, 2026
0cf882c
Merge lane D: database, file tools, HTTP server and discovery hardeni…
runyourempire Sep 27, 2026
a1f574b
fix(vscode): discover 0.9 apps in the per-user Unix root; another use…
runyourempire Sep 27, 2026
bf1699c
docs: round-3 audit changes in CHANGELOG, MIGRATION, security model a…
runyourempire Sep 27, 2026
961c519
fix(init): patched main.rs/Cargo.toml never written through a symlink…
runyourempire Sep 27, 2026
e2324f6
fix(test): slice::from_ref in a unix-only test (clippy 1.98 cloned_re…
runyourempire Sep 27, 2026
ea40ec5
fix(query_db): refuse a bad query before resolving any database; demo…
runyourempire Sep 27, 2026
a7ea293
chore: Cargo.lock for demo-app's rusqlite dependency
runyourempire Sep 27, 2026
43b7561
fix(examples): enable Tauri's x11 feature so Linux screenshots work i…
runyourempire Sep 27, 2026
732a5a3
docs: round-4 audit corrections (tool params, smoke checks, MIGRATION…
runyourempire Sep 28, 2026
edfc014
fix(introspect): contract_record truncates its sample on a char bound…
runyourempire Sep 28, 2026
d5db7eb
fix(animation): scrub capture=true requires the screenshot tool (R4-N…
runyourempire Sep 28, 2026
881385b
fix(query_db): quote-aware SQL pre-checks (R4-DB1)
runyourempire Sep 28, 2026
4a1dab9
fix(resources): a bare-name tool disable also blocks its resources (R…
runyourempire Sep 28, 2026
99d148b
fix(recording): drain watermark reset is monotonic (R4-RACE1)
runyourempire Sep 28, 2026
7724fe5
fix(plugin): keep recording-drain plumbing out of the public API (R4-…
runyourempire Sep 28, 2026
19b5eb9
fix(privacy): disable_tools accepts both inspect spellings and warns …
runyourempire Sep 28, 2026
aa472fc
fix(trace): check generation and push a frame atomically (R4-RACE2)
runyourempire Sep 28, 2026
92af54d
fix(bridge): ignore synthetic pagehide/pageshow events (R4-JS1)
runyourempire Sep 28, 2026
4d12e13
fix(bridge): keep the agent key out of reach of page hooks via .calle…
runyourempire Sep 28, 2026
9e2eec4
fix(bridge): an abandoned main-thread closure keeps the round trip se…
runyourempire Sep 28, 2026
86fb49f
fix(input): trusted input requires confirmed focus and a clickable po…
runyourempire Sep 28, 2026
19ce9e2
fix(eval): an unconfirmed ready signal no longer aborts an eval (R4-E…
runyourempire Sep 28, 2026
c1fcc17
fix(bridge): log the fetch/XHR target the request really uses (R4-JS3)
runyourempire Sep 28, 2026
f1fd285
fix(input): trusted click must land inside the client area (R4-IN2, R…
runyourempire Sep 28, 2026
26556ac
fix(bridge): clamp route delay_ms to the timer maximum (G-12)
runyourempire Sep 28, 2026
9a20eb8
fix(introspection): bound the fault, contract and page-load maps (G-10)
runyourempire Sep 28, 2026
d3f8f0e
merge: round-4 JS-bridge lane (R4-JS1, R4-JS2, R4-JS3, G-12)
runyourempire Sep 28, 2026
18c3153
fix(introspection): a panicked background task is reported finished (…
runyourempire Sep 28, 2026
d7c8e20
fix(eval): auto-return scanner no longer drops statements on CR, comm…
runyourempire Sep 28, 2026
4ef7758
fix(eval): the timeout message rules out a parse error only when the …
runyourempire Sep 28, 2026
83254e9
fix(backend): bound read_app_file and cap concurrent app probes (R4-B…
runyourempire Sep 28, 2026
9960159
fix(introspect): command_timings reports when its command cap is hit …
runyourempire Sep 28, 2026
7a8d503
fix(screenshot): run WGC COM work on a dedicated MTA thread (G-11)
runyourempire Sep 28, 2026
6ccf436
fix(discovery): unpredictable plugin uid-probe file name (R4-DISC2, p…
runyourempire Sep 28, 2026
f64ec57
fix(tools): budget page-callable window queries (G-2)
runyourempire Sep 28, 2026
2b10c86
fix(route): cap route add delay_ms (G-12)
runyourempire Sep 28, 2026
2091507
fix(victauri-test): discovery keeps live apps' entries and never send…
runyourempire Sep 28, 2026
ede95ec
fix(victauri-test): page text in the smoke summary cannot drive the t…
runyourempire Sep 28, 2026
75dfe2d
fix(victauri-test): Locator check()/uncheck() work on ARIA checkboxes…
runyourempire Sep 28, 2026
91ce30f
docs(victauri-test): README visual-regression example compiles (`is_m…
runyourempire Sep 28, 2026
4dbe90c
fix(watchdog): a 429 or an undeterminable PID no longer triggers reco…
runyourempire Sep 28, 2026
950f641
fix(cli bridge): 429 health = alive, exact --app matching, safe port-…
runyourempire Sep 28, 2026
15a7a7e
fix(cli): --app on every connecting command, ghost names listed, safe…
runyourempire Sep 28, 2026
cef779b
fix(vscode): escape generated Rust, never send the token to the defau…
runyourempire Sep 28, 2026
1db6f80
ci(release): verify packages in a secret-free job; publish job compil…
runyourempire Sep 28, 2026
a096191
merge: round-4 plugin-internals lane (R4-DB1, R4-API1, R4-RACE1/2, R4…
runyourempire Sep 28, 2026
83a767b
fix(watchdog): clippy-clean on Unix (Windows-only liveness variant, d…
runyourempire Sep 28, 2026
205b26e
chore(plugin): clippy -D warnings clean for the round-4 fixes
runyourempire Sep 28, 2026
bd25520
fix(plugin): accept rusqlite >=0.32,<0.41 with fail-closed setup (R4-…
runyourempire Sep 28, 2026
54fb87b
merge: round-4 clients lane (R4-NET1, R4-DISC1/2, R4-TOK1, R4-VSC1, R…
runyourempire Sep 28, 2026
67afd59
test(plugin): unix FIFO read test compiles and releases its reader; j…
runyourempire Sep 28, 2026
d8980f1
ci: prove the newest end of the rusqlite range; fix the smoke-check l…
runyourempire Sep 28, 2026
dc4f500
test(plugin): run the trusted-input jsdom tests in their own test binary
runyourempire Sep 28, 2026
1f56df2
merge: round-4 plugin tool-path lane (R4-PANIC1, R4-NET2/3/4, R4-IN1/…
runyourempire Sep 28, 2026
4f56d66
docs: round-4 CHANGELOG + MIGRATION (and correct four round-3 claims)
runyourempire Sep 28, 2026
d246eef
fix(server): refused requests close their connection; release notes f…
runyourempire Sep 28, 2026
b5f04c0
fix(recording): `recording stop` flushes every window before stopping
runyourempire Sep 28, 2026
31442cb
fix: round-4 regression review — shadow-DOM clicks, Tcl SQL params, b…
runyourempire Sep 28, 2026
659e353
fix(discovery): accept a discovery root owned by BUILTIN\Administrato…
runyourempire Sep 28, 2026
6d4ce97
revert(bridge): drop the dispatch-gate yield spin — it crashed the We…
runyourempire Sep 28, 2026
ae033e8
fix(plugin): never clone or drop a Tauri handle off the main thread —…
runyourempire Sep 29, 2026
872753d
test, ci, docs: guard the off-main-handle fix; repeat the Linux heap …
runyourempire Sep 29, 2026
9846473
docs: CI + live validation of the off-main-handle fix; correct MAIN_D…
runyourempire Sep 29, 2026
12f2a91
fix(server): never drop the bridge's AppHandle off the main thread at…
runyourempire Sep 29, 2026
c59e5ce
fix(watchdog): match --app identity ASCII case-insensitively, like th…
runyourempire Sep 29, 2026
2ac4858
fix(permissions): drop eval_js / dom_snapshot from victauri:default
runyourempire Sep 29, 2026
9ecb6fb
fix(cli): treat a blank VICTAURI_APP / --app as unset in the bridge (…
runyourempire Sep 29, 2026
294d963
fix(examples): keep Tauri handles on the main thread
runyourempire Sep 29, 2026
f2f59ed
fix(server): a connection holds a request slot only after its first b…
runyourempire Sep 29, 2026
6627e8a
fix(bridge): select + limit IPC/network log entries before deep-copyi…
runyourempire Sep 29, 2026
7adb767
ci: compile the plugin without SQLite; MSRV --locked; honest semver note
runyourempire Sep 29, 2026
df67b1b
docs: fix Pages link case, document bundled-sqlite, drop no-op --wait
runyourempire Sep 29, 2026
316414a
docs: state the real browser-origin rule (403 vs 415)
runyourempire Sep 29, 2026
d37a88f
fix(cli): answer a JSON-RPC batch locally, never forward it (R5-BR1)
runyourempire Sep 29, 2026
d6783fb
fix(cli): never answer a client's JSON-RPC response (R5-BR3)
runyourempire Sep 29, 2026
5216659
fix(cli): a tool call whose SSE response dies mid-stream says it may …
runyourempire Sep 29, 2026
8570e02
fix(victauri-test): JUnit XML never contains characters XML 1.0 forbi…
runyourempire Sep 29, 2026
6f0fa67
fix(victauri-test): neutralize page text in check details, panics and…
runyourempire Sep 29, 2026
c71ebcc
fix(vscode): never re-send the token to a port its app no longer owns…
runyourempire Sep 29, 2026
9212819
docs: same-window page script can rewrite eval results (correct claims)
runyourempire Sep 29, 2026
1afecba
fix(db): db_health counts only canonical CREATE TABLE definitions (R5…
runyourempire Sep 29, 2026
25b7085
fix(server): animation scrub never reports a capture it did not make …
runyourempire Sep 29, 2026
a816d89
fix(bridge): always deliver an eval outcome when the page breaks toJS…
runyourempire Sep 29, 2026
b4c3889
fix(bridge): slotted content no longer "covers" its shadow slot host …
runyourempire Sep 29, 2026
198d234
docs(migration): list every item 0.9.0 hid, removed or made non_exhau…
runyourempire Sep 29, 2026
b6244fc
fix(bridge): a route glob's `?` matches a literal `?` (R5-JS4)
runyourempire Sep 29, 2026
c0df9ee
fix(bridge): cap uncaught-error messages, pristine addRoute parse, lo…
runyourempire Sep 29, 2026
96d1083
fix(server): eval auto-return no longer drops statements after contro…
runyourempire Sep 29, 2026
13bcd88
test(plugin): pin every registered command's sync-ness; correct the w…
runyourempire Sep 29, 2026
5fd7056
test(bridge): run the R5-JS1 projection tests from their own test binary
runyourempire Sep 29, 2026
f342044
merge: round-5 server lane
runyourempire Sep 29, 2026
63c54f8
merge: round-5 clients lane
runyourempire Sep 29, 2026
b04cdb3
merge: round-5 docs lane
runyourempire Sep 29, 2026
55f0319
merge: round-5 js lane
runyourempire Sep 29, 2026
c1a5f5e
docs: round-5 CHANGELOG for the bridge, client and extension fixes; f…
runyourempire Sep 29, 2026
ef22039
ci, docs: rusqlite-range job asserts it reached the newest minor; hon…
runyourempire Sep 29, 2026
790af9d
fix(cli): victauri doctor exits 1 when any check FAILs (R5B-DOCTOR1)
runyourempire Sep 29, 2026
ce6b51b
fix(css): allowlist-based remote-URL check for css inject (R5B-CSS1)
runyourempire Sep 29, 2026
99b46a4
fix(tools): expression tools accept a trailing `;` / comment; a wait_…
runyourempire Sep 29, 2026
f051e3f
fix(tools): assert_semantic / verify_state read `undefined` as null (…
runyourempire Sep 29, 2026
f623128
fix(bridge): animation scrub/sweep ops behind the agent key (R5B-SCRU…
runyourempire Sep 29, 2026
53ba3e4
fix(plugin): adopt the real main thread when setup runs off it (R5B-M…
runyourempire Sep 29, 2026
bb9acc5
docs(plugin): threading contract for probe/on_ready; honest round-tri…
runyourempire Sep 29, 2026
797e2e6
fix(bridge): route rules match relative and absolute request URLs ali…
runyourempire Sep 29, 2026
25c4631
fix(plugin): bound the page-callable IPC queries run on the UI thread…
runyourempire Sep 29, 2026
cac5ec2
fix(tools): wait_for `timeout_ms: 0` is a single immediate check (R5B…
runyourempire Sep 29, 2026
d0a8750
fix(tools): `logs slow_ipc` honours `webview_label` (R5B-SLOWIPC1)
runyourempire Sep 29, 2026
33073eb
fix(bridge): one log entry per XHR request, listeners attached once (…
runyourempire Sep 29, 2026
a523560
fix(tools): `explain diff` counts every call and lists each command o…
runyourempire Sep 29, 2026
7e17e98
fix(cli): init prints paths without the Windows verbatim prefix (R5B-…
runyourempire Sep 29, 2026
830eff3
fix(cli): init's .mcp.json suggestion pins --app like the generated f…
runyourempire Sep 29, 2026
2c7ce9b
fix(victauri-test): IPC checkpoints are u64 epoch milliseconds (R5B-C…
runyourempire Sep 29, 2026
a306673
fix(victauri-test): the 401 hint names the real per-user token locati…
runyourempire Sep 29, 2026
41c3dab
fix(victauri-test): tool/JSON-RPC error text is sanitized when displa…
runyourempire Sep 29, 2026
bd7fd8b
fix(victauri-test): the smoke suite never stops a recording it did no…
runyourempire Sep 29, 2026
9ca683e
fix(cli): bridge liveness reuses victauri-test's hardened check, neve…
runyourempire Sep 29, 2026
7963470
fix(bridge): fetch() interceptor passes arguments through exactly (R5…
runyourempire Sep 29, 2026
4857fac
fix(cli): bridge handles requests concurrently (R5B-BR5)
runyourempire Sep 29, 2026
6995452
fix(tools): a page-refused interact/input/inspect/route-add is a tool…
runyourempire Sep 29, 2026
247f580
fix(cli): bridge confirms an --app backend's identity on /info (R5B-BR6)
runyourempire Sep 29, 2026
b1ea3ff
fix(cli,victauri-test): VICTAURI_PORT and an app selector must agree …
runyourempire Sep 29, 2026
98e0392
fix(plugin): query_db runs only built-in or deterministic SQL functio…
runyourempire Sep 29, 2026
0a22b45
fix(bridge): cap URLs stored in the network and route-match logs (R5B…
runyourempire Sep 29, 2026
d878e97
fix(plugin): db_health never runs host-registered virtual-table modul…
runyourempire Sep 29, 2026
959a902
fix(plugin): accept an eval result only from the window it was sent t…
runyourempire Sep 29, 2026
e81cd8d
fix(plugin): redact URL credential params and keys in embedded/nested…
runyourempire Sep 29, 2026
c0d4042
fix(tools): make the load-sensitive dispatch / probe / file-read test…
runyourempire Sep 29, 2026
20ca143
fix(plugin): 10 s request-head deadline (was hyper's 30 s) (R5B-SLOWL…
runyourempire Sep 29, 2026
8c9eb0c
fix(bridge): IPC body capture and page evals use the init-time JSON (…
runyourempire Sep 29, 2026
806f33d
fix(discovery): Windows readers trust only discovery dirs the user ow…
runyourempire Sep 29, 2026
507af94
fix(discovery): per-user home fallback when /tmp/victauri-<uid> is ta…
runyourempire Sep 30, 2026
8dc0021
merge: round-5b tools lane (Lows)
runyourempire Sep 30, 2026
7c0c130
merge: round-5b js lane (Lows)
runyourempire Sep 30, 2026
97c90b1
merge: round-5b sec lane (Lows)
runyourempire Sep 30, 2026
c5c1871
merge: round-5b clients lane (Lows)
runyourempire Sep 30, 2026
72b7601
fix: round-5b integration — client pool below the 10 s keep-alive, de…
runyourempire Sep 30, 2026
ac1afad
fix(db): collapse a stray run of spaces in the function-list fallback…
runyourempire Sep 30, 2026
a981634
test(bridge): R5B-XHR1 waits for each request's real loadend (Windows…
runyourempire Sep 30, 2026
b5d8f4a
test(bridge): R5B-XHR1 asserts the re-opened request finished, not ho…
runyourempire Sep 30, 2026
3ccd94b
release: 0.9.0 — CHANGELOG date
runyourempire Sep 30, 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
14 changes: 12 additions & 2 deletions .github/actions/victauri-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ inputs:
victauri-version:
description: Version of victauri-cli to install
required: false
default: "0.8.8"
default: "0.9.0"
cli-source-path:
description: >-
Build & install victauri-cli from this local repo path instead of
Expand Down Expand Up @@ -104,7 +104,17 @@ runs:

elapsed=0
echo "Waiting for Victauri server on port ${VICTAURI_PORT}..."
until curl -sf "http://127.0.0.1:${VICTAURI_PORT}/health" > /dev/null 2>&1; do
# A 2xx — or a 429: /health is rate-limited from the public bucket, and a
# rate-limited answer still proves the server is up (R4-NET1).
server_answers() {
local code
code=$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:${VICTAURI_PORT}/health" 2>/dev/null) || true
case "$code" in
2??|429) return 0 ;;
*) return 1 ;;
esac
}
until server_answers; do
if [ "$elapsed" -ge "$HEALTH_TIMEOUT" ]; then
echo "::error::Victauri server did not become healthy within ${HEALTH_TIMEOUT}s on port ${VICTAURI_PORT}"
exit 1
Expand Down
183 changes: 162 additions & 21 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,19 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: cargo clippy --workspace --all-targets --no-default-features -- -D warnings

# The workspace step above does NOT compile the plugin without SQLite: demo-app and
# gauntlet-app depend on victauri-plugin with default features, and cargo's feature
# unification keeps `sqlite` on for every member. Only a `-p victauri-plugin` build
# actually compiles the `not(feature = "sqlite")` paths a consumer with
# `default-features = false` gets.
- name: Clippy (plugin alone, no SQLite)
if: matrix.os == 'ubuntu-latest'
run: cargo clippy -p victauri-plugin --all-targets --no-default-features -- -D warnings

- name: Plugin unit tests (no SQLite)
if: matrix.os == 'ubuntu-latest'
run: cargo test -p victauri-plugin --no-default-features --lib

- name: Clippy (release profile — incl. tests)
if: matrix.os == 'ubuntu-latest'
run: cargo clippy --workspace --all-targets --release -- -D warnings
Expand Down Expand Up @@ -336,6 +349,43 @@ jobs:
path: gauntlet.log
if-no-files-found: ignore

# The VS Code extension: typecheck, bundle, and its unit tests (code generation escaping,
# discovery/connection resolution, health semantics) under plain Node.
vscode:
name: VS Code extension
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
defaults:
run:
working-directory: editors/vscode
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
with:
node-version: 22

# rustc lets the codegen test prove each generated literal lexes back to its input.
- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master (2026-06)
with:
toolchain: stable

- name: Install dependencies (no install scripts)
run: npm ci --ignore-scripts --no-audit --no-fund

- name: Typecheck
run: npm run lint

- name: Build
run: npm run build

- name: Unit tests
run: npm test

docs:
name: Docs
runs-on: ubuntu-latest
Expand Down Expand Up @@ -377,8 +427,52 @@ jobs:
with:
save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}

# --locked: check the committed lockfile's versions (the ones CI and a fresh
# `cargo install --locked` resolve), and fail if Cargo.lock is out of date instead of
# silently re-resolving.
- name: Check MSRV
run: cargo check --workspace
run: cargo check --workspace --locked

# victauri-plugin accepts rusqlite `>=0.32, <0.41` so cargo unifies onto the app's own
# rusqlite (`links = "sqlite3"` allows one libsqlite3-sys per build). The lockfile pins the
# OLD end; this job proves the NEW end: the security setters changed return type across the
# range (`SetupOutcome` in database.rs keeps them fail-closed on every version).
rusqlite-range:
name: rusqlite range (newest)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Install system dependencies
uses: ./.github/actions/linux-deps

- uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master (2026-06)
with:
toolchain: stable

- name: Move rusqlite to the newest version the range allows
# Fails if the update did not reach the newest minor the workspace range allows
# (`>=0.32, <0.41` in Cargo.toml) — otherwise this job would silently keep testing 0.32.
# Widen NEWEST together with the range.
env:
NEWEST: "0.40."
run: |
cargo update -p rusqlite
resolved=$(grep -A1 '^name = "rusqlite"' Cargo.lock | sed -n 's/^version = "\(.*\)"/\1/p')
echo "rusqlite resolved to ${resolved:-<none>}"
case "$resolved" in
"$NEWEST"*) ;;
*) echo "::error::rusqlite resolved to '$resolved', expected $NEWEST* (the newest the range allows)"; exit 1 ;;
esac

- name: Clippy (plugin, sqlite)
run: cargo clippy -p victauri-plugin --all-targets --features sqlite -- -D warnings

- name: Plugin unit tests (incl. query_db / db_health)
run: cargo test -p victauri-plugin --features sqlite --lib

security:
name: Security Audit
Expand Down Expand Up @@ -439,10 +533,15 @@ jobs:
- name: Generate coverage
run: cargo llvm-cov --workspace --lcov --output-path lcov.info

- name: Upload coverage to Codecov
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v4.7.1
# No Codecov upload: without a token it failed on every run (tokenless upload
# refused) while reporting green, and the action ran an unverified `latest`
# CLI. The report is kept as an artifact instead.
- name: Keep the coverage report
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
files: lcov.info
name: lcov
path: lcov.info
retention-days: 14

semver:
name: Semver Checks
Expand All @@ -466,27 +565,27 @@ jobs:
save-if: ${{ github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' }}

# Prebuilt binary — avoids ~3 min compiling cargo-semver-checks from source.
# Pinned: the version this action pin defaults to (0.48) cannot read the rustdoc JSON of
# current stable ("unsupported rustdoc format v60"), and failed before checking anything.
- uses: taiki-e/install-action@25435dc8dd3baed7417e0c96d3fe89013a5b2e09 # v2
with:
tool: cargo-semver-checks

# INFORMATIONAL — not a required gate (removed from ci-success). cargo-semver-
# checks builds rustdoc and is currently broken in CI in two INDEPENDENT ways,
# neither of which is an API break:
# - victauri-plugin: rustdoc hits an upstream E0119 ("conflicting
# implementations of From<HourBase>") compiling `time` (pulled by
# tauri → cookie) on every stable toolchain tested (1.93.1, 1.95) and the
# latest time (0.3.48). The baseline build uses fresh crates.io resolution,
# so pinning our lock can't fix it.
# - victauri-core: cargo-semver-checks' fresh baseline resolution fails in CI
# (passes locally only with a warm cache).
# A plain `cargo doc --workspace` succeeds, so these are tooling/toolchain
# issues, not semver violations. Keep it running for signal; use local
# `cargo semver-checks` as the pre-release gate. Re-add to ci-success once the
# upstream time/rustdoc bug is fixed.
tool: cargo-semver-checks@0.50.0

# INFORMATIONAL — not a required gate: a new stable rustdoc JSON format can outrun
# the pinned cargo-semver-checks, which is a tooling failure, not an API break. Note
# that for a 0.x MAJOR bump (0.8.8 -> 0.9.0) this step checks NOTHING: every lint is
# already permitted by a major bump, so it reports "0 checks … 254 skip" and passes.
# It only has teeth between patch releases of one 0.x line. RELEASING.md step 3 covers
# what to run for a major bump (`--release-type minor`, to list what actually broke).
# A failure is surfaced as a warning annotation below, never swallowed silently;
# RELEASING.md makes the local run the pre-release gate.
- name: Check semver (informational)
id: semver
continue-on-error: true
run: cargo semver-checks check-release --workspace
- name: Surface a semver-checks failure
if: steps.semver.outcome == 'failure'
run: echo "::warning title=Semver Checks::cargo semver-checks failed (API break, or a toolchain/tool mismatch) — read the log above"

e2e:
name: E2E Integration (${{ matrix.os }})
Expand Down Expand Up @@ -566,6 +665,46 @@ jobs:
env:
VICTAURI_E2E: "1"

# One run of the suite is a weak detector for a host crash that depends on timing: the
# 0.9.0 Linux heap corruption (a Tauri handle cloned/dropped off the main thread) killed the
# host in only ~25-50% of runs and hid behind nine green single runs. So on Linux the
# heap-sensitive tests run again against three FRESH apps, and any dead host fails the job.
- name: Heap-safety repeats against fresh apps (Linux)
if: runner.os == 'Linux'
env:
VICTAURI_E2E: "1"
run: |
# The suite's app is stopped on purpose here; clear APP_PID so the failure step below
# does not report it as a host that died.
if [ -n "$APP_PID" ]; then kill "$APP_PID" 2>/dev/null || true; fi
echo "APP_PID=" >> "$GITHUB_ENV"
sleep 1
deaths=0
for i in 1 2 3; do
xvfb-run -a ./target/debug/demo-app >/tmp/repeat-$i.out 2>/tmp/repeat-$i.err &
pid=$!
for t in $(seq 1 60); do
code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:7373/health || true)
case "$code" in 2??|429) break ;; esac
sleep 1
done
cargo test -q -p demo-app --test integration -- --test-threads=1 --exact \
concurrent_window_introspection_is_heap_safe \
webview_access_main_thread_safe_under_ipc_load \
webview_reload_during_introspection_is_safe || true
sleep 2
if ! pgrep -x demo-app >/dev/null || grep -qE 'malloc|corrupted|double free|unaligned|free\(\)' /tmp/repeat-$i.err /tmp/repeat-$i.out; then
deaths=$((deaths + 1))
echo "::error::repeat $i: the demo-app host died"
tail -n 40 /tmp/repeat-$i.err /tmp/repeat-$i.out
fi
pkill -x demo-app || true
kill "$pid" 2>/dev/null || true
sleep 1
done
echo "host deaths: $deaths/3"
test "$deaths" -eq 0

# Only on failure, and only where we captured it. If the host died, its own output names
# the cause; without this the log shows nothing but "connection refused".
- name: Show demo app output on failure (Unix)
Expand Down Expand Up @@ -601,7 +740,7 @@ jobs:
# Listing ~15 matrix legs as required checks is brittle (a renamed job
# silently stops being required). This job depends on all of them and fails
# if any FAILED or was CANCELLED — a SKIPPED job (a conditional leg that
# legitimately did not apply, e.g. `semver` on push or `e2e` on a PR) passes.
# legitimately did not apply, e.g. `semver` on a push to main) passes.
# Require ONLY "CI Success" in branch protection.
# ─────────────────────────────────────────────────────────────────────
ci-success:
Expand All @@ -614,7 +753,9 @@ jobs:
live-app,
gauntlet,
docs,
vscode,
msrv,
rusqlite-range,
security,
deny,
coverage,
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ jobs:
app: [kanri, en-croissant, lettura]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# Third-party apps and their install scripts run in this job: leave no
# token in .git/config for them to find.
persist-credentials: false

- name: Skip non-selected apps (manual single-app runs)
id: gate
Expand Down Expand Up @@ -72,6 +76,9 @@ jobs:
if: steps.gate.outputs.run == 'true'
with:
key: compat-${{ matrix.app }}
# Never save: third-party build scripts ran here, so this target/ must
# not become a cache another workflow restores.
save-if: false

# The four apps use two JS package managers: yarn (Kanri) and pnpm (the rest).
# corepack supplies both shims. (Bun was only needed for Surrealist, which was
Expand Down
13 changes: 11 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ on:
- '.github/workflows/docs.yml'
workflow_dispatch:

# Least privilege: read-only by default. Only the deploy job (which runs no repo code)
# gets the Pages + OIDC permissions it needs.
permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
Expand All @@ -20,8 +20,13 @@ concurrency:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false

- name: Install mdBook
uses: peaceiris/actions-mdbook@062dc9e3eab0bad35531417c6bb6c6a7a184764f # v2
Expand All @@ -39,6 +44,10 @@ jobs:
deploy:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
Expand Down
Loading
Loading