feat(gitea): HTTPS support and training-ready seeding (#171)#197
Open
t0kubetsu wants to merge 18 commits into
Open
feat(gitea): HTTPS support and training-ready seeding (#171)#197t0kubetsu wants to merge 18 commits into
t0kubetsu wants to merge 18 commits into
Conversation
Implements all WAVE_04 training-readiness checklist items for the Gitea admin Docker stack: TLS / HTTPS - cert-gen init container generates a self-signed cert (GITEA_TLS_MODE=self-signed) or validates an operator-mounted cert (provided); exits immediately when disabled - gitea-certs named volume shared between cert-gen (write) and gitea (read-only) - GITEA_PROTOCOL and GITEA__server__PROTOCOL wired through compose.yml and .env.example - All provisioning curl calls use -k to tolerate self-signed certs on the internal network Organisation and team seeding (provision-org.sh) - Creates org GITEA_ORG_NAME (default: range42-training) - instructors team (owner perm) + one write-perm team per entry in GITEA_TEAMS - Two sample repos: workshop-linux-basics and workshop-ctf-intro - 5 labels each (exercise, hint, solution, bug, in-progress) - 2 milestones (Day 1, Day 2) with assigned issues - Feature branch + file commit + pre-seeded PR (demonstrates review workflow) - Branch protection on main (require 1 approving review, no direct push) - Topics and optional webhook (GITEA_WEBHOOK_URL) - Augments gitea-credentials.json with service_version, provisioned_at, org, sample_repos - Idempotency stamp at /tokens/.org-provisioned (separate from /tokens/.provisioned) Other changes - provision.sh: inserts provision-org.sh between users and tokens steps - Makefile reprovision: clears both stamps (.provisioned + .org-provisioned) - catalog_try_init_timeout bumped 90 → 120s to cover org-provisioning API calls Closes #171
Adds maybe_create_mirror() to provision-org.sh — mirrors a remote git repo under the org as a private, read-only Gitea mirror (8h sync interval). Skipped silently when GITEA_MIRROR_URL is empty. New env vars in .env.example: GITEA_MIRROR_URL — remote clone URL to mirror (empty = skip) GITEA_MIRROR_REPO_NAME — repo name inside the org (default: public-mirror) The mirrored repo is automatically added to the instructors team. Closes #171 (read-only mirror item)
Adds upload_ssh_keys() to provision-users.sh. After every user is
created, the function scans /ssh_keys/ (bind-mounted from ./ssh_keys/ on
the host) for .pub files whose name contains _<username>_ (r42playbooks
convention: r42.<scenario>-student-key_<username>_<n>.pub) or is named
<username>.pub, then registers each one via
POST /api/v1/admin/users/{username}/keys.
compose.yml: adds ./ssh_keys:/ssh_keys:ro mount to the provisioner
service (Docker silently skips the mount when the host dir is absent,
so the default no-key-seeding path is unchanged).
.env.example: documents expected key-file layout and seeding workflow.
Closes the "End-to-end SSH cycle" item tracked in ISSUE 171.
… key pattern
Two bugs in upload_ssh_keys():
- Search root was the entire ssh_keys/ directory, picking up deployer
and jump keys (backend_keys/, jump_keys/) that must never be uploaded
to Gitea. Now prefers ssh_keys/student_keys/ when present.
- Pattern "${username}.pub" matched only a bare filename; actual
r42playbooks naming is *-student-key_<user>.pub. Changed to
"*_${username}.pub" to match the un-numbered key alongside the
numbered variants (*_${username}_*.pub).
Depth of additional.students/ is 2 from student_keys/, well within
the existing -maxdepth 3.
Adds upload_backend_keys(username) which scans ssh_keys/backend_keys/
for all .pub files (maxdepth 1) and registers each via
POST /api/v1/admin/users/{username}/keys.
Called immediately after admin creation so the range42 backend can
clone repos over SSH using the same deployer key (alice) already
deployed to the VM.
Bash requires a function to be defined before it is called. The call was placed before the function body, causing 'command not found' at runtime. Moved the call to after upload_backend_keys() is defined, immediately before section 6 (instructors).
Two bugs: - cert-gen ran as git (uid 1000) and couldn't write to /certs/ volume; add `user: root` to compose.yml cert-gen service - mktemp template had a .cnf suffix which BusyBox mktemp rejects; drop the extension (OpenSSL accepts any filename as config)
- gen_password: replace printf|head pipe (SIGPIPE under pipefail) with printf '%.16s' format-string truncation — no subprocess, no signal - create_user: separate jq into its own variable to prevent set -e triggering silently before the || guard; capture HTTP status code explicitly so API errors are visible instead of swallowed
Replaces GITEA_MIRROR_URL + GITEA_MIRROR_REPO_NAME with GITEA_MIRRORS, a semicolon-separated list of "url|repo-name" pairs, allowing an arbitrary number of read-only mirrors to be seeded under the org.
Add --max-time 30 to prevent indefinite hang when Gitea is slow to respond on the token endpoint. Drop -f and guard with || true so an HTTP error falls through to the existing warn path instead of killing the script via set -e.
…llowing it Replace blind >/dev/null 2>&1 with HTTP status capture so mirror failures print the real Gitea error message. Also adds --max-time 120 since the migrate endpoint triggers a server-side clone.
Drop the workshop-linux-basics and workshop-ctf-intro seeding blocks. Repos are now seeded exclusively via GITEA_MIRRORS. Cleans up credentials JSON and script header accordingly.
…>=1.21 Mirror: split 409 (exists) from 422 (unreachable/invalid) and show the actual Gitea error message instead of a misleading 'already exists' warn. Tokens: check .token field first (.sha1 is deprecated since Gitea 1.21); print actual API error message when token creation fails.
…Gitea ≥1.21 - provision-org.sh: rename clone_url → clone_addr in migrate request body (Gitea API schema uses clone_addr; clone_url caused HTTP 422 [CloneAddr]: Required) - provision-tokens.sh: add scopes array to token creation request (Gitea ≥1.22 rejects tokens with no scopes; covers repo, issue, user, org read/write)
- Add GITEA__oauth2__JWT_SECRET env var to enable id_token signing for full OIDC compliance; without it the discovery endpoint exists but id_token is absent (OAuth2-only mode) - Add provision-oauth2.sh: idempotent script to register OAuth2 apps (Mattermost, Rocket.Chat, Nextcloud, …) via the Gitea REST API; appends client_id + client_secret to gitea-credentials.json - Add service.configure.gitea_oauth2_app Ansible role: registers an app via uri module, outputs gitea_oauth2_client_id / _client_secret facts for use by consumer service roles
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements all WAVE_04 training-readiness items from issue #171 for the Gitea admin Docker stack. Builds on top of #194 (
feat/gitea-docker-stack).HTTPS / TLS
cert-geninit container (reuses provisioner image): auto-generates a self-signed cert (GITEA_TLS_MODE=self-signed), validates an operator-provided cert (provided), or skips entirely (disabled, default)gitea-certsnamed volume shared betweencert-gen(write) andgitea(read-only)GITEA_PROTOCOL/GITEA__server__PROTOCOLwired throughcompose.ymland.env.examplecurlcalls use-k(safe on the internal Docker network)Organisation and team seeding (
provision-org.sh, new — ~240 lines)GITEA_ORG_NAME(default:range42-training)instructorsteam (owner perm) + one write-perm team perGITEA_TEAMSentryworkshop-linux-basics,workshop-ctf-introexercise,hint,solution,bug,in-progressDay 1,Day 2) with 3 assigned issues eachmain: require 1 approving review, no direct pushGITEA_WEBHOOK_URL)instructorsteam and all per-team Gitea teamsgitea-credentials.jsonwithservice_version,provisioned_at,org,sample_repos(backward-compatible —provision-tokens.shreads only.baseurland.users[])/tokens/.org-provisioned(independent of the existing/tokens/.provisioned)Other changes
provision.sh: addsprovision-org.shbetween users and tokens stepsMakefile reprovision: clears both stampscatalog_try_init_timeout: 90 → 120 s.env.example: new varsGITEA_TLS_MODE,GITEA_PROTOCOL,GITEA_ORG_NAME,GITEA_WEBHOOK_URLTest plan
make upwith default.env(HTTP, no TLS) — provisioner runs all three scripts,gitea-credentials.jsoncontainsorgandsample_reposfieldsGITEA_TLS_MODE=self-signed GITEA_PROTOCOL=https make rebuild-up— cert generated, Gitea serves HTTPS, healthcheck passes, provisioner connects over HTTPSGITEA_TLS_MODE=providedwith operator cert mounted — provisioner validates files, continuesmake reprovision— both stamps removed, full re-provisioning runs cleanlyrange42-trainingvisible, teams, two sample repos with labels/milestones/issues/PRs/branch protectionmake keys— credentials JSON includesservice_version,provisioned_at,org,sample_reposCloses #171
Depends on #194