Fix git deploy permissions: entrypoint chown and no remote set-url
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+6
-4
@@ -6,6 +6,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
libpq-dev \
|
libpq-dev \
|
||||||
gcc \
|
gcc \
|
||||||
git \
|
git \
|
||||||
|
gosu \
|
||||||
docker.io \
|
docker.io \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
@@ -14,10 +15,10 @@ RUN pip install --no-cache-dir -r requirements.txt
|
|||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
RUN mkdir -p /app/uploads && adduser --disabled-password --gecos "" appuser \
|
RUN mkdir -p /app/uploads \
|
||||||
&& chown -R appuser:appuser /app
|
&& adduser --disabled-password --gecos "" appuser \
|
||||||
|
&& chown -R appuser:appuser /app \
|
||||||
USER appuser
|
&& chmod +x /app/entrypoint.sh
|
||||||
|
|
||||||
ENV FLASK_APP=wsgi:app
|
ENV FLASK_APP=wsgi:app
|
||||||
ENV GIT_CONFIG_COUNT=1
|
ENV GIT_CONFIG_COUNT=1
|
||||||
@@ -26,4 +27,5 @@ ENV GIT_CONFIG_VALUE_0=/repo
|
|||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||||
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "2", "--timeout", "120", "wsgi:app"]
|
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "2", "--timeout", "120", "wsgi:app"]
|
||||||
|
|||||||
+59
-20
@@ -38,38 +38,77 @@ def run_git(args, timeout=120):
|
|||||||
return True, result.stdout.strip()
|
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():
|
def fetch_remote():
|
||||||
remote = get_git_remote()
|
remote = get_git_remote()
|
||||||
if remote:
|
if not 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)
|
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():
|
def list_tags():
|
||||||
ok, msg = fetch_remote()
|
ok, err, lines = run_ls_remote(["--tags"])
|
||||||
if not ok:
|
if not ok:
|
||||||
return [], msg
|
return [], err
|
||||||
ok, out = run_git(["tag", "--sort=-version:refname"])
|
|
||||||
if not ok:
|
tags = []
|
||||||
return [], out
|
for line in lines:
|
||||||
return [line for line in out.splitlines() if line.strip()], None
|
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():
|
def list_branches():
|
||||||
ok, msg = fetch_remote()
|
ok, err, lines = run_ls_remote(["--heads"])
|
||||||
if not ok:
|
if not ok:
|
||||||
return [], msg
|
return [], err
|
||||||
ok, out = run_git(["branch", "-a", "--format=%(refname:short)"])
|
|
||||||
if not ok:
|
|
||||||
return [], out
|
|
||||||
branches = []
|
branches = []
|
||||||
for line in out.splitlines():
|
for line in lines:
|
||||||
name = line.strip().replace("origin/", "")
|
parts = line.split()
|
||||||
if name and name not in branches and "HEAD" not in name:
|
if len(parts) < 2:
|
||||||
branches.append(name)
|
continue
|
||||||
return branches, None
|
ref = parts[1]
|
||||||
|
if ref.startswith("refs/heads/"):
|
||||||
|
branches.append(ref.removeprefix("refs/heads/"))
|
||||||
|
|
||||||
|
return sorted(set(branches)), None
|
||||||
|
|
||||||
|
|
||||||
def get_current_version():
|
def get_current_version():
|
||||||
|
|||||||
@@ -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 "$@"
|
||||||
Reference in New Issue
Block a user