diff --git a/README.md b/README.md index 7494b4a..8272a9f 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ TAPM Deployment Access is a short-lived authorization broker for protected deployment packages and installer actions. Technicians authenticate through -the bundled Gitea service, create deployment codes, and authorize a limited +the bundled Git service, create deployment codes, and authorize a limited number of hosts for selected capabilities. The production layout is a self-contained, single-VM Docker deployment: - Go broker with a persistent embedded SQLite database -- rootless Gitea with SQLite, repositories, and package registry +- rootless Git service with SQLite, repositories, and package registry - Nginx reverse proxy for both public domains - Certbot and Let's Encrypt HTTP-01 certificate management - explicit runtime storage under `config/` beside the Compose files @@ -19,7 +19,7 @@ needs to forward public TCP 80 and 443 to the configured Docker VM ports. All services are managed by one Compose project while remaining separate containers for independent health checks and upgrades. -See [docs/deployment.md](docs/deployment.md) for the installation, Gitea setup, +See [docs/deployment.md](docs/deployment.md) for the installation, Git setup, TLS bootstrap, repository move, renewal, backup, and update procedures. The ProxMenu integration contract is in [docs/client-api.md](docs/client-api.md). @@ -32,9 +32,9 @@ After cloning the repository, run: ``` The installer defaults to `SSL_MODE=none`, writes a mode-`0600` `.env`, creates -the runtime directories and Docker network, and starts Gitea behind the -HTTP-only Nginx test configuration. It does not invent Gitea OAuth or package -credentials. After creating those resources in Gitea, run +the runtime directories and Docker network, and starts Git behind the +HTTP-only Nginx test configuration. It does not invent Git OAuth or package +credentials. After creating those resources in Git, run `./manage.sh configure-broker` and `./manage.sh start`. New deployment codes default to seven days. While a code is active, the Codes diff --git a/deploy/nginx/templates/http.conf.template b/deploy/nginx/templates/http.conf.template index 24be857..30acf69 100644 --- a/deploy/nginx/templates/http.conf.template +++ b/deploy/nginx/templates/http.conf.template @@ -40,7 +40,7 @@ server { add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always; location / { - # Resolve at request time so Gitea-only bootstrap works before the + # Resolve at request time so Git-only bootstrap works before the # broker container exists. Requests return 502 until broker setup ends. set $broker_backend_url http://broker:8080; proxy_pass $broker_backend_url; diff --git a/docs/client-api.md b/docs/client-api.md index 24a5532..36e9cff 100644 --- a/docs/client-api.md +++ b/docs/client-api.md @@ -1,6 +1,6 @@ # Proxmox client API -The ProxMenu client uses two HTTPS requests. It never receives Gitea +The ProxMenu client uses two HTTPS requests. It never receives Git credentials. ## Exchange a deployment code diff --git a/docs/deployment.md b/docs/deployment.md index 64fc6ef..862b7cd 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -7,8 +7,8 @@ VM. `/opt/idssys/TA-Deployment-Access` is only one possible example. One Compose project manages: - TAPM broker, with an embedded SQLite database -- Gitea, with its own embedded SQLite database and repository storage -- Nginx, terminating TLS for the broker and Gitea +- Git, with its own embedded SQLite database and repository storage +- Nginx, terminating TLS for the broker and Git - Certbot, as an on-demand utility for certificate issuance and renewal The same deployment supports an explicitly insecure HTTP testing phase before @@ -18,9 +18,9 @@ runtime data. In production, only the configured Nginx HTTP and HTTPS ports are published. They default to 8680 and 8643. Inside Docker, Nginx listens on ports 80 and 443, -the broker on 8080, and Gitea is explicitly pinned to `0.0.0.0:3000`. Gitea +the broker on 8080, and Git is explicitly pinned to `0.0.0.0:3000`. Git SSH is disabled. Deployment-level variables such as `HTTP_PORT` are not passed -into the Gitea container, preventing them from overriding its internal listener. +into the Git container, preventing them from overriding its internal listener. ## 1. VM and network @@ -38,7 +38,7 @@ the required forwarded ports. Nginx supplies the application-edge controls: unknown HTTP hostnames are dropped, unknown TLS SNI names are rejected, TLS is restricted to 1.2/1.3, session tickets and version disclosure are disabled, broker requests and per-address connections are limited, slow-client -timeouts are bounded, Gitea login bursts are throttled, and HSTS plus browser +timeouts are bounded, Git login bursts are throttled, and HSTS plus browser security headers are returned. Container PID ceilings and Docker log rotation reduce the impact of local resource exhaustion. Nginx also runs with a read-only container filesystem and narrowly scoped @@ -50,7 +50,7 @@ forwarding headers. ```sh sudo mkdir -p /YOUR/INSTALL/PARENT -sudo git clone GITEA-REPOSITORY-URL /YOUR/INSTALL/PARENT/TA-Deployment-Access +sudo git clone GIT-REPOSITORY-URL /YOUR/INSTALL/PARENT/TA-Deployment-Access sudo chown -R 1000:1000 /YOUR/INSTALL/PARENT/TA-Deployment-Access cd /YOUR/INSTALL/PARENT/TA-Deployment-Access ./install.sh @@ -58,7 +58,7 @@ cd /YOUR/INSTALL/PARENT/TA-Deployment-Access The guided installer validates both hostnames and Docker ports, generates the broker cookie secret, writes `.env` with mode `0600`, prepares persistent -storage, and starts only Gitea and Nginx. It defaults to `SSL_MODE=none`, so no +storage, and starts only Git and Nginx. It defaults to `SSL_MODE=none`, so no certificate or public port forwarding is required. With the default `HTTP_PORT=8680`, test URLs include that port: @@ -82,7 +82,7 @@ Runtime state is deliberately visible below the checkout: config/ ├── broker/ # tapm.db and SQLite WAL files ├── gitea/ -│ ├── config/ # app.ini and Gitea configuration +│ ├── config/ # app.ini and Git configuration │ └── data/ # repositories, packages, and gitea.db ├── letsencrypt/ # account data, certificate, and private key ├── ssl/ # optional administrator-provided certificate @@ -92,15 +92,15 @@ config/ The contents are ignored by Git. They must never be committed. -## 3. Configure Gitea and the broker +## 3. Configure Git and the broker -The installer has already bootstrapped Gitea. Create the initial administrator: +The installer has already bootstrapped Git. Create the initial administrator: ```sh ./manage.sh create-admin ``` -Sign in at the Gitea URL printed by the command and change the temporary +Sign in at the Git URL printed by the command and change the temporary password. Create the `TAI` organization, then create: 1. `tapm-packages`, with a read-only package token. @@ -116,13 +116,13 @@ Save the resulting values without echoing secrets to the terminal: ``` The broker is deliberately not started during the first bootstrap. Blank -OAuth/package values are valid for Gitea-only setup, while `start` refuses to +OAuth/package values are valid for Git-only setup, while `start` refuses to launch the broker until all required credentials are present. -`TAPM_GITEA_URL` is the public browser-facing Gitea URL. +`TAPM_GITEA_URL` is the public browser-facing Git URL. `TAPM_GITEA_INTERNAL_URL` defaults to `http://gitea:3000` in installations so OAuth token exchange and package traffic stay on the private Compose network. -Do not publish Gitea's internal port to make broker authentication work. +Do not publish Git's internal port to make broker authentication work. Deployment codes default to seven days: @@ -141,7 +141,7 @@ For troubleshooting, use `./manage.sh diagnostics`. Do not share unredacted `docker compose config` output: Compose resolves the broker's `.env` file and can print cookie, OAuth, and package secrets. If configuration output is accidentally disclosed, rotate the cookie secret with -`./manage.sh rotate-cookie-secret` and replace any configured Gitea tokens or +`./manage.sh rotate-cookie-secret` and replace any configured Git tokens or OAuth secret that appeared. ## 4. Enable TLS when forwarding is ready @@ -157,7 +157,7 @@ After public DNS resolves and the datacenter edge forwards public TCP 80 and `set-ssl` changes all public URLs to HTTPS and removes the temporary `:8680` test port. `bootstrap` obtains the certificate and switches Nginx to TLS. -`start` recreates Gitea and the broker with secure cookies. Existing SQLite +`start` recreates Git and the broker with secure cookies. Existing SQLite databases, repositories, packages, installation identities, and secrets remain in place. @@ -188,7 +188,7 @@ curl --fail "http://GITEA_DOMAIN:HTTP_PORT/api/healthz" # SSL_MODE=none ``` The broker automatically applies SQLite schema migrations before starting. -Gitea uses its own SQLite database at +Git uses its own SQLite database at `config/gitea/data/data/gitea.db`. After TLS is enabled, use the equivalent `https://` URLs without the temporary HTTP test port. @@ -196,7 +196,7 @@ HTTP test port. ### Final identity hardening After public DNS, WAN TCP 80/443 forwarding, and the Let's Encrypt certificate -are working, configure Microsoft Entra ID as Gitea's OpenID Connect +are working, configure Microsoft Entra ID as Git's OpenID Connect authentication source. Register the final callback URL: ```text @@ -204,9 +204,9 @@ https://GITEA_DOMAIN/user/oauth2/entra/callback ``` Require assignment to the Entra enterprise application, apply the company's -Duo-backed Conditional Access policy, and map the Entra `Gitea.User` and -`Gitea.Admin` application roles into Gitea. Verify an Entra administrator can -sign in and reach the broker before disabling Gitea's local password sign-in +Duo-backed Conditional Access policy, and map the Entra `Git.User` and +`Git.Admin` application roles into Git. Verify an Entra administrator can +sign in and reach the broker before disabling Git's local password sign-in form. Keep a documented VM-console recovery procedure and retain the package reader and publisher as non-admin service accounts with narrowly scoped tokens. @@ -227,8 +227,8 @@ Then run: ./manage.sh start-direct ``` -This adds host mappings to the broker's port 8080 and Gitea's port 3000. It -also changes Gitea's root URL and session cookie policy to permit HTTP login. +This adds host mappings to the broker's port 8080 and Git's port 3000. It +also changes Git's root URL and session cookie policy to permit HTTP login. The direct broker port is suitable for health and API testing; technician OAuth login remains designed for the HTTPS public URL. Do not use the direct-port override on an Internet-facing production VM. Return to the @@ -241,7 +241,7 @@ production URL and secure-cookie policy with: ## 6. Move repositories For each existing repository, create an empty matching repository in the new -Gitea and mirror all refs: +Git and mirror all refs: ```sh git clone --mirror OLD-REPOSITORY-URL @@ -280,10 +280,10 @@ cd /YOUR/INSTALL/PARENT/TA-Deployment-Access ``` The updater operates only on the current VM. It fast-forwards the checked-out -branch, pulls the pinned Gitea and Nginx images, rebuilds and restarts the local +branch, pulls the pinned Git and Nginx images, rebuilds and restarts the local stack, and waits for the local broker to become healthy. Certbot is not pulled or run during a routine update; it is used only by `bootstrap` and `renew`. The updater has no peer discovery, SSH, or multi-node update behavior. Pin image versions as supplied and review release notes before changing them. -Never change Gitea between rootless and rootful image families in place. +Never change Git between rootless and rootful image families in place. diff --git a/install.sh b/install.sh index 99418d2..9417553 100755 --- a/install.sh +++ b/install.sh @@ -52,15 +52,15 @@ docker info >/dev/null 2>&1 || fail "the Docker daemon is unavailable or this user cannot access it" printf '\nTAPM Deployment Access installer\n' -printf 'This creates the initial environment and starts Gitea behind Nginx.\n' -printf 'The broker starts only after its Gitea OAuth and package credentials are configured.\n\n' +printf 'This creates the initial environment and starts Git behind Nginx.\n' +printf 'The broker starts only after its Git OAuth and package credentials are configured.\n\n' broker_domain="$(prompt_default 'Broker hostname' 'tapm.example.com')" -gitea_domain="$(prompt_default 'Gitea hostname' 'git.example.com')" +gitea_domain="$(prompt_default 'Git hostname' 'git.example.com')" valid_hostname "$broker_domain" || fail "invalid broker hostname" -valid_hostname "$gitea_domain" || fail "invalid Gitea hostname" +valid_hostname "$gitea_domain" || fail "invalid Git hostname" [[ "$broker_domain" != "$gitea_domain" ]] || - fail "broker and Gitea hostnames must be different" + fail "broker and Git hostnames must be different" http_port="$(prompt_default 'VM port mapped to Nginx HTTP port 80' '8680')" https_port="$(prompt_default 'VM port mapped to Nginx HTTPS port 443' '8643')" @@ -136,20 +136,20 @@ chmod 600 .env printf '\nInitial configuration saved to %s/.env.\n' "$DEPLOY_ROOT" if [[ "$ssl_mode" == "custom" ]]; then printf 'Place the certificate and key in config/ssl, then run ./manage.sh bootstrap.\n' - printf 'Gitea has not been started yet.\n' + printf 'Git has not been started yet.\n' exit 0 fi "${DEPLOY_ROOT}/manage.sh" bootstrap -printf '\nInitial Gitea deployment is running.\n' -printf 'Gitea URL: %s://%s%s\n' "$public_scheme" "$gitea_domain" "$public_port_suffix" +printf '\nInitial Git deployment is running.\n' +printf 'Git URL: %s://%s%s\n' "$public_scheme" "$gitea_domain" "$public_port_suffix" if [[ "$ssl_mode" == "none" ]]; then printf 'This is HTTP-only testing mode. Do not expose it publicly.\n' printf 'Make both hostnames resolve to this VM or its test-forwarding address.\n' fi printf '\nNext steps:\n' printf ' 1. Run ./manage.sh create-admin\n' -printf ' 2. Sign in to Gitea and create the organization, package users/tokens,\n' +printf ' 2. Sign in to Git and create the organization, package users/tokens,\n' printf ' and OAuth application documented in docs/deployment.md.\n' printf ' 3. Run ./manage.sh configure-broker\n' printf ' 4. Run ./manage.sh start\n' diff --git a/internal/app/auth.go b/internal/app/auth.go index 4ab8446..9f1e91a 100644 --- a/internal/app/auth.go +++ b/internal/app/auth.go @@ -91,13 +91,13 @@ func (s *Server) handleCallback(w http.ResponseWriter, r *http.Request) { user, err := s.exchangeOAuthCode(r.Context(), code) if err != nil { - log.Printf("Gitea OAuth code exchange failed: %v", err) - http.Error(w, "Gitea sign-in failed", http.StatusBadGateway) + log.Printf("Git OAuth code exchange failed: %v", err) + http.Error(w, "Git sign-in failed", http.StatusBadGateway) return } if _, allowed := s.cfg.AllowedGiteaUsers[strings.ToLower(user.Login)]; !allowed { _ = s.audit(r.Context(), "login_denied", user.Login, nil, "", "", s.clientIP(r), "user is not allowed") - http.Error(w, "this Gitea user is not authorized", http.StatusForbidden) + http.Error(w, "this Git user is not authorized", http.StatusForbidden) return } diff --git a/internal/app/config.go b/internal/app/config.go index 8281222..1df2135 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -139,7 +139,7 @@ func LoadConfig() (Config, error) { return cfg, fmt.Errorf("TAPM_COOKIE_SECRET must contain at least 32 bytes") } if len(cfg.AllowedGiteaUsers) == 0 { - return cfg, fmt.Errorf("at least one Gitea user must be allowed") + return cfg, fmt.Errorf("at least one Git user must be allowed") } return cfg, nil diff --git a/internal/app/static/app.css b/internal/app/static/app.css index 8d04eb4..d03dc59 100644 --- a/internal/app/static/app.css +++ b/internal/app/static/app.css @@ -247,7 +247,20 @@ dd { margin: 4px 0 0; overflow-wrap: anywhere; } .package-row { display: flex; justify-content: space-between; gap: 16px; padding: 14px 0; border-bottom: 1px solid var(--line); } .package-row div { display: grid; gap: 4px; } .package-row small { color: var(--muted); } -.package-row .status { align-items: center; justify-content: center; align-self: center; line-height: 1; text-align: center; } +.package-row .status { + align-items: center; + justify-content: center; + align-self: center; + min-width: 88px; + padding: 7px 12px; + line-height: 1; + text-align: center; +} +.package-row .status:not(.enabled) { + color: var(--danger); + border-color: rgba(181, 59, 51, .38); + background: rgba(181, 59, 51, .1); +} .package-update-actions { display: flex; flex-wrap: wrap; gap: 12px; } .toggle { display: flex; align-items: center; gap: 9px; } .empty, .fine-print { color: var(--muted); } diff --git a/internal/app/upload.go b/internal/app/upload.go index ba16d07..dd429b6 100644 --- a/internal/app/upload.go +++ b/internal/app/upload.go @@ -124,7 +124,7 @@ func (s *Server) handleUploadPackage(w http.ResponseWriter, r *http.Request) { if target.Replacing { if err := s.deletePackageVersion(r, target.PreviousName, target.PreviousVersion); err != nil { warning = fmt.Sprintf( - "Package updated, but Gitea could not remove superseded version %s: %s", + "Package updated, but Git could not remove superseded version %s: %s", target.PreviousVersion, err, ) diff --git a/manage.sh b/manage.sh index eb22159..3bd9f85 100755 --- a/manage.sh +++ b/manage.sh @@ -244,10 +244,10 @@ create-admin) require_env command -v openssl >/dev/null 2>&1 || fail "openssl is required to generate the temporary password" - printf 'Gitea administrator username [taiadmin]: ' + printf 'Git administrator username [taiadmin]: ' read -r admin_username admin_username="${admin_username:-taiadmin}" - printf 'Gitea administrator email: ' + printf 'Git administrator email: ' read -r admin_email [[ -n "$admin_email" ]] || fail "an administrator email is required" temporary_password="$(openssl rand -base64 24)" @@ -257,7 +257,7 @@ create-admin) --email "$admin_email" \ --password "$temporary_password" \ --must-change-password - printf '\nGitea administrator created.\n' + printf '\nGit administrator created.\n' printf 'Username: %s\n' "$admin_username" printf 'Temporary password: %s\n' "$temporary_password" printf 'Sign in at %s and change the password immediately.\n' \ @@ -267,12 +267,12 @@ configure-broker) require_env command -v openssl >/dev/null 2>&1 || fail "openssl is required to generate the cookie secret" - printf 'Create the Gitea OAuth application with this callback URL:\n' + printf 'Create the Git OAuth application with this callback URL:\n' printf ' %s/auth/callback\n\n' "$(read_env_setting TAPM_PUBLIC_URL)" - printf 'Gitea OAuth client ID: ' + printf 'Git OAuth client ID: ' read -r oauth_client_id [[ -n "$oauth_client_id" ]] || fail "OAuth client ID is required" - printf 'Gitea OAuth client secret: ' + printf 'Git OAuth client secret: ' read -r -s oauth_client_secret printf '\n' [[ -n "$oauth_client_secret" ]] || fail "OAuth client secret is required" @@ -290,7 +290,7 @@ configure-broker) read -r -s publisher_token printf '\n' [[ -n "$publisher_token" ]] || fail "publisher token is required" - printf 'Allowed Gitea users [taiadmin]: ' + printf 'Allowed Git users [taiadmin]: ' read -r allowed_users allowed_users="${allowed_users:-taiadmin}" cookie_secret="$(read_env_setting TAPM_COOKIE_SECRET)" diff --git a/tests/test-deployment-scripts.sh b/tests/test-deployment-scripts.sh index 968a530..fd2b97d 100755 --- a/tests/test-deployment-scripts.sh +++ b/tests/test-deployment-scripts.sh @@ -96,7 +96,7 @@ fi } if "${deployment}/manage.sh" start >/dev/null 2>&1; then - printf 'FAIL: broker started without Gitea credentials\n' >&2 + printf 'FAIL: broker started without Git credentials\n' >&2 exit 1 fi diff --git a/update.sh b/update.sh index e8f7c3a..db7d8b9 100755 --- a/update.sh +++ b/update.sh @@ -53,7 +53,7 @@ if ((post_pull == 0)); then fi fi -printf 'Updating the local Gitea image and deployment stack...\n' +printf 'Updating the local Git image and deployment stack...\n' docker compose --env-file .env pull gitea nginx "${DEPLOY_ROOT}/manage.sh" start