flowproof 0.23.28__tar.gz → 0.23.30__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.
- {flowproof-0.23.28 → flowproof-0.23.30}/Cargo.lock +45 -55
- {flowproof-0.23.28 → flowproof-0.23.30}/Cargo.toml +8 -2
- {flowproof-0.23.28 → flowproof-0.23.30}/PKG-INFO +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/lib.rs +11 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/web.rs +216 -8
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/heal.rs +41 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/spec.rs +82 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/agent_flow.rs +30 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/lib.rs +223 -6
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/agent_conversation_anthropic_e2e.rs +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/agent_conversation_streaming_e2e.rs +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/agent_flow_e2e.rs +10 -9
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/agent_url_record_e2e.rs +2 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/config_seed_e2e.rs +2 -2
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/egress_e2e.rs +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_arg_matchers.rs +1 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_call_order.rs +1 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_mcp_kill.rs +1 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_no_tool_call.rs +1 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_reply_contains.rs +1 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_side_effect.rs +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/mcp_http_e2e.rs +1 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/mcp_stdio_e2e.rs +6 -6
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/skip_unless_env.rs +2 -2
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/suite_env_from.rs +6 -2
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/suite_flow_isolation.rs +6 -2
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/Cargo.toml +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-python/src/lib.rs +8 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/flowproof/__init__.py +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/pyproject.toml +1 -1
- {flowproof-0.23.28 → flowproof-0.23.30}/README.md +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/Cargo.toml +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/examples/vision_bench.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/examples/vision_do.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/agent_proxy.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/agent_runner.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_linux.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/audit.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/capture.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/env_block.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/filters.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/identity.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/logon.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/netevents.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/run.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/spawn.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows/wfp.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/egress_windows.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/fiori.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/fs_observe.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/mcp_core.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/mcp_http.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/mcp_stdio.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/sap_com.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/vision/start.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/vision.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/vision_bench.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/vision_elements.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/src/vision_winocr.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/a11y_capture.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/drag_spike.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/fingerprint_capture.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/fixtures/windows-start.png +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/fs_observation_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/grid_scene_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/list_scene_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/network_idle_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/password_recording_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/shared_browser_shutdown_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/side_effect_http_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/static_area_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/visibility_detach_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-adapters/tests/windows_containment_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/Cargo.toml +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/agent_steps.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/author.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/clarify.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/code_author.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/doc_author.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/doc_formats/hp_alm.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/doc_formats.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/draft_assembly.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/lib.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/llm.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/recorder.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/repair.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/src/rules.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-agent/tests/model_client_http.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/Cargo.toml +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/skills/flowproof-config/SKILL.md +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/agent_surface.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/capture.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/config.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/doctor.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/main.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/suite.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/suite_checkpoint.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/suite_inputs.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/suite_journal.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/src/update_check.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/a11y_selector_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/api_pipeline.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/audit_record_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/author_from_code_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/calc_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/citrix_start.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/clock_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/config_cli_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/config_skill_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/cookie_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/doctor_ai_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/doctor_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/documented_flags.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/examples_resolve.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/export_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_audit_since.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_capability_regression.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/falsifiability_control_verdict.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/fiori_field_commit_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/grid_cell_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/heal_apply_proposal.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/heal_vars_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/iframe_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/llm_author_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/notepad_author_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/notepad_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/page_title_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/pinned_random_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/record_progress.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/sap_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/sap_pipeline.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/sap_sim_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/scoped_container_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/select_missing_option_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/sigterm_shared_browser_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/suite_checkpoint.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/suite_missing_trace.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/suite_policy.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/support/sap_simulator.py +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/visibility_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/vision_pipeline.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/vision_start_replay.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-cli/tests/web_e2e.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/app.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/backend.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/gdi.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/lib.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/mock.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/oob.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/recording.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/redact.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/surface.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/uia_scan.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/visual.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-driver/src/window.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-python/Cargo.toml +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-replay/Cargo.toml +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-replay/src/lib.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-replay/src/report.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-replay/src/runrecord.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-replay/tests/replay_calc.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/Cargo.toml +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/schema/cassette-v1.schema.json +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/schema/side-effect-v1.schema.json +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/schema/trace-v1.schema.json +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/captures.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/cassette.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/cassette_diff.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/egress.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/format.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/lib.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/secret.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/secret_scan.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/side_effect.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/substitution.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/toolcalls.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/src/tosca.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/cassette_conformance.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/fixtures/guarded.trace.jsonl +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/fixtures/multi.trace.jsonl +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/fixtures/repeat.trace.jsonl +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/fixtures/sample.trace.jsonl +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/schema_conformance.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/side_effect_conformance.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/crates/flowproof-trace/tests/tosca_export.rs +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/flowproof/cli.py +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/flowproof/flow.py +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/flowproof/mcp_server.py +0 -0
- {flowproof-0.23.28 → flowproof-0.23.30}/flowproof/py.typed +0 -0
|
@@ -141,15 +141,6 @@ dependencies = [
|
|
|
141
141
|
"num-traits",
|
|
142
142
|
]
|
|
143
143
|
|
|
144
|
-
[[package]]
|
|
145
|
-
name = "arbitrary"
|
|
146
|
-
version = "1.4.2"
|
|
147
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
148
|
-
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
|
149
|
-
dependencies = [
|
|
150
|
-
"derive_arbitrary",
|
|
151
|
-
]
|
|
152
|
-
|
|
153
144
|
[[package]]
|
|
154
145
|
name = "ascii"
|
|
155
146
|
version = "1.1.0"
|
|
@@ -169,11 +160,12 @@ dependencies = [
|
|
|
169
160
|
|
|
170
161
|
[[package]]
|
|
171
162
|
name = "atoi_simd"
|
|
172
|
-
version = "0.
|
|
163
|
+
version = "0.18.1"
|
|
173
164
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
174
|
-
checksum = "
|
|
165
|
+
checksum = "f3cdb3708a128e559a30fb830e8a77a5022ee6902806925c216658652b452a44"
|
|
175
166
|
dependencies = [
|
|
176
167
|
"debug_unsafe",
|
|
168
|
+
"rustversion",
|
|
177
169
|
]
|
|
178
170
|
|
|
179
171
|
[[package]]
|
|
@@ -309,9 +301,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
|
|
309
301
|
|
|
310
302
|
[[package]]
|
|
311
303
|
name = "calamine"
|
|
312
|
-
version = "0.
|
|
304
|
+
version = "0.38.0"
|
|
313
305
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
314
|
-
checksum = "
|
|
306
|
+
checksum = "f431b67cba6122a1f7d26b7adafc71bbdf07026095fe811f5efc025d8748e1d8"
|
|
315
307
|
dependencies = [
|
|
316
308
|
"atoi_simd",
|
|
317
309
|
"byteorder",
|
|
@@ -628,9 +620,9 @@ dependencies = [
|
|
|
628
620
|
|
|
629
621
|
[[package]]
|
|
630
622
|
name = "ctutils"
|
|
631
|
-
version = "0.4.
|
|
623
|
+
version = "0.4.7"
|
|
632
624
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
633
|
-
checksum = "
|
|
625
|
+
checksum = "a2376ffd6f96d8a9db59875b4b6b0237d6900b5baf64279714e05493ce64828a"
|
|
634
626
|
dependencies = [
|
|
635
627
|
"cmov",
|
|
636
628
|
]
|
|
@@ -688,17 +680,6 @@ version = "0.5.8"
|
|
|
688
680
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
689
681
|
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
|
|
690
682
|
|
|
691
|
-
[[package]]
|
|
692
|
-
name = "derive_arbitrary"
|
|
693
|
-
version = "1.4.2"
|
|
694
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
695
|
-
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
|
696
|
-
dependencies = [
|
|
697
|
-
"proc-macro2",
|
|
698
|
-
"quote",
|
|
699
|
-
"syn 2.0.119",
|
|
700
|
-
]
|
|
701
|
-
|
|
702
683
|
[[package]]
|
|
703
684
|
name = "derive_builder"
|
|
704
685
|
version = "0.20.2"
|
|
@@ -930,7 +911,7 @@ dependencies = [
|
|
|
930
911
|
|
|
931
912
|
[[package]]
|
|
932
913
|
name = "flowproof-adapters"
|
|
933
|
-
version = "0.23.
|
|
914
|
+
version = "0.23.30"
|
|
934
915
|
dependencies = [
|
|
935
916
|
"anyhow",
|
|
936
917
|
"flowproof-driver",
|
|
@@ -949,7 +930,7 @@ dependencies = [
|
|
|
949
930
|
|
|
950
931
|
[[package]]
|
|
951
932
|
name = "flowproof-agent"
|
|
952
|
-
version = "0.23.
|
|
933
|
+
version = "0.23.30"
|
|
953
934
|
dependencies = [
|
|
954
935
|
"base64",
|
|
955
936
|
"chrono",
|
|
@@ -959,7 +940,7 @@ dependencies = [
|
|
|
959
940
|
"regex",
|
|
960
941
|
"serde",
|
|
961
942
|
"serde_json",
|
|
962
|
-
"
|
|
943
|
+
"serde_norway",
|
|
963
944
|
"thiserror 2.0.18",
|
|
964
945
|
"tiny_http",
|
|
965
946
|
"ureq",
|
|
@@ -968,7 +949,7 @@ dependencies = [
|
|
|
968
949
|
|
|
969
950
|
[[package]]
|
|
970
951
|
name = "flowproof-cli"
|
|
971
|
-
version = "0.23.
|
|
952
|
+
version = "0.23.30"
|
|
972
953
|
dependencies = [
|
|
973
954
|
"ab_glyph",
|
|
974
955
|
"chrono",
|
|
@@ -985,7 +966,7 @@ dependencies = [
|
|
|
985
966
|
"rpassword",
|
|
986
967
|
"serde",
|
|
987
968
|
"serde_json",
|
|
988
|
-
"
|
|
969
|
+
"serde_norway",
|
|
989
970
|
"sha2 0.10.9",
|
|
990
971
|
"tiny_http",
|
|
991
972
|
"ureq",
|
|
@@ -994,7 +975,7 @@ dependencies = [
|
|
|
994
975
|
|
|
995
976
|
[[package]]
|
|
996
977
|
name = "flowproof-driver"
|
|
997
|
-
version = "0.23.
|
|
978
|
+
version = "0.23.30"
|
|
998
979
|
dependencies = [
|
|
999
980
|
"calamine",
|
|
1000
981
|
"flowproof-trace",
|
|
@@ -1010,7 +991,7 @@ dependencies = [
|
|
|
1010
991
|
|
|
1011
992
|
[[package]]
|
|
1012
993
|
name = "flowproof-python"
|
|
1013
|
-
version = "0.23.
|
|
994
|
+
version = "0.23.30"
|
|
1014
995
|
dependencies = [
|
|
1015
996
|
"flowproof-agent",
|
|
1016
997
|
"flowproof-cli",
|
|
@@ -1022,7 +1003,7 @@ dependencies = [
|
|
|
1022
1003
|
|
|
1023
1004
|
[[package]]
|
|
1024
1005
|
name = "flowproof-replay"
|
|
1025
|
-
version = "0.23.
|
|
1006
|
+
version = "0.23.30"
|
|
1026
1007
|
dependencies = [
|
|
1027
1008
|
"chrono",
|
|
1028
1009
|
"flowproof-agent",
|
|
@@ -1036,7 +1017,7 @@ dependencies = [
|
|
|
1036
1017
|
|
|
1037
1018
|
[[package]]
|
|
1038
1019
|
name = "flowproof-trace"
|
|
1039
|
-
version = "0.23.
|
|
1020
|
+
version = "0.23.30"
|
|
1040
1021
|
dependencies = [
|
|
1041
1022
|
"jsonschema",
|
|
1042
1023
|
"regex",
|
|
@@ -2169,9 +2150,9 @@ dependencies = [
|
|
|
2169
2150
|
|
|
2170
2151
|
[[package]]
|
|
2171
2152
|
name = "quick-xml"
|
|
2172
|
-
version = "0.
|
|
2153
|
+
version = "0.42.0"
|
|
2173
2154
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2174
|
-
checksum = "
|
|
2155
|
+
checksum = "41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b"
|
|
2175
2156
|
dependencies = [
|
|
2176
2157
|
"encoding_rs",
|
|
2177
2158
|
"memchr",
|
|
@@ -2571,9 +2552,9 @@ dependencies = [
|
|
|
2571
2552
|
|
|
2572
2553
|
[[package]]
|
|
2573
2554
|
name = "rustls"
|
|
2574
|
-
version = "0.23.
|
|
2555
|
+
version = "0.23.46"
|
|
2575
2556
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2576
|
-
checksum = "
|
|
2557
|
+
checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf"
|
|
2577
2558
|
dependencies = [
|
|
2578
2559
|
"log",
|
|
2579
2560
|
"once_cell",
|
|
@@ -2634,9 +2615,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
|
|
2634
2615
|
|
|
2635
2616
|
[[package]]
|
|
2636
2617
|
name = "rustls-webpki"
|
|
2637
|
-
version = "0.103.
|
|
2618
|
+
version = "0.103.16"
|
|
2638
2619
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2639
|
-
checksum = "
|
|
2620
|
+
checksum = "4443b1b6d39d7c663139942cc4558262562d2c84123bb6282ef177009ca8b281"
|
|
2640
2621
|
dependencies = [
|
|
2641
2622
|
"ring",
|
|
2642
2623
|
"rustls-pki-types",
|
|
@@ -2761,16 +2742,16 @@ dependencies = [
|
|
|
2761
2742
|
]
|
|
2762
2743
|
|
|
2763
2744
|
[[package]]
|
|
2764
|
-
name = "
|
|
2765
|
-
version = "0.9.
|
|
2745
|
+
name = "serde_norway"
|
|
2746
|
+
version = "0.9.42"
|
|
2766
2747
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2767
|
-
checksum = "
|
|
2748
|
+
checksum = "e408f29489b5fd500fab51ff1484fc859bb655f32c671f307dcd733b72e8168c"
|
|
2768
2749
|
dependencies = [
|
|
2769
2750
|
"indexmap",
|
|
2770
2751
|
"itoa",
|
|
2771
2752
|
"ryu",
|
|
2772
2753
|
"serde",
|
|
2773
|
-
"unsafe-libyaml",
|
|
2754
|
+
"unsafe-libyaml-norway",
|
|
2774
2755
|
]
|
|
2775
2756
|
|
|
2776
2757
|
[[package]]
|
|
@@ -3142,6 +3123,12 @@ dependencies = [
|
|
|
3142
3123
|
"pom",
|
|
3143
3124
|
]
|
|
3144
3125
|
|
|
3126
|
+
[[package]]
|
|
3127
|
+
name = "typed-path"
|
|
3128
|
+
version = "0.13.0"
|
|
3129
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3130
|
+
checksum = "9ce898823d8cd0f028662d2f349694b1af0a5cc9be83f1d213a00d3147445e1e"
|
|
3131
|
+
|
|
3145
3132
|
[[package]]
|
|
3146
3133
|
name = "typeid"
|
|
3147
3134
|
version = "1.0.3"
|
|
@@ -3211,10 +3198,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
3211
3198
|
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
|
3212
3199
|
|
|
3213
3200
|
[[package]]
|
|
3214
|
-
name = "unsafe-libyaml"
|
|
3215
|
-
version = "0.2.
|
|
3201
|
+
name = "unsafe-libyaml-norway"
|
|
3202
|
+
version = "0.2.15"
|
|
3216
3203
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3217
|
-
checksum = "
|
|
3204
|
+
checksum = "b39abd59bf32521c7f2301b52d05a6a2c975b6003521cbd0c6dc1582f0a22104"
|
|
3218
3205
|
|
|
3219
3206
|
[[package]]
|
|
3220
3207
|
name = "untrusted"
|
|
@@ -3420,18 +3407,18 @@ dependencies = [
|
|
|
3420
3407
|
|
|
3421
3408
|
[[package]]
|
|
3422
3409
|
name = "webpki-root-certs"
|
|
3423
|
-
version = "1.0.
|
|
3410
|
+
version = "1.0.11"
|
|
3424
3411
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3425
|
-
checksum = "
|
|
3412
|
+
checksum = "e49d0e65abc00c142e8f9428da991da9f1a250c39be97459901eb12b9b49f62a"
|
|
3426
3413
|
dependencies = [
|
|
3427
3414
|
"rustls-pki-types",
|
|
3428
3415
|
]
|
|
3429
3416
|
|
|
3430
3417
|
[[package]]
|
|
3431
3418
|
name = "webpki-roots"
|
|
3432
|
-
version = "1.0.
|
|
3419
|
+
version = "1.0.11"
|
|
3433
3420
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3434
|
-
checksum = "
|
|
3421
|
+
checksum = "f5f280bbb2b287bc8e7de7e3852945a0ff50d1bbcb5ed42b6c7a568c546df171"
|
|
3435
3422
|
dependencies = [
|
|
3436
3423
|
"rustls-pki-types",
|
|
3437
3424
|
]
|
|
@@ -3890,15 +3877,18 @@ dependencies = [
|
|
|
3890
3877
|
|
|
3891
3878
|
[[package]]
|
|
3892
3879
|
name = "zip"
|
|
3893
|
-
version = "
|
|
3880
|
+
version = "9.1.3"
|
|
3894
3881
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3895
|
-
checksum = "
|
|
3882
|
+
checksum = "1156b39d142a34b999c2310a50455e0cb3760bf7efad0122f796d813bee26ccb"
|
|
3896
3883
|
dependencies = [
|
|
3897
|
-
"arbitrary",
|
|
3898
3884
|
"crc32fast",
|
|
3899
3885
|
"flate2",
|
|
3886
|
+
"getrandom 0.4.3",
|
|
3900
3887
|
"indexmap",
|
|
3901
3888
|
"memchr",
|
|
3889
|
+
"nix",
|
|
3890
|
+
"typed-path",
|
|
3891
|
+
"windows-sys 0.61.2",
|
|
3902
3892
|
"zopfli",
|
|
3903
3893
|
]
|
|
3904
3894
|
|
|
@@ -22,7 +22,7 @@ members = ["crates/flowproof-driver", "crates/flowproof-trace", "crates/flowproo
|
|
|
22
22
|
exclude = ["spike/windows-containment"]
|
|
23
23
|
|
|
24
24
|
[workspace.package]
|
|
25
|
-
version = "0.23.
|
|
25
|
+
version = "0.23.30"
|
|
26
26
|
edition = "2021"
|
|
27
27
|
license = "Apache-2.0"
|
|
28
28
|
repository = "https://github.com/automators-com/flowproof"
|
|
@@ -44,7 +44,13 @@ pdf-extract = "0.12"
|
|
|
44
44
|
serde = { version = "1", features = ["derive"] }
|
|
45
45
|
regex = "1"
|
|
46
46
|
serde_json = "1"
|
|
47
|
-
serde_yaml
|
|
47
|
+
# serde_yaml (dtolnay) is archived/unmaintained and pulls the unmaintained
|
|
48
|
+
# unsafe-libyaml (RUSTSEC-2024-0449). serde_norway is the RustSec-recommended
|
|
49
|
+
# maintained 0.9-compatible fork; it rides on the maintained
|
|
50
|
+
# unsafe-libyaml-norway. Aliased back to `serde_yaml` so the ~124 existing
|
|
51
|
+
# `serde_yaml::` call sites stay unchanged — the name is cosmetic, the crate
|
|
52
|
+
# is serde_norway. (A6)
|
|
53
|
+
serde_yaml = { package = "serde_norway", version = "0.9" }
|
|
48
54
|
thiserror = "2"
|
|
49
55
|
uuid = { version = "1", features = ["v4"] }
|
|
50
56
|
|
|
@@ -112,6 +112,12 @@ pub use web::shutdown_shared_browser;
|
|
|
112
112
|
#[cfg(feature = "web")]
|
|
113
113
|
pub use web::SharedBrowserGuard;
|
|
114
114
|
|
|
115
|
+
/// The words a missing-browser failure starts with. By the time it reaches a
|
|
116
|
+
/// caller it is only a message (the driver, the CLI and the desktop app all
|
|
117
|
+
/// carry it as a string), so these words are what tells it apart from any
|
|
118
|
+
/// other launch failure. Changing them breaks those callers.
|
|
119
|
+
pub const NO_BROWSER: &str = "no browser found";
|
|
120
|
+
|
|
115
121
|
#[derive(Debug, thiserror::Error)]
|
|
116
122
|
pub enum AdapterError {
|
|
117
123
|
#[error("adapter '{0}' is not implemented yet")]
|
|
@@ -120,6 +126,11 @@ pub enum AdapterError {
|
|
|
120
126
|
UnsupportedPlatform(&'static str),
|
|
121
127
|
#[error("web adapter: {0}")]
|
|
122
128
|
Web(String),
|
|
129
|
+
/// No Chromium browser to drive: not a launch that went wrong but one
|
|
130
|
+
/// that could not start, and installing a browser fixes it. Starts with
|
|
131
|
+
/// [`NO_BROWSER`]; the web adapter's tests hold the two together.
|
|
132
|
+
#[error("no browser found: {0}")]
|
|
133
|
+
NoBrowser(String),
|
|
123
134
|
}
|
|
124
135
|
|
|
125
136
|
/// Names of the adapters compiled into this build.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
//!
|
|
5
5
|
//! Selector mapping: `css` payload key, else `#<automation_id>`. `launch`
|
|
6
6
|
//! interprets `command` as the URL to open. The Chromium binary is found via
|
|
7
|
-
//! the `CHROME` env var or platform auto-detection.
|
|
7
|
+
//! the `CHROME` env var or platform auto-detection ([`find_browser`]).
|
|
8
8
|
|
|
9
9
|
use std::sync::{Arc, Mutex, OnceLock};
|
|
10
10
|
use std::time::{Duration, Instant};
|
|
@@ -897,19 +897,132 @@ fn present_headed_window(window: &impl HeadedTabWindow, headed: bool) -> Result<
|
|
|
897
897
|
Ok(())
|
|
898
898
|
}
|
|
899
899
|
|
|
900
|
+
/// What a person reads when no browser is found: which browsers work, and the
|
|
901
|
+
/// two ways to give flowproof one.
|
|
902
|
+
const NO_BROWSER_HELP: &str = "web flows run in Google Chrome, Microsoft Edge, Chromium or \
|
|
903
|
+
Brave, and none is installed where flowproof looks. Install one, or set CHROME to the \
|
|
904
|
+
path of one.";
|
|
905
|
+
|
|
906
|
+
/// The browser to launch. `CHROME` wins when set, and a `CHROME` naming a file
|
|
907
|
+
/// that is not there is an error rather than a quiet fall-back to whatever
|
|
908
|
+
/// else is installed: the person asked for that browser. Otherwise the places
|
|
909
|
+
/// headless_chrome looks, first and unchanged, so nobody's browser changes
|
|
910
|
+
/// under them; then the Chromium browsers it misses.
|
|
911
|
+
fn find_browser() -> Result<std::path::PathBuf, AdapterError> {
|
|
912
|
+
pick_browser(
|
|
913
|
+
std::env::var_os("CHROME"),
|
|
914
|
+
headless_chrome::browser::default_executable,
|
|
915
|
+
&extra_browser_candidates(std::env::consts::OS, std::env::var_os),
|
|
916
|
+
|path| path.is_file(),
|
|
917
|
+
)
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
/// [`find_browser`] with the environment, the default lookup and the
|
|
921
|
+
/// filesystem passed in, so every branch is testable on any host.
|
|
922
|
+
fn pick_browser(
|
|
923
|
+
chrome: Option<std::ffi::OsString>,
|
|
924
|
+
default: impl FnOnce() -> Result<std::path::PathBuf, String>,
|
|
925
|
+
extra: &[std::path::PathBuf],
|
|
926
|
+
exists: impl Fn(&std::path::Path) -> bool,
|
|
927
|
+
) -> Result<std::path::PathBuf, AdapterError> {
|
|
928
|
+
if let Some(chrome) = chrome.filter(|c| !c.is_empty()) {
|
|
929
|
+
let path = std::path::PathBuf::from(chrome);
|
|
930
|
+
if exists(&path) {
|
|
931
|
+
return Ok(path);
|
|
932
|
+
}
|
|
933
|
+
return Err(AdapterError::NoBrowser(format!(
|
|
934
|
+
"CHROME is set to {}, and there is no browser there. Point it at a Chrome, \
|
|
935
|
+
Edge, Chromium or Brave executable, or unset it to let flowproof look.",
|
|
936
|
+
path.display()
|
|
937
|
+
)));
|
|
938
|
+
}
|
|
939
|
+
if let Ok(path) = default() {
|
|
940
|
+
return Ok(path);
|
|
941
|
+
}
|
|
942
|
+
extra
|
|
943
|
+
.iter()
|
|
944
|
+
.find(|path| exists(path))
|
|
945
|
+
.cloned()
|
|
946
|
+
.ok_or_else(|| AdapterError::NoBrowser(NO_BROWSER_HELP.into()))
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/// Chromium browsers headless_chrome does not look for: per-user installs of
|
|
950
|
+
/// Chrome, Edge and Chromium (where they land without admin rights) and Brave.
|
|
951
|
+
/// Other Chromium browsers stay out until one is seen driving a flow.
|
|
952
|
+
fn extra_browser_candidates(
|
|
953
|
+
os: &str,
|
|
954
|
+
env: impl Fn(&'static str) -> Option<std::ffi::OsString>,
|
|
955
|
+
) -> Vec<std::path::PathBuf> {
|
|
956
|
+
let dir = |key: &'static str| {
|
|
957
|
+
env(key)
|
|
958
|
+
.filter(|v| !v.is_empty())
|
|
959
|
+
.map(std::path::PathBuf::from)
|
|
960
|
+
};
|
|
961
|
+
let mut candidates = Vec::new();
|
|
962
|
+
match os {
|
|
963
|
+
"macos" => {
|
|
964
|
+
// The app bundle and its executable share a name for all four.
|
|
965
|
+
let apps = [
|
|
966
|
+
"Google Chrome",
|
|
967
|
+
"Microsoft Edge",
|
|
968
|
+
"Chromium",
|
|
969
|
+
"Brave Browser",
|
|
970
|
+
];
|
|
971
|
+
let user_apps = dir("HOME").map(|home| home.join("Applications"));
|
|
972
|
+
for root in user_apps
|
|
973
|
+
.into_iter()
|
|
974
|
+
.chain([std::path::PathBuf::from("/Applications")])
|
|
975
|
+
{
|
|
976
|
+
for app in apps {
|
|
977
|
+
candidates.push(root.join(format!("{app}.app/Contents/MacOS/{app}")));
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
"windows" => {
|
|
982
|
+
let chrome = ["Google", "Chrome", "Application", "chrome.exe"];
|
|
983
|
+
let edge = ["Microsoft", "Edge", "Application", "msedge.exe"];
|
|
984
|
+
let brave = ["BraveSoftware", "Brave-Browser", "Application", "brave.exe"];
|
|
985
|
+
let installs: [(&str, &[[&str; 4]]); 3] = [
|
|
986
|
+
("LOCALAPPDATA", &[chrome, edge, brave]),
|
|
987
|
+
("ProgramFiles", &[chrome, edge, brave]),
|
|
988
|
+
("ProgramFiles(x86)", &[chrome, brave]),
|
|
989
|
+
];
|
|
990
|
+
for (key, browsers) in installs {
|
|
991
|
+
let Some(root) = dir(key) else { continue };
|
|
992
|
+
for parts in browsers {
|
|
993
|
+
candidates.push(
|
|
994
|
+
parts
|
|
995
|
+
.iter()
|
|
996
|
+
.fold(root.clone(), |path, part| path.join(part)),
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
_ => {
|
|
1002
|
+
if let Some(path) = env("PATH") {
|
|
1003
|
+
for bin in std::env::split_paths(&path) {
|
|
1004
|
+
for name in ["brave-browser", "brave"] {
|
|
1005
|
+
candidates.push(bin.join(name));
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
candidates
|
|
1012
|
+
}
|
|
1013
|
+
|
|
900
1014
|
/// Build the launch options, split out from [`launch_browser`] so the headless
|
|
901
1015
|
/// decision is testable without starting a browser.
|
|
902
1016
|
fn launch_options_for(
|
|
903
1017
|
os_args: &[std::ffi::OsString],
|
|
904
1018
|
headed: bool,
|
|
1019
|
+
path: std::path::PathBuf,
|
|
905
1020
|
) -> Result<LaunchOptions<'_>, AdapterError> {
|
|
906
1021
|
let mut options = LaunchOptions::default_builder();
|
|
907
1022
|
options.headless(!headed).sandbox(false);
|
|
908
1023
|
options.idle_browser_timeout(BROWSER_IDLE_TIMEOUT);
|
|
909
1024
|
options.args(os_args.iter().map(AsRef::as_ref).collect());
|
|
910
|
-
|
|
911
|
-
options.path(Some(path.into()));
|
|
912
|
-
}
|
|
1025
|
+
options.path(Some(path));
|
|
913
1026
|
options
|
|
914
1027
|
.build()
|
|
915
1028
|
.map_err(|e| AdapterError::Web(format!("building launch options: {e}")))
|
|
@@ -1052,7 +1165,7 @@ fn settled_scene(
|
|
|
1052
1165
|
fn launch_browser(extra_args: &[String]) -> Result<Browser, AdapterError> {
|
|
1053
1166
|
let headed = headed_requested();
|
|
1054
1167
|
let os_args: Vec<std::ffi::OsString> = extra_args.iter().map(Into::into).collect();
|
|
1055
|
-
let options = launch_options_for(&os_args, headed)?;
|
|
1168
|
+
let options = launch_options_for(&os_args, headed, find_browser()?)?;
|
|
1056
1169
|
Browser::new(options)
|
|
1057
1170
|
.map_err(|e| AdapterError::Web(launch_failure_message(&e.to_string(), headed)))
|
|
1058
1171
|
}
|
|
@@ -5978,14 +6091,108 @@ mod tests {
|
|
|
5978
6091
|
#[test]
|
|
5979
6092
|
fn headed_flips_the_headless_launch_option() {
|
|
5980
6093
|
let no_args: Vec<std::ffi::OsString> = Vec::new();
|
|
6094
|
+
let chrome = || std::path::PathBuf::from("/opt/chrome");
|
|
5981
6095
|
|
|
5982
|
-
let headless = super::launch_options_for(&no_args, false).expect("options build");
|
|
6096
|
+
let headless = super::launch_options_for(&no_args, false, chrome()).expect("options build");
|
|
5983
6097
|
assert!(headless.headless, "default must stay headless");
|
|
6098
|
+
assert_eq!(
|
|
6099
|
+
headless.path,
|
|
6100
|
+
Some(chrome()),
|
|
6101
|
+
"the found browser is the one launched"
|
|
6102
|
+
);
|
|
5984
6103
|
|
|
5985
|
-
let headed = super::launch_options_for(&no_args, true).expect("options build");
|
|
6104
|
+
let headed = super::launch_options_for(&no_args, true, chrome()).expect("options build");
|
|
5986
6105
|
assert!(!headed.headless, "FLOWPROOF_HEADED must show the window");
|
|
5987
6106
|
}
|
|
5988
6107
|
|
|
6108
|
+
/// The order the browser is chosen in, and what a person reads when there
|
|
6109
|
+
/// is none. The message must start with `NO_BROWSER`: the CLI and the
|
|
6110
|
+
/// desktop app recognise the failure by those words alone.
|
|
6111
|
+
#[test]
|
|
6112
|
+
fn a_browser_is_chosen_from_chrome_then_the_defaults_then_the_extras() {
|
|
6113
|
+
use std::path::{Path, PathBuf};
|
|
6114
|
+
let found = |p: &Path| p == Path::new("/set/chrome") || p == Path::new("/extra/brave");
|
|
6115
|
+
let default_finds = || -> Result<PathBuf, String> { Ok(PathBuf::from("/default/chrome")) };
|
|
6116
|
+
let default_misses = || -> Result<PathBuf, String> {
|
|
6117
|
+
Err("Could not auto detect a chrome executable".into())
|
|
6118
|
+
};
|
|
6119
|
+
let extras = [
|
|
6120
|
+
PathBuf::from("/extra/missing"),
|
|
6121
|
+
PathBuf::from("/extra/brave"),
|
|
6122
|
+
];
|
|
6123
|
+
|
|
6124
|
+
let chosen = super::pick_browser(Some("/set/chrome".into()), default_finds, &extras, found);
|
|
6125
|
+
assert_eq!(chosen.expect("CHROME"), PathBuf::from("/set/chrome"));
|
|
6126
|
+
|
|
6127
|
+
// An empty CHROME is unset, not a path.
|
|
6128
|
+
let chosen = super::pick_browser(Some("".into()), default_finds, &extras, found);
|
|
6129
|
+
assert_eq!(chosen.expect("default"), PathBuf::from("/default/chrome"));
|
|
6130
|
+
|
|
6131
|
+
// headless_chrome's own lookup still comes first, so nobody's browser
|
|
6132
|
+
// changes when a second one is installed.
|
|
6133
|
+
let chosen = super::pick_browser(None, default_finds, &extras, found);
|
|
6134
|
+
assert_eq!(chosen.expect("default"), PathBuf::from("/default/chrome"));
|
|
6135
|
+
|
|
6136
|
+
let chosen = super::pick_browser(None, default_misses, &extras, found);
|
|
6137
|
+
assert_eq!(chosen.expect("extra"), PathBuf::from("/extra/brave"));
|
|
6138
|
+
|
|
6139
|
+
let none = super::pick_browser(None, default_misses, &extras[..1], found)
|
|
6140
|
+
.expect_err("nothing installed")
|
|
6141
|
+
.to_string();
|
|
6142
|
+
assert!(none.starts_with(crate::NO_BROWSER), "{none}");
|
|
6143
|
+
assert!(none.contains("set CHROME"), "names the way out: {none}");
|
|
6144
|
+
|
|
6145
|
+
// A CHROME pointing nowhere is the person's choice gone wrong: say so
|
|
6146
|
+
// rather than quietly launching some other browser.
|
|
6147
|
+
let wrong = super::pick_browser(Some("/gone/chrome".into()), default_finds, &extras, found)
|
|
6148
|
+
.expect_err("CHROME names nothing")
|
|
6149
|
+
.to_string();
|
|
6150
|
+
assert!(wrong.starts_with(crate::NO_BROWSER), "{wrong}");
|
|
6151
|
+
assert!(
|
|
6152
|
+
wrong.contains("/gone/chrome"),
|
|
6153
|
+
"names the path it tried: {wrong}"
|
|
6154
|
+
);
|
|
6155
|
+
}
|
|
6156
|
+
|
|
6157
|
+
/// The per-user installs are the point: Chrome and Edge installed without
|
|
6158
|
+
/// admin rights land there, and headless_chrome does not look.
|
|
6159
|
+
#[test]
|
|
6160
|
+
fn extra_candidates_cover_per_user_installs_and_brave() {
|
|
6161
|
+
use std::ffi::OsString;
|
|
6162
|
+
let env = |key: &str| -> Option<OsString> {
|
|
6163
|
+
match key {
|
|
6164
|
+
"HOME" => Some("/Users/ana".into()),
|
|
6165
|
+
"LOCALAPPDATA" => Some("C:\\Users\\ana\\AppData\\Local".into()),
|
|
6166
|
+
"PATH" => Some("/usr/bin".into()),
|
|
6167
|
+
_ => None,
|
|
6168
|
+
}
|
|
6169
|
+
};
|
|
6170
|
+
let shown = |os: &str| -> Vec<String> {
|
|
6171
|
+
super::extra_browser_candidates(os, env)
|
|
6172
|
+
.iter()
|
|
6173
|
+
.map(|p| p.to_string_lossy().replace('\\', "/"))
|
|
6174
|
+
.collect()
|
|
6175
|
+
};
|
|
6176
|
+
|
|
6177
|
+
let mac = shown("macos");
|
|
6178
|
+
assert!(mac.contains(
|
|
6179
|
+
&"/Users/ana/Applications/Google Chrome.app/Contents/MacOS/Google Chrome".to_string()
|
|
6180
|
+
));
|
|
6181
|
+
assert!(mac
|
|
6182
|
+
.contains(&"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser".to_string()));
|
|
6183
|
+
|
|
6184
|
+
let windows = shown("windows");
|
|
6185
|
+
assert!(windows.contains(
|
|
6186
|
+
&"C:/Users/ana/AppData/Local/Google/Chrome/Application/chrome.exe".to_string()
|
|
6187
|
+
));
|
|
6188
|
+
assert!(
|
|
6189
|
+
windows.iter().all(|p| p.starts_with("C:/Users/ana")),
|
|
6190
|
+
"an unset ProgramFiles adds nothing: {windows:?}"
|
|
6191
|
+
);
|
|
6192
|
+
|
|
6193
|
+
assert_eq!(shown("linux"), ["/usr/bin/brave-browser", "/usr/bin/brave"]);
|
|
6194
|
+
}
|
|
6195
|
+
|
|
5989
6196
|
/// A visible shared browser leaks its keep-alive window into the user's
|
|
5990
6197
|
/// desktop after the flow tab closes. Headless suites retain reuse; either
|
|
5991
6198
|
/// explicit opt-out or headed mode must select one privately-owned process.
|
|
@@ -6259,7 +6466,8 @@ mod startup_tab_tests {
|
|
|
6259
6466
|
return;
|
|
6260
6467
|
}
|
|
6261
6468
|
let browser = super::Browser::new(
|
|
6262
|
-
super::launch_options_for(&[], true).expect("
|
|
6469
|
+
super::launch_options_for(&[], true, super::find_browser().expect("a browser"))
|
|
6470
|
+
.expect("valid launch options"),
|
|
6263
6471
|
)
|
|
6264
6472
|
.expect("browser starts");
|
|
6265
6473
|
let first = super::private_flow_tab(&browser).expect("flow tab opens");
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
//! original as `<name>.proposed.jsonl` and is only applied on explicit
|
|
7
7
|
//! request.
|
|
8
8
|
|
|
9
|
-
use std::path::{Path, PathBuf};
|
|
9
|
+
use std::path::{Component, Path, PathBuf};
|
|
10
10
|
|
|
11
11
|
use flowproof_driver::AppDriver;
|
|
12
12
|
use flowproof_trace::format::{Header, Step};
|
|
@@ -308,6 +308,19 @@ fn remap_selector_refs(value: &mut serde_json::Value, moved: &dyn Fn(usize) -> u
|
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
/// A recording-bundle path from a trace header is trusted only when it stays a
|
|
312
|
+
/// relative path inside the trace directory: every component must be `Normal`
|
|
313
|
+
/// (which rejects an absolute root, `.`, and `..`) and it must contain no `\`,
|
|
314
|
+
/// a path separator on Windows that would otherwise traverse there. Mirrors the
|
|
315
|
+
/// CLI's suite-selection guard (`relative_path`).
|
|
316
|
+
fn is_confined_rel(dir: &str) -> bool {
|
|
317
|
+
!dir.is_empty()
|
|
318
|
+
&& !dir.contains('\\')
|
|
319
|
+
&& Path::new(dir)
|
|
320
|
+
.components()
|
|
321
|
+
.all(|c| matches!(c, Component::Normal(_)))
|
|
322
|
+
}
|
|
323
|
+
|
|
311
324
|
/// The step time-range → frame files of one execution's recording bundle.
|
|
312
325
|
/// Derivable purely from the structured data plus the content-named files.
|
|
313
326
|
fn frames_for_range(
|
|
@@ -321,6 +334,15 @@ fn frames_for_range(
|
|
|
321
334
|
let Some(recording) = &header.recording else {
|
|
322
335
|
return Vec::new();
|
|
323
336
|
};
|
|
337
|
+
// `recording.dir` comes from the trace header, which may be attacker-
|
|
338
|
+
// authored (an imported trace). Confine it to a child of `trace_dir` before
|
|
339
|
+
// reading the bundle or embedding its files into the diff HTML: an absolute
|
|
340
|
+
// path, a `..`, or a `\` (a separator on Windows) would otherwise point the
|
|
341
|
+
// page at files outside the recording. A bad value yields no frames rather
|
|
342
|
+
// than reaching out of the tree.
|
|
343
|
+
if !is_confined_rel(&recording.dir) {
|
|
344
|
+
return Vec::new();
|
|
345
|
+
}
|
|
324
346
|
let dir = trace_dir.join(&recording.dir);
|
|
325
347
|
let Ok(entries) = std::fs::read_dir(&dir) else {
|
|
326
348
|
return Vec::new();
|
|
@@ -485,6 +507,24 @@ steps:
|
|
|
485
507
|
MockAppDriver::new(&CALC_ELEMENTS).with_text("CalculatorResults", "Display is 8")
|
|
486
508
|
}
|
|
487
509
|
|
|
510
|
+
#[test]
|
|
511
|
+
fn recording_dir_is_confined_to_the_trace_tree() {
|
|
512
|
+
// Legitimate bundle paths: relative, forward-slashed, no traversal.
|
|
513
|
+
assert!(is_confined_rel("recording"));
|
|
514
|
+
assert!(is_confined_rel("exec-0/recording"));
|
|
515
|
+
|
|
516
|
+
// A header must not point the diff page outside the trace directory.
|
|
517
|
+
assert!(!is_confined_rel(""), "empty");
|
|
518
|
+
assert!(!is_confined_rel("../recording"), "parent traversal");
|
|
519
|
+
assert!(!is_confined_rel("a/../../etc"), "nested traversal");
|
|
520
|
+
assert!(!is_confined_rel("/etc/ssh"), "absolute (unix)");
|
|
521
|
+
assert!(!is_confined_rel("..\\recording"), "backslash traversal");
|
|
522
|
+
assert!(
|
|
523
|
+
!is_confined_rel("C:\\Windows"),
|
|
524
|
+
"backslash catches a Windows absolute path on any host"
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
|
|
488
528
|
#[test]
|
|
489
529
|
fn healthy_trace_needs_no_healing() {
|
|
490
530
|
let dir = std::env::temp_dir().join("flowproof-heal-healthy");
|