blob: 5257d35832086754f54756c376f410c809240046 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
#!/usr/bin/env bash
set -euo pipefail
APP_ROOT=/opt/pentest-ghostwriter/app
ENV_FILE=/etc/pentest-ghostwriter/pentest-ghostwriter.env
STATE_ROOT=/var/lib/pentest-ghostwriter
VENV_DIR=${STATE_ROOT}/venv
LOG_DIR=/var/log/pentest-ghostwriter
CRED_FILE=/etc/pentest-ghostwriter/admin-credentials
MEDIA_ROOT=${STATE_ROOT}/media
PY312_BIN=/usr/bin/python3.12
need_cmd() {
command -v "$1" >/dev/null 2>&1 || {
echo "Missing: $1" >&2
exit 1
}
}
rand_secret() {
"$PY312_BIN" - <<'PY'
import secrets
print(secrets.token_urlsafe(48))
PY
}
rand_password() {
"$PY312_BIN" - <<'PY'
import secrets
print(secrets.token_urlsafe(24))
PY
}
replace_env_value() {
local key="$1"
local value="$2"
"$PY312_BIN" - "$ENV_FILE" "$key" "$value" <<'PY'
from pathlib import Path
import sys
path = Path(sys.argv[1])
key = sys.argv[2]
value = sys.argv[3]
lines = path.read_text(encoding='utf-8').splitlines()
out = []
replaced = False
for line in lines:
if line.startswith(f"{key}="):
out.append(f"{key}={value}")
replaced = True
else:
out.append(line)
if not replaced:
out.append(f"{key}={value}")
path.write_text("\n".join(out) + "\n", encoding='utf-8')
PY
}
if [[ $EUID -ne 0 ]]; then
echo "Please run this command as root." >&2
exit 1
fi
need_cmd "$PY312_BIN"
need_cmd node
need_cmd npm
need_cmd systemd-tmpfiles
need_cmd systemd-sysusers
if [[ ! -f ${ENV_FILE} ]]; then
install -Dm640 /etc/pentest-ghostwriter/pentest-ghostwriter.env.example "${ENV_FILE}"
echo "Env file created: ${ENV_FILE}" >&2
fi
systemd-sysusers /usr/lib/sysusers.d/pentest-ghostwriter.conf
systemd-tmpfiles --create /usr/lib/tmpfiles.d/pentest-ghostwriter.conf
current_secret=$(grep '^DJANGO_SECRET_KEY=' "${ENV_FILE}" | cut -d= -f2- || true)
[[ -n "$current_secret" ]] || replace_env_value DJANGO_SECRET_KEY "$(rand_secret)"
current_secret=$(grep '^DJANGO_JWT_SECRET_KEY=' "${ENV_FILE}" | cut -d= -f2- || true)
[[ -n "$current_secret" ]] || replace_env_value DJANGO_JWT_SECRET_KEY "$(rand_secret)"
current_secret=$(grep '^HASURA_GRAPHQL_ADMIN_SECRET=' "${ENV_FILE}" | cut -d= -f2- || true)
[[ -n "$current_secret" ]] || replace_env_value HASURA_GRAPHQL_ADMIN_SECRET "$(rand_secret)"
current_secret=$(grep '^HASURA_ACTION_SECRET=' "${ENV_FILE}" | cut -d= -f2- || true)
[[ -n "$current_secret" ]] || replace_env_value HASURA_ACTION_SECRET "$(rand_secret)"
pg_pass=$(grep '^POSTGRES_PASSWORD=' "${ENV_FILE}" | cut -d= -f2- || true)
if [[ -z "$pg_pass" || "$pg_pass" == 'change-me' ]]; then
pg_pass=$(rand_password)
replace_env_value POSTGRES_PASSWORD "$pg_pass"
replace_env_value DATABASE_URL "postgres://ghostwriter:${pg_pass}@127.0.0.1:5432/ghostwriter"
fi
admin_pass=$(grep '^DJANGO_SUPERUSER_PASSWORD=' "${ENV_FILE}" | cut -d= -f2- || true)
if [[ -z "$admin_pass" || "$admin_pass" == 'change-me' ]]; then
admin_pass=$(rand_password)
replace_env_value DJANGO_SUPERUSER_PASSWORD "$admin_pass"
fi
# shellcheck disable=SC1090
set -a
source "${ENV_FILE}"
set +a
mkdir -p "${MEDIA_ROOT}" "${LOG_DIR}" "${STATE_ROOT}"
chown -R pentest-ghostwriter:pentest-ghostwriter "${STATE_ROOT}" "${LOG_DIR}"
rm -rf "${VENV_DIR}"
"$PY312_BIN" -m venv "${VENV_DIR}"
"${VENV_DIR}/bin/pip" install --upgrade pip 'setuptools<81' wheel
"${VENV_DIR}/bin/pip" install -r "${APP_ROOT}/requirements/production.txt"
"${VENV_DIR}/bin/pip" install whitenoise
"${VENV_DIR}/bin/python" -m spacy download "${SPACY_MODEL:-en_core_web_sm}"
pushd "${APP_ROOT}/javascript" >/dev/null
npm ci
npm run build-frontend-prod
npm run build-collab-server-prod
popd >/dev/null
export DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE:-config.settings.production}
export PYTHONPATH="${APP_ROOT}:${PYTHONPATH:-}"
export DATABASE_URL=${DATABASE_URL:-postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}}
export REDIS_URL=${REDIS_URL:-redis://${REDIS_HOST}:${REDIS_PORT}/0}
pushd "${APP_ROOT}" >/dev/null
"${VENV_DIR}/bin/python" manage.py collectstatic --noinput
"${VENV_DIR}/bin/python" manage.py migrate
"${VENV_DIR}/bin/python" manage.py shell -c '
from django.contrib.auth import get_user_model
import os
User = get_user_model()
username = os.environ.get("DJANGO_SUPERUSER_USERNAME", "admin")
email = os.environ.get("DJANGO_SUPERUSER_EMAIL", "admin@example.invalid")
password = os.environ["DJANGO_SUPERUSER_PASSWORD"]
u, _ = User.objects.get_or_create(username=username, defaults={"email": email})
u.email = email
u.is_staff = True
u.is_superuser = True
u.is_active = True
u.set_password(password)
u.save()
print(f"admin user ready: {username}")
'
popd >/dev/null
umask 077
cat > "${CRED_FILE}" <<EOF
URL=http://127.0.0.1:8000
USERNAME=${DJANGO_SUPERUSER_USERNAME:-admin}
PASSWORD=${DJANGO_SUPERUSER_PASSWORD}
LOCAL_TRUST_MODE=${LOCAL_TRUST_MODE:-false}
EOF
chmod 600 "${CRED_FILE}"
echo
cat <<MSG
Bootstrap complete.
Important paths:
- Python runtime: ${VENV_DIR}
- Env file: ${ENV_FILE}
- App source: ${APP_ROOT}
- Media: ${MEDIA_ROOT}
- Credentials: ${CRED_FILE}
Next steps:
1. sudo systemctl enable --now postgresql valkey
2. sudo systemctl enable --now pentest-ghostwriter-web.service
3. sudo systemctl enable --now pentest-ghostwriter-queue.service
4. sudo systemctl enable --now pentest-ghostwriter-collab.service
5. Optional: sudo pentest-ghostwriter-init --local-trust
MSG
|