Lightweight shared Gitea runner

The existing global registration and deploy label are retained. The runner is not privileged, has no Docker socket, drops all capabilities, and now runs as UID 10001 with a read-only root filesystem and read-only registration mount. Job workspaces live in bounded tmpfs and do not persist across container restarts. Job capacity is one; timeout is 60 minutes. The deployment SSH credential remains repository-scoped and its CORP forced command accepts only the current master SHA.

Install this directory's files on the Gitea server and run sudo python3 /path/to/install-runner-hardening.py only after pausing assignment of new jobs in Gitea and waiting for the current job to finish. Resume assignment after the installer confirms the runner is healthy. An idle ps snapshot alone is insufficient: the runner could receive a new job before container replacement. The installer does not pause scheduling automatically or verify that pause. The installer backs up configuration and restores it if the runner cannot rejoin.

Trust boundary: deploy:host executes all jobs as the same container user. It is not a security boundary between repository authors. Keep workflow-writing permissions restricted to trusted developers. Strict isolation requires separate ephemeral job environments; the shared host runner must not run untrusted forks. Container restrictions do not make it safe for mutually untrusted tenants.