From 6a6704bc4b5dbf980a4af04c106b2a1ccaecfea9 Mon Sep 17 00:00:00 2001 From: test2 Date: Sat, 6 Jun 2026 22:45:55 +0300 Subject: [PATCH] Fix git deploy permissions: entrypoint chown and no remote set-url Co-authored-by: Cursor --- Dockerfile | 10 +++--- app/deploy_utils.py | 81 +++++++++++++++++++++++++++++++++------------ entrypoint.sh | 11 ++++++ 3 files changed, 77 insertions(+), 25 deletions(-) create mode 100644 entrypoint.sh diff --git a/Dockerfile b/Dockerfile index 8312cee..092f5de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libpq-dev \ gcc \ git \ + gosu \ docker.io \ && rm -rf /var/lib/apt/lists/* @@ -14,10 +15,10 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . . -RUN mkdir -p /app/uploads && adduser --disabled-password --gecos "" appuser \ - && chown -R appuser:appuser /app - -USER appuser +RUN mkdir -p /app/uploads \ + && adduser --disabled-password --gecos "" appuser \ + && chown -R appuser:appuser /app \ + && chmod +x /app/entrypoint.sh ENV FLASK_APP=wsgi:app ENV GIT_CONFIG_COUNT=1 @@ -26,4 +27,5 @@ ENV GIT_CONFIG_VALUE_0=/repo EXPOSE 8000 +ENTRYPOINT ["/app/entrypoint.sh"] CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "2", "--timeout", "120", "wsgi:app"] diff --git a/app/deploy_utils.py b/app/deploy_utils.py index 9b91524..b98300c 100644 --- a/app/deploy_utils.py +++ b/app/deploy_utils.py @@ -38,38 +38,77 @@ def run_git(args, timeout=120): return True, result.stdout.strip() +def run_ls_remote(extra_args=None, timeout=60): + remote = get_git_remote() + if not remote: + return False, "GIT_REMOTE_URL не задан", [] + + cmd = ["git", "ls-remote", remote] + if extra_args: + cmd.extend(extra_args) + + result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) + if result.returncode != 0: + return False, (result.stderr or result.stdout or "ls-remote error").strip(), [] + return True, "", result.stdout.splitlines() + + def fetch_remote(): remote = get_git_remote() - if remote: - ok, msg = run_git(["remote", "set-url", "origin", remote]) - if not ok: - return False, msg - return run_git(["fetch", "--all", "--tags", "--prune"], timeout=180) + if not remote: + return run_git(["fetch", "--all", "--tags", "--prune"], timeout=180) + + # Fetch from URL directly — do not write remote.origin.url to .git/config + return run_git( + [ + "fetch", + "--tags", + "--prune", + remote, + "+refs/heads/*:refs/remotes/origin/*", + "+refs/tags/*:refs/tags/*", + ], + timeout=180, + ) def list_tags(): - ok, msg = fetch_remote() + ok, err, lines = run_ls_remote(["--tags"]) if not ok: - return [], msg - ok, out = run_git(["tag", "--sort=-version:refname"]) - if not ok: - return [], out - return [line for line in out.splitlines() if line.strip()], None + return [], err + + tags = [] + for line in lines: + parts = line.split() + if len(parts) < 2: + continue + ref = parts[1] + if not ref.startswith("refs/tags/"): + continue + tag = ref.removeprefix("refs/tags/") + if tag.endswith("^{}"): + continue + tags.append(tag) + + tags = sorted(set(tags), reverse=True) + return tags, None def list_branches(): - ok, msg = fetch_remote() + ok, err, lines = run_ls_remote(["--heads"]) if not ok: - return [], msg - ok, out = run_git(["branch", "-a", "--format=%(refname:short)"]) - if not ok: - return [], out + return [], err + branches = [] - for line in out.splitlines(): - name = line.strip().replace("origin/", "") - if name and name not in branches and "HEAD" not in name: - branches.append(name) - return branches, None + for line in lines: + parts = line.split() + if len(parts) < 2: + continue + ref = parts[1] + if ref.startswith("refs/heads/"): + branches.append(ref.removeprefix("refs/heads/")) + + return sorted(set(branches)), None def get_current_version(): diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..c8093c6 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +# Mounted /repo belongs to host user; appuser needs write access for git deploy. +if [ "$ALLOW_GIT_DEPLOY" = "true" ] || [ "$ALLOW_GIT_DEPLOY" = "1" ] || [ "$ALLOW_GIT_DEPLOY" = "yes" ]; then + if [ -d /repo ]; then + chown -R appuser:appuser /repo + fi +fi + +exec gosu appuser "$@"