Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions .github/workflows/build-manifest-index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,11 @@ jobs:
# in a YAML workflow file. Emitting pairs and grouping in jq avoids
# the question entirely.
#
# Packages with neither a product code nor a package family name are
# excluded: they cannot be identified this way, so they are dead
# weight in a file every endpoint downloads.
# Every package gets an entry, including those with neither a product
# code nor a package family name. Those cannot be matched by code,
# but the entry still carries the canonical display name, and that is
# what bridges an ID to its ARP entry: "Valve.Steam" never matches
# "Steam" on its own. A name-only row costs about 80 bytes.
sqlite3 "$DB" -json "
SELECT p.id AS Id, p.name AS Name, p.latest_version AS Version,
'P' AS Kind, c.productcode AS Value
Expand All @@ -64,6 +66,12 @@ jobs:
SELECT p.id, p.name, p.latest_version,
'F', f.pfn
FROM packages p JOIN pfns2 f ON f.package = p.rowid
UNION ALL
SELECT p.id, p.name, p.latest_version,
'N', NULL
FROM packages p
WHERE NOT EXISTS (SELECT 1 FROM productcodes2 WHERE package = p.rowid)
AND NOT EXISTS (SELECT 1 FROM pfns2 WHERE package = p.rowid)
ORDER BY 1;" > pairs.json

NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
Expand Down
7 changes: 7 additions & 0 deletions Private/Resolve-GitHubManifest.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ function Get-ManifestVersionKey {
# discarding the failures silently dropped real releases, and threw outright
# for packages where no folder happened to parse. Build a zero-padded key so
# ordinary string sorting gives correct numeric ordering instead.
# A winget version folder starts with a digit. Siblings like "x86",
# "arm64", "Canary", "PTB" and "Development" are architectures or release
# channels, not versions, and must not be ranked as such: "x86" yields 86,
# which outranks the first component of 1.0.9258 and wins the sort. Discord
# carries all five of those alongside 144 real versions.
if ($Name -notmatch '^v?\d') { return $null }

$Numbers = [regex]::Matches($Name, '\d+') | ForEach-Object { $_.Value }
if (-not $Numbers) { return $null }

Expand Down
38 changes: 32 additions & 6 deletions Public/Test-TecharyApp.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -143,18 +143,39 @@ function Test-TecharyApp {

# --- 2. EXACT DISPLAY NAME ----------------------------------------
# A custom catalogue entry carries the real ARP DisplayName for its ID.
$Candidates = New-Object System.Collections.Generic.List[string]
$Candidates.Add($Name)
# Two lists, because a name safe to compare exactly is not safe to compare
# as a substring.
#
# The detection index carries each package's canonical display name, which
# is what bridges an ID to its ARP entry: "Google.Chrome" never matches
# "Google Chrome" on its own, and product codes alone do not cover it
# because Chrome's installed code varies by build.
#
# Those names are short and generic, so they are used for exact comparison
# ONLY. Feeding them to the substring tier reports anything that merely
# contains them: "Steam" matches the MSIX package "MSTeams", and "Git"
# matches "GitHub CLI". Both were observed.
$ExactCandidates = New-Object System.Collections.Generic.List[string]
$LooseCandidates = New-Object System.Collections.Generic.List[string]

$ExactCandidates.Add($Name)
$LooseCandidates.Add($Name)

try {
$CustomApp = Get-CustomApp -Id $Name -NoRefresh
if ($CustomApp -and $CustomApp.DisplayName) { $Candidates.Add($CustomApp.DisplayName) }
if ($CustomApp -and $CustomApp.DisplayName) {
$ExactCandidates.Add($CustomApp.DisplayName)
$LooseCandidates.Add($CustomApp.DisplayName)
}
} catch {}

if ($Entry -and $Entry.Name) { $ExactCandidates.Add($Entry.Name) }

$AllArp = foreach ($Hive in $Hives) {
Get-ItemProperty -Path (Join-Path $Hive '*') -ErrorAction SilentlyContinue
}

foreach ($Candidate in $Candidates) {
foreach ($Candidate in $ExactCandidates) {
$Exact = $AllArp | Where-Object { $_.DisplayName -eq $Candidate } | Select-Object -First 1
if ($Exact) {
Write-Verbose "Matched exactly on DisplayName '$Candidate'"
Expand All @@ -164,7 +185,9 @@ function Test-TecharyApp {
}

# --- 3. SUBSTRING (imprecise, kept for compatibility) -------------
foreach ($Candidate in $Candidates) {
# Loose list only. A canonical name from the index is too generic to
# widen with wildcards.
foreach ($Candidate in $LooseCandidates) {
# Escaped: an unescaped name containing [ or ] is a wildcard pattern,
# which previously made the comparison silently match nothing.
$Pattern = "*" + [System.Management.Automation.WildcardPattern]::Escape($Candidate) + "*"
Expand All @@ -186,7 +209,10 @@ function Test-TecharyApp {
[Security.Principal.WindowsBuiltInRole]::Administrator)
} catch {}

foreach ($Candidate in $Candidates) {
# Loose list only, for the same reason: "Steam" as a wildcard matches the
# MSIX package MSTeams, which was reported as Valve.Steam being installed
# on a machine that has never had it.
foreach ($Candidate in $LooseCandidates) {
$Pattern = "*" + [System.Management.Automation.WildcardPattern]::Escape($Candidate) + "*"
$Msix = $null
try {
Expand Down