Skip to content

Commit e8477e3

Browse files
authored
Merge pull request #18 from cloud-py-api/feat/stability-security
feat(stability): remove nodes & flows that require too specific extra nodes
2 parents 3dcf668 + dc0a594 commit e8477e3

File tree

7 files changed

+214
-3
lines changed

7 files changed

+214
-3
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: Flows Install
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
permissions:
9+
contents: read
10+
11+
concurrency:
12+
group: flows_install-${{ github.head_ref || github.run_id }}
13+
cancel-in-progress: true
14+
15+
jobs:
16+
github_flows_install:
17+
name: Flows Install GitHub Ubuntu 24
18+
runs-on: ubuntu-24.04
19+
env:
20+
DATABASE_URI: postgresql+psycopg://vix_user:vix_password@localhost:5432/vix_db
21+
22+
services:
23+
postgres:
24+
image: postgres:17
25+
env:
26+
POSTGRES_USER: vix_user
27+
POSTGRES_PASSWORD: vix_password
28+
POSTGRES_DB: vix_db
29+
options: >-
30+
--health-cmd pg_isready
31+
--health-interval 10s
32+
--health-timeout 5s
33+
--health-retries 5
34+
ports:
35+
- 5432:5432
36+
37+
steps:
38+
- uses: actions/checkout@v4
39+
- name: Checkout Visionatrix (engine)
40+
uses: actions/checkout@v4
41+
with:
42+
repository: Visionatrix/Visionatrix
43+
path: visionatrix_main
44+
45+
- uses: actions/setup-python@v5
46+
with:
47+
python-version: '3.12'
48+
49+
- name: Install Visionatrix dependencies
50+
working-directory: visionatrix_main
51+
run: |
52+
python3 -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
53+
python3 -m pip install ".[pgsql]"
54+
55+
- name: Export Visionatrix exclude flows
56+
run: |
57+
value=$(python3 scripts/ci/get_excludes.py flows)
58+
echo "VISIONATRIX_EXCLUDE_FLOWS=$value" >> "$GITHUB_ENV"
59+
60+
- name: Export Visionatrix exclude nodes
61+
run: |
62+
value=$(python3 scripts/ci/get_excludes.py nodes)
63+
echo "VISIONATRIX_INSTALL_EXCLUDE_NODES=$value" >> "$GITHUB_ENV"
64+
65+
- name: Run Visionatrix install
66+
working-directory: visionatrix_main
67+
run: python3 -m visionatrix install
68+
69+
- name: Install flows from CMD
70+
working-directory: visionatrix_main
71+
run: |
72+
echo "Y" | VIX_MODE=SERVER VIX_SERVER_FULL_MODELS=0 python3 -m visionatrix install-flow --name=*
73+
74+
- name: Generate openapi-flows.json
75+
working-directory: visionatrix_main
76+
run: |
77+
VIX_MODE=SERVER VIX_SERVER_FULL_MODELS=0 python3 -m visionatrix openapi --flows="*" --exclude-base --file=openapi-flows.json
78+
79+
- name: Create test user
80+
working-directory: visionatrix_main
81+
run: |
82+
VIX_MODE=SERVER VIX_SERVER_FULL_MODELS=0 python3 -m visionatrix create-user --name=user --password=user
83+
84+
- name: Start Visionatrix in Server mode
85+
working-directory: visionatrix_main
86+
run: |
87+
nohup python3 -m visionatrix run --ui --mode=SERVER > visionatrix.log 2>&1 &
88+
echo "Server started in background with PID $!"
89+
90+
- name: Wait for Visionatrix server
91+
run: |
92+
max_attempts=30
93+
for i in $(seq 1 $max_attempts); do
94+
echo "Attempt $i/$max_attempts: Checking Visionatrix server..."
95+
if curl -s http://localhost:8288/whoami > /dev/null; then
96+
echo "Visionatrix server is up!"
97+
exit 0
98+
fi
99+
echo "Server not ready yet. Sleeping 10s..."
100+
sleep 10
101+
done
102+
echo "Server not responding after 5 minutes!"
103+
exit 1
104+
105+
- name: Download test image
106+
working-directory: visionatrix_main
107+
run: |
108+
wget -O tests/source-cube_rm_background.png "https://github.com/Visionatrix/VixFlowsDocs/blob/main/tests_data/source-cube_rm_background.png?raw=true"
109+
110+
- name: Create task for each Flow
111+
working-directory: visionatrix_main
112+
run: python3 tests/create_flow_tasks.py
113+
114+
- name: Display logs
115+
if: ${{ always() }}
116+
working-directory: visionatrix_main
117+
run: cat visionatrix.log

Dockerfile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,17 @@ RUN --mount=type=cache,target=/root/.cache/pip \
6262
venv/bin/python -m pip install torch==2.7.0 torchvision torchaudio; \
6363
fi
6464

65+
COPY ex_app/lib/exclude_nodes.py ex_app/lib/exclude_flows.py /ex_app/lib/
66+
COPY scripts/ci/get_excludes.py /get_excludes.py
6567
RUN --mount=type=cache,target=/root/.cache/pip \
6668
cd /Visionatrix && \
6769
venv/bin/python -m pip install "psycopg[binary]" greenlet && \
6870
venv/bin/python -m pip install . && \
69-
venv/bin/python -m visionatrix install && \
70-
rm visionatrix.db
71+
VISIONATRIX_INSTALL_EXCLUDE_NODES="$(python /get_excludes.py nodes)" \
72+
venv/bin/python -m visionatrix install && \
73+
rm visionatrix.db && \
74+
rm /get_excludes.py && \
75+
rm -rf /ex_app
7176

