Initial state: - ia_dev was historically referenced as ./ia_dev in docs and integrations, while the vendored module lives under services/ia_dev. - AnythingLLM sync and hook installation had error masking / weak exit signaling. - Proxy layers did not validate proxy path segments, allowing path normalization tricks. Motivation: - Make the IDE-oriented workflow usable (sync -> act -> deploy/preview) with explicit errors. - Reduce security footguns in proxying and script automation. Resolution: - Standardize IA_DEV_ROOT usage and documentation to services/ia_dev. - Add SSH remote data mirroring + optional AnythingLLM ingestion. - Extend AnythingLLM pull sync to support upload-all/prefix and fail on upload errors. - Harden smart-ide-sso-gateway and smart-ide-global-api proxying with safe-path checks and non-leaking error responses. - Improve ia-dev-gateway runner validation and reduce sensitive path leakage. - Add site scaffold tool (Vite/React) with OIDC + chat via sso-gateway -> orchestrator. Root cause: - Historical layout changes (submodule -> vendored tree) and missing central contracts for path resolution. - Missing validation for proxy path traversal patterns. - Overuse of silent fallbacks (|| true, exit 0 on partial failures) in automation scripts. Impacted features: - Project sync: git pull + AnythingLLM sync + remote data mirror ingestion. - Site frontends: SSO gateway proxy and orchestrator intents (rag.query, chat.local). - Agent execution: ia-dev-gateway script runner and SSE output. Code modified: - scripts/remote-data-ssh-sync.sh - scripts/anythingllm-pull-sync/sync.mjs - scripts/install-anythingllm-post-merge-hook.sh - cron/git-pull-project-clones.sh - services/smart-ide-sso-gateway/src/server.ts - services/smart-ide-global-api/src/server.ts - services/smart-ide-orchestrator/src/server.ts - services/ia-dev-gateway/src/server.ts - services/ia_dev/tools/site-generate.sh Documentation modified: - docs/** (architecture, API docs, ia_dev module + integration, scripts) Configurations modified: - config/services.local.env.example - services/*/.env.example Files in deploy modified: - services/ia_dev/deploy/* Files in logs impacted: - logs/ia_dev.log (runtime only) - .logs/* (runtime only) Databases and other sources modified: - None Off-project modifications: - None Files in .smartIde modified: - .smartIde/agents/*.md - services/ia_dev/.smartIde/** Files in .secrets modified: - None New patch version in VERSION: - 0.0.5 CHANGELOG.md updated: - yes
135 lines
4.5 KiB
Bash
Executable File
135 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Shared config and helpers for Gitea issues scripts.
|
|
# Source from git-issues/*.sh. Standalone: run from ia_dev root.
|
|
#
|
|
set -euo pipefail
|
|
|
|
GIT_ISSUES_DIR="${GIT_ISSUES_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
|
GITEA_API_URL="${GITEA_API_URL:-https://git.4nkweb.com/api/v1}"
|
|
GITEA_REPO_OWNER="${GITEA_REPO_OWNER:-4nk}"
|
|
GITEA_REPO_NAME="${GITEA_REPO_NAME:-lecoffre_ng}"
|
|
|
|
# Optional: load project config from ia_dev (projects/<id>/conf.json); logs and data per project under projects/<id>/
|
|
PROJECT_CONFIG_PATH=""
|
|
PROJECT_LOGS_DIR=""
|
|
DATA_ISSUES_DIR=""
|
|
if [[ -f "${GIT_ISSUES_DIR}/../lib/project_config.sh" ]]; then
|
|
PROJECT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || true
|
|
if [[ -z "${PROJECT_ROOT:-}" || "$(basename "$PROJECT_ROOT")" = "ia_dev" ]]; then
|
|
PROJECT_ROOT="$(cd "${GIT_ISSUES_DIR}/../.." && pwd)"
|
|
fi
|
|
IA_DEV_ROOT="$(cd "$GIT_ISSUES_DIR/.." && pwd)"
|
|
if [[ -n "${PROJECT_ROOT:-}" ]]; then
|
|
# shellcheck source=../lib/project_config.sh
|
|
source "${GIT_ISSUES_DIR}/../lib/project_config.sh"
|
|
if [[ -n "${PROJECT_ID:-}" && -n "${IA_DEV_ROOT:-}" ]]; then
|
|
PROJECT_LOGS_DIR="${IA_DEV_ROOT}/projects/${PROJECT_ID}/logs"
|
|
DATA_ISSUES_DIR="${IA_DEV_ROOT}/projects/${PROJECT_ID}/data/issues"
|
|
mkdir -p "${PROJECT_LOGS_DIR}" "${DATA_ISSUES_DIR}"
|
|
fi
|
|
fi
|
|
fi
|
|
export PROJECT_LOGS_DIR
|
|
export DATA_ISSUES_DIR
|
|
|
|
if [[ -f "${GIT_ISSUES_DIR}/../lib/smart_ide_logs.sh" ]]; then
|
|
# shellcheck source=../lib/smart_ide_logs.sh
|
|
source "${GIT_ISSUES_DIR}/../lib/smart_ide_logs.sh"
|
|
_IA_DEV_ROOT_FOR_LOG="$(cd "${GIT_ISSUES_DIR}/.." && pwd)"
|
|
smart_ide_logs_begin "$_IA_DEV_ROOT_FOR_LOG" "${BASH_SOURCE[1]}" "$*"
|
|
smart_ide_logs_register_exit_trap
|
|
fi
|
|
|
|
# Load token: GITEA_TOKEN env, then project config git.token_file (path relative to ia_dev root), then default
|
|
load_gitea_token() {
|
|
if [[ -n "${GITEA_TOKEN:-}" ]]; then
|
|
return 0
|
|
fi
|
|
local token_file=""
|
|
local ia_dev_root="${GIT_ISSUES_DIR}/.."
|
|
if [[ -n "${PROJECT_CONFIG_PATH:-}" && -f "$PROJECT_CONFIG_PATH" ]] && command -v jq >/dev/null 2>&1; then
|
|
local rel_path
|
|
rel_path="$(jq -r '.git.token_file // empty' "$PROJECT_CONFIG_PATH" 2>/dev/null)"
|
|
if [[ -n "$rel_path" ]]; then
|
|
# token_file in conf is relative to ia_dev root (this project)
|
|
if [[ -f "${ia_dev_root}/${rel_path}" ]]; then
|
|
token_file="${ia_dev_root}/${rel_path}"
|
|
fi
|
|
fi
|
|
fi
|
|
if [[ -z "$token_file" ]]; then
|
|
token_file="${ia_dev_root}/.secrets/git-issues/token"
|
|
fi
|
|
if [[ -f "$token_file" ]]; then
|
|
GITEA_TOKEN="$(cat "$token_file")"
|
|
return 0
|
|
fi
|
|
echo "[git-issues] ERROR: GITEA_TOKEN not set and ${token_file} not found" >&2
|
|
echo "[git-issues] Set GITEA_TOKEN or create the token file with a Gitea Personal Access Token." >&2
|
|
return 1
|
|
}
|
|
|
|
# curl wrapper for Gitea API (GET). Usage: gitea_api_get "/repos/owner/repo/issues"
|
|
gitea_api_get() {
|
|
local path="$1"
|
|
load_gitea_token || return 1
|
|
curl -sS -H "Accept: application/json" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_API_URL}${path}"
|
|
}
|
|
|
|
# curl wrapper for Gitea API (POST). Usage: gitea_api_post "/repos/owner/repo/issues/123/comments" '{"body":"..."}'
|
|
gitea_api_post() {
|
|
local path="$1"
|
|
local data="${2:-}"
|
|
load_gitea_token || return 1
|
|
curl -sS -X POST -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-d "$data" \
|
|
"${GITEA_API_URL}${path}"
|
|
}
|
|
|
|
# curl wrapper for Gitea API (PATCH). Usage: gitea_api_patch "/repos/owner/repo/wiki/page/Foo" '{"content_base64":"..."}'
|
|
gitea_api_patch() {
|
|
local path="$1"
|
|
local data="${2:-}"
|
|
load_gitea_token || return 1
|
|
curl -sS -X PATCH -H "Accept: application/json" -H "Content-Type: application/json" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-d "$data" \
|
|
"${GITEA_API_URL}${path}"
|
|
}
|
|
|
|
# curl wrapper for Gitea API (DELETE). Usage: gitea_api_delete "/repos/owner/repo/wiki/page/Foo"
|
|
gitea_api_delete() {
|
|
local path="$1"
|
|
load_gitea_token || return 1
|
|
curl -sS -X DELETE -H "Accept: application/json" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_API_URL}${path}"
|
|
}
|
|
|
|
log_ts() { date -u '+%Y-%m-%dT%H:%M:%SZ'; }
|
|
log_info() { echo "[$(log_ts)] [git-issues] $*"; }
|
|
log_err() { echo "[$(log_ts)] [git-issues] $*" >&2; }
|
|
|
|
# Require jq for JSON output
|
|
require_jq() {
|
|
if ! command -v jq &>/dev/null; then
|
|
log_err "jq is required. Install with: apt install jq / brew install jq"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Ensure we are in the git repo root (for create-branch, etc.)
|
|
require_git_root() {
|
|
local root
|
|
root="$(git rev-parse --show-toplevel 2>/dev/null)" || true
|
|
if [[ -z "$root" ]]; then
|
|
log_err "Not inside a git repository."
|
|
return 1
|
|
fi
|
|
cd "$root"
|
|
}
|