Skip to main content

Jscad Stl Validator

@magistr/jscad-stl-validatorv2026.08.19.1· 27d agoMODELS
01README

STL file validator — checks triangle count, degenerate faces, bounding box

02Models1
@magistr/jscad-stl-validatorv2026.08.19.1extensions/models/jscad_stl_validator.ts

Global Arguments

ArgumentTypeDescription
allowedRootsarrayOptional operator-set confinement roots for validateFile. When
maxFileBytesnumberMaximum size in bytes validateFile will read from disk. Checked
fn validate(cadModelName: string, version?: number)
Validate the STL output stored by a @magistr/jscad-cad model instance
ArgumentTypeDescription
cadModelNamestringName of the @magistr/jscad-cad model whose stored output STL to validate
version?numberData version to validate (defaults to latest)
fn validateFile(filePath: string)
Validate an STL file at an absolute path on disk
ArgumentTypeDescription
filePathstringAbsolute path to the STL file to validate

Resources

report(infinite)— STL validation report
03Previous Versions6
2026.08.02.1

2026.08.02.1

Real-fixes the four remaining latent bugs (LB2–LB5) tracked in the LOCAL jscad-stl-validator-latent-bugs issue-lifecycle model (NEVER a swamp.club Lab issue). LB1 (path traversal, fixed in 2026.08.01.1) is untouched. The pure domain service extensions/models/jscad/stl_validator.ts — previously declared BYTE-FROZEN — is deliberately un-frozen for these fixes; every benign contract pin in the test suites stays byte-identical.

Behavior changes:

  • LB2 (format misdetection, MEDIUM) — FIXED. A binary buffer whose 80-byte header happens to spell "solid" AND whose claimed (offset-80) triangle count does NOT match the actual buffer size is now correctly classified as binary (restoring the real "Size mismatch" diagnosis and the actual triangle data), instead of falling through to the ASCII parser. The discriminator: when the claimed count is > 0 but the size doesn't match exactly, the buffer's decoded text is checked for ASCII geometry keywords (facet normal / endsolid); only a buffer that genuinely looks like ASCII text keeps the ASCII path. The existing positive/negative reclassification pins (exact-size-match → binary; claimed-count-0 → ASCII) are unaffected.
  • LB3 (unbounded read + issues[] amplification, MEDIUM) — FIXED, in two independent halves:
    • Domain half: issues[] no longer grows linearly with a hostile triangle count. At most 10 individual Triangle i: contains NaN or Infinity values strings are pushed; beyond that, one (<k> further triangle issue(s) suppressed) note is added, and the existing <n> degenerate triangle(s) found ... summary is always kept. The bounding box is now computed with incremental min/max accumulators instead of retaining a Triangle[] array — memory is O(1) in triangle count. Output is byte-identical for triangle counts at or below the cap (single-NaN/single-Infinity pins unaffected).
    • Application half: added a new defaulted global argument maxFileBytes (default 268435456, 256 MiB). validateFile now Deno.stats the resolved path and rejects with Refusing to read "<path>": file exceeds maxFileBytes (<size> > <cap>) BEFORE calling Deno.readFile, so an oversized file is never buffered into memory. Read only from context.globalArgs (never per-call arguments), mirroring the allowedRoots trust-boundary convention. Order is resolveStlPath (policy) → Deno.stat size check → Deno.readFile, preserving the LB1 traversal pin, the missing-file pin (stat NotFound → Cannot read), and the directory pin (stat ok + small size → readFile EISDIR → Cannot read).
  • LB4 (weak ASCII validation, LOW) — FIXED. ASCII validation now parses facets into triangles (grouping vertices in consecutive triples) and runs the SAME degenerate-triangle check as binary (duplicate-vertex OR near-zero cross-product area), via a shared, non-exported isDegenerateTri helper. A fully degenerate (duplicate-vertex) ASCII facet is now reported valid: false, degenerateTriangles: 1, with the same <n> degenerate triangle(s) found ... summary as binary, and excluded from the bounding box. Malformed vertex remainders (count not a multiple of 3) are ignored for the geometry check. The canonical (non-degenerate, finite) ASCII contract pins in jscad/stl_validator_test.ts are byte-identical.
  • LB5 (NaN/Infinity asymmetry, binary vs ASCII, LOW) — FIXED. Folded into the LB4 rewrite: ASCII vertices now run the SAME isFinite/isNaN guard as binary, via a shared, non-exported isFiniteCoords helper. A non-finite ASCII triangle is flagged with a Triangle i: contains NaN or Infinity values issue (subject to the LB3 cap), counted as degenerate, and EXCLUDED from the bounding box — so an Infinity-valued coordinate can no longer poison the bounding box's max/min, and an all-NaN facet can no longer produce the nonsensical inverted min:[Infinity,...]/max:[-Infinity,...] box. Binary and ASCII now classify an identical NaN vertex equivalently.
  • extensions/models/jscad_stl_validator.ts: model version bumped to 2026.08.02.1. Added an identity upgrades[] entry (the model previously had none) — the only globalArguments change is the new defaulted maxFileBytes field, so existing instances re-parse cleanly with zod filling the default; the upgrade transform is (old) => old.
  • manifest.yaml version bumped to 2026.08.02.1 in sync.
  • Test suites: flipped the four buggy pins in

Notes trimmed at a line boundary to fit the registry's 4900-byte per-version cap. Full section: https://github.com/umag/swamp-workspace/blob/d850d8e8372d4c0008c9245959a090b37095de7a/jscad-stl-validator/CHANGELOG.md

2026.08.01.1

2026.08.01.1

Fixes the HIGH-severity path-traversal / arbitrary-file-read finding (LB1) in validateFile, tracked in the LOCAL jscad-stl-validator-latent-bugs issue-lifecycle model (NEVER a swamp.club Lab issue). validateFile is an operator-supplied-absolute-path method by design; this fix is defense in depth for any future less-trusted exposure.

Behavior change: validateFile now rejects any filePath that is not absolute, and any filePath containing a literal . or .. path segment — previously such a path (e.g. a traversal-shaped path) was read verbatim with no confinement at all. The traversal/absolute-path check runs BEFORE any filesystem access, so a traversal attempt against a nonexistent target is still refused as a policy violation, never silently masked by a "file not found" error. Legitimate callers passing a clean absolute path (as shown in this README's examples) are unaffected.

  • Added extensions/models/jscad/safe_path.ts — a new infrastructure guard, resolveStlPath, implementing the always-on checks above plus canonicalization via Deno.realPath. The pure domain service jscad/stl_validator.ts stays BYTE-FROZEN; path safety is an infrastructure concern, kept out of the domain service.
  • Added an OPT-IN allowedRoots global argument (default [], read via context.globalArgs — never the per-call arguments) that confines validateFile to one or more operator-set root directories, using canonicalized (Deno.realPath'd) separator-boundary prefix matching so a sibling directory sharing a name prefix (/rootFOO vs. /root) or a symlinked root cannot be mistaken for containment. Empty allowedRoots (the default) preserves the historical unconfined contract.
  • extensions/models/jscad_stl_validator.ts: validateFile now resolves args.filePath through resolveStlPath before calling Deno.readFile. Error messages still key to the ORIGINAL args.filePath (not the canonicalized path), so the existing missing-file/directory-path Cannot read "<path>" throw-tests stay green; policy violations get a distinct Refusing to read "<path>": ... message. Model version bumped to 2026.08.01.1.
  • manifest.yaml version bumped to 2026.08.01.1 in sync; added extensions/models/jscad/safe_path_test.ts to additionalFiles. deno.json's check task extended to typecheck jscad/safe_path.ts + jscad/safe_path_test.ts.
  • Test suite: added extensions/models/jscad/safe_path_test.ts (11 unit tests covering reject-relative, reject-./..-segment including the nonexistent-traversal-target ordering guarantee, accept-clean-absolute, allowedRoots accept/reject, separator-boundary /rootFOO-vs-/root, symlink-escape rejection, and root/target canonicalization). Flipped the LB1 "../ traversal path read verbatim" pin in jscad_stl_validator_adversarial_test.ts to assert rejection; relabeled the "no base dir, two unrelated roots both succeed" pin from a HIGH bug-pin to a regression:-prefixed default-contract test (still asserts both calls succeed — that is the intended behavior when allowedRoots is not configured). Added allowedRoots accept/deny cases plus a test proving a smuggled per-call args.allowedRoots has no effect to jscad_stl_validator_methods_test.ts. All prior binary/ASCII happy paths and the missing-file/directory-path throw-path tests are unchanged and still green.
  • README.md: documented the validateFile operator-trust boundary and the opt-in allowedRoots confinement, including the residual "report reflects file bytes" oracle risk to keep in mind when narrowing allowedRoots.
  • LB2/LB3/LB4/LB5 remain pinned as characterized (not fixed) latent bugs — out of scope for this fix, tracked in the same issue-lifecycle model. The sibling jscad-stl-slicer extension shares the same unconfined-path pattern; deliberately NOT fixed here — tracked as its own follow-up.
2026.07.16.2

Release 2026.07.16.2 — align model versions with manifests

Maintenance release across the @magistr extensions. For most packages this carries no functional change: the only edit is the model's version: field, brought back in line with its manifest version so the published model type version and the package version no longer drift.

Functional changes in this release are limited to:

  • anime-cron: normalizeTitle now strips a ": subtitle" suffix and a trailing parenthesized year before comparison, fixing dedup false-misses where the torrent title carries a subtitle or year that the AniList romaji does not.

  • arckit: first publish. Standalone ArcKit port — a 12-phase architecture governance state machine with 65 bundled templates, driven by a bundled skill.

Also tracks three extensions (kaiten, observability-agent, music-library) that previously existed only as untracked working-tree directories, recovered from stashes.

Added 1, removed 1 models

2026.05.25.1

Merge pull request #5 from umag/extensions/jscad-stl-pair

extensions: add 15 more @magistr extensions + auto-discover CI

2026.04.04.2
2026.04.04.1
04Stats
A
100 / 100
Downloads
4
Archive size
19.1 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented1/1earned
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License declared1/1earned
  • Verified public repository2/2earned
05Platforms
06Labels