diff options
| author | Maxim Cournoyer <maxim@guixotic.coop> | 2026-06-01 15:46:21 +0900 |
|---|---|---|
| committer | Maxim Cournoyer <maxim@guixotic.coop> | 2026-06-01 15:46:21 +0900 |
| commit | adbee8d605d2e7c4b6ea1fd3d0c8b4e878289c75 (patch) | |
| tree | b467fd434cd11d4fb631d551df9ccc1f151a6dbc /gnu/services | |
| parent | e8ac9c3c3aee52866c8c48dc0aacccb27fc88d5a (diff) | |
Revert "services: Add forgejo-service-type."
This reverts commit e8ac9c3c3aee52866c8c48dc0aacccb27fc88d5a, pushed by mistake.
Diffstat (limited to 'gnu/services')
| -rw-r--r-- | gnu/services/forgejo.scm | 913 |
1 files changed, 0 insertions, 913 deletions
diff --git a/gnu/services/forgejo.scm b/gnu/services/forgejo.scm deleted file mode 100644 index 86db26775d2..00000000000 --- a/gnu/services/forgejo.scm +++ /dev/null | |||
| @@ -1,913 +0,0 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2026 Maxim Cournoyer <maxim@guixotic.coop> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (gnu services forgejo) | ||
| 20 | #:use-module (guix gexp) | ||
| 21 | #:use-module (guix least-authority) | ||
| 22 | #:use-module (guix records) | ||
| 23 | #:use-module (gnu build linux-container) | ||
| 24 | #:use-module (gnu packages forgejo) | ||
| 25 | #:use-module (gnu services) | ||
| 26 | #:use-module (gnu services shepherd) | ||
| 27 | #:use-module (gnu services configuration) | ||
| 28 | #:use-module (gnu system file-systems) | ||
| 29 | #:use-module (gnu system shadow) | ||
| 30 | #:use-module (ice-9 match) | ||
| 31 | #:use-module (srfi srfi-1) | ||
| 32 | #:export (forgejo-service-type | ||
| 33 | forgejo-configuration | ||
| 34 | forgejo-configuration-forgejo | ||
| 35 | forgejo-configuration-application-name | ||
| 36 | forgejo-configuration-application-slogan | ||
| 37 | forgejo-configuration-run-mode | ||
| 38 | forgejo-configuration-configuration-wizard? | ||
| 39 | forgejo-configuration-domain | ||
| 40 | forgejo-configuration-port | ||
| 41 | forgejo-configuration-protocol | ||
| 42 | forgejo-configuration-root-url | ||
| 43 | forgejo-configuration-http-address | ||
| 44 | forgejo-configuration-acme? | ||
| 45 | forgejo-configuration-tls-cert-file | ||
| 46 | forgejo-configuration-tls-key-file | ||
| 47 | forgejo-configuration-ssh-address | ||
| 48 | forgejo-configuration-ssh-port | ||
| 49 | forgejo-configuration-actions? | ||
| 50 | forgejo-configuration-default-actions-url | ||
| 51 | forgejo-configuration-disable-registration? | ||
| 52 | forgejo-configuration-confirm-mail-on-registration? | ||
| 53 | forgejo-configuration-internal-token-file | ||
| 54 | forgejo-configuration-secret-key-file | ||
| 55 | forgejo-configuration-lfs? | ||
| 56 | forgejo-configuration-lfs-secret-file | ||
| 57 | forgejo-configuration-log-level | ||
| 58 | forgejo-configuration-oauth2-secret-file | ||
| 59 | forgejo-configuration-mail-notification? | ||
| 60 | forgejo-configuration-mail-notification-on-new-user-signin? | ||
| 61 | forgejo-configuration-mailer? | ||
| 62 | forgejo-configuration-mail-subject-prefix | ||
| 63 | forgejo-configuration-mail-protocol | ||
| 64 | forgejo-configuration-smtp-address | ||
| 65 | forgejo-configuration-smtp-port | ||
| 66 | forgejo-configuration-smtp-user | ||
| 67 | forgejo-configuration-smtp-password-file | ||
| 68 | forgejo-configuration-mail-plain-text? | ||
| 69 | forgejo-configuration-mail-from | ||
| 70 | forgejo-configuration-sendmail-command | ||
| 71 | forgejo-configuration-sendmail-options | ||
| 72 | forgejo-configuration-sendmail-timeout | ||
| 73 | forgejo-configuration-sendmail-convert-crlf? | ||
| 74 | forgejo-configuration-openid-signin? | ||
| 75 | forgejo-configuration-metrics? | ||
| 76 | forgejo-configuration-metrics-token | ||
| 77 | forgejo-configuration-database-type | ||
| 78 | forgejo-configuration-database-host | ||
| 79 | forgejo-configuration-database-name | ||
| 80 | forgejo-configuration-database-user | ||
| 81 | forgejo-configuration-database-password-file | ||
| 82 | forgejo-configuration-database-tls? | ||
| 83 | forgejo-configuration-user-push-to-create? | ||
| 84 | forgejo-configuration-organization-push-to-create? | ||
| 85 | forgejo-configuration-default-push-to-create-private? | ||
| 86 | forgejo-configuration-require-signin-to-view? | ||
| 87 | forgejo-configuration-default-merge-style | ||
| 88 | forgejo-configuration-default-trust-model | ||
| 89 | forgejo-configuration-default-keep-email-private? | ||
| 90 | forgejo-configuration-offline-mode? | ||
| 91 | forgejo-configuration-user | ||
| 92 | forgejo-configuration-group | ||
| 93 | forgejo-configuration-custom-configuration-file | ||
| 94 | forgejo-configuration-shepherd-provision | ||
| 95 | forgejo-configuration-work-directory)) | ||
| 96 | |||
| 97 | ;;; Copied from (gnu services base) | ||
| 98 | (define (ipv6-address? str) | ||
| 99 | "Return true if STR denotes an IPv6 address." | ||
| 100 | (false-if-exception (->bool (inet-pton AF_INET6 str)))) | ||
| 101 | |||
| 102 | (define (database-type? x) | ||
| 103 | (member x '("sqlite3" "mysql" "postgres"))) | ||
| 104 | |||
| 105 | (define (port? x) | ||
| 106 | (and (number? x) | ||
| 107 | (and (>= x 1) (<= x 65535)))) | ||
| 108 | |||
| 109 | (define (privileged-port? x) | ||
| 110 | (and (number? x) | ||
| 111 | (and (>= x 1) (<= x 1023)))) | ||
| 112 | |||
| 113 | (define (unprivileged-port? x) | ||
| 114 | (and (number? x) | ||
| 115 | (and (>= x 1024) (<= x 65535)))) | ||
| 116 | |||
| 117 | (define (port-or-false? x) | ||
| 118 | (or (not x) | ||
| 119 | (port? x))) | ||
| 120 | |||
| 121 | (define (log-level? x) | ||
| 122 | (member x '("trace" "debug" "info" "warn" "error" "none"))) | ||
| 123 | |||
| 124 | (define (merge-style? x) | ||
| 125 | (member x '("merge" "rebase" "rebase-merge" "squash" "fast-forward-only"))) | ||
| 126 | |||
| 127 | (define (protocol? x) | ||
| 128 | (member x '("http" "https" "fcgi" "http+unix" "fcgi+unix"))) | ||
| 129 | |||
| 130 | (define (run-mode? x) | ||
| 131 | (member x '("dev" "prod"))) | ||
| 132 | |||
| 133 | (define (trust-model? x) | ||
| 134 | (member x '("collaborator" "committer" "collaboratorcommitter"))) | ||
| 135 | |||
| 136 | (define (ssl-mode? x) | ||
| 137 | (member x '(#t #f 'skip-verify))) | ||
| 138 | |||
| 139 | (define (serialize-database-tls type value) | ||
| 140 | (match type | ||
| 141 | ("sqlite3" "disable") ;does not apply | ||
| 142 | ("mysql" (match value | ||
| 143 | (#t "true") | ||
| 144 | (#f "false") | ||
| 145 | ('skip-verify "skip-verify"))) | ||
| 146 | ("postgres" (match value | ||
| 147 | (#t "verify-full") | ||
| 148 | (#f "disable") | ||
| 149 | ('skip-verify "require"))))) | ||
| 150 | |||
| 151 | (define-maybe file-like) | ||
| 152 | |||
| 153 | (define-maybe/no-serialization string) | ||
| 154 | |||
| 155 | (define (mail-protocol? x) | ||
| 156 | (member x '("" "dummy" "sendmail" | ||
| 157 | "smtp" "smtps" "smtp+starttls" "smtp+unix"))) | ||
| 158 | |||
| 159 | (define-configuration/no-serialization forgejo-configuration | ||
| 160 | (forgejo | ||
| 161 | (file-like forgejo) | ||
| 162 | "The forgejo package.") | ||
| 163 | |||
| 164 | (work-directory | ||
| 165 | (string "/var/lib/forgejo") | ||
| 166 | "The directory where Forgejo keeps its state, including its database when | ||
| 167 | using @code{\"sqlite3\"} as the @code{database-type}.") | ||
| 168 | |||
| 169 | (shepherd-provision | ||
| 170 | (list-of-symbols '(forgejo)) | ||
| 171 | "The name(s) of the service.") | ||
| 172 | |||
| 173 | (configuration-wizard? | ||
| 174 | (boolean #f) | ||
| 175 | "Whether to use the initial configuration page (wizard) to setup Forgejo. | ||
| 176 | Setting this to @code{#t} means that none of the declarative configuration | ||
| 177 | values will be honored. The Forgejo-generated configuration file will be kept | ||
| 178 | under @file{custom/conf/app.ini}, relative to the value of the | ||
| 179 | @code{work-directory}.") | ||
| 180 | |||
| 181 | (user | ||
| 182 | (string "forgejo") | ||
| 183 | "The name of the user under which Forgejo will be executed.") | ||
| 184 | |||
| 185 | (group | ||
| 186 | (string "forgejo") | ||
| 187 | "The name of the group under which Forgejo will be executed.") | ||
| 188 | |||
| 189 | (custom-configuration-file | ||
| 190 | maybe-file-like | ||
| 191 | "File-like object to provide a complete Forgejo configuration file as an | ||
| 192 | escape hatch, overriding every other fields of this configuration.") | ||
| 193 | |||
| 194 | ;; Global settings (no section). | ||
| 195 | (application-name | ||
| 196 | (string "Forgejo") | ||
| 197 | "The application name that shows in every page title.") | ||
| 198 | |||
| 199 | (application-slogan | ||
| 200 | (string "") | ||
| 201 | "Slogan to show near the application name in every page title.") | ||
| 202 | |||
| 203 | (run-mode | ||
| 204 | (run-mode "prod") | ||
| 205 | "The run mode to use; either @code{\"dev\"} or @code{\"prod\"}.") | ||
| 206 | |||
| 207 | ;; [server] settings. | ||
| 208 | (domain | ||
| 209 | (string "localhost") | ||
| 210 | "The domain name or host address of the server.") | ||
| 211 | |||
| 212 | (offline-mode? | ||
| 213 | (boolean #f) | ||
| 214 | "Set to @code{#t} to run Forgejo in offline mode, meaning it won't reach | ||
| 215 | out to any external services such as Gravatar, CDNs, etc. and serve everything | ||
| 216 | locally instead.") | ||
| 217 | |||
| 218 | (port | ||
| 219 | (unprivileged-port 3000) | ||
| 220 | "The port Forgejo will listen on. The port should be an unprivileged port; | ||
| 221 | to serve Forgejo on a privileged port like @code{80}, configure a reverse | ||
| 222 | proxy. It is ignored when using a Unix-domain socket.") | ||
| 223 | |||
| 224 | (protocol | ||
| 225 | (protocol "http") | ||
| 226 | "Listen protocol. Either @code{http}, @code{https}, @code{fcgi}, | ||
| 227 | @code{\"http+unix\"} or @code{\"fcgi+unix\"}. @samp{+unix} means @emph{via} a | ||
| 228 | Unix-domain socket, in which case @code{http-address} must be the file name of | ||
| 229 | the socket to use.") | ||
| 230 | |||
| 231 | (root-url | ||
| 232 | maybe-string | ||
| 233 | "Overwrite the automatically generated public URL, | ||
| 234 | which implicitly defaults to @samp{@var{protocol}://@var{domain}:@var{port}}, | ||
| 235 | which is necessary using a reverse proxy.") | ||
| 236 | |||
| 237 | (http-address | ||
| 238 | (string "0.0.0.0") | ||
| 239 | "The address to listen to. It can be an absolute file name when using a | ||
| 240 | Unix-domain socket, for example @file{/run/forgejo.sock}, or a file name | ||
| 241 | relative to the @code{work-directory}, for example @file{forgejo.sock}.") | ||
| 242 | |||
| 243 | (ssh-address | ||
| 244 | (string "0.0.0.0") | ||
| 245 | "The IP address to listen on for the SSH server.") | ||
| 246 | |||
| 247 | (lfs? | ||
| 248 | (boolean #t) | ||
| 249 | "Whether to enable Git LFS support.") | ||
| 250 | |||
| 251 | (lfs-secret-file | ||
| 252 | (string "/etc/forgejo/lfs_jwt_secret") | ||
| 253 | "The file name of the LFS JWT (JSON Web Token) secret, necessary for | ||
| 254 | proper Git LFS operation, which can be generated with @samp{forgejo generate | ||
| 255 | secret JWT_SECRET}. Automatically generated the first time Forgejo runs if it | ||
| 256 | does not yet exist.") | ||
| 257 | |||
| 258 | (mail-notification? | ||
| 259 | (boolean #f) | ||
| 260 | "Whether to enable email notifications.") | ||
| 261 | |||
| 262 | (acme? | ||
| 263 | (boolean #f) | ||
| 264 | "Whether to enable @acronym{ACME, Automatic Certificate Management | ||
| 265 | Environment}, to automatically provision TLS certificates, which can be useful | ||
| 266 | if you use the @code{https} or @code{https+unix} protocols.") | ||
| 267 | |||
| 268 | (tls-cert-file | ||
| 269 | (string "https/cert.pem") | ||
| 270 | "File name of a TLS certificate file. Ignored if @code{acme?} is enabled. | ||
| 271 | A relative file name is located under @file{@var{work-directory}/custom}.") | ||
| 272 | |||
| 273 | (tls-key-file | ||
| 274 | (string "https/key.pem") | ||
| 275 | "File name of a TLS key. Ignored if @code{acme?} is enabled. A relative | ||
| 276 | file name is located under @file{@var{work-directory}/custom}.") | ||
| 277 | |||
| 278 | (ssh-port | ||
| 279 | (port-or-false 22) | ||
| 280 | "The SSH port Forgejo will use; if you already run an OpenSSH as the SSH | ||
| 281 | server, specify the port used by the SSH daemon. Otherwise, you need to use | ||
| 282 | an unprivileged port (greater or equal to 1024) which Forgejo will use with | ||
| 283 | its built-in SSH server. Set to @code{#f} to disable SSH support.") | ||
| 284 | |||
| 285 | ;; [actions] settings. | ||
| 286 | (actions? | ||
| 287 | (boolean #t) | ||
| 288 | "Whether to enable actions capabilities.") | ||
| 289 | |||
| 290 | (default-actions-url | ||
| 291 | (string "https://code.forgejo.org") | ||
| 292 | "The default address to fetch action plugins from.") | ||
| 293 | |||
| 294 | ;; [security] settings. | ||
| 295 | (internal-token-file | ||
| 296 | (string "/etc/forgejo/internal_token") | ||
| 297 | "The file name of the internal token used to validate communication within | ||
| 298 | Forgejo, which can be generated with @samp{forgejo generate | ||
| 299 | secret INTERNAL_TOKEN}") | ||
| 300 | |||
| 301 | (secret-key-file | ||
| 302 | (string "/etc/forgejo/secret_key") | ||
| 303 | "The file name containing the global secret key used for encrypting data | ||
| 304 | like 2FA secrets; it is thus very important to back it up somewhere safe to | ||
| 305 | avoid losing access to encrypted data.") | ||
| 306 | |||
| 307 | ;; [oauth2] settings. | ||
| 308 | (oauth2-jwt-secret-file | ||
| 309 | (string "/etc/forgejo/oauth2_jwt_secret") | ||
| 310 | "The file name of the OAuth2 JWT secret, which Forgejo expects to exist.") | ||
| 311 | |||
| 312 | ;; [admin] settings. | ||
| 313 | (mail-notification-on-new-user-signin? | ||
| 314 | (boolean #f) | ||
| 315 | "Whether to notify administrators by email when a new user signs in for the | ||
| 316 | first time.") | ||
| 317 | |||
| 318 | ;; [mailer] settings. | ||
| 319 | (mailer? | ||
| 320 | (boolean #f) | ||
| 321 | "Whether to enable the mail server integration, used for sending email | ||
| 322 | notifications for example.") | ||
| 323 | |||
| 324 | (mail-from | ||
| 325 | (string "") | ||
| 326 | "The FROM email address used for sent emails, per the RFC 5322 | ||
| 327 | specification. This can be for example just an email address, or something | ||
| 328 | like @samp{\"Name\" <email@@example.com>}. This field @emph{must} be specified | ||
| 329 | if @code{mailer?} is set to @code{#t}.") | ||
| 330 | |||
| 331 | (mail-subject-prefix | ||
| 332 | (string "") | ||
| 333 | "The prefix displayed before the subject in emails.") | ||
| 334 | |||
| 335 | (mail-protocol | ||
| 336 | (mail-protocol "") | ||
| 337 | "The mail server protocol. One of @code{\"smtp\"}, @code{\"smtps\"}, | ||
| 338 | @code{\"smtp+starttls\"}, @code{\"smtp+unix\"}, @code{\"sendmail\"}, | ||
| 339 | @code{\"dummy\"} or @code{\"\"}. The empty string defaults means the protocol | ||
| 340 | is inferred from the value of the @code{smtp-port} value, meaning its | ||
| 341 | effective implicit value is @code{\"smtps\"}. @code{\"dummy\"} causes emails | ||
| 342 | to be sent to the log, useful for testing. When @code{\"sendmail\"} is used, | ||
| 343 | it is expected to be fully and correctly externally configured, with the other | ||
| 344 | @samp{smtp-} prefixed options of this configuration ignored.") | ||
| 345 | |||
| 346 | (smtp-address | ||
| 347 | (string "") | ||
| 348 | "The mail server address, for example @code{\"smtp.example.com\"} or an | ||
| 349 | absolute file name, if using @code{\"smtp+unix\"} for the | ||
| 350 | @code{mail-protocol}.") | ||
| 351 | |||
| 352 | (smtp-port | ||
| 353 | (port 465) ;implies smtps protocol | ||
| 354 | "The mail server port. This field affects the implicit value of the | ||
| 355 | @code{mail-protocol}.") | ||
| 356 | |||
| 357 | (smtp-user | ||
| 358 | (string "") | ||
| 359 | "The SMTP server user name, if required ") | ||
| 360 | |||
| 361 | (smtp-password-file | ||
| 362 | (string "") | ||
| 363 | "An absolute file name containing the password of the SMTP server.") | ||
| 364 | |||
| 365 | (mail-plain-text? | ||
| 366 | (boolean #f) | ||
| 367 | "Send emails only in plain text, without HTML alternative.") | ||
| 368 | |||
| 369 | (sendmail-command | ||
| 370 | (string "sendmail") | ||
| 371 | "The file name of the @command{sendmail} command to use, which can be | ||
| 372 | either an absolute file name or a command name to be looked from | ||
| 373 | @env{\"PATH\"}.") | ||
| 374 | |||
| 375 | (sendmail-options | ||
| 376 | (list-of-strings '()) | ||
| 377 | "Optional options to pass to the @command{sendmail} command. If your | ||
| 378 | @code{sendmail} program, like that of Postfix, interprets options, you should | ||
| 379 | provide @code{\"--\"} as the first option.") | ||
| 380 | |||
| 381 | (sendmail-timeout | ||
| 382 | (string "5m") | ||
| 383 | "The timeout for Sendmail, provided as a | ||
| 384 | @url{https://pkg.go.dev/time#ParseDuration, Go @code{time.Duration} string}, | ||
| 385 | for example @code{\"300ms\"}, @code{\"1.5h\"} or @code{\"2h45m\"}.") | ||
| 386 | |||
| 387 | (sendmail-convert-crlf? | ||
| 388 | (boolean #t) | ||
| 389 | "Whether to convert @samp{\\r\\n} to @samp{\\n} for Sendmail.") | ||
| 390 | |||
| 391 | ;; [log] settings. | ||
| 392 | (log-level | ||
| 393 | (log-level "info") | ||
| 394 | "The log level to use. Either @code{\"trace\"}, @code{\"debug\"}, | ||
| 395 | @code{\"info\"}, @code{\"warn\"}, @code{\"error\"} or @code{\"none\"}.") | ||
| 396 | |||
| 397 | ;; [openid] settings. | ||
| 398 | (openid-signin? | ||
| 399 | (boolean #t) | ||
| 400 | "Whether to allow signing in using OpenID.") | ||
| 401 | |||
| 402 | ;; [service] settings. | ||
| 403 | (disable-registration? | ||
| 404 | (boolean #f) | ||
| 405 | "Disallow registration, only allowing administrators to create accounts.") | ||
| 406 | |||
| 407 | (confirm-mail-on-registration? | ||
| 408 | (boolean #f) | ||
| 409 | "Whether to require email confirmation when new users register.") | ||
| 410 | |||
| 411 | (require-signin-to-view? | ||
| 412 | (boolean #f) | ||
| 413 | "Whether users must sign in before they can view the explore pages.") | ||
| 414 | |||
| 415 | (default-keep-email-private? | ||
| 416 | (boolean #f) | ||
| 417 | "Whether by default a user email is displayed on their profile.") | ||
| 418 | |||
| 419 | (user-push-to-create? | ||
| 420 | (boolean #f) | ||
| 421 | "Allow users to push local repositories to Forgejo and have them | ||
| 422 | automatically created for a user.") | ||
| 423 | |||
| 424 | (organization-push-to-create? | ||
| 425 | (boolean #f) | ||
| 426 | "Allow users to push local repositories to Forgejo and have them | ||
| 427 | automatically created for an organization.") | ||
| 428 | |||
| 429 | (default-push-to-create-private? | ||
| 430 | (boolean #t) | ||
| 431 | "Whether to make newly created repositories private by default when they | ||
| 432 | were created via push.") | ||
| 433 | |||
| 434 | ;; [repository.pull-request] settings. | ||
| 435 | (default-merge-style | ||
| 436 | (merge-style "merge") | ||
| 437 | "The default merge style to use. Either @code{\"merge\"}, | ||
| 438 | @code{\"rebase\"}, @code{\"rebase-merge\"}, @code{\"squash\"} or | ||
| 439 | @code{\"fast-forward-only\"}.") | ||
| 440 | |||
| 441 | ;; [repository.signing] settings. | ||
| 442 | (default-trust-model | ||
| 443 | (trust-model "committer") | ||
| 444 | "The default trust model for repositories. Either | ||
| 445 | @code{\"collaborator\"}, @code{\"committer\"} or | ||
| 446 | @code{\"collaboratorcommitter\"}") | ||
| 447 | |||
| 448 | ;; [metrics] settings. | ||
| 449 | (metrics? | ||
| 450 | (boolean #f) | ||
| 451 | "Whether to enable the metrics endpoint.") | ||
| 452 | |||
| 453 | (metrics-token | ||
| 454 | (string "") | ||
| 455 | "A secret to use, if authorization to the metrics endpoint is desired.") | ||
| 456 | |||
| 457 | ;; [database] settings. | ||
| 458 | (database-type | ||
| 459 | (database-type "sqlite3") | ||
| 460 | "The database type to use. Either @code{\"sqlite3\"}, @code{\"mysql\"} or | ||
| 461 | @code{\"postgres\"}. The sqlite3 type is the simplest to use, but a | ||
| 462 | full-fledged database like PostgreSQL may scale better for multiple users. If | ||
| 463 | you change this, make sure to adjust the other @samp{database-*} values | ||
| 464 | accordingly. Also note that currently, the PostgreSQL and MySQL databases | ||
| 465 | must be manually created: refer to the official Forgejo documentation for | ||
| 466 | @url{https://forgejo.org/docs/latest/admin/installation/database-preparation, | ||
| 467 | database preparation}.") | ||
| 468 | |||
| 469 | (database-host | ||
| 470 | (string "/var/run/postgresql") | ||
| 471 | "This is the @samp{@var{host}:@var{port}} tuple for remote database | ||
| 472 | MySQL/PostgreSQL hosts, or a local Unix-domain socket file. If using MySQL, | ||
| 473 | this should be adjusted to @file{/run/mysqld/mysqld.sock}") | ||
| 474 | |||
| 475 | (database-name | ||
| 476 | ;; Keep the default database name in sync with the database user name, so | ||
| 477 | ;; that it can be easily provisioned via a the | ||
| 478 | ;; postgresql-role-service-type, which assumes both match. | ||
| 479 | (string "forgejo") | ||
| 480 | "The MySQL/PostgreSQL database name to use.") | ||
| 481 | |||
| 482 | (database-user | ||
| 483 | (string "forgejo") | ||
| 484 | "The MySQL/PostgreSQL database user to use.") | ||
| 485 | |||
| 486 | (database-password-file | ||
| 487 | maybe-string | ||
| 488 | "A file name containing the password to access the MySQL/PostgreSQL | ||
| 489 | database, for example @file{\"/etc/forgejo/db_passwd\"}.") | ||
| 490 | |||
| 491 | (database-tls? | ||
| 492 | (ssl-mode #f) | ||
| 493 | "Whether the connection to a MySQL/PostgreSQL database should use TLS. Set | ||
| 494 | to @code{#t} to enable TLS with full verification or to @code{'skip-verify} to | ||
| 495 | enable TLS without verification.")) | ||
| 496 | |||
| 497 | ;;; TODO: Allow enabling/configuring email integration | ||
| 498 | ;;; See custom/conf/app.example.ini for a documentation of the fields. | ||
| 499 | (define forgejo-configuration->file | ||
| 500 | (match-record-lambda <forgejo-configuration> | ||
| 501 | ( application-name application-slogan work-directory | ||
| 502 | run-mode domain protocol http-address port root-url | ||
| 503 | acme? tls-cert-file tls-key-file | ||
| 504 | ssh-address ssh-port | ||
| 505 | default-keep-email-private? | ||
| 506 | default-merge-style default-trust-model | ||
| 507 | actions? default-actions-url | ||
| 508 | disable-registration? confirm-mail-on-registration? | ||
| 509 | require-signin-to-view? mail-notification? | ||
| 510 | internal-token-file secret-key-file | ||
| 511 | lfs? lfs-secret-file oauth2-jwt-secret-file | ||
| 512 | mail-notification-on-new-user-signin? | ||
| 513 | mailer? mail-subject-prefix mail-protocol | ||
| 514 | smtp-address smtp-port smtp-user smtp-password-file | ||
| 515 | mail-plain-text? mail-from | ||
| 516 | sendmail-command sendmail-options sendmail-timeout | ||
| 517 | sendmail-convert-crlf? | ||
| 518 | log-level offline-mode? openid-signin? | ||
| 519 | metrics? metrics-token | ||
| 520 | user-push-to-create? organization-push-to-create? | ||
| 521 | default-push-to-create-private? | ||
| 522 | user group | ||
| 523 | custom-configuration-file | ||
| 524 | database-type database-host database-name database-user | ||
| 525 | database-password-file database-tls?) | ||
| 526 | (if (maybe-value-set? custom-configuration-file) | ||
| 527 | custom-configuration-file | ||
| 528 | (mixed-text-file "forgejo.ini" " | ||
| 529 | APP_NAME = " application-name " | ||
| 530 | APP_SLOGAN = " application-slogan " | ||
| 531 | RUN_USER = " user " | ||
| 532 | WORK_PATH = " work-directory " | ||
| 533 | RUN_MODE = " run-mode " | ||
| 534 | |||
| 535 | [database] | ||
| 536 | DB_TYPE = " database-type " | ||
| 537 | HOST = " database-host " | ||
| 538 | NAME = " database-name " | ||
| 539 | USER = " database-user "\n" | ||
| 540 | (if (maybe-value-set? database-password-file) | ||
| 541 | (string-append "PASSWD_URI = file://" database-password-file "\n") | ||
| 542 | "") | ||
| 543 | "SSL_MODE = " (serialize-database-tls database-type database-tls?) " | ||
| 544 | |||
| 545 | [repository] | ||
| 546 | ROOT = " work-directory "/data/forgejo-repositories | ||
| 547 | DEFAULT_PUSH_CREATE_PRIVATE = " | ||
| 548 | (if default-push-to-create-private? "true" "false") " | ||
| 549 | ENABLE_PUSH_CREATE_USER = " (if user-push-to-create? "true" "false") " | ||
| 550 | ENABLE_PUSH_CREATE_ORG = " (if organization-push-to-create? "true" "false") " | ||
| 551 | |||
| 552 | [server] | ||
| 553 | SSH_DOMAIN = " domain " | ||
| 554 | SSH_LISTEN_HOST = " ssh-address " | ||
| 555 | PROTOCOL = " protocol " | ||
| 556 | DOMAIN = " domain " | ||
| 557 | HTTP_ADDR = " http-address " | ||
| 558 | HTTP_PORT = " (number->string port) "\n" | ||
| 559 | (if (maybe-value-set? root-url) | ||
| 560 | (string-append "ROOT_URL = " root-url "\n") | ||
| 561 | "") | ||
| 562 | "ENABLE_ACME = " (if acme? "true" "false") " | ||
| 563 | CERT_FILE = " tls-cert-file " | ||
| 564 | KEY_FILE = " tls-key-file " | ||
| 565 | APP_DATA_PATH = " work-directory "/data | ||
| 566 | DISABLE_SSH = " (if (not ssh-port) "true" "false") " | ||
| 567 | SSH_PORT = " (if (not ssh-port) "" (number->string ssh-port)) " | ||
| 568 | LFS_START_SERVER = " (if lfs? "true" "false") " | ||
| 569 | LFS_JWT_SECRET_URI = file://" lfs-secret-file " | ||
| 570 | OFFLINE_MODE = " (if offline-mode? "true" "false") " | ||
| 571 | |||
| 572 | [lfs] | ||
| 573 | PATH = " work-directory "/data/lfs | ||
| 574 | |||
| 575 | [service] | ||
| 576 | REGISTER_EMAIL_CONFIRM = false | ||
| 577 | ENABLE_NOTIFY_MAIL = " (if mail-notification? "true" "false") " | ||
| 578 | DISABLE_REGISTRATION = " (if disable-registration? "true" "false") " | ||
| 579 | REGISTER_EMAIL_CONFIRM = " (if confirm-mail-on-registration? "true" "false") " | ||
| 580 | ENABLE_CAPTCHA = false | ||
| 581 | REQUIRE_SIGNIN_VIEW = " (if require-signin-to-view? "true" "false") " | ||
| 582 | DEFAULT_KEEP_EMAIL_PRIVATE = " (if default-keep-email-private? "true" "false") " | ||
| 583 | |||
| 584 | [openid] | ||
| 585 | ENABLE_OPENID_SIGNIN = " (if openid-signin? "true" "false") " | ||
| 586 | |||
| 587 | [cron.update_checker] | ||
| 588 | ENABLED = false | ||
| 589 | |||
| 590 | [log] | ||
| 591 | LEVEL = " log-level " | ||
| 592 | ROOT_PATH = " work-directory "/log | ||
| 593 | |||
| 594 | [repository.pull-request] | ||
| 595 | DEFAULT_MERGE_STYLE = " default-merge-style " | ||
| 596 | |||
| 597 | [repository.signing] | ||
| 598 | DEFAULT_TRUST_MODEL = " default-trust-model " | ||
| 599 | |||
| 600 | [security] | ||
| 601 | INSTALL_LOCK = true | ||
| 602 | SECRET_KEY = file://" secret-key-file " | ||
| 603 | INTERNAL_TOKEN_URI = file://" internal-token-file " | ||
| 604 | |||
| 605 | [oauth2] | ||
| 606 | JWT_SECRET_URI = file://" oauth2-jwt-secret-file " | ||
| 607 | |||
| 608 | [admin] | ||
| 609 | SEND_NOTIFICATION_EMAIL_ON_NEW_USER = " | ||
| 610 | (if mail-notification-on-new-user-signin? "true" "false") " | ||
| 611 | |||
| 612 | [mailer] | ||
| 613 | ENABLED = " (if mailer? "true" "false") " | ||
| 614 | SUBJECT_PREFIX = " mail-subject-prefix " | ||
| 615 | PROTOCOL = " mail-protocol " | ||
| 616 | SMTP_ADDR = " smtp-address " | ||
| 617 | SMTP_PORT = " (number->string smtp-port) " | ||
| 618 | USER = " smtp-user " | ||
| 619 | PASSWD_URI = " (if (string-null? smtp-password-file) | ||
| 620 | "" | ||
| 621 | (string-append "file://" smtp-password-file)) " | ||
| 622 | SEND_AS_PLAIN_TEXT = " (if mail-plain-text? "true" "false") " | ||
| 623 | FROM = " mail-from " | ||
| 624 | SENDMAIL_PATH = " sendmail-command " | ||
| 625 | SENDMAIL_ARGS = " (string-join sendmail-options " ") " | ||
| 626 | SENDMAIL_TIMEOUT = " sendmail-timeout " | ||
| 627 | SENDMAIL_CONVERT_CRLF = " (if sendmail-convert-crlf? "true" "false") " | ||
| 628 | |||
| 629 | [metrics] | ||
| 630 | ENABLED = " (if metrics? "true" "false") " | ||
| 631 | TOKEN = " metrics-token " | ||
| 632 | |||
| 633 | [actions] | ||
| 634 | ENABLED = " (if actions? "true" "false") " | ||
| 635 | DEFAULT_ACTIONS_URL = " default-actions-url " | ||
| 636 | ")))) | ||
| 637 | |||
| 638 | (define (forgejo-shepherd-service config) | ||
| 639 | (match-record config <forgejo-configuration> | ||
| 640 | ( forgejo work-directory user group port | ||
| 641 | http-address protocol ssh-port | ||
| 642 | database-type database-host | ||
| 643 | configuration-wizard? | ||
| 644 | internal-token-file lfs-secret-file | ||
| 645 | smtp-password-file | ||
| 646 | tls-cert-file tls-key-file | ||
| 647 | oauth2-jwt-secret-file secret-key-file | ||
| 648 | shepherd-provision) | ||
| 649 | (let* ((mappings (append | ||
| 650 | %network-file-mappings | ||
| 651 | (list %store-mapping ;XXX: coarse-grained | ||
| 652 | (file-system-mapping | ||
| 653 | (source "/etc/ssl/certs") | ||
| 654 | (target source)) | ||
| 655 | (file-system-mapping | ||
| 656 | (source work-directory) | ||
| 657 | (target source) | ||
| 658 | (writable? #t)) | ||
| 659 | (file-system-mapping | ||
| 660 | (source internal-token-file) | ||
| 661 | (target source)) | ||
| 662 | (file-system-mapping | ||
| 663 | (source lfs-secret-file) | ||
| 664 | (target source)) | ||
| 665 | (file-system-mapping | ||
| 666 | (source oauth2-jwt-secret-file) | ||
| 667 | (target source)) | ||
| 668 | (file-system-mapping | ||
| 669 | (source secret-key-file) | ||
| 670 | (target source))) | ||
| 671 | (if (absolute-file-name? smtp-password-file) | ||
| 672 | (list (file-system-mapping | ||
| 673 | (source smtp-password-file) | ||
| 674 | (target source))) | ||
| 675 | '()) | ||
| 676 | (if (absolute-file-name? tls-cert-file) | ||
| 677 | (list (file-system-mapping | ||
| 678 | (source tls-cert-file) | ||
| 679 | (target source))) | ||
| 680 | '()) | ||
| 681 | (if (absolute-file-name? tls-key-file) | ||
| 682 | (list (file-system-mapping | ||
| 683 | (source tls-key-file) | ||
| 684 | (target source))) | ||
| 685 | '()) | ||
| 686 | (if (and (not (string=? "sqlite3" database-type)) | ||
| 687 | (absolute-file-name? database-host)) ;socket | ||
| 688 | (list (file-system-mapping | ||
| 689 | (source database-host) | ||
| 690 | (target source) | ||
| 691 | (writable? #t))) | ||
| 692 | '()))) | ||
| 693 | (forgejo (file-append forgejo "/bin/forgejo")) | ||
| 694 | (forgejo-wrapper (least-authority-wrapper | ||
| 695 | forgejo | ||
| 696 | #:name "forgejo-pola-wrapper" | ||
| 697 | #:user user #:group group | ||
| 698 | #:namespaces | ||
| 699 | ;; The wrapper needs access to the forgejo user | ||
| 700 | ;; to be able to mount | ||
| 701 | ;; /etc/forgejo/internal_token for example. | ||
| 702 | (fold delq %namespaces '(net user)) | ||
| 703 | #:mappings mappings | ||
| 704 | #:preserved-environment-variables | ||
| 705 | (cons* "FORGEJO_WORK_DIR" | ||
| 706 | "SSL_CERT_DIR" | ||
| 707 | %default-preserved-environment-variables))) | ||
| 708 | (config (forgejo-configuration->file config)) | ||
| 709 | (init-provision (list (symbol-append (first shepherd-provision) | ||
| 710 | '-init)))) | ||
| 711 | (list (shepherd-service | ||
| 712 | (documentation "Run Forgejo pre-start actions.") | ||
| 713 | (requirement '(networking user-processes)) | ||
| 714 | (provision init-provision) | ||
| 715 | (one-shot? #t) | ||
| 716 | (modules (cons '(srfi srfi-19) %default-modules)) | ||
| 717 | (start | ||
| 718 | #~(lambda _ | ||
| 719 | (chdir #$work-directory) | ||
| 720 | |||
| 721 | (define app.ini "custom/conf/app.ini") | ||
| 722 | |||
| 723 | (define (symlink? x) | ||
| 724 | (eq? (stat:type (stat x)) 'symlink)) | ||
| 725 | |||
| 726 | (define (delete-file/backup x) | ||
| 727 | (let* ((timestamp (date->string | ||
| 728 | (current-date) "~4")) | ||
| 729 | (bak (string-append | ||
| 730 | x "-" timestamp ".bak"))) | ||
| 731 | (copy-file x bak) | ||
| 732 | (delete-file x))) | ||
| 733 | |||
| 734 | (define (fork+exec-forgejo . options) | ||
| 735 | ;; We can't change the environment in a one-shot | ||
| 736 | ;; service/Shepherd (is this a bug?), so use this wrapper | ||
| 737 | ;; of fork+exec-command that passes the needed | ||
| 738 | ;; environment variables and raises on unclean exit. | ||
| 739 | (let ((pid | ||
| 740 | (apply fork+exec-command | ||
| 741 | (cons #$forgejo-wrapper options) | ||
| 742 | (list #:environment-variables | ||
| 743 | (list #$(string-append | ||
| 744 | "FORGEJO_WORK_DIR=" | ||
| 745 | work-directory) | ||
| 746 | #$(string-append | ||
| 747 | "HOME=" work-directory)))))) | ||
| 748 | (unless (zero? (cdr (waitpid pid))) | ||
| 749 | (error "failed to run forgejo command" | ||
| 750 | #$forgejo-wrapper options)))) | ||
| 751 | |||
| 752 | (unless #$configuration-wizard? | ||
| 753 | ;; When users transition from configuration-wizard? #t to | ||
| 754 | ;; #f, the stale wizard configuration is backed up. | ||
| 755 | (when (file-exists? app.ini) | ||
| 756 | (if (symlink? app.ini) | ||
| 757 | (delete-file app.ini) | ||
| 758 | (delete-file/backup app.ini))) | ||
| 759 | (symlink #$config app.ini)) | ||
| 760 | |||
| 761 | (when (file-exists? app.ini) | ||
| 762 | ;; Initialize Forgejo's database. | ||
| 763 | (fork+exec-forgejo "migrate") | ||
| 764 | ;; Refresh binary file names captured in git hooks. | ||
| 765 | (fork+exec-forgejo "admin" "regenerate" "hooks") | ||
| 766 | ;; Update command option in 'authorized_keys' file. | ||
| 767 | (fork+exec-forgejo "admin" "regenerate" "keys") | ||
| 768 | ;; Sanity check configuration/environment. | ||
| 769 | (fork+exec-forgejo "doctor" "check" "--all"))))) | ||
| 770 | (shepherd-service | ||
| 771 | (documentation "Run the Forgejo Git forge") | ||
| 772 | (requirement (append init-provision | ||
| 773 | '(networking | ||
| 774 | user-processes) | ||
| 775 | (if (privileged-port? ssh-port) | ||
| 776 | '(ssh-daemon) | ||
| 777 | '()) | ||
| 778 | (if (string=? "postgres" database-type) | ||
| 779 | '(postgres) | ||
| 780 | '()) | ||
| 781 | (if (string=? "mysql" database-type) | ||
| 782 | '(mysql) | ||
| 783 | '()))) | ||
| 784 | (provision shepherd-provision) | ||
| 785 | (actions | ||
| 786 | (list (shepherd-configuration-action | ||
| 787 | (if configuration-wizard? | ||
| 788 | (string-append work-directory "/custom/conf/app.ini") | ||
| 789 | config)))) | ||
| 790 | (start | ||
| 791 | #~(make-systemd-constructor | ||
| 792 | (list #$forgejo-wrapper "web" | ||
| 793 | #$@(if configuration-wizard? | ||
| 794 | '() | ||
| 795 | #~("--config" #$config))) | ||
| 796 | (cond | ||
| 797 | (#$(string-suffix? "+unix" protocol) | ||
| 798 | (list (endpoint (make-socket-address AF_UNIX | ||
| 799 | #$http-address) | ||
| 800 | #:socket-owner #$user | ||
| 801 | #:socket-group #$group))) | ||
| 802 | (#$(string=? "0.0.0.0" http-address) | ||
| 803 | (list (endpoint (make-socket-address AF_INET | ||
| 804 | INADDR_ANY #$port)) | ||
| 805 | (endpoint (make-socket-address AF_INET6 | ||
| 806 | INADDR_ANY #$port)))) | ||
| 807 | (#$(ipv6-address? http-address) | ||
| 808 | (list (endpoint (make-socket-address | ||
| 809 | AF_INET6 | ||
| 810 | (inet-pton AF_INET6 #$http-address) | ||
| 811 | #$port)))) | ||
| 812 | (else ;assumed ipv4 | ||
| 813 | (list (endpoint (make-socket-address | ||
| 814 | AF_INET | ||
| 815 | (inet-pton AF_INET #$http-address) | ||
| 816 | #$port))))) | ||
| 817 | #:log-file "/var/log/forgejo.log" | ||
| 818 | #:environment-variables | ||
| 819 | (list (string-append "HOME=" #$work-directory) | ||
| 820 | "SSL_CERT_DIR=/etc/ssl/certs"))) | ||
| 821 | (stop #~(make-systemd-destructor))))))) | ||
| 822 | |||
| 823 | (define %forgejo-accounts | ||
| 824 | (match-record-lambda <forgejo-configuration> | ||
| 825 | (user group work-directory) | ||
| 826 | (list (user-group (name user) | ||
| 827 | (system? #t)) | ||
| 828 | (user-account | ||
| 829 | (name user) | ||
| 830 | (group group) | ||
| 831 | (system? #t) | ||
| 832 | (comment "Forgejo User") | ||
| 833 | (home-directory work-directory))))) | ||
| 834 | |||
| 835 | (define %forgejo-activation | ||
| 836 | (match-record-lambda <forgejo-configuration> | ||
| 837 | ( forgejo user configuration-wizard? work-directory | ||
| 838 | protocol http-address | ||
| 839 | secret-key-file internal-token-file lfs-secret-file | ||
| 840 | oauth2-jwt-secret-file) | ||
| 841 | #~(begin | ||
| 842 | (use-modules (gnu build activation) | ||
| 843 | (guix build utils) | ||
| 844 | (ice-9 match)) | ||
| 845 | |||
| 846 | (define secret-files `(("SECRET_KEY" . ,#$secret-key-file) | ||
| 847 | ("INTERNAL_TOKEN" . ,#$internal-token-file) | ||
| 848 | ("LFS_JWT_SECRET" . ,#$lfs-secret-file) | ||
| 849 | ("JWT_SECRET" . ,#$oauth2-jwt-secret-file))) | ||
| 850 | |||
| 851 | (define forgejo #$(file-append forgejo "/bin/forgejo")) | ||
| 852 | |||
| 853 | (define (generate-secret type file) | ||
| 854 | (with-exception-handler | ||
| 855 | (lambda (e) | ||
| 856 | (false-if-exception (delete-file file)) | ||
| 857 | (raise-exception e)) | ||
| 858 | (lambda () | ||
| 859 | (call-with-output-file file | ||
| 860 | (lambda (port) | ||
| 861 | (let ((pid (spawn forgejo | ||
| 862 | (list forgejo "generate" "secret" type) | ||
| 863 | #:output port))) | ||
| 864 | (match (waitpid pid) | ||
| 865 | ((_ . status) | ||
| 866 | (unless (zero? status) | ||
| 867 | (error "failed to generate forgejo secret" type)))))))))) | ||
| 868 | |||
| 869 | (let* ((owner (getpw #$user)) | ||
| 870 | (uid (passwd:uid owner)) | ||
| 871 | (gid (passwd:gid owner))) | ||
| 872 | ;; Top-level directories of secrets; needed even when not using the | ||
| 873 | ;; wizard. | ||
| 874 | (for-each (match-lambda | ||
| 875 | ((_ . file) | ||
| 876 | (mkdir-p/perms (dirname file) owner #o750))) | ||
| 877 | secret-files) | ||
| 878 | (when (and (string-suffix? "-unix" #$protocol) | ||
| 879 | (absolute-file-name? http-address)) | ||
| 880 | (mkdir-p/perms (dirname http-address) owner #o750)) | ||
| 881 | ;; To please 'forgejo doctor check --all' out of the box. | ||
| 882 | (mkdir-p/perms #$work-directory owner #o750) | ||
| 883 | (with-directory-excursion #$work-directory | ||
| 884 | (mkdir-p/perms ".ssh" owner #o700) | ||
| 885 | (mkdir-p/perms "custom" owner #o750) | ||
| 886 | (mkdir-p/perms "custom/conf" owner #o750) | ||
| 887 | (mkdir-p/perms "data" owner #o750) | ||
| 888 | (mkdir-p/perms "data/forgejo-repositories" owner #o750) | ||
| 889 | (mkdir-p/perms "log" owner #o750)) | ||
| 890 | (unless #$configuration-wizard? | ||
| 891 | ;; Bootstrap secret files. | ||
| 892 | (for-each (match-lambda | ||
| 893 | ((type . file) | ||
| 894 | (unless (file-exists? file) | ||
| 895 | (generate-secret type file)) | ||
| 896 | (chown file uid gid) | ||
| 897 | (chmod file #o400))) | ||
| 898 | secret-files)))))) | ||
| 899 | |||
| 900 | (define forgejo-service-type | ||
| 901 | (service-type | ||
| 902 | (name 'forgejo) | ||
| 903 | (extensions | ||
| 904 | (list (service-extension shepherd-root-service-type | ||
| 905 | forgejo-shepherd-service) | ||
| 906 | (service-extension account-service-type | ||
| 907 | %forgejo-accounts) | ||
| 908 | (service-extension activation-service-type | ||
| 909 | %forgejo-activation) | ||
| 910 | (service-extension profile-service-type | ||
| 911 | (compose list forgejo-configuration-forgejo)))) | ||
| 912 | (default-value (forgejo-configuration)) | ||
| 913 | (description "Run Forgejo."))) | ||