7277
# Setup nodejs and npm for building the front-end client
7378
RUN apt-get update && \

ex_app/lib/exclude_flows.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
EXCLUDE_FLOWS_IDS = [
2+
"all_your_life",
3+
"photo_stickers2",
4+
"photomaker_2",
5+
]

ex_app/lib/exclude_nodes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
EXCLUDE_NODES_IDS = [
2+
"https://github.com/Fannovel16/ComfyUI-Frame-Interpolation",
3+
"https://github.com/shiimizu/ComfyUI-PhotoMaker-Plus",
4+
"https://github.com/FizzleDorf/ComfyUI_FizzNodes",
5+
]

ex_app/lib/main.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
from time import sleep
1818

1919
import httpx
20+
from exclude_flows import EXCLUDE_FLOWS_IDS
21+
from exclude_nodes import EXCLUDE_NODES_IDS
2022
from fastapi import BackgroundTasks, Body, Depends, FastAPI, Request, responses
2123
from nc_py_api import NextcloudApp
2224
from nc_py_api.ex_app import (
@@ -29,7 +31,7 @@
2931
from nc_py_api.ex_app.providers.task_processing import TaskProcessingProvider
3032
from starlette.middleware.base import BaseHTTPMiddleware
3133
from starlette.responses import FileResponse, Response
32-
from supported_flows import FLOWS_IDS
34+
from task_processing_flows import FLOWS_IDS
3335

3436
# ---------Start of configuration values for manual deploy---------
3537
# Uncommenting the following lines may be useful when installing manually.
@@ -74,6 +76,9 @@
7476
print("[DEBUG]: PROJECT_ROOT_FOLDER=", PROJECT_ROOT_FOLDER, flush=True)
7577
print("[DEBUG]: STATIC_FRONTEND_PRESENT=", STATIC_FRONTEND_PRESENT, flush=True)
7678

79+
os.environ["VISIONATRIX_INSTALL_EXCLUDE_NODES"] = EXCLUDE_NODES_IDS
80+
os.environ["VISIONATRIX_EXCLUDE_FLOWS"] = EXCLUDE_FLOWS_IDS
81+
7782

7883
def _(text):
7984
return current_translator.get().gettext(text)
File renamed without changes.

scripts/ci/get_excludes.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Tiny helper for GitHub Actions *and* Docker builds.
4+
5+
Usage:
6+
python3 get_excludes.py flows # → prints "id1;id2;…"
7+
python3 get_excludes.py nodes # → prints "url1;url2;…"
8+
9+
It echoes a semicolon-joined list so callers can assign it to an environment variable, e.g.:
10+
11+
VISIONATRIX_INSTALL_EXCLUDE_NODES="$(python /get_excludes.py nodes)"
12+
"""
13+
14+
from __future__ import annotations
15+
16+
import importlib.util
17+
import sys
18+
from pathlib import Path
19+
from collections.abc import Sequence
20+
21+
22+
def _import_list(file: Path, var: str) -> Sequence[str]:
23+
spec = importlib.util.spec_from_file_location(file.stem, file)
24+
module = importlib.util.module_from_spec(spec) # type: ignore[arg-type]
25+
spec.loader.exec_module(module) # type: ignore[attr-defined]
26+
value: list[str] | Sequence[str] = getattr(module, var, [])
27+
if not isinstance(value, list | tuple):
28+
raise TypeError(f"{file}:{var} is not a list/tuple")
29+
return value
30+
31+
32+
def find_repo_root() -> Path:
33+
"""
34+
Locate directory that contains ex_app/lib/ .
35+
Strategy (first match wins):
36+
1. Walk up from this script's directory.
37+
2. Walk up from CWD (useful if script is executed via absolute path).
38+
3. Fallback to filesystem root (where Dockerfile copies it as /ex_app/lib).
39+
"""
40+
def search_up(start: Path) -> Path | None:
41+
for p in [start, *list(start.parents)]:
42+
if (p / "ex_app" / "lib").is_dir():
43+
return p
44+
return None
45+
46+
here = Path(__file__).resolve().parent
47+
return search_up(here) or search_up(Path.cwd()) or Path("/")
48+
49+
50+
def main() -> None:
51+
if len(sys.argv) != 2 or sys.argv[1] not in {"flows", "nodes"}:
52+
print("Usage: get_excludes.py [flows|nodes]", file=sys.stderr)
53+
sys.exit(1)
54+
55+
mode = sys.argv[1]
56+
repo_root = find_repo_root() # <repo root> or "/" inside container
57+
58+
if mode == "flows":
59+
py_file = repo_root / "ex_app" / "lib" / "exclude_flows.py"
60+
var_name = "EXCLUDE_FLOWS_IDS"
61+
else:
62+
py_file = repo_root / "ex_app" / "lib" / "exclude_nodes.py"
63+
var_name = "EXCLUDE_NODES_IDS"
64+
65+
if not py_file.is_file():
66+
print(f"Error: cannot locate {py_file}", file=sys.stderr)
67+
sys.exit(2)
68+
69+
items = _import_list(py_file, var_name)
70+
print(";".join(items))
71+
72+
73+
if __name__ == "__main__":
74+
main()

0 commit comments

Comments
 (0)