All checks were successful
continuous-integration/drone/push Build is passing
WARM_CANONICAL=True added to every recipe in cc-ci-plan/used-recipes.md (20 weekly + uptime-kuma external). enrolled_recipes() now returns all 21. Test fixtures (custom-html-*-bad, concurrency, regression) intentionally left unenrolled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
145 lines
6.5 KiB
Python
145 lines
6.5 KiB
Python
# Per-recipe harness config for gitea — used in TWO roles:
|
|
#
|
|
# 1. DEP PROVIDER (RECIPE=drone): gitea is deployed as an install-time dependency for the drone
|
|
# recipe. The harness deploys it before drone, provisions an admin user + OAuth2 app inside it
|
|
# (sso.setup_gitea_oauth), and tears it down after. All keys below apply to this path too.
|
|
#
|
|
# 2. RECIPE-UNDER-TEST (RECIPE=gitea): gitea is the enrolled recipe being tested. The full
|
|
# install/upgrade/backup/restore/custom lifecycle runs against it. The recipe-under-test keys
|
|
# (BACKUP_CAPABLE, SCREENSHOT, READY_PROBE, EXPECTED_NA) below are harmless to the dep path.
|
|
#
|
|
# Database: sqlite3 (compose.sqlite3.yml) — matches the dep config + lightest footprint.
|
|
# Backup: REAL tier — compose.yml carries backupbot.backup=true labels.
|
|
#
|
|
# LFS overlay (compose.lfs.yml, PR #1 lfs-plain-gitea): enabled ONLY when
|
|
# (a) compose.lfs.yml is present in the recipe checkout (it's on the PR branch, not main), AND
|
|
# (b) RECIPE=gitea (this is a recipe-under-test run, not a drone dep deploy).
|
|
# See DECISIONS.md (phase gtea) and tests/gitea/PARITY.md for the full split rationale.
|
|
|
|
import os as _os
|
|
|
|
HEALTH_PATH = "/api/healthz"
|
|
HEALTH_OK = (200,)
|
|
DEPLOY_TIMEOUT = 600
|
|
HTTP_TIMEOUT = 600
|
|
BACKUP_CAPABLE = True # compose.yml carries backupbot.backup=true labels — force on
|
|
|
|
|
|
def READY_PROBE(ctx):
|
|
# Extra readiness: the /api/v1/version endpoint returns 200 JSON when the API is fully up
|
|
# (healthz passes earlier, before the API router is fully wired). Avoids flaky test_install
|
|
# failures where healthz=200 but admin API calls fail with 503.
|
|
return [{"host": ctx.domain, "path": "/api/v1/version", "ok": (200,)}]
|
|
|
|
|
|
def SCREENSHOT(page, ctx):
|
|
# Navigate to the sign-in page — a credential-free view that shows the gitea UI.
|
|
from playwright.sync_api import sync_playwright # noqa: F401 — re-entry guard
|
|
|
|
page.goto(f"{ctx.base_url}/user/login", wait_until="networkidle", timeout=30_000)
|
|
page.wait_for_selector("form.ui.form", timeout=15_000)
|
|
|
|
|
|
def _lfs_enabled():
|
|
"""True when compose.lfs.yml is available in the recipe checkout AND this is a
|
|
recipe-under-test run (RECIPE=gitea). Both conditions prevent LFS leaking into the dep path."""
|
|
abra_dir = _os.environ.get("ABRA_DIR") or _os.path.expanduser("~/.abra")
|
|
lfs_overlay = _os.path.join(abra_dir, "recipes", "gitea", "compose.lfs.yml")
|
|
return _os.path.exists(lfs_overlay) and _os.environ.get("RECIPE", "") == "gitea"
|
|
|
|
|
|
def UPGRADE_EXTRA_ENV(ctx):
|
|
"""Applied after PR-head checkout: add compose.lfs.yml to COMPOSE_FILE when LFS lands in the PR
|
|
(e.g. lfs-plain-gitea PR #1). At this point compose.lfs.yml has already been checked out.
|
|
The harness generates any new secrets (lfs_jwt_secret) before the chaos redeploy."""
|
|
if not _lfs_enabled():
|
|
return {}
|
|
return {
|
|
"COMPOSE_FILE": "compose.yml:compose.sqlite3.yml:compose.lfs.yml",
|
|
"GITEA_LFS_START_SERVER": "true",
|
|
"SECRET_LFS_JWT_SECRET_VERSION": "v1",
|
|
}
|
|
|
|
|
|
def UPGRADE_SECRET_PREP(ctx):
|
|
"""Pre-insert lfs_jwt_secret with the correct 43-char base64 URL-safe format before
|
|
`abra secret generate --all` runs. The lfs-plain-gitea PR's .env.sample has the
|
|
SECRET_LFS_JWT_SECRET_VERSION=v1 spec COMMENTED OUT, so abra uses a wrong default length;
|
|
gitea requires exactly 43 chars (32 bytes) or it fatals on the read-only app.ini."""
|
|
if not _lfs_enabled():
|
|
return
|
|
import base64
|
|
import subprocess
|
|
|
|
# abra derives STACK_NAME from the domain by replacing dots with underscores
|
|
# (e.g. gite-e1cb78.ci.commoninternet.net → gite-e1cb78_ci_commoninternet_net).
|
|
stack_name = ctx.domain.replace(".", "_")
|
|
docker_secret = f"{stack_name}_lfs_jwt_secret_v1"
|
|
value = base64.urlsafe_b64encode(_os.urandom(32)).rstrip(b"=").decode()
|
|
|
|
subprocess.run(["docker", "secret", "rm", docker_secret], capture_output=True)
|
|
result = subprocess.run(
|
|
["docker", "secret", "create", docker_secret, "-"],
|
|
input=value,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
if result.returncode != 0:
|
|
raise RuntimeError(
|
|
f"UPGRADE_SECRET_PREP: docker secret create {docker_secret}: {result.stderr.strip()}"
|
|
)
|
|
print(f" gitea upgrade: pre-created {docker_secret} (43-char lfs_jwt_secret)", flush=True)
|
|
|
|
|
|
def EXTRA_ENV(ctx):
|
|
lfs = _lfs_enabled()
|
|
compose_file = "compose.yml:compose.sqlite3.yml"
|
|
if lfs:
|
|
compose_file += ":compose.lfs.yml"
|
|
|
|
env = {
|
|
"COMPOSE_FILE": compose_file,
|
|
"GITEA_APP_NAME": "CI Dep Gitea",
|
|
"GITEA_ALLOW_ONLY_EXTERNAL_REGISTRATION": "false",
|
|
"GITEA_AUTO_WATCH_NEW_REPOS": "false",
|
|
"GITEA_DISABLE_REGISTRATION": "false",
|
|
"GITEA_ENABLE_NOTIFY_MAIL": "false",
|
|
"GITEA_ENABLE_OPENID_SIGNIN": "false",
|
|
"GITEA_ENABLE_OPENID_SIGNUP": "false",
|
|
"GITEA_DISABLE_GRAVATAR": "true",
|
|
"GITEA_ENABLE_FEDERATED_AVATAR": "false",
|
|
# Not requiring sign-in lets the /api/healthz endpoint work without a session.
|
|
"GITEA_REQUIRE_SIGNIN_VIEW": "false",
|
|
"GITEA_LANDING_PAGE": "explore",
|
|
"GITEA_SHOW_USER_EMAIL": "false",
|
|
"GITEA_DISABLE_REGULAR_ORG_CREATION": "false",
|
|
"GITEA_DEFAULT_KEEP_EMAIL_PRIVATE": "false",
|
|
"GITEA_DEFAULT_ALLOW_CREATE_ORGANIZATION": "true",
|
|
"GITEA_ENABLE_USER_HEATMAP": "false",
|
|
"GITEA_DEFAULT_USER_VISIBILITY": "public",
|
|
"GITEA_ALLOWED_USER_VISIBILITY_MODES": "public,limited,private",
|
|
"GITEA_DEFAULT_ORG_VISIBILITY": "public",
|
|
"GITEA_SSH_PORT": "2222",
|
|
"GITEA_REPO_UPLOAD_ENABLED": "false",
|
|
"GITEA_REPO_UPLOAD_ALLOWED_TYPES": "",
|
|
"GITEA_REPO_UPLOAD_MAX_SIZE": "0",
|
|
"GITEA_REPO_UPLOAD_MAX_FILES": "0",
|
|
"GITEA_ENABLE_PUSH_CREATE_USER": "false",
|
|
"GITEA_ENABLE_PUSH_CREATE_ORG": "false",
|
|
"GITEA_LFS_START_SERVER": "true" if lfs else "false",
|
|
# CORS allow-domain — left empty; OAuth2 redirects are not CORS-gated.
|
|
"GITEA_CORS_ALLOW_DOMAIN": "",
|
|
# Mailer placeholder — required by app.ini.tmpl but SMTP is not enabled.
|
|
"GITEA_MAILER_FROM": "noreply@ci.local",
|
|
"GITEA_MAILER_USER": "noreply@ci.local",
|
|
}
|
|
if lfs:
|
|
# Tell abra's secret generator which version to use for lfs_jwt_secret.
|
|
env["SECRET_LFS_JWT_SECRET_VERSION"] = "v1"
|
|
return env
|
|
|
|
|
|
# canon §2.B: enroll as a DATA-WARM canonical (all recipes enrolled — operator 2026-06-17).
|
|
# The weekly sweep promotes this recipe's canonical to its latest green RELEASE TAG.
|
|
WARM_CANONICAL = True
|