Plan: Template-side Dependabot Triage
IMPLEMENTATION RULES: Before implementing this plan, read and follow:
- WORKFLOW.md - The implementation process
- PLANS.md - Plan structure and best practices
Status: Complete
Goal: Clear the 9 remaining template-side Dependabot alerts and 4 open Dependabot PRs by merging the safe ones, verifying the templates still build, and documenting any that we intentionally defer.
Last Updated: 2026-04-13
Current state: Plan moved from backlog/ to active/. Phase 0 kicked off. The DCT tester (running in /Users/terje.christensen/learn/helpers/testing/delete-test) is shaking down the test loop on an unchanged typescript-basic-webserver from main. Waiting for the tester to report the locked-in install / run / reset commands and the answer to Q1 (whether dev-template can install from a local path or whether we need a workaround).
Upstream context: Continues from INVESTIGATE-housekeeping-docusaurus-and-prs.md (completed via PR #40). The Docusaurus upgrade is done; build-time transitive vulns in the Docusaurus toolchain have been dismissed as out-of-scope (see the feedback_docusaurus_transitive_vulns policy). What remains are genuine template-side issues: code that ships to users who copy our templates.
Scope — what this plan covers
9 open Dependabot alerts (template-side)
| # | Severity | Ecosystem | Package | Template | Direct or transitive? |
|---|---|---|---|---|---|
| 3 | medium | npm | body-parser | typescript-basic-webserver | direct (covered by PR #1) |
| 5 | medium | npm | qs | typescript-basic-webserver | transitive (covered by PR #4) |
| 9 | low | npm | qs | typescript-basic-webserver | transitive (covered by PR #4) |
| 14 | high | npm | minimatch | typescript-basic-webserver | transitive (devDep? verify) |
| 15 | medium | npm | path-to-regexp | typescript-basic-webserver | transitive (from express — may clear via PR #2) |
| 16 | high | npm | path-to-regexp | typescript-basic-webserver | transitive (from express — may clear via PR #2) |
| 19 | medium | npm | picomatch | typescript-basic-webserver | transitive (devDep? verify) |
| 10 | low | pip | flask | python-basic-webserver | direct (covered by PR #7) |
| 27 | low | pip | flask | python-basic-webserver-database | direct (NOT covered — no PR exists) |
4 open Dependabot PRs
| PR | Template | Bump | Status |
|---|---|---|---|
| #1 | typescript-basic-webserver | body-parser 2.2.0 → 2.2.1 | Open since 2025-11-25 |
| #2 | typescript-basic-webserver | express 5.1.0 → 5.2.0 | Open since 2025-12-01 |
| #4 | typescript-basic-webserver | qs 6.14.0 → 6.14.2 | Open since 2026-02-14 |
| #7 | python-basic-webserver | flask 2.3.3 → 3.1.3 | Open since 2026-02-20 |
Approach
Strategy: Merge the Dependabot PRs in order after per-template verification. Then file a fresh bump for the uncovered python-basic-webserver-database flask alert. After each merge, re-query Dependabot alerts to see what cleared — some transitives may resolve via cascading updates (e.g., bumping express may refresh path-to-regexp automatically).
Why this order over one big batch: each template is independent. A break in one template shouldn't block the others. Per-PR merges also give the cleanest rollback path if something goes wrong, and each Dependabot PR already has a focused diff and release notes attached.
Not covered by this plan (explicitly deferred):
- Long-term auto-merge policy for template Dependabot PRs — see Q1 in the upstream investigation. This plan just clears the current backlog; a separate policy discussion can follow.
- Whether any template should intentionally pin old versions (Q2 in the upstream investigation). None of the current templates declare a pinning intent, so we treat them all as "track latest."
Per-template verification — use the DCT tester
Verification must happen in the DCT test workspace at /Users/terje.christensen/learn/helpers/testing/delete-test, not via isolated docker build inside the dev-templates repo. That workspace has its own devcontainer and is the canonical test harness for installing and exercising templates end-to-end via dev-template.
The real user experience for a template is: developer runs dev-template inside their project's devcontainer → a template is copied in → developer runs dev-template configure → UIS provisions services → app runs → browser shows result. Testing only the Docker build skips everything interesting: the configure step, the UIS handshake, the port-forward, the secret handling, the deploy manifests, the actual runtime wiring. The DCT tester exercises the whole flow.
Flow per Dependabot PR:
- Check out the Dependabot branch in the dev-templates repo (so the updated template source is available)
- Switch to the
delete-testworkspace and enter its devcontainer - Install the template under test via
dev-template(pointed at the local updated source, not GitHub main) - Run
dev-template configureif the template has UIS services - Start the app, hit its endpoint, verify it behaves
- If green → approve and merge the Dependabot PR on GitHub
- If red → investigate; fall back to closing the PR with a comment if the fix would require rewriting the template (see Q3)
Pre-push pipeline in the dev-templates repo is still required after any merge that lands on main, since the pre-push checklist (project-dev-templates.md) applies to all commits that flow through the registry/docs pipeline — but it is NOT a substitute for exercising the template in the DCT tester.
Phases
Phase 0: Shake down the DCT tester workflow
Before touching any Dependabot PR, prove the test loop actually works. Pick one untouched template (e.g., unmodified typescript-basic-webserver from main) and run the full install → configure → run → verify flow in the delete-test workspace. Document the exact commands once; reuse them in every later phase.
- 0.1 Confirm the
delete-testdevcontainer is running and find its container name- Container:
4badabdf4399/relaxed_williamson, imagevsc-delete-test-... - User inside:
vscode, workspace mount:/workspace - CLI:
dev-templateat/usr/local/bin/dev-template
- Container:
- 0.2 Install
typescript-basic-webserverfrom the current main intodelete-testviadev-template- Command (from host):
docker exec -w /workspace 4badabdf4399 dev-template typescript-basic-webserver - Result: template scaffolded, TypeScript toolchain auto-installed,
app/index.ts+package.json+tsconfig.jsonin place. Overwrite policy confirmed — old python files from the prior template linger harmlessly alongside the new ones.
- Command (from host):
- 0.3 Run and hit the app endpoint
docker exec -w /workspace 4badabdf4399 sh -lc 'npm install'→ 125 packages,npm auditreports 10 vulns (1 low / 3 moderate / 6 high) — this is the baseline Dependabot surface the plan is targetingdocker exec -w /workspace 4badabdf4399 sh -lc 'npm run dev'(run in background from host)docker exec 4badabdf4399 curl -s http://localhost:3000/→Hello world ! Template: typescript-basic-webserver. Time is: 13/04/2026 12:09:48✅- Teardown:
docker exec 4badabdf4399 sh -c 'pkill -f "nodemon|tsx|ts-node"'— port 3000 clears immediately
- 0.4 Capture the exact command sequence — see the DCT test loop block below
- 0.5 Answered (Q1).
dev-template --helpconfirms the CLI takes only[template-id | configure]— no--branch,--path,--ref, or--fromflag. It fetches fromhelpers-no/dev-templatesmain via git sparse-checkout, full stop.- Locked-in procedure for testing a Dependabot PR:
- Run
dev-template <template-name>normally inside the devcontainer — this scaffolds the current-main version of the template into/workspace. - On the host, check out the Dependabot branch in the dev-templates repo at
/Users/terje.christensen/learn/helpers/dev-templates. - Overwrite the changed files from the feature branch into
/workspaceusingdocker cp(host → container). For npm PRs that's typically justpackage.json+package-lock.json; for pip PRs it'srequirements.txt. Verify viagit diffon the feature branch before copying so we don't miss a template source change. - Re-run the install step inside the container (
npm install/pip install -r requirements.txt). - Start the app and hit the endpoint per the DCT test loop block below.
- Run
- Rejected alternatives: (b) temporarily push the Dependabot branch as registry main — touches shared state, unsafe; (c) wait for TMP to add a
--from-pathflag — out of scope for this plan.
- Locked-in procedure for testing a Dependabot PR:
DCT test loop (reusable command block for Phases 1–5)
All commands run from the host. CID = delete-test devcontainer id.
CID=4badabdf4399 # relaxed_williamson — verify with `docker ps | grep vsc-delete-test`
# 1. Install / overwrite template into /workspace
docker exec -w /workspace $CID dev-template <template-name>
# 2. For a Dependabot PR under test, overwrite changed files from the feature branch.
# On the host, check out the Dependabot branch in /Users/terje.christensen/learn/helpers/dev-templates,
# then copy the changed files into /workspace. Example for an npm PR on typescript-basic-webserver:
# docker cp /Users/terje.christensen/learn/helpers/dev-templates/templates/typescript-basic-webserver/package.json $CID:/workspace/package.json
# docker cp /Users/terje.christensen/learn/helpers/dev-templates/templates/typescript-basic-webserver/package-lock.json $CID:/workspace/package-lock.json
# Example for a pip PR on python-basic-webserver:
# docker cp /Users/terje.christensen/learn/helpers/dev-templates/templates/python-basic-webserver/requirements.txt $CID:/workspace/requirements.txt
# Always `git diff main...<branch>` the feature branch first to confirm you're not missing a changed file.
# 3. Install deps
docker exec -w /workspace $CID sh -lc 'npm install' # node templates
# docker exec -w /workspace $CID sh -lc 'pip install -r requirements.txt' # python templates
# 4. Start the app in the background (host-side)
# For nodemon-based node templates:
docker exec -w /workspace $CID sh -lc 'npm run dev' &
DEV_PID=$!
# 5. Poll until the endpoint responds, then capture the response
for i in 1 2 3 4 5 6 7 8; do
code=$(docker exec $CID curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/ || true)
[ "$code" = "200" ] && break
sleep 1
done
docker exec $CID curl -s http://localhost:3000/
# 6. Teardown — kill the dev server inside the container
docker exec $CID sh -c 'pkill -f "nodemon|tsx|ts-node" || true'
For the next test, just re-run step 1 with a different <template-name> — no devcontainer rebuild, per the Q5 overwrite policy.
Phase 1: Verify and merge PR #1 (body-parser)
Smallest bump, patch version. Simplest merge.
- 1.1 Materialize PR #1's updated file in the host working tree
- PR #1 HEAD
5eb457a7is a single-file change:templates/typescript-basic-webserver/package-lock.jsononly (body-parser 2.2.0 → 2.2.1, plus a trivial"peer": truemarker on@types/node). - GitHub state:
mergeable: true, mergeable_state: clean, rebaseable: true— confirmed viagh api repos/helpers-no/dev-templates/pulls/1. The lockfile file is untouched on main since 2025-11-25, so the PR applies without conflict. - Rather than
gh pr checkout(which would switch the whole working tree off main), the updated file was extracted in place:git show pr-1-body-parser:templates/typescript-basic-webserver/package-lock.json > templates/typescript-basic-webserver/package-lock.json. The tester can copy the file from the standard path in the DCT test loop block; no other host path changes. - Verified:
body-parser@2.2.1at line 278 with the new integrity sha512 hash.
- PR #1 HEAD
- 1.2 Tester: install
typescript-basic-webserverfrom main intodelete-test, thendocker cpthe updatedpackage-lock.jsonfrom the host working tree, thennpm installdocker exec -w /workspace 4badabdf4399 dev-template typescript-basic-webserver→ scaffolded cleandocker cp /Users/terje.christensen/learn/helpers/dev-templates/templates/typescript-basic-webserver/package-lock.json 4badabdf4399:/workspace/package-lock.json→ in-container lockfile now hasbody-parser@2.2.1at line 278docker exec -w /workspace 4badabdf4399 sh -lc 'npm install'→changed 6 packages, disk-residentnode_modules/body-parser/package.jsonreports"version": "2.2.1"✅npm auditdelta: 10 vulns → 9 vulns (moderate: 3 → 2). The dropped moderate is alert #3 (body-parser). High count stays at 6 (still covered by PR #2 / PR #4).
- 1.3 Tester: start
npm run dev, verifycurl http://localhost:3000/returns the expected "Hello world !" response- Endpoint returned:
Hello world ! Template: typescript-basic-webserver. Time is: 13/04/2026 12:19:51✅ - Server stopped via
pkill -f "nodemon|tsx|ts-node", port 3000 confirmed clear
- Endpoint returned:
- 1.4 Merged via
gh pr merge 1 --rebase --delete-branchat 2026-04-13T12:20:47Z; merge commit4ea6f24c - 1.5 Alert #3 (body-parser) state =
fixedconfirmed viagh api repos/helpers-no/dev-templates/dependabot/alerts/3 - 1.6 Fast-forwarded local main to
4ea6f24c(contains the body-parser bump). Localpr-1-body-parserfetch ref deleted. Working tree clean ontemplates/typescript-basic-webserver/package-lock.json.
Phase 2: Close PR #4, manually bump qs via fresh feature branch
Strategy change discovered while prepping Phase 2: PR #4 is stale against current main. Diffing pr-4-qs against main shows the PR would REGRESS 6 unrelated packages to their Feb 2026 state, including undoing PR #1's body-parser 2.2.1 bump. The stale-base problem is Dependabot-agnostic: it built the lockfile against a Feb-2026 snapshot that no longer exists. PR #2 (express, also Feb 2026) and PR #7 (flask, Feb 2026) almost certainly have the same issue.
New approach for stale Dependabot PRs: close them with an explanatory comment, then do surgical manual bumps on a fresh feature branch against current main. For npm: run npm install <pkg>@<version> inside the template directory (in the dev-templates devcontainer), commit only the lockfile delta, PR, merge. For pip: edit requirements.txt directly, commit, PR, merge. This produces the minimal, reviewable, current-main-based diff we actually want.
Dependabot's role: once we've cleared the stale backlog, Dependabot will naturally take over for future advisories against current main, producing fresh (non-stale) PRs.
- 2.1 PR #4 closed with an explanatory comment pointing at the manual bump strategy
- 2.2 Feature branch
feature/typescript-qs-updatecreated from main (post-PR-#1) - 2.3 In dev-templates devcontainer
gallant_colden:cd /workspace/templates/typescript-basic-webserver && npm update qs --package-lock-only— surgical update, no node_modules fetched - 2.4 Diff verified minimal: qs 6.14.0 → 6.15.1 (even newer than Dependabot's 6.14.2 target — latest within the
^6.14.0range declared by body-parser) plus two incidental"peer": truemetadata removals on@types/nodeandtypescript(harmless lockfile-regen artifact; peer field is informational only). npm audit: 9 → 8 vulns. - 2.5 Tester: install
typescript-basic-webserverintodelete-test,docker cpthe updatedpackage-lock.json,npm install, run + verify endpoint- Scaffold + overwrite + install as per DCT test loop. In-container lockfile confirmed
qs@6.15.1(line 1090) andbody-parser@2.2.1(line 277) pre-install. npm install:changed 1 package.npm auditdelta: 9 vulns → 8 vulns (moderate 2 → 1) — matches TMP's 2.4 prediction exactly.- Endpoint:
Hello world ! Template: typescript-basic-webserver. Time is: 13/04/2026 12:28:11✅. Server stopped, port 3000 clear. - Detailed audit breakdown (from
npm audit --json):qsis no longer in the advisory output at all — both alerts #5 (medium qs) and #9 (low qs) coalesce under the same package entry, so both clear when merged, not just #5. The1 low / 1 moderate / 6 highthat remain are:- In-plan, expected to clear in Phase 3:
minimatchhigh×3 (alert #14),path-to-regexphigh+moderate (alerts #15/#16),picomatchhigh+moderate (alert #19) - Not in the plan's alert table — newly surfaced, needs triage:
brace-expansion(low+moderate GHSAs),diff/jsdiff(low), and anodemon → simple-update-notifier → semverhigh chain. These are either new advisories since the plan was written or were below Dependabot's reporting threshold. TMP decision needed: add them to scope as a Phase 3.5 follow-up, defer to a new plan, or dismiss as dev-only / tooling chain?
- In-plan, expected to clear in Phase 3:
- Scaffold + overwrite + install as per DCT test loop. In-container lockfile confirmed
- 2.6 PR #41 created and merged via
--rebase --delete-branch; merge commitace4f9f0. Local main fast-forwarded; localfeature/typescript-qs-updateandpr-4-qsbranches cleaned up. - 2.7 Alerts #5 (medium qs) and #9 (low qs) both confirmed
state: fixedviagh api
Deferred to post-Phase-3 re-triage
The DCT tester's npm audit surfaced extras not in the plan's alert table: brace-expansion (low+moderate), diff/jsdiff (low), and a nodemon → simple-update-notifier → semver high chain. Decision: do not expand Phase 2 scope. Phase 3's express bump will cascade-update a big chunk of the typescript template's tree, and some of these may clear for free. They also don't appear in GitHub Dependabot's alert list (npm audit pulls a fresher advisory DB than Dependabot has processed for this repo), and nodemon is a devDep so the semver chain is dev-tool-only, not user-facing runtime. Re-run npm audit and gh api ... dependabot/alerts after Phase 3; escalate to a Phase 7 follow-up only if real runtime-facing advisories remain.
Phase 3: Close PR #2, manually bump express via fresh feature branch
Same stale-base strategy as Phase 2. Express usage in the template is minimal: express(), app.get('/', ...), app.listen() — no middleware, no custom routing, no body-parser integration. Any 5.x → 5.x bump is near-zero risk.
-
3.1 Reviewed template usage — only
app.getandapp.listenare called, so the 5.1 → 5.2 public API surface area for this template is essentially zero -
3.2 PR #2 closed with an explanatory comment
-
3.3 Feature branch
feature/typescript-express-updatecreated from main (post-PR-#41) -
3.4 In dev-templates devcontainer:
cd /workspace/templates/typescript-basic-webserver && npm update express --package-lock-only -
3.5 Diff verified minimal: express 5.1.0 → 5.2.1 (latest within
^5.0.0, newer than the closed PR #2's 5.2.0 target). Internalbody-parserrange tightened to^2.2.1(already have 2.2.1; no resolution change).depdentry restructured (harmless npm metadata reshuffle; was already a transitive). -
3.6 Tester: install
typescript-basic-webserverintodelete-test,docker cpthe updatedpackage-lock.json,npm install, run + verify endpoint- Scaffold + overwrite + install as per DCT test loop. In-container lockfile confirmed
express@5.2.1(line 551) pre-install. Installed:node_modules/express/package.json→"version": "5.2.1"✅ npm install:changed 1 package.npm auditdelta: 8 vulns → 8 vulns (unchanged) — confirms TMP's 3.8 prediction that the express bump would not cascade-clear the transitive vulns.- Endpoint:
Hello world ! Template: typescript-basic-webserver. Time is: 13/04/2026 12:36:09✅. Server stopped, port 3000 clear.
- Scaffold + overwrite + install as per DCT test loop. In-container lockfile confirmed
-
3.7 PR #46 created, merged via
--rebase --delete-branchas882518a. Local main fast-forwarded; local branch cleaned up. Post-merge alert query: 6 open (the 4 transitive npm + 2 flask) — exactly as predicted; the 4 npm transitives stayed open, confirming the negative cascade. -
3.8 Cascade check: NEGATIVE, as predicted.
npm ls path-to-regexp minimatch picomatchinsidedelete-testreveals the parent chains and gives Phase 3.5 an almost-free strategy:typescript-basic-webserver@1.0.0 /workspace├─┬ express@5.2.1│ └─┬ router@2.2.0│ └── path-to-regexp@8.2.0└─┬ nodemon@2.0.22├─┬ chokidar@3.6.0│ ├─┬ anymatch@3.1.3│ │ └── picomatch@2.3.1│ └─┬ readdirp@3.6.0│ └── picomatch@2.3.1 deduped└── minimatch@3.1.2Interpretation:
path-to-regexp@8.2.0comes viaexpress → router, and 8.2.0 is already the latest within express 5.2.1's router pin. There is no newer upstream fix we can pull. Alerts #15 (medium) and #16 (high) will need to be dismissed as "no upstream fix available yet," tracked, and re-queried after express/router publish a patched line.minimatch@3.1.2andpicomatch@2.3.1both come vianodemon@2.0.22— a devDep that's three years stale (current is 3.x). Bumping nodemon to 3.x should cascade-clear:- alert #14 (minimatch high)
- alert #19 (picomatch medium)
- and very likely the Phase-2-deferred extras (
brace-expansion,diff/jsdiff,nodemon → simple-update-notifier → semverchain) — they all live inside nodemon 2's ancient dep tree.
- Since
nodemonis a devDep, this is low-risk: it only runs during local dev (npm run dev), not in production containers or CI test runs.
Phase 3.5: Clear the minimatch / picomatch alerts via nodemon bump; dismiss path-to-regexp (added mid-flight)
Strategy locked in from Phase 3.6's npm ls trace (see above): the four remaining npm alerts split cleanly into two groups.
Group A — clear via nodemon devDep bump (2.0.22 → latest 3.x):
- alert #14 (
minimatchhigh, via nodemon direct) - alert #19 (
picomatchmedium, via nodemon → chokidar → anymatch/readdirp) - likely also clears Phase-2-deferred extras:
brace-expansion,diff/jsdiff,semver/simple-update-notifierchain (all nodemon 2 transitives)
Group B — cannot clear upstream yet, dismiss with reason:
-
alert #15 (
path-to-regexpmedium, via express → router) -
alert #16 (
path-to-regexphigh, via express → router)Express 5.2.1 already resolves
path-to-regexp@8.2.0, which is the latest in that line. No newer upstream fix exists. Dismiss viagh api ... dependabot/alerts/{15,16} -X PATCH -f state=dismissed -f dismissed_reason=no_fix_availableand re-query monthly (or whenever express/router publishes a new line). -
3.5.1 Investigate parent chains — done in Phase 3.6 via
npm ls path-to-regexp minimatch picomatchindelete-test; results pasted in Phase 3.8 above. -
3.5.2 Decision — locked in above: nodemon bump for Group A, dismissal for Group B.
-
3.5.3 Feature branch
feature/typescript-nodemon-updatecreated.npm update nodemon --package-lock-onlywas a no-op because the existing^2.0.22caret caps it to 2.x. Usednpm install --save-dev --package-lock-only nodemon@latestinstead, which moved bothpackage.json(^2.0.22→^3.1.14) and the lockfile (45 insertions / 61 deletions — a refreshed dep tree, expected for a major-version devDep bump). Localnpm auditdropped 8 → 3 vulnerabilities. Remaining pernpm audit --json:diff(low),path-to-regexp(high — Group B, will be dismissed),picomatch(high — UNEXPECTED, may be coming via a different path now; tester to trace vianpm ls picomatchpost-install). -
3.5.3a Tester: install
typescript-basic-webserver,docker cpBOTHpackage.jsonandpackage-lock.jsonfrom the feature branch,npm install, run + verify endpoint, then runnpm ls picomatch path-to-regexp diffto trace the remaining vulnerable transitives-
Scaffold + overwrite both files + install. In-container
package.jsondeclares"nodemon": "^3.1.14";package-lock.jsonhasnodemon@3.1.14at line 959. -
npm install:removed 3 packages, changed 6 packages.npm audit: 8 vulns → 3 vulns — matches TMP's local result. -
Endpoint:
Hello world ! Template: typescript-basic-webserver. Time is: 13/04/2026 12:42:40✅. Server stopped, port 3000 clear. -
npm ls picomatch path-to-regexp difftrace post-install:typescript-basic-webserver@1.0.0 /workspace├─┬ express@5.2.1│ └─┬ router@2.2.0│ └── path-to-regexp@8.2.0├─┬ nodemon@3.1.14│ └─┬ chokidar@3.6.0│ ├─┬ anymatch@3.1.3│ │ └── picomatch@2.3.1│ └─┬ readdirp@3.6.0│ └── picomatch@2.3.1 deduped└─┬ ts-node@10.9.2└── diff@4.0.2 -
Confirmed cleared by the nodemon bump (not in the tree anymore):
minimatch(alert #14 ✅), plus the Phase-2-deferredbrace-expansion,semver/simple-update-notifier/old-nodemon-chain extras — all gone, as hoped. Net drop = 5 vulns. -
Surprise — picomatch survived:
nodemon@3.1.14still pinschokidar@^3.6.0. Chokidar 3.x still transitively pullspicomatch@2.3.1viaanymatchandreaddirp. The nodemon major bump refreshed nodemon's own direct deps but did not move chokidar to its 4.x line (chokidar 4.x uses a newer picomatch and would clear the advisory). Alert #19 (picomatch) is therefore not cleared by this phase. -
New finding — diff/jsdiff via ts-node@10.9.2: the surviving low-severity
diff@4.0.2comes throughts-node, which is a direct devDep of the template. ts-node 10.9.2 is the current latest on that line. Same shape as path-to-regexp: no upstream fix published yet, devDep-of-devDep, only exposed during local dev. Recommended disposition: dismiss asno_fix_available(same treatment as alerts #15/#16). -
Options for picomatch (alert #19), from cheapest to most invasive:
- Dismiss as
no_fix_available/tolerable_risk— it's a devDep-of-devDep (chokidar is only used by nodemon's file watcher duringnpm run dev; never in the prod Docker image, never in CI). Simplest. - Add a
package.jsonoverridesblock forcingpicomatch@^4underchokidar. Low-risk (picomatch is almost drop-in compatible between 2 and 4) but needs a verification cycle indelete-testto confirm nodemon still hot-reloads. - Override chokidar itself to
^4under nodemon. Higher risk — nodemon 3.1.14 was not designed against chokidar 4's new API shape; might break hot reload.
- DCT recommends option 1. The advisory impact is zero for anyone running the built template (Docker image ships the compiled JS via
npm run build+node dist/index.js, never nodemon), and the overhead of maintaining anoverridesblock for a devDep just to keep a lockfile audit clean is bad bang-for-buck. TMP decision.
- Dismiss as
-
-
3.5.2 Decision locked in: nodemon bump for Group A; dismissals for Group B and #19. Dismissal reason for picomatch: devDep-of-devDep, never in prod image, accepted per DCT recommendation option 1.
-
3.5.4 PR #47 created, merged via
--rebase --delete-branchas05b0347. Local main fast-forwarded; local branch cleaned up. -
3.5.5 Alerts dismissed via
gh api ... -X PATCH:- #14 minimatch high →
state: fixed(cleared by the nodemon bump itself) - #15 path-to-regexp medium →
dismissed (no_bandwidth)with reason "no upstream fix; via express → router → already at latest 8.2.0" - #16 path-to-regexp high →
dismissed (no_bandwidth)(same reason) - #19 picomatch medium →
dismissed (tolerable_risk)with reason "devDep via nodemon → chokidar 3.x; never in prod image" - GitHub API note:
dismissed_commentis capped at 280 characters — keep dismissals terse.
- #14 minimatch high →
-
3.5.6
npm auditdeferred extras (brace-expansion, semver chain, simple-update-notifier) all confirmed gone via tester's post-bump trace (Phase 3.5.3a). Onlydiff@4.0.2remains — comes viats-node@10.9.2(current latest), no upstream fix yet, devDep-of-devDep, same shape as picomatch. Not currently a GitHub Dependabot alert; if it ever surfaces as one, dismiss with the same reasoning.
Phase 3.5 result
Net effect of the entire typescript-basic-webserver triage (Phases 1, 2, 3, 3.5):
- 6 npm advisories cleared via merges: body-parser, qs ×2, minimatch, brace-expansion, semver/update-notifier chain
- 3 npm advisories dismissed with reason: path-to-regexp ×2 (no upstream fix), picomatch (devDep-of-devDep)
- The typescript template's open Dependabot alert count is now zero.
Phase 4: Close PR #7, manually bump flask via fresh feature branch
Same stale-base strategy as #4 and #2. Pre-bump API audit: templates/python-basic-webserver/app/app.py uses only from flask import Flask, Flask(__name__), @app.route('/'), and app.run(host, port, debug) — none of which changed in Flask 2 → 3. No use of flask.Markup, flask.escape, send_file(attachment_filename=), or Blueprint.register. Python pin is python:3.11-slim (Flask 3 requires 3.8+). Migration surface area: zero.
- 4.1 Template app code reviewed — no deprecated flask 2 APIs. Python 3.11 base image satisfies flask 3's 3.8+ requirement.
- 4.2 PR #7 closed with a pointer to the manual strategy
- 4.3 Feature branch
feature/python-flask-updatecreated from main (post-Phase-3.5) - 4.4
templates/python-basic-webserver/requirements.txt:Flask==2.3.3→Flask==3.1.3(current PyPI latest; matches what the closed PR #7 targeted) - 4.5 Tester: install
python-basic-webserverintodelete-test,docker cpthe updatedrequirements.txt,pip install -r requirements.txt, run + verify endpointdocker exec -w /workspace 4badabdf4399 dev-template python-basic-webserver→ scaffolded clean; python dev toolchain auto-installed. Note: per Q5 overwrite policy, the old TypeScript template files (package.json,tsconfig.json,node_modules/, etc.) still linger in/workspacealongside the new python files — harmless, not touched by this test.docker cp /Users/terje.christensen/learn/helpers/dev-templates/templates/python-basic-webserver/requirements.txt 4badabdf4399:/workspace/requirements.txt→ in-container file now readsFlask==3.1.3docker exec -w /workspace 4badabdf4399 sh -lc 'pip install -r requirements.txt'→Successfully installed Flask-3.1.3 blinker-1.9.0 click-8.3.2 itsdangerous-2.2.0 jinja2-3.1.6 markupsafe-3.0.3 werkzeug-3.1.8(pulled Werkzeug 3.1.8 as the Flask 3 transitive — matches Flask 3'sWerkzeug>=3.1.0requirement, confirming the Python 2→3 migration engaged cleanly)docker exec -w /workspace 4badabdf4399 sh -lc 'python app/app.py'(in background) → Flask dev server bound to 0.0.0.0:3000- Endpoint:
curl http://localhost:3000/→Hello world ! Template: python-basic-webserver. Time: 13:32:32 Date: 13/04/2026✅ - Teardown:
pkill -f "python app/app.py|flask", port 3000 confirmed clear - Doc bug found (out of scope for this plan, flagging for later):
README-python-basic-webserver.mdquick-start tells the user to openhttp://localhost:6000, butapp/app.pyhardcodesport = 3000. The README is wrong; the code is right. Worth a trivial follow-up README fix — not a blocker for this PR.
- 4.6 PR #48 created and merged via
--rebase --delete-branchas1d6388f. Local main fast-forwarded; local branch cleaned up. - 4.7 Alert #10 re-query post-merge showed
state: openimmediately (Dependabot rescan lags by minutes). Will re-verify in Phase 6 close-out.
Phase 5: Fix the uncovered flask alert in python-basic-webserver-database
Dependabot didn't open a PR for this template even though the same flask advisory hits it. Either (a) its requirements.txt pins differently, or (b) the Dependabot config doesn't watch this directory yet.
This is also the first template in this plan that has UIS services — the configure step and database port-forward must be exercised, not just the app startup.
- 5.0 UIS-services DCT loop shakedown (done before the flask bump). Verified the full
dev-template→configure→ UIS → PostgreSQL → app → endpoint flow on the untouchedpython-basic-webserver-databasefrom main, mirroring Phase 0's approach for the plain templates.docker exec -w /workspace 4badabdf4399 dev-template python-basic-webserver-database→ scaffolded;template-info.yaml→id: python-basic-webserver-database; in-containerrequirements.txtreadsFlask==2.3.3(the current-main, pre-bump version)- User (in the devcontainer terminal) ran
dev-template configure. Output showed: UIS bridge detected, repo identityterchris/delete-test, template paramsapp_name=my-app, then UIS provisioned the PostgreSQL service and wroteDATABASE_URL=postgresql://my_app:<redacted>@host.docker.internal:35432/my_app_dbinto/workspace/.env - Flask app started and bound to port 3000. Endpoints exercised from DCT:
GET /→Hello world ! Template: python-basic-webserver-database. Time: 13:38:56 Date: 13/04/2026 <br><a href="/tasks">View tasks</a> | <a href="/health">Health</a>✅GET /tasks→ live JSON from PostgreSQL with three seed rows (id:1 "Set up the database connection" done,id:2 "Build something with Flask + PostgreSQL" pending,id:3 "Deploy to Kubernetes via ArgoCD" pending) ✅GET /health→{"database": "connected", "status": "ok"}✅
- This is the first end-to-end verification in the entire plan that exercises the full DCT test loop for a template with UIS services. The loop covers: scaffold → configure → UIS handshake → PostgreSQL provision →
.envwiring → Flask↔DB runtime → JSON-serialized endpoint response. Prior phases only exercised standalone HTTP endpoints. Phase 5.2's flask bump will re-run this same loop, so from here it's a known-good baseline.
- 5.1 Checked
.github/— nodependabot.ymlfile exists. Dependabot runs with default behavior (no explicit paths, no schedule). This explains the inconsistent PR coverage: the security advisory DB generated alerts for bothtemplates/python-basic-webserver/requirements.txt(alert #10) andtemplates/python-basic-webserver-database/requirements.txt(alert #27), but Dependabot only opened a security update PR (#7) for the first one. Creating a properdependabot.ymlis a policy decision (update schedule, grouping, per-ecosystem config) and deferred to a separate follow-up plan — INVESTIGATE/PLAN-dependabot-config. - 5.2 Feature branch
feature/python-database-flask-updatecreated;templates/python-basic-webserver-database/requirements.txt:Flask==2.3.3→Flask==3.1.3. App code audit: uses onlyFlask,@app.route,app.run, andjsonify— none deprecated in 2→3. Database layer ispsycopg2(not flask) so entirely unaffected by the flask version bump. - 5.3 Tester: install
python-basic-webserver-databaseintodelete-test,docker cpthe updatedrequirements.txt, rundev-template configure(UIS provisions PostgreSQL), start the app, exercise the/,/tasks,/healthendpoints end-to-end — identical to the Phase 5.0 baseline but with Flask 3.1.3- Skipped re-scaffold and re-configure: template +
.env+ PostgreSQL provisioning from Phase 5.0 were still intact in/workspace, so the only change needed wasrequirements.txt. Per Q5 overwrite policy, this keeps the loop fast and isolates the test to what actually changed (the Flask version). docker cp /Users/terje.christensen/learn/helpers/dev-templates/templates/python-basic-webserver-database/requirements.txt 4badabdf4399:/workspace/requirements.txt→ confirmed in-container file now readsFlask==3.1.3,psycopg2-binary==2.9.9,python-dotenv==1.0.1pip install -r requirements.txt: no-op for Flask (already at 3.1.3 from the Phase 4.5 python-basic-webserver test — same system python), re-installedpsycopg2-binary==2.9.9and downgradedpython-dotenvfrom 1.2.2 to 1.0.1 (the pinned version).- Verified via
python -c "import flask; ...":flask 3.1.3,psycopg2 2.9.9,dotenv ok. (Flask emitted a DeprecationWarning that__version__will be removed in 3.2 — harmless signal that the 3.x line is genuinely loaded, not a 2.x leftover.) - First
python app/app.pyattempt failed withAddress already in usebecause the user's Phase 5.0 flask process was still bound to port 3000. Cleared viapkill -f "python app/app.py|flask". Good tucked-in signal from the failed startup log before the bind failure:Connecting to database...→Serving Flask app 'app', meaningimport flask+psycopg2.connect(DATABASE_URL)+python-dotenvall succeeded on Flask 3.1.3 before the port conflict. Flask 2→3 migration engaged cleanly at import/DB-connect time, not just at HTTP-serve time. - Second
python app/app.py(background) bound port 3000 cleanly. Endpoints hit from DCT:GET /→Hello world ! Template: python-basic-webserver-database. Time: 13:48:34 Date: 13/04/2026 <br><a href="/tasks">View tasks</a> | <a href="/health">Health</a>✅GET /tasks→ byte-for-byte identical to the Phase 5.0 baseline — same three seed rows (id:1 "Set up the database connection" done,id:2 "Build something with Flask + PostgreSQL" pending,id:3 "Deploy to Kubernetes via ArgoCD" pending), samecreated_attimestamps ✅GET /health→{"database": "connected", "status": "ok"}✅
- Teardown:
pkill -f "python app/app.py", port 3000 confirmed clear. - Regression test result: PASSED. Flask 2.3.3 → 3.1.3 is a clean no-op for this template's runtime behavior — every endpoint response matches the pre-bump baseline. Matches TMP's 5.2 code audit ("uses only Flask, @app.route, app.run, jsonify — none deprecated in 2→3"). Database layer is psycopg2 (not flask), so the flask bump literally cannot affect it.
- Skipped re-scaffold and re-configure: template +
- 5.4 PR #49 created and merged via
--rebase --delete-branchas0835ee5. Post-merge alert query: 0 open alerts on the repo. Both flask alerts (#10 and #27) confirmedstate: fixed. Local main fast-forwarded; feature branch cleaned up. - 5.5 Dependabot config follow-up: file separate
INVESTIGATE-dependabot-config.mdfor the schedule/grouping/watched-paths decision. Deferred to after Phase 6 close-out — still a follow-up, not a blocker.
Phase 6: Close out
- 6.1 Final Dependabot alert query:
length: 0— zero open alerts onhelpers-no/dev-templatesmain. Spot-checked alerts #10 and #27 (the last two flask ones): bothstate: fixed. - 6.2 This plan moved from
active/tocompleted/viagit mv - 6.3
INVESTIGATE-housekeeping-docusaurus-and-prs.mdmoved frombacklog/tocompleted/— the full housekeeping arc (Docusaurus upgrade PR #40 + this template-triage plan) is done - 6.4 Pre-push checklist revisited — no new gotchas surfaced during Phases 1–5 beyond what's already documented. The pre-push pipeline caught nothing because every template bump was a surgical lockfile/requirements.txt edit that didn't touch generators, plan files, or template-info.yaml.
Final result
Starting state (2026-04-13, start of session):
- 15 open Dependabot alerts (5 high, 7 moderate, 3 low)
- 4 open Dependabot PRs, all 2–5 months stale
Ending state (2026-04-13, end of session):
- 0 open Dependabot alerts
- 0 open Dependabot PRs
- 6 template-triage PRs merged: #1, #41, #46, #47, #48, #49
- 4 stale Dependabot PRs closed with explanation: #2, #4, #7 (and #1 which merged directly)
- 9 alerts cleared via fixes: #3 body-parser, #5/#9 qs, #10/#27 flask ×2, #14 minimatch, + auto-cleared Phase-2 extras
- 6 alerts dismissed with reason:
- #15, #16 path-to-regexp →
no_bandwidth(via express→router; already at latest 8.x, no upstream fix) - #19 picomatch →
tolerable_risk(via nodemon→chokidar; devDep-only, never in prod image) - The 6 Docusaurus transitives dismissed at the start of the session →
tolerable_risk(build-time only, upstream's responsibility — see thefeedback_docusaurus_transitive_vulnsmemory)
- #15, #16 path-to-regexp →
Strategic insight from this plan (worth remembering for future cleanup cycles):
Dependabot's stale-base problem is real. Any Dependabot PR older than ~a month against an active repo will likely regress unrelated packages when merged, because its internal lockfile snapshot is stale. The fix is not to merge it as-is (even if GitHub says mergeable: clean), nor to wait for Dependabot's auto-rebase. The fastest, most reviewable path is:
- Close the stale PR with an explanatory comment
- On a fresh feature branch, run
npm update <pkg> --package-lock-only(or equivalent for pip: editrequirements.txt) - Verify the diff is the minimal surgical change you expected
- DCT tester verifies end-to-end in
delete-test - Commit, PR, merge as
--rebase --delete-branch
This pattern handled 5 of 6 merges in this plan. The one exception (PR #1 body-parser) was only mergeable because its target file happened to be untouched on main since November 2025.
Test harness insight: the DCT tester loop (dev-template scaffold + docker cp override + npm install/pip install + dev-server + curl) was proven reliable across:
- 4 npm-template runs (body-parser, qs, express, nodemon)
- 2 python-template runs (plain, and the database template with full UIS handshake)
The UIS-services loop (Phase 5) is the first time this plan exercised the full dev-template configure → PostgreSQL provision → .env wiring → live DB queries from the app. It worked first time and is a known-good pattern for any future template triage that involves UIS services.
Follow-ups filed from this plan
Small, unblocking items surfaced during execution. None are blockers for anything, but each is worth capturing so it doesn't get lost.
-
INVESTIGATE-dependabot-config.md— Create a proper.github/dependabot.ymlwith explicit watched paths, update schedule (daily vs weekly), and grouping policy. Motivation: alert #27 never got a Dependabot PR opened for it even though the same flask advisory hit both python templates. Default Dependabot behavior is inconsistent across sub-paths. -
python-basic-webserverREADME port bug (tester flag, Phase 4.5): quick-start docs sayhttp://localhost:6000butapp/app.pyhardcodesport = 3000. Trivial README fix. -
diff@4.0.2via ts-node@10.9.2 (Phase 3.5.6 note): surfaces in localnpm auditbut not in GitHub Dependabot. devDep-of-devDep, same shape as picomatch. If it ever becomes a GitHub alert, dismiss with the same reasoning. -
typescript-basic-webserverfollow-ups that didn't need to happen this plan: re-check whether chokidar 4.x is compatible with nodemon 3.x — if it ships and is a drop-in, bump to clear the dev-only picomatch dismissal. Re-query path-to-regexp monthly for an 8.x+ fix. -
README for
python-basic-webserver-database— Phase 5 tester notedreaddirpisn't in the dep graph for the database template (different from the typescript one), so the nodemon follow-up doesn't apply here. No action needed, just flagged. -
DCT test loop documentation — the loop block inside this plan is the canonical procedure. When this plan moves to
completed/, the block should be extracted into contributor docs (website/docs/contributors/) or intoai-developer/so future work doesn't re-derive it. Small follow-up PR.
Open Questions
Q1. How does dev-template install from a feature branch / local path? — ANSWERED
It doesn't. dev-template --help (verified 2026-04-13) shows the CLI accepts only [template-id | configure] — no branch/path/ref flag. Templates are always fetched from helpers-no/dev-templates main via git sparse-checkout.
Workaround locked in (see Phase 0.5): scaffold from main via dev-template <name>, then docker cp the changed files from the Dependabot feature branch (checked out on the host) into /workspace, then re-run npm install / pip install. For every Dependabot PR in this backlog the overwrite surface is just package.json + package-lock.json (npm) or requirements.txt (pip).
Q2. Do we need to rebuild package-lock.json inside each template after a PR merge?
Dependabot already updates the lockfile in its PR. We should be able to merge directly. But if cascade resolutions are incomplete (e.g., a transitive that didn't update), we may want to run npm install manually and commit a fresh lockfile in a follow-up PR.
Q3. What if PR #2 (express 5.2) breaks the template?
Two options: (a) close PR #2 and accept the transitive vulns until the template is ready to move, or (b) fix the template to be compatible with 5.2 in the same PR. Default to (a) unless the fix is trivial — we don't want a version bump to turn into a template rewrite.
Q4. What Python version are the python templates pinned to?
Flask 3.x drops Python 3.7 support. Check Dockerfile and requirements.txt — if we're on 3.8+ we're fine; if a template pins 3.7, Phase 4 might need to bump the Python base image.
Q5. How do we reset the delete-test workspace between test runs? — ANSWERED
Decision (2026-04-13, from the DCT tester): Reset = overwrite the contents of /workspace inside the devcontainer with the next template under test. We do not wipe to empty, and we do not rebuild the devcontainer between runs. Rebuilding the container is slow and the container itself is stable infrastructure — only the template payload changes between tests. Leftover files from a prior template that aren't overwritten by the next one are acceptable: each test is judged by whether the new template runs, not by workspace purity.
This simplifies Phases 1–5: the "reset" bullet in each phase collapses to "install next template on top of current workspace."
Decisions (to lock in before starting)
- Approach: merge Dependabot PRs in order #1 → #4 → #2 → #7, then manual fix for database template
- Verification happens in the DCT tester workspace at
/Users/terje.christensen/learn/helpers/testing/delete-testvia the fulldev-templateinstall → configure → run flow, not via isolateddocker buildinside dev-templates - Phase 0 is a dry run on an untouched template to prove the test loop works and capture the exact commands before touching any Dependabot PR
- Policy for a breaking bump: close the PR and document, don't rewrite the template in the same PR
- Defer long-term auto-merge policy to a separate discussion
Next Steps
- User reviews and approves this plan
- Move from
backlog/toactive/ - Execute Phase 1 through Phase 6