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
69 changes: 69 additions & 0 deletions docs/dnn/dnn10-migration-readiness.md
Original file line number Diff line number Diff line change
@@ -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).
107 changes: 107 additions & 0 deletions docs/dnn/machinekey-rotation-scrub-runbook.md
Original file line number Diff line number Diff line change
@@ -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` → `<system.web>` → `<machineKey validationKey="…" decryptionKey="…" decryption="AES" validation="HMACSHA256" />` | 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) `<system.web>` `<machineKey>` 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 "<DNN-app-pool-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 '<key-fragment>'` — 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.
Loading