Browse / github.com/storytold/artcraft-services / patch
security: triage operator tooling and dev-only findings (SonarCloud)
security: triage operator tooling and dev-only findings (SonarCloud) Second security batch for artcraft-services, after #177. - **pythonsecurity:S8702/S8705/S8707** `script/database/mysql_dump_table.py` — the table name is checked against `ALLOWED_TABLES` before any use, and `--directory` is the operator's own output folder. The findings are annotated at the four call sites with that reasoning. - **typescript:S2819** `generatePipeline.worker.ts` — a dedicated worker only receives messages from the page that created it, so `MessageEvent.origin` is always empty. - **shell:S6505** the remaining `npm install` sites need nx/esbuild/@swc/core lifecycle scripts; `--i
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- dylanmtaylor (imported from pull request #178, open)
- Base
e57ee3d63ac478a24149384bf1473ef97aa067f8- Size
- +26 −12 in 6 files
- Review
- pending
- Shared
- 2026-10-28
- Id
b8ced3d99795ae4e968100e6
How it went
No other operator has reported using it yet.
Diff
raw · frontend/build_modules.sh frontend/libs/components/pagedraw/src/lib/utilities/generatePipeline.worker.ts includes/container_includes/python_overrides/logger/__init__.py script/common/frontend_preflight.sh script/database/mysql_dump_table.py script/website/unix_frontend_webapp_dev.sh
@@ -16,8 +16,9 @@ set -euxo pipefail echo 'TEMPORARY HACK: Build shared frontend dependencies since nx is not finding them...' -# A 'clean' will remove nx-npm install+# A 'clean' will remove nx. nx, esbuild and @swc/core need their lifecycle scripts, so+# --ignore-scripts would leave an unusable tree.+npm install # NOSONAR # TODO: Temp commented out nx build "@storyteller/api"@@ -35,7 +35,9 @@ const post = (response: WorkerResponse, transfer: Transferable[] = []) => { ); }; -self.addEventListener("message", async (event: MessageEvent<WorkerRequest>) => {+// A dedicated worker only receives messages from the page that created it; MessageEvent.origin is+// always empty here, so there is no origin to verify.+self.addEventListener("message", async (event: MessageEvent<WorkerRequest>) => { // NOSONAR const req = event.data; try { if (req.type === "composite") {@@ -1464,7 +1464,9 @@ class Manager(object): """ return getFakeYouLogger() - rv = None+ # Retained from the CPython logging.Manager this override replaces; the early return+ # above is the whole override.+ rv = None # NOSONAR if not isinstance(name, str): raise TypeError('A logger name must be a string') _acquireLock()@@ -2217,7 +2219,8 @@ def getLogger(name=None): """ return getFakeYouLogger() - if not name or isinstance(name, str) and name == root.name:+ # Retained from the CPython logging module this override replaces; see getFakeYouLogger().+ if not name or isinstance(name, str) and name == root.name: # NOSONAR return root return Logger.manager.getLogger(name) @@ -66,7 +66,9 @@ frontend_preflight() { # layout causing ENOTEMPTY rename errors), wipe node_modules and the nx cache # and retry once before giving up. frontend_npm_install() {- if npm install; then+ # nx, esbuild and @swc/core need their lifecycle scripts, so --ignore-scripts would leave+ # an unusable tree.+ if npm install; then # NOSONAR return 0 fi @@ -77,7 +79,7 @@ frontend_npm_install() { rm -rf node_modules .nx - if ! npm install; then+ if ! npm install; then # NOSONAR echo "" echo "ERROR: npm install failed again. See the npm output above and the" echo "troubleshooting section in frontend/README.md."@@ -98,7 +98,8 @@ def table_exists(conn, table_name): def count_rows(conn, table_name): with conn.cursor() as cursor:- cursor.execute(f"SELECT COUNT(*) AS cnt FROM `{table_name}`")+ # table_name is checked against ALLOWED_TABLES in main() before this is reached.+ cursor.execute(f"SELECT COUNT(*) AS cnt FROM `{table_name}`") # NOSONAR result = cursor.fetchone() return result["cnt"] @@ -137,7 +138,8 @@ def main(): conn.close() # Build output path- backup_dir.mkdir(parents=True, exist_ok=True)+ # The operator picks the output directory with --directory; this is a local backup tool.+ backup_dir.mkdir(parents=True, exist_ok=True) # NOSONAR timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") output_file = backup_dir / f"{table_name}_{timestamp}.sql" @@ -170,8 +172,10 @@ def main(): print(f"\nRunning mysqldump for '{table_name}'...") - with open(output_file, "w") as f:- result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, text=True)+ # output_file lives under the operator-chosen backup directory.+ with open(output_file, "w") as f: # NOSONAR+ # argv, no shell; table_name is allowlisted and the rest comes from secrets.toml.+ result = subprocess.run(cmd, stdout=f, stderr=subprocess.PIPE, text=True) # NOSONAR if result.returncode != 0: print(f"Error: mysqldump failed (exit code {result.returncode})")@@ -22,7 +22,9 @@ fi cd "${frontend_path}" -npm install+# nx, esbuild and @swc/core need their lifecycle scripts, so --ignore-scripts would leave+# an unusable tree.+npm install # NOSONAR export VITE_ENVIRONMENT_TYPE="production"