This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Epics

Od zera do bohatera

Celem tej dokumentacji jest opisanie w jaki sposób przygotowałem środowisko od “zera”. Poniższy diagram przedstawia Road Map.

flowchart TD
    n1@{ label: "<span style=\"color:\">Przygotowanie środowiska developerskiego</span>" } --> n2["Zarządzenie przestrzenią gitlab za pomocą opentofu"]
    n2 --> n3["Gitlab CI<br>(CI/CD)"]
    n3 --> n4@{ label: "<div style=\"color:\"><span style=\"color:\">Utworzenie centralnego miejsca do przechowywania dokumentacji</span></div>" } & n5["Kontrola Zależności<br>(update depedency renovate)"] & n6["Utworzenie template VM<br>na Proxmox za pomocą<br>Packer"] & n10["Mikrotik IAC"]
    n6 --> n7["Utworzenie playboków dla VM<br>(hardening)"] & n11["Proxmox IAC"]
    n7 --> n8["gitlab-runner<br>"] & n9["Consul + Vault"]
    n11 --> n7
    n10 --> n11
    n3 --> n2

    n1@{ shape: rect}
    n4@{ shape: rect}
    click n1 "/docs/epics/epic1/"
    click n2 "/docs/epics/epic2/"
    click n3 "/docs/epics/epic3/"
    click n4 "/docs/epics/epic4/"
    click n5 "/docs/epics/epic5/"
    click n6 "/docs/epics/epic6/"
    click n7 "/docs/epics/epic7/"

1 - Epic 1

vagrant Przygotowanie środowiska developerskiego

🎯 Cel epiki

