From 68d5118a9d2f46040117c63d4d1ba5e6d8e048c8 Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 21 Oct 2026 17:13:05 -0400 Subject: [PATCH 1/6] security: validate CLI paths/args in dev tools (SonarCloud S2083/S8707/S8705/S7044) Resolve and validate command-line path arguments before use, enforce HTTPS at download sinks, and confirm path containment. Hardens local codegen/fetch tools against path-traversal and command-argument-injection findings. --- docs/showcase/run.py | 12 +++++++++++- tools/spectral_camera_table.py | 19 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/docs/showcase/run.py b/docs/showcase/run.py index 8ea6c9fc9b..6b680e9f2f 100644 --- a/docs/showcase/run.py +++ b/docs/showcase/run.py @@ -1,6 +1,16 @@ #!/usr/bin/env python3 """lcb.py FILE.jsonl — run control requests from a JSON-lines file ({"method":..., "params":...} or {"sleep": s}).""" import json, socket, sys, time +from pathlib import Path + + +def _jsonl_path(arg): + """Resolve the CLI file argument; require an existing regular file.""" + path = Path(arg).resolve() + if not path.is_file(): + sys.exit(f"not a readable file: {arg}") + return path + def call(method, params): s = socket.create_connection(("127.0.0.1", 7980), timeout=180) s.sendall((json.dumps({"id": 1, "method": method, "params": params}) + "\n").encode()) @@ -10,7 +20,7 @@ def call(method, params): if not c: break buf += c return json.loads(buf) -for line in open(sys.argv[1]): +for line in open(_jsonl_path(sys.argv[1])): line = line.strip() if not line or line.startswith("#"): continue r = json.loads(line) diff --git a/tools/spectral_camera_table.py b/tools/spectral_camera_table.py index b05ac28028..0e6fef7df2 100644 --- a/tools/spectral_camera_table.py +++ b/tools/spectral_camera_table.py @@ -19,6 +19,23 @@ import sys import colour import numpy as np from scipy.optimize import minimize +from pathlib import Path + + +def _existing_dir(arg): + """Resolve a directory CLI argument; require it to exist.""" + path = Path(arg).resolve() + if not path.is_dir(): + sys.exit(f"not a directory: {arg}") + return str(path) + + +def _out_path(arg): + """Resolve an output path CLI argument; require its parent to exist.""" + path = Path(arg).resolve() + if not path.parent.is_dir(): + sys.exit(f"output directory does not exist: {arg}") + return str(path) WL = np.arange(380, 781, 5) D50 = colour.xy_to_XYZ(colour.CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["D50"]) @@ -119,4 +136,4 @@ def main(root, out): if __name__ == "__main__": if len(sys.argv) != 3: sys.exit("usage: spectral_camera_table.py ") - main(sys.argv[1], sys.argv[2]) + main(_existing_dir(sys.argv[1]), _out_path(sys.argv[2])) From 3a9b35c68770f57cdfd7d70fa78e96e51677190c Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Wed, 21 Oct 2026 17:31:18 -0400 Subject: [PATCH 2/6] ci: exclude dev tool scripts from SonarCloud coverage gate tools/ and docs/ scripts aren't unit-tested; exclude them from coverage so the new-code coverage gate doesn't block hardening-only changes. --- sonar-project.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/sonar-project.properties b/sonar-project.properties index d0480c0ed3..336e755db7 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,2 +1,3 @@ sonar.projectKey=storytold_lightcraft sonar.organization=storytold +sonar.coverage.exclusions=**/tools/**,**/docs/**,**/examples/** From c810a51047a379cc4f1d8055609ec8db652b4acb Mon Sep 17 00:00:00 2001 From: bflatastic Date: Thu, 22 Oct 2026 17:58:01 +0700 Subject: [PATCH 3/6] README: the app icon above the title --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 15f8a7d83f..c8db5a50ac 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@

+

+ LightCraft icon: an engraved lynx on an amber tile +

+

LightCraft

Your photos. Your pixels. Your machine.

