Enable Forgejo Actions (Phase 1) (#48)
All checks were successful
Test CI / test (push) Successful in 0s

## Summary
- Refactor Forgejo app.ini to be managed by ansible with secrets from 1Password
- Enable Forgejo Actions in config (`[actions] ENABLED = true`)
- Add `repo.actions` to DEFAULT_REPO_UNITS
- Clean up unused MySQL database fields (we use SQLite)

## Phase 1 Progress
This PR covers the first part of Phase 1 (ci-cd-bootstrap plan):
- [x] Refactor app.ini to ansible template
- [x] Store secrets in 1Password
- [x] Enable Actions in config
- [ ] Deploy config changes (pending review)
- [ ] Create runner registration token
- [ ] Deploy runner to k8s
- [ ] Test with simple workflow

## Deployment and Testing
- [ ] Run `mise run provision-indri -- --tags forgejo` to deploy
- [ ] Verify Forgejo restarts correctly
- [ ] Verify Actions tab appears in repo settings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: https://forge.tail8d86e.ts.net/eblume/blumeops/pulls/48
This commit is contained in:
Erich Blume 2026-01-23 17:00:12 -08:00
commit 7893c41020
15 changed files with 426 additions and 15 deletions

View file

@ -22,6 +22,45 @@
no_log: true
tags: [borgmatic]
# Forgejo secrets
- name: Fetch forgejo LFS JWT secret
ansible.builtin.command:
cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get w3663ffnvkewbftncqxtcpeavy --fields lfs-jwt-secret --reveal
delegate_to: localhost
register: _forgejo_lfs_jwt
changed_when: false
no_log: true
check_mode: false
tags: [forgejo]
- name: Fetch forgejo internal token
ansible.builtin.command:
cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get w3663ffnvkewbftncqxtcpeavy --fields internal-token --reveal
delegate_to: localhost
register: _forgejo_internal_token
changed_when: false
no_log: true
check_mode: false
tags: [forgejo]
- name: Fetch forgejo OAuth2 JWT secret
ansible.builtin.command:
cmd: op --vault vg6xf6vvfmoh5hqjjhlhbeoaie item get w3663ffnvkewbftncqxtcpeavy --fields oauth2-jwt-secret --reveal
delegate_to: localhost
register: _forgejo_oauth2_jwt
changed_when: false
no_log: true
check_mode: false
tags: [forgejo]
- name: Set forgejo secrets facts
ansible.builtin.set_fact:
forgejo_lfs_jwt_secret: "{{ _forgejo_lfs_jwt.stdout }}"
forgejo_internal_token: "{{ _forgejo_internal_token.stdout }}"
forgejo_oauth2_jwt_secret: "{{ _forgejo_oauth2_jwt.stdout }}"
no_log: true
tags: [forgejo]
roles:
- role: alloy
tags: alloy

View file

@ -0,0 +1,51 @@
---
# Forgejo configuration
# Secrets are fetched from 1Password in the playbook pre_tasks
forgejo_app_name: Forgejo
forgejo_app_slogan: "Beyond coding. We Forge."
forgejo_run_user: forgejo
forgejo_run_mode: prod
# Paths (brew-managed for now, will change to mcquack in Phase 3)
forgejo_work_path: /opt/homebrew/var/forgejo
forgejo_config_path: "{{ forgejo_work_path }}/custom/conf/app.ini"
forgejo_data_path: "{{ forgejo_work_path }}/data"
forgejo_repo_root: "{{ forgejo_data_path }}/forgejo-repositories"
forgejo_lfs_path: "{{ forgejo_data_path }}/lfs"
forgejo_log_path: "{{ forgejo_work_path }}/log"
# Server settings
forgejo_http_addr: 0.0.0.0
forgejo_http_port: 3001
forgejo_domain: forge.tail8d86e.ts.net
forgejo_ssh_domain: "{{ forgejo_domain }}"
forgejo_root_url: "https://{{ forgejo_domain }}/"
forgejo_offline_mode: true
# SSH settings (built-in SSH server)
forgejo_disable_ssh: false
forgejo_start_ssh_server: true
forgejo_builtin_ssh_user: forgejo
forgejo_ssh_port: 22
forgejo_ssh_listen_port: 2200
forgejo_lfs_start_server: true
# Database (SQLite)
forgejo_db_type: sqlite3
forgejo_db_path: "{{ forgejo_data_path }}/forgejo.db"
# Service settings
forgejo_disable_registration: true
forgejo_require_signin_view: false
# Session
forgejo_session_provider: file
# Logging
forgejo_log_mode: console
forgejo_log_level: info
# Actions (Forgejo CI)
forgejo_actions_enabled: true
forgejo_actions_default_url: https://code.forgejo.org

View file

@ -1,26 +1,29 @@
---
# Note: forgejo config at /opt/homebrew/var/forgejo/custom/conf/app.ini
# is not managed here (contains secrets). It is backed up by borgmatic.
# Forgejo role
#
# Currently uses brew-managed forgejo. Phase 3 of ci-cd-bootstrap will
# transition to mcquack LaunchAgent with CI-built binary.
#
# Secrets (lfs_jwt_secret, internal_token, oauth2_jwt_secret) are fetched
# from 1Password in the playbook pre_tasks.
- name: Install forgejo via homebrew
community.general.homebrew:
name: forgejo
state: present
- name: Check forgejo config exists
ansible.builtin.stat:
path: /opt/homebrew/var/forgejo/custom/conf/app.ini
register: forgejo_config
- name: Ensure forgejo config directory exists
ansible.builtin.file:
path: "{{ forgejo_work_path }}/custom/conf"
state: directory
mode: '0755'
- name: Fail if forgejo config is missing
ansible.builtin.fail:
msg: |
Forgejo config not found at /opt/homebrew/var/forgejo/custom/conf/app.ini
This file contains secrets and is not managed by ansible.
To restore from backup, run:
borgmatic --config ~/.config/borgmatic/config.yaml extract --archive latest \
--path /opt/homebrew/var/forgejo/custom/conf/app.ini
when: not forgejo_config.stat.exists
- name: Deploy forgejo config
ansible.builtin.template:
src: app.ini.j2
dest: "{{ forgejo_config_path }}"
mode: '0600'
notify: Restart forgejo
- name: Ensure forgejo service is started
ansible.builtin.command: brew services start forgejo

View file

@ -0,0 +1,82 @@
# {{ ansible_managed }}
APP_NAME = {{ forgejo_app_name }}
APP_SLOGAN = {{ forgejo_app_slogan }}
RUN_USER = {{ forgejo_run_user }}
WORK_PATH = {{ forgejo_work_path }}
RUN_MODE = {{ forgejo_run_mode }}
[server]
HTTP_ADDR = {{ forgejo_http_addr }}
HTTP_PORT = {{ forgejo_http_port }}
SSH_DOMAIN = {{ forgejo_ssh_domain }}
DOMAIN = {{ forgejo_domain }}
ROOT_URL = {{ forgejo_root_url }}
APP_DATA_PATH = {{ forgejo_data_path }}
DISABLE_SSH = {{ forgejo_disable_ssh | lower }}
START_SSH_SERVER = {{ forgejo_start_ssh_server | lower }}
BUILTIN_SSH_SERVER_USER = {{ forgejo_builtin_ssh_user }}
SSH_PORT = {{ forgejo_ssh_port }}
SSH_LISTEN_PORT = {{ forgejo_ssh_listen_port }}
LFS_START_SERVER = {{ forgejo_lfs_start_server | lower }}
LFS_JWT_SECRET = {{ forgejo_lfs_jwt_secret }}
OFFLINE_MODE = {{ forgejo_offline_mode | lower }}
[database]
DB_TYPE = {{ forgejo_db_type }}
PATH = {{ forgejo_db_path }}
LOG_SQL = false
[repository]
ROOT = {{ forgejo_repo_root }}
DEFAULT_REPO_UNITS = repo.code,repo.issues,repo.pulls,repo.releases,repo.wiki,repo.projects,repo.packages,repo.actions
[lfs]
PATH = {{ forgejo_lfs_path }}
[mailer]
ENABLED = false
[service]
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
DISABLE_REGISTRATION = {{ forgejo_disable_registration | lower }}
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
REQUIRE_SIGNIN_VIEW = {{ forgejo_require_signin_view | lower }}
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.indri
[openid]
ENABLE_OPENID_SIGNIN = false
ENABLE_OPENID_SIGNUP = false
[cron.update_checker]
ENABLED = false
[session]
PROVIDER = {{ forgejo_session_provider }}
[log]
MODE = {{ forgejo_log_mode }}
LEVEL = {{ forgejo_log_level }}
ROOT_PATH = {{ forgejo_log_path }}
[repository.pull-request]
DEFAULT_MERGE_STYLE = merge
[repository.signing]
DEFAULT_TRUST_MODEL = committer
[security]
INSTALL_LOCK = true
INTERNAL_TOKEN = {{ forgejo_internal_token }}
PASSWORD_HASH_ALGO = pbkdf2_hi
[oauth2]
JWT_SECRET = {{ forgejo_oauth2_jwt_secret }}
[actions]
ENABLED = {{ forgejo_actions_enabled | lower }}
DEFAULT_ACTIONS_URL = {{ forgejo_actions_default_url }}