@yunuseon/kayra 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -66,10 +66,11 @@ kayra status
|
|
|
66
66
|
|
|
67
67
|
| | |
|
|
68
68
|
|---|---|
|
|
69
|
+
| [**The docs site**](https://yunuseon.github.io/kayra/) | architecture diagrams, getting started, the fleet, the CLI |
|
|
70
|
+
| [The app contract](https://yunuseon.github.io/kayra/concepts/app-contract/) | what an app provides and what it may not do |
|
|
71
|
+
| [CI isolation](https://yunuseon.github.io/kayra/concepts/ci-isolation/) | why app code cannot reach the host or the platform |
|
|
72
|
+
| [Authentication](https://yunuseon.github.io/kayra/concepts/authentication/) | staff login (Authelia), adding people, recovery |
|
|
69
73
|
| [`CLAUDE.md`](CLAUDE.md) | how everything fits together, and the rules that keep it working |
|
|
70
|
-
| [`docs/app-contract.md`](docs/app-contract.md) | what an app provides and what it may not do |
|
|
71
|
-
| [`docs/authentication.md`](docs/authentication.md) | staff login (Authelia), adding people, recovery |
|
|
72
|
-
| [`docs/ci-isolation.md`](docs/ci-isolation.md) | why app code cannot reach the host or the platform |
|
|
73
74
|
|
|
74
75
|
## Contributing
|
|
75
76
|
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
#
|
|
9
9
|
# Never deletes: a stack dropped from the list keeps running until it is
|
|
10
10
|
# taken down by hand (docker compose -p <name> down).
|
|
11
|
+
#
|
|
12
|
+
# Private images: compose_registry_logins (in secrets.yml, a list of
|
|
13
|
+
# {registry, username, password}) are logged in with a Docker config kept in
|
|
14
|
+
# <dir>/.docker, which every compose call here uses (DOCKER_CONFIG) — the
|
|
15
|
+
# host's own Docker config is never written.
|
|
11
16
|
# =============================================================================
|
|
12
17
|
|
|
13
18
|
- name: Create stack directories
|
|
@@ -52,7 +57,28 @@
|
|
|
52
57
|
loop: "{{ compose_stacks.stacks | select('in', compose_stack_secrets | default({})) }}"
|
|
53
58
|
no_log: true
|
|
54
59
|
|
|
60
|
+
- name: Create the stacks' Docker config directory
|
|
61
|
+
ansible.builtin.file:
|
|
62
|
+
path: "{{ compose_stacks.dir }}/.docker"
|
|
63
|
+
state: directory
|
|
64
|
+
owner: root
|
|
65
|
+
group: root
|
|
66
|
+
mode: "0700"
|
|
67
|
+
when: compose_registry_logins | default([]) | length > 0
|
|
68
|
+
|
|
69
|
+
- name: Log in to private registries
|
|
70
|
+
community.docker.docker_login:
|
|
71
|
+
registry_url: "{{ item.registry }}"
|
|
72
|
+
username: "{{ item.username }}"
|
|
73
|
+
password: "{{ item.password }}"
|
|
74
|
+
config_path: "{{ compose_stacks.dir }}/.docker/config.json"
|
|
75
|
+
loop: "{{ compose_registry_logins | default([]) }}"
|
|
76
|
+
loop_control: {label: "{{ item.registry }}"}
|
|
77
|
+
no_log: true
|
|
78
|
+
|
|
55
79
|
- name: Start stacks
|
|
80
|
+
environment:
|
|
81
|
+
DOCKER_CONFIG: "{{ compose_stacks.dir }}/.docker"
|
|
56
82
|
community.docker.docker_compose_v2:
|
|
57
83
|
project_src: "{{ compose_stacks.dir }}/{{ item }}"
|
|
58
84
|
project_name: "{{ item }}"
|
|
@@ -64,6 +90,8 @@
|
|
|
64
90
|
# when a file it mounts did (a Caddyfile, Homepage's config): those take
|
|
65
91
|
# effect on a restart.
|
|
66
92
|
- name: Restart stacks whose files changed
|
|
93
|
+
environment:
|
|
94
|
+
DOCKER_CONFIG: "{{ compose_stacks.dir }}/.docker"
|
|
67
95
|
ansible.builtin.command: docker compose --project-name {{ item.item }} --file compose.yaml restart
|
|
68
96
|
args:
|
|
69
97
|
chdir: "{{ compose_stacks.dir }}/{{ item.item }}"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
# =============================================================================
|
|
3
3
|
# forgejo-config role — what a Forgejo holds beyond its own config file, as
|
|
4
|
-
# code: users and their SSH keys, Actions runners, repos (created empty
|
|
4
|
+
# code: users and their SSH keys, organizations, Actions runners, repos (created empty
|
|
5
5
|
# where missing) and their settings (issues, pull requests, actions), Actions
|
|
6
6
|
# secrets, collaborators, webhooks and push mirrors, from
|
|
7
7
|
# forgejo_config in the server's vars.yml. Adds what is missing through the
|
|
@@ -46,6 +46,45 @@
|
|
|
46
46
|
loop_control: {label: "{{ item.name }}"}
|
|
47
47
|
no_log: true
|
|
48
48
|
|
|
49
|
+
- name: Look up organizations
|
|
50
|
+
ansible.builtin.uri:
|
|
51
|
+
url: "{{ forgejo_config.url }}/api/v1/orgs/{{ item.name }}"
|
|
52
|
+
headers: {Authorization: "token {{ forgejo_admin_token }}"}
|
|
53
|
+
status_code: [200, 404]
|
|
54
|
+
register: forgejo_orgs
|
|
55
|
+
loop: "{{ forgejo_config.orgs | default([]) }}"
|
|
56
|
+
loop_control: {label: "{{ item.name }}"}
|
|
57
|
+
no_log: true
|
|
58
|
+
|
|
59
|
+
# An organization owns repos and packages alike, and its visibility is
|
|
60
|
+
# theirs: a private one keeps what it owns, images included, from the world.
|
|
61
|
+
# Created with its visibility, so it is never public for a moment.
|
|
62
|
+
- name: Create missing organizations
|
|
63
|
+
ansible.builtin.uri:
|
|
64
|
+
url: "{{ forgejo_config.url }}/api/v1/admin/users/{{ item.owner }}/orgs"
|
|
65
|
+
method: POST
|
|
66
|
+
headers: {Authorization: "token {{ forgejo_admin_token }}"}
|
|
67
|
+
body_format: json
|
|
68
|
+
body: {username: "{{ item.name }}", visibility: "{{ item.visibility }}"}
|
|
69
|
+
status_code: [201]
|
|
70
|
+
changed_when: true
|
|
71
|
+
loop: "{{ forgejo_orgs.results | selectattr('status', 'eq', 404) | map(attribute='item') | list }}"
|
|
72
|
+
loop_control: {label: "{{ item.name }}"}
|
|
73
|
+
no_log: true
|
|
74
|
+
|
|
75
|
+
- name: Apply organization visibility
|
|
76
|
+
ansible.builtin.uri:
|
|
77
|
+
url: "{{ forgejo_config.url }}/api/v1/orgs/{{ item.item.name }}"
|
|
78
|
+
method: PATCH
|
|
79
|
+
headers: {Authorization: "token {{ forgejo_admin_token }}"}
|
|
80
|
+
body_format: json
|
|
81
|
+
body: {visibility: "{{ item.item.visibility }}"}
|
|
82
|
+
changed_when: true
|
|
83
|
+
when: item.status == 200 and item.json.visibility != item.item.visibility
|
|
84
|
+
loop: "{{ forgejo_orgs.results }}"
|
|
85
|
+
loop_control: {label: "{{ item.item.name }}"}
|
|
86
|
+
no_log: true
|
|
87
|
+
|
|
49
88
|
- name: Look up SSH keys
|
|
50
89
|
ansible.builtin.uri:
|
|
51
90
|
url: "{{ forgejo_config.url }}/api/v1/users/{{ item.user }}/keys"
|
|
@@ -103,7 +142,9 @@
|
|
|
103
142
|
# the content is pushed by hand.
|
|
104
143
|
- name: Create missing repos
|
|
105
144
|
ansible.builtin.uri:
|
|
106
|
-
url:
|
|
145
|
+
url: >-
|
|
146
|
+
{{ forgejo_config.url }}/api/v1/{{ 'orgs' if item.name.split('/')[0] in (forgejo_config.orgs | default([]) | map(attribute='name'))
|
|
147
|
+
else 'admin/users' }}/{{ item.name.split('/')[0] }}/repos
|
|
107
148
|
method: POST
|
|
108
149
|
headers: {Authorization: "token {{ forgejo_admin_token }}"}
|
|
109
150
|
body_format: json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yunuseon/kayra",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A self-hosted app platform and the CLI that runs it: Traefik, Authelia, Jenkins, a registry and rootless BuildKit per server, set up with OpenTofu and Ansible.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Yunus Öztürk",
|