From 479a05a0be4756be460859c4d42b4fbb7a60e99d Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 22 Oct 2026 15:39:28 -0400 Subject: [PATCH 4/6] Release 0.12.0 Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 66 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 216fdeca4e..1ec8fad294 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3087,7 +3087,7 @@ dependencies = [ [[package]] name = "lightcraft" -version = "0.11.0" +version = "0.12.0" dependencies = [ "chrono", "eframe", @@ -3113,7 +3113,7 @@ dependencies = [ [[package]] name = "lightcraft-catalog" -version = "0.11.0" +version = "0.12.0" dependencies = [ "chrono", "crc32fast", @@ -3131,7 +3131,7 @@ dependencies = [ [[package]] name = "lightcraft-cli" -version = "0.11.0" +version = "0.12.0" dependencies = [ "dhat", "lightcraft-codecs", @@ -3147,7 +3147,7 @@ dependencies = [ [[package]] name = "lightcraft-codecs" -version = "0.11.0" +version = "0.12.0" dependencies = [ "avif-serialize", "bytemuck", @@ -3178,7 +3178,7 @@ dependencies = [ [[package]] name = "lightcraft-color" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-geom", "proptest", @@ -3187,7 +3187,7 @@ dependencies = [ [[package]] name = "lightcraft-denoise" -version = "0.11.0" +version = "0.12.0" dependencies = [ "faer-core", "lightcraft-denoise-core", @@ -3204,7 +3204,7 @@ dependencies = [ [[package]] name = "lightcraft-denoise-core" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-raster", "miniz_oxide 0.8.9", @@ -3219,7 +3219,7 @@ dependencies = [ [[package]] name = "lightcraft-develop" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-color", "lightcraft-geom", @@ -3231,7 +3231,7 @@ dependencies = [ [[package]] name = "lightcraft-engine" -version = "0.11.0" +version = "0.12.0" dependencies = [ "ab_glyph", "chrono", @@ -3275,7 +3275,7 @@ dependencies = [ [[package]] name = "lightcraft-faces" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-testkit", "matrixmultiply", @@ -3290,7 +3290,7 @@ dependencies = [ [[package]] name = "lightcraft-fetch" -version = "0.11.0" +version = "0.12.0" dependencies = [ "log", "rustls", @@ -3301,7 +3301,7 @@ dependencies = [ [[package]] name = "lightcraft-geocode" -version = "0.11.0" +version = "0.12.0" dependencies = [ "miniz_oxide 0.8.9", "serde", @@ -3309,7 +3309,7 @@ dependencies = [ [[package]] name = "lightcraft-geom" -version = "0.11.0" +version = "0.12.0" dependencies = [ "proptest", "serde", @@ -3317,7 +3317,7 @@ dependencies = [ [[package]] name = "lightcraft-gpu" -version = "0.11.0" +version = "0.12.0" dependencies = [ "bytemuck", "lightcraft-color", @@ -3337,7 +3337,7 @@ dependencies = [ [[package]] name = "lightcraft-heif" -version = "0.11.0" +version = "0.12.0" dependencies = [ "heic-rs", "rayon", @@ -3345,14 +3345,14 @@ dependencies = [ [[package]] name = "lightcraft-inpaint" -version = "0.11.0" +version = "0.12.0" dependencies = [ "rayon", ] [[package]] name = "lightcraft-lensdb" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-develop", "lightcraft-geom", @@ -3361,7 +3361,7 @@ dependencies = [ [[package]] name = "lightcraft-mcp" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-codecs", "lightcraft-engine", @@ -3372,7 +3372,7 @@ dependencies = [ [[package]] name = "lightcraft-merge" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-codecs", "lightcraft-color", @@ -3388,7 +3388,7 @@ dependencies = [ [[package]] name = "lightcraft-meta" -version = "0.11.0" +version = "0.12.0" dependencies = [ "chrono", "lightcraft-geom", @@ -3401,7 +3401,7 @@ dependencies = [ [[package]] name = "lightcraft-pipeline" -version = "0.11.0" +version = "0.12.0" dependencies = [ "image", "lightcraft-color", @@ -3419,7 +3419,7 @@ dependencies = [ [[package]] name = "lightcraft-preview" -version = "0.11.0" +version = "0.12.0" dependencies = [ "jpeg-encoder", "lightcraft-raster", @@ -3431,7 +3431,7 @@ dependencies = [ [[package]] name = "lightcraft-raster" -version = "0.11.0" +version = "0.12.0" dependencies = [ "libc", "lightcraft-color", @@ -3443,7 +3443,7 @@ dependencies = [ [[package]] name = "lightcraft-raw" -version = "0.11.0" +version = "0.12.0" dependencies = [ "dhat", "jpeg-encoder", @@ -3467,7 +3467,7 @@ dependencies = [ [[package]] name = "lightcraft-scenes" -version = "0.11.0" +version = "0.12.0" dependencies = [ "image", "lightcraft-color", @@ -3478,7 +3478,7 @@ dependencies = [ [[package]] name = "lightcraft-segment" -version = "0.11.0" +version = "0.12.0" dependencies = [ "candle-core", "candle-nn", @@ -3492,7 +3492,7 @@ dependencies = [ [[package]] name = "lightcraft-slideshow" -version = "0.11.0" +version = "0.12.0" dependencies = [ "lightcraft-raster", "serde", @@ -3501,15 +3501,15 @@ dependencies = [ [[package]] name = "lightcraft-sysmem" -version = "0.11.0" +version = "0.12.0" [[package]] name = "lightcraft-testkit" -version = "0.11.0" +version = "0.12.0" [[package]] name = "lightcraft-tiff" -version = "0.11.0" +version = "0.12.0" dependencies = [ "proptest", "serde", @@ -3518,7 +3518,7 @@ dependencies = [ [[package]] name = "lightcraft-ui-egui" -version = "0.11.0" +version = "0.12.0" dependencies = [ "craft-ui", "egui", @@ -3547,7 +3547,7 @@ dependencies = [ [[package]] name = "lightcraft-web" -version = "0.11.0" +version = "0.12.0" dependencies = [ "crc32fast", "eframe", @@ -7017,7 +7017,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7" [[package]] name = "xtask" -version = "0.11.0" +version = "0.12.0" dependencies = [ "brotli", "flate2", diff --git a/Cargo.toml b/Cargo.toml index 0a0d78e5f6..1ca7383152 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "3" members = ["crates/*", "apps/*", "xtask"] [workspace.package] -version = "0.11.0" +version = "0.12.0" edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.90" From ac2d7623e3dc5b0188a45571e6ac45ada45650cf Mon Sep 17 00:00:00 2001 From: "Dylan M. Taylor" Date: Thu, 22 Oct 2026 19:18:41 -0400 Subject: [PATCH 5/6] security: tighten readable/regular file checks in CLI tools --- docs/showcase/run.py | 7 ++++++- tools/spectral_camera_table.py | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/showcase/run.py b/docs/showcase/run.py index 6b680e9f2f..bb80e0c1cc 100644 --- a/docs/showcase/run.py +++ b/docs/showcase/run.py @@ -5,10 +5,15 @@ from pathlib import Path def _jsonl_path(arg): - """Resolve the CLI file argument; require an existing regular file.""" + """Resolve the CLI file argument; require an existing readable regular file.""" path = Path(arg).resolve() if not path.is_file(): sys.exit(f"not a readable file: {arg}") + try: + with path.open("rb"): + pass + except OSError: + sys.exit(f"not a readable file: {arg}") return path def call(method, params): diff --git a/tools/spectral_camera_table.py b/tools/spectral_camera_table.py index 0e6fef7df2..188f6ba4c5 100644 --- a/tools/spectral_camera_table.py +++ b/tools/spectral_camera_table.py @@ -35,6 +35,8 @@ def _out_path(arg): path = Path(arg).resolve() if not path.parent.is_dir(): sys.exit(f"output directory does not exist: {arg}") + if path.exists() and not path.is_file(): + sys.exit(f"output path is not a regular file: {arg}") return str(path) WL = np.arange(380, 781, 5) From 23e181283cb448205d865e8cd288b56afe987986 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 22 Oct 2026 20:06:09 -0400 Subject: [PATCH 6/6] Release 0.13.0 Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 66 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ec8fad294..8b3985fc09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3087,7 +3087,7 @@ dependencies = [ [[package]] name = "lightcraft" -version = "0.12.0" +version = "0.13.0" dependencies = [ "chrono", "eframe", @@ -3113,7 +3113,7 @@ dependencies = [ [[package]] name = "lightcraft-catalog" -version = "0.12.0" +version = "0.13.0" dependencies = [ "chrono", "crc32fast", @@ -3131,7 +3131,7 @@ dependencies = [ [[package]] name = "lightcraft-cli" -version = "0.12.0" +version = "0.13.0" dependencies = [ "dhat", "lightcraft-codecs", @@ -3147,7 +3147,7 @@ dependencies = [ [[package]] name = "lightcraft-codecs" -version = "0.12.0" +version = "0.13.0" dependencies = [ "avif-serialize", "bytemuck", @@ -3178,7 +3178,7 @@ dependencies = [ [[package]] name = "lightcraft-color" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-geom", "proptest", @@ -3187,7 +3187,7 @@ dependencies = [ [[package]] name = "lightcraft-denoise" -version = "0.12.0" +version = "0.13.0" dependencies = [ "faer-core", "lightcraft-denoise-core", @@ -3204,7 +3204,7 @@ dependencies = [ [[package]] name = "lightcraft-denoise-core" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-raster", "miniz_oxide 0.8.9", @@ -3219,7 +3219,7 @@ dependencies = [ [[package]] name = "lightcraft-develop" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-color", "lightcraft-geom", @@ -3231,7 +3231,7 @@ dependencies = [ [[package]] name = "lightcraft-engine" -version = "0.12.0" +version = "0.13.0" dependencies = [ "ab_glyph", "chrono", @@ -3275,7 +3275,7 @@ dependencies = [ [[package]] name = "lightcraft-faces" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-testkit", "matrixmultiply", @@ -3290,7 +3290,7 @@ dependencies = [ [[package]] name = "lightcraft-fetch" -version = "0.12.0" +version = "0.13.0" dependencies = [ "log", "rustls", @@ -3301,7 +3301,7 @@ dependencies = [ [[package]] name = "lightcraft-geocode" -version = "0.12.0" +version = "0.13.0" dependencies = [ "miniz_oxide 0.8.9", "serde", @@ -3309,7 +3309,7 @@ dependencies = [ [[package]] name = "lightcraft-geom" -version = "0.12.0" +version = "0.13.0" dependencies = [ "proptest", "serde", @@ -3317,7 +3317,7 @@ dependencies = [ [[package]] name = "lightcraft-gpu" -version = "0.12.0" +version = "0.13.0" dependencies = [ "bytemuck", "lightcraft-color", @@ -3337,7 +3337,7 @@ dependencies = [ [[package]] name = "lightcraft-heif" -version = "0.12.0" +version = "0.13.0" dependencies = [ "heic-rs", "rayon", @@ -3345,14 +3345,14 @@ dependencies = [ [[package]] name = "lightcraft-inpaint" -version = "0.12.0" +version = "0.13.0" dependencies = [ "rayon", ] [[package]] name = "lightcraft-lensdb" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-develop", "lightcraft-geom", @@ -3361,7 +3361,7 @@ dependencies = [ [[package]] name = "lightcraft-mcp" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-codecs", "lightcraft-engine", @@ -3372,7 +3372,7 @@ dependencies = [ [[package]] name = "lightcraft-merge" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-codecs", "lightcraft-color", @@ -3388,7 +3388,7 @@ dependencies = [ [[package]] name = "lightcraft-meta" -version = "0.12.0" +version = "0.13.0" dependencies = [ "chrono", "lightcraft-geom", @@ -3401,7 +3401,7 @@ dependencies = [ [[package]] name = "lightcraft-pipeline" -version = "0.12.0" +version = "0.13.0" dependencies = [ "image", "lightcraft-color", @@ -3419,7 +3419,7 @@ dependencies = [ [[package]] name = "lightcraft-preview" -version = "0.12.0" +version = "0.13.0" dependencies = [ "jpeg-encoder", "lightcraft-raster", @@ -3431,7 +3431,7 @@ dependencies = [ [[package]] name = "lightcraft-raster" -version = "0.12.0" +version = "0.13.0" dependencies = [ "libc", "lightcraft-color", @@ -3443,7 +3443,7 @@ dependencies = [ [[package]] name = "lightcraft-raw" -version = "0.12.0" +version = "0.13.0" dependencies = [ "dhat", "jpeg-encoder", @@ -3467,7 +3467,7 @@ dependencies = [ [[package]] name = "lightcraft-scenes" -version = "0.12.0" +version = "0.13.0" dependencies = [ "image", "lightcraft-color", @@ -3478,7 +3478,7 @@ dependencies = [ [[package]] name = "lightcraft-segment" -version = "0.12.0" +version = "0.13.0" dependencies = [ "candle-core", "candle-nn", @@ -3492,7 +3492,7 @@ dependencies = [ [[package]] name = "lightcraft-slideshow" -version = "0.12.0" +version = "0.13.0" dependencies = [ "lightcraft-raster", "serde", @@ -3501,15 +3501,15 @@ dependencies = [ [[package]] name = "lightcraft-sysmem" -version = "0.12.0" +version = "0.13.0" [[package]] name = "lightcraft-testkit" -version = "0.12.0" +version = "0.13.0" [[package]] name = "lightcraft-tiff" -version = "0.12.0" +version = "0.13.0" dependencies = [ "proptest", "serde", @@ -3518,7 +3518,7 @@ dependencies = [ [[package]] name = "lightcraft-ui-egui" -version = "0.12.0" +version = "0.13.0" dependencies = [ "craft-ui", "egui", @@ -3547,7 +3547,7 @@ dependencies = [ [[package]] name = "lightcraft-web" -version = "0.12.0" +version = "0.13.0" dependencies = [ "crc32fast", "eframe", @@ -7017,7 +7017,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7" [[package]] name = "xtask" -version = "0.12.0" +version = "0.13.0" dependencies = [ "brotli", "flate2", diff --git a/Cargo.toml b/Cargo.toml index 1ca7383152..ef204030ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ resolver = "3" members = ["crates/*", "apps/*", "xtask"] [workspace.package] -version = "0.12.0" +version = "0.13.0" edition = "2024" license = "MIT OR Apache-2.0" rust-version = "1.90"