feat: new-release detector tools + missing 25H2 V2 China catalog entries #36

Merged
starkSV merged 2 commits from feat/check-new-releases-script into main 2026-07-14 11:29:25 +05:30
starkSV commented 2026-07-14 11:24:04 +05:30 (Migrated from github.com)

Summary

  • Adds scripts/check-new-releases/ with two complementary tools for finding Windows product edition IDs that exist on Microsoft's side but aren't yet in the catalog: Method 1 (msdls_v3.py, moved from repo root, range-scan) and Method 2 (main.go, auto-discovery via page-scrape). Both documented in that directory's README.
  • Fixes msdls_v3.py's release-name extraction (checked non-existent EditionName/ReleaseName/FriendlyName fields; real field is ProductDisplayName) and adds the missing vlscppe session-permit call.
  • Both tools' live runs surfaced a real catalog gap: product IDs 3322/3323/3325/3326 (Home/Pro China variants of the 25H2 "V2" refresh) exist on Microsoft's side but weren't in our catalog. Added across cli/catalog.go, frontend/public/data/products.json, backend/main.go's validContributeProducts, README.md, and frontend/public/sitemap.xml. Also renamed 3321/3324 from our own guessed "(Updated Oct)" label to Microsoft's real "(V2)" name.

Test plan

  • go build ./... and go test ./... pass for cli/ (21 catalog entries, up from 17)
  • go build passes for backend/
  • products.json validated as valid JSON
  • Both check-new-releases tools re-verified working from their new location against live Microsoft endpoints
  • After merge: cut a new CLI release (catalog change needs to ship to CLI users)
  • After merge: redeploy backend (Coolify) so /contribute accepts the new product IDs
  • After merge: redeploy frontend (Cloudflare Pages) so the new products/sitemap entries go live

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • Added Windows 11 25H2 V2 editions, including Home and Pro China variants for x64 and ARM64.
    • Added product pages and catalog entries for the new editions.
    • Updated related-product links to connect the new V2 variants.
  • Updates

    • Renamed existing Windows 11 25H2 “Updated Oct” listings to “V2.”
    • Expanded release discovery and verification guidance for maintaining current product information.
## Summary - Adds `scripts/check-new-releases/` with two complementary tools for finding Windows product edition IDs that exist on Microsoft's side but aren't yet in the catalog: Method 1 (`msdls_v3.py`, moved from repo root, range-scan) and Method 2 (`main.go`, auto-discovery via page-scrape). Both documented in that directory's README. - Fixes `msdls_v3.py`'s release-name extraction (checked non-existent `EditionName`/`ReleaseName`/`FriendlyName` fields; real field is `ProductDisplayName`) and adds the missing `vlscppe` session-permit call. - Both tools' live runs surfaced a real catalog gap: product IDs `3322`/`3323`/`3325`/`3326` (Home/Pro China variants of the 25H2 "V2" refresh) exist on Microsoft's side but weren't in our catalog. Added across `cli/catalog.go`, `frontend/public/data/products.json`, `backend/main.go`'s `validContributeProducts`, `README.md`, and `frontend/public/sitemap.xml`. Also renamed 3321/3324 from our own guessed "(Updated Oct)" label to Microsoft's real "(V2)" name. ## Test plan - [x] `go build ./...` and `go test ./...` pass for `cli/` (21 catalog entries, up from 17) - [x] `go build` passes for `backend/` - [x] `products.json` validated as valid JSON - [x] Both check-new-releases tools re-verified working from their new location against live Microsoft endpoints - [ ] After merge: cut a new CLI release (catalog change needs to ship to CLI users) - [ ] After merge: redeploy backend (Coolify) so `/contribute` accepts the new product IDs - [ ] After merge: redeploy frontend (Cloudflare Pages) so the new products/sitemap entries go live Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Windows 11 25H2 V2 editions, including Home and Pro China variants for x64 and ARM64. * Added product pages and catalog entries for the new editions. * Updated related-product links to connect the new V2 variants. * **Updates** * Renamed existing Windows 11 25H2 “Updated Oct” listings to “V2.” * Expanded release discovery and verification guidance for maintaining current product information. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
coderabbitai[bot] (Migrated from github.com) reviewed 2026-07-14 11:28:59 +05:30
coderabbitai[bot] (Migrated from github.com) left a comment

Actionable comments posted: 2

🧹 Nitpick comments (1)
scripts/check-new-releases/msdls_v3.py (1)

34-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid catching blind exceptions.

Catching Exception is generally discouraged as it can mask unexpected errors (such as built-in exceptions). Since you are performing an HTTP request with the requests library, it is safer and more idiomatic to catch requests.RequestException.

♻️ Proposed refactor
-    except Exception as e:
+    except requests.RequestException as e:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-new-releases/msdls_v3.py` around lines 34 - 35, Update the
exception handler around the session permit HTTP request to catch
requests.RequestException instead of the broad Exception type, while preserving
the existing warning and continuation behavior.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Around line 288-289: Update the Windows 11 25H2 (V2) catalog table in
README.md to add the missing China variant entries for catalog IDs 3322, 3323,
3325, and 3326, preserving the existing table format and architecture
associations.

In `@scripts/check-new-releases/main.go`:
- Around line 103-143: Update newSession to capture successful responses from
the req1 and req3 client.Do calls and close each Response.Body, while preserving
the existing request flow and ignoring only the returned errors as appropriate.

---

Nitpick comments:
In `@scripts/check-new-releases/msdls_v3.py`:
- Around line 34-35: Update the exception handler around the session permit HTTP
request to catch requests.RequestException instead of the broad Exception type,
while preserving the existing warning and continuation behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b6e3a20e-065d-475e-8fc4-50beeec56c18

📥 Commits

Reviewing files that changed from the base of the PR and between f67fe84348 and c30c2d2b3b.

📒 Files selected for processing (9)
  • README.md
  • backend/main.go
  • cli/catalog.go
  • frontend/public/data/products.json
  • frontend/public/sitemap.xml
  • scripts/check-new-releases/README.md
  • scripts/check-new-releases/go.mod
  • scripts/check-new-releases/main.go
  • scripts/check-new-releases/msdls_v3.py
**Actionable comments posted: 2** <details> <summary>🧹 Nitpick comments (1)</summary><blockquote> <details> <summary>scripts/check-new-releases/msdls_v3.py (1)</summary><blockquote> `34-35`: _📐 Maintainability & Code Quality_ | _🔵 Trivial_ | _💤 Low value_ **Avoid catching blind exceptions.** Catching `Exception` is generally discouraged as it can mask unexpected errors (such as built-in exceptions). Since you are performing an HTTP request with the `requests` library, it is safer and more idiomatic to catch `requests.RequestException`. <details> <summary>♻️ Proposed refactor</summary> ```diff - except Exception as e: + except requests.RequestException as e: ``` </details> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/check-new-releases/msdls_v3.py` around lines 34 - 35, Update the exception handler around the session permit HTTP request to catch requests.RequestException instead of the broad Exception type, while preserving the existing warning and continuation behavior. ``` </details> <!-- cr-comment:v1:e4734a80cf0e403f0775afc8 --> _Source: Linters/SAST tools_ </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Inline comments: In `@README.md`: - Around line 288-289: Update the Windows 11 25H2 (V2) catalog table in README.md to add the missing China variant entries for catalog IDs 3322, 3323, 3325, and 3326, preserving the existing table format and architecture associations. In `@scripts/check-new-releases/main.go`: - Around line 103-143: Update newSession to capture successful responses from the req1 and req3 client.Do calls and close each Response.Body, while preserving the existing request flow and ignoring only the returned errors as appropriate. --- Nitpick comments: In `@scripts/check-new-releases/msdls_v3.py`: - Around line 34-35: Update the exception handler around the session permit HTTP request to catch requests.RequestException instead of the broad Exception type, while preserving the existing warning and continuation behavior. ``` </details> <details> <summary>🪄 Autofix (Beta)</summary> Fix all unresolved CodeRabbit comments on this PR: - [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended) - [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes </details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: defaults **Review profile**: CHILL **Plan**: Pro Plus **Run ID**: `b6e3a20e-065d-475e-8fc4-50beeec56c18` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between f67fe8434843b8cd90a510248c1ad78352be9d77 and c30c2d2b3b48c98401be88828458bc6ece919ac0. </details> <details> <summary>📒 Files selected for processing (9)</summary> * `README.md` * `backend/main.go` * `cli/catalog.go` * `frontend/public/data/products.json` * `frontend/public/sitemap.xml` * `scripts/check-new-releases/README.md` * `scripts/check-new-releases/go.mod` * `scripts/check-new-releases/main.go` * `scripts/check-new-releases/msdls_v3.py` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
@ -290,2 +288,4 @@
| Windows 11 25H2 (V2) | 3321 | x64 |
| Windows 11 25H2 (V2) | 3324 | ARM64 |
| Windows 11 24H2 | 3113 | x64 |
| Windows 11 24H2 | 3131 | ARM64 |
coderabbitai[bot] (Migrated from github.com) commented 2026-07-14 11:28:58 +05:30

📐 Maintainability & Code Quality | 🟡 Minor | Quick win

Add the missing China variants to the catalog table.

The PR objectives mention adding the catalog entries for the Windows 11 25H2 V2 China variants (3322, 3323, 3325, 3326) to the README, but they are missing from this table.

📝 Proposed additions
 | Windows 11 25H2 (V2) | 3321 | x64 |
+| Windows 11 25H2 Home China (V2) | 3322 | x64 |
+| Windows 11 25H2 Pro China (V2) | 3323 | x64 |
 | Windows 11 25H2 (V2) | 3324 | ARM64 |
+| Windows 11 Arm64 25H2 Home China (V2) | 3325 | ARM64 |
+| Windows 11 Arm64 25H2 Pro China (V2) | 3326 | ARM64 |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

| Windows 11 25H2 (V2) | 3321 | x64 |
| Windows 11 25H2 Home China (V2) | 3322 | x64 |
| Windows 11 25H2 Pro China (V2) | 3323 | x64 |
| Windows 11 25H2 (V2) | 3324 | ARM64 |
| Windows 11 Arm64 25H2 Home China (V2) | 3325 | ARM64 |
| Windows 11 Arm64 25H2 Pro China (V2) | 3326 | ARM64 |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 288 - 289, Update the Windows 11 25H2 (V2) catalog
table in README.md to add the missing China variant entries for catalog IDs
3322, 3323, 3325, and 3326, preserving the existing table format and
architecture associations.
_📐 Maintainability & Code Quality_ | _🟡 Minor_ | _⚡ Quick win_ **Add the missing China variants to the catalog table.** The PR objectives mention adding the catalog entries for the Windows 11 25H2 V2 China variants (`3322`, `3323`, `3325`, `3326`) to the README, but they are missing from this table. <details> <summary>📝 Proposed additions</summary> ```diff | Windows 11 25H2 (V2) | 3321 | x64 | +| Windows 11 25H2 Home China (V2) | 3322 | x64 | +| Windows 11 25H2 Pro China (V2) | 3323 | x64 | | Windows 11 25H2 (V2) | 3324 | ARM64 | +| Windows 11 Arm64 25H2 Home China (V2) | 3325 | ARM64 | +| Windows 11 Arm64 25H2 Pro China (V2) | 3326 | ARM64 | ``` </details> <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion | Windows 11 25H2 (V2) | 3321 | x64 | | Windows 11 25H2 Home China (V2) | 3322 | x64 | | Windows 11 25H2 Pro China (V2) | 3323 | x64 | | Windows 11 25H2 (V2) | 3324 | ARM64 | | Windows 11 Arm64 25H2 Home China (V2) | 3325 | ARM64 | | Windows 11 Arm64 25H2 Pro China (V2) | 3326 | ARM64 | ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` around lines 288 - 289, Update the Windows 11 25H2 (V2) catalog table in README.md to add the missing China variant entries for catalog IDs 3322, 3323, 3325, and 3326, preserving the existing table format and architecture associations. ``` </details> <!-- fingerprinting:phantom:poseidon:panther --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:d4203a33505f6e3c65801827 --> <!-- This is an auto-generated comment by CodeRabbit -->
@ -0,0 +140,4 @@
client.Do(req3)
}
return client, sessionID
}
coderabbitai[bot] (Migrated from github.com) commented 2026-07-14 11:28:58 +05:30

🩺 Stability & Availability | 🟡 Minor | Quick win

Close response bodies to prevent resource leaks.

When client.Do returns successfully, the Response.Body must be closed to avoid leaking the underlying HTTP connection. Although this is a short-lived script, it is best practice to close the response bodies for req1 and req3.

🛠️ Proposed fix
-	client.Do(req1)
+	if resp1, err := client.Do(req1); err == nil {
+		resp1.Body.Close()
+	}
 
 	q2 := url.Values{}
 	q2.Set("instanceId", msCustomer)
 	q2.Set("PageId", "si")
 	q2.Set("session_id", sessionID)
 	req2, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/mdt.js?"+q2.Encode(), nil)
 	req2.Header.Set("User-Agent", msUA)
 	resp2, err := client.Do(req2)
 	if err != nil {
 		return client, sessionID
 	}
 	body, _ := io.ReadAll(resp2.Body)
 	resp2.Body.Close()
 
 	wMatch := reW.FindStringSubmatch(string(body))
 	rtMatch := reRt.FindStringSubmatch(string(body))
 	if len(wMatch) > 1 && len(rtMatch) > 1 {
 		q3 := url.Values{}
 		q3.Set("session_id", sessionID)
 		q3.Set("CustomerId", msCustomer)
 		q3.Set("PageId", "si")
 		q3.Set("w", wMatch[1])
 		q3.Set("mdt", fmt.Sprintf("%d", time.Now().UnixMilli()))
 		q3.Set("rticks", rtMatch[1])
 		req3, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/?"+q3.Encode(), nil)
 		req3.Header.Set("User-Agent", msUA)
-		client.Do(req3)
+		if resp3, err := client.Do(req3); err == nil {
+			resp3.Body.Close()
+		}
 	}
 	return client, sessionID
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