Stworzenie wirtualnej maszyny dla zespołu deweloperskiego, który zawiera niezbędne narzędzia do pracy.

  • Utworzenie w vagrant registry obrazu Ubuntu 24.10
  • Wykorzystanie vagrant do provisioning`u maszyny wirtualnej.
---
config:
  theme: neo
  layout: dagre
  look: neo
---
flowchart LR
 subgraph s1["Przygotowanie obrazu"]
        n5@{ label: "Przygotowanie maszyny<br style=\"--tw-scale-x:\">wirtualnej na virtualbox" }
        n6@{ label: "<span style=\"padding-left:\">Utworzenie box<br></span><span style=\"padding-left:\">(vagrant package)</span>" }
        n7@{ label: "Wysłanie do<br style=\"--tw-scale-x:\">Vagrant box Registry" }
  end
 subgraph s2["Użycie obrazu (vagrant up)"]
        n8["vagrant up"]
        n9["run bootstrap.bash"]
        n11["bash scripts"]
  end
    n5 --> n6
    n6 --> n7
    s1 --> s2
    n8 --> n9
    s2 --> n10("Ready to use")
    n9 --> n11
    n5@{ shape: rect}
    n6@{ shape: rect}
    n7@{ shape: rect}
    n9@{ shape: lean-r}
    n11@{ shape: procs}

Przygotowanie obrazu

  • Utworzenie projektu w Vagrant Box Registries
  • Instalacja manualna Ubuntu server 24.10 z użytkownikiem vagrant password vagrant
  • Wykonanie skryptu poleceń na koncie vagrant
      sudo apt-get update
      sudo apt-get dist-upgrade -y
      sudo apt install -y openssh-server curl wget sudo
      sudo apt install -y build-essential dkms linux-headers-$(uname -r)
      mkdir -p /home/vagrant/.ssh
      curl -fsSL https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant.pub -o /home/vagrant/.ssh/authorized_keys
      chown -R vagrant:vagrant /home/vagrant/.ssh
      chmod 700 /home/vagrant/.ssh
      chmod 600 /home/vagrant/.ssh/authorized_keys
      echo "vagrant ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/vagrant
    
  • Przygotowanie maszyny wirtualnej do eksportu
    vagrant package --base ubuntu-24.04-base --output ubuntu-24.04.box
    
  • Wysłanie obrazu do Vagrant box Registry

Przygotowanie maszyny deweloperskiej

2 - Epic 2

opentofu Zarządzenie przestrzenią pl.rachuna-net w gitlab za pomocą OpenTofu

🎯 Cel epiki

Pełna automatyzacja zarządzania strukturą grup i projektów w przestrzeni pl.rachuna-net na GitLabie przy wykorzystaniu podejścia Infrastructure as Code (IaC) opartego na OpenTofu.

  • Utworzenie modułów OpenTofu do zarządzania grupami (gitlab-group), projektami (gitlab-project) oraz kontenerami (OpenTofu).

  • Import istniejących zasobów do OpenTofu state (OpenTofu import).

  • Ujednolicenie struktury folderów i repozytoriów (infrastructure/OpenTofu, modules, iac-gitlab, containers).

  • Przeniesienie konfiguracji do zarządzalnych modułów oraz refaktoryzację kodu.

---
config:
  theme: neo
  layout: dagre
  look: neo
---
flowchart TD
 subgraph s1["Czynności manualne"]
        n5["Utworzenie grup i repozytoriów<br>"]
  end
 subgraph s2["Utworzenie modułów"]
        n8["gitlab-group"]
        n10["gitlab-project"]
  end
 subgraph s3["Repozytorium IAC"]
        n12["iac-gitlab"]
  end
 subgraph s4["Wykonywanie zmian"]
        n13["tofu plan<br>(wyświetlenie zmian)"]
        n14["tofu apply<br>(Wykonywanie zmian)"]
  end
    s1 --> s2
    n8 --> n12
    n10 --> n12
    n13 --> n14
    n12 --> s4
    n11["Utworzenie obrazu <br>kontenerowego<br>z OpenTofu"] --> s4

    n5@{ shape: rect}
    n12@{ shape: rounded}
    n11@{ shape: rounded}
     n8:::Sky
     n10:::Sky
     n12:::Sky
     n11:::Sky
    classDef Sky stroke-width:1px, stroke-dasharray:none, stroke:#374D7C, fill:#E2EBFF, color:#374D7C
    click n8 "https://gitlab.com/pl.rachuna-net/infrastructure/opentofu/modules/gitlab-group"
    click n10 "https://gitlab.com/pl.rachuna-net/infrastructure/opentofu/modules/gitlab-project"
    click n12 "https://gitlab.com/pl.rachuna-net/infrastructure/opentofu/iac-gitlab"
    click n11 "https://gitlab.com/pl.rachuna-net/containers/opentofu"

Manualne tworzenie repozytoriów i grup

  • ✅ Utworzenie manualne grupy pl.rachuna-net
  • ✅ Utworzenie manualne grupy pl.rachuna-net/infrastructure
  • ✅ Utworzenie manualne grupy pl.rachuna-net/infrastructure/opentofu
  • ✅ Utworzenie manualne grupy pl.rachuna-net/infrastructure/opentofu/modules
  • ✅ Utworzenie manualne repozytorium pl.rachuna-net/infrastructure/opentofu/iac-gitlab
  • ✅ Utworzenie manualne repozytorium pl.rachuna-net/infrastructure/opentofu/modules/gitlab-group
  • ✅ Utworzenie manualne repozytorium pl.rachuna-net/infrastructure/opentofu/modules/gitlab-project

Moduły OpenTofu


Utworzenie obrazu z OpenTofu

podman run -it -v $PWD:/opentofu -v ~/.ssh:/root/.ssh -u root registry.gitlab.com/pl.rachuna-net/containers/opentofu:1.0.0-3d3738b8 bash

cd /opentofu

CI_SERVER_URL="https://gitlab.com"
CI_PROJECT_ID="123456789"
CI_USERNAME="gitlab-runner"
CI_JOB_TOKEN="***"
TF_STATE_NAME="default"

tofu init \
  -backend-config="address=${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/opentofu/state/${TF_STATE_NAME}" \
  -backend-config="lock_address=${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/opentofu/state/${TF_STATE_NAME}/lock" \
  -backend-config="unlock_address=${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/opentofu/state/${TF_STATE_NAME}/lock" \
  -backend-config="username=${CI_USERNAME}" \
  -backend-config="password=${CI_JOB_TOKEN}" \
  -backend-config="lock_method=POST" \
  -backend-config="unlock_method=DELETE" \
  -backend-config="retry_wait_min=5" \
  -lock=false \
  -migrate-state
tofu plan
tofu apply -auto-aprove

Import istniejących zasobów do OpenTofu

tofu import module.group_pl_rachuna-net.gitlab_group.group 105046057

Utworzenie zasobów do OpenTofu

3 - Epic 3

gitlab Utworzenie procesów gitlab-ci

🎯 Cel epiki

Zadanie polega na zaprojektowaniu i wdrożeniu ustandaryzowanych procesów CI/CD w przestrzeni pl.rachuna-net z wykorzystaniem GitLab-CI, zgodnie z podejściem modularnym i komponentowym.

Projekt zakłada utworzenie dedykowanej struktury repozytoriów, komponentów oraz definicji pipeline’ów, które umożliwią zarządzanie i automatyzację procesów testowania, budowania, publikowania oraz wdrażania aplikacji i bibliotek w spójny, skalowalny sposób.

---
config:
  theme: neo
  layout: dagre
  look: neo
---
flowchart LR
 subgraph s3["Repozytorium IAC"]
        n12["iac-gitlab"]
  end
 subgraph s4["Infrastruktura"]
        n13["Zarządzanie grupami i repozytoriami"]
  end
 subgraph s5["Przestrzeń CI/CD"]
        n18["gitlab-ci"]
        n19["components"]
  end
    n12 --> s4
    n18 --> n19
    n13 -- Definicja pipeline --> s5
    s5 --> n11["containers"]
    n11 --> n22["Job"]

    n12@{ shape: rounded}
    n18@{ shape: rect}
    n19@{ shape: procs}
    n11@{ shape: procs}
    n22@{ shape: lean-r}
     n12:::Sky
     n22:::Pine
    classDef Aqua stroke-width:1px, stroke-dasharray:none, stroke:#46EDC8, fill:#DEFFF8, color:#378E7A
    classDef Pine stroke-width:1px, stroke-dasharray:none, stroke:#254336, fill:#27654A, color:#FFFFFF
    classDef Sky stroke-width:1px, stroke-dasharray:none, stroke:#374D7C, fill:#E2EBFF, color:#374D7C
    click n12 "https://gitlab.com/pl.rachuna-net/infrastructure/opentofu/iac-gitlab"

Przygotowanie grup i repozytoriów za pomocą Terraform

- przestrzeń pl.rachuna-net / cicd

- przestrzeń pl.rachuna-net / containers


Przygotowanie minimalistycznego procesu do budowania kontenerów (image builder)

---
config:
  theme: neo
  layout: dagre
  look: neo
---
flowchart LR
    A(["Ręczne przygotowanie obrazu konterowego"]) --> B["proces-ci"]
    B --> C@{ label: "<span style=\"color:\">wydanie obrazu</span><br style=\"--tw-scale-x:\"><span style=\"color:\">buildah</span>" } & D["wydanie obrazu<br>semantic-release"] & n2@{ label: "<span style=\"color:\">wydanie obrazu</span><br style=\"--tw-scale-x:\"><span style=\"color:\">python</span>" } & n4@{ label: "<span style=\"padding-left:\"><span style=\"color:\">wydanie obrazu</span><br style=\"--tw-scale-x:\">conftest</span>" } & n5@{ label: "<span style=\"padding-left:\"><span style=\"padding-left:\"><span style=\"color:\">wydanie obrazu<br></span>trivy</span></span>" }
    n1(["Przygotowanie minimalistyczny<br>proces gitlab-ci"]) --> B

    B@{ shape: proc}
    C@{ shape: rect}
    n2@{ shape: rect}
    n4@{ shape: rect}
    n5@{ shape: rect}
     A:::Pine
     n1:::Pine
    classDef Pine stroke-width:1px, stroke-dasharray:none, stroke:#254336, fill:#27654A, color:#FFFFFF
    click A "https://gitlab.com/pl.rachuna-net/containers/buildah/-/blob/main/Dockerfile?ref_type=heads"
    click C "https://gitlab.com/pl.rachuna-net/containers/buildah/-/releases/v1.0.0"
    click D "https://gitlab.com/pl.rachuna-net/containers/semantic-release"
    click n2 "https://gitlab.com/pl.rachuna-net/containers/python"
    click n4 "https://gitlab.com/pl.rachuna-net/containers/conftest"
    click n5 "https://gitlab.com/pl.rachuna-net/containers/trivy"
    click n1 "http://localhost:1313/blog/2025/07/23/proces-budowania-kontenerów/#przygotowanie-procesu-ci"

Przygotowanie procesu defaultowego procesu


---
config:
  theme: redux
---
flowchart LR
 subgraph s1["validate"]
        n1["🧑‍💻 YAML lint"]
  end
 subgraph s2["prepare"]
        n2["🔍 Analyze Conventional Commits"]
        n3["🔍 input parameters"]
        n4["🕵 Set Version"]
  end
 subgraph s4["release"]
        n6["📍 Publish Version"]
  end
    s2 --> s1
    n2 --- n3
    n3 --- n4
    s1 --> s4

    click n1 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/yamllint.yml?ref_type=heads"
    click n2 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/conventional_commits.yml?ref_type=heads"
    click n3 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"
    click n4 "https://gitlab.com/pl.rachuna-net/cicd/components/release/-/blob/main/templates/versioning.yml?ref_type=heads"
    click n6 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"

(prepare) Przygotowanie procesu

(validate) Walidacja

(release) Wydawnie


Przygotowanie procesu dla builder image


---
config:
  theme: redux
---
flowchart LR
 subgraph s1["prepare"]
        n1["🔍 Analyze Conventional Commits"]
        n2["⚙️ Input Parameters"]
        n3["🕵 Set Version"]
  end
 subgraph s2["validate"]
        n4["🧪 Validate files (conftest)"]
        n11@{ label: "<div style=\"color:\"><span style=\"color:\">🧑‍💻 YAML lint</span></div>" }
  end
 subgraph s3["build"]
        n5["🚀 build container image"]
  end
 subgraph s4["publish"]
        n6["🌐 publish container image"]
  end
 subgraph s5["release"]
        n8["📍 Publish Version"]
  end
 subgraph s6["integration-test"]
        n9["🔬 trivy (dast)"]
        n10["🧪 test docker image"]
  end
    s1 --> s2
    s2 --> s3
    s3 --> s4
    s4 --> s5
    s5 --> s6
    n1 --- n2
    n2 --- n3
    n9 --- n10
    n4 --> n11
    n11@{ shape: rect}
    click n1 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/conventional_commits.yml?ref_type=heads"
    click n2 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"
    click n3 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/set_version.yml?ref_type=heads"
    click n4 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/contrest.yml"
    click n5 "https://gitlab.com/pl.rachuna-net/cicd/components/containers/-/blob/main/templates/image-builder.yml"
    click n6 "https://gitlab.com/pl.rachuna-net/cicd/components/containers/-/blob/main/templates/image-builder.yml"
    click n7 "https://gitlab.com/pl.rachuna-net/cicd/components/release/-/blob/main/templates/vault.yml"
    click n8 "https://gitlab.com/pl.rachuna-net/cicd/components/release/-/blob/main/templates/versioning.yml"
    click n9 "https://gitlab.com/pl.rachuna-net/cicd/components/ast/-/blob/main/templates/trivy.yml?ref_type=heads"
    click n10 "https://gitlab.com/pl.rachuna-net/cicd/components/containers/-/blob/main/templates/image-builder.yml"

(validate) Walidacja

(build)

(publish) Publikacja

(integration-test) Testy integracyjne


Przygotowanie procesu dla opentofu modules


---
config:
  theme: redux
---
flowchart LR
 subgraph s1["validate"]
        n1["🧑‍💻 YAML lint"]
        n8@{ label: "<code><span class=\"hljs-string\">🕵</span><span class=\"\"> </span><span class=\"hljs-attr\">opentofu fmt</span></code>" }
        n10@{ label: "<code><span class=\"hljs-string\">✅</span><span class=\"\"> </span><span class=\"hljs-attr\">tflint</span></code>" }
        n11@{ label: "<code><span class=\"hljs-string\">✅</span><span class=\"\"> </span><span class=\"hljs-attr\">terraform-docs</span></code>" }
  end
 subgraph s2["prepare"]
        n2["🔍 Analyze Conventional Commits"]
        n3["🔍 input parameters"]
        n4["🕵 Set Version"]
  end
 subgraph s3["sast"]
        n5["💪 sonarqube scan"]
  end
 subgraph s4["release"]
        n6["📍 Publish Version"]
  end
    s2 --> s1
    n2 --- n3
    n3 --- n4
    s3 --> s4
    n1 --- n8
    n8 --- n10
    n10 --- n11
    s1 --> s3
    n8@{ shape: rect}
    n10@{ shape: rect}
    n11@{ shape: rect}
    click n1 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/yamllint.yml?ref_type=heads"
    click n8 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n10 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n11 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n2 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/conventional_commits.yml?ref_type=heads"
    click n3 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"
    click n4 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"
    click n5 "https://gitlab.com/pl.rachuna-net/cicd/components/ast/-/blob/main/templates/sonarqube.yml?ref_type=heads"
    click n6 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"

(validate) Walidacja

Przygotowanie procesu dla opentofu


---
config:
  theme: redux
---
flowchart LR
 subgraph s1["validate"]
        n1["🧑‍💻 YAML lint"]
        n8@{ label: "<code><span class=\"hljs-string\">🕵</span><span class=\"\"> </span><span class=\"hljs-attr\">opentofu fmt</span></code>" }
        n9@{ label: "<code><span class=\"hljs-string\">✅</span><span class=\"\"> </span><span class=\"hljs-attr\">opentofu validate</span></code>" }
        n10@{ label: "<code><span class=\"hljs-string\">✅</span><span class=\"\"> </span><span class=\"hljs-attr\">tflint</span></code>" }
        n11@{ label: "<code><span class=\"hljs-string\">✅</span><span class=\"\"> </span><span class=\"hljs-attr\">terraform-docs</span></code>" }
  end
 subgraph s2["prepare"]
        n2["🔍 Analyze Conventional Commits"]
        n3["🔍 input parameters"]
        n4["🕵 Set Version"]
  end
 subgraph s3["sast"]
        n5["💪 sonarqube scan"]
  end
 subgraph s4["release"]
        n6["📍 Publish Version"]
  end
 subgraph s5["unit-test"]
        n12@{ label: "<span style=\"color:\" color=\"\">🧪 opentofu plan</span>" }
  end
 subgraph s6["deploy"]
        n13@{ label: "<span style=\"color:\" color=\"\">💥 opentofu apply</span>" }
  end
    s2 --> s1
    n2 --- n3
    n3 --- n4
    s3 --> s4
    s1 --> s5
    n1 --- n8
    n8 --> n9
    n9 --> n10
    n10 --> n11
    s5 --> s3
    s4 --> s6
    n8@{ shape: rect}
    n9@{ shape: rect}
    n10@{ shape: rect}
    n11@{ shape: rect}
    n12@{ shape: rect}
    n13@{ shape: rect}
    click n1 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/yamllint.yml?ref_type=heads"
    click n8 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n9 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n10 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n11 "https://gitlab.com/pl.rachuna-net/cicd/components/validate/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n2 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/conventional_commits.yml?ref_type=heads"
    click n3 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"
    click n4 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"
    click n5 "https://gitlab.com/pl.rachuna-net/cicd/components//-/blob/main/templates/sonarqube.yml?ref_type=heads"
    click n6 "https://gitlab.com/pl.rachuna-net/cicd/components/prepare/-/blob/main/templates/input_parameters.yml?ref_type=heads"
    click n7 "https://gitlab.com/pl.rachuna-net/cicd/components/release/-/blob/main/templates/vault.yml?ref_type=heads"
    click n12 "https://gitlab.com/pl.rachuna-net/cicd/components/unit-test/-/blob/main/templates/opentofu.yml?ref_type=heads"
    click n13 "https://gitlab.com/pl.rachuna-net/cicd/components/deploy/-/blob/main/templates/opentofu.yml?ref_type=heads"

4 - Epic 4

gitlab Utworzenie centralnego miejsca do przechowywania dokumentacji

🎯 Cel epiki

Celem tego epika jest kompleksowe opracowanie i wdrożenie systemu dokumentacji technicznej dla projektów realizowanych w ramach organizacji rachuna-net. Dokumentacja ma być publikowana w nowym repozytorium pl.rachuna-net/docs, hostowana pod domeną rachuna-net.pl i dostępna w nowoczesnej, łatwej do aktualizacji formie, z wykorzystaniem gohugo.

Zakres prac obejmuje:

  • Utworzenie dedykowanych repozytoriów dla dokumentacji i kontenerów wspierających proces publikacji.
  • Stworzenie kontenera hugo oraz zautomatyzowanego procesu publikacyjnego.
  • Integrację z domeną rachuna-net.pl w celu zapewnienia publicznego dostępu do dokumentacji.
  • Integrację GitLab Pages z domeną rachuna-net.pl jako mechanizmu publikacji statycznej dokumentacji.
  • Uzupełnienie brakujących sekcji dokumentacyjnych dotyczących projektów infrastrukturalnych, CI/CD oraz kontenerów.
  • Realizacja tego epika zapewni ustandaryzowaną, centralną i łatwo dostępną platformę dokumentacyjną wspierającą rozwój oraz utrzymanie systemów i infrastruktury w organizacji.

Przygotowanie grup i repozytoriów za pomocą Terraform


Przygotowanie kontenera do procesu Gitlab CI


Przygotowanie procesu CI/CD

  • ✅ Stworzenie procesu do publikacji strony z użyciem gitlab pages

Publikacja gitlab-pages i integracja z domeną

  • ✅ Integracja z gitlab-pages zbudowane na mkdocs z domeną rachuna-net.pl

5 - Epic 5

gitlab Renovate

🎯 Cel epiki