25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

7.4KB

WSC-MVC — Decisions and Experiment Log

M0 — Environment inventory (2026-09-19, win2025test VM, 100.127.62.31)

Host: Windows Server 2025 Standard, build 10.0.26100, 64-bit, AMD Ryzen 5 1500X (4c). Verified via SSH (key-based, Administrator) + PowerShell 5.1.

  • IIS: installed (Web-Server) with Web-ASP, Web-CGI, Web-ISAPI-Ext, Web-ISAPI-Filter, management tools/console/scripting tools all Installed.
  • URL Rewrite module: present (%SystemRoot%\system32\inetsrv\rewrite.dll, registered as RewriteModule in global modules).
  • WebAdministration PowerShell module: available (v1.0.0.0).
  • WSC/COM runtime: scrobj.dll present in both System32 and SysWOW64.
  • regsvr32.exe, cscript.exe, wscript.exe: present at standard C:\WINDOWS\system32 paths.
  • Existing app pools are all 64-bit (enable32BitAppOnWin64 = False); no 32-bit requirement observed. WSC-MVC will target 64-bit and re-verify if this changes.
  • Existing sites: Default Web Site (*:80), AspClassicUnifiedFramework (*:8080, unrelated pre-existing project). No port conflict for a new dedicated site on *:8090.
  • Disk: C: only (106 GB, ~80 GB free). No D:/E:/F: volumes despite drive letters being visible (0 bytes each — not usable). Project deployed under C:\Projects\wsc-mvc.
  • Firewall: World Wide Web Services (HTTP Traffic-In) inbound rule enabled.
  • HTTP reachability: VM only reachable over the private Tailscale tailnet (100.127.62.31); no public exposure.

No blocking gaps found for M0/M1. Proceeding to M1.

Open question #1 — Can WSC receive ASP intrinsic objects across the IIS/COM boundary?

Decision: not attempted for M1. Per SPEC and AGENTS.md hard rules, business logic must never reference ASP Request/Response/Server/Session anyway, so this is avoided by design rather than tested as a compatibility question. Application.Run and HomeController.Hello use a primitive-only, ByRef-out contract: all parameters are strings (pathInfo in; statusLine, contentType, body out via VBScript's default ByRef parameter passing — no ByVal/ByRef keywords are available in WSC <public> XML, so behavior follows the Sub/Function signature in the script block). Default.asp owns all ASP host object access and is the only file that touches Request/Response/Server.

This resolves the open question pragmatically: no experiment needed because the architecture never crosses that boundary. Revisit only if a future milestone needs to pass richer data (e.g. multi-value POST bodies) — prefer additional scalar out-params or a Scripting.Dictionary (a standard COM component, not an ASP intrinsic) over passing ASP objects into a WSC.

Registration tooling

regsvr32.exe /s "<path>.wsc" registers a Windows Script Component directly (scrobj.dll is the underlying handler associated with the .wsc extension). Verified working for both Application.wsc and HomeController.wsc on this host — see docs/TEST-RESULTS.md. Both scripts require elevation (registry write); the deployment/registration step is intentionally separate from the request-handling pipeline per SPEC §10 and AGENTS.md.

Finding: regsvr32 /s /u component.wsc does not actually unregister. Verified experimentally on this host (Windows Server 2025, build 26100): after regsvr32 /s /u on both components, regsvr32 reports exit code 0, but HKLM:\SOFTWARE\Classes\<ProgID> and HKLM:\SOFTWARE\Classes\CLSID\<CLSID> are both still present and functional (confirmed via direct registry inspection and a follow-up CreateObject that still succeeded). This reproduced identically via Start-Process -Wait and via a direct cmd-level regsvr32 /s /u call with %ERRORLEVEL% checked. This is a real scrobj.dll/WSC limitation, not a script bug — do not trust regsvr32 /u's exit code as evidence of removal for .wsc files on this host.

Fix implemented: tools/Unregister-Components.ps1 still calls regsvr32 /s /u first (harmless best-effort), then explicitly checks whether HKLM:\SOFTWARE\Classes\<ProgID> still resolves to this project's known CLSID, and if so removes exactly that ProgID key and exactly that CLSID key (recursive), nothing else. It refuses (throws) instead of deleting if the registered CLSID under that ProgID doesn't match what this project expects, to guarantee it can never remove a different component's registration that happens to reuse a ProgID string. Full reversibility cycle (register → verify via HTTP+WSH → unregister → verify HTTP 500 + WSH CreateObject failure → re-register → verify recovery) was run end-to-end and passed; see docs/TEST-RESULTS.md.

Finding: IIS httpErrors substitutes its own error page for remote clients by default

With the out-of-the-box system.webServer/httpErrors setting (errorMode="DetailedLocalOnly"), a request from a remote client (e.g. over the tailnet, not literally localhost on the IIS box) that hits a 500 gets IIS's own generic friendly-error HTML page, not whatever Default.asp wrote to the response body — even though Default.asp's own On Error Resume Next / Err.Number handling ran correctly and wrote its intended "Internal Server Error" / text/plain body. Verified by comparing a curl from the Linux host (tailnet IP) against a curl run locally on the VM (http://localhost:8090/hello) with components deliberately unregistered: the local request returned our own exact Content-Type: text/plain; charset=utf-8 / Internal Server Error body; the remote request returned IIS's generic HTML page. Both are HTTP 500 and both satisfy the SPEC §14/§10 requirement (safe failure, no path or exception text leaked to any client) — this is IIS being conservative for non-local requests, not a defect in our error handling. Documented here so a future milestone doesn't mistake this for Default.asp's error branch not firing.

Diagnostic note: system.webServer/asp is locked (overrideModeDefault="Deny") at the machine level by default, so it cannot be overridden from a site's own web.config. Toggling scriptErrorSentToBrowser for diagnosis requires appcmd unlock config /section:system.webServer/asp first; remember to appcmd lock config /section:system.webServer/asp again afterward and to manually strip any <asp .../> element that Set-WebConfigurationProperty writes into the site's web.config before re-locking, or the site's config becomes invalid (locked section referenced from a location that has an explicit override) and every request 500s until the stray element is removed. This happened once during M1 testing on this host and was fixed by editing web.config directly; the repository's web.config was never affected (this only happened to the deployed copy on the VM).

Static/source protection approach

Used IIS requestFiltering/hiddenSegments (blocks any URL path containing Framework, Controllers, tests, tools, docs as a path segment, anywhere in the tree) plus requestFiltering/fileExtensions denylist for .wsc, .vbs, .ps1, .md. This keeps Default.asp at the project root (matching the SPEC §5 target tree) while denying direct access to source/config/test files, rather than moving Default.asp into a separate public/ webroot. Verified with tests/Test-Http.ps1 (direct .wsc request must return 404).

Site/port allocation

New dedicated site WscMvc, app pool WscMvc (64-bit, no managed code), binding *:8090, physical path C:\Projects\wsc-mvc. Chosen to avoid the existing *:80 and *:8080 bindings already in use on this VM.

Powered by TurnKey Linux.