func newSession() (*http.Client, string) {
	sessionID := newSessionID()
	jar := &simpleCookieJar{}
	client := &http.Client{Timeout: 15 * time.Second, Jar: jar}

	q1 := url.Values{}
	q1.Set("org_id", msOrgID)
	q1.Set("session_id", sessionID)
	req1, _ := http.NewRequest("GET", "https://vlscppe.microsoft.com/tags?"+q1.Encode(), nil)
	req1.Header.Set("User-Agent", msUA)
	if resp1, err := client.Do(req1); err == nil {
		resp1.Body.Close()
	}

	q2 := url.Values{}
	q2.Set("instanceId", msCustomer)
	q2.Set("PageId", "si")
	q2.Set("session_id", sessionID)
	req2, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/mdt.js?"+q2.Encode(), nil)
	req2.Header.Set("User-Agent", msUA)
	resp2, err := client.Do(req2)
	if err != nil {
		return client, sessionID
	}
	body, _ := io.ReadAll(resp2.Body)
	resp2.Body.Close()

	wMatch := reW.FindStringSubmatch(string(body))
	rtMatch := reRt.FindStringSubmatch(string(body))
	if len(wMatch) > 1 && len(rtMatch) > 1 {
		q3 := url.Values{}
		q3.Set("session_id", sessionID)
		q3.Set("CustomerId", msCustomer)
		q3.Set("PageId", "si")
		q3.Set("w", wMatch[1])
		q3.Set("mdt", fmt.Sprintf("%d", time.Now().UnixMilli()))
		q3.Set("rticks", rtMatch[1])
		req3, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/?"+q3.Encode(), nil)
		req3.Header.Set("User-Agent", msUA)
		if resp3, err := client.Do(req3); err == nil {
			resp3.Body.Close()
		}
	}
	return client, sessionID
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/check-new-releases/main.go` around lines 103 - 143, Update newSession
to capture successful responses from the req1 and req3 client.Do calls and close
each Response.Body, while preserving the existing request flow and ignoring only
the returned errors as appropriate.
_🩺 Stability & Availability_ | _🟡 Minor_ | _⚡ Quick win_ **Close response bodies to prevent resource leaks.** When `client.Do` returns successfully, the `Response.Body` must be closed to avoid leaking the underlying HTTP connection. Although this is a short-lived script, it is best practice to close the response bodies for `req1` and `req3`. <details> <summary>🛠️ Proposed fix</summary> ```diff - client.Do(req1) + if resp1, err := client.Do(req1); err == nil { + resp1.Body.Close() + } q2 := url.Values{} q2.Set("instanceId", msCustomer) q2.Set("PageId", "si") q2.Set("session_id", sessionID) req2, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/mdt.js?"+q2.Encode(), nil) req2.Header.Set("User-Agent", msUA) resp2, err := client.Do(req2) if err != nil { return client, sessionID } body, _ := io.ReadAll(resp2.Body) resp2.Body.Close() wMatch := reW.FindStringSubmatch(string(body)) rtMatch := reRt.FindStringSubmatch(string(body)) if len(wMatch) > 1 && len(rtMatch) > 1 { q3 := url.Values{} q3.Set("session_id", sessionID) q3.Set("CustomerId", msCustomer) q3.Set("PageId", "si") q3.Set("w", wMatch[1]) q3.Set("mdt", fmt.Sprintf("%d", time.Now().UnixMilli())) q3.Set("rticks", rtMatch[1]) req3, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/?"+q3.Encode(), nil) req3.Header.Set("User-Agent", msUA) - client.Do(req3) + if resp3, err := client.Do(req3); err == nil { + resp3.Body.Close() + } } return client, sessionID } ``` </details> <!-- suggestion_start --> <details> <summary>📝 Committable suggestion</summary> > ‼️ **IMPORTANT** > Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements. ```suggestion func newSession() (*http.Client, string) { sessionID := newSessionID() jar := &simpleCookieJar{} client := &http.Client{Timeout: 15 * time.Second, Jar: jar} q1 := url.Values{} q1.Set("org_id", msOrgID) q1.Set("session_id", sessionID) req1, _ := http.NewRequest("GET", "https://vlscppe.microsoft.com/tags?"+q1.Encode(), nil) req1.Header.Set("User-Agent", msUA) if resp1, err := client.Do(req1); err == nil { resp1.Body.Close() } q2 := url.Values{} q2.Set("instanceId", msCustomer) q2.Set("PageId", "si") q2.Set("session_id", sessionID) req2, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/mdt.js?"+q2.Encode(), nil) req2.Header.Set("User-Agent", msUA) resp2, err := client.Do(req2) if err != nil { return client, sessionID } body, _ := io.ReadAll(resp2.Body) resp2.Body.Close() wMatch := reW.FindStringSubmatch(string(body)) rtMatch := reRt.FindStringSubmatch(string(body)) if len(wMatch) > 1 && len(rtMatch) > 1 { q3 := url.Values{} q3.Set("session_id", sessionID) q3.Set("CustomerId", msCustomer) q3.Set("PageId", "si") q3.Set("w", wMatch[1]) q3.Set("mdt", fmt.Sprintf("%d", time.Now().UnixMilli())) q3.Set("rticks", rtMatch[1]) req3, _ := http.NewRequest("GET", "https://ov-df.microsoft.com/?"+q3.Encode(), nil) req3.Header.Set("User-Agent", msUA) if resp3, err := client.Do(req3); err == nil { resp3.Body.Close() } } return client, sessionID } ``` </details> <!-- suggestion_end --> <details> <summary>🤖 Prompt for AI Agents</summary> ``` Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/check-new-releases/main.go` around lines 103 - 143, Update newSession to capture successful responses from the req1 and req3 client.Do calls and close each Response.Body, while preserving the existing request flow and ignoring only the returned errors as appropriate. ``` </details> <!-- fingerprinting:phantom:poseidon:panther --> <!-- cr-indicator-types:potential_issue --> <!-- cr-comment:v1:06aabc48a5593dffe39bf1e7 --> <!-- This is an auto-generated comment by CodeRabbit -->
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: shekhar/windows-iso-downloader#36
No description provided.