Skip to content

[tizen] align BlazorWebView TizenMauiAssetFileProvider with other platforms - #37972

Merged
kubaflo merged 1 commit into
mainfrom
jonathanpeppers-fix-tizen-blazor-path-resolution
Aug 28, 2026
Merged

kubaflo merged 1 commit into
mainfrom
jonathanpeppers-fix-tizen-blazor-path-resolution

Conversation

@jonathanpeppers

Copy link
Copy Markdown
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description

Align BlazorWebView TizenMauiAssetFileProvider with other platforms.

…tforms

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: b3d0f96a-4910-4ad2-ab29-132558b736b9
Copilot AI lite review requested due to automatic review settings August 28, 2026 18:17
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 37972

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 37972"

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@kubaflo

This comment has been minimized.

@github-actions github-actions Bot added s/agent-review-in-progress AI review is currently running for this PR area-blazor Blazor Hybrid / Desktop, BlazorWebView and removed s/agent-review-in-progress AI review is currently running for this PR labels Aug 28, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns the Tizen TizenMauiAssetFileProvider implementation with the Android/iOS implementations in the BlazorWebView MAUI integration by using FileSystemUtils.Combine for safe path resolution.

Changes:

  • Switch Tizen asset path joining from Path.Combine to FileSystemUtils.Combine for both directory and file lookups.
  • Return NotFoundDirectoryContents.Singleton / NotFoundFileInfo when path resolution fails, matching other platforms.

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

@jonathanpeppers — new AI review results are available based on commit 0a6d12a.

Gate No Tests Confidence Low Platform Android


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ⚠️ SKIPPED

No tests were detected in this PR.

Recommendation: Add tests to verify the fix using the write-tests-agent.


📋 Pre-Flight — Context & Validation

PR #37972 Pre-Flight

Pull Request

  • Title: [tizen] align BlazorWebView TizenMauiAssetFileProvider with other platforms
  • Author: jonathanpeppers
  • Base: main (169aff2b46345d4cefcdc54902409460f9e8411e)
  • Head: jonathanpeppers-fix-tizen-blazor-path-resolution (0a6d12a73d18864dd690bbed6266d1e82ab74abb)
  • Materialized review commit: 42991180df79f360c24cbbd404ee42371c02c8c6
  • Scope: 1 file, +13/-2

The PR description only states that it aligns the Tizen TizenMauiAssetFileProvider with the other platform implementations. There is no linked issue and no human review feedback.

Problem and Existing Fix

TizenMauiAssetFileProvider used Path.Combine(_resDir, subpath) directly in both GetDirectoryContents and GetFileInfo. A rooted request path can cause Path.Combine to discard the trusted resource root, while .. segments can resolve outside it.

The PR replaces those calls with FileSystemUtils.Combine, which rejects rooted paths and parent-directory segments and verifies that an absolute result remains under the root. Invalid directory requests return NotFoundDirectoryContents.Singleton; invalid file requests return new NotFoundFileInfo(subpath). This matches the existing Android and iOS providers.

 using Microsoft.Extensions.FileProviders;
 using Microsoft.Extensions.Primitives;
+using Microsoft.Maui.Storage;
 using Tizen.Applications;

 public IDirectoryContents GetDirectoryContents(string subpath)
-	=> new TizenMauiAssetDirectoryContents(Path.Combine(_resDir, subpath));
+{
+	var resolvedPath = FileSystemUtils.Combine(_resDir, subpath);
+	if (resolvedPath is null)
+		return NotFoundDirectoryContents.Singleton;
+	return new TizenMauiAssetDirectoryContents(resolvedPath);
+}

 public IFileInfo GetFileInfo(string subpath)
-	=> new TizenMauiAssetFileInfo(Path.Combine(_resDir, subpath));
+{
+	var resolvedPath = FileSystemUtils.Combine(_resDir, subpath);
+	if (resolvedPath is null)
+		return new NotFoundFileInfo(subpath);
+	return new TizenMauiAssetFileInfo(resolvedPath);
+}

Alternative-Fix Boundaries

  • The only production file changed by the PR, and therefore the only candidate-edit target, is src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs.
  • Each candidate must replace the PR implementation with a genuinely different mechanism, not relocate the same FileSystemUtils.Combine check.
  • The baseline/restore workflow must use only .github/scripts/EstablishBrokenBaseline.ps1 and must preserve all pre-existing worktree changes and untracked files.
  • Candidate 2 must consume candidate 1's recorded result and avoid its mechanism.

Test Scope

The prior gate result is SKIPPED because the PR adds no tests; it must not be rerun. The regression cross-reference found no recent bug-fix overlap, and the UI-test detector found no UI categories.

For the requested Android platform, the narrowest supported behavioral proxy is the exact BlazorWebView device-test class. Its BlazorWebViewTests.ContentRootResolution.cs partial contains positive asset loading plus rooted-path, parent-segment, and encoded-separator regressions:

pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project BlazorWebView -Platform android -IncludeClasses "Microsoft.Maui.MauiBlazorWebView.DeviceTests.Elements.BlazorWebViewTests"

Android does not compile the Tizen provider, so this validates the shared BlazorWebView path-resolution contract rather than directly executing candidate Tizen code. A result cannot be reported as Pass unless the command actually executes and reports test success; missing Android prerequisites/device are Blocked.

Environment

gh is unauthenticated, so public GitHub API data and the locally materialized PR commit were used. The worktree contains numerous pre-existing changes outside the PR target; they are out of scope and must remain untouched.


🔬 Code Review — Deep Analysis

Code Review — PR #37972

Independent Assessment

What this changes: Tizen BlazorWebView asset lookups now resolve file and directory subpaths through FileSystemUtils.Combine instead of Path.Combine. Invalid rooted paths, parent traversal segments, and paths that resolve outside the Tizen resource root return the standard not-found provider objects instead of reaching filesystem lookup code.

Inferred motivation: The Tizen provider was the remaining platform implementation that did not use MAUI's shared, containment-checking path resolver.

Reconciliation with PR Narrative

Author claims: The change aligns TizenMauiAssetFileProvider with the other platform implementations.

Agreement/disagreement: The claim is accurate but terse. The submitted diff mirrors the existing Android and iOS resolution and not-found contracts; the concrete benefit is rejecting unsafe or invalid asset subpaths before filesystem access.

Prior Review Reconciliation

No prior ❌ Error findings found. The top-level Copilot review describes the same behavior and contains no actionable finding; the inline-review surface is empty, and the issue-comment surface contains only automation/status comments.

Blast Radius Assessment

  • Runs for all instances: The modified methods run for Tizen BlazorWebView asset requests, regardless of which asset is requested, but do not affect other controls or platforms.
  • Startup impact: The provider is constructed during Tizen BlazorWebView startup, but the changed resolution logic runs only when file or directory content is requested.
  • Static/shared state: None.
  • Null/default behavior: Empty subpaths continue to resolve to the resource root. Rooted or parent-traversing subpaths now return not-found results. A runtime null still fails in Path.Combine, as it did before, and the interface contract does not supply null.

CI Status

  • Required-check result: Undetermined; gh pr checks 37972 --required could not authenticate and returned no check rows.
  • Classification: Undetermined. The trusted Gate was explicitly skipped because the PR contains no tests.
  • Action taken: No gate rerun. Confidence is capped at low because relevant PR validation is absent.

Findings

No actionable code findings. The expert reviewer wrote an empty JSON array to inline-findings.json.

The lack of a focused Tizen regression test is a coverage gap, but the changed behavior delegates to the already-tested shared FileSystemUtils.Combine implementation and exactly follows the established Android/iOS provider pattern.

Failure-Mode Probing

  • Rooted or traversal subpath: IsValidRelativePath rejects it and the provider returns a not-found object; no filesystem constructor or stream open receives the rejected path.
  • Empty subpath: FileSystemUtils.Combine accepts it, canonicalizes the resource root, and the root-equality check succeeds.
  • Ordinary missing asset: The resolved in-root path reaches TizenMauiAssetFileInfo; Exists is false and Length remains -1, preserving prior behavior.
  • Handler disconnect/reconnect: The change adds no state, subscriptions, or lifecycle coupling; each lookup resolves independently.
  • Assets not using the new behavior: Valid relative asset paths resolve to the same location as before, except that absolute canonicalization is now applied under the rooted Tizen resource directory.

External Output Contract

Not applicable.

Verdict: NEEDS_DISCUSSION

Confidence: low

Summary: The submitted implementation is sound and the expert review found no actionable code defect. The review cannot produce an LGTM/approval recommendation under the code-review evidence rules because the trusted Gate was skipped and required-check state could not be retrieved, so validation coverage remains undetermined.


🛠️ Try-Fix — Analysis & Comparison

Try-Fix Aggregate — PR #37972 ([tizen] align BlazorWebView TizenMauiAssetFileProvider with other platforms)

Pre-Flight Test-Scope Context

  • PR: #37972 by jonathanpeppers; base main (169aff2b46), head jonathanpeppers-fix-tizen-blazor-path-resolution (0a6d12a73d), materialized review commit 42991180df. Scope: 1 file, +13/-2.
  • Problem: TizenMauiAssetFileProvider used Path.Combine(_resDir, subpath) in GetDirectoryContents and GetFileInfo. A rooted request path makes Path.Combine discard the trusted resource root, and .. segments can resolve outside it.
  • PR fix: replaces both calls with Microsoft.Maui.Storage.FileSystemUtils.Combine, mapping a null result to NotFoundDirectoryContents.Singleton (directories) and new NotFoundFileInfo(subpath) (files), matching the Android/iOS providers.
  • Only editable production target: src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs.
  • Gate: prior result SKIPPED — the PR adds no tests. Not rerun; gate/content.md untouched.
  • Regression cross-reference: no recent bug-fix overlap. UI-test detector: no UI categories.
  • Test scope (sole permitted command, Android behavioral proxy):
    pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project BlazorWebView -Platform android -IncludeClasses "Microsoft.Maui.MauiBlazorWebView.DeviceTests.Elements.BlazorWebViewTests"
    
    The class's BlazorWebViewTests.ContentRootResolution.cs partial covers positive asset loading plus rooted-path, parent-segment, and encoded-separator regressions. Android does not compile the Tizen provider, so this validates the shared BlazorWebView path-resolution contract rather than candidate Tizen code directly. A Pass requires the command to actually execute and report success; missing prerequisites/device are Blocked.
  • Environment: gh unauthenticated; worktree carries numerous pre-existing changes outside the PR target that must remain untouched.

Candidate Summary

Candidate Approach Result Findings Artifacts
1 Containment-by-construction path sanitization (designed; not implemented) Blocked 0 try-fix/attempt-1/, narrative try-fix-1/content.md
2 Filesystem capability walk (designed; not implemented) Blocked 0 try-fix/attempt-2/, narrative try-fix-2/content.md

Candidate 1 — Full Narrative

Try-Fix Candidate 1 — PR #37972 (TizenMauiAssetFileProvider path resolution)

Result: Blocked (no production edit made; test command not executed)

1. Candidate Approach (designed, not implemented)

Name: Containment-by-Construction Path Sanitization

TizenMauiAssetFileProvider.GetDirectoryContents / GetFileInfo would stop passing the untrusted
subpath to any combine primitive. Instead a private helper ResolveWithinRoot(string root, string subpath)
would:

  1. Return the trimmed root immediately for null/empty subpath.
  2. Split subpath on both '/' and '\\' with RemoveEmptyEntries (this alone neutralizes a
    leading separator, i.e. the "rooted request" case).
  3. Skip . segments.
  4. On a .. segment, pop the accumulated segment list, clamping at zero — never allowing the
    walk to rise above the root.
  5. Re-anchor the surviving segments onto root.TrimEnd(separators) by explicit string
    concatenation with Path.DirectorySeparatorChar.

Both public members then construct TizenMauiAssetFileInfo / TizenMauiAssetDirectoryContents
unconditionally from the resolved path. No NotFoundFileInfo / NotFoundDirectoryContents.Singleton
branch is needed: a clamped path such as <root>/etc/passwd simply does not exist on disk, so the
existing FileInfo.Exists == false logic already yields correct not-found semantics, and
TizenMauiAssetDirectoryContents.Exists is hard-coded false regardless.

2. Mechanism-Level Difference from the PR Fix

PR mechanism (validate-and-reject + null sentinel): the PR keeps Path.Combine and wraps it in
Microsoft.Maui.Storage.FileSystemUtils.Combine, which (a) runs an IsValidRelativePath predicate
rejecting rooted paths and .. segments, (b) for absolute roots re-canonicalizes with
Path.GetFullPath and performs a StartsWith prefix comparison against the normalized root, and
(c) reports failure by returning null, which each of the two call sites must translate into
NotFoundDirectoryContents.Singleton or new NotFoundFileInfo(subpath).

Candidate mechanism (containment by construction): the escape conditions are made
unrepresentable rather than detected. Because the untrusted string is decomposed into segments
and re-anchored onto the trusted root by concatenation, Path.Combine's "rooted right-hand side
discards the left-hand side" rule is never reachable at all, and no .. token ever survives into the
resolved string, so there is nothing for a canonicalization check to catch. The full cause-to-effect
chain: leading separators vanish at the split step → root discard is impossible; .. is consumed by
a clamped pop at the accumulation step → parent escape is impossible; the final string is built as
root + sep + safe-segments → containment holds by construction. Consequences: no null sentinel,
no per-call-site rejection branch, no dependency on Microsoft.Maui.Storage, and no reliance on a
case-sensitivity-heuristic prefix comparison. It is a different root-cause hypothesis (the provider
should canonicalize requests into its own namespace, as static-file web servers do) rather than a
relocation of the same guard.

3. Blocker (why nothing was implemented or tested)

Step 2 of the try-fix workflow (Establish Baseline) is mandatory and must be performed only with
.github/scripts/EstablishBrokenBaseline.ps1. That script aborted:

╔═══════════════════════════════════════════════════════════════════╗
║  ERROR: DIRTY WORKING DIRECTORY - Cannot establish baseline       ║
╚═══════════════════════════════════════════════════════════════════╝
... ~56 modified files under .github/scripts/, .github/skills/, eng/scripts/ ...
EstablishBrokenBaseline.ps1 failed: Working directory is not clean.

The listed modifications are pre-existing worktree state that this task requires be preserved.
The script's own remedies (git add . && git commit, or git checkout -- .) are both prohibited —
by the invocation ("Preserve every pre-existing worktree modification/untracked path"; "never use
git checkout/restore/reset/stash/clean") and by the skill's script-only-restoration principle. The
script exposes no -AllowDirty/scoped mode (parameters are only -BaseBranch, -DryRun,
-Restore).

Therefore .github/.baseline-state.json was never created. The skill's baseline-file boundary
rule and the invocation's hard bounds both mandate: state file absent → report Blocked before
editing
. Consequently:

  • No edit was made to src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs.
  • There is no RevertedFiles allow-list, so the target was not (and could not be) confirmed inside
    the editable set.
  • The target file at HEAD (42991180df, "PR #37972 squashed for review") still contains the PR's
    FileSystemUtils.Combine implementation — i.e. the broken pre-fix baseline was never in place.

4. Captured Diff

fix.diff (scoped to the only editable production file) is empty — zero bytes. No production
change exists:

(no changes — `git diff -- src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs` produced no output)

5. Test Command, Result, Output Summary

Command (the sole permitted one):

pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project BlazorWebView -Platform android -IncludeClasses "Microsoft.Maui.MauiBlazorWebView.DeviceTests.Elements.BlazorWebViewTests"

Result: NOT EXECUTED. With no baseline and no candidate edit, the working tree is byte-identical
to HEAD, so the run would have exercised the PR's own FileSystemUtils.Combine fix and produced no
candidate signal. Android is in any case only a behavioral proxy — it does not compile the Tizen
provider.

Output summary: none; test-output.log records the non-execution and its reason instead of
fabricated results. Environment evidence recorded for honesty: adb is present at
/usr/local/lib/android/sdk/platform-tools/adb and adb devices reports emulator-5554 device,
so the emulator prerequisite was available — the blocker is baseline establishment alone, not device
availability. Per the skill's Pass/Fail table, this is recorded as Blocked, never Pass.

The prior gate (SKIPPED — no PR tests detected) was not rerun and
CustomAgentLogsTmp/PRState/37972/PRAgent/gate/content.md was not created or modified.

6. Failure / Blocker Analysis

The failure is procedural/environmental, not a defect in the candidate mechanism. The try-fix
contract assumes a worktree whose only modifications are the PR's fix files, so the baseline script
can revert exactly those and record them in RevertedFiles. This worktree carries ~56 unrelated
agent-infrastructure modifications, which trips the script's cleanliness precondition. Any further
candidate in this same worktree will hit the identical abort. Unblocking requires either the harness
committing/stashing those unrelated modifications before invoking the skill, or a scoped baseline
mode that ignores modifications outside the PR's changed-file set.

Only one pass was performed. No correction/retest pass was warranted because the blocker is not a
candidate defect and no second attempt could change the baseline script's precondition.

7. Expert Self-Review

Performed inline against .github/agents/maui-expert-reviewer.md (Overarching Principles plus the
always-active Logic and Correctness, Regression Prevention, and Complexity Reduction dimensions).
No file-routed dimensions apply because the diff is empty.

Self-review findings count: 0 (reviewer-findings.json = []). Vacuously clean — there is no
production diff to review.

8. Artifacts

Attempt directory: CustomAgentLogsTmp/PRState/37972/PRAgent/try-fix/attempt-1/

File Contents
baseline.log Full dirty-worktree abort output from EstablishBrokenBaseline.ps1
approach.md Candidate design + mechanism-level difference (marked NOT IMPLEMENTED)
reviewer-findings.json [] — 0 findings
reviewer-findings.diff Empty (0 bytes) — reviewed diff snapshot
fix.diff Empty (0 bytes) — no production change
result.txt Blocked
test-output.log Non-execution record with reason and environment evidence
analysis.md Blocker analysis and insights

9. Restore Confirmation

Restore was performed with the sole permitted command:

pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restore
→  No baseline state found. Nothing to restore.
   Restored  False
   Message   No baseline state found

Restored False / No baseline state found is the expected and accepted outcome for the verified
no-state path: Step 2 never created .github/.baseline-state.json and no attempt edits were made.
Verified afterwards: git diff -- src/BlazorWebView/src/Maui/Tizen/TizenMauiAssetFileProvider.cs is
empty (target identical to HEAD), and every pre-existing modified/untracked path remains untouched.
No git checkout/restore/reset/stash/clean was used at any point, and no files were deleted.
No candidate production changes remain applied.


Candidate 2 — Full Narrative

Try-Fix Candidate 2 — PR #37972 (TizenMauiAssetFileProvider path resolution)

Result: Blocked (no production edit made; test command not executed)

1. Candidate Approach (designed, not implemented)

Name: Filesystem Capability Walk

Instead of interpreting the request as a path string, start from a trusted DirectoryInfo for
_resDir and resolve each requested name by enumerating the current directory and selecting an
exact child entry. A leading/rooted separator, ., .., embedded separator, or missing child fails
lookup because it is not an enumerated child name. A file or directory is returned only after every
lookup has remained within the object-capability tree rooted at _resDir.

2. Explicit Difference from the PR and Candidate 1

The PR uses validate-and-reject string resolution: FileSystemUtils.Combine examines untrusted
path text, canonicalizes/combines it, rejects invalid input with null, and each caller maps that
sentinel to a not-found object.

Candidate 1 proposed containment-by-construction sanitization: split on separators, drop leading
and . segments, clamp .. at the root, then explicitly concatenate the surviving segments onto
the trusted root.

Candidate 2 uses neither mechanism. Its different root-cause hypothesis is that escape is
possible because caller-controlled text is granted authority to name an operating-system path.
The capability walk removes that authority: only children enumerated from the current trusted
DirectoryInfo can become the next object. No untrusted string is passed to a path combine or
canonicalization primitive, and no sanitized segments are concatenated to the root. Therefore a
rooted string cannot replace the root and .. cannot select a parent. This is filesystem-object
lookup, not PR-style validation/rejection and not candidate-1-style normalization/re-anchoring.

3. Mandatory Baseline Result and Blocker

Candidate 2 independently ran the required command:

pwsh .github/scripts/EstablishBrokenBaseline.ps1

It failed because the script rejected numerous pre-existing unrelated modifications under
.github/scripts, .github/skills, and eng/scripts:

ERROR: DIRTY WORKING DIRECTORY - Cannot establish baseline
EstablishBrokenBaseline.ps1 failed: Working directory is not clean.
Clean up before establishing baseline.

baseline.log contains zero Baseline established matches and
.github/.baseline-state.json was absent. Thus NewFiles and RevertedFiles could not be
validated, and the sole target was not in a restoration allow-list. The hard boundary required a
Blocked result before production edits. The pre-existing modifications and untracked paths were
preserved; the baseline script was not changed.

4. Full Captured Diff

fix.diff is zero bytes:

(no candidate production changes)

5. Exact Test Command, Result, and Output Summary

The sole permitted test command was:

pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project BlazorWebView -Platform android -IncludeClasses "Microsoft.Maui.MauiBlazorWebView.DeviceTests.Elements.BlazorWebViewTests"

Result: NOT EXECUTED; overall result Blocked. With no baseline and no permitted candidate edit,
running it would measure unchanged PR HEAD, which the task explicitly prohibited. Android is only a
behavioral proxy and does not compile the Tizen provider. test-output.log records this
non-execution and reason; no Pass was claimed. The prior SKIPPED gate was not rerun and
gate/content.md was not created or overwritten.

6. Failure / Blocker Analysis

The blocker is baseline establishment, not evidence that the candidate mechanism passes or fails.
The script's cleanliness precondition conflicts with the required preservation of unrelated
worktree changes. Its suggested cleanup operations are prohibited. One bounded implementation/test
pass stopped at this guard; there was no concrete candidate defect to justify a correction/retest.

7. Inline Expert Self-Review

Self-review was performed inline against all eight Overarching Principles and the always-active
Logic and Correctness, Regression Prevention, and Complexity Reduction checks in
.github/agents/maui-expert-reviewer.md. With no production diff, no file-routed dimension applied.

Findings count: 0 (reviewer-findings.json is []). The final diff matched the Step 6 snapshot,
so Step 7.5 confirmed the review remained current.

8. Artifacts

Attempt directory:
CustomAgentLogsTmp/PRState/37972/PRAgent/try-fix/attempt-2/

The mandatory artifact gate passed for baseline.log, approach.md, result.txt, fix.diff,
analysis.md, test-output.log, reviewer-findings.json, and reviewer-findings.diff.

9. Exact Script-Only Restore Confirmation

After artifact capture, restoration ran with exactly:

pwsh .github/scripts/EstablishBrokenBaseline.ps1 -Restore

Output:

No baseline state found. Nothing to restore.
Message   No baseline state found
Restored  False

This is the accepted verified no-state path: baseline creation failed and no candidate edit was
made. Post-restore verification found a zero-byte target diff and no baseline-state file. No
git checkout, git restore, git reset, git stash, or git clean was used, nothing unrelated
was deleted, and no candidate production changes remain applied.


📝 PR Finalize — Recommended Title & Description

Assessment: ✏️ Recommend updating — the current metadata identifies the platform and type but does not explain the path-resolution risk, the shared helper used, or the invalid-path behavior.

Recommended title

[Tizen] BlazorWebView: Resolve asset paths with FileSystemUtils.Combine

Recommended description

### Description of Change

Align the Tizen BlazorWebView `TizenMauiAssetFileProvider` with the Android and iOS implementations by resolving file and directory subpaths through `FileSystemUtils.Combine`.

### Root Cause

The Tizen provider passed requested subpaths directly to `Path.Combine`. A rooted subpath could discard the trusted Tizen resource directory, while parent-directory segments could resolve outside it.

### Fix

Use the shared `FileSystemUtils.Combine` path validation and containment logic in `GetDirectoryContents` and `GetFileInfo`. Invalid paths now return `NotFoundDirectoryContents.Singleton` or `NotFoundFileInfo`; valid paths continue to resolve beneath the application resource directory.

🏁 Report — Final Recommendation

⚠️ Final Recommendation: REQUEST CHANGES

Winner

pr — the raw submitted fix

The submitted implementation is the strongest and only implemented functional solution. It reuses the shared, tested FileSystemUtils.Combine contract, matches the established Android/iOS providers, rejects invalid paths rather than reinterpreting them, and received no actionable expert finding. The recommendation cannot be APPROVE because the trusted Gate was SKIPPED — no tests detected in this PR, required-check state is unavailable, and no candidate produced regression-test evidence.

Comparative Ranking

Rank Candidate Implementation Regression validation Expert/result evidence Assessment
1 pr Complete submitted diff Gate skipped; no PR tests Single expert pass found no actionable findings Best: simple reuse of shared path validation and established provider contracts
2 pr-plus-reviewer Code-equivalent to pr; reviewer.patch is empty Not run because there was no reviewer change to validate Same expert result as pr Safe but offers no improvement, so it cannot displace the raw PR
3 try-fix-1 Design only; empty candidate diff Blocked before execution Empty-diff self-review only Unproven, more bespoke, and semantically weaker because invalid rooted/traversal requests would be normalized or clamped into potentially valid in-root assets instead of rejected
4 try-fix-2 Design only; empty candidate diff Blocked before execution Empty-diff self-review only Unproven and substantially more complex; directory enumeration adds I/O and unresolved symlink/capability semantics without improving the shared-helper solution

No candidate reported a regression-test failure, so the rule placing failed candidates below passing candidates does not distinguish this field. More importantly, no candidate passed regression tests: pr and pr-plus-reviewer have skipped/not-run coverage, while both try-fix-* candidates were blocked and never implemented.

Candidate Analysis

pr

GetDirectoryContents and GetFileInfo resolve subpath through FileSystemUtils.Combine(_resDir, subpath). That helper rejects rooted inputs and .. segments, canonicalizes absolute-root results, verifies root containment, and returns null on rejection. The provider translates rejection to NotFoundDirectoryContents.Singleton or NotFoundFileInfo, exactly as the Android and iOS implementations do.

This solution centralizes security-sensitive path handling instead of introducing another Tizen-only resolver. Valid relative paths preserve their destination; missing valid assets preserve normal IFileInfo.Exists == false behavior; invalid paths no longer reach filesystem lookup or stream creation.

pr-plus-reviewer

The required sandbox resolved to the exact expected root and immutable baseline. The expert reviewer supplied no actionable feedback, so no consolidated patch was appropriate. reviewer.patch is zero bytes and the functional source remains identical to pr. The candidate therefore ties the PR on correctness but ranks below it because selecting an unchanged derivative would falsely imply that the submitted PR needs a code modification.

try-fix-1

The proposed segment sanitizer was never implemented or tested. Its clamping/normalization behavior is also not equivalent to secure rejection: a rooted /images/logo.png could become the valid in-root images/logo.png, and excessive parent traversal could be clamped back to the root and resolve an existing asset. That turns malformed or adversarial requests into different valid requests. It duplicates shared path logic and would diverge from other platforms.

try-fix-2

The proposed filesystem capability walk was never implemented or tested. Enumerating every path segment is more expensive and complex than lexical validation, changes missing-path and case behavior, and does not establish that directory links cannot lead outside the resource tree. It offers no demonstrated correctness advantage over the existing shared helper.

Required Change

Add focused regression coverage for the submitted Tizen behavior, or provide equivalent trusted validation that directly exercises/compiles the Tizen provider's handling of valid, rooted, and parent-traversing subpaths. The Android device-test command identified in pre-flight is only a shared behavioral proxy and does not compile Tizen code, so even a successful proxy run would not fully close the platform-specific coverage gap.

Final Rationale

The raw PR is the single winning candidate on implementation quality. The request-changes recommendation is evidence-driven rather than a request to replace its algorithm: the code review is clean, but the explicit skipped Gate does not permit approval under the required decision contract.


🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@MauiBot MauiBot added s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) labels Aug 28, 2026
This was referenced Sep 25, 2026
@github-actions github-actions Bot locked and limited conversation to collaborators Sep 28, 2026

This branch was previously deployed

1 inactive deployment
copilot-pat-pool — 0a6d12a7 Deployed Aug 28, 2026 by jonathanpeppers via conclusion #1621
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-blazor Blazor Hybrid / Desktop, BlazorWebView s/agent-changes-requested AI agent recommends changes - found a better alternative or issues s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants