panel: Forgejo integration, ssh deploy key and per-app environment variables

Forgejo:
- panel.nix passes the local Forgejo's public, API and ssh URLs (derived
  from forgejo.nix) to panel-api.
- Settings dialog: connect a Forgejo access token (verified against
  /api/v1/user, stored 0600 in state/panel/forgejo-token).
- New-app dialog gets a Forgejo repository picker with search and a branch
  dropdown; private repos are cloned over https with the stored token, or
  over ssh with the deploy key when no token is connected. The app name and
  domain are filled in from the repository name.
- Commit and compare links in the Source tab point at Forgejo; cards show
  the provider ("Forgejo · main").

Git over ssh:
- ssh:// and git@host:owner/repo URLs are accepted; the panel generates an
  ed25519 deploy key in state/panel/ssh and uses it for clone/fetch
  (BatchMode, accept-new host keys). openssh added to the service path.
- Credential redaction only applies to http(s) URLs, so ssh usernames are
  kept; git errors now report the meaningful line instead of git's advice.

Environment variables:
- Stored per app in state/env/<app>.env (0600), outside the repo and stack.
- panelctl passes them to every compose command via env(1), so ${VAR}
  interpolation works; by default deploy/restart also generate a compose
  override listing the keys under every service's environment (values are
  read from compose's environment, never quoted into YAML).
- Environment tab (and a section in the new-app dialog) with .env paste
  import, hidden values, validation of names (reserved podman/compose vars
  rejected), hints for ${VAR}s the compose file uses but aren't set, and
  Save / Save & deploy. Removing an app deletes its variables.

The API still accepts the old source_type "github" / github_* fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UbWSNkXxZhYf7eqHTyx3Bf
This commit is contained in:
agent 2026-09-26 22:52:09 +00:00
parent 2d3b30d078
commit db46c5e793
5 changed files with 1258 additions and 100 deletions

View file

@ -114,13 +114,49 @@ panelctl remove whoami
### Git-backed apps
Apps created from a repository (GitHub, Forgejo/Gitea or any https git host)
are cloned to `stacks/<app>/repo`. **Sync** fetches the configured branch and
Apps created from a repository (Forgejo, GitHub or any git host, over https or
ssh) are cloned to `stacks/<app>/repo`.
**Forgejo.** `panel.nix` points the panel at the local Forgejo
(`PANEL_FORGEJO_URL`, `PANEL_FORGEJO_API_URL`, `PANEL_FORGEJO_SSH_URL`, taken
from `forgejo.nix`). In the panel's **Settings** you can connect a Forgejo
access token (read access to repositories and user). With it, the new-app
dialog lists your repositories and branches, and private ones are cloned over
https with the token. Without it, public repositories are listed and private
ones are cloned over ssh with the deploy key. Commit and compare links point at
Forgejo. The token is stored in `state/panel/forgejo-token` (mode 0600).
**SSH / deploy key.** The panel generates an ed25519 key pair in
`state/panel/ssh/` the first time it is needed. Its public half is shown in
Settings (and next to ssh URLs); add it as a read-only deploy key to a
repository — or to your Forgejo account for access to all repositories — to
clone `ssh://git@git.srazka.com:14922/owner/repo.git` style URLs. **Sync** fetches the configured branch and
hard-resets the checkout to it before redeploying, so the repository is the
source of truth: compose edits made in the panel are discarded on the next sync
(the UI warns about this). An access token for a private repository is stored in
the clone's `.git/config`; use a read-only token.
### Environment variables
Each app can have environment variables (the **Environment** tab, or when
creating the app; `.env` text can be pasted in). They are stored in
`state/env/<app>.env` as `KEY=VALUE` lines (mode 0600) — outside the repository
and stack directory, so git syncs never touch them — and `panelctl` passes them
to every compose command:
- They are always available for `${VAR}` interpolation in the compose file.
The UI points out variables the compose file uses without a default that
aren't set.
- With **Pass to every container** (the default), `deploy`/`restart` also
generate `stacks/<app>/.panel-env.yaml`, a compose override that lists the
keys under every service's `environment:`. Compose reads the values from its
own environment, so they are never quoted into YAML, and they take
precedence over values set in the compose file.
Values must be single-line. Names that would change how podman/compose run
(`PATH`, `HOME`, `XDG_*`, `DOCKER_*`, `COMPOSE_*`, `PODMAN_*`, …) are rejected.
Changes apply on the next deploy. Backups do not include variables.
### Concurrency
`panel-api` handles requests concurrently, so a long deploy never blocks status