Use this checklist before publishing the website, creating an updated-files archive, or enabling a new paid/AI/runtime feature. It is deliberately operational: it does not ask you to change product behavior, only to keep secrets out of source artifacts and make risky config states visible.
Never include Web.config in customer/source snapshots or updated-files zips. Production values should live in host-level configuration, deployment transforms, or an approved secret manager.
Release archive rules
| Rule |
Status |
Reason |
Exclude Web.config |
Required |
It may contain payment, admin, AI, database, and provider credentials. Rotate any credential that was ever sent in a public or vendor-facing archive. |
| Exclude generated build folders |
Required |
Skip bin, obj, _RETempCode, node_modules, and local cache directories. Package source/content changes, not transient compiler output. |
| Exclude rebuilt desktop download binaries unless intentionally shipping them |
Review |
Build verification can update timestamps on binaries. Do not let timestamp-only changes enter a source update archive. |
| Verify archive contents after creation |
Required |
Check entry names for Web.config, generated temp code, and unexpected binaries before handing the zip to anyone. |
Reusable archive command
The project folder includes a helper script for the updated-after-date archives used during this release pass:
powershell -ExecutionPolicy Bypass -File tools/Build-UpdatedArchives.ps1 `
-Root D:\Projects\javascriptobfuscator `
-Cutoff 2026-05-28 `
-ReportPath _temp/archive-hygiene.json
The script excludes Web.config, zip files, local scratch folders such as _temp, generated temp folders, build outputs, package dependencies, and timestamp-only desktop download binaries. It prints a verification table after creating the website and full-project archives, then fails the command if a blocked deployment file appears in either zip.
When -ReportPath is supplied, the script also writes a machine-readable hygiene report for source-free release handoff. The JSON includes the cutoff date, archive sizes, missing required files, blocked entries, the exclusion policy used for zip verification, and an operator checklist with before-sharing steps, rotation triggers, and a reminder not to attach secrets or host-specific deployment transforms.
Before sharing the updated-files zip, convert that JSON into a reviewer packet:
jso-protector --deployment-hygiene-evidence _temp/archive-hygiene.json `
--deployment-hygiene-output reports/deployment-hygiene.md
The packet summarizes archive names, entry counts, byte sizes, missing or blocked entries, blocked category booleans, the exclusion policy, the operator checklist, rotation triggers, and the hygiene-report SHA-256. It also includes a source-free Deployment Hygiene Review Assistant for BYO AI or internal reviewers. Do not add Web.config contents, raw secrets, provider keys, webhook signing secrets, database strings, host-specific deployment transforms, customer data, or source code. If the archive builder reported blocked deployment files or missing required entries, the command writes the failed packet and exits nonzero so the handoff can stop before external sharing.
Live deployment checks
| Check |
Target state |
Why it matters |
| Rendered-page and readiness smoke |
Run npm run verify:live-health after deployment; require the static probe, database readiness endpoint, homepage, online tool, and Docs pages to pass. |
A static-only uptime check can miss an ASP.NET compilation or pipeline outage while robots.txt still returns 200. |
| Canonical and legacy-host consolidation |
Run npm run verify:live-seo; require exact one-hop destinations for HTTP, www, service, and svc, plus apex canonicals, robots policy, and a unique lowercase sitemap. |
Preserving legacy path casing at the edge creates avoidable redirect/index residue even when canonical tags are correct. |
| Admin credential storage |
Use JSOAdminPasswordHash; remove plaintext JSOAdminPassword. |
Plaintext admin credentials in config are an audit finding and increase blast radius if the file is copied. |
| Stripe webhook enforcement |
Set StripeWebhookEnforce=True after confirming Stripe signatures validate. |
Audit-only mode is useful during rollout, but production should reject invalid webhook signatures. |
| AI daily cost cap |
Set JSOAI.CostCapDailyCents before enabling live site-wide AI provider calls. |
A deployment-wide cap prevents runaway provider spend from a bug, loop, or abuse attempt. |
| BYO AI key path |
Let accounts save encrypted provider keys in AI settings while managed billing is gated. |
BYO keys keep provider billing and model access under the customer's provider account. |
| VM sidecar paths |
Keep machine-local VM paths in host-specific deployment config. |
Hard-coded workstation paths can break production or reveal local operator assumptions. |
Both commands are read-only network diagnostics and intentionally stay outside the deterministic npm run verify chain. Run them against the deployed environment, save their output with the release evidence, and correct the application or edge rule before requesting recrawl. A passing result proves only the checked HTTP contracts; it is not Search Console coverage or a ranking claim.
Rotation trigger
Rotate a credential when any of these happen:
Web.config was included in a zip, ticket, email, chat, or source snapshot.
- A provider key or webhook secret was pasted into a log or support transcript.
- A live key was used in staging or a local test environment longer than needed for a test.
- An operator can no longer explain which deployment currently owns a credential.
Frequently asked questions
Why does deployment hygiene matter if the code is already protected?
Because the most common way protected code gets read is that something unprotected was published alongside it. A source map, a stale build directory, an archive containing the original files, or a development bundle left on the server all return a reader to your original source in one step, and no transform prevents that. Hygiene is the part of the work that decides whether the protection was worth doing.
What is the single most important file to keep out of a release?
The source map, because it exists specifically to reverse the transformation. Publishing one next to a protected bundle undoes the entire exercise for anybody who opens developer tools. Generate maps if you need them for debugging, retain them somewhere private for symbolication, and confirm they are absent from what you actually serve.
How should we build a release archive?
From an explicit list of what belongs in it rather than by excluding what does not, because an allowlist fails safe and a denylist fails open. Build the archive with a repeatable command checked into the repository so that it produces the same contents on every machine, and verify the result by listing what came out rather than by trusting the command.
What should we check on the live deployment?
That the protected artifact is the one being served, that no map file resolves, and that no development or staging build remains reachable at a predictable path. These are quick requests you can automate, and running them as a post-deploy check catches the cases where a release succeeded but shipped the wrong contents.
When should we rotate credentials because of a deployment mistake?
As soon as you establish that something reached a public path which should not have. If a build containing a key, a token or an internal endpoint was served even briefly, treat it as disclosed and rotate, because you have no way to know what was fetched or cached while it was reachable. Rotation is inexpensive and the alternative is an unbounded assumption.
Does obfuscation help if a secret is already in the bundle?
Not meaningfully. Anything the code must use at run time has to be reconstructed before use, which means it can be observed at the point of use. The transforms delay a casual reader and do not stop a determined one. The correct fix is to move the value behind a request your server authorises rather than to conceal it in the artifact.