Sonar: shell, workflow, Rust, HTML and analysis-scope findings

See the pull request for each change.
This commit is contained in:
Dylan M. Taylor committed 2026-11-10 23:37:49 +00:00
1 parent 71adfd4701
commit 4982e6e3aa
22 files changed
+53 -58

No files matched your search

+5 -6
View File
@@ -46,7 +46,7 @@ jobs:
node-version: lts/*
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable
with:
targets: ${{ matrix.platform == 'macos-latest-xlarge' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
@@ -72,7 +72,7 @@ jobs:
npm cache clean --force
echo "Installing all workspace dependencies..."
npm ci
npm ci --ignore-scripts
echo "=== Version Information ==="
echo "Node version:"
@@ -205,9 +205,8 @@ jobs:
# Increase Node.js memory limit for the build
export NODE_OPTIONS="--max-old-space-size=8192"
# Use npx to ensure we use the local nx version
echo "Building with npx nx..."
npx nx run artcraft:build
echo "Building with nx..."
./node_modules/.bin/nx run artcraft:build
echo "Checking build output..."
# shellcheck disable=SC2012
@@ -226,7 +225,7 @@ jobs:
- name: build and publish
uses: tauri-apps/tauri-action@v0
uses: tauri-apps/tauri-action@fce9c6108b31ea247710505d3aaaa893ee6768d4 # v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APPLE_ID: ${{ secrets.APPLE_ID }}
@@ -36,7 +36,7 @@ jobs:
- uses: actions/checkout@v7
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable
- name: install wreq dependencies
run: |
@@ -61,7 +61,7 @@ jobs:
npm cache clean --force
echo "Installing all workspace dependencies..."
npm ci
npm ci --ignore-scripts
echo "=== Version Information ==="
echo "Node version:"
@@ -101,7 +101,7 @@ jobs:
$config | ConvertTo-Json -Depth 10 | Set-Content tauri.conf.json
- name: build and publish
uses: tauri-apps/tauri-action@v0
uses: tauri-apps/tauri-action@fce9c6108b31ea247710505d3aaaa893ee6768d4 # v0
env:
# NB(bt): This is needed by wreq. Hopefully it doesn't kill Tauri
RUSTFLAGS: "-C target-feature=+crt-static"
Generated
+1
View File
@@ -8075,6 +8075,7 @@ dependencies = [
"sqlx",
"tempfile",
"tokens",
"tokio",
]
[[package]]
@@ -21,10 +21,6 @@ impl TaskId {
pub fn as_str(&self) -> &str {
&self.0
}
pub fn to_string(&self) -> String {
self.0.to_string()
}
}
impl Display for TaskId {
@@ -141,8 +141,8 @@ mod tests {
async fn test_requests() -> AnyhowResult<()> {
setup_test_logging(LevelFilter::Debug);
let refresh_token = "AMf-vByUgA0J9S93vULECe-sD50cbR85AFVYF60gKAmLFF1MBYwXlKRJCsv7z3oSpLtP0ApyOU5fAl52qHWM2U0yKgEu5gQ5UCUDt5SEG4UBRHWvHEmLLcu-Zl04Fq4ljocSEO3qJzuX1wyshmptZxlDPRkjdLYgyn-Kp03woI2yRPKLuQF5hQtABHabsNUh9Zhs129sgxuUlOuw4zsFI4L8UdE3bEuF3k6Mic7KlE3440YwyQ8Qtmk9zHtXIx2ob56N-1WTGSqwMUuQ1mX4OOvLve9bw2zDW3UzchomTWkh732886RPrP-DNRkPbO3FejUEMxuYQFWYX3EEeIEdfNGXFNGPL1dNniSXlSaKadpX699Ishjviv-x9o-pPQa3zoAj3NzWLyd8mn5rDBh9qAO_iDETaeo01Sjhb4mGYfAWZ-g4S6nW778";
let refresh_token = WorldLabsRefreshToken::new(refresh_token.to_string());
let refresh_token = std::env::var("WORLDLABS_REFRESH_TOKEN")?;
let refresh_token = WorldLabsRefreshToken::new(refresh_token);
let result = google_refresh_token(GoogleRefreshTokenArgs {
refresh_token: &refresh_token,
@@ -31,8 +31,6 @@ use sqlite_tasks::queries::task::Task;
use sqlite_tasks::queries::update_successful_task_status_with_metadata::{
update_successful_task_status_with_metadata, UpdateSuccessfulTaskArgs,
};
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::time::Duration;
use tauri::AppHandle;
@@ -255,8 +253,7 @@ async fn download_file(
let filename = format!("fal_{}_{}.{}", generate_random_uuid(), index, extension);
let download_path = tempdir.join(filename);
let mut file = File::create(&download_path)?;
file.write_all(&bytes)?;
tokio::fs::write(&download_path, &bytes).await?;
Ok(download_path)
}
@@ -94,7 +94,7 @@ async fn download_generated_results(
}
ensure!(!urls.is_empty(), "Completed task has no downloadable results");
let path = checkpoint_path(root, task);
let mut checkpoint: AutoDownloadCheckpoint = match std::fs::read(&path) {
let mut checkpoint: AutoDownloadCheckpoint = match tokio::fs::read(&path).await {
Ok(bytes) => serde_json::from_slice(&bytes)?,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => {
AutoDownloadCheckpoint { download_time: Local::now(), saved: BTreeMap::new() }
@@ -1,8 +1,6 @@
use errors::AnyhowResult;
use reqwest::Client;
use reqwest::Url;
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
const USER_AGENT: &str = "storyteller-client/1.0";
@@ -22,13 +20,7 @@ pub async fn simple_http_download<P: AsRef<Path>>(url: &Url, download_path: P) -
//let response : Response = reqwest::get(url).await?;
let bytes = response.bytes().await?;
let mut file = OpenOptions::new()
.create(true) // To create a new file
.write(true)
.truncate(true)
.open(download_path)?;
file.write_all(&bytes)?;
tokio::fs::write(download_path, &bytes).await?;
Ok(())
}
@@ -33,8 +33,6 @@ use sqlite_tasks::queries::task::Task;
use sqlite_tasks::queries::update_successful_task_status_with_metadata::{update_successful_task_status_with_metadata, UpdateSuccessfulTaskArgs};
use sqlite_tasks::queries::update_task_status::{update_task_status, UpdateTaskArgs};
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet;
use artcraft_client::endpoints::media_files::get_media_file::get_media_file;
@@ -213,8 +211,7 @@ async fn download_generation_item(
info!("Writing to path: {:?}", download_path);
let mut file = File::create(&download_path)?;
file.write_all(&image_bytes)?;
tokio::fs::write(&download_path, &image_bytes).await?;
Ok(download_path)
}
@@ -39,8 +39,6 @@ use sqlite_tasks::queries::task::Task;
use sqlite_tasks::queries::update_successful_task_status_with_metadata::{update_successful_task_status_with_metadata, UpdateSuccessfulTaskArgs};
use sqlite_tasks::queries::update_task_status::{update_task_status, UpdateTaskArgs};
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::time::Duration;
use artcraft_client::credentials::storyteller_credential_set::StorytellerCredentialSet;
@@ -378,8 +376,7 @@ async fn download_spz(
info!("Writing to path: {:?}", download_path);
let mut file = File::create(&download_path)?;
file.write_all(&image_bytes)?;
tokio::fs::write(&download_path, &image_bytes).await?;
Ok(download_path)
}
@@ -19,6 +19,7 @@ tokens.workspace = true
anyhow.workspace = true
chrono.workspace = true
log.workspace = true
tokio = { workspace = true, features = ["fs"] }
# TODO(bt,2025-07-09): Update sqlx ASAP. We're stuck on 0.7 because of the complex use of internal types and macros in the database crate.
# We're going to embed in-memory SQLite
@@ -22,7 +22,7 @@ impl TaskDbConnection {
info!("Deleting and recreating SQLite database at {:?}", database_file.as_ref());
if let Err(err) = std::fs::remove_file(&database_file) {
if let Err(err) = tokio::fs::remove_file(&database_file).await {
error!("Error deleting SQLite database file: {:?}", err);
}
+3 -3
View File
@@ -5,14 +5,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="SwaggerUI" />
<title>Storyteller API</title>
<link rel="stylesheet" href="//unpkg.com/swagger-ui-dist@5.32.0/swagger-ui.css" />
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@5.32.0/swagger-ui.css" integrity="sha384-3nuX7df3EaAoiqLBeyS1Ola0Gpg9ryJKVtarubwfnA1cOH8AWHUdbPSIvEqPZ9VH" crossorigin="anonymous" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="//unpkg.com/swagger-ui-dist@5.32.0/swagger-ui-bundle.js" crossorigin></script>
<script src="//unpkg.com/swagger-ui-dist@5.32.0/swagger-ui-standalone-preset.js" crossorigin></script>
<script src="https://unpkg.com/swagger-ui-dist@5.32.0/swagger-ui-bundle.js" integrity="sha384-7xcoc6ZKDFF7Ek627QTC3Bg/K+5Y36NJ8MWAE43D2m6+3Sh9XO3tdsfHhrS8gNIQ" crossorigin="anonymous"></script>
<script src="https://unpkg.com/swagger-ui-dist@5.32.0/swagger-ui-standalone-preset.js" integrity="sha384-FjFI+0PRyd5aAEoduVmUYk65iDC5+onNzam4WJtbAKKBim/kWvGUMk/2+9qRaYZb" crossorigin="anonymous"></script>
<script>
window.onload = () => {
window.ui = SwaggerUIBundle({
+1 -1
View File
@@ -17,7 +17,7 @@ set -euxo pipefail
echo 'TEMPORARY HACK: Build internal dependencies of artcraft since nx is not finding them...'
# A 'clean' will remove nx
npm install
npm install --ignore-scripts
# TODO: Temp commented out
nx build "@storyteller/api"
+3 -3
View File
@@ -37,11 +37,11 @@ rpmbuild --define "_topdir $work/rpmbuild" -bb rpmbuild/SPECS/artcraft.spec
find rpmbuild/RPMS -name '*.rpm' -exec cp {} target/x86_64-unknown-linux-gnu/release/bundle/rpm/ \;
printf 'appimage fixture\n' > target/x86_64-unknown-linux-gnu/release/bundle/appimage/ArtCraft.AppImage
"$script" x86_64 x86_64-unknown-linux-gnu
for format in deb rpm AppImage AppImage.zsync tar.gz; do test -s "dist/release/artcraft-0.42.0-linux-x86_64.$format"; done
for format in deb rpm AppImage AppImage.zsync tar.gz; do [[ -s "dist/release/artcraft-0.42.0-linux-x86_64.$format" ]]; done
mkdir unpacked
tar -xzf dist/release/artcraft-0.42.0-linux-x86_64.tar.gz -C unpacked
test -x unpacked/artcraft-0.42.0-linux-x86_64/bin/artcraft
test -f unpacked/artcraft-0.42.0-linux-x86_64/share/applications/ai.artcraft.app.desktop
[[ -x unpacked/artcraft-0.42.0-linux-x86_64/bin/artcraft ]]
[[ -f unpacked/artcraft-0.42.0-linux-x86_64/share/applications/ai.artcraft.app.desktop ]]
rm target/x86_64-unknown-linux-gnu/release/bundle/rpm/*.rpm
if "$script" x86_64 x86_64-unknown-linux-gnu; then
echo 'Packaging accepted a missing RPM' >&2
+1 -1
View File
@@ -31,7 +31,7 @@ if [[ "${desktops[0]}" != "$work/$base/share/applications/ai.artcraft.app.deskto
fi
install -Dm644 "$script_dir/ai.artcraft.app.metainfo.xml" "$work/$base/share/metainfo/ai.artcraft.app.metainfo.xml"
sed -i 's/^Name=.*/Name=ArtCraft Studio/' "$work/$base/share/applications/ai.artcraft.app.desktop"
test -x "$work/$base/bin/artcraft"
[[ -x "$work/$base/bin/artcraft" ]]
case "$arch" in
x86_64) machine='Advanced Micro Devices X86-64' ;;
aarch64) machine='AArch64' ;;
+1 -1
View File
@@ -15,7 +15,7 @@ config_path="${rust_crate_path}/tauri.conf.json"
pushd "${frontend_path}" || exit
npm install --verbose
npm install --ignore-scripts --verbose
popd || exit
+1 -1
View File
@@ -38,7 +38,7 @@ fi
cd "${frontend_path}"
if [[ ! -f node_modules/vite/package.json ]]; then
# Do not use the legacy install helper: its failure recovery deletes caches.
npm install
npm install --ignore-scripts
fi
exec node "${frontend_path}/scripts/unix-dev.mjs"
@@ -9,7 +9,7 @@ echo ""
pushd "${frontend_path}" || exit
npm install --verbose
npm install --ignore-scripts --verbose
export VITE_ENVIRONMENT_TYPE="production"
@@ -20,7 +20,7 @@ fi
pushd "${frontend_path}" || exit
npm install --verbose
npm install --ignore-scripts --verbose
export VITE_ENVIRONMENT_TYPE="production"
+8 -8
View File
@@ -16,7 +16,7 @@ FRONTEND_MINIMUM_NODE_MAJOR=20
frontend_preflight() {
local frontend_path="$1"
if [ ! -d "${frontend_path}" ]; then
if [[ ! -d "${frontend_path}" ]]; then
echo "ERROR: frontend directory not found at: ${frontend_path}"
echo "Run this script from the repository root."
exit 1
@@ -40,7 +40,7 @@ frontend_preflight() {
# --- Node must be recent enough for Nx 21 / Vite 6 ---
local node_major
node_major=$(node --version | sed -E 's/^v([0-9]+).*/\1/')
if [ "${node_major}" -lt "${FRONTEND_MINIMUM_NODE_MAJOR}" ]; then
if [[ "${node_major}" -lt "${FRONTEND_MINIMUM_NODE_MAJOR}" ]]; then
echo "ERROR: Node.js ${FRONTEND_MINIMUM_NODE_MAJOR}+ is required (found $(node --version))."
echo "Upgrade via nvm ('nvm install --lts') or https://nodejs.org."
exit 1
@@ -50,13 +50,13 @@ frontend_preflight() {
# pnpm was briefly adopted ("add pnpm to solve build issues") and then dropped
# ("fix(frontend): consume video-editor libs via nx path aliases, drop pnpm").
# A node_modules tree written by pnpm makes npm fail with ENOTEMPTY errors.
if [ -e "${frontend_path}/pnpm-lock.yaml" ] \
|| [ -e "${frontend_path}/pnpm-workspace.yaml" ] \
|| [ -d "${frontend_path}/node_modules/.pnpm" ]; then
if [[ -e "${frontend_path}/pnpm-lock.yaml" ]] \
|| [[ -e "${frontend_path}/pnpm-workspace.yaml" ]] \
|| [[ -d "${frontend_path}/node_modules/.pnpm" ]]; then
echo "ERROR: Stale pnpm artifacts detected in ${frontend_path}."
echo "The frontend uses npm (pnpm was dropped; see frontend/README.md)."
echo "Clean up with:"
echo " cd ${frontend_path} && rm -rf node_modules pnpm-lock.yaml pnpm-workspace.yaml && npm install"
echo " cd ${frontend_path} && rm -rf node_modules pnpm-lock.yaml pnpm-workspace.yaml && npm install --ignore-scripts"
exit 1
fi
}
@@ -66,7 +66,7 @@ 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
if npm install --ignore-scripts; then
return 0
fi
@@ -77,7 +77,7 @@ frontend_npm_install() {
rm -rf node_modules .nx
if ! npm install; then
if ! npm install --ignore-scripts; then
echo ""
echo "ERROR: npm install failed again. See the npm output above and the"
echo "troubleshooting section in frontend/README.md."
+15
View File
@@ -6,3 +6,18 @@ sonar.organization=storytold
# as filmcraft and lightcraft excluding tools/docs/examples.
sonar.coverage.exclusions=**/*.ts,**/*.tsx,**/*.js,**/*.jsx
# Not analysed: code that isn't ArtCraft's or isn't run by the app or CI.
# - crates/vendor/: third-party crates kept in the tree.
# - The Python beside the Grok and Sora clients: the upstream reference implementations the Rust ports
# cite ("Based on Grok-Api/core/xctid.py"); nothing runs them.
# - frontend/scripts/unix-dev.mjs and frontend/tools/performance/: developer tools run by hand
# (script/artcraft/unix_dev.sh, `npm run perf:desktop`); they start git, cargo and a browser from
# the developer's own PATH and write where the developer says.
sonar.exclusions=crates/vendor/**,crates/api_clients/grok_consumer_client/src/credentials/_metadata/**,crates/api_clients/openai_sora_client/src/requests/auth_sentinel_2/metadata/python_impl/**,frontend/scripts/unix-dev.mjs,frontend/tools/performance/**
# S4347 (predictable seed): DeterministicRng is the fixed-seed generator for tests and dev seed
# tools; being reproducible is its purpose.
sonar.issue.ignore.multicriteria=deterministic_rng
sonar.issue.ignore.multicriteria.deterministic_rng.ruleKey=rust:S4347
sonar.issue.ignore.multicriteria.deterministic_rng.resourceKey=crates/schema/public/tokens/src/deterministic_rng.rs