Commit: 581cc7e
Version: 3.4dev-20260823_165236
Branch: master
Goal: prepare a trustworthy Mediabot 3.5 release without reopening the feature scope
Status: MB697 security/runtime baseline committed and deployed; functional mbweb review is next
MB697 starts immediately after two large pre-release hardening rounds:
node_modules/ vendor tree from version control.At that point the next question was no longer “can Mediabot run?” but something closer to:
Can the parts that actually run in production — including mbweb — be reproduced, secured, cleaned up and trusted enough to become part of a stable 3.5 release?
That is the purpose of MB697.
This first MB697 checkpoint deliberately concentrates on mbweb dependency security and runtime hygiene before opening the broader functional/UX review.
No new IRC feature was added in this round.
Before starting MB697, one leftover repository-hygiene problem from MB696 had to be finished properly.
The repository historically tracked 526 files under the root node_modules/ directory.
The intended MB696 cleanup had already been tested successfully, but the normal local commit.sh helper protects node_modules/** and therefore removed those staged deletions before creating commit fd44628.
A dedicated follow-up was therefore performed.
The operation used:
git rm -r --cached node_modules
The critical point is the --cached flag: the dependency files were removed from Git’s index, not from the local filesystem.
Validation proved this explicitly:
tracked_node_modules=0
local_files=640->640
local_node_modules=PRESERVED
mbweb_manifests=2
The dedicated repository-hygiene contract also passed:
1/1 files
9/9 tests
PASS
The cleanup was committed separately as:
7a46617 đź§ą Vanish the Vendored Node Vault from the Grimoire
with version:
3.4dev-20260823_154141
and pushed successfully to origin/master.
That closed MB696 for real:
tracked_node_modules=0
mbweb_manifests=2
master synchronized with origin/master
MB696=CLOSED
The roadmap was then deliberately adjusted.
Rather than treating mbweb as a peripheral contrib/ extra to be reviewed at the very end, MB697 now treats it as part of the runtime that must be reliable for 3.5.
The real architecture was established in MB696 and confirmed again in MB697:
Canonical source : contrib/mbweb/
Live runtime : /opt/mbweb/app
systemd service : mbweb.service
WorkingDirectory : /opt/mbweb/app
ExecStart : /usr/bin/node /opt/mbweb/app/app.js
The canonical npm manifests are now public project files:
contrib/mbweb/package.json
contrib/mbweb/package-lock.json
The direct dependency contract is:
bcryptjs ^2.4.3
dotenv ^16.6.1
express ^5.2.1
express-session ^1.19.0
helmet ^8.0.0
mysql2 ^3.22.2
This is important because it replaces a historical, ambiguous state where the repository contained a vendor tree but did not publicly expose the actual mbweb dependency manifest.
The first MB697 pass was intentionally read-only.
It checked:
contrib/mbweb and /opt/mbweb/app.The live service was healthy:
MainPID=228188
NRestarts=0
ExecMainStatus=0
ActiveState=active
SubState=running
Both canonical manifests matched the deployed runtime:
package.json=MATCH
package-lock.json=MATCH
Excluding intentional runtime state such as .env, npm manifests, .git and node_modules, the comparison found:
source_files=32
live_files=102
missing_live=0
changed=0
extra_live=70
This was a very useful result.
There was no missing source file and no changed application file.
In other words, the running mbweb application code matched the canonical source exactly.
The only divergence consisted of 70 additional historical files in /opt/mbweb/app.
Once the canonical mbweb manifests were committed publicly, GitHub reported two dependency vulnerabilities on the default branch:
1 moderate
1 low
A local npm audit --omit=dev reproduced the same findings:
critical:0
high:0
moderate:1
low:1
info:0
The affected packages were both transitive, not direct application dependencies.
Observed version:
body-parser=2.2.2
Severity:
low
Advisory summary:
body-parser vulnerable to denial of service when an invalid limit value
silently disables size enforcement
Observed version:
qs=6.15.1
Severity:
moderate
Advisory summary:
qs has a remotely triggerable DoS involving comma-format arrays when
encodeValuesOnly is enabled and null/undefined entries are encountered
Both advisories reported:
fixAvailable=True
For a 3.5 release candidate, leaving known fixable web-stack DoS advisories in the canonical lockfile would have been unnecessary risk.
npm audit fix on the real runtimeThe remediation was rehearsed first in a disposable /tmp directory.
Only copies of:
package.json
package-lock.json
were used.
The temporary operation was:
npm audit fix --package-lock-only --ignore-scripts
The result was clean and minimal.
Before:
express=5.2.1
body-parser=2.2.2
qs=6.15.1
After:
express=5.2.1
body-parser=2.3.0
qs=6.15.3
The direct Express version did not move.
The application manifest did not change.
Only the dependency lock needed refreshing.
The temporary audit then reported:
critical:0
high:0
moderate:0
low:0
The lockfile delta revealed another useful cleanup.
The canonical application does not declare express-rate-limit as a direct dependency and no current mbweb source file uses it.
The old lock still contained a stale entry:
express-rate-limit 7.5.1
After the controlled lock refresh:
express-rate-limit=ABSENT
This is preferable to preserving a package simply because it happened to exist in an old installation state.
The lockfile is now more accurately derived from the real mbweb dependency contract.
The audited lock refresh changed the following dependency nodes:
body-parser 2.2.2 -> 2.3.0
qs 6.15.1 -> 6.15.3
es-object-atoms 1.1.1 -> 1.1.2
hasown 2.0.3 -> 2.0.4
side-channel 1.1.0 -> 1.1.1
type-is 2.0.1 -> 2.1.0
and introduced newer nested content-type nodes where required by the dependency tree.
The stale lock entry:
express-rate-limit 7.5.1
was removed.
The direct mbweb dependency declaration itself remained unchanged.
A lockfile update is not sufficient evidence by itself.
The canonical manifest and refreshed lockfile were copied into a clean temporary directory and installed with:
npm ci --omit=dev --ignore-scripts
Result:
RC_NPM_CI=0
The clean installation resolved the expected direct dependencies:
bcryptjs=2.4.3
dotenv=16.6.1
express=5.2.1
express-session=1.19.0
helmet=8.1.0
mysql2=3.22.2
This is an important release property:
mbweb can now be reconstructed from the public canonical manifest and lockfile rather than from an old working directory.
MB697 adds:
t/cases/911_mb697_mbweb_dependency_security.t
Its purpose is to make the security cleanup durable.
The test verifies at least the following contract:
body-parser >= 2.3.0
qs >= 6.15.2
express-rate-limit absent from canonical lock
This converts a one-time manual npm audit fix into a regression-protected project rule.
Together with MB696’s Node hygiene test:
t/cases/910_mb696_node_dependency_hygiene.t
the project now protects both sides of the dependency contract:
node_modules/ into Git;Focused validation:
2/2 files
12/12 tests
PASS
The source/live comparison found no application-code drift but did find exactly 70 extra files in /opt/mbweb/app.
They were classified as:
env_backup=2
bak=67
example=1
other=0
That classification matters.
There were no unknown live-only application files that needed to be reverse-engineered back into contrib/mbweb.
The extras were maintenance residue.
Examples included historical copies such as:
app.js.bak.*
lib/config.js.bak.*
lib/dashboardData.js.bak.*
lib/mediabotRepository.js.bak.*
and two .env.bak* files.
.env backup had unsafe permissionsThe content of .env and .env.bak* was deliberately not displayed during the audit.
Only metadata was inspected.
Observed permissions included:
-rw------- mediabot:mediabot .env
-rw------- mediabot:mediabot .env.bak.runtime-json-run-path.20260510-034029
-rw-r--r-- mediabot:mediabot .env.bak.20260424-021451
The last historical backup was world-readable.
Even though mbweb only serves explicitly configured public directories and not the application root, keeping historical environment backups with broad local read permissions is poor release hygiene.
For 3.5, old .env backup material should not accumulate inside the live application tree.
Nothing was deleted blindly.
Before touching the 70 extra runtime files, they were archived privately to:
/home/mediabot/backups/mb697_mbweb_before_20260823_164350/runtime-debris.tar.gz
The backup directory was restricted and the archive was made private.
Archive SHA-256:
28ba71b5dcf355588d080c5efbdf720fc7e8cee8213bad11f1e3fee1586f5781
The canonical runtime manifests were also backed up before deployment.
No .env value or historical secret was printed into the terminal transcript.
After the rehearsal succeeded, the canonical refreshed lockfile was deployed to:
/opt/mbweb/app/package-lock.json
The service was stopped deliberately for the dependency replacement.
A clean production install then ran with:
npm ci \
--omit=dev \
--ignore-scripts \
--no-audit \
--no-fund
The install succeeded:
RC_INSTALL=0
ROLLBACK=NO
The rollback path was prepared but never needed.
Before deployment:
MainPID=228188
NRestarts=0
After controlled restart:
MainPID=3856992
NRestarts=0
ActiveState=active
The PID change is expected because this was an intentional stop/start cycle.
The important part is:
NRestarts=0
There was no systemd crash/restart loop.
The Node listener was detected on:
127.0.0.1:4002
A request to / returned:
HTTP 404
That is not considered a health failure here: it proves that the Node process is listening and answering HTTP, while / is not necessarily the application’s configured base route.
A route-aware health check belongs to the upcoming functional mbweb pass.
The deployed runtime was audited again after npm ci.
Result:
critical:0
high:0
moderate:0
low:0
RC_NPM_AUDIT=0
npm ls --omit=dev --depth=0 also returned cleanly:
RC_NPM_LS=0
The source and live npm contracts remained identical:
package_json=MATCH
package_lock=MATCH
Only after all of the following were true:
backup PASS
npm install PASS
service active
HTTP listener responding
npm audit clean
npm ls clean
package.json MATCH
package-lock.json MATCH
were the 70 historical extra files removed from /opt/mbweb/app.
Result:
removed=70
RC_CLEAN=0
The live .env was retained and restricted to private permissions.
After cleanup, the same application-tree comparison was run again.
Result:
missing=0
extra=0
changed=0
This is one of the strongest results of the entire round.
Outside intentional runtime state such as:
.env
node_modules/
package manifests handled explicitly
the deployed mbweb application tree is now identical to the canonical source tree.
That makes future deployment, rollback and debugging much less ambiguous.
The relevant Node/repository security contracts passed again after the live deployment:
2/2 files
12/12 tests
PASS
The source tree contained exactly the intended changes:
M CHANGELOG.md
M contrib/mbweb/package-lock.json
A t/cases/911_mb697_mbweb_dependency_security.t
No unrelated source modification entered this checkpoint.
The mbweb dependency/runtime hardening was committed as:
581cc7e 🛡️ Fortify the Web Ward and Sweep the Runtime Cobwebs
The version advanced to:
3.4dev-20260823_165236
Commit scope:
CHANGELOG.md
VERSION
contrib/mbweb/package-lock.json
t/cases/911_mb697_mbweb_dependency_security.t
Summary:
4 files changed
171 insertions
49 deletions
The commit was pushed successfully:
7a46617..581cc7e master -> master
During the final fetch, GitHub exposed two new Dependabot branches:
dependabot/npm_and_yarn/contrib/mbweb/body-parser-2.3.0
dependabot/npm_and_yarn/contrib/mbweb/qs-6.15.3
Those branch targets correspond exactly to the versions already integrated manually and validated in this MB697 round:
body-parser=2.3.0
qs=6.15.3
The push output still displayed GitHub’s previous:
1 moderate
1 low
vulnerability summary immediately after the push.
The local canonical lockfile and the deployed runtime both report:
npm audit = 0 vulnerabilities
So the remaining GitHub banner should be treated as pending repository-side refresh until verified, not as evidence that the local remediation failed.
The next release-hardening pass should re-check the GitHub/Dependabot state before calling this point administratively closed.
A fresh private project snapshot taken after this work reports:
VERSION=3.4dev-20260823_165236
and contains:
contrib/mbweb/package-lock.json
t/cases/911_mb697_mbweb_dependency_security.t
CHANGELOG entry: ### mb697 — mbweb dependency and runtime hardening
The lockfile in that snapshot resolves:
express=5.2.1
body-parser=2.3.0
qs=6.15.3
express-rate-limit=ABSENT
This confirms that the checkpoint is present in the current source snapshot, not merely in an earlier terminal state.
The pre-release roadmap is now deliberately narrow.
MB695 database compatibility / drift CLOSED
MB696 secrets / TLS / Git hygiene CLOSED
MB697 runtime + mbweb stabilization IN PROGRESS
MB698 install / upgrade / rollback NEXT LATER
MB699 3.5 release-candidate qualification FINAL GATE
3.5 EXPLICIT GO ONLY
The first technical foundation of MB697 is now complete:
mbweb canonical npm contract established
known npm advisories remediated locally
clean npm install proven
live npm deployment proven
runtime debris privately archived and removed
source/live application drift zero
systemd restart clean
regression test 911 added
This checkpoint is deliberately not being confused with “mbweb is finished”.
The next MB697 phase is the functional review.
That will start from real operator/user observations rather than another generic automated audit.
Items may include, depending on the actual feedback:
functional bugs
missing or confusing web actions
authentication/session behavior
dashboard usefulness
runtime diagnostics
UX inconsistencies
web/IRC state consistency
error reporting
health/readiness route
operational controls
Each observation will be classified as:
BLOCKER 3.5
BUG
SECURITY
RELIABILITY
UX / FUNCTIONAL
DOCUMENTATION
POST-3.5
The rule remains simple:
If it threatens the reliability, security, installability or credible operation of 3.5, fix it before release. If it is merely an attractive improvement, move it to the post-3.5 backlog.
After MB697 functional/runtime stabilization:
The project must prove that an administrator can actually perform:
fresh install
stable 3.3 -> 3.5 upgrade
recent 3.4dev -> 3.5 upgrade
rollback / recovery
with documented service, database and mbweb ordering.
A fresh Debian 13 installation is now considered a real release gate before final 3.5 qualification.
It no longer belongs in an indefinite “nice to test someday” bucket.
At MB699, development stops.
The candidate must be challenged across:
source hygiene
secret scanning
database compatibility
migrations
Doctor
fast/full tests
DEV runtime
Undernet runtime
mbweb
Debian 12
Debian 13 fresh install
installation documentation
upgrade documentation
rollback documentation
release artifact hygiene
known residual risks
The desired final condition is:
BLOCKERS=0
Only then is a technical GO recommendation appropriate.
And even then:
the move from
3.4dev-*to stable3.5remains an explicit release decision.
This was not a flashy feature round.
It was the kind of work that determines whether a stable release is merely functional on the maintainer’s machine or genuinely reproducible and supportable.
mbweb now has:
npm ci proof;The web ward is considerably less improvised than it was a few hours ago. 🛡️🕸️🪄
Next stop: the actual functional mbweb review — driven by real remarks, not theoretical polishing.
You must be logged in to reply.