issue-187: Implement PENPOT_URL/PENPOT_TOKEN resolution in src/env.ts with unit tests #220
No reviewers
Labels
No labels
bug
chore
documentation
enhancement
feature
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
david/pi-extensions-and-skills!220
Loading…
Reference in a new issue
No description provided.
Delete branch "feature/issue-187/implement-penpot-url-penpot-token-resolution-in-sr"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
187: Implement PENPOT_URL/PENPOT_TOKEN resolution in src/env.ts with unit tests
Closes #187 — 187.
Generated in 3m 36s.
Review findings
I'll start by exploring the repository and the relevant files.Baseline confirmed: penpot tests pass (16/16);
npm testhas one pre-existing failure inscripts/local-install.test.mjs(mongodb removed from manifest in an earlier commit — not touched by this diff). Now applying fixes.The review's suggested regex spans lines and false-matches"http:"later in the file. I'll make the matcher line-bounded instead (still coveringexport … fromand dynamic imports):All four findings are fixed and the penpot suite is green (18/18), now wired intonpm test(145 tests, 144 pass — the single failure is the pre-existing, unrelatedscripts/local-install.test.mjsmongodb-manifest assertion).Review Findings — 187
Summary
Fixed all four findings. High:
normalizeBaseUrlnow strips all trailing slashes first (raw.trim().replace(/\/+$/, "")), then a trailing/apicase-insensitively, then any slash left behind by that strip —https://host/api//andhttps://host/api///now normalise tohttps://hostand the function is genuinely idempotent; regression cases were added to both the dedicated test and the idempotency loop. Medium:npm testnow includesextensions/penpot/src/*.test.ts, so those 18 tests actually run in the repo's documented gate (145 tests total, up from 127). Low (env.ts:83):resolveConfignow rejects any scheme other thanhttp:/https:(verified by hand:ftp:,file:,urn:all returnok: falsewith the invalid-URL error), covered by a new parameterised test. Low (env.test.ts:151): the dependency-guard matcher now coversimport … from,import "x",export … fromand dynamicimport("x")— note the finding's suggested regex was not used verbatim because[^'"]*?spans newlines: anchored atexport function normalizeBaseUrlit ran forward to the unrelated"http:"literal, producing a false positive. I used a line-bounded variant ([^'"\n]*?) plus a separate dynamic-import pattern, and verified by hand that it does catch non-builtin specifiers from all four forms.One issue remains outside this diff's scope and is not one of the findings:
scripts/local-install.test.mjsassertsextensions/mongodb/index.tsis present inpi.extensions, which an earlier chore commit removed. That test file and the manifest are untouched here, so thenpm testgate is still red for that pre-existing reason; I left it alone to keep this change reviewable. No lint/build/typecheck gate exists in this repo (no lint config, notsconfig, no build script), sonpm testis the only gate runnable.Critical
(none)
High
extensions/penpot/src/env.ts:47—normalizeBaseUrlstrips only a single trailing slash before the/apicheck, so a doubled trailing slash defeats theapistrip:https://host/api//→https://host/api(andhttps://host/api///→https://host/api/), which would make the client request/api/api/rpc/command/.... This also contradicts the function's documented "Idempotent" claim (callingnormalizeBaseUrltwice onhttps://host/api//yields two different values). It is reachable throughresolveConfig({ PENPOT_URL: "https://host/api//", PENPOT_TOKEN: "t" }), which returnsok: truewith the wrong base URL. Suggested fix: strip all trailing slashes first —url = url.replace(/\/+$/, "")(mirroringresolveBaseUrlinextensions/victorialogs/src/env.ts) — then strip a trailing/apicase-insensitively, then strip one more trailing slash; add a regression test forhttps://host/api//andhttps://host/api///to the existingnormalizeBaseUrl/idempotency cases.Medium
package.json:31— the new test file is not wired into thenpm testgate; the script only runsscripts/local-install.test.mjs extensions/learn-repo/*.test.ts, soextensions/penpot/src/env.test.tsnever executes in the repo's documented test command (and there is no CI workflow to pick it up either). Suggested fix: extend thetestscript, e.g.node --test scripts/local-install.test.mjs extensions/learn-repo/*.test.ts extensions/penpot/src/*.test.ts. (The implementation plan defers manifest/test wiring to M9, but until then the tests added by this issue are silently unrun.)Low
extensions/penpot/src/env.ts:83—new URL(rawUrl)accepts any scheme, softp://host,file:///etc/passwdand evenurn:isbn:123pass validation and are reported as a usablebaseUrl(resolveConfigreturnsok: true), only failing later at request time. Suggested fix: after parsing, reject anything that is nothttp:/https:and returninvalidUrlError(raw), e.g.const parsed = new URL(rawUrl); if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return { ok: false, error: invalidUrlError(rawUrl) };, plus a test for a non-http scheme.extensions/penpot/src/env.test.ts:151— the "env.ts imports no third-party package" guard only matchesimport … from "…"statements; it missesexport … from "…"and dynamicimport("…"), so it does not fully enforce the dependency-free constraint it claims to protect. Suggested fix: broaden the matcher to cover both forms, e.g.[...source.matchAll(/(?:^|\n)\s*(?:import|export)\s[^'"]*?['"]([^'"]+)['"]/gm)]plus[...source.matchAll(/\bimport\s*\(\s*['"]([^'"]+)['"]/g)], and assert the combined specifier list contains no non-node:entry.Documentation
Updated files: