diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fac1c60 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 1.0.0 + +* Initial Release \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..fb1770a --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Ansible Collection - enbewe.forgejo + +Collecion to configure forgejo git server. + +## Playbooks + +### enbewe.forgejo.deployment +Deploys the role `enbewe.forgejo.forgejo` to all hosts in the group `forgejo`. + +## Roles + +### enbewe.forgejo.forgejo +Deploys [Forgejo](https://forgejo.org/) through a podman container. +Additionally deploys an accompanying postgres database. + +When configured the Forgejo instance is automatically connected with some OAuth2 provider, +to implement single-sign-on. + +## Modules + +### enbewe.forgejo.forgejo_oauth +Manages OAuth sources through the CLI of the forgejo server. \ No newline at end of file diff --git a/galaxy.yml b/galaxy.yml new file mode 100644 index 0000000..bf69cdd --- /dev/null +++ b/galaxy.yml @@ -0,0 +1,68 @@ +--- +### REQUIRED +# The namespace of the collection. This can be a company/brand/organization or product namespace under which all +# content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with +# underscores or numbers and cannot contain consecutive underscores +namespace: 'enbewe' + +# The name of the collection. Has the same character restrictions as 'namespace' +name: 'forgejo' + +# The version of the collection. Must be compatible with semantic versioning +version: '1.0.0' + +# The path to the Markdown (.md) readme file. This path is relative to the root of the collection +readme: 'README.md' + +# A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) +# @nicks:irc/im.site#channel' +authors: + - 'Nis Wechselberg ' + + +### OPTIONAL but strongly recommended +# A short summary description of the collection +description: 'Collection to deploy a forgejo server' + +# Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only +# accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' +license: + - 'MIT' + +# A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character +# requirements as 'namespace' and 'name' +tags: + - 'linux' + +# Collections that this collection requires to be installed for it to be usable. The key of the dict is the +# collection label 'namespace.name'. The value is a version range +# L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version +# range specifiers can be set and are separated by ',' +dependencies: + containers.podman: '1.13.0' + +# The URL of the originating SCM repository +repository: 'https://git.enbewe.de/Coding/ansible-collection-forgejo' + +# The URL to any online docs +# documentation: http://docs.example.com + +# The URL to the homepage of the collection/project +# homepage: http://example.com + +# The URL to the collection issue tracker +# issues: http://example.com/issue/tracker + +# A list of file glob-like patterns used to filter any files or directories that should not be included in the build +# artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This +# uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', +# and '.git' are always filtered. Mutually exclusive with 'manifest' +# build_ignore: [] + +# A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a +# list of MANIFEST.in style +# L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key +# 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive +# with 'build_ignore' +# manifest: null + diff --git a/meta/runtime.yml b/meta/runtime.yml new file mode 100644 index 0000000..d6c6f44 --- /dev/null +++ b/meta/runtime.yml @@ -0,0 +1,52 @@ +--- +# Collections must specify a minimum required ansible version to upload +# to galaxy +requires_ansible: '>=2.17.0' + +# Content that Ansible needs to load from another location or that has +# been deprecated/removed +# plugin_routing: +# action: +# redirected_plugin_name: +# redirect: ns.col.new_location +# deprecated_plugin_name: +# deprecation: +# removal_version: "4.0.0" +# warning_text: | +# See the porting guide on how to update your playbook to +# use ns.col.another_plugin instead. +# removed_plugin_name: +# tombstone: +# removal_version: "2.0.0" +# warning_text: | +# See the porting guide on how to update your playbook to +# use ns.col.another_plugin instead. +# become: +# cache: +# callback: +# cliconf: +# connection: +# doc_fragments: +# filter: +# httpapi: +# inventory: +# lookup: +# module_utils: +# modules: +# netconf: +# shell: +# strategy: +# terminal: +# test: +# vars: + +# Python import statements that Ansible needs to load from another location +# import_redirection: +# ansible_collections.ns.col.plugins.module_utils.old_location: +# redirect: ansible_collections.ns.col.plugins.module_utils.new_location + +# Groups of actions/modules that take a common set of options +# action_groups: +# group_name: +# - module1 +# - module2 diff --git a/playbooks/deployment.yml b/playbooks/deployment.yml new file mode 100644 index 0000000..0c5a2a2 --- /dev/null +++ b/playbooks/deployment.yml @@ -0,0 +1,5 @@ +--- +- name: 'Deploy collection roles to matching host groups' + hosts: 'forgejo' + roles: + - 'enbewe.forgejo.forgejo' diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 0000000..269a4c2 --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,31 @@ +# Collections Plugins Directory + +This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that +is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that +would contain module utils and modules respectively. + +Here is an example directory of the majority of plugins currently supported by Ansible: + +``` +└── plugins + ├── action + ├── become + ├── cache + ├── callback + ├── cliconf + ├── connection + ├── filter + ├── httpapi + ├── inventory + ├── lookup + ├── module_utils + ├── modules + ├── netconf + ├── shell + ├── strategy + ├── terminal + ├── test + └── vars +``` + +A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.17/plugins/plugins.html). diff --git a/plugins/modules/forgejo_oauth.py b/plugins/modules/forgejo_oauth.py new file mode 100644 index 0000000..2a3d51d --- /dev/null +++ b/plugins/modules/forgejo_oauth.py @@ -0,0 +1,299 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: Nis Wechselberg +# MIT License (see https://spdx.org/licenses/MIT.html) +from __future__ import absolute_import, print_function + +DOCUMENTATION = r''' +--- +module: forgejo_auth + +short_description: Module to manage forgejo oauth authentication sources + +version_added: "1.0.0" + +description: This module uses the forgejo api to manage the configured oauth +authentication sources. It can add, remove or update an authentication source. +This module only works for forgejo running inside containers, created through +this collections role. There are several assumptions regardings names and ids. + +author: + - Nis Wechselberg (@eNBeWe) +''' + +EXAMPLES = r''' +# Create a new auth provider, but don't touch existing source +- name: 'Add authentication source' + enbewe.forgejo.forgejo_oauth: + state: 'present' + update: true + name: 'eNBeWe.eu SSO' + provider: 'openidConnect' + key: 'clientIdConfiguredInAuthProvider' + secret: 'secretKeyOfTheClientIdInAuthProvider' + auto_discover_url: 'https://' + skip_local_2fa: true +''' + +RETURN = r''' +# Return values +''' + +from ansible.module_utils.basic import AnsibleModule + +class ForgejoOAuth: + ''' + Handles the management of forgejo authentication sources. + ''' + module = None + + def __init__(self, module: AnsibleModule): + ''' + Create a new OAuth Handler + ''' + self.module = module + + self.name = module.params.get('name') + + def run(self): + ''' + Apply the configuration. + ''' + oauth_source_already_exists, oauth_source_id = self.get_oauth_source_with_name() + + if self.module.params.get('state') == 'absent': + if oauth_source_already_exists: + return self.remove_auth_source(oauth_source_id) + + return { + 'failed': False, + 'changed': False, + 'msg': f'OAuth2 authorization source {self.name} is not configured.' + } + + if self.module.params.get('state') == 'present': + if oauth_source_already_exists and self.module.params.get('update'): + return self.update_oauth_source(oauth_source_id) + + if oauth_source_already_exists: + return { + 'failed': False, + 'changed': False, + 'msg': f'OAuth2 authorization source {self.name} already exists.' + } + + return self.add_oauth_source() + + return { + 'failed': True, + 'changed': False, + 'msg': 'Misconfigured plugin, unknown state.' + } + + def get_oauth_source_with_name(self): + ''' + Check the list of configured authentication sources for + an existing OAuth source of the given name. + ''' + args_list = [ + 'podman', 'exec', + '-u', '1000:1000', + '-it', 'forgejo-app', + 'forgejo', 'admin', 'auth', 'list', + '--vertical-bars' + ] + _, auth_list_stdout, _ = self.module.run_command(args_list) + auth_table_rows = auth_list_stdout.split("\n") + + if len(auth_table_rows) > 2: + for auth_id in range(1, len(auth_table_rows) - 1): + auth_row = auth_table_rows[auth_id].split('|') + auth_id = int(auth_row[0].strip()) + auth_name = auth_row[1].strip() + auth_type = auth_row[2].strip() + if auth_type == 'OAuth2' and auth_name == self.name: + return (True, auth_id) + return (False, -1) + + def add_oauth_source(self): + ''' + Add a new OAuth2 source with the given configuration. + ''' + args_list = [ + 'podman', 'exec', + '-u', '1000:1000', + '-it', 'forgejo-app', + 'forgejo', 'admin', 'auth', 'add-oauth', + ] + args_list += self.create_command_arguments() + + auth_add_rc, auth_add_stdout, _ = self.module.run_command(args_list) + + if auth_add_rc == 0: + return { + 'failed': False, + 'changed': True, + 'msg': f'OAuth2 authorization source {self.name} successful created.' + } + + return { + 'failed': True, + 'msg': auth_add_stdout + } + + def remove_auth_source(self, source_id): + ''' + Removes the authentication source with the given id from the config. + ''' + args_list = [ + 'podman', 'exec', + '-u', '1000:1000', + '-it', 'forgejo-app', + 'forgejo', 'admin', 'auth', 'delete', + '--id', str(source_id), + ] + auth_delete_rc, auth_delete_stdout, _ = self.module.run_command(args_list) + + if auth_delete_rc == 0: + return { + 'failed': False, + 'changed': True, + 'msg': f'OAuth2 authorization source {self.name} removed.' + } + + return { + 'failed': True, + 'msg': auth_delete_stdout + } + + def update_oauth_source(self, source_id): + ''' + Updates the authentication source with the given id to match the passed config. + ''' + args_list = [ + 'podman', 'exec', + '-u', '1000:1000', + '-it', 'forgejo-app', + 'forgejo', 'admin', 'auth', 'update-oauth', + '--id', str(source_id), + ] + args_list += self.create_command_arguments() + + auth_update_rc, auth_update_stdout, _ = self.module.run_command(args_list) + + if auth_update_rc == 0: + return { + 'failed': False, + 'changed': True, + 'msg': f'OAuth2 authorization source {self.name} has been updated' + } + + return { + 'failed': True, + 'msg': auth_update_stdout + } + + def create_command_arguments(self): + ''' + Create the command arguments for cli commands from the passed config. + ''' + result = [ + '--name', self.name, + '--provider', self.module.params.get('provider'), + '--key', self.module.params.get('key'), + '--secret', self.module.params.get('secret'), + '--auto-discover-url', + (self.module.params.get('auto_discover_url') + if self.module.params.get('auto_discover_url') else ""), + '--custom-tenant-id', + (self.module.params.get('custom_tenant_id') + if self.module.params.get('custom_tenant_id') else ""), + '--custom-auth-url', + (self.module.params.get('custom_auth_url') + if self.module.params.get('custom_auth_url') else ""), + '--custom-token-url', + (self.module.params.get('custom_token_url') + if self.module.params.get('custom_token_url') else ""), + '--custom-profile-url', + (self.module.params.get('custom_profile_url') + if self.module.params.get('custom_profile_url') else ""), + '--custom-email-url', + (self.module.params.get('custom_email_url') + if self.module.params.get('custom_email_url') else ""), + '--icon-url', + (self.module.params.get('icon_url') + if self.module.params.get('icon_url') else ""), + '--required-claim-name', + (self.module.params.get('required_claim_name') + if self.module.params.get('required_claim_name') else ""), + '--required-claim-value', + (self.module.params.get('required_claim_value') + if self.module.params.get('required_claim_value') else ""), + '--group-claim-name', + (self.module.params.get('group_claim_name') + if self.module.params.get('group_claim_name') else ""), + '--admin-group', + (self.module.params.get('admin_group') + if self.module.params.get('admin_group') else ""), + '--restricted-group', + (self.module.params.get('restricted_group') + if self.module.params.get('restricted_group') else ""), + '--group-team-map', + (self.module.params.get('group_team_map') + if self.module.params.get('group_team_map') else ""), + ] + for scope in self.module.params.get('scopes').split(): + result.append('--scopes') + result.append(scope) + if self.module.params.get('use_custom_urls'): + result.append('--use-custom-urls') + if self.module.params.get('skip_local_2fa'): + result.append('--skip-local-2fa') + if self.module.params.get('group_team_map_removal'): + result.append('--group-team-map-removal') + + return result + +def main(): + ''' + Run the module code. + ''' + module_args = { + 'state': {'type': str, 'default': 'present', 'choices': ['present', 'absent']}, + 'update': {'type': bool, 'default': False}, + 'name': {'type': str, 'required': True}, + 'provider': {'type': str, 'required': True}, + 'key': {'type': str, 'required': True}, + 'secret': {'type': str, 'required': True}, + 'auto_discover_url': {'type': str, 'required': False}, + 'use_custom_urls': {'type': bool, 'default': False}, + 'custom_tenant_id': {'type': str, 'required': False}, + 'custom_auth_url': {'type': str, 'required': False}, + 'custom_token_url': {'type': str, 'required': False}, + 'custom_profile_url': {'type': str, 'required': False}, + 'custom_email_url': {'type': str, 'required': False}, + 'icon_url': {'type': str, 'required': False}, + 'skip_local_2fa': {'type': bool, 'default': False}, + 'scopes': {'type': str, 'required': False}, + 'required_claim_name': {'type': str, 'required': False}, + 'required_claim_value': {'type': str, 'required': False}, + 'group_claim_name': {'type': str, 'required': False}, + 'admin_group': {'type': str, 'required': False}, + 'restricted_group': {'type': str, 'required': False}, + 'group_team_map': {'type': str, 'required': False}, + 'group_team_map_removal': {'type': bool, 'default': False}, + } + + module = AnsibleModule( + argument_spec = module_args, + supports_check_mode = False, + ) + + forgejo_auth_module = ForgejoOAuth(module) + result = forgejo_auth_module.run() + + module.exit_json(**result) + +if __name__ == '__main__': + main() diff --git a/roles/forgejo/defaults/main.yml b/roles/forgejo/defaults/main.yml new file mode 100644 index 0000000..3837b8e --- /dev/null +++ b/roles/forgejo/defaults/main.yml @@ -0,0 +1,21 @@ +--- +forgejo_db_image_name: 'docker.io/library/postgres' +forgejo_db_image_tag: '16' +forgejo_db_volume_name: 'forgejo_db_storage' + +forgejo_network_name: 'forgejo' + +forgejo_app_image_name: 'codeberg.org/forgejo/forgejo' +forgejo_app_image_tag: '7' +forgejo_app_volume_name: 'forgejo_app_storage' + +forgejo_db_user: 'forgejo' +forgejo_db_password: 'forgejo' +forgejo_db_database: 'forgejo' + +forgejo_ssh_port: 222 + + + + + diff --git a/roles/forgejo/files/forgejo/templates/user/auth/signin_inner.tmpl b/roles/forgejo/files/forgejo/templates/user/auth/signin_inner.tmpl new file mode 100644 index 0000000..a40085c --- /dev/null +++ b/roles/forgejo/files/forgejo/templates/user/auth/signin_inner.tmpl @@ -0,0 +1,69 @@ +{{if or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn)}} +{{template "base/alert" .}} +{{end}} +

+ {{if .LinkAccountMode}} + {{ctx.Locale.Tr "auth.oauth_signin_title"}} + {{else}} + {{ctx.Locale.Tr "auth.login_userpass"}} + {{end}} +

+
+
+ {{.CsrfTokenHtml}} + {{if (not .OAuth2Providers)}} +
+ + +
+ {{if or (not .DisablePassword) .LinkAccountMode}} +
+ + +
+ {{end}} + {{if not .LinkAccountMode}} +
+
+ + +
+
+ {{end}} + + {{template "user/auth/captcha" .}} + +
+ + {{ctx.Locale.Tr "auth.forgot_password"}} +
+ + {{if .ShowRegistrationButton}} + + {{end}} + {{end}} + + {{if .OAuth2Providers}} + + {{end}} +
+
diff --git a/roles/forgejo/handlers/main.yml b/roles/forgejo/handlers/main.yml new file mode 100644 index 0000000..b8f090c --- /dev/null +++ b/roles/forgejo/handlers/main.yml @@ -0,0 +1,7 @@ +--- +- name: 'Restart forgejo container' + become: true + ansible.builtin.service: + name: 'container-forgejo-app' + state: 'restarted' + daemon_reload: true diff --git a/roles/forgejo/tasks/main.yml b/roles/forgejo/tasks/main.yml new file mode 100644 index 0000000..7000460 --- /dev/null +++ b/roles/forgejo/tasks/main.yml @@ -0,0 +1,120 @@ +--- +# Basic stuff +- name: 'Install required software' + become: true + ansible.builtin.apt: + name: 'podman' + state: 'present' + +- name: 'Create podman network for forgejo deployment' + become: true + containers.podman.podman_network: + name: '{{ forgejo_network_name }}' + state: 'present' + +- name: 'Create the volume for database storage' + become: true + containers.podman.podman_volume: + name: '{{ item }}' + state: 'present' + loop: + - '{{ forgejo_db_volume_name }}' + - '{{ forgejo_app_volume_name }}' + +# Database +- name: 'Create config for database for forgejo' + become: true + ansible.builtin.template: + src: 'systemd/container-forgejo-db.service.j2' + dest: '/etc/systemd/system/container-forgejo-db.service' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + +- name: 'Start and enable forgejo-db service' + become: true + ansible.builtin.systemd: + name: 'container-forgejo-db.service' + state: 'started' + enabled: true + daemon_reload: true + +# Application +- name: 'Prepare config location' + become: true + ansible.builtin.file: + path: '{{ item }}' + state: 'directory' + owner: 'root' + group: 'root' + mode: 'u=rwx,g=rx,o=rx' + loop: + - '/srv/git/conf/' + - '/srv/git/custom/templates/user/auth' + +- name: 'Deploy application config' + become: true + ansible.builtin.template: + src: 'forgejo/forgejo.ini' + dest: '/srv/git/conf/forgejo.ini' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + notify: 'Restart forgejo container' + +- name: 'Write customized login page' + become: true + ansible.builtin.copy: + src: 'forgejo/templates/user/auth/signin_inner.tmpl' + dest: '/srv/git/custom/templates/user/auth/signin_inner.tmpl' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + notify: 'Restart forgejo container' + +- name: 'Create service for forgejo' + become: true + ansible.builtin.template: + src: 'systemd/container-forgejo-app.service.j2' + dest: '/etc/systemd/system/container-forgejo-app.service' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + notify: 'Restart forgejo container' + +- name: 'Start and enable forgejo-app service' + become: true + ansible.builtin.systemd: + name: 'container-forgejo-app.service' + state: 'started' + enabled: true + daemon_reload: true + +# Authentication source +- name: 'Configure forgejo authentication source' + become: true + when: forgejo_sso_create_source + enbewe.forgejo.forgejo_oauth: + state: 'present' + update: '{{ forgejo_sso_update | default(false) }}' + name: '{{ forgejo_sso_name }}' + provider: '{{ forgejo_sso_provider }}' + key: '{{ forgejo_sso_key }}' + secret: '{{ forgejo_sso_secret }}' + auto_discover_url: '{{ forgejo_sso_auto_discover_url | default("") }}' + use_custom_urls: '{{ forgejo_sso_use_custom_urls | default(false) }}' + custom_tenant_id: '{{ forgejo_sso_custom_tenant_id | default("") }}' + custom_auth_url: '{{ forgejo_sso_custom_auth_url | default("") }}' + custom_token_url: '{{ forgejo_sso_custom_token_url | default("") }}' + custom_profile_url: '{{ forgejo_sso_custom_profile_url | default("") }}' + custom_email_url: '{{ forgejo_sso_custom_email_url | default("") }}' + icon_url: '{{ forgejo_sso_icon_url | default("") }}' + skip_local_2fa: '{{ forgejo_sso_skip_local_2fa | default(true) }}' + scopes: '{{ forgejo_sso_scopes | default("") }}' + required_claim_name: '{{ forgejo_sso_required_claim_name | default("") }}' + required_claim_value: '{{ forgejo_sso_required_claim_value | default("") }}' + group_claim_name: '{{ forgejo_sso_group_claim_name | default("") }}' + admin_group: '{{ forgejo_sso_admin_group | default("") }}' + restricted_group: '{{ forgejo_sso_restricted_group | default("") }}' + group_team_map: '{{ forgejo_sso_group_team_map | default("") }}' + group_team_map_removal: '{{ forgejo_sso_group_team_map_removal | default(false) }}' diff --git a/roles/forgejo/templates/forgejo/forgejo.ini b/roles/forgejo/templates/forgejo/forgejo.ini new file mode 100644 index 0000000..904b841 --- /dev/null +++ b/roles/forgejo/templates/forgejo/forgejo.ini @@ -0,0 +1,124 @@ +APP_NAME = {{ forgejo_general_app_name }} +RUN_MODE = {{ forgejo_general_run_mode | default('prod') }} +RUN_USER = git +WORK_PATH = /data/gitea + +[repository] +ROOT = /data/git/repositories +DEFAULT_PRIVATE = {{ forgejo_repostiory_default_private | default('last') }} +DISABLE_HTTP_GIT = {{ forgejo_repostiory_disable_http_git | default(false) }} +ENABLE_PUSH_CREATE_USER = {{ forgejo_repostiory_enable_push_create_user | default(false) }} +ENABLE_PUSH_CREATE_ORG = {{ forgejo_repostiory_enable_push_create_org | default(false) }} + +[repository.pull-request] +DEFAULT_MERGE_STYLE = merge + +[repository.upload] +TEMP_PATH = /data/gitea/uploads + +[repository.signing] +DEFAULT_TRUST_MODEL = committer + +[repository.local] +LOCAL_COPY_PATH = /data/gitea/tmp/local-repo + +[server] +APP_DATA_PATH = /data/gitea +DOMAIN = {{ forgejo_server_domain }} +SSH_DOMAIN = {{ forgejo_server_ssh_domain | default(forgejo_server_domain) }} +HTTP_PORT = 3000 +ROOT_URL = {{ forgejo_server_root_url }} +DISABLE_SSH = false +SSH_PORT = {{ forgejo_ssh_port }} +SSH_LISTEN_PORT = 22 +LFS_START_SERVER = true +LFS_JWT_SECRET = {{ forgejo_server_lfs_jwt_secret }} +OFFLINE_MODE = {{ forgejo_server_offline_mode | default(true) }} +LANDING_PAGE = {{ forgejo_server_landing_page | default('home') }} + +[database] +DB_TYPE = postgres +HOST = forgejo-db:5432 +NAME = {{ forgejo_db_database }} +USER = {{ forgejo_db_user }} +PASSWD = {{ forgejo_db_password }} +SCHEMA = +SSL_MODE = disable +LOG_SQL = false + +[indexer] +ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve + +[admin] +DEFAULT_EMAIL_NOTIFICATIONS = {{ forgejo_admin_default_email_notification | default('enabled') }} +DISABLE_REGULAR_ORG_CREATION = {{ forgejo_admin_disable_regular_org_creation | default(false) }} +SEND_NOTIFICATION_EMAIL_ON_NEW_USER = {{ forgejo_admin_send_notification_email_on_new_user | default(false) }} + +[security] +INSTALL_LOCK = true +SECRET_KEY = {{ forgejo_security_secret_key }} +REVERSE_PROXY_LIMIT = 1 +REVERSE_PROXY_TRUSTED_PROXIES = * +INTERNAL_TOKEN = {{ forgejo_security_internal_token }} +PASSWORD_HASH_ALGO = pbkdf2_hi + +[openid] +ENABLE_OPENID_SIGNIN = {{ forgejo_openid_enable_openid_signin | default(true) }} +ENABLE_OPENID_SIGNUP = {{ forgejo_openid_enable_openid_signup | default(false) }} + +[oauth2_client] +ENABLE_AUTO_REGISTRATION = {{ forgejo_oauth2_enable_auto_registration | default(false) }} + +[service] +REGISTER_EMAIL_CONFIRM = {{ forgejo_service_register_email_confirm | default(false) }} +REGISTER_MANUAL_CONFIRM = {{ forgejo_service_register_manual_confirm | default(false) }} +DISABLE_REGISTRATION = {{ forgejo_service_disable_registration | default(false) }} +REQUIRE_SIGNIN_VIEW = {{ forgejo_service_require_signin_view | default(true) }} +ENABLE_NOTIFY_MAIL = {{ forgejo_service_enable_notify_mail | default(false) }} +ENABLE_CAPTCHA = false +DEFAULT_KEEP_EMAIL_PRIVATE = {{ forgejo_service_default_keep_email_private | default(true) }} +DEFAULT_ALLOW_CREATE_ORGANIZATION = {{ forgejo_service_default_allow_create_organization | default(false) }} +DEFAULT_ENABLE_TIMETRACKING = false +ALLOW_ONLY_INTERNAL_REGISTRATION = {{ forgejo_service_allow_only_internal_registration | default(false) }} +ALLOW_ONLY_EXTERNAL_REGISTRATION = {{ forgejo_service_allow_only_external_registration | default(false) }} + +[service.explore] +REQUIRE_SIGNIN_VIEW = {{ forgejo_service_explore_require_signin_view | default(false) }} +DISABLE_USERS_PAGE = {{ forgejo_service_explore_disable_users_page | default(true) }} + +[mailer] +ENABLED = false + +[session] +PROVIDER = file +PROVIDER_CONFIG = /data/gitea/sessions + +[picture] +AVATAR_UPLOAD_PATH = /data/gitea/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars + +[attachment] +PATH = /data/gitea/attachments + +[log] +MODE = console +LEVEL = {{ forgejo_log_level | default('info') }} +ROOT_PATH = /data/gitea/log + +[cron.update_checker] +ENABLED = true + +[oauth2] +ENABLED = {{ forgejo_oauth2_provider_enabled | default(false) }} +JWT_SECRET = {{ forgejo_oauth2_jwt_secret }} + +[federation] +ENABLED = {{ forgejo_federation_enabled | default(false) }} +SHARE_USER_STATISTICS = {{ forgejo_federation_share_user_statistics | default(true) }} +MAX_SIZE = {{ forgejo_federation_max_size | default(4) }} + +[lfs] +PATH = /data/git/lfs + +[actions] +ENABLED = {{ forgejo_actions_enabled | default(false) }} diff --git a/roles/forgejo/templates/systemd/container-forgejo-app.service.j2 b/roles/forgejo/templates/systemd/container-forgejo-app.service.j2 new file mode 100644 index 0000000..bed56ec --- /dev/null +++ b/roles/forgejo/templates/systemd/container-forgejo-app.service.j2 @@ -0,0 +1,52 @@ +[Unit] +Description=Podman container-forgejo-app.service +Documentation=man:podman-generate-systemd(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=%t/containers + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +Type=notify +NotifyAccess=all + +ExecStartPre=/bin/rm -f %t/%n.ctr-id + +ExecStart=/usr/bin/podman run \ + --cidfile=%t/%n.ctr-id \ + --cgroups=no-conmon \ + --rm \ + --sdnotify=conmon \ + --replace \ + --publish 127.0.0.1:8082:3000/tcp \ + --publish {{ forgejo_ssh_port }}:22/tcp \ + --detach \ + --tty \ + --network={{ forgejo_network_name }} \ + --volume {{ forgejo_app_volume_name }}:/data/:Z \ + --volume /etc/timezone:/etc/timezone:ro \ + --volume /etc/localtime:/etc/localtime:ro \ + --volume /srv/git/conf/forgejo.ini:/data/gitea/conf/app.ini:ro \ + --volume /srv/git/custom/templates:/data/gitea/templates:ro \ + --env USER_UID=1000 \ + --env USER_GID=1000 \ + --env FORGEJO__database__DB_TYPE=postgres \ + --env FORGEJO__database__HOST=forgejo-db:5432 \ + --env FORGEJO__database__NAME={{ forgejo_db_database }} \ + --env FORGEJO__database__USER={{ forgejo_db_user }} \ + --env FORGEJO__database__PASSWD={{ forgejo_db_password }} \ + --name=forgejo-app \ + {{ forgejo_app_image_name }}:{{ forgejo_app_image_tag }} + +ExecStop=/usr/bin/podman stop \ + --ignore \ + --cidfile=%t/%n.ctr-id + +ExecStopPost=/usr/bin/podman rm \ + --force --ignore \ + --cidfile=%t/%n.ctr-id + +[Install] +WantedBy=default.target diff --git a/roles/forgejo/templates/systemd/container-forgejo-db.service.j2 b/roles/forgejo/templates/systemd/container-forgejo-db.service.j2 new file mode 100644 index 0000000..0a51090 --- /dev/null +++ b/roles/forgejo/templates/systemd/container-forgejo-db.service.j2 @@ -0,0 +1,42 @@ +[Unit] +Description=Podman container-forgejo-db.service +Documentation=man:podman-generate-systemd(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=%t/containers + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +TimeoutStopSec=70 +Type=notify +NotifyAccess=all + +ExecStartPre=/bin/rm -f %t/%n.ctr-id + +ExecStart=/usr/bin/podman run \ + --cidfile=%t/%n.ctr-id \ + --cgroups=no-conmon \ + --rm \ + --sdnotify=conmon \ + --replace \ + --detach \ + --tty \ + --network={{ forgejo_network_name }} \ + --volume {{ forgejo_db_volume_name }}:/var/lib/postgresql/data/:Z \ + --env POSTGRES_USER={{ forgejo_db_user }} \ + --env POSTGRES_PASSWORD={{ forgejo_db_password }} \ + --env POSTGRES_DB={{ forgejo_db_database }} \ + --name=forgejo-db \ + {{ forgejo_db_image_name }}:{{ forgejo_db_image_tag }} + +ExecStop=/usr/bin/podman stop \ + --ignore \ + --cidfile=%t/%n.ctr-id + +ExecStopPost=/usr/bin/podman rm \ + --force --ignore \ + --cidfile=%t/%n.ctr-id + +[Install] +WantedBy=default.target