-
Notifications
You must be signed in to change notification settings - Fork 0
Development #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development
Are you sure you want to change the base?
Development #19
Changes from all commits
9080c9a
8a48f24
64d9477
b698be6
ea2459e
3407d1b
dccad52
48c236c
ae22df7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -160,9 +160,21 @@ update-deps: ## Update dependencies | |||||||||||||||||||||
| fi | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Docker | ||||||||||||||||||||||
| DOCKER_BASE_IMAGE := ctxos/ctxai-base | ||||||||||||||||||||||
| DOCKER_BASE_TAG := latest | ||||||||||||||||||||||
| DOCKER_PLATFORMS := linux/amd64,linux/arm64 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| docker-base: ## Build base Docker image for current platform | ||||||||||||||||||||||
| @echo "$(BLUE)Building base Docker image $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG)...$(NC)" | ||||||||||||||||||||||
| docker buildx build --builder mybuilder -f docker/base/Dockerfile -t $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG) --load . | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| docker-base-push: ## Build and push multi-arch base Docker image | ||||||||||||||||||||||
| @echo "$(BLUE)Building and pushing multi-arch base Docker image $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG)...$(NC)" | ||||||||||||||||||||||
| docker buildx build --builder mybuilder -f docker/base/Dockerfile -t $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG) --platform $(DOCKER_PLATFORMS) --push . | ||||||||||||||||||||||
|
Comment on lines
+169
to
+173
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid hardcoding buildx builder name. Using 🔧 Proposed fix-docker buildx build --builder mybuilder -f docker/base/Dockerfile -t $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG) --load .
+docker buildx build -f docker/base/Dockerfile -t $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG) --load .
-docker buildx build --builder mybuilder -f docker/base/Dockerfile -t $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG) --platform $(DOCKER_PLATFORMS) --push .
+docker buildx build -f docker/base/Dockerfile -t $(DOCKER_BASE_IMAGE):$(DOCKER_BASE_TAG) --platform $(DOCKER_PLATFORMS) --push .📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| docker-build: ## Build Docker image | ||||||||||||||||||||||
| @echo "$(BLUE)Building Docker image $(DOCKER_IMAGE):$(DOCKER_TAG)...$(NC)" | ||||||||||||||||||||||
| docker build -t $(DOCKER_IMAGE):$(DOCKER_TAG) . | ||||||||||||||||||||||
| docker build -f DockerfileLocal -t $(DOCKER_IMAGE):$(DOCKER_TAG) . | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| docker-run: ## Run CtxAI with Docker | ||||||||||||||||||||||
| @echo "$(BLUE)Running CtxAI with Docker...$(NC)" | ||||||||||||||||||||||
|
|
@@ -177,6 +189,10 @@ docker-stop: ## Stop Docker Compose services | |||||||||||||||||||||
| @echo "$(BLUE)Stopping Docker Compose services...$(NC)" | ||||||||||||||||||||||
| cd docker/run && docker-compose down | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| docker-test: ## Run tests inside Docker container | ||||||||||||||||||||||
| @echo "$(BLUE)Running tests in Docker container...$(NC)" | ||||||||||||||||||||||
| docker run --rm --entrypoint python $(DOCKER_IMAGE):$(DOCKER_TAG) -m pytest -v | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| # Documentation | ||||||||||||||||||||||
| docs: ## Generate documentation | ||||||||||||||||||||||
| @echo "$(BLUE)Generating documentation...$(NC)" | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -28,10 +28,8 @@ async def communicate(self, input: dict, request: Request): | |||||
| attachments = request.files.getlist("attachments") | ||||||
| attachment_paths = [] | ||||||
|
|
||||||
| upload_folder_int = "/ctx0/usr/uploads" | ||||||
| upload_folder_ext = files.get_abs_path( | ||||||
| "usr/uploads" | ||||||
| ) # for development environment | ||||||
| upload_folder_int = "/ctx0/usr/uploads" | ||||||
| upload_folder_ext = files.get_abs_path("usr/uploads") # for development environment | ||||||
|
|
||||||
| if attachments: | ||||||
| os.makedirs(upload_folder_ext, exist_ok=True) | ||||||
|
|
@@ -60,9 +58,7 @@ async def communicate(self, input: dict, request: Request): | |||||
|
|
||||||
| # call extension point, alow it to modify data | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick (typo): Fix the typo in the comment for clarity. Change # call extension point, allow it to modify data
Suggested change
|
||||||
| data = {"message": message, "attachment_paths": attachment_paths} | ||||||
| await extension.call_extensions_async( | ||||||
| "user_message_ui", agent=context.get_agent(), data=data | ||||||
| ) | ||||||
| await extension.call_extensions_async("user_message_ui", agent=context.get_agent(), data=data) | ||||||
| message = data.get("message", "") | ||||||
| attachment_paths = data.get("attachment_paths", []) | ||||||
|
|
||||||
|
|
@@ -73,7 +69,5 @@ async def communicate(self, input: dict, request: Request): | |||||
| mq.log_user_message(context, message, attachment_paths, message_id) | ||||||
|
|
||||||
| return context.communicate( | ||||||
| UserMessage( | ||||||
| message=message, attachments=attachment_paths, id=message_id or "" | ||||||
| ) | ||||||
| UserMessage(message=message, attachments=attachment_paths, id=message_id or "") | ||||||
| ), context | ||||||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -33,12 +33,8 @@ | |||||||
| "CTX0_SELF_UPDATE_HEALTH_URL", | ||||||||
| "http://127.0.0.1:80/api/health", | ||||||||
| ) | ||||||||
| DEFAULT_HEALTH_TIMEOUT_SECONDS = int( | ||||||||
| os.environ.get("CTX0_SELF_UPDATE_HEALTH_TIMEOUT_SECONDS", "120") | ||||||||
| ) | ||||||||
| DEFAULT_HEALTH_POLL_INTERVAL_SECONDS = float( | ||||||||
| os.environ.get("CTX0_SELF_UPDATE_HEALTH_POLL_INTERVAL_SECONDS", "2") | ||||||||
| ) | ||||||||
| DEFAULT_HEALTH_TIMEOUT_SECONDS = int(os.environ.get("CTX0_SELF_UPDATE_HEALTH_TIMEOUT_SECONDS", "120")) | ||||||||
| DEFAULT_HEALTH_POLL_INTERVAL_SECONDS = float(os.environ.get("CTX0_SELF_UPDATE_HEALTH_POLL_INTERVAL_SECONDS", "2")) | ||||||||
| DEFAULT_BACKUP_DIR = "/root/update-backups" | ||||||||
| DEFAULT_BACKUP_CONFLICT_POLICY = "rename" | ||||||||
| BACKUP_CONFLICT_POLICIES = {"rename", "overwrite", "fail"} | ||||||||
|
|
@@ -216,8 +212,7 @@ def get_latest_same_major_tag( | |||||||
| ] | ||||||||
| if not same_major_tags: | ||||||||
| raise RuntimeError( | ||||||||
| f"No v{current_major}.x release tags are reachable from branch " | ||||||||
| f"{branch_ref.rsplit('/', 1)[-1]}." | ||||||||
| f"No v{current_major}.x release tags are reachable from branch {branch_ref.rsplit('/', 1)[-1]}." | ||||||||
| ) | ||||||||
| return sort_selector_supported_tags(same_major_tags)[0] | ||||||||
|
|
||||||||
|
|
@@ -238,8 +233,7 @@ def ensure_latest_target_matches_current_major( | |||||||
| target_major = parse_major_version(target_version) | ||||||||
| if target_major is None or not is_supported_selector_tag(target_version): | ||||||||
| raise RuntimeError( | ||||||||
| f"Could not resolve latest on branch {branch} to a supported vX.Y release. " | ||||||||
| "Use an explicit tag instead." | ||||||||
| f"Could not resolve latest on branch {branch} to a supported vX.Y release. Use an explicit tag instead." | ||||||||
| ) | ||||||||
|
|
||||||||
| if target_major != current_major: | ||||||||
|
|
@@ -398,8 +392,7 @@ def run_command( | |||||||
| logger.log_block("stderr", completed.stderr) | ||||||||
| if completed.returncode != 0: | ||||||||
| raise RuntimeError( | ||||||||
| error_message | ||||||||
| or f"Command failed with exit code {completed.returncode}: {' '.join(command)}" | ||||||||
| error_message or f"Command failed with exit code {completed.returncode}: {' '.join(command)}" | ||||||||
| ) | ||||||||
| return completed | ||||||||
|
|
||||||||
|
|
@@ -439,8 +432,7 @@ def create_rollback_stash(repo_dir: Path, logger: AttemptLogger) -> str | None: | |||||||
| if not stash_ref or stash_ref == previous_top: | ||||||||
| raise RuntimeError("Failed to create the pre-update rollback stash.") | ||||||||
| logger.log( | ||||||||
| f"Saved local tracked/untracked changes into {stash_ref}. " | ||||||||
| "Ignored files stay in place and are not stashed." | ||||||||
| f"Saved local tracked/untracked changes into {stash_ref}. Ignored files stay in place and are not stashed." | ||||||||
| ) | ||||||||
| return stash_ref | ||||||||
|
|
||||||||
|
|
@@ -471,9 +463,7 @@ def apply_stash(repo_dir: Path, stash_ref: str, logger: AttemptLogger) -> None: | |||||||
| try: | ||||||||
| drop_stash(repo_dir, stash_ref, logger) | ||||||||
| except Exception as exc: | ||||||||
| logger.log( | ||||||||
| f"Rollback stash {stash_ref} was restored but could not be dropped automatically: {exc}" | ||||||||
| ) | ||||||||
| logger.log(f"Rollback stash {stash_ref} was restored but could not be dropped automatically: {exc}") | ||||||||
|
|
||||||||
|
|
||||||||
| def clean_repo_worktree( | ||||||||
|
|
@@ -598,9 +588,7 @@ def resolve_requested_target( | |||||||
| current_version=current_version, | ||||||||
| target_version=head_short_tag, | ||||||||
| ) | ||||||||
| logger.log( | ||||||||
| f"Resolved latest on branch {branch} to commit {head_commit[:7]} ({head_describe})" | ||||||||
| ) | ||||||||
| logger.log(f"Resolved latest on branch {branch} to commit {head_commit[:7]} ({head_describe})") | ||||||||
| return { | ||||||||
| "requested_tag": LATEST_SELECTOR_TAG, | ||||||||
| "effective_tag": head_short_tag, | ||||||||
|
|
@@ -692,7 +680,8 @@ def launch_ui_process(repo_dir: Path, logger: AttemptLogger) -> subprocess.Popen | |||||||
| [ | ||||||||
| sys.executable, | ||||||||
| str(repo_dir / "run_ui.py"), | ||||||||
| "--dockerized=true", | ||||||||
| "--dockerized=false", | ||||||||
| "--development=true", | ||||||||
|
Comment on lines
+683
to
+684
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify how docker/development flags are interpreted and consumed
rg -n -C3 'def is_dockerized|def is_development|def initialize|get_arg\(' helpers/runtime.py
rg -n -C3 '--dockerized|--development|is_dockerized\(|is_development\(' run_ui.py docker/run/fs/exe/self_update_manager.pyRepository: FortiShield/CtxAI Length of output: 1353 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check exact lines 683-684 in self_update_manager.py
echo "=== Lines 680-690 in self_update_manager.py ==="
sed -n '680,690p' docker/run/fs/exe/self_update_manager.py | cat -n
# Search for flag usage patterns separately
echo -e "\n=== Flag usage in self_update_manager.py ==="
rg -n 'dockerized|development' docker/run/fs/exe/self_update_manager.py
# Search for how this is invoked from run_ui or other places
echo -e "\n=== References to self_update_manager ==="
rg -n 'self_update_manager' --type pyRepository: FortiShield/CtxAI Length of output: 3658 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Get broader context around lines 674 and 683
echo "=== Context around line 674 (prepare_script) ==="
sed -n '670,680p' docker/run/fs/exe/self_update_manager.py | cat -n
echo -e "\n=== Context around line 683 (run_ui) ==="
sed -n '675,695p' docker/run/fs/exe/self_update_manager.py | cat -n
# Search for function definition containing these lines
echo -e "\n=== Function containing these lines ==="
rg -n -B20 'run_command.*prepare_script.*--dockerized=true' docker/run/fs/exe/self_update_manager.py | head -40
# Check run_ui.py to see how it uses these flags
echo -e "\n=== run_ui.py usage of dockerized and development ==="
rg -n 'dockerized|development' run_ui.py | head -20Repository: FortiShield/CtxAI Length of output: 2651 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check where launch_ui_process is called from
echo "=== Where is launch_ui_process called? ==="
rg -n 'launch_ui_process' docker/run/fs/exe/self_update_manager.py
# Check the broader context of the docker-run-ui command
echo -e "\n=== docker-run-ui command context ==="
rg -n -B5 -A10 'docker-run-ui' docker/run/fs/exe/self_update_manager.py | head -50
# Check if there are any other UI launches and how they set these flags
echo -e "\n=== Other run_ui.py invocations ==="
rg -n 'run_ui.py' --type py
# Check run_ui.py itself to see how it determines if it should run in dev mode
echo -e "\n=== run_ui.py initialization of runtime args ==="
head -50 run_ui.pyRepository: FortiShield/CtxAI Length of output: 3509 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Get the full docker_run_ui function to understand the overall flow
echo "=== docker_run_ui function ==="
rg -n -A50 'def docker_run_ui\(' docker/run/fs/exe/self_update_manager.py | head -70
# Check if there are comments or documentation about these flags
echo -e "\n=== Documentation/comments about dockerized flag ==="
rg -n -B2 -A2 'dockerized' docker/run/fs/exe/self_update_manager.py
# Check if run_ui.py is ever launched with --dockerized=true
echo -e "\n=== All run_ui.py invocations with flags ==="
rg -n -A10 'run_ui.py' docker/run/fs/exe/self_update_manager.pyRepository: FortiShield/CtxAI Length of output: 3381 Set The self_update_manager runs inside a docker container (as indicated by its path in Since 🔧 Proposed fix- "--dockerized=false",
- "--development=true",
+ "--dockerized=true",📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
| "--port=80", | ||||||||
| "--host=0.0.0.0", | ||||||||
|
Comment on lines
680
to
686
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (bug_risk): Re-evaluate Passing |
||||||||
| ], | ||||||||
|
Comment on lines
680
to
687
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. security (python.lang.security.audit.dangerous-subprocess-use-audit): Detected subprocess function 'Popen' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. Source: opengrep |
||||||||
|
|
@@ -873,7 +862,10 @@ def execute_pending_update( | |||||||
| "Git checkout completed but the repository commit does not match the requested target. " | ||||||||
| f"Expected {resolved_target['expected_commit']}, got {current_info['commit']}." | ||||||||
| ) | ||||||||
| if resolved_target.get("expected_short_tag") and current_info["short_tag"] != resolved_target["expected_short_tag"]: | ||||||||
| if ( | ||||||||
| resolved_target.get("expected_short_tag") | ||||||||
| and current_info["short_tag"] != resolved_target["expected_short_tag"] | ||||||||
| ): | ||||||||
| raise RuntimeError( | ||||||||
| "Git checkout completed but the repository version does not match the requested tag. " | ||||||||
| f"Expected {resolved_target['expected_short_tag']}, got {current_info['short_tag']}." | ||||||||
|
|
@@ -908,9 +900,7 @@ def execute_pending_update( | |||||||
| try: | ||||||||
| drop_stash(REPO_DIR, stash_ref, logger) | ||||||||
| except Exception as exc: | ||||||||
| logger.log( | ||||||||
| f"Temporary rollback stash {stash_ref} could not be dropped automatically: {exc}" | ||||||||
| ) | ||||||||
| logger.log(f"Temporary rollback stash {stash_ref} could not be dropped automatically: {exc}") | ||||||||
| return updated_process | ||||||||
|
|
||||||||
| logger.log(f"Updated UI failed health check, rolling back: {details}") | ||||||||
|
|
@@ -939,8 +929,7 @@ def execute_pending_update( | |||||||
| record_result( | ||||||||
| status="rolled_back", | ||||||||
| message=( | ||||||||
| "Updated version failed its health check and the previous version was restored. " | ||||||||
| f"Reason: {details}" | ||||||||
| f"Updated version failed its health check and the previous version was restored. Reason: {details}" | ||||||||
| ), | ||||||||
| request_data=request_data, | ||||||||
| source_info=source_info, | ||||||||
|
|
@@ -955,9 +944,7 @@ def execute_pending_update( | |||||||
| terminate_process(rollback_process) | ||||||||
| record_result( | ||||||||
| status="rollback_failed", | ||||||||
| message=( | ||||||||
| "Updated version failed its health check and rollback also failed to become healthy." | ||||||||
| ), | ||||||||
| message=("Updated version failed its health check and rollback also failed to become healthy."), | ||||||||
| request_data=request_data, | ||||||||
| source_info=source_info, | ||||||||
| current_version=source_info["short_tag"], | ||||||||
|
|
@@ -1159,9 +1146,7 @@ def docker_run_ui() -> int: | |||||||
| requested_branch=requested_branch, | ||||||||
| requested_tag=requested_tag, | ||||||||
| ): | ||||||||
| logger.log( | ||||||||
| "Requested tag already matches the installed version, skipping file replacement." | ||||||||
| ) | ||||||||
| logger.log("Requested tag already matches the installed version, skipping file replacement.") | ||||||||
| record_result( | ||||||||
| status="skipped", | ||||||||
| message="Requested tag already matches the installed version.", | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Avoid hard-coding the
buildxbuilder name to reduce setup friction.These targets currently depend on a preconfigured BuildKit builder named
mybuilder, so they’ll fail on machines where that builder doesn’t exist.Consider either:
--builderflag and using the default builder, orDOCKER_BUILDER ?= mybuilder) and documenting the requirement, orThat would make these targets more portable across different environments.
Suggested implementation: