Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
506212b
fix: support 'null' workaround as optional input in Panel
grubmeshi Mar 16, 2026
84092ae
feat(git-repository): support action_secrets, refactor ske starterkit…
grubmeshi Mar 16, 2026
e970c7c
feat(ske): register forgejo connector as tenant building block
grubmeshi Mar 16, 2026
656d321
feat(ske): write stage-specific forgejo repo secrets
grubmeshi Mar 16, 2026
dafa0df
feat(ske): compose tenant forgejo connectors in starterkit
grubmeshi Mar 16, 2026
b4b7b76
feat(ske): pass git repository definition uuid to starterkit
grubmeshi Mar 16, 2026
56326a4
feat(stackit): expose git-repository definition uuid output
grubmeshi Mar 16, 2026
1236697
fix(ske): use harbor vars for image pull secret auth
grubmeshi Mar 16, 2026
6389548
fix(ske): declare supported platform for tenant connector
grubmeshi Mar 16, 2026
32fb777
refactor(ske): drop obsolete git repository definition input
grubmeshi Mar 16, 2026
0cd74b4
chore(ske): commit pending forgejo connector adjustments
grubmeshi Mar 16, 2026
3a3a792
refactor(ske): remove unused additional connector env vars
grubmeshi Mar 16, 2026
d4eb0ab
fix(ske): restore kubeconfig stub and file input wiring
grubmeshi Mar 16, 2026
2ca4690
feat(ske): rework forgejo connector kubeconfig wiring
grubmeshi Mar 17, 2026
86f793b
fix: get ske/starterkit tg apply to work
grubmeshi Mar 17, 2026
76af2aa
fix(ske): align repository_id wiring and platform support
grubmeshi Mar 17, 2026
b836d1e
feat(ske): simplify kubeconfig flow and align forgejo env inputs
grubmeshi Mar 17, 2026
9864f8d
feat(ske): align composition with BBD output object
grubmeshi Mar 18, 2026
e8b1d42
feat(ske): simplify forgejo connector kubeconfig input
grubmeshi Mar 18, 2026
89ba134
feat(ske): configure default SA to use harbor pull secret
grubmeshi Mar 18, 2026
b1aec4b
feat(ske): add action variables and trigger pipeline dispatch
grubmeshi Mar 18, 2026
0583aac
chore: ignore python build files
grubmeshi Mar 18, 2026
176571e
feat(ske): refactor forgejo connector workflow trigger wiring
grubmeshi Mar 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ yarn-error.log*
*tfvars*
.terraform.lock.hcl
.env
__pycache__/
*.pyc

# Generated assets
website/public/assets/building-block-logos/
Expand Down
38 changes: 0 additions & 38 deletions modules/ske/forgejo-connector/backplane/README.md

This file was deleted.

11 changes: 0 additions & 11 deletions modules/ske/forgejo-connector/backplane/main.tf

This file was deleted.

30 changes: 0 additions & 30 deletions modules/ske/forgejo-connector/backplane/outputs.tf

This file was deleted.

28 changes: 0 additions & 28 deletions modules/ske/forgejo-connector/backplane/variables.tf

This file was deleted.

10 changes: 0 additions & 10 deletions modules/ske/forgejo-connector/backplane/versions.tf

This file was deleted.

22 changes: 14 additions & 8 deletions modules/ske/forgejo-connector/buildingblock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ the backplane module's `config_tf` output.

| Name | Version |
|------|---------|
| <a name="requirement_external"></a> [external](#requirement\_external) | ~> 2.3.0 |
| <a name="requirement_kubernetes"></a> [kubernetes](#requirement\_kubernetes) | 2.35.1 |
| <a name="requirement_restapi"></a> [restapi](#requirement\_restapi) | 3.0.0 |

## Modules

Expand All @@ -55,29 +57,33 @@ No modules.

| Name | Type |
|------|------|
| [forgejo_repository_action_secret.additional](https://registry.terraform.io/providers/svalabs/forgejo/latest/docs/resources/repository_action_secret) | resource |
| [forgejo_repository_action_secret.container_registry](https://registry.terraform.io/providers/svalabs/forgejo/latest/docs/resources/repository_action_secret) | resource |
| [forgejo_repository_action_secret.kubeconfig](https://registry.terraform.io/providers/svalabs/forgejo/latest/docs/resources/repository_action_secret) | resource |
| [forgejo_repository_action_secret.action_secrets](https://registry.terraform.io/providers/svalabs/forgejo/latest/docs/resources/repository_action_secret) | resource |
| [kubernetes_cluster_role.clusterissuer_reader](https://registry.terraform.io/providers/hashicorp/kubernetes/2.35.1/docs/resources/cluster_role) | resource |
| [kubernetes_cluster_role_binding.forgejo_actions_clusterissuer_access](https://registry.terraform.io/providers/hashicorp/kubernetes/2.35.1/docs/resources/cluster_role_binding) | resource |
| [kubernetes_default_service_account.namespace_default](https://registry.terraform.io/providers/hashicorp/kubernetes/2.35.1/docs/resources/default_service_account) | resource |
| [kubernetes_role_binding.forgejo_actions](https://registry.terraform.io/providers/hashicorp/kubernetes/2.35.1/docs/resources/role_binding) | resource |
| [kubernetes_secret.forgejo_actions](https://registry.terraform.io/providers/hashicorp/kubernetes/2.35.1/docs/resources/secret) | resource |
| [kubernetes_secret.image_pull](https://registry.terraform.io/providers/hashicorp/kubernetes/2.35.1/docs/resources/secret) | resource |
| [kubernetes_service_account.forgejo_actions](https://registry.terraform.io/providers/hashicorp/kubernetes/2.35.1/docs/resources/service_account) | resource |
| [forgejo_repository.this](https://registry.terraform.io/providers/svalabs/forgejo/latest/docs/data-sources/repository) | data source |
| [random_string.clusterissuer_reader_name_suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource |
| [restapi_object.action_variables](https://registry.terraform.io/providers/Mastercard/restapi/3.0.0/docs/resources/object) | resource |
| [terraform_data.await_pipeline_workflow](https://registry.terraform.io/providers/hashicorp/terraform/latest/docs/resources/data) | resource |
| [external_external.repository_context](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_additional_environment_variables"></a> [additional\_environment\_variables](#input\_additional\_environment\_variables) | Map of additional environment variable key/value pairs to set as Forgejo repository action secrets. | `map(string)` | `{}` | no |
| <a name="input_forgejo_repository_name"></a> [forgejo\_repository\_name](#input\_forgejo\_repository\_name) | The name of the Forgejo repository. | `string` | n/a | yes |
| <a name="input_forgejo_repository_owner"></a> [forgejo\_repository\_owner](#input\_forgejo\_repository\_owner) | The owner of the Forgejo repository. | `string` | n/a | yes |
| <a name="input_harbor_host"></a> [harbor\_host](#input\_harbor\_host) | The URL of the Harbor registry. | `string` | `"https://registry.onstackit.cloud"` | no |
| <a name="input_harbor_password"></a> [harbor\_password](#input\_harbor\_password) | The password for the Harbor registry. | `string` | n/a | yes |
| <a name="input_harbor_username"></a> [harbor\_username](#input\_harbor\_username) | The username for the Harbor registry. | `string` | n/a | yes |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | Associated namespace in kubernetes cluster. | `string` | n/a | yes |
| <a name="input_repository_id"></a> [repository\_id](#input\_repository\_id) | The ID of the Forgejo repository. | `number` | n/a | yes |
| <a name="input_repository_secret_name_suffix"></a> [repository\_secret\_name\_suffix](#input\_repository\_secret\_name\_suffix) | Optional suffix appended to created repository secret names. | `string` | `""` | no |

## Outputs

No outputs.
| Name | Description |
|------|-------------|
| <a name="output_action_variables"></a> [action\_variables](#output\_action\_variables) | Action variables to expose for dependent building block wiring. |
<!-- END_TF_DOCS -->
123 changes: 81 additions & 42 deletions modules/ske/forgejo-connector/buildingblock/forgejo.tf
Original file line number Diff line number Diff line change
@@ -1,55 +1,94 @@
locals {
kubeconfig_user = {
users = [
{
name = kubernetes_service_account.forgejo_actions.metadata[0].name
user = {
"token" = kubernetes_secret.forgejo_actions.data.token
}
}
]

contexts = [
{
name = "stackit_k8s"
context = {
cluster = "stackit_k8s"
namespace = var.namespace
user = kubernetes_service_account.forgejo_actions.metadata[0].name
}
}
]
}
kubeconfig = merge(local.stackit_kubeconfig_stub, local.kubeconfig_user)
provider "forgejo" {
# configured via env variables FORGEJO_HOST, FORGEJO_API_TOKEN
}

data "forgejo_repository" "this" {
name = var.forgejo_repository_name
owner = var.forgejo_repository_owner
provider "restapi" {
uri = data.external.repository_context.result.forgejo_host
write_returns_object = false

headers = {
Authorization = "token ${data.external.repository_context.result.forgejo_api_token}"
Content-Type = "application/json"
}
}

resource "forgejo_repository_action_secret" "kubeconfig" {
repository_id = data.forgejo_repository.this.id
name = "KUBECONFIG"
data = yamlencode(local.kubeconfig)
data "external" "repository_context" {
program = ["python3", "${path.module}/get_forgejo_repository_context.py"]

query = {
FORGEJO_REPOSITORY_ID = tostring(var.repository_id)
}
}

resource "forgejo_repository_action_secret" "container_registry" {
for_each = {
HOST = var.harbor_host
USERNAME = var.harbor_username
PASSWORD = var.harbor_password
locals {
repository_owner = data.external.repository_context.result.owner
repository_name = data.external.repository_context.result.name
repository_default_branch = data.external.repository_context.result.default_branch

action_secrets = {
"KUBECONFIG${var.repository_secret_name_suffix}" = yamlencode(merge(local.kubeconfig, {
current-context = local.kubeconfig_cluster_name

users = [
{
name = kubernetes_service_account.forgejo_actions.metadata[0].name
user = {
"token" = kubernetes_secret.forgejo_actions.data.token
}
}
]

contexts = [
{
name = local.kubeconfig_cluster_name
context = {
cluster = local.kubeconfig_cluster_name
namespace = var.namespace
user = kubernetes_service_account.forgejo_actions.metadata[0].name
}
}
]
}))
}

repository_id = data.forgejo_repository.this.id
name = "STACKIT_HARBOR_${each.key}"
data = each.value
action_variables = {
"K8S_NAMESPACE${var.repository_secret_name_suffix}" = var.namespace
}
}

resource "forgejo_repository_action_secret" "additional" {
for_each = var.additional_environment_variables
resource "forgejo_repository_action_secret" "action_secrets" {
for_each = local.action_secrets

repository_id = data.forgejo_repository.this.id
repository_id = var.repository_id
name = each.key
data = each.value
}
}

resource "restapi_object" "action_variables" {
for_each = local.action_variables

path = "/api/v1/repos/${local.repository_owner}/${local.repository_name}/actions/variables"
id_attribute = "name"
object_id = each.key
update_method = "PATCH"
data = jsonencode({
name = each.key
value = each.value
})
ignore_server_additions = true
}

resource "terraform_data" "await_pipeline_workflow" {
depends_on = [
forgejo_repository_action_secret.action_secrets,
restapi_object.action_variables,
]

provisioner "local-exec" {
command = "python3 ${path.module}/trigger_and_await_forgejo_workflow.py"
environment = {
FORGEJO_REPOSITORY_ID = tostring(var.repository_id)
FORGEJO_WORKFLOW_NAME = "pipeline.yaml"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env python3

import json
import os
import sys
import urllib.request


def normalize_host(raw_host: str) -> str:
host = raw_host.strip()
if not host.startswith(("https://", "http://")):
host = f"https://{host}"
return host.rstrip("/")


def main() -> None:
query = json.loads(sys.stdin.read())

forgejo_host = normalize_host(os.environ["FORGEJO_HOST"])
forgejo_api_token = os.environ["FORGEJO_API_TOKEN"]
repository_id = query["FORGEJO_REPOSITORY_ID"]

req = urllib.request.Request(
f"{forgejo_host}/api/v1/repositories/{repository_id}",
headers={"Authorization": f"token {forgejo_api_token}", "Content-Type": "application/json"},
method="GET",
)
with urllib.request.urlopen(req, timeout=30) as resp:
payload = json.loads(resp.read().decode("utf-8"))

print(
json.dumps(
{
"forgejo_host": forgejo_host,
"forgejo_api_token": forgejo_api_token,
"owner": payload["owner"]["username"],
"name": payload["name"],
"default_branch": payload.get("default_branch", "main"),
}
)
)


if __name__ == "__main__":
main()
18 changes: 18 additions & 0 deletions modules/ske/forgejo-connector/buildingblock/kubeconfig-mock.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This mock kubeconfig is only used as a fallback when kubeconfig.yaml is not
# injected by meshStack yet (e.g. local terraform validate).
current-context: mock-context
clusters:
- name: mock-cluster
cluster:
server: https://example.invalid # This must not be changed to avoid accidental usage via precondition check
certificate-authority-data: ""
users:
- name: mock-user
user:
client-certificate-data: ""
client-key-data: ""
contexts:
- name: mock-context
context:
cluster: mock-cluster
user: mock-user
Loading
Loading