diff --git a/docs/dnn/dnn10-migration-readiness.md b/docs/dnn/dnn10-migration-readiness.md new file mode 100644 index 00000000..b9b6a0db --- /dev/null +++ b/docs/dnn/dnn10-migration-readiness.md @@ -0,0 +1,69 @@ +# DNN 10 Migration — Code Readiness Assessment (read-only, consolidated) + +> **Purpose**: consolidate the read-only findings (ticks 29-31) into a **durable** document that survives dashboard condensation. Establishes that the **code-side migration surface for DNN 10.3.2 is low-risk**; the dominant unknowns (Telerik removal, deprecated APIs) are cleared. +> **Scope**: repo-runtime state (branch `dnn/sandbox-runtime-1032`, commit `4b0297ee`, DNN 10.3.2.0 + 2sxc 21.07.00, .NET Framework 4.8). NOT public prod (`dnn.argumentum.myia.io` = HTTP 500 skin `tabid=138`, version-independent). +> **Author**: po-2023 (dispatch ai-01 `msg-20260722T224852-6cz88c`, secondaire). +> **Cross-ref**: #131, `skin-tabid138-diagnostic-runbook.md` (PR #851 merged), `RUNBOOKS-GATED-OPS.md`, `UPGRADE-ASSESSMENT.md`. + +--- + +## 1. Versions (measured, DLL-level) + +| Component | Installed (repo-runtime) | Target | Method | +|-----------|--------------------------|--------|--------| +| DNN Platform | **10.3.2.0** ✅ | 10.3.2 | `DotNetNuke.dll` FileVersion | +| 2sxc | **21.07.00** ✅ | 21.07 LTS | `ToSic.Sxc.*.dll` | +| .NET runtime | Framework 4.8 | 4.8 | verified (not .NET 8/9) | +| OpenStore (NBrightBuy) | 4.1.11.0 | 4.2.4 or replace | `NBrightBuy.dll` FileVersion | + +> `web.config` `InstallVersion=09.06.02` is a **legacy initial-install appSetting**, NOT the runtime version. See #131 body refresh (PR comment, 2026-07-22). + +--- + +## 2. Telerik removal — migration surface = ZERO ✅ + +DNN 10 removes Telerik. Historically the dominant pain-point of DNN upgrades. For this codebase it is **already done**: + +- **DLL-level**: `0/206` DLLs in `bin/` reference Telerik (`Assembly.GetReferencedAssemblies()` scan). `Telerik.Web.UI.dll` is **absent** from `bin/`. Only `Dnn.Modules.TelerikRemoval.dll` (the removal shim) is present. +- **OpenStore / NBrightBuy**: **Telerik-free** (6 DLLs checked: NBrightBuy 4.1.11, NBrightCore/NBrightDNN 8.7.2, OS_Stripe/OS_Reports/OS_Chronopost2 — 0 Telerik AssemblyRefs). Comment on #131 (`issuecomment-5049252377`). +- **Skin markup**: `0` `.ascx` files reference Telerik (3 CSS files in `_default/WebControlSkin/` are cosmetic styles for Telerik controls — never loaded without a Telerik control). + +**Conclusion**: Telerik is not a blocker for OpenStore or any repo module/skin on DNN 10. + +--- + +## 3. Skin objects — DNN 10 standard, compatible ✅ + +- **26 `.ascx`** across all skins (Xcillion, nvQuickTheme, DnnContra, DnnBootsterV2, Bootstrap 4 Instant, 2shineBS5) use **standard DNN skin objects** (`dnn:BREADCRUMB` / `dnn:MENU` / `dnn:LOGIN` / `dnn:SEARCH` / `dnn:USER` / etc.) — core controls, compatible with DNN 10. +- **6 Razor skins** (DnnContra, DnnBootsterV2, Bootstrap 4 Instant, 2shineBS5) use `TabInfo` + `PortalSettings.ActiveTab` — **stable APIs, not deprecated** in DNN 10. + +--- + +## 4. OpenStore secondary refs (documented, non-blocking) + +From `NBrightBuy.dll` AssemblyRefs: +- `→ DotNetNuke 9.7.1.0` (runtime is 10.3.2.0 — handled by standard DNN binding redirects). +- `→ RazorEngine 3.10.0.0` (legacy Razor engine; OpenStore ships its own — watch-point for the 2sxc Razor14 migration #596 interaction, separate concern). + +--- + +## 5. Residual open items (gated, not code-blocking) + +| Item | Status | Gated by | +|------|--------|----------| +| **Runtime smoke-test** on DNN 10.3.2 sandbox | not yet re-verified live | sandbox blocked by HTTP 500 skin `tabid=138` (≠ platform version); smoke at GO jsboige | +| **Skin `tabid=138` HTTP 500** (`lblBreadCrumb` HttpParseException) | diagnostic runbook ready | Opt 1 (fix v0.9.1, tag not blocked) — `skin-tabid138-diagnostic-runbook.md` | +| **OpenStore runtime re-verify** (Phase A checkbox) | gated | same sandbox block; risk Telerik cleared → smoke-test, not porting effort | +| **machineKey rotation** | runbook ready | jsboige ops server (HIGH exposure) — `machinekey-rotation-scrub-runbook.md` | +| **2sxc App export #681** | hard-unblocker DNN i18n | jsboige (content lives in live 2sxc DB) | + +--- + +## 6. Bottom line + +The **code-side** migration to DNN 10.3.2 is **low-risk and essentially complete** in the repo-runtime state: +- Telerik surface = 0 (the usual DNN 10 blocker) ✅ +- Skin objects + Razor APIs = DNN 10 standard ✅ +- OpenStore = Telerik-free ✅ + +The remaining work is **runtime/ops** (smoke-test at GO, skin `tabid=138` fix, machineKey rotation), not code porting. None of it blocks the v0.9.0 tag (Opt 1: skin fix deferred to v0.9.1). diff --git a/docs/dnn/machinekey-rotation-scrub-runbook.md b/docs/dnn/machinekey-rotation-scrub-runbook.md new file mode 100644 index 00000000..d2911907 --- /dev/null +++ b/docs/dnn/machinekey-rotation-scrub-runbook.md @@ -0,0 +1,107 @@ +# DNN machineKey — Rotation + Scrub Runbook (gated jsboige, secret-safe) + +> **Severity**: HIGH — the DNN `machineKey` is **exposed publicly on GitHub** (branch `dnn/sandbox-runtime-1032`, commit `4b0297ee`). Treat as compromised. **Rotation is the only real fix.** +> **Secret-safe policy**: this document references secrets **by location only** (file path + attribute name). **No key value is ever written here.** GitGuardian must pass on this file. Matches discipline of PR #842 / #851. +> **Scope**: staged runbook — **ZERO execution** without explicit GO from jsboige (ops server, `#415` git-rewrite gated). Copy-paste procedure for jsboige. +> **Author**: po-2023 (dispatch ai-01 `msg-20260722T224852-6cz88c`, primaire). +> **Cross-ref**: #131 Phase D, `.githooks/pre-commit` (#842), `RUNBOOKS-GATED-OPS.md`. + +--- + +## 0. Where the secret lives (emplacement, NOT value) + +| Location | Content | Status | +|----------|---------|--------| +| `DNNPlatform/web.config` → `` → `` | on **master**: placeholder `validationKey="REPLACE" decryptionKey="REPLACE"` (7-char, **not a secret**) | ✅ master clean | +| Same element, branch `dnn/sandbox-runtime-1032` (commit `4b0297ee`, **public on origin**) | **real** keys (128-hex `validationKey` + 64-hex `decryptionKey`, no `AutoGenerate`) | ⛔ **EXPOSED** | +| Same element, local working tree (runtime-expanded) | real keys (DNN runtime writes them on startup) | local-only, never committed | + +> The exposed commit `4b0297ee` = sandbox runtime snapshot of DNN 10.3.2 + 2sxc 21.07 (bin/ 330 files). Git author = jsboige (auth routing, not provably human-vs-agent). + +**Why this matters** (threat model): a leaked `machineKey` lets an attacker forge DNN authentication cookies + tamper ViewState → **unauthenticated account impersonation / privilege escalation** on any DNN site using the same key. The prod site (`dnn.argumentum.myia.io`) is the target if it runs the exposed key. + +--- + +## A. Rotation (server-side — the ONLY real fix) — do FIRST + +**Why first**: deleting the branch (B) does NOT purge the secret — GitHub retains orphaned commits server-side, and any fork/cache still has it. **Rotation invalidates the exposed key everywhere**; scrub (B) is then repo hygiene. + +**Good timing**: the site is **not yet in public prod** (go-live pending v0.9.0) → rotation cost is near-zero (no active user sessions to disrupt). Do it **before** go-live. + +### A.1 Generate fresh key material (run ON THE SERVER; output is NEVER committed) + +```powershell +# Run on the production server. Output is a NEW key — do NOT paste it into git, this repo, or any dashboard. +$bytes = { param($n) -join (1..$n | ForEach-Object { '{0:X2}' -f (Get-Random -Maximum 256) }) } +$validationKey = & $bytes 64 # 128 hex chars (SHA256/HMACSHA256) +$decryptionKey = & $bytes 32 # 64 hex chars (AES) +"validationKey=$validationKey" +"decryptionKey=$decryptionKey" +``` + +> Alternative: IIS Manager → site → **Machine Key** feature → uncheck "Automatically generate at runtime" → **Generate Keys** → Apply (writes new values to the site `web.config`). + +### A.2 Apply the new keys to the live site `web.config` + +Edit the live site's `web.config` (NOT the repo's tracked template) `` `` element with the new values, keeping `decryption="AES" validation="HMACSHA256"`. + +### A.3 Recycle the app pool + +```powershell +# Force DNN to pick up the new machineKey — invalidates ALL old cookies/ViewState/sessions +Restart-WebAppPool -Name "" +``` + +**Side effect (expected)**: every existing auth cookie / ViewState / session is invalidated → all users must re-authenticate. Acceptable for a compromise + pre-go-live (no active public users yet). + +### A.4 Smoke + +- `dnn.argumentum.myia.io` homepage → HTTP 200. +- Login flow works (cookie signed with new key). +- 0 "Validation of viewstate MAC failed" errors (Event Viewer → Application log). + +--- + +## B. Scrub the repository (repo hygiene, AFTER rotation A) + +> **Load-bearing warning**: branch `dnn/sandbox-runtime-1032` is the **migration reference** for po-2023 (bin/ 330 files, clean net48 runtime). Before **any** delete (B1), ensure its migration analysis is captured durably → see `dnn10-migration-readiness.md` (item 2 of the dispatch). **Do NOT delete before that capture + before rotation (A) is confirmed live.** + +### B.1 Bleed-stop (quick, recommended) — delete the exposed remote ref + +```bash +# Removes the ref from origin. The commit becomes unreachable from any branch. +git push origin --delete dnn/sandbox-runtime-1032 +``` + +**What this does / does NOT do**: +- ✅ Stops the secret from being trivially discoverable via `git ls-remote` / branch listing. +- ❌ Does **NOT** purge the commit: GitHub retains orphaned commits server-side (accessible by SHA via the API for an extended period), and any local clone/fork that fetched it still has it. **Hence rotation (A) is the only true fix.** + +### B.2 History-rewrite + force-push (heavier, gated) — OPTIONAL + +Rewriting `4b0297ee` out of history (`git filter-repo` / BFG on the key) + force-push would scrub the literal from the repo's history. **Gated by `#415`** (force-push on a shared repo requires explicit jsboige arbitration). And even then, it does not purge GitHub server-side retention or external forks. + +**Recommendation**: B1 (bleed-stop) + rotation (A) is sufficient. B2 only if jsboige wants the literal gone from visible history (low marginal value given server-side retention). + +--- + +## C. Post-action verification (after A + B1) + +1. **master clean**: `git show origin/master:DNNPlatform/web.config | grep machineKey` → `validationKey="REPLACE"` (placeholder, unchanged). +2. **ref gone**: `git ls-remote origin dnn/sandbox-runtime-1032` → empty (post B1). +3. **live site on new keys**: login works, 0 ViewState-MAC errors (A.4). +4. **local scan (informational)**: `git log --all -S ''` — should return only the (now-deleted) branch's commits if any local ref still points there; this confirms no *other* branch carried the secret. (Does NOT reflect GitHub server-side state.) +5. **pre-commit guard active**: `.githooks/pre-commit` (#842) blocks any future staged `web.config` carrying a real key → defense-in-depth against re-introduction. + +--- + +## D. Optional hardening (post-rotation, separate decision) + +- `.gitignore` should cover `DNNPlatform/web.config` so the runtime-expanded copy can't be accidentally staged. Currently it is git-tracked but the pre-commit hook (#842) is the active guard. A `.gitignore` entry + `git rm --cached` would be belt-and-suspenders (jsboige-gated — don't break the master template `092bb8f3` / #442). +- Rotate the SQL password (`dnn_user`) too — it was verified CLEAN (never committed) but shares the threat surface with the sandbox snapshot. + +--- + +## Ordering (mandatory) + +**A (rotation, server) → B1 (bleed-stop, repo) → C (verify).** Never scrub (B) before rotation (A): scrubbing a key that is still live on the server does nothing for security. Rotation is the remediation; scrub is hygiene.