Skip to content

Conversation

CoveMB
Copy link
Contributor

@CoveMB CoveMB commented Aug 26, 2025

Summary

  • Introduces a Rust-based Stellar backend service, adds Dockerized dev/prod setups, and reorganizes the AI API into a dedicated packages/ui/api/ai module.
  • Updates CI with Docker build/deploy workflows and a reusable OIDC action.

Key Changes

  • Backend: Stellar service (Rust)
    • New crate: packages/ui/api/stellar with routes, controllers, utils, and tests.
    • Endpoints include GET /health and upgrade/scaffold routes (see src/routes /* and src/controllers/*).
    • Docker: Dockerfile.dev, Dockerfile.prod, .dockerignore, README.md, rustfmt.toml, and Cargo.toml/lock.
    • Tests for routes and utilities under packages/ui/api/stellar/tests/*.
  • AI API Reorg
    • Moves AI API from packages/ui/api/* to packages/ui/api/ai/*:
      • Function definitions now under packages/ui/api/ai/ai-assistant/*.
      • Types, utils, and services moved 1:1 (paths updated).
      • Deno dev server relocated to packages/ui/api/ai/development-server.ts.
      • Adds packages/ui/api/ai/.env.example and Dockerfile.dev.
    • Adds packages/ui/api/docker-compose.yaml to orchestrate local API componen
      ts.
  • CI/CD
    • New GitHub Workflows: .github/workflows/docker-stg.yaml, .github/workflows/docker-prod.yaml.
    • Reusable OIDC action for AWS/GCP auth: .github/actions/oidc/action.yaml.
  • Stellar core utilities
    • Minor packages/core/stellar/src/zip-rust.ts update.
    • Adds packages/core/stellar/zip-env-rust.js to package Rust env/scaffold artifacts.
  • Cairo/Cairo Alpha updates
    • Bumps/aligns versions and test snapshots for Cairo Alpha (v3.0.0-alpha.1).
    • Small fixes in update-scarb-project.ts, erc20.ts, and assorted test updates.
    • Changelog touch-ups in packages/core/cairo_alpha/CHANGELOG.md.
  • UI/Tweaks
    • Minor Svelte app edits across Cairo, Stellar, Stylus pages and shared components.
    • packages/ui/.env.example updated with keys used by the new layout.
    • Minor config updates (.gitignore, .prettierignore, package.json, netlify.toml, .vscode/*, rollup.config.mjs).
  • Changesets and locks
    • Refreshes yarn.lock.

Breaking/Structural Changes

  • AI API paths moved under packages/ui/api/ai. Any imports or tooling referencing the old packages/ui/api/* paths must be updated to the new location.
  • Docker workflows expect OIDC configuration if used for deployment.

How to Run (Local)

  • Stellar service (Rust):
    • From packages/ui/api/stellar: cargo run (dev) or build with Docker: doc ker build -f Dockerfile.dev .
    • Health check: GET /health
  • AI dev server (Deno):
    • From packages/ui/api/ai: deno task dev (see deno.json and development -server.ts)
  • Compose:
    • From packages/ui/api: docker compose up --build
  • Configure environment:
    • Copy .env.example to .env in packages/ui, packages/ui/api/ai, and packages/ui/api/stellar as needed.

Security/Infra

  • Uses GitHub OIDC for secure, short-lived cloud credentials in CI.
  • Dockerfiles refined for dev/prod;
  • Rust service adheres to explicit routes and typed errors/utilities.

Testing/Verification

  • Stellar service includes route and utils tests under packages/ui/api/stellar/ tests/*.
  • Sanity checks:
    • GET /health returns healthy.
    • AI dev server loads and responds with expected mock behavior (when env vars
      set).

Scope/Risk

  • Large move set for AI API;
  • New infra (Docker, OIDC) adds deployment flexibility but requires env/secret configuration.

Copy link

sourcery-ai bot commented Aug 26, 2025

Reviewer's Guide

This PR scaffolds a new Rust-based Stellar backend API deployed via Fargate, integrates it with the existing Svelte UI for scaffold download, reorganizes the AI Deno server and import paths, and updates build/deploy configurations including Docker Compose and GitHub Actions workflows.

Sequence diagram for Svelte UI downloading Stellar scaffold via Fargate backend

sequenceDiagram
    participant User as actor User
    participant SvelteUI as Svelte UI
    participant StellarAPI as Stellar Rust API (Fargate)
    User->>SvelteUI: Click "Download Scaffold"
    SvelteUI->>StellarAPI: POST /stellar/upgrade-scaffold (zip blob)
    StellarAPI->>StellarAPI: Unzip, upgrade, re-zip contract
    StellarAPI-->>SvelteUI: Return scaffold-project.zip
    SvelteUI->>User: Save scaffold-project.zip
Loading

Class diagram for new and updated Rust backend modules

classDiagram
    class ServerConfig {
      +host: String
      +port: u16
      +rate_limit_requests_per_second: u64
      +wizard_origin: String
      +from_environment_variables(): ServerConfig
    }
    class upgrade_scaffold {
      +upgrade_to_scaffold(rust_contract_zip: web::Bytes): Result<Vec<u8>, HttpError>
    }
    class scaffold_upgrade {
      +run_scaffold_upgrade_command(project_dir_path: &Path): Result<(), Error>
    }
    class zip_folder {
      +unzip_in_temporary_folder(zip_data: Vec<u8>, expected_files: &[&str]): Result<TempDir, ZipError>
      +zip_directory(zip_path: &Path): ZipResult<Vec<u8>>
    }
    class errors {
      +to_http_hidden_error<E: Debug>(error: E): HttpError
      +to_io_error<E: Debug>(error: E): IOError
      +to_zip_io_error<E: Debug>(error: E): ZipError
    }
    ServerConfig <|-- upgrade_scaffold
    upgrade_scaffold <|-- scaffold_upgrade
    scaffold_upgrade <|-- zip_folder
    zip_folder <|-- errors
Loading

File-Level Changes

Change Details Files
Introduce Rust Actix-web Stellar API backend
  • Add main server entrypoint with Actix-web, CORS, rate limiting, and routes configuration
  • Implement controllers, routes (health, upgrade_scaffold), environment logic, and utility modules (glob, path, dir, errors)
  • Include Dockerfiles for dev/prod, docker-compose.yaml for local containers, and Cargo.toml/Cargo.lock
  • Add unit tests for health endpoint, glob matching, and environment utilities
packages/ui/api/stellar/src/main.rs
packages/ui/api/stellar/src/config/server.rs
packages/ui/api/stellar/src/controllers/upgrade_scaffold.rs
packages/ui/api/stellar/src/routes/upgrade_scaffold.rs
packages/ui/api/stellar/src/routes/health.rs
packages/ui/api/stellar/src/utils/*
packages/ui/api/stellar/src/environment/*
packages/ui/api/stellar/Dockerfile.dev
packages/ui/api/stellar/Dockerfile.prod
packages/ui/api/docker-compose.yaml
packages/ui/api/stellar/Cargo.toml
packages/ui/api/stellar/Cargo.lock
packages/ui/api/stellar/tests/**/*
Integrate Fargate scaffold endpoint in Svelte UI
  • Expose process.env.FARGATE_HOST and inject into rollup build
  • Replace direct zip download with POST to /stellar/upgrade-scaffold and handle blob response
  • Add isDownloadingScaffold and downloadScaffoldError states, plus conditional button text
  • Import zipRustProjectBlob from core and remove legacy zipScaffoldProject usage
packages/ui/src/stellar/App.svelte
packages/core/stellar/src/zip-rust.ts
packages/core/stellar/zip-env-rust.js
packages/ui/rollup.config.mjs
Extend core Stellar zip utility with blob support
  • Export zipRustProjectBlob that generates a compressed Blob asynchronously
  • Ensure compression and format align with front-end expectations
packages/core/stellar/src/zip-rust.ts
Reorganize AI Deno API structure and update import paths
  • Move development-server.ts and import utils under packages/ui/api/ai, adjust import paths
  • Relocate AI endpoints into api/ai/paths and update dynamic imports in dev server
  • Refactor all ai-assistant imports to use ../ai/ai-assistant and adjust deno.json importMap
  • Update netlify.toml edge_functions path to new api/ai/paths
packages/ui/api/ai/development-server.ts
packages/ui/api/ai/paths/ai.ts
packages/ui/api/ai/**/*/function-definitions/**/*.ts
packages/ui/api/ai/deno.json
netlify.toml
Adjust dev scripts and package.json for API composition
  • Change type:check:api to point at ./api/ai/deno.json and update dev:api to docker-compose up
  • Add dev:api:build script and update root workspace concurrency for UI/API
  • Update root and packages/ui package.json scripts to streamline build, dev, and type check
packages/ui/package.json
package.json
Add GitHub Actions workflows for Docker build & deployment
  • Create production workflow (docker-prod.yaml) to build, scan, and push ECR images and trigger ECS deployment
  • Create staging workflow (docker-stg.yaml) to build, scan, and push staging images and force ECS redeploy
  • Configure OIDC role chaining, QEMU setup, and Anchore scan SARIF upload
.github/workflows/docker-prod.yaml
.github/workflows/docker-stg.yaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

coderabbitai bot commented Aug 26, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Adds a new Rust-based Stellar API service (Actix-web) with secure ZIP handling and a scaffold upgrade endpoint, supporting Docker dev/prod builds and tests. Introduces staging/production GitHub Actions workflows with OIDC role chaining. Refactors AI API paths, adds editor/config ignores, environment samples, and UI changes to call the new scaffold upgrade flow.

Changes

Cohort / File(s) Summary
GitHub Actions: OIDC composite
.github/actions/oidc/action.yaml
New composite action to obtain AWS credentials via OIDC then chain-assume a target role using aws-actions/configure-aws-credentials with pinned commit.
GitHub Workflows: Docker build/deploy
.github/workflows/docker-prod.yaml, .github/workflows/docker-stg.yaml
New workflows for building, scanning (Anchore), pushing multi-arch images to ECR, and deploying to ECS, authenticating via OIDC role chaining.
Repo ignores & editor setup
.gitignore, .prettierignore, .vscode/extensions.json, .vscode/example.settings.json
Ignore new folders/artifacts (e.g., .qodo/, Cargo outputs, *.rs for Prettier). Recommend Rust Analyzer and configure rust-analyzer settings.
Netlify routing/import map
netlify.toml
Points edge functions and import map to packages/ui/api/ai/paths and .../ai/import_map.json.
Root/package scripts
package.json, packages/ui/package.json
Adds root dev:api:build. Updates UI: type:check:api to ./api/ai/deno.json, dev:api to docker-compose, adds dev:api:build.
Env samples
packages/ui/.env.example, packages/ui/api/ai/.env.example, packages/ui/api/stellar/.env.example
New example environment files for UI, AI API, and Stellar API.
Deno AI API: dev infra
packages/ui/api/ai/Dockerfile.dev, packages/ui/api/docker-compose.yaml, packages/ui/api/ai/deno.json, packages/ui/api/ai/development-server.ts, packages/ui/api/ai/paths/ai.ts
Adds dev Dockerfile and docker-compose; updates scripts/paths; refactors imports; adds directory listing helper and new dynamic import target.
AI assistant path refactors
packages/ui/api/ai/ai-assistant/function-definitions/... (cairo*, solidity*, stellar*, stylus*, shared.ts)
Adjusts relative import paths to ../../../..../common/... without logic changes; minor formatting tweaks.
AI assistant types
packages/ui/api/ai/ai-assistant/types/assistant.ts
Adds ChatRoles constant; updates Chat.type.chat.role to derive from it.
Core Stellar helper
packages/core/stellar/src/zip-rust.ts
Adds zipRustProjectBlob to generate a ZIP blob from a Rust project.
Stellar Rust service: project meta
packages/ui/api/stellar/Cargo.toml, README.md, rustfmt.toml, .dockerignore, Dockerfile.dev, Dockerfile.prod
New Rust crate with dev/prod Dockerfiles, formatting config, and documentation; ignores build artifacts in Docker context.
Stellar Rust service: server/config
packages/ui/api/stellar/src/lib.rs, src/main.rs, src/config/mod.rs, src/config/server.rs
Adds server entrypoint, config module with ServerConfig from env vars, rate limiting, CORS, and route wiring.
Stellar Rust service: routes/controllers
packages/ui/api/stellar/src/routes/mod.rs, src/routes/health.rs, src/routes/upgrade_scaffold.rs, src/controllers/mod.rs, src/controllers/upgrade_scaffold.rs
Health route and POST /upgrade-scaffold endpoint; controller to unzip, run scaffold upgrade, and re-zip artifacts.
Stellar Rust service: environment utilities
packages/ui/api/stellar/src/environment/mod.rs, src/environment/zip_folder.rs, src/environment/scaffold_upgrade.rs
Secure ZIP extract/create with limits and glob allowlist; function to run stellar scaffold upgrade.
Stellar Rust service: utils
packages/ui/api/stellar/src/utils/mod.rs, src/utils/errors.rs, src/utils/glob.rs, src/utils/path.rs, src/utils/dir.rs
Error converters; glob utilities; safe path handling (canonicalization, anti-traversal, symlink checks); safe dir/file creation/writes.
Stellar Rust service: tests
packages/ui/api/stellar/tests/... (routes/health.rs, routes/mod.rs, environment/mod.rs, environment/zip_folder.rs, utils/mod.rs, utils/glob.rs, tests_paths.rs)
Adds tests for health route and glob utilities; scaffolds test modules.
UI build config
packages/ui/rollup.config.mjs
Adds process.env.FARGATE_HOST replacement (prod 'TODO', dev `http://localhost:${FARGATE_PORT
UI Svelte: type path updates
packages/ui/src/.../App.svelte (cairo, cairo_alpha, solidity, stylus), packages/ui/src/common/Wiz.svelte
Updates imports to new AI assistant types path; removes one TS suppression comment.
UI Svelte: Stellar scaffold flow
packages/ui/src/stellar/App.svelte
Switches to Rust ZIP flow: builds Rust ZIP blob, POSTs to ${FARGATE_HOST}/stellar/upgrade-scaffold, handles progress/error UI, downloads resulting ZIP, and calls postConfig.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as UI (Stellar App.svelte)
  participant RustAPI as Stellar API (Actix-web)
  participant Env as Env Utils (ZIP & Scaffold)
  note over UI: Build Rust project ZIP (zipRustProjectBlob)

  User->>UI: Click "Scaffold Stellar Package"
  UI->>RustAPI: POST /stellar/upgrade-scaffold (body: rust_project.zip)
  alt Valid ZIP
    RustAPI->>Env: unzip_in_temporary_folder(zip, expected_files)
    Env-->>RustAPI: TempDir with files
    RustAPI->>Env: run_scaffold_upgrade_command(temp_dir)
    alt Upgrade OK
      RustAPI->>Env: zip_directory(temp_dir)
      Env-->>RustAPI: scaffold_project.zip
      RustAPI-->>UI: 200 OK (application/zip)
      UI->>User: Save scaffold-project.zip
    else Upgrade fails
      RustAPI-->>UI: 500 Internal Server Error
      UI->>User: Show error state
    end
  else Invalid ZIP
    RustAPI-->>UI: 415 Unsupported Media Type
    UI->>User: Show error state
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.48% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title refers to the main addition—a Stellar scaffold Fargate backend—and is therefore related to the primary changes in the PR (new Rust Stellar service and Fargate/CI infra). It is short and focused but contains a spelling mistake ("scafold" → "scaffold") and could be slightly clearer about whether it adds the backend or wires it to Fargate. Overall it accurately points at a central change in the changeset.
Description Check ✅ Passed The pull request description is detailed, matches the changes summarized in the diff, and documents key areas (backend, AI reorg, CI/CD, running instructions, and breaking notes), so it is clearly related to the changeset and useful for reviewers. It includes scope, security notes, and testing guidance that map to files and modules added in the summary. The description is not vague or off-topic.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@collins-w collins-w left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CoveMB the release workflows looks ok. I've left some comments. I will also need to provision the required resources to AWS e.g ECS cluster, ALB etc. I will do that work in a different IaC repository.

uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
id: push
with:
context: .

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't have Dockerfile at the root, we need to specify a file setting which points to the dockerfile. e.g
file: .//Dockerfile.production

fetch-depth: 0

- name: Prepare pre-requisites
uses: ./.github/actions/prepare

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add this action. (the prepare action)

Copy link

socket-security bot commented Sep 12, 2025

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

@CoveMB CoveMB marked this pull request as ready for review September 16, 2025 15:12
@CoveMB CoveMB requested review from a team as code owners September 16, 2025 15:12
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/api/stellar/Dockerfile.prod (1)

1-66: Prettier pipeline failing on Dockerfile; exclude it from formatting.

Add the file to .prettierignore to unblock CI.

Additional change outside this file:

+# .prettierignore
+packages/ui/api/stellar/Dockerfile.prod
♻️ Duplicate comments (1)
.github/workflows/docker-prod.yaml (1)

65-77: Specify the correct build context and Dockerfile; no root-level Dockerfile exists.

This step will fail without file: or a corrected context. Point it to the Stellar Dockerfile.

Apply this diff:

-      - name: Build Stellar API Docker image
+      - name: Build Stellar API Docker image (for scan)
         uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
         id: build
         with:
-          context: .
+          context: packages/ui/api/stellar
+          file: Dockerfile.prod
           platforms: linux/amd64 # linux/arm64 causes anchore/scan-action to fail
           tags: |
             ${{ env.REGISTRY }}/wizard-stellar-api-prod:latest
             ${{ env.REGISTRY }}/wizard-stellar-api-prod:${{ github.sha }}
           cache-from: type=gha
           cache-to: type=gha,mode=max
           load: true
🧹 Nitpick comments (66)
.prettierignore (1)

18-19: Confirm intent to skip formatting for .sh and .rs files

  • Ignoring .rs is correct (rustfmt handles Rust).
  • Ignoring .sh will disable any Prettier shell formatting (if a plugin exists). If you rely on shfmt instead, consider documenting it in CONTRIBUTING.md or adding a pre-commit hook.
.gitignore (1)

10-13: Nit: debug/ may be redundant

Cargo places debug artifacts under target/, which is already ignored. Consider removing debug/ to avoid accidentally ignoring non-Cargo debug folders elsewhere.

 # Generated by Cargo
 # will have compiled files and executables
-debug/
 target/
packages/ui/.env.example (1)

1-4: Dotenv style nits and newline

  • Drop quotes around ENV to satisfy common linters.
  • Add a trailing newline.
-ENV="dev"
+ENV=dev
 API_HOST=http://localhost:3000
 FARGATE_HOST=http://localhost:8888
+
packages/ui/api/ai/.env.example (1)

1-2: Add trailing newline

Tiny lint nit; add a newline at EOF.

 API_PORT=3000
-OPENAI_API_KEY=
+OPENAI_API_KEY=
+
packages/ui/api/ai/ai-assistant/function-definitions/shared.ts (2)

2-2: Deep relative import is brittle; prefer import map alias

Recommend adding an alias (e.g., "common/") in packages/ui/api/ai/import_map.json and importing from 'common/src/ai/descriptions/common.ts' to avoid long ../../../ paths.

Example import_map.json entry (outside this diff):

{
  "imports": {
    "common/": "../../../common/"
  }
}

Then:

import { commonDescriptions } from 'common/src/ai/descriptions/common.ts';

31-46: Merge override order likely inverted; shared values currently override commonOptions

If a key exists in both sharedFunctionDescription and commonOptions, the current spread makes shared win. Usually, caller-provided commonOptions should override defaults. Also, avoid rebuilding the merged object inside reduce.

 ) =>
-  commonOptionNames.reduce(
-    (pickedCommonOptions, commonOptionName) => ({
-      ...pickedCommonOptions,
-      [commonOptionName]: { ...commonOptions, ...sharedFunctionDescription }[commonOptionName],
-    }),
-    {} as Pick<typeof sharedFunctionDescription & TCommonOptions, TCommonOptionName>,
-  );
+  {
+    const merged = { ...sharedFunctionDescription, ...commonOptions } as const;
+    return commonOptionNames.reduce(
+      (picked, name) => ({
+        ...picked,
+        [name]: merged[name],
+      }),
+      {} as Pick<typeof merged, TCommonOptionName>,
+    );
+  };
.vscode/extensions.json (1)

5-7: Fix trailing comma (invalid JSON).

extensions.json is strict JSON; the trailing comma after the array breaks parsing.

Apply:

-    "denoland.vscode-deno",
-    "rust-lang.rust-analyzer"
-  ],
+    "denoland.vscode-deno",
+    "rust-lang.rust-analyzer"
+  ]
packages/ui/api/stellar/.env.example (1)

1-2: Add trailing newline; consider documenting configurable port/host.

  • Lint: file should end with a newline.
  • Optional: if the server supports HOST/PORT vars, add them here for discoverability.

Can you confirm the exact env var names for host/port in packages/ui/api/stellar/src/config so we can include them?

packages/ui/api/stellar/rustfmt.toml (1)

2-5: Remove unsupported rustfmt options; set edition in Cargo.toml.

  • rustfmt reads edition from Cargo.toml, not rustfmt.toml.
  • use_try_shorthand/use_field_init_shorthand are unstable or not honored in stable; they’ll be ignored and emit warnings.

Apply:

-max_width = 100
-tab_spaces = 4
-hard_tabs = false
-edition = "2024"
+max_width = 100
+tab_spaces = 4
+hard_tabs = false
@@
-use_try_shorthand = true
-use_field_init_shorthand = true
+## Consider enabling only if you opt into nightly + unstable_features
+# unstable_features = false

And in packages/ui/api/stellar/Cargo.toml set:

[package]
edition = "2024"  # if you’re actually on Rust 2024; otherwise "2021"

Also applies to: 17-19

.vscode/example.settings.json (1)

11-13: Fix rust-analyzer linked project path (crate lives under api/stellar).

Current path points to packages/ui/stellar, which doesn’t exist after the reorg.

Apply:

-  "rust-analyzer.linkedProjects": [
-    "packages/ui/stellar/Cargo.toml"
-  ],
+  "rust-analyzer.linkedProjects": [
+    "packages/ui/api/stellar/Cargo.toml"
+  ],
packages/ui/api/stellar/README.md (1)

1-1: Fix heading indentation and make Docker build explicit.

  • Remove leading spaces so headings lint cleanly.
  • Use -f Dockerfile.prod to avoid ambiguity.

Apply:

- # Stellar Backend (Actix-web)
+# Stellar Backend (Actix-web)
@@
- ## Local Run
+## Local Run
@@
- ## Docker
+## Docker
@@
- docker build -t stellar packages/ui/api/stellar
+ docker build -f Dockerfile.prod -t stellar packages/ui/api/stellar
  docker run -p 8888:8888 stellar

Optional: add a quick check tip:

curl -fsS http://localhost:8888/health

Also applies to: 5-5, 14-14, 16-19

packages/ui/src/cairo_alpha/App.svelte (1)

306-333: Remove unused .controls-footer styles (silence Svelte warnings).

CI warns these selectors are unused.

Apply:

-  .controls-footer {
-    display: flex;
-    flex-direction: row;
-    justify-content: flex-end;
-    color: var(--gray-5);
-    margin-top: var(--size-3);
-    padding: 0 var(--size-2);
-    font-size: var(--text-small);
-
-    & > * + * {
-      margin-left: var(--size-3);
-    }
-
-    :global(.icon) {
-      margin-right: 0.2em;
-      opacity: 0.8;
-    }
-
-    a {
-      color: inherit;
-      text-decoration: none;
-
-      &:hover {
-        color: var(--text-color);
-      }
-    }
-  }
packages/ui/api/stellar/Dockerfile.dev (1)

14-14: Fix syntax error in package installation.

Missing space between gdb and backslash continuation.

-    gdb\
+    gdb \
packages/ui/api/stellar/src/utils/glob.rs (3)

9-20: Avoid intermediate Vec and generalize input; keep one pass build.

Removes an allocation and broadens usability to any IntoIterator of AsRef.

-pub fn build_globset(patterns: Vec<String>) -> Result<GlobSet, GlobError> {
-    patterns
-        .iter()
-        .map(|p| Glob::new(p))
-        .collect::<Result<Vec<_>, _>>()?
-        .into_iter()
-        .fold(GlobSetBuilder::new(), |mut builder, glob| {
-            builder.add(glob);
-            builder
-        })
-        .build()
-}
+pub fn build_globset<I, S>(patterns: I) -> Result<GlobSet, GlobError>
+where
+    I: IntoIterator<Item = S>,
+    S: AsRef<str>,
+{
+    patterns
+        .into_iter()
+        .try_fold(GlobSetBuilder::new(), |mut builder, p| {
+            let glob = Glob::new(p.as_ref())?;
+            builder.add(glob);
+            Ok::<_, GlobError>(builder)
+        })?
+        .build()
+}

22-28: Rename parameter for clarity: it's a candidate path, not a glob.

Small readability win; avoids confusion with pattern vs input.

-pub fn is_glob_match(matchers: &GlobSet, glob: &str) -> Result<usize, MatchError> {
-    matchers
-        .matches(glob)
+pub fn is_glob_match(matchers: &GlobSet, candidate: &str) -> Result<usize, MatchError> {
+    matchers
+        .matches(candidate)
         .first()
         .copied()
-        .ok_or_else(|| MatchError::NoMatch(glob.to_string()))
+        .ok_or_else(|| MatchError::NoMatch(candidate.to_string()))
 }

3-7: Unused error variant; either wire it or drop it.

MatchError::Glob isn’t produced anywhere. Consider adding impl From<GlobError> for MatchError or removing the variant until needed.

+impl From<GlobError> for MatchError {
+    fn from(e: GlobError) -> Self {
+        MatchError::Glob(e)
+    }
+}
packages/ui/api/stellar/src/utils/path.rs (5)

6-20: Preserve error kinds; don’t downgrade NotFound to Other.

Keep semantics so callers can branch on kind.

-    let can_path = canonicalize(dir).map_err(|e| {
-        if e.kind() == IoErrorKind::NotFound {
-            IoError::other("Directory does not exist")
-        } else {
-            e
-        }
-    })?;
+    let can_path = canonicalize(dir).map_err(|e| {
+        if e.kind() == IoErrorKind::NotFound {
+            IoError::new(IoErrorKind::NotFound, "directory does not exist")
+        } else {
+            e
+        }
+    })?;
 
     if !can_path.is_dir() {
-        return Err(IoError::other("destination is not a directory"));
+        return Err(IoError::new(IoErrorKind::InvalidInput, "destination is not a directory"));
     }

30-40: Normalize separators for ancestors on all platforms.

Without this, Windows ancestors may reintroduce backslashes and then you append “/”, producing mixed separators.

-        .map(|a| a.components()
-             .filter(|c| !matches!(c, Component::CurDir))
-             .collect::<std::path::PathBuf>()
-             .to_string_lossy()
-             .into_owned())
+        .map(|a| {
+            let s = a
+                .components()
+                .filter(|c| !matches!(c, Component::CurDir))
+                .collect::<PathBuf>()
+                .to_string_lossy()
+                .into_owned();
+            norm(&s)
+        })

42-57: Return order should be deterministic.

Set iteration order is arbitrary; sort for stable results and flake‑free tests.

-    set.into_iter().collect()
+    let mut out: Vec<_> = set.into_iter().collect();
+    out.sort();
+    out

67-97: Use consistent error kinds and messages.

Prefer InvalidInput over Other for validation failures; keep messages consistent.

     let rel = path
         .strip_prefix(root)
-        .map_err(|_| IoError::other("path escapes root"))?;
+        .map_err(|_| IoError::new(IoErrorKind::InvalidInput, "path escapes root"))?;
@@
             let ft = symlink_metadata(&p)?.file_type();
             if ft.is_symlink() {
-                Err(IoError::other("symlink detected"))
+                Err(IoError::new(IoErrorKind::InvalidInput, "symlink detected"))
             } else {
                 Ok(())
             }
         })?;
@@
-        Ok(meta) if meta.file_type().is_symlink() => {
-            return Err(IoError::other("symlink detected"))
-        }
+        Ok(meta) if meta.file_type().is_symlink() => {
+            return Err(IoError::new(IoErrorKind::InvalidInput, "symlink detected"))
+        }

30-40: De-duplicate helpers across modules.

There’s another ancestors_rel in environment/zip_folder.rs (PathBuf-based). Consider consolidating to one impl to avoid drift.

.github/actions/oidc/action.yaml (4)

33-33: Clarify 900s session or make it configurable.

You expose role-duration-seconds but fix step 1 to 900. Either document why, or parameterize with a separate input (e.g., oidc-role-duration-seconds).


38-41: Prefer action outputs over env passthrough for chaining.

Using ${{ steps.<id>.outputs.* }} is clearer and avoids accidental env leakage.

Example (no diff applied):

  • Give step 1 an id (e.g., id: assume-oidc-role).
  • Then: aws-access-key-id: ${{ steps.assume-oidc-role.outputs.aws-access-key-id }} etc.

45-45: Add a trailing newline.

Fixes YAML lint error.

-        role-duration-seconds: ${{ inputs.role-duration-seconds }}
+        role-duration-seconds: ${{ inputs.role-duration-seconds }}
+

24-45: Pin is fine — latest release is v5.0.0 (2025-09-03), which is a major upgrade.
Keep the commit SHA pin; schedule periodic checks to auto-bump pins for new minor/patch releases, but require manual review and testing before upgrading to v5.x (major) due to possible breaking changes.

packages/ui/api/stellar/tests/environment/zip_folder.rs (1)

1-1: Empty test module; add at least one smoke test or remove placeholder.

Prevents stale scaffolding; happy to draft tests against unzip/zip helpers.

packages/ui/api/ai/ai-assistant/function-definitions/stellar.ts (1)

102-106: Duplicate property key: 'upgradeable' is defined twice in NonFungible; the latter overrides the spread.
Keep one source of truth to avoid drift.

Apply:

       sequential: {
         type: 'boolean',
         description: stellarNonFungibleDescriptions.sequential,
       },
-      upgradeable: {
-        type: 'boolean',
-        description: stellarCommonDescriptions.upgradeable,
-      },
packages/ui/src/solidity/App.svelte (1)

356-374: Silence Svelte warnings by removing unused CSS selectors.
These selectors are flagged as unused in CI; safe to drop.

Apply:

-  .button-bg:hover {
-    transform: translateX(-2px);
-    transition: transform 300ms;
-  }
-
-  .hide-deploy {
-    transform: translateX(-320px);
-    transition: transform 0.45s;
-  }
-  .hide-deploy button {
-    background-color: white;
-    border: 1px solid white;
-  }
-
-  .hide-deploy:hover {
-    transform: translatex(-318px);
-  }
+  /* (removed unused .button-bg:hover and .hide-deploy styles) */
-  .controls-footer {
-    display: flex;
-    flex-direction: row;
-    justify-content: flex-end;
-    color: var(--gray-5);
-    margin-top: var(--size-3);
-    padding: 0 var(--size-2);
-    font-size: var(--text-small);
-
-    & > * + * {
-      margin-left: var(--size-3);
-    }
-
-    :global(.icon) {
-      margin-right: 0.2em;
-      opacity: 0.8;
-    }
-
-    a {
-      color: inherit;
-      text-decoration: none;
-
-      &:hover {
-        color: var(--text-color);
-      }
-    }
-  }
+  /* (removed unused .controls-footer block) */

Also applies to: 457-483

packages/ui/src/stylus/App.svelte (1)

278-304: Remove unused CSS selector for .controls-footer and related styles.

The pipeline failure indicates these CSS selectors are unused. Since this appears to be dead CSS code, it should be cleaned up.

Apply this diff to remove the unused CSS:

-  .controls-footer {
-    display: flex;
-    flex-direction: row;
-    justify-content: flex-end;
-    color: var(--gray-5);
-    margin-top: var(--size-3);
-    padding: 0 var(--size-2);
-    font-size: var(--text-small);
-
-    & > * + * {
-      margin-left: var(--size-3);
-    }
-
-    :global(.icon) {
-      margin-right: 0.2em;
-      opacity: 0.8;
-    }
-
-    a {
-      color: inherit;
-      text-decoration: none;
-
-      &:hover {
-        color: var(--text-color);
-      }
-    }
-  }
packages/ui/src/cairo/App.svelte (1)

300-326: Remove unused CSS selector for .controls-footer and related styles.

The pipeline failure indicates these CSS selectors are unused. Since this appears to be dead CSS code, it should be cleaned up.

Apply this diff to remove the unused CSS:

-  .controls-footer {
-    display: flex;
-    flex-direction: row;
-    justify-content: flex-end;
-    color: var(--gray-5);
-    margin-top: var(--size-3);
-    padding: 0 var(--size-2);
-    font-size: var(--text-small);
-
-    & > * + * {
-      margin-left: var(--size-3);
-    }
-
-    :global(.icon) {
-      margin-right: 0.2em;
-      opacity: 0.8;
-    }
-
-    a {
-      color: inherit;
-      text-decoration: none;
-
-      &:hover {
-        color: var(--text-color);
-      }
-    }
-  }
packages/ui/api/stellar/src/environment/mod.rs (1)

1-4: Tighten public surface: avoid glob re‑exports.

Export only the intended symbols to prevent accidental API bloat and semver churn.

-mod zip_folder;
-pub use zip_folder::*;
-mod scaffold_upgrade;
-pub use scaffold_upgrade::*;
+//! Public environment utilities (keep exports minimal).
+mod zip_folder;
+pub use zip_folder::{ZipEntryLimits, unzip_in_temporary_folder, zip_directory, expected_entry_count};
+mod scaffold_upgrade;
+pub use scaffold_upgrade::run_scaffold_upgrade_command;
packages/ui/api/stellar/src/routes/health.rs (1)

1-14: Add HEAD and no-store; be explicit on content type.

Health endpoints are often cached by proxies; add Cache-Control: no-store and support HEAD.

-//! This module provides a health check endpoint for the API.
-//! The `/health` endpoint can be used to verify that the service is running and responsive.
-use actix_web::{get, web, HttpResponse};
+//! This module provides a health check endpoint for the API.
+//! The `/health` endpoint can be used to verify that the service is running and responsive.
+use actix_web::{get, head, http::header, web, HttpResponse};

-#[get("/health")]
-async fn health() -> Result<HttpResponse, actix_web::Error> {
-    Ok(HttpResponse::Ok().body("OK"))
-}
+#[get("/health")]
+async fn health() -> HttpResponse {
+    HttpResponse::Ok()
+        .insert_header((header::CACHE_CONTROL, "no-store"))
+        .insert_header((header::CONTENT_TYPE, "text/plain; charset=utf-8"))
+        .body("OK")
+}
+
+#[head("/health")]
+async fn health_head() -> HttpResponse {
+    HttpResponse::Ok()
+        .insert_header((header::CACHE_CONTROL, "no-store"))
+        .finish()
+}

 /// Initializes the health check service.
 /// Registers the `health` endpoint with the provided service configuration.
 
 pub fn init(cfg: &mut web::ServiceConfig) {
-    cfg.service(health);
+    cfg.service(health).service(health_head);
 }
packages/ui/api/stellar/src/config/mod.rs (1)

1-2: Re-export only the needed types.

Prefer explicit re-exports to keep the config surface stable.

-mod server;
-pub use server::*;
+//! Server configuration surface.
+mod server;
+pub use server::ServerConfig;
packages/ui/api/stellar/src/controllers/mod.rs (1)

1-2: Make controller re-exports explicit.

Expose only the intended handler(s) to avoid leaking internals.

-mod upgrade_scaffold;
-pub use upgrade_scaffold::*;
+mod upgrade_scaffold;
+pub use upgrade_scaffold::upgrade_to_scaffold;
packages/ui/api/ai/ai-assistant/function-definitions/cairo-shared.ts (1)

3-7: Use a tsconfig path alias for the common package

Deep relative imports are brittle — add a path alias and update the imports in packages/ui/api/ai/ai-assistant/function-definitions/cairo-shared.ts (lines ~3-7).

-import { infoDescriptions } from '../../../../../common/src/ai/descriptions/common.ts';
+import { infoDescriptions } from '@common/ai/descriptions/common.ts';
 import {
   cairoCommonDescriptions,
   cairoRoyaltyInfoDescriptions,
-} from '../../../../../common/src/ai/descriptions/cairo.ts';
+} from '@common/ai/descriptions/cairo.ts';

Add to packages/ui/tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@common/*": ["../common/src/*"]
    }
  }
}

Verify no remaining deep imports:

rg -nP -S '\.\./\.\./\.\./\.\./\.\./common/src/ai/descriptions/(common|cairo)\.ts' packages -g '!**/dist/**'
packages/ui/package.json (1)

10-11: Prefer Docker Compose v2 CLI (or provide a fallback).

Most environments expose Compose as docker compose (v2). Using docker-compose can break dev flows.

Apply this diff:

-    "dev:api": "cd api && docker-compose up",
-    "dev:api:build": "cd api && docker-compose up --build",
+    "dev:api": "cd api && docker compose up",
+    "dev:api:build": "cd api && docker compose up --build",
packages/ui/api/stellar/src/lib.rs (1)

9-11: Doc grammar nit.

“create, upgrading and zipping” → “creating, upgrading, and zipping”.

Apply this diff:

-//! * `environment` - The logic for create, upgrading and zipping the contract environment
+//! * `environment` - The logic for creating, upgrading, and zipping the contract environment
packages/ui/api/stellar/src/controllers/upgrade_scaffold.rs (4)

7-14: Remove unused helper to avoid dead code warnings.

list_files is not used and will trigger a warning in CI with -D warnings.

Apply this diff:

-fn list_files(dir: &Path) -> Vec<PathBuf> {
-    WalkDir::new(dir)
-        .into_iter()
-        .filter_map(|e| e.ok())
-        .filter(|e| e.file_type().is_file())
-        .map(|e| e.into_path())
-        .collect()
-}

16-25: Hoist expected file patterns to a module-level constant.

Avoids re-allocating on each call and clarifies intent.

Apply this diff:

-pub async fn upgrade_to_scaffold(rust_contract_zip: web::Bytes) -> Result<Vec<u8>, HttpError> {
-    let contract_zipped_files = [
+const CONTRACT_ZIPPED_FILES: &[&str] = &[
         "contracts/*/src/contract.rs",
         "contracts/*/src/test.rs",
         "contracts/*/src/lib.rs",
         "contracts/*/Cargo.toml",
         "Cargo.toml",
         "README.md",
-    ];
+];
+
+pub async fn upgrade_to_scaffold(rust_contract_zip: web::Bytes) -> Result<Vec<u8>, HttpError> {

26-31: Don’t block Actix workers; offload the external CLI to a blocking thread.

run_scaffold_upgrade_command is synchronous; running it on the worker can starve the server under load.

Apply this diff:

-    let contracts_dir =
-        unzip_in_temporary_folder(rust_contract_zip.to_vec(), &contract_zipped_files)
+    let contracts_dir =
+        unzip_in_temporary_folder(rust_contract_zip.to_vec(), CONTRACT_ZIPPED_FILES)
             .map_err(to_http_hidden_error)?;
 
-    run_scaffold_upgrade_command(contracts_dir.path()).map_err(to_http_hidden_error)?;
+    let project_dir = contracts_dir.path().to_path_buf();
+    web::block(move || run_scaffold_upgrade_command(project_dir.as_path()))
+        .await
+        .map_err(to_http_hidden_error)?
+        .map_err(to_http_hidden_error)?;

32-35: Zip work can be heavy; consider offloading as well.

Zipping large trees can block a worker thread; offload similarly.

Apply this diff:

-    let zipped_env = zip_directory(contracts_dir.path()).map_err(to_http_hidden_error)?;
+    let zip_root = contracts_dir.path().to_path_buf();
+    let zipped_env = web::block(move || zip_directory(zip_root.as_path()))
+        .await
+        .map_err(to_http_hidden_error)?
+        .map_err(to_http_hidden_error)?;
packages/ui/api/stellar/src/environment/scaffold_upgrade.rs (1)

7-25: Consider adding a timeout and using async process APIs.

A hung stellar scaffold upgrade would block indefinitely. Using tokio::process with a timeout improves resilience.

If you choose to adopt this, we’ll also update the call site to .await the async function.

-use std::{
-    io::Error,
-    process::{Command, Stdio},
-};
+use std::io::Error;
+use std::time::Duration;
+use tokio::process::Command;
+use tokio::time::timeout;
 
-pub fn run_scaffold_upgrade_command(project_dir_path: &Path) -> Result<(), Error> {
-    let output = Command::new("stellar")
+pub async fn run_scaffold_upgrade_command(project_dir_path: &Path) -> Result<(), Error> {
+    let child = Command::new("stellar")
         .args(["scaffold", "upgrade", "--skip-prompt"])
         .stdin(Stdio::null())
         .stdout(Stdio::null())
         .stderr(Stdio::piped())
         .current_dir(project_dir_path)
-        .output()?;
+        .output();
+
+    let output = timeout(Duration::from_secs(60), child)
+        .await
+        .map_err(|_| Error::other("Timed out running 'stellar scaffold upgrade'"))??;
 
     if output.status.success() {
         Ok(())
     } else {
         Err(Error::other(format!(
             "'stellar scaffold upgrade' failed with code {:?}: {}",
             output.status.code(),
             String::from_utf8_lossy(&output.stderr)
         )))
     }
 }
.github/workflows/docker-prod.yaml (2)

131-133: Add trailing newline.

YAML lint flags “no newline at end of file”.

Apply this diff:

-          aws ecs update-service --cluster $ECS_CLUSTER --service $ECS_SERVICE --force-new-deployment --region $AWS_REGION
+          aws ecs update-service --cluster $ECS_CLUSTER --service $ECS_SERVICE --force-new-deployment --region $AWS_REGION
+

1-8: Trigger on release is fine; consider tagging images with the release tag too.

In addition to latest and sha, pushing ${{ github.event.release.tag_name }} helps traceability.

packages/ui/api/docker-compose.yaml (4)

6-8: Use a dev Dockerfile for the dev service.

You’re building the dev service with Dockerfile.prod. Switch back to .dev as per TODO.

Apply this diff:

-      # TODO revert to .dev
-      dockerfile: Dockerfile.prod
+      dockerfile: Dockerfile.dev

31-34: Mount common assets read-only to avoid accidental writes.

Safer defaults for shared code/assets.

Apply this diff:

-      - ../../common:/app/common
+      - ../../common:/app/common:ro

46-51: Prune unused named volumes.

stellar-* volumes are defined but not mounted; remove or comment until used.

 volumes:
-  stellar-cargo-target:
-  stellar-cargo-cache:
-  stellar-cargo-git:
-  stellar-tmp:
   deno-cache:

2-25: Optional: add healthchecks for faster feedback.

Healthchecks help docker compose report readiness for both services.

I can draft healthcheck commands if you share the ports/paths (e.g., GET /health for Stellar).

packages/ui/api/stellar/src/routes/upgrade_scaffold.rs (1)

28-30: Update init to register renamed handler.

Apply:

 pub fn init(cfg: &mut web::ServiceConfig) {
-    cfg.service(download_scaffold_route);
+    cfg.service(upgrade_scaffold_route);
 }
packages/ui/api/stellar/src/utils/dir.rs (2)

7-17: Tighten unix-only import usage and remove redundant use DirBuilderExt;.

The local use DirBuilderExt; is unnecessary; fully qualify or rely on the gated import.

Apply:

 #[cfg(unix)]
 {
-        use DirBuilderExt;
         let mut b = DirBuilder::new();
         b.recursive(true)
             .mode(0o700)
             .create(path)
             .map_err(to_io_error)
 }

24-49: Good secure file creation; consider Windows hardening (optional).

Unix path uses O_NOFOLLOW and 0600; ensure_no_symlinks is also called pre-open. On Windows there’s no O_NOFOLLOW; if this will run on Windows, consider an extra symlink_metadata check after open() to ensure the created handle isn’t a reparse point.

.github/workflows/docker-stg.yaml (4)

1-3: Header comment doesn’t match triggers.

Comment says “whenever a release is created”, but the workflow triggers on pushes to staging and manual dispatch.

Apply:

-# This workflow runs whenever a release is created.
-# The image is tagged with latest and the release version.
+# Builds, scans, and deploys on push to `staging` or manual dispatch.

49-54: Validate OIDC role chaining early.

Add a quick identity check to fail fast if role assumption breaks.

Apply:

       - name: Set up AWS credentials via OIDC and role chaining
         uses: ./.github/actions/oidc
         with:
           role-for-oidc: ${{ env.ROLE_FOR_OIDC }}
           role-to-assume: ${{ env.ROLE_TO_ASSUME }}
+      - name: Verify AWS caller identity
+        run: aws sts get-caller-identity

@@
       - name: Set up AWS credentials via OIDC and role chaining
         uses: ./.github/actions/oidc
         with:
           role-for-oidc: ${{ env.ROLE_FOR_OIDC }}
           role-to-assume: ${{ env.ROLE_TO_ASSUME }}
+      - name: Verify AWS caller identity
+        run: aws sts get-caller-identity

Also applies to: 118-123


71-77: Consider failing on high-severity vulns.

Currently fail-build: false. Consider gating on high/critical severity.

Example:

-          fail-build: false
+          fail-build: true
+          severity-cutoff: high

126-126: Add newline at end of file.

YAML linter error: missing trailing newline.

packages/ui/api/stellar/src/config/server.rs (2)

20-23: Docs vs code mismatch for APP_PORT default.

Doc says 8080; code defaults to 8888. Make them consistent (pick one).

Apply either:

  • Update docs to 8888:
-    /// - `APP_PORT` defaults to `8080`.
+    /// - `APP_PORT` defaults to `8888`.
  • Or change default to 8080:
-            port: env::var("APP_PORT")
-                .unwrap_or_else(|_| "8888".to_string())
+            port: env::var("APP_PORT")
+                .unwrap_or_else(|_| "8080".to_string())
                 .parse()
-                .unwrap_or(8888),
+                .unwrap_or(8080),

Also applies to: 26-29


30-36: Nit: clarify wizard_origin default in docs.

Consider documenting the WIZARD_ORIGIN default alongside others for completeness.

packages/ui/src/stellar/App.svelte (3)

37-38: Guard missing FARGATE_HOST.

Avoid an invalid URL like “undefined/stellar/…”.

-const fargateHost = process.env.FARGATE_HOST;
+const fargateHost = process.env.FARGATE_HOST ?? '';

260-266: Minor UX: ensure the progress text shows during retries.

Because downloadScaffoldError isn’t cleared until success, users may still see the error message while a new attempt is in progress (since the error branch is checked first). The diff above clears it before starting.


309-309: Clean up unused selectors to satisfy the pipeline.

.controls-footer (and nested rules) are unused; remove or reintroduce the markup.

packages/ui/api/stellar/src/environment/zip_folder.rs (2)

214-215: Nit: typo in comment.

“EvLUATE” -> “Evaluate”.


255-259: Use 0644 for files; reserve 0755 for directories.

Avoid making all files executable in the ZIP.

 fn default_options() -> FileOptions<'static, ()> {
-    FileOptions::default()
-        .compression_method(CompressionMethod::Deflated)
-        .unix_permissions(0o755)
+    FileOptions::default()
+        .compression_method(CompressionMethod::Deflated)
+        .unix_permissions(0o644)
 }
packages/core/stellar/src/zip-rust.ts (1)

60-64: Unnecessary async/await nesting; simplify and avoid double-await.

Make zipRustProject sync and call generateAsync directly in zipRustProjectBlob.

-export const zipRustProject = async (c: Contract, opts: GenericOptions) =>
-  addRustProjectReadme(createRustZipEnvironment(c, opts));
+export const zipRustProject = (c: Contract, opts: GenericOptions) =>
+  addRustProjectReadme(createRustZipEnvironment(c, opts));

-export const zipRustProjectBlob = async (c: Contract, opts: GenericOptions) =>
-  await (await zipRustProject(c, opts)).generateAsync({ type: 'blob', compression: 'DEFLATE' });
+export const zipRustProjectBlob = (c: Contract, opts: GenericOptions) =>
+  zipRustProject(c, opts).generateAsync({ type: 'blob', compression: 'DEFLATE' });

Optionally, maximize compression:

-  ... { type: 'blob', compression: 'DEFLATE' });
+  ... { type: 'blob', compression: 'DEFLATE', compressionOptions: { level: 9 } });
packages/ui/api/stellar/Dockerfile.prod (2)

50-57: Large runtime image and unnecessary toolchain in final image.

Copying Cargo/Rustup homes bloats the image and increases attack surface. You already copy the needed binaries; drop the toolchains.

-ENV CARGO_HOME=/usr/local/cargo
-ENV RUSTUP_HOME=/usr/local/rustup
-ENV PATH=/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
-COPY --from=builder /usr/local/cargo/ $CARGO_HOME
-COPY --from=builder /usr/local/rustup/ $RUSTUP_HOME
-
-RUN rm -rf /usr/local/cargo/registry /usr/local/cargo/git
+ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Result: smaller image, fewer CVE surfaces.


29-33: Speed up builds with BuildKit caches for the target dir.

Cache the target directory between builds.

-RUN TMPDIR=/opt/tmp cargo build --release
+RUN --mount=type=cache,target=/opt/target,sharing=locked \
+    TMPDIR=/opt/tmp cargo build --release
packages/ui/api/ai/development-server.ts (1)

5-7: Mixing two std path versions; import both from the same pinned module.

Avoid split-version imports to prevent subtle incompatibilities.

-import { dirname } from 'https://deno.land/std/path/mod.ts';
-import { join } from 'https://deno.land/[email protected]/path/mod.ts';
+import { dirname, join } from 'https://deno.land/[email protected]/path/mod.ts';
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 607dd0c and a017ba9.

⛔ Files ignored due to path filters (2)
  • packages/ui/api/ai/deno.lock is excluded by !**/*.lock
  • packages/ui/api/stellar/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (68)
  • .github/actions/oidc/action.yaml (1 hunks)
  • .github/workflows/docker-prod.yaml (1 hunks)
  • .github/workflows/docker-stg.yaml (1 hunks)
  • .gitignore (1 hunks)
  • .prettierignore (1 hunks)
  • .vscode/example.settings.json (1 hunks)
  • .vscode/extensions.json (1 hunks)
  • netlify.toml (1 hunks)
  • package.json (2 hunks)
  • packages/core/stellar/src/zip-rust.ts (1 hunks)
  • packages/ui/.env.example (1 hunks)
  • packages/ui/api/ai/.env.example (1 hunks)
  • packages/ui/api/ai/Dockerfile.dev (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-alpha-shared.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-alpha.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-shared.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/cairo.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/shared.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/solidity-shared.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/solidity.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/stellar-shared.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/stellar.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/stylus-shared.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/function-definitions/stylus.ts (1 hunks)
  • packages/ui/api/ai/ai-assistant/types/assistant.ts (1 hunks)
  • packages/ui/api/ai/deno.json (1 hunks)
  • packages/ui/api/ai/development-server.ts (2 hunks)
  • packages/ui/api/ai/paths/ai.ts (1 hunks)
  • packages/ui/api/docker-compose.yaml (1 hunks)
  • packages/ui/api/stellar/.dockerignore (1 hunks)
  • packages/ui/api/stellar/.env.example (1 hunks)
  • packages/ui/api/stellar/Cargo.toml (1 hunks)
  • packages/ui/api/stellar/Dockerfile.dev (1 hunks)
  • packages/ui/api/stellar/Dockerfile.prod (1 hunks)
  • packages/ui/api/stellar/README.md (1 hunks)
  • packages/ui/api/stellar/rustfmt.toml (1 hunks)
  • packages/ui/api/stellar/src/config/mod.rs (1 hunks)
  • packages/ui/api/stellar/src/config/server.rs (1 hunks)
  • packages/ui/api/stellar/src/controllers/mod.rs (1 hunks)
  • packages/ui/api/stellar/src/controllers/upgrade_scaffold.rs (1 hunks)
  • packages/ui/api/stellar/src/environment/mod.rs (1 hunks)
  • packages/ui/api/stellar/src/environment/scaffold_upgrade.rs (1 hunks)
  • packages/ui/api/stellar/src/environment/zip_folder.rs (1 hunks)
  • packages/ui/api/stellar/src/lib.rs (1 hunks)
  • packages/ui/api/stellar/src/main.rs (1 hunks)
  • packages/ui/api/stellar/src/routes/health.rs (1 hunks)
  • packages/ui/api/stellar/src/routes/mod.rs (1 hunks)
  • packages/ui/api/stellar/src/routes/upgrade_scaffold.rs (1 hunks)
  • packages/ui/api/stellar/src/utils/dir.rs (1 hunks)
  • packages/ui/api/stellar/src/utils/errors.rs (1 hunks)
  • packages/ui/api/stellar/src/utils/glob.rs (1 hunks)
  • packages/ui/api/stellar/src/utils/mod.rs (1 hunks)
  • packages/ui/api/stellar/src/utils/path.rs (1 hunks)
  • packages/ui/api/stellar/tests/environment/mod.rs (1 hunks)
  • packages/ui/api/stellar/tests/environment/zip_folder.rs (1 hunks)
  • packages/ui/api/stellar/tests/routes/health.rs (1 hunks)
  • packages/ui/api/stellar/tests/routes/mod.rs (1 hunks)
  • packages/ui/api/stellar/tests/tests_paths.rs (1 hunks)
  • packages/ui/api/stellar/tests/utils/glob.rs (1 hunks)
  • packages/ui/api/stellar/tests/utils/mod.rs (1 hunks)
  • packages/ui/package.json (2 hunks)
  • packages/ui/rollup.config.mjs (1 hunks)
  • packages/ui/src/cairo/App.svelte (1 hunks)
  • packages/ui/src/cairo_alpha/App.svelte (1 hunks)
  • packages/ui/src/common/Wiz.svelte (1 hunks)
  • packages/ui/src/solidity/App.svelte (1 hunks)
  • packages/ui/src/stellar/App.svelte (3 hunks)
  • packages/ui/src/stylus/App.svelte (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-19T15:21:06.991Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#638
File: packages/core/cairo_alpha/src/account.test.ts.md:18-18
Timestamp: 2025-08-19T15:21:06.991Z
Learning: In the OpenZeppelin contracts-wizard repository, the cairo_alpha package (packages/core/cairo_alpha) and the stable cairo package (packages/core/cairo) are separate implementations that do not need to have the same code or matching dependency versions. The cairo_alpha package targets dependencies that are either newer than or the same as the stable cairo package, allowing it to test and support newer Cairo/Scarb/OpenZeppelin versions while the stable version maintains compatibility with stable releases.

Applied to files:

  • packages/ui/api/ai/ai-assistant/function-definitions/cairo.ts
  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-alpha-shared.ts
  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-alpha.ts
📚 Learning: 2025-08-19T15:31:24.984Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#0
File: :0-0
Timestamp: 2025-08-19T15:31:24.984Z
Learning: Changes within packages/core/cairo_alpha should have a corresponding changelog entry in packages/core/cairo_alpha/CHANGELOG.md under the Unreleased section to track these changes. When cairo_alpha is eventually promoted to cairo (stable), these entries will be moved into a changeset for cairo (stable).

Applied to files:

  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-alpha-shared.ts
  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-alpha.ts
📚 Learning: 2025-08-19T15:18:09.410Z
Learnt from: ericglau
PR: OpenZeppelin/contracts-wizard#638
File: packages/core/cairo_alpha/src/scripts/update-scarb-project.ts:62-79
Timestamp: 2025-08-19T15:18:09.410Z
Learning: In the cairo_alpha package (packages/core/cairo_alpha), the OpenZeppelin dependency in test_project/Scarb.toml is expected to be in { git, tag } form rather than a simple registry-style string, so the update script only needs to update the tag value, not convert between formats.

Applied to files:

  • packages/ui/api/ai/ai-assistant/function-definitions/cairo-alpha.ts
🧬 Code graph analysis (12)
packages/ui/api/stellar/tests/utils/glob.rs (1)
packages/ui/api/stellar/src/utils/glob.rs (1)
  • build_globset (9-20)
packages/ui/api/stellar/src/routes/health.rs (1)
packages/ui/api/stellar/src/routes/upgrade_scaffold.rs (1)
  • init (28-30)
packages/ui/api/stellar/src/controllers/upgrade_scaffold.rs (3)
packages/ui/api/stellar/src/environment/scaffold_upgrade.rs (1)
  • run_scaffold_upgrade_command (7-25)
packages/ui/api/stellar/src/environment/zip_folder.rs (2)
  • unzip_in_temporary_folder (18-35)
  • zip_directory (215-249)
packages/ui/api/stellar/src/utils/errors.rs (1)
  • to_http_hidden_error (7-10)
packages/ui/api/stellar/tests/routes/mod.rs (1)
packages/ui/api/stellar/src/routes/health.rs (1)
  • health (6-8)
packages/ui/api/stellar/src/utils/dir.rs (2)
packages/ui/api/stellar/src/utils/path.rs (1)
  • ensure_no_symlinks (67-99)
packages/ui/api/stellar/src/utils/errors.rs (1)
  • to_io_error (12-15)
packages/ui/api/stellar/src/utils/path.rs (1)
packages/ui/api/stellar/src/environment/zip_folder.rs (1)
  • ancestors_rel (170-174)
packages/ui/api/stellar/src/routes/mod.rs (2)
packages/ui/api/stellar/src/routes/health.rs (2)
  • health (6-8)
  • init (12-14)
packages/ui/api/stellar/src/routes/upgrade_scaffold.rs (1)
  • init (28-30)
packages/ui/api/stellar/src/routes/upgrade_scaffold.rs (2)
packages/ui/api/stellar/src/controllers/upgrade_scaffold.rs (1)
  • upgrade_to_scaffold (16-36)
packages/ui/api/stellar/src/routes/health.rs (1)
  • init (12-14)
packages/ui/rollup.config.mjs (1)
packages/ui/svelte.config.js (1)
  • production (3-3)
packages/ui/api/stellar/tests/routes/health.rs (1)
packages/ui/api/stellar/src/routes/health.rs (2)
  • health (6-8)
  • init (12-14)
packages/ui/api/stellar/src/environment/zip_folder.rs (4)
packages/ui/api/stellar/src/utils/glob.rs (2)
  • build_globset (9-20)
  • is_glob_match (22-28)
packages/ui/api/stellar/src/utils/dir.rs (2)
  • create_dir_safe (7-22)
  • write_file_safe (24-49)
packages/ui/api/stellar/src/utils/path.rs (4)
  • expand_with_directories (42-57)
  • join_and_assert_inside (59-65)
  • ancestors_rel (30-40)
  • a (35-37)
packages/ui/api/stellar/src/utils/errors.rs (1)
  • to_zip_io_error (17-20)
packages/ui/api/stellar/src/main.rs (4)
packages/ui/api/stellar/src/routes/mod.rs (1)
  • configure_routes (6-9)
packages/ui/api/stellar/src/routes/upgrade_scaffold.rs (1)
  • init (28-30)
packages/ui/api/stellar/src/routes/health.rs (1)
  • init (12-14)
packages/ui/api/stellar/src/config/server.rs (1)
  • from_environment_variables (23-37)
🪛 GitHub Actions: Test
packages/ui/src/cairo_alpha/App.svelte

[warning] 226-226: Unused CSS selector ".controls-footer" (svelte)


[warning] 226-226: Unused CSS selector ".controls-footer > * + *" (svelte)


[warning] 226-226: Unused CSS selector ".controls-footer :global(.icon)" (svelte)


[warning] 226-226: Unused CSS selector ".controls-footer a" (svelte)


[warning] 226-226: Unused CSS selector ".controls-footer a:hover" (svelte)

packages/ui/src/cairo/App.svelte

[warning] 220-220: Unused CSS selector ".controls-footer" (svelte)


[warning] 220-220: Unused CSS selector ".controls-footer > * + *" (svelte)


[warning] 220-220: Unused CSS selector ".controls-footer :global(.icon)" (svelte)


[warning] 220-220: Unused CSS selector ".controls-footer a" (svelte)


[warning] 220-220: Unused CSS selector ".controls-footer a:hover" (svelte)

packages/ui/src/stylus/App.svelte

[warning] 198-198: Unused CSS selector ".controls-footer" (svelte)


[warning] 198-198: Unused CSS selector ".controls-footer > * + *" (svelte)


[warning] 198-198: Unused CSS selector ".controls-footer :global(.icon)" (svelte)


[warning] 198-198: Unused CSS selector ".controls-footer a" (svelte)


[warning] 198-198: Unused CSS selector ".controls-footer a:hover" (svelte)

packages/ui/src/solidity/App.svelte

[warning] 356-356: Unused CSS selector ".button-bg:hover" (svelte)


[warning] 356-356: Unused CSS selector ".hide-deploy" (svelte)


[warning] 356-356: Unused CSS selector ".hide-deploy button" (svelte)


[warning] 356-356: Unused CSS selector ".hide-deploy:hover" (svelte)


[warning] 356-356: Unused CSS selector ".controls-footer" (svelte)


[warning] 356-356: Unused CSS selector ".controls-footer > * + *" (svelte)


[warning] 356-356: Unused CSS selector ".controls-footer :global(.icon)" (svelte)


[warning] 356-356: Unused CSS selector ".controls-footer a" (svelte)


[warning] 356-356: Unused CSS selector ".controls-footer a:hover" (svelte)

packages/ui/api/ai/Dockerfile.dev

[error] 1-1: Prettier: No parser could be inferred for file /home/runner/work/contracts-wizard/contracts-wizard/packages/ui/api/ai/Dockerfile.dev.

packages/ui/api/stellar/Dockerfile.dev

[error] 1-1: Prettier: No parser could be inferred for file /home/runner/work/contracts-wizard/contracts-wizard/packages/ui/api/stellar/Dockerfile.dev.

packages/ui/api/stellar/Dockerfile.prod

[error] 1-1: Prettier: No parser could be inferred for file /home/runner/work/contracts-wizard/contracts-wizard/packages/ui/api/stellar/Dockerfile.prod.

packages/ui/src/stellar/App.svelte

[warning] 309-309: Unused CSS selector ".controls-footer" (svelte)


[warning] 309-309: Unused CSS selector ".controls-footer > * + *" (svelte)


[warning] 309-309: Unused CSS selector ".controls-footer :global(.icon)" (svelte)


[warning] 309-309: Unused CSS selector ".controls-footer a" (svelte)


[warning] 309-309: Unused CSS selector ".controls-footer a:hover" (svelte)

🪛 actionlint (1.7.7)
.github/workflows/docker-prod.yaml

44-44: description is required in metadata of "Setup" action at "/home/jailuser/git/.github/actions/setup/action.yml"

(action)


46-46: input "token" is not defined in action "Setup" defined at "./.github/actions/setup". available inputs are

(action)

🪛 YAMLlint (1.37.1)
.github/workflows/docker-prod.yaml

[error] 133-133: no new line character at the end of file

(new-line-at-end-of-file)

.github/workflows/docker-stg.yaml

[error] 126-126: no new line character at the end of file

(new-line-at-end-of-file)

.github/actions/oidc/action.yaml

[error] 45-45: no new line character at the end of file

(new-line-at-end-of-file)

🪛 dotenv-linter (3.3.0)
packages/ui/.env.example

[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 4-4: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

packages/ui/api/stellar/.env.example

[warning] 2-2: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

packages/ui/api/ai/.env.example

[warning] 2-2: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)

🪛 markdownlint-cli2 (0.17.2)
packages/ui/api/stellar/README.md

1-1: Headings must start at the beginning of the line

(MD023, heading-start-left)


5-5: Headings must start at the beginning of the line

(MD023, heading-start-left)


14-14: Headings must start at the beginning of the line

(MD023, heading-start-left)

- name: assume oidc role
uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0
with:
aws-region: us-east-1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Don’t hard‑code AWS region; respect the input.

This breaks callers outside us‑east‑1.

-        aws-region: us-east-1
+        aws-region: ${{ inputs.aws-region }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
aws-region: us-east-1
aws-region: ${{ inputs.aws-region }}
🤖 Prompt for AI Agents
.github/actions/oidc/action.yaml around line 30: the aws-region is hard-coded to
"us-east-1" which ignores caller input; update the action to use the aws-region
input variable (falling back to a sensible default only if input is empty) so
callers can supply their region, and remove the fixed "us-east-1" literal.

Comment on lines +43 to +47
- name: Setup pre-requisites
uses: ./.github/actions/setup
with:
token: ${{ steps.gh-app-token.outputs.token }}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Local action input mismatch (actionlint): setup action lacks a token input and description.

Per static analysis, ./.github/actions/setup doesn’t define inputs.token and is missing description. This step will error.

Options:

  • Define inputs.token and description in ./.github/actions/setup/action.yml, or
  • Remove the with: token: ... from this step if unused.
🧰 Tools
🪛 actionlint (1.7.7)

44-44: description is required in metadata of "Setup" action at "/home/jailuser/git/.github/actions/setup/action.yml"

(action)


46-46: input "token" is not defined in action "Setup" defined at "./.github/actions/setup". available inputs are

(action)

🤖 Prompt for AI Agents
In .github/workflows/docker-prod.yaml around lines 43 to 47, the workflow step
calls the local action ./.github/actions/setup with a `with: token: ...` but
that action's action.yml lacks an `inputs.token` entry and a `description`,
causing actionlint errors; fix by editing .github/actions/setup/action.yml to
add a descriptive `description` field and declare an `inputs` mapping that
includes `token` (type string, required if used, with a short description and
default if appropriate) so the workflow input is valid, or alternatively remove
the `with: token: ${{ steps.gh-app-token.outputs.token }}` line from the
workflow if the action does not need the token.

Comment on lines +9 to +15
inputs:
branch:
description: 'Branch to build from'
required: true
default: 'ci-cd'
type: string

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

workflow_dispatch input branch is unused. Wire it to checkout.

Use actions/checkout@… with ref: ${{ inputs.branch }} when manually dispatched.

Apply:

   workflow_dispatch:
     inputs:
       branch:
         description: 'Branch to build from'
         required: true
-        default: 'ci-cd'
+        default: 'staging'
         type: string
@@
-      - name: Checkout code
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+      - name: Checkout code
+        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        with:
+          ref: ${{ github.event_name == 'workflow_dispatch' && inputs.branch || github.ref }}

Also applies to: 38-40

🤖 Prompt for AI Agents
In .github/workflows/docker-stg.yaml around lines 9-15 (and similarly update
lines 38-40), the workflow_dispatch input "branch" is declared but never used;
update the checkout step(s) to pass that input by setting actions/checkout@...
with ref: ${{ inputs.branch }} so the workflow checks out the specified branch
when manually dispatched; ensure you add the ref field to every actions/checkout
step that should honor the input.

Comment on lines +9 to 12
export const ChatRoles = ['user', 'assistant', 'system'];
export type Chat = {
role: 'user' | 'assistant' | 'system';
role: (typeof ChatRoles)[number];
content: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Make ChatRoles a literal tuple to preserve role type safety.

Without as const, (typeof ChatRoles)[number] collapses to string.

Apply:

-export const ChatRoles = ['user', 'assistant', 'system'];
+export const ChatRoles = ['user', 'assistant', 'system'] as const;
 
 export type Chat = {
-  role: (typeof ChatRoles)[number];
+  role: (typeof ChatRoles)[number];
   content: string;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const ChatRoles = ['user', 'assistant', 'system'];
export type Chat = {
role: 'user' | 'assistant' | 'system';
role: (typeof ChatRoles)[number];
content: string;
export const ChatRoles = ['user', 'assistant', 'system'] as const;
export type Chat = {
role: (typeof ChatRoles)[number];
content: string;
};
🤖 Prompt for AI Agents
In packages/ui/api/ai/ai-assistant/types/assistant.ts around lines 9 to 12,
ChatRoles is defined as a mutable string array which causes (typeof
ChatRoles)[number] to widen to string; change ChatRoles to a readonly literal
tuple by appending "as const" (e.g. export const ChatRoles =
['user','assistant','system'] as const) so the role type remains the exact union
of those strings, and optionally introduce a ChatRole type alias (export type
ChatRole = typeof ChatRoles[number]) and use that for the Chat.role declaration.

Comment on lines +8 to +17
const listAll = async (dirPath: string) => {
for await (const entry of Deno.readDir(dirPath)) {
const fullPath = join(dirPath, entry.name);
console.log(fullPath);

if (entry.isDirectory) {
await listAll(fullPath);
}
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove recursive directory logging on every request.

listAll('.') on each request is noisy, slow, and leaks filesystem layout in logs.

-const listAll = async (dirPath: string) => {
-  for await (const entry of Deno.readDir(dirPath)) {
-    const fullPath = join(dirPath, entry.name);
-    console.log(fullPath);
-
-    if (entry.isDirectory) {
-      await listAll(fullPath);
-    }
-  }
-};
+// Optional debug-only scanner (disabled by default)
+const listAll = async (_: string) => {};

Also applies to: 38-39

🤖 Prompt for AI Agents
In packages/ui/api/ai/development-server.ts around lines 8-17 (and also
addressing the call at lines 38-39), the recursive helper listAll('.') currently
logs every file path on each request, which is noisy, slow, and leaks filesystem
layout; remove the recursive listing and any console.log calls or gate them
behind a strict debug flag so they never run on normal requests. Specifically,
delete or disable the listAll('.') invocation at lines 38-39 and remove the
console.log(fullPath) from the helper (or eliminate the helper entirely if
unused), and if you need optional diagnostics, expose a debug option that
triggers a single, non-recursive, rate-limited or explicitly-invoked listing
instead of running it per request.

Comment on lines +18 to +21
#[cfg(not(unix))]
{
fs::create_dir_all(path).map_err(utils::to_io_error::to_io_error)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix incorrect path to to_io_error.

utils::to_io_error::to_io_error is invalid; use the imported to_io_error.

Apply:

 #[cfg(not(unix))]
 {
-        fs::create_dir_all(path).map_err(utils::to_io_error::to_io_error)
+        fs::create_dir_all(path).map_err(to_io_error)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#[cfg(not(unix))]
{
fs::create_dir_all(path).map_err(utils::to_io_error::to_io_error)
}
#[cfg(not(unix))]
{
fs::create_dir_all(path).map_err(to_io_error)
}
🤖 Prompt for AI Agents
In packages/ui/api/stellar/src/utils/dir.rs around lines 18 to 21, the call uses
an incorrect path `utils::to_io_error::to_io_error`; replace that
fully-qualified path with the imported function name `to_io_error` (i.e., call
fs::create_dir_all(path).map_err(to_io_error)) so the compiler uses the
already-imported helper rather than an invalid module path.

Comment on lines +59 to +65
pub fn join_and_assert_inside(root: &Path, rel: &Path) -> Result<PathBuf, IoError> {
let full = root.join(rel);
if !full.starts_with(root) {
return Err(IoError::other("Path escape root"));
}
Ok(full)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Path traversal check is insufficient (lexical starts_with).

root.join("../escape") still starts with root lexically. Reject absolute paths and any .., Prefix, or RootDir components up front.

 pub fn join_and_assert_inside(root: &Path, rel: &Path) -> Result<PathBuf, IoError> {
-    let full = root.join(rel);
-    if !full.starts_with(root) {
-        return Err(IoError::other("Path escape root"));
-    }
-    Ok(full)
+    // Reject obvious escapes before joining.
+    if rel.is_absolute()
+        || rel
+            .components()
+            .any(|c| matches!(c, Component::ParentDir | Component::Prefix(_) | Component::RootDir))
+    {
+        return Err(IoError::new(
+            IoErrorKind::InvalidInput,
+            "path escapes root or is absolute",
+        ));
+    }
+    let full = root.join(rel);
+    if !full.starts_with(root) {
+        return Err(IoError::new(IoErrorKind::InvalidInput, "path escapes root"));
+    }
+    Ok(full)
 }

If this is used with untrusted archive entries, please run:


🏁 Script executed:

#!/bin/bash
# Find callsites and nearby usage context
rg -nC3 --type=rust '\bjoin_and_assert_inside\s*\('

Length of output: 1247


Reject path-traversal escapes before joining (critical)

Lexical starts_with after root.join(rel) is insufficient — a rel containing .., absolute, Prefix, or RootDir components can escape. This function is called at packages/ui/api/stellar/src/environment/zip_folder.rs:59 with untrusted zip entries; fix is required.

 pub fn join_and_assert_inside(root: &Path, rel: &Path) -> Result<PathBuf, IoError> {
-    let full = root.join(rel);
-    if !full.starts_with(root) {
-        return Err(IoError::other("Path escape root"));
-    }
-    Ok(full)
+    // Reject obvious escapes before joining.
+    if rel.is_absolute()
+        || rel
+            .components()
+            .any(|c| matches!(c, Component::ParentDir | Component::Prefix(_) | Component::RootDir))
+    {
+        return Err(IoError::new(
+            IoErrorKind::InvalidInput,
+            "path escapes root or is absolute",
+        ));
+    }
+    let full = root.join(rel);
+    if !full.starts_with(root) {
+        return Err(IoError::new(IoErrorKind::InvalidInput, "path escapes root"));
+    }
+    Ok(full)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn join_and_assert_inside(root: &Path, rel: &Path) -> Result<PathBuf, IoError> {
let full = root.join(rel);
if !full.starts_with(root) {
return Err(IoError::other("Path escape root"));
}
Ok(full)
}
pub fn join_and_assert_inside(root: &Path, rel: &Path) -> Result<PathBuf, IoError> {
// Reject obvious escapes before joining.
if rel.is_absolute()
|| rel
.components()
.any(|c| matches!(c, Component::ParentDir | Component::Prefix(_) | Component::RootDir))
{
return Err(IoError::new(
IoErrorKind::InvalidInput,
"path escapes root or is absolute",
));
}
let full = root.join(rel);
if !full.starts_with(root) {
return Err(IoError::new(IoErrorKind::InvalidInput, "path escapes root"));
}
Ok(full)
}

Comment on lines +5 to +7
let globset = build_globset(&["*.rs"]).unwrap();
let matcher = globset.matches("main.rs");
assert!(!matcher.is_empty());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix type mismatch: build_globset expects Vec, not &[&str].

Current tests won’t compile against the function signature.

Apply this diff:

-    let globset = build_globset(&["*.rs"]).unwrap();
+    let globset = build_globset(vec!["*.rs".into()]).unwrap();
@@
-    let globset = build_globset(&["*.rs"]).unwrap();
+    let globset = build_globset(vec!["*.rs".into()]).unwrap();
@@
-    let globset = build_globset(&["*.rs", "*.txt"]).unwrap();
+    let globset = build_globset(vec!["*.rs".into(), "*.txt".into()]).unwrap();
@@
-    let globset = build_globset(&[]).unwrap();
+    let globset = build_globset(Vec::<String>::new()).unwrap();
@@
-    let result = build_globset(&["[invalid"]);
+    let result = build_globset(vec!["[invalid".into()]);
@@
-    let globset = build_globset(&["src/*"]).unwrap();
+    let globset = build_globset(vec!["src/*".into()]).unwrap();
@@
-    let globset = build_globset(&["file?.rs"]).unwrap();
+    let globset = build_globset(vec!["file?.rs".into()]).unwrap();

Alternatively, generalize build_globset to accept impl IntoIterator<Item: AsRef<str>> and keep tests unchanged.

Also applies to: 12-14, 19-23, 27-29, 33-35, 39-42, 46-50

Comment on lines +132 to +134
'process.env.FARGATE_HOST': JSON.stringify(
production ? 'TODO' : `http://localhost:${process.env.FARGATE_PORT || 8888}`,
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Production FARGATE_HOST is 'TODO' — will break prod calls.

Resolve from env at build time or default to empty (relative) like API_HOST.

-        'process.env.FARGATE_HOST': JSON.stringify(
-          production ? 'TODO' : `http://localhost:${process.env.FARGATE_PORT || 8888}`,
-        ),
+        'process.env.FARGATE_HOST': JSON.stringify(
+          process.env.FARGATE_HOST || (production ? '' : `http://localhost:${process.env.FARGATE_PORT || 8888}`)
+        ),

Ensure packages/ui/.env.example documents FARGATE_HOST and CI injects it for production builds.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

search() {
  pattern="$1"
  if command -v rg >/dev/null 2>&1; then
    rg -n --hidden --no-ignore-vcs -S "$pattern" || true
  else
    grep -RIn --line-number --exclude-dir=node_modules --exclude-dir=.git --binary-files=without-match "$pattern" . || true
  fi
}

echo "PWD: $(pwd)"
echo
echo "=== Search for FARGATE_HOST occurrences ==="
search 'FARGATE_HOST'
echo
echo "=== Search for process.env.FARGATE_HOST occurrences ==="
search 'process.env.FARGATE_HOST'
echo
echo "=== Show packages/ui/rollup.config.mjs (lines 120-140) ==="
if [ -f packages/ui/rollup.config.mjs ]; then
  sed -n '120,140p' packages/ui/rollup.config.mjs
else
  echo "MISSING: packages/ui/rollup.config.mjs"
fi
echo
echo "=== Show packages/ui/rollup.config.mjs (full file head up to 400 lines for context) ==="
if [ -f packages/ui/rollup.config.mjs ]; then
  sed -n '1,400p' packages/ui/rollup.config.mjs
fi
echo
echo "=== packages/ui/.env.example (first 200 lines) ==="
if [ -f packages/ui/.env.example ]; then
  sed -n '1,200p' packages/ui/.env.example
else
  echo "MISSING: packages/ui/.env.example"
fi
echo
echo "=== Search .github/workflows and CI files for FARGATE_HOST or env injection ==="
if [ -d .github/workflows ]; then
  search '.github/workflows'
fi
search 'FARGATE_HOST'
search 'FARGATE'
echo
echo "=== Search for API_HOST usage (to compare pattern) ==="
search 'API_HOST'

Length of output: 6742


Fix production FARGATE_HOST — don't ship 'TODO'

rollup sets process.env.FARGATE_HOST to 'TODO' in production (will break prod requests). Use the real env var or an empty (relative) fallback and ensure CI injects it.

Location: packages/ui/rollup.config.mjs (around lines 131–133)

-        'process.env.FARGATE_HOST': JSON.stringify(
-          production ? 'TODO' : `http://localhost:${process.env.FARGATE_PORT || 8888}`,
-        ),
+        'process.env.FARGATE_HOST': JSON.stringify(
+          process.env.FARGATE_HOST || (production ? '' : `http://localhost:${process.env.FARGATE_PORT || 8888}`)
+        ),
  • packages/ui/.env.example already documents FARGATE_HOST (packages/ui/.env.example:4); ensure CI injects FARGATE_HOST for production builds.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
'process.env.FARGATE_HOST': JSON.stringify(
production ? 'TODO' : `http://localhost:${process.env.FARGATE_PORT || 8888}`,
),
'process.env.FARGATE_HOST': JSON.stringify(
process.env.FARGATE_HOST || (production ? '' : `http://localhost:${process.env.FARGATE_PORT || 8888}`)
),
🤖 Prompt for AI Agents
In packages/ui/rollup.config.mjs around lines 132–134, the build currently
injects the literal string 'TODO' for process.env.FARGATE_HOST in production
which will break prod requests; replace that hardcoded value with the actual
environment variable (use process.env.FARGATE_HOST) and provide a safe fallback
(e.g., an empty string or relative URL) before JSON.stringify, and update CI to
ensure FARGATE_HOST is set for production builds (per packages/ui/.env.example).

Comment on lines +93 to +114
try {
isDownloadingScaffold = true;

const {
ok,
status,
body: scaffoldProject,
} = await fetch(`${fargateHost}/stellar/upgrade-scaffold`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: await zipRustProjectBlob(contract, opts),
});

if (!ok) throw new Error(`HTTP ${status}`);

saveAs(await new Response(scaffoldProject).blob(), 'scaffold-project.zip');
await postConfig(opts, 'download-file', language);

isDownloadingScaffold = false;
} catch (error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix content-type, reset error state, and simplify response handling.

The request sends a binary Blob but advertises JSON, and the response handling via Response(body).blob() is brittle. Also, the error flag isn’t cleared before a retry.

Apply this diff:

   try {
-      isDownloadingScaffold = true;
-
-      const {
-        ok,
-        status,
-        body: scaffoldProject,
-      } = await fetch(`${fargateHost}/stellar/upgrade-scaffold`, {
-        method: 'POST',
-        headers: {
-          'Content-Type': 'application/json',
-        },
-        body: await zipRustProjectBlob(contract, opts),
-      });
-
-      if (!ok) throw new Error(`HTTP ${status}`);
-
-      saveAs(await new Response(scaffoldProject).blob(), 'scaffold-project.zip');
+      downloadScaffoldError = false;
+      isDownloadingScaffold = true;
+
+      const endpoint = fargateHost
+        ? new URL('/stellar/upgrade-scaffold', fargateHost).toString()
+        : '/stellar/upgrade-scaffold';
+
+      const resp = await fetch(endpoint, {
+        method: 'POST',
+        headers: {
+          'Content-Type': 'application/zip',
+        },
+        body: await zipRustProjectBlob(contract, opts),
+      });
+
+      if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
+
+      const zipBlob = await resp.blob();
+      saveAs(zipBlob, 'scaffold-project.zip');
       await postConfig(opts, 'download-file', language);
 
       isDownloadingScaffold = false;
     } catch (error) {
       console.log(error);
 
       downloadScaffoldError = true;
       isDownloadingScaffold = false;
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
isDownloadingScaffold = true;
const {
ok,
status,
body: scaffoldProject,
} = await fetch(`${fargateHost}/stellar/upgrade-scaffold`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: await zipRustProjectBlob(contract, opts),
});
if (!ok) throw new Error(`HTTP ${status}`);
saveAs(await new Response(scaffoldProject).blob(), 'scaffold-project.zip');
await postConfig(opts, 'download-file', language);
isDownloadingScaffold = false;
} catch (error) {
try {
downloadScaffoldError = false;
isDownloadingScaffold = true;
const endpoint = fargateHost
? new URL('/stellar/upgrade-scaffold', fargateHost).toString()
: '/stellar/upgrade-scaffold';
const resp = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/zip',
},
body: await zipRustProjectBlob(contract, opts),
});
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
const zipBlob = await resp.blob();
saveAs(zipBlob, 'scaffold-project.zip');
await postConfig(opts, 'download-file', language);
isDownloadingScaffold = false;
} catch (error) {
console.log(error);
downloadScaffoldError = true;
isDownloadingScaffold = false;
}
🤖 Prompt for AI Agents
In packages/ui/src/stellar/App.svelte around lines 93 to 114, the request
currently advertises JSON while sending a binary Blob, the response handling via
Response(body).blob() is brittle, and the error flag isn’t reset before retries;
change the request Content-Type to a binary type like application/zip or
application/octet-stream, stop destructuring the fetch result into body and
instead capture the full response object (await fetch...), check response.ok and
status, then call await response.blob() to get the file and pass that to saveAs;
also reset isDownloadError = false before starting the download (or clear it on
success) and ensure isDownloadingScaffold is cleared in a finally block so error
state is reset for retries.

Copy link
Contributor

@0xNeshi 0xNeshi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CoveMB I reviewed the changed Stylus files, those look ok.

Are there any changes that indirectly affect Stylus logic that I should take a look at?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants