docs(acl): reconcile spec prose with the shipped implementation
Secret Scan / scan (push) Successful in 6s
Build App (Preview) / compute-version (pull_request) Successful in 5s
Secret Scan / scan (pull_request) Successful in 7s
Build App (Preview) / create-release (pull_request) Successful in 3s
Build App (Preview) / build-macos (pull_request) Successful in 2m49s
Build App (Preview) / build-linux (pull_request) Successful in 5m16s
Build App (Preview) / build-windows (pull_request) Successful in 10m4s
Build App (Preview) / prune-previews (pull_request) Successful in 9s

Final-wave cleanups from the whole-branch review (final-review.md Minor
1-5): spec §4 now says selective pruning, not "deletes the directory
every build"; spec §3.3 now describes the TypeScript-AST scan
(fail-closed Vite-order resolution, namespace imports as member access
only, the every-code-file boundary check) instead of the old
regex/chunk description; the viewer spec's historical "every command
is callable from every window" line gets a dated "closed by the
AppManifest lockdown" note; the lib.rs doc comment on
the_generated_app_manifest_matches_the_handler_list no longer claims
independence from the shared parser it actually reuses; and the vitest
command-name regex now allows digits, matching Rust's [a-z0-9_]+.

Also adds a cargo test backstop
(the_tauri_config_capability_check_runs_against_the_real_tree) that
runs build.rs's tauri-config capability check against the real
app/src-tauri tree on every `cargo test`, closing the gap where a new
tauri.<platform>.conf.json on an already-built tree only gets checked
by build.rs on a clean build.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-22 23:25:50 -07:00
co-authored by Claude Opus 5.5
parent a479bce639
commit 71ba5076db
4 changed files with 93 additions and 20 deletions
+50 -6
View File
@@ -972,12 +972,16 @@ mod tests {
/// `build.rs` derives the AppManifest from the handler list and this reads back what
/// tauri-build actually embedded. `cargo test` runs the build script first, so
/// `gen/schemas/acl-manifests.json` is fresh. Independent of the shared parser: if
/// `registered_commands` ever lost half the list, `build.rs` would declare half a
/// manifest and this would still compare it against… the same half. So the count is
/// pinned too, from a source that is not the parser: the `#[tauri::command]` scan in
/// `every_command_is_registered_exactly_once` guarantees definitions == registrations,
/// and here the embedded set must match the number of registrations that scan found.
/// `gen/schemas/acl-manifests.json` is fresh. This guards against the committed/generated
/// artifact diverging from `generate_handler!` — a stale `acl-manifests.json`, or a
/// tauri-build naming change — using the same `registered_commands` parser `build.rs` used
/// to derive the manifest in the first place. It is *not* independent of a parser dropout on
/// its own: if `registered_commands` lost half the list, `build.rs` would declare half a
/// manifest and this would still compare it against the same half. That guarantee is
/// transitive, not local — `every_command_is_registered_exactly_once` covers it, by
/// cross-checking the parser's output against an independent `#[tauri::command]` scan, so a
/// parser regression that silently dropped commands fails there rather than going unnoticed
/// here.
#[test]
fn the_generated_app_manifest_matches_the_handler_list() {
use std::collections::BTreeSet;
@@ -1021,4 +1025,44 @@ mod tests {
);
assert!(app["default_permission"].is_null(), "no app `default` permission set");
}
/// `build.rs`'s `check_tauri_config` (inline `app.security.capabilities`, a JSON5/TOML tauri
/// config, `TAURI_CONFIG`) only runs inside the build script, so it only re-runs on a clean
/// build or in CI — cargo's incremental build has no reason to notice a new
/// `tauri.<platform>.conf.json` dropped into an already-built tree (CLAUDE.md, "Known
/// limit"). This runs the same check, using the same `command_census` functions build.rs
/// calls, directly against the real `app/src-tauri` directory on every `cargo test`, so that
/// gap is closed locally too.
#[test]
fn the_tauri_config_capability_check_runs_against_the_real_tree() {
let dir = env!("CARGO_MANIFEST_DIR");
let mut problems = Vec::new();
for entry in std::fs::read_dir(dir).expect("readable src-tauri/") {
let path = entry.expect("readable entry in src-tauri/").path();
let name = path
.file_name()
.expect("a directory entry has a file name")
.to_string_lossy()
.into_owned();
match crate::command_census::tauri_config_file(&name) {
None => {}
Some(false) => problems.push(format!(
"{name}: the census reads JSON tauri configs only; a JSON5/TOML config \
could declare capabilities it cannot see"
)),
Some(true) => {
let json =
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{name}: {e}"));
problems.extend(crate::command_census::tauri_config_problem(&name, &json));
}
}
}
if let Ok(json) = std::env::var("TAURI_CONFIG") {
problems.extend(crate::command_census::tauri_config_problem("TAURI_CONFIG", &json));
}
assert!(
problems.is_empty(),
"cargo test found what build.rs would refuse on a clean build: {problems:?}"
);
}
}