[tizen] align BlazorWebView TizenMauiAssetFileProvider with other platforms - #37972
Conversation
…tforms Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b3d0f96a-4910-4ad2-ab29-132558b736b9
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 37972Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 37972" |
|
Azure Pipelines: Successfully started running 1 pipeline(s). There may be pipelines that require an authorized user to comment /azp run to run. |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
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.CombinetoFileSystemUtils.Combinefor both directory and file lookups. - Return
NotFoundDirectoryContents.Singleton/NotFoundFileInfowhen path resolution fails, matching other platforms.
MauiBot
left a comment
There was a problem hiding this comment.
AI Review Summary
@jonathanpeppers — new AI review results are available based on commit
0a6d12a.
🗂️ 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.Combinecheck. - The baseline/restore workflow must use only
.github/scripts/EstablishBrokenBaseline.ps1and 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
nullstill fails inPath.Combine, as it did before, and the interface contract does not supply null.
CI Status
- Required-check result: Undetermined;
gh pr checks 37972 --requiredcould 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:
IsValidRelativePathrejects it and the provider returns a not-found object; no filesystem constructor or stream open receives the rejected path. - Empty subpath:
FileSystemUtils.Combineaccepts it, canonicalizes the resource root, and the root-equality check succeeds. - Ordinary missing asset: The resolved in-root path reaches
TizenMauiAssetFileInfo;Existsis false andLengthremains-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; basemain(169aff2b46), headjonathanpeppers-fix-tizen-blazor-path-resolution(0a6d12a73d), materialized review commit42991180df. Scope: 1 file, +13/-2. - Problem:
TizenMauiAssetFileProviderusedPath.Combine(_resDir, subpath)inGetDirectoryContentsandGetFileInfo. A rooted request path makesPath.Combinediscard the trusted resource root, and..segments can resolve outside it. - PR fix: replaces both calls with
Microsoft.Maui.Storage.FileSystemUtils.Combine, mapping anullresult toNotFoundDirectoryContents.Singleton(directories) andnew 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.mduntouched. - Regression cross-reference: no recent bug-fix overlap. UI-test detector: no UI categories.
- Test scope (sole permitted command, Android behavioral proxy):
The class's
pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project BlazorWebView -Platform android -IncludeClasses "Microsoft.Maui.MauiBlazorWebView.DeviceTests.Elements.BlazorWebViewTests"BlazorWebViewTests.ContentRootResolution.cspartial 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. APassrequires the command to actually execute and report success; missing prerequisites/device areBlocked. - Environment:
ghunauthenticated; 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:
- Return the trimmed root immediately for null/empty
subpath. - Split
subpathon both'/'and'\\'withRemoveEmptyEntries(this alone neutralizes a
leading separator, i.e. the "rooted request" case). - Skip
.segments. - On a
..segment, pop the accumulated segment list, clamping at zero — never allowing the
walk to rise above the root. - Re-anchor the surviving segments onto
root.TrimEnd(separators)by explicit string
concatenation withPath.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
RevertedFilesallow-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.Combineimplementation — 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.ps1It 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 -RestoreOutput:
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.
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
TizenMauiAssetFileProviderwith other platforms.