diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ec50cd286e7b47974349d1a56c5007a19d99c58f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.tgz
+*.xpkg
+local
+argopw
+argowftoken
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3b2bfe14be500df86d195ea674951905791ac54
--- /dev/null
+++ b/README.md
@@ -0,0 +1,51 @@
+# Infrastructure Crossplane Provisioner
+This repository contains the resources required to setup the Infrastructure Provisioner. The required components are the following:
+
+ * [Crossplane](https://docs.crossplane.io/latest/)
+ * [ArgoCD](https://argo-cd.readthedocs.io/en/stable/)
+ * [Gitea](https://about.gitea.com/products/gitea/)
+ * [ArgoEvents](https://argoproj.github.io/argo-events/)
+ * [ArgoWorkflows](https://argoproj.github.io/workflows/)
+
+## Installation
+
+The installation uses [Helm](https://helm.sh/docs/intro/install/) and requires a running Kubernetes cluster.
+
+The two charts which need to be installed in the cluster:
+ * `dependencies` installs and configures the required k8s controllers and CRDs
+ * `resources` installs the required resources that implement provisioner logic
+
+In the dependencies chart, ensure the appropriate `storageClassName` is set for your cluster.
+In the resources chart, ensure the correct `kafkaEndpoint` is set.
+
+<b>Note: Currently, the charts have to be installed as-is with all their listed dependencies. Do not try to replace a dependency with one that you already have running, such as using an already existing gitea instance. Decoupling of dependencies is still a work in progress!</b>
+
+Before running helm install ensure that the following `secrets` are present:
+ * `ec-pull-secret` allows the installer or the argo workflows to pull the necessary images from code.europa.eu (EC_USERNAME: gitlab username, EC_PASSWORD: gitlab password or token)
+ * `ionos-provider` access token for the Ionos cloud API
+ * `gitea-secret` internal to the provisioner, used in the gitops process (will be removed in the future)
+```cmd
+NS=infrastructure
+kubectl create -n $NS secret docker-registry "ec-pull-secret"  --docker-server="code.europa.eu:4567" --docker-username="$EC_USERNAME" --docker-password="$EC_PASSWORD"
+kubectl create -n $NS secret generic ionos-provider --from-literal=credentials="{\"token\":\"${IONOS_TOKEN}\"}"
+kubectl create -n $NS secret generic gitea-secret --from-literal=username=gitops_test --from-literal=password=test1234
+```
+
+## Local setup
+
+#### To setup locally, install [KinD](https://kind.sigs.k8s.io/) to setup a local K8s cluster. Then run the `local-setup.sh` script to setup your environment.
+#### Accessing the UIs of the components:
+Retrieve initial admin password for ArgoCD and Auth Token for ArgoWorkflows
+```cmd
+NS=infrastructure
+echo "Bearer $(kubectl get -n $NS secret cli.service-account-token -o=jsonpath='{.data.token}' | base64 --decode)" > argowftoken
+kubectl get -n $NS secret argocd-initial-admin-secret  -o jsonpath="{.data.password}" | base64 -d > argopw
+```
+
+Port forward for each service
+```cmd
+NS=infrastructure
+kubectl port-forward -n $NS svc/argocd-server 8888:443
+kubectl port-forward -n $NS svc/argowf-argo-workflows-server 8777:2746
+kubectl port-forward -n $NS svc/gitea-http 8333:3000
+```
diff --git a/build_package.sh b/build_package.sh
new file mode 100644
index 0000000000000000000000000000000000000000..b1cc1a304273a8b821a9386ed7243bafc27170ca
--- /dev/null
+++ b/build_package.sh
@@ -0,0 +1,4 @@
+# Builds the crossplane configuration package image and pushes it to EC gitlab
+# VERSION=v0.3.7
+crossplane xpkg build -f package/ -e package/examples/ -o configuration-${VERSION}.xpkg --verbose
+crossplane xpkg push code.europa.eu:4567/simpl/simpl-open/development/infrastructure/infrastructure-crossplane/configuration:${VERSION} -f configuration-${VERSION}.xpkg --domain https://code.europa.eu
\ No newline at end of file
diff --git a/charts/dependencies/Chart.lock b/charts/dependencies/Chart.lock
new file mode 100644
index 0000000000000000000000000000000000000000..6a940d5f7df074ac417fdfebc331480f0ace7eba
--- /dev/null
+++ b/charts/dependencies/Chart.lock
@@ -0,0 +1,18 @@
+dependencies:
+- name: crossplane
+  repository: https://charts.crossplane.io/stable
+  version: 1.16.2
+- name: argo-cd
+  repository: https://argoproj.github.io/argo-helm
+  version: 6.7.13
+- name: argo-events
+  repository: https://argoproj.github.io/argo-helm
+  version: 2.4.8
+- name: argo-workflows
+  repository: https://argoproj.github.io/argo-helm
+  version: 0.42.5
+- name: gitea
+  repository: https://dl.gitea.com/charts
+  version: 10.4.1
+digest: sha256:45897c92d11fd234df71398dc2b5775f46a36c53bd4772f6d6ef9e54367013f6
+generated: "2024-12-10T23:20:09.55863639+02:00"
diff --git a/charts/dependencies/Chart.yaml b/charts/dependencies/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..55a22eb4f8949d42cd3b56c47ba5a7223636c07c
--- /dev/null
+++ b/charts/dependencies/Chart.yaml
@@ -0,0 +1,21 @@
+apiVersion: v2
+name: provisioner-dependencies
+description: Chart which installs dependencies for the Provisioner
+version: 0.1.0
+
+dependencies:
+  - name: crossplane
+    version: 1.16.2
+    repository: https://charts.crossplane.io/stable
+  - name: argo-cd
+    version: 6.7.13
+    repository: https://argoproj.github.io/argo-helm
+  - name: argo-events
+    version: 2.4.8
+    repository: https://argoproj.github.io/argo-helm
+  - name: argo-workflows
+    version: 0.42.5
+    repository: https://argoproj.github.io/argo-helm
+  - name: gitea
+    version: 10.4.1
+    repository: https://dl.gitea.com/charts
diff --git a/charts/dependencies/templates/post-install-cm.yaml b/charts/dependencies/templates/post-install-cm.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a74435860f4c97d4d0eda9b287ef687f307fa736
--- /dev/null
+++ b/charts/dependencies/templates/post-install-cm.yaml
@@ -0,0 +1,69 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ .Release.Name }}-postinstall-configmap
+data:
+  setup-gitea.sh: |
+    set -euo pipefail
+    apk add --no-cache curl
+    GITEA_HEALTH="http://{{ .Release.Name }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/api/healthz"
+    curl -v "$GITEA_HEALTH"
+
+    git config --global user.email "setup@helm-hook.kube";
+    git config --global user.name "${GIT_USER}";
+
+    DIR1="management-repo"
+    MGMT_REPO="http://${GIT_USER}:${GIT_PASSWORD}@{{ .Release.Name }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/management-repo.git"
+    echo "Creating directory: $DIR1"
+    mkdir -p "$DIR1"
+    cd "$DIR1"
+    git init
+    cp /postconfig/data-application-template.yaml .
+    mkdir applications
+    touch applications/.empty
+    git add data-application-template.yaml
+    git add applications
+    git commit -m "initialized $DIR1"
+    git remote add origin "$MGMT_REPO"
+    git branch -M master
+    git push -u origin master
+    cd ..
+
+    DIR2="data-repo"
+    DATA_REPO="http://${GIT_USER}:${GIT_PASSWORD}@{{ .Release.Name }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/data-repo.git"
+    echo "Creating directory: $DIR2"
+    mkdir -p "$DIR2"
+    cd "$DIR2"
+    git init
+    mkdir claims
+    touch claims/.empty
+    git add claims
+    git commit -m "initialized $DIR2"
+    git remote add origin "$DATA_REPO"
+    git branch -M master
+    git push -u origin master
+  data-application-template.yaml: |
+    apiVersion: argoproj.io/v1alpha1
+    kind: Application
+    metadata:
+        name: crossplane-claim-{UUID}
+        namespace: {{ .Release.Namespace }}
+        finalizers:
+            - resources-finalizer.argocd.argoproj.io
+        labels:
+            track-events: claim-application
+            claim-uuid: "{UUID}"
+            claim-kind: "{KIND}"
+    spec:
+        project: default
+        source:
+            repoURL: http://{{ .Release.Name }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/data-repo.git
+            path: claims/claim_{UUID}
+            targetRevision: master
+        destination:
+            server: https://kubernetes.default.svc
+        syncPolicy:
+            automated:
+                selfHeal: true
+                prune: true
+                allowEmpty: true
\ No newline at end of file
diff --git a/charts/dependencies/templates/post-install.yaml b/charts/dependencies/templates/post-install.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b36b294e4d39057f9c3e7e8dc92d7003ed157473
--- /dev/null
+++ b/charts/dependencies/templates/post-install.yaml
@@ -0,0 +1,36 @@
+# templates/post-install-job.yaml
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: post-install-job
+  annotations:
+    "helm.sh/hook": post-install
+    "helm.sh/hook-weight": "0"
+spec:
+  backoffLimit: 12
+  ttlSecondsAfterFinished: 600
+  template:
+    spec:
+      restartPolicy: Never
+      containers:
+      - name: script-runner
+        image: alpine/git:latest
+        command: ["/bin/sh", "/postconfig/setup-gitea.sh"]
+        env:
+        - name: GIT_USER
+          valueFrom:
+            secretKeyRef:
+              name: gitea-secret
+              key: username
+        - name: GIT_PASSWORD
+          valueFrom:
+            secretKeyRef:
+              name: gitea-secret
+              key: password
+        volumeMounts:
+        - name: postconfig-volume
+          mountPath: /postconfig
+      volumes:
+      - name: postconfig-volume
+        configMap:
+          name: {{ .Release.Name }}-postinstall-configmap
diff --git a/charts/dependencies/templates/pvc.yaml b/charts/dependencies/templates/pvc.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..50014ef6914aad419603f018768f0ef4cbdbcc44
--- /dev/null
+++ b/charts/dependencies/templates/pvc.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: PersistentVolumeClaim
+metadata:
+  name: gitea-pvc
+spec:
+  storageClassName: {{ .Values.gitea.storageClassName }}
+  accessModes:
+    - ReadWriteOnce
+  resources:
+    requests:
+      storage: {{ .Values.gitea.volumeSize }}
\ No newline at end of file
diff --git a/charts/dependencies/values.yaml b/charts/dependencies/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f9e8b9c00a5b55ce984b40f6b9f37031d1939b9a
--- /dev/null
+++ b/charts/dependencies/values.yaml
@@ -0,0 +1,230 @@
+crossplane:
+  imagePullSecrets: 
+    - ec-pull-secret
+  configuration:
+    packages:
+      - code.europa.eu:4567/simpl/simpl-open/development/infrastructure/infrastructure-crossplane/configuration:v0.3.6
+
+gitea:
+  # storageClassName: standard
+  storageClassName: csi-cinder-high-speed
+  volumeSize: 100G
+  service:
+    http:
+      type: ClusterIP
+      port: 3000
+  redis-cluster:
+    enabled: false
+  redis:
+    enabled: false
+  postgresql:
+    enabled: false
+  postgresql-ha:
+    enabled: false
+  persistence:
+    enabled: true
+    mount: true
+    create: false
+    claimName: gitea-pvc
+  gitea:
+    config:
+      APP_NAME: "Provisioner GIT Server"
+      repository:
+        ENABLE_PUSH_CREATE_USER: true
+        DEFAULT_PUSH_CREATE_PRIVATE: false
+      database:
+        DB_TYPE: sqlite3
+      session:
+        PROVIDER: memory
+      cache:
+        ADAPTER: db
+      queue:
+        TYPE: level
+    admin:
+      username: "gitops_test"
+      password: "test1234"
+      email: "test@gitops.email.com"
+
+argo-cd:
+  server:
+    extraArgs:
+      - --insecure
+    service:
+      type: ClusterIP
+  dex:
+    enabled: false
+  notifications:
+    enabled: false
+  applicationSet:
+    enabled: false
+  # Health check for crossplane MRs:
+  # https://docs.crossplane.io/latest/guides/crossplane-with-argo-cd/#set-health-status
+  configs:
+    cm:
+      timeout.reconciliation: 180s
+      application.resourceTrackingMethod: annotation
+      resource.exclusions: |
+        - apiGroups:
+          - "*"
+          kinds:
+          - ProviderConfigUsage
+          - XServerInstance
+      resource.customizations: |
+          "*.upbound.io/*":
+            health.lua: |
+              health_status = {
+                status = "Progressing",
+                message = "Provisioning ..."
+              }
+          
+              local function contains (table, val)
+                for i, v in ipairs(table) do
+                  if v == val then
+                    return true
+                  end
+                end
+                return false
+              end
+          
+              local has_no_status = {
+                "ProviderConfig",
+                "ProviderConfigUsage"
+              }
+          
+              if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
+                health_status.status = "Healthy"
+                health_status.message = "Resource is up-to-date."
+                return health_status
+              end
+          
+              if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
+                if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
+                  health_status.status = "Healthy"
+                  health_status.message = "Resource is in use."
+                  return health_status
+                end
+                return health_status
+              end
+          
+              for i, condition in ipairs(obj.status.conditions) do
+                if condition.type == "LastAsyncOperation" then
+                  if condition.status == "False" then
+                    health_status.status = "Degraded"
+                    health_status.message = condition.message
+                    return health_status
+                  end
+                end
+          
+                if condition.type == "Synced" then
+                  if condition.status == "False" then
+                    health_status.status = "Degraded"
+                    health_status.message = condition.message
+                    return health_status
+                  end
+                end
+          
+                if condition.type == "Ready" then
+                  if condition.status == "True" then
+                    health_status.status = "Healthy"
+                    health_status.message = "Resource is up-to-date."
+                    return health_status
+                  end
+                  health_status.message = condition.reason
+                end
+              end
+          
+              return health_status
+          
+          "*.crossplane.io/*":
+            health.lua: |
+              health_status = {
+                status = "Progressing",
+                message = "Provisioning ..."
+              }
+
+              local function contains (table, val)
+                for i, v in ipairs(table) do
+                  if v == val then
+                    return true
+                  end
+                end
+                return false
+              end
+          
+              local has_no_status = {
+                "Composition",
+                "CompositionRevision",
+                "DeploymentRuntimeConfig",
+                "ControllerConfig",
+                "ProviderConfig",
+                "ProviderConfigUsage"
+              }
+              if obj.status == nil or next(obj.status) == nil and contains(has_no_status, obj.kind) then
+                  health_status.status = "Healthy"
+                  health_status.message = "Resource is up-to-date."
+                return health_status
+              end
+          
+              if obj.status == nil or next(obj.status) == nil or obj.status.conditions == nil then
+                if obj.kind == "ProviderConfig" and obj.status.users ~= nil then
+                  health_status.status = "Healthy"
+                  health_status.message = "Resource is in use."
+                  return health_status
+                end
+                return health_status
+              end
+          
+              for i, condition in ipairs(obj.status.conditions) do
+                if condition.type == "LastAsyncOperation" then
+                  if condition.status == "False" then
+                    health_status.status = "Degraded"
+                    health_status.message = condition.message
+                    return health_status
+                  end
+                end
+          
+                if condition.type == "Synced" then
+                  if condition.status == "False" then
+                    health_status.status = "Degraded"
+                    health_status.message = condition.message
+                    return health_status
+                  end
+                end
+          
+                if contains({"Ready", "Healthy", "Offered", "Established"}, condition.type) then
+                  if condition.status == "True" then
+                    health_status.status = "Healthy"
+                    health_status.message = "Resource is up-to-date."
+                    return health_status
+                  end
+                end
+              end
+          
+              return health_status
+
+          "*.example.org/*":
+            health.lua: |
+              health_status = {
+                status = "Progressing",
+                message = "Provisioning of resources in progress."
+              }
+
+              if obj.status == nil or next(obj.status) == nil then
+                return health_status
+              end
+
+              for i, condition in ipairs(obj.status.conditions) do
+                if condition.type == "Ready" then
+                  if condition.status == "True" then
+                    health_status.status = "Healthy"
+                    health_status.message = "Provisioning finalized successfully."
+                    return health_status
+                  end
+                  if condition.message ~= nil then
+                    health_status.message = condition.message
+                  end
+                  return health_status
+                end
+              end
+          
+              return health_status
\ No newline at end of file
diff --git a/charts/resources/Chart.yaml b/charts/resources/Chart.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c64cb7aa1befc6c88f134206835b9915405fc8b9
--- /dev/null
+++ b/charts/resources/Chart.yaml
@@ -0,0 +1,4 @@
+apiVersion: v2
+name: provisioner-resources
+description: Chart which installs resources of the Provisioner
+version: 0.1.0
diff --git a/charts/resources/templates/claim-manager.yaml b/charts/resources/templates/claim-manager.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2e245634f98786cd108861f205be452a9d25dd01
--- /dev/null
+++ b/charts/resources/templates/claim-manager.yaml
@@ -0,0 +1,21 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+  name: claim-manager
+  finalizers:
+    - resources-finalizer.argocd.argoproj.io
+spec:
+  project: default
+  source:
+    repoURL: http://{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace}}.svc.cluster.local:3000/gitops_test/management-repo.git
+    path: applications
+    targetRevision: master
+    directory:
+      recurse: true
+  destination:
+    server: https://kubernetes.default.svc
+  syncPolicy:
+    automated:
+      selfHeal: true
+      prune: true
+      allowEmpty: true
\ No newline at end of file
diff --git a/charts/resources/templates/cli.yaml b/charts/resources/templates/cli.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..dab3b7759ecfbb9a7ec2c011ff2c91b5d918a790
--- /dev/null
+++ b/charts/resources/templates/cli.yaml
@@ -0,0 +1,187 @@
+{{- if .Values.cliEnabled }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: cli
+  namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: cli
+  namespace: {{ .Release.Namespace }}
+rules:
+  - apiGroups:
+      - coordination.k8s.io
+    resources:
+      - leases
+    verbs:
+      - create
+      - get
+      - update
+  - apiGroups:
+      - ""
+    resources:
+      - pods
+      - pods/exec
+    verbs:
+      - create
+      - get
+      - list
+      - watch
+      - update
+      - patch
+      - delete
+  - apiGroups:
+      - ""
+    resources:
+      - configmaps
+    verbs:
+      - get
+      - watch
+      - list
+  - apiGroups:
+      - ""
+    resources:
+      - persistentvolumeclaims
+      - persistentvolumeclaims/finalizers
+    verbs:
+      - create
+      - update
+      - delete
+      - get
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - workflows
+      - workflows/finalizers
+      - workflowtasksets
+      - workflowtasksets/finalizers
+      - workflowartifactgctasks
+    verbs:
+      - get
+      - list
+      - watch
+      - update
+      - patch
+      - delete
+      - create
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - workflowtemplates
+      - workflowtemplates/finalizers
+    verbs:
+      - get
+      - list
+      - watch
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - workflowtaskresults
+    verbs:
+      - list
+      - watch
+      - deletecollection
+  - apiGroups:
+      - ""
+    resources:
+      - serviceaccounts
+    verbs:
+      - get
+      - list
+  - apiGroups:
+      - ""
+    resources:
+      - secrets
+    verbs:
+      - get
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - cronworkflows
+      - cronworkflows/finalizers
+    verbs:
+      - get
+      - list
+      - watch
+      - update
+      - patch
+      - delete
+  - apiGroups:
+      - ""
+    resources:
+      - events
+    verbs:
+      - create
+      - patch
+  - apiGroups:
+      - "policy"
+    resources:
+      - poddisruptionbudgets
+    verbs:
+      - create
+      - get
+      - delete
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: cli
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: cli
+subjects:
+- kind: ServiceAccount
+  name: cli
+  namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: operate-workflow-role
+  namespace: {{ .Release.Namespace }}
+rules:
+  - apiGroups:
+      - argoproj.io
+    verbs:
+      - "*"
+    resources:
+      - workflows
+      - workflowtemplates
+      - cronworkflows
+      - clusterworkflowtemplates
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: operate-workflow-role-binding
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: operate-workflow-role
+subjects:
+  - kind: ServiceAccount
+    name: {{ .Values.workflowOperatorSA }}
+    namespace: {{ .Release.Namespace }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  namespace: {{ .Release.Namespace }}
+  name: cli.service-account-token
+  annotations:
+    kubernetes.io/service-account.name: cli
+type: kubernetes.io/service-account-token
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: argocli.service-account-token
+  annotations:
+    kubernetes.io/service-account.name: argocli
+type: kubernetes.io/service-account-token
+{{- end }}
\ No newline at end of file
diff --git a/charts/resources/templates/crossplane/provider-ionos-config.yaml b/charts/resources/templates/crossplane/provider-ionos-config.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1d8795fc5a9e1f1131c6be3b48d3210e2c6ccb62
--- /dev/null
+++ b/charts/resources/templates/crossplane/provider-ionos-config.yaml
@@ -0,0 +1,12 @@
+apiVersion: ionoscloud.crossplane.io/v1alpha1
+kind: ProviderConfig
+metadata:
+  name: example
+  namespace: {{ .Release.Namespace }}
+spec:
+  credentials:
+    source: Secret
+    secretRef:
+      namespace: {{ .Release.Namespace }}
+      name: ionos-provider
+      key: credentials
diff --git a/charts/resources/templates/events/decommission/sensor.yaml b/charts/resources/templates/events/decommission/sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ca7506e5f8cde91999f2a38b9738fad21c39c702
--- /dev/null
+++ b/charts/resources/templates/events/decommission/sensor.yaml
@@ -0,0 +1,110 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: decommission
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  template:
+    serviceAccountName: {{ .Values.workflowOperatorSA }}
+  dependencies:
+    - name: message
+      eventSourceName: decommission
+      eventName: decommissionRequest
+  triggers:
+    - template:
+        name: argo-workflow-trigger
+        argoWorkflow:
+          operation: submit
+          source:
+            resource:
+              apiVersion: argoproj.io/v1alpha1
+              kind: Workflow
+              metadata:
+                generateName: decommission-gitops-
+                namespace: {{ .Release.Namespace }}
+              spec:
+                podGC:
+                  strategy: OnWorkflowSuccess
+                  deleteDelayDuration: 120s
+                imagePullSecrets:
+                  - name: ec-pull-secret
+                volumes:
+                  - name: repos
+                    emptyDir: {}
+                serviceAccountName: cli
+                entrypoint: main
+                workflowMetadata:
+                  labels:
+                    track-workflow: "true"
+                    workflow-type: to-decommission
+                  labelsFrom:
+                    scriptTriggerId:
+                      expression: workflow.parameters.scriptTriggerId
+                arguments:
+                  parameters:
+                    - name: scriptTriggerId
+                      value: default-is-overriden
+                templates:
+                  - name: main
+                    inputs:
+                      artifacts:
+                        - name: data-repo
+                          path: repos/data
+                          git:
+                            repo: http://{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/data-repo.git
+                            revision: "master"
+                        - name: management-repo
+                          path: /repos/management
+                          git:
+                            repo: http://{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/management-repo.git
+                            revision: "master"
+                      parameters:
+                        - name: scriptTriggerId
+                          value: {{`"'{{workflow.parameters.scriptTriggerId}}'"`}}
+                    script:
+                      image: alpine/git:v2.45.2
+                      env:
+                        - name: GIT_USER
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: username
+                        - name: GIT_PASSWORD
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: password
+                      command: [sh, -c]
+                      args: ['
+                          echo --- decommissioning request with ID: {{`{{inputs.parameters.scriptTriggerId}}`}};
+                          echo ---ls ../work---;
+                          ls;
+                          echo ---ls ../repos---;
+                          ls ../repos;
+                          git config --global user.email "workflow@argo.kube";
+                          git config --global user.name "gitops_test";
+                          echo ---commit data changes---;
+                          git -C ../repos/data checkout master;
+                          git -C ../repos/data rm -r claims/claim_{{`{{inputs.parameters.scriptTriggerId}}`}};
+                          git -C ../repos/data commit -v -m "Remove claim_{{`{{inputs.parameters.scriptTriggerId}}`}}";
+                          git -C ../repos/data push http://$GIT_USER:$GIT_PASSWORD@{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/data-repo.git;
+                          echo ---commit management changes---;
+                          git -C ../repos/management checkout master;
+                          git -C ../repos/management rm -r applications/application_{{`{{inputs.parameters.scriptTriggerId}}`}};
+                          git -C ../repos/management commit -v -m "Remove application_{{`{{inputs.parameters.scriptTriggerId}}`}}";
+                          git -C ../repos/management push http://$GIT_USER:$GIT_PASSWORD@{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/management-repo.git;
+                        ']
+                      volumeMounts:
+                        - name: repos
+                          mountPath: /repos
+                      workingDir: /work
+          parameters:
+            - src:
+                dependencyName: message
+                dataKey: headers.scriptTriggerId
+                value: ""
+              dest: spec.arguments.parameters.0.value
+      retryStrategy:
+        steps: 2
+        duration: 30s
\ No newline at end of file
diff --git a/charts/resources/templates/events/decommission/source.yaml b/charts/resources/templates/events/decommission/source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d005e94709f32aa325440df80d1e007d8640a2dd
--- /dev/null
+++ b/charts/resources/templates/events/decommission/source.yaml
@@ -0,0 +1,28 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: decommission
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  kafka:
+    decommissionRequest:
+      url: {{ .Values.kafkaEndpoint }}
+      topic: to-decommission
+      jsonBody: false
+      partition: "0"
+      {{- if .Values.kafkaAuth.enable }}
+      sasl:
+        mechanism: {{ .Values.kafkaAuth.mechanism }}
+        userSecret:
+          name: {{ .Values.kafkaAuth.secretName }}
+          key: username
+        passwordSecret:
+          name: {{ .Values.kafkaAuth.secretName }}
+          key: password
+      {{- end }}
+      connectionBackoff:
+        duration: 10s
+        steps: 3
+        factor: 1
+        jitter: 0.2
\ No newline at end of file
diff --git a/charts/resources/templates/events/decommission/status-sensor.yaml b/charts/resources/templates/events/decommission/status-sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fbd61f637ac36afad9760fa17080e3825b258790
--- /dev/null
+++ b/charts/resources/templates/events/decommission/status-sensor.yaml
@@ -0,0 +1,42 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: decommission-status
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  dependencies:
+    - name: message
+      eventSourceName: decommission-status
+      eventName: decommissionStatus
+  triggers:
+    - template:
+        name: kafka
+        kafka:
+          url: {{ .Values.kafkaEndpoint }}
+          topic: decommissioned
+          {{- if .Values.kafkaAuth.enable }}
+          sasl:
+            mechanism: {{ .Values.kafkaAuth.mechanism }}
+            userSecret:
+              name: {{ .Values.kafkaAuth.secretName }}
+              key: username
+            passwordSecret:
+              name: {{ .Values.kafkaAuth.secretName }}
+              key: password
+          {{- end }}
+          payload:
+            - src:
+                dependencyName: message
+                dataKey: body.metadata.labels.claim-uuid
+                value: ""
+              dest: scriptTriggerId
+            - src:
+                dependencyName: message
+                value: "Succeeded"
+              dest: status
+            - src:
+                dependencyName: message
+                dataKey: body.metadata.deletionTimestamp
+                value: ""
+              dest: deletionTimestamp
\ No newline at end of file
diff --git a/charts/resources/templates/events/decommission/status-source.yaml b/charts/resources/templates/events/decommission/status-source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cd136e742856549e1ae621f277114cc4e1da9e35
--- /dev/null
+++ b/charts/resources/templates/events/decommission/status-source.yaml
@@ -0,0 +1,24 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: decommission-status
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  template:
+    serviceAccountName: {{ .Values.applicationStatusViewerSA }}
+  resource:
+    decommissionStatus:
+      namespace: {{ .Release.Namespace }}
+      group: argoproj.io
+      version: v1alpha1
+      resource: applications
+      eventTypes:
+        - DELETE
+      filter:
+        afterStart: true
+        labels:
+          - key: track-events
+            operation: "=="
+            value: "claim-application"
+
diff --git a/charts/resources/templates/events/eventbus.yaml b/charts/resources/templates/events/eventbus.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..abf1475325bd70d5055844e28a79fabee5ef3fb7
--- /dev/null
+++ b/charts/resources/templates/events/eventbus.yaml
@@ -0,0 +1,10 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventBus
+metadata:
+  name: provisioner-eventbus
+  namespace: {{ .Release.Namespace }}
+spec:
+  nats:
+    native:
+      replicas: 2
+      auth: token
diff --git a/charts/resources/templates/events/provision/gitops-status-sensor.yaml b/charts/resources/templates/events/provision/gitops-status-sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4dfb54db706c5ca95a900901b619aab3e9fa1ce5
--- /dev/null
+++ b/charts/resources/templates/events/provision/gitops-status-sensor.yaml
@@ -0,0 +1,54 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: provision-gitops
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  dependencies:
+    - name: gitops-status
+      eventSourceName: provision-gitops
+      eventName: provisionGitops
+  triggers:
+    - template:
+        name: kafka
+        kafka:
+          url: {{ .Values.kafkaEndpoint }}
+          topic: provisioned
+          partition: 0
+          {{- if .Values.kafkaAuth.enable }}
+          sasl:
+            mechanism: {{ .Values.kafkaAuth.mechanism }}
+            userSecret:
+              name: {{ .Values.kafkaAuth.secretName }}
+              key: username
+            passwordSecret:
+              name: {{ .Values.kafkaAuth.secretName }}
+              key: password
+          {{- end }}
+          payload:
+            - src:
+                dependencyName: gitops-status
+                dataKey: body.metadata.name
+                value: "None"
+              dest: name
+            - src:
+                dependencyName: gitops-status
+                dataKey: "body.metadata.labels.workflows\\.argoproj\\.io/phase"
+                value: "Unknown"
+              dest: phase
+            - src:
+                dependencyName: gitops-status
+                dataKey: "body.metadata.labels.workflows\\.argoproj\\.io/completed"
+                value: "false"
+              dest: completed
+            - src:
+                dependencyName: gitops-status
+                dataKey: "body.metadata.labels.scriptTriggerId"
+                value: ""
+              dest: scriptTriggerId
+            - src:
+                dependencyName: gitops-status
+                dataKey: body.status.message
+                value: ""
+              dest: message
\ No newline at end of file
diff --git a/charts/resources/templates/events/provision/gitops-status-source.yaml b/charts/resources/templates/events/provision/gitops-status-source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c1b0fe4580714f683cac5d68b60bcfc396469d75
--- /dev/null
+++ b/charts/resources/templates/events/provision/gitops-status-source.yaml
@@ -0,0 +1,27 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: provision-gitops
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  template:
+    serviceAccountName: {{ .Values.workflowOperatorSA }}
+  resource:
+    provisionGitops:
+      namespace: {{ .Release.Namespace }}
+      group: argoproj.io
+      version: v1alpha1
+      resource: workflows
+      eventTypes:
+        - ADD
+        - UPDATE
+      filter:
+        afterStart: true
+        labels:
+          - key: track-workflow
+            operation: "=="
+            value: "true"
+          - key: workflow-type
+            operation: "=="
+            value: provision-gitops
diff --git a/charts/resources/templates/events/provision/sensor.yaml b/charts/resources/templates/events/provision/sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..704cc81550aa27b7456d91b7bf47898671b907ed
--- /dev/null
+++ b/charts/resources/templates/events/provision/sensor.yaml
@@ -0,0 +1,126 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: provision
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  template:
+    serviceAccountName: {{ .Values.workflowOperatorSA }}
+  dependencies:
+    - name: message
+      eventSourceName: provision
+      eventName: provisionRequest
+  triggers:
+    - template:
+        name: argo-workflow-trigger
+        argoWorkflow:
+          operation: submit
+          source:
+            resource:
+              apiVersion: argoproj.io/v1alpha1
+              kind: Workflow
+              metadata:
+                generateName: provision-gitops-
+                namespace: {{ .Release.Namespace }}
+              spec:
+                podGC:
+                  strategy: OnWorkflowSuccess
+                  deleteDelayDuration: 30s
+                imagePullSecrets:
+                  - name: ec-pull-secret
+                volumes:
+                  - name: repos
+                    emptyDir: {}
+                serviceAccountName: cli
+                entrypoint: main
+                workflowMetadata:
+                  labels:
+                    track-workflow: "true"
+                    workflow-type: provision-gitops
+                  labelsFrom:
+                    scriptTriggerId:
+                      expression: workflow.parameters.scriptTriggerId
+                arguments:
+                  parameters:
+                    - name: headers
+                      value: default-is-overriden
+                    - name: scriptTriggerId
+                      value: default-is-overriden
+                    - name: body
+                      value: default-is-overriden
+                templates:
+                  - name: main
+                    inputs:
+                      artifacts:
+                        - name: data-repo
+                          path: repos/data
+                          git:
+                            repo: http://{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/data-repo.git
+                            revision: "master"
+                        - name: management-repo
+                          path: /repos/management
+                          git:
+                            repo: http://{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/management-repo.git
+                            revision: "master"
+                      parameters:
+                        - name: headers
+                          value: {{`"'{{workflow.parameters.headers}}'"`}}
+                        - name: scriptTriggerId
+                          value: {{`"'{{workflow.parameters.scriptTriggerId}}'"`}}
+                        - name: body
+                          value: {{`"'{{workflow.parameters.body}}'"`}}
+                    container:
+                      image: code.europa.eu:4567/simpl/simpl-open/development/infrastructure/infrastructure-crossplane/to-provision-workflow:v0.2.1
+                      env:
+                        - name: GIT_USER
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: username
+                        - name: GIT_PASSWORD
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: password
+                      command: [sh, -c]
+                      args: ['
+                          echo --- provisioning request with ID: {{`{{inputs.parameters.scriptTriggerId}}`}};
+                          echo ---ls ../work---;
+                          ls;
+                          echo ---ls ../repos---;
+                          ls ../repos;
+                          python doesntexist.py;
+                          python main.py {{`{{inputs.parameters.scriptTriggerId}}`}} {{`{{inputs.parameters.body}}`}} || exit $?;
+                          git config --global user.email "workflow@argo.kube";
+                          git config --global user.name "gitops_test";
+                          echo ---commit data changes---;
+                          git -C ../repos/data checkout master;
+                          git -C ../repos/data/claims add -A && git -C ../repos/data commit -m "add UUID {{`{{inputs.parameters.scriptTriggerId}}`}}";
+                          git -C ../repos/data push http://$GIT_USER:$GIT_PASSWORD@{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/data-repo.git;
+                          echo ---commit management changes---;
+                          git -C ../repos/management checkout master;
+                          git -C ../repos/management/applications add -A && git -C ../repos/management commit -m "add UUID {{`{{inputs.parameters.scriptTriggerId}}`}}";
+                          git -C ../repos/management push http://$GIT_USER:$GIT_PASSWORD@{{ .Values.dependenciesReleaseName }}-gitea-http.{{ .Release.Namespace }}.svc.cluster.local:3000/gitops_test/management-repo.git;
+                        ']
+                      volumeMounts:
+                        - name: repos
+                          mountPath: /repos
+                      workingDir: /work
+          parameters:
+            - src:
+                dependencyName: message
+                dataKey: headers
+              dest: spec.arguments.parameters.0.value
+            - src:
+                dependencyName: message
+                dataKey: headers.scriptTriggerId
+                value: dummy
+              dest: spec.arguments.parameters.1.value
+            - src:
+                dependencyName: message
+                dataKey: body
+              dest: spec.arguments.parameters.2.value
+      retryStrategy:
+        steps: 2
+        duration: 30s
\ No newline at end of file
diff --git a/charts/resources/templates/events/provision/source.yaml b/charts/resources/templates/events/provision/source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fd56ff4c6078aa76e122b32317493a017118e96c
--- /dev/null
+++ b/charts/resources/templates/events/provision/source.yaml
@@ -0,0 +1,28 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: provision
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  kafka:
+    provisionRequest:
+      url: {{ .Values.kafkaEndpoint }}
+      topic: to-provision
+      jsonBody: false
+      partition: "0"
+      {{- if .Values.kafkaAuth.enable }}
+      sasl:
+        mechanism: {{ .Values.kafkaAuth.mechanism }}
+        userSecret:
+          name: {{ .Values.kafkaAuth.secretName }}
+          key: username
+        passwordSecret:
+          name: {{ .Values.kafkaAuth.secretName }}
+          key: password
+      {{- end }}
+      connectionBackoff:
+        duration: 10s
+        steps: 3
+        factor: 1
+        jitter: 0.2
\ No newline at end of file
diff --git a/charts/resources/templates/events/provision/status-sensor.yaml b/charts/resources/templates/events/provision/status-sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..349feb598229ea3d4405c999596ca8964c04cd81
--- /dev/null
+++ b/charts/resources/templates/events/provision/status-sensor.yaml
@@ -0,0 +1,199 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: provision-status
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  template:
+    serviceAccountName: {{ .Values.workflowOperatorSA }}
+  dependencies:
+    - name: message
+      eventSourceName: provision-status
+      eventName: provisionStatus
+  triggers:
+    - template:
+        name: argo-workflow-trigger
+        argoWorkflow:
+          operation: submit
+          source:
+            resource:
+              apiVersion: argoproj.io/v1alpha1
+              kind: Workflow
+              metadata:
+                generateName: provision-status-
+                namespace: {{ .Release.Namespace }}
+              spec:
+                podGC:
+                  strategy: OnPodCompletion
+                  deleteDelayDuration: 120s
+                serviceAccountName: cli
+                entrypoint: main
+                workflowMetadata:
+                arguments:
+                  parameters:
+                    - name: body
+                      value: default-is-overriden
+                templates:
+                  - name: main
+                    steps:
+                      - - name: validate
+                          template: validate-status
+                          arguments:
+                            parameters:
+                              - name: message
+                                value: "{{`{{workflow.parameters.body}}`}}"
+                      - - name: label
+                          template: done-label
+                          arguments:
+                            parameters:
+                              - name: UUID
+                                value: "{{`{{steps.validate.outputs.result}}`}}"
+                      - - name: parse-application
+                          template: parse-application
+                          arguments:
+                            parameters:
+                              - name: resource
+                                value: "{{`{{steps.label.outputs.parameters.application-resource}}`}}"
+                      - - name: parse-claim
+                          template: parse-claim
+                          arguments:
+                            parameters:
+                              - name: claim-reference
+                                value: "{{`{{steps.parse-application.outputs.result}}`}}"
+                      - - name: payload
+                          template: payload
+                          arguments:
+                            parameters:
+                              - name: resource
+                                value: "{{`{{steps.parse-claim.outputs.parameters.claim-resource}}`}}"
+                      - - name: message
+                          template: message
+                          arguments:
+                            parameters:
+                              - name: payload
+                                value: "{{`{{steps.payload.outputs.result}}`}}"
+                  - name: validate-status
+                    inputs:
+                      parameters:
+                        - name: message
+                    script:
+                      image: python:alpine3.10
+                      command: [python]
+                      source: |
+                        import json
+                        rawstr = r'''{{`{{inputs.parameters.message}}`}}'''
+                        d = json.loads(rawstr)
+                        try:
+                          app_status = d['status']
+                          app_meta = d['metadata']
+                          app_health = app_status['health']['status']
+                          app_sync = app_status['sync']['status']
+                          # Application only tracks the Claim, so one resource should be present
+                          claim = app_status['resources'][0]
+                          claim_health = claim['health']['status']
+                          claim_sync = claim['status']
+                          claim_id = app_meta['labels']['claim-uuid']
+                          assert app_health == "Healthy" and claim_health == "Healthy" and app_sync == "Synced" and claim_sync == "Synced"
+                          print(f"{claim_id}")
+                        except (KeyError, IndexError):
+                          raise ValueError("Not all status fields available")
+                  - name: done-label
+                    inputs:
+                      parameters:
+                        - name: UUID
+                    script:
+                      image: bitnami/kubectl:latest
+                      command: [sh]
+                      source: |
+                        echo "patching application with label claim-uuid:{{`{{inputs.parameters.UUID}}`}}"
+                        kubectl label -n {{ .Release.Namespace }} applications crossplane-claim-{{`{{inputs.parameters.UUID}}`}} provisioning-status="finalized"
+                        kubectl get -n {{ .Release.Namespace }} applications --selector=claim-uuid={{`{{inputs.parameters.UUID}}`}} -o json > /tmp/resource.json
+                    outputs:
+                      parameters:
+                        - name: application-resource
+                          valueFrom:
+                            path: /tmp/resource.json
+                  - name: parse-application
+                    inputs:
+                      parameters:
+                        - name: resource
+                    script:
+                      image: python:alpine3.10
+                      command: [python]
+                      source: |
+                          import json
+                          rawstr = r'''{{`{{inputs.parameters.resource}}`}}'''
+                          d = json.loads(rawstr)
+                          claim_kind = d['items'][0]['metadata']['labels']['claim-kind']
+                          claim_selector = d['items'][0]['metadata']['labels']['claim-uuid']
+                          print(f"{claim_kind} --selector=uuid={claim_selector}")
+                  - name: parse-claim
+                    inputs:
+                      parameters:
+                        - name: claim-reference
+                    script:
+                      image: bitnami/kubectl:latest
+                      command: [sh]
+                      source: |
+                        kubectl get -n {{ .Release.Namespace }} {{`{{inputs.parameters.claim-reference}}`}}
+                        kubectl get -n {{ .Release.Namespace }} -o json {{`{{inputs.parameters.claim-reference}}`}} > /tmp/resource.json
+                    outputs:
+                      parameters:
+                        - name: claim-resource
+                          valueFrom:
+                            path: /tmp/resource.json
+                  - name: payload
+                    inputs:
+                      parameters:
+                        - name: resource
+                    script:
+                      image: python:alpine3.10
+                      command: [python]
+                      source: |
+                        import json
+                        rawstr = r'''{{`{{inputs.parameters.resource}}`}}'''
+                        d = json.loads(rawstr)
+                        payload = {}
+                        payload["vmIps"] = d["items"][0]["status"]["vmIps"]
+                        payload["status"] = "Provisioning finalized successfully"
+                        payload["scriptTriggerId"] = d["items"][0]["metadata"]["labels"]["uuid"]
+                        print(json.dumps(payload).replace('"', '\\"'))
+                  - name: message
+                    inputs:
+                      parameters:
+                        - name: payload
+                    script:
+                      {{- if .Values.kafkaAuth.enable }}
+                      env:
+                        - name: MECHANISM
+                          value: {{ .Values.kafkaAuth.mechanism }}
+                        - name: USERNAME
+                          valueFrom:
+                            secretKeyRef:
+                              name: {{ .Values.kafkaAuth.secretName }}
+                              key: username
+                        - name: PASSWORD
+                          valueFrom:
+                            secretKeyRef:
+                              name: {{ .Values.kafkaAuth.secretName }}
+                              key: password
+                      {{- end }}
+                      image: confluentinc/cp-kafkacat:7.1.14
+                      command: [sh]
+                      {{- if .Values.kafkaAuth.enable }}
+                      source: |
+                        echo {{`{{inputs.parameters.payload}}`}} | kafkacat -P -b {{ .Values.kafkaEndpoint }} -X security.protocol=SASL_PLAINTEXT -X sasl.username="$USERNAME" -X sasl.password="$PASSWORD" -X sasl.mechanism="$MECHANISM" -t provisioned -J
+                      {{- else }}
+                      source: |
+                        echo {{`{{inputs.parameters.payload}}`}} | kafkacat -P -b {{ .Values.kafkaEndpoint }} -t provisioned -J
+                      {{- end }}
+                      
+          parameters:
+            - src:
+                dependencyName: message
+                dataKey: body
+              dest: spec.arguments.parameters.0.value
+      retryStrategy:
+        steps: 2
+        duration: 30s
\ No newline at end of file
diff --git a/charts/resources/templates/events/provision/status-source.yaml b/charts/resources/templates/events/provision/status-source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f47ede78a87c20140743e8c974e1620aadf712c7
--- /dev/null
+++ b/charts/resources/templates/events/provision/status-source.yaml
@@ -0,0 +1,27 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: provision-status
+  namespace: {{ .Release.Namespace }}
+spec:
+  eventBusName: provisioner-eventbus
+  template:
+    serviceAccountName: {{ .Values.applicationStatusViewerSA }}
+  resource:
+    provisionStatus:
+      namespace: {{ .Release.Namespace }}
+      group: argoproj.io
+      version: v1alpha1
+      resource: applications
+      eventTypes:
+        - UPDATE
+      filter:
+        afterStart: true
+        labels:
+          - key: track-events
+            operation: "=="
+            value: "claim-application"
+          - key: provisioning-status
+            operation: "!="
+            value: "finalized"
+
diff --git a/charts/resources/templates/rbac.yaml b/charts/resources/templates/rbac.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c4e53db5d395cf1e25e42aefd18ec678817e6bbe
--- /dev/null
+++ b/charts/resources/templates/rbac.yaml
@@ -0,0 +1,77 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: view-application
+  namespace: {{ .Release.Namespace }}
+rules:
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - applications
+    verbs:
+      - list
+      - get
+      - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: patch-application
+  namespace: {{ .Release.Namespace }}
+rules:
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - applications
+    verbs:
+      - patch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: view-application
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: view-application
+subjects:
+- kind: ServiceAccount
+  name: claim-application-status
+  namespace: {{ .Release.Namespace }}
+- kind: ServiceAccount
+  name: operate-workflow
+  namespace: {{ .Release.Namespace }}
+- kind: ServiceAccount
+  name: cli
+  namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: patch-application
+  namespace: {{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: patch-application
+subjects:
+- kind: ServiceAccount
+  name: cli
+  namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: view-composite-status-events
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: crossplane-view
+subjects:
+  - kind: ServiceAccount
+    name: composite-status
+    namespace: {{ .Release.Namespace }}
+  - kind: ServiceAccount
+    name: cli
+    namespace: {{ .Release.Namespace }}
\ No newline at end of file
diff --git a/charts/resources/templates/service-account.yaml b/charts/resources/templates/service-account.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f70a04a34d5ec16b40a7fd9ea99286615e373121
--- /dev/null
+++ b/charts/resources/templates/service-account.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Values.workflowOperatorSA }}
+  namespace: {{ .Release.Namespace }}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ .Values.applicationStatusViewerSA }}
+  namespace: {{ .Release.Namespace }}
diff --git a/charts/resources/values.yaml b/charts/resources/values.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5941d462ee643e22a414afa4c55611eab50caf86
--- /dev/null
+++ b/charts/resources/values.yaml
@@ -0,0 +1,10 @@
+workflowOperatorSA: operate-workflow
+applicationStatusViewerSA: claim-application-status
+cliEnabled: true
+dependenciesReleaseName: provisioner-dependencies
+# kafkaEndpoint: kafka:9092
+kafkaEndpoint: kafka.infrastructure.dev.simpl-europe.eu:9092
+kafkaAuth:
+  enable: true
+  mechanism: PLAIN
+  secretName: kafka-secret
\ No newline at end of file
diff --git a/k8s/argocd-claim-manager.yaml b/k8s/argocd-claim-manager.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7e8154a2503bb87b77193f4810b3310d66236366
--- /dev/null
+++ b/k8s/argocd-claim-manager.yaml
@@ -0,0 +1,21 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Application
+metadata:
+  name: claim-management
+  finalizers:
+    - resources-finalizer.argocd.argoproj.io
+spec:
+  project: default
+  source:
+    repoURL: http://gitea-http.gitea.svc.cluster.local:3000/gitops_test/management-repo.git
+    path: applications
+    targetRevision: master
+    directory:
+      recurse: true
+  destination:
+    server: https://kubernetes.default.svc
+  syncPolicy:
+    automated:
+      selfHeal: true
+      prune: true
+      allowEmpty: true
\ No newline at end of file
diff --git a/k8s/crossplane-configuration.yaml b/k8s/crossplane-configuration.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f488bf227ce1b8608a319a599a2020b2571a461e
--- /dev/null
+++ b/k8s/crossplane-configuration.yaml
@@ -0,0 +1,10 @@
+apiVersion: pkg.crossplane.io/v1
+kind: Configuration
+metadata:
+  name: demo
+spec:
+  package: code.europa.eu:4567/simpl/simpl-open/development/infrastructure/infrastructure-crossplane/configuration:v0.3.3
+  packagePullSecrets: 
+    - name: ec-pull-secret
+  revisionHistoryLimit: 0
+  packagePullPolicy: Always
\ No newline at end of file
diff --git a/k8s/debug.yaml b/k8s/debug.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d26eebb6e94d823f529e285527da387340af63c8
--- /dev/null
+++ b/k8s/debug.yaml
@@ -0,0 +1,29 @@
+apiVersion: v1
+kind: Pod
+metadata:
+  name: kafkacat
+  namespace: infrastructure
+spec:
+  containers:
+  - name: kafkacat
+    image: confluentinc/cp-kafkacat
+    command:
+      - sleep
+      - "3600"
+    imagePullPolicy: Always
+  restartPolicy: Never
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  name: nettools
+  namespace: infrastructure
+spec:
+  containers:
+  - name: nettools
+    image: jrecord/nettools:latest
+    command:
+      - sleep
+      - "3600"
+    imagePullPolicy: Always
+  restartPolicy: Never
\ No newline at end of file
diff --git a/k8s/events/decommission/sensor.yaml b/k8s/events/decommission/sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b4ebe68c0fedf8b234ce113834d2bfe39e3b0763
--- /dev/null
+++ b/k8s/events/decommission/sensor.yaml
@@ -0,0 +1,107 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: to-decommission-wf
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  template:
+    serviceAccountName: operate-workflow
+  dependencies:
+    - name: message
+      eventSourceName: kafka-to-decommission
+      eventName: decommissionRequest
+  triggers:
+    - template:
+        name: argo-workflow-trigger
+        argoWorkflow:
+          operation: submit
+          source:
+            resource:
+              apiVersion: argoproj.io/v1alpha1
+              kind: Workflow
+              metadata:
+                generateName: workflow-gitops-
+                namespace: argowf
+              spec:
+                imagePullSecrets:
+                  - name: ec-pull-secret
+                volumes:
+                  - name: repos
+                    emptyDir: {}
+                serviceAccountName: cli
+                entrypoint: main
+                workflowMetadata:
+                  labels:
+                    track-workflow: "true"
+                    workflow-type: to-decommission
+                  labelsFrom:
+                    scriptTriggerId:
+                      expression: workflow.parameters.scriptTriggerId
+                arguments:
+                  parameters:
+                    - name: scriptTriggerId
+                      value: default-is-overriden
+                templates:
+                  - name: main
+                    inputs:
+                      artifacts:
+                        - name: data-repo
+                          path: repos/data
+                          git:
+                            repo: http://gitea-http.gitea.svc.cluster.local:3000/gitops_test/data-repo.git
+                            revision: "master"
+                        - name: management-repo
+                          path: /repos/management
+                          git:
+                            repo: http://gitea-http.gitea.svc.cluster.local:3000/gitops_test/management-repo.git
+                            revision: "master"
+                      parameters:
+                        - name: scriptTriggerId
+                          value: "'{{workflow.parameters.scriptTriggerId}}'"
+                    script:
+                      image: alpine/git:v2.45.2
+                      env:
+                        - name: GIT_USER
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: username
+                        - name: GIT_PASSWORD
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: password
+                      command: [sh, -c]
+                      args: ['
+                          echo --- decommissioning request with ID: {{inputs.parameters.scriptTriggerId}};
+                          echo ---ls ../work---;
+                          ls;
+                          echo ---ls ../repos---;
+                          ls ../repos;
+                          git config --global user.email "workflow@argo.kube";
+                          git config --global user.name "gitops_test";
+                          echo ---commit data changes---;
+                          git -C ../repos/data checkout master;
+                          git -C ../repos/data rm -r claims/claim_{{inputs.parameters.scriptTriggerId}};
+                          git -C ../repos/data commit -v -m "Remove claim_{{inputs.parameters.scriptTriggerId}}";
+                          git -C ../repos/data push http://$GIT_USER:$GIT_PASSWORD@gitea-http.gitea.svc.cluster.local:3000/gitops_test/data-repo.git;
+                          echo ---commit management changes---;
+                          git -C ../repos/management checkout master;
+                          git -C ../repos/management rm -r applications/application_{{inputs.parameters.scriptTriggerId}};
+                          git -C ../repos/management commit -v -m "Remove application_{{inputs.parameters.scriptTriggerId}}";
+                          git -C ../repos/management push http://$GIT_USER:$GIT_PASSWORD@gitea-http.gitea.svc.cluster.local:3000/gitops_test/management-repo.git;
+                        ']
+                      volumeMounts:
+                        - name: repos
+                          mountPath: /repos
+                      workingDir: /work
+          parameters:
+            - src:
+                dependencyName: message
+                dataKey: headers.scriptTriggerId
+                value: ""
+              dest: spec.arguments.parameters.0.value
+      retryStrategy:
+        steps: 2
+        duration: 30s
\ No newline at end of file
diff --git a/k8s/events/decommission/source.yaml b/k8s/events/decommission/source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4dcd5cd5ef26ec4195d4987669f57903987e3899
--- /dev/null
+++ b/k8s/events/decommission/source.yaml
@@ -0,0 +1,18 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: kafka-to-decommission
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  kafka:
+    decommissionRequest:
+      url: {{ .Values.kafkaEndpoint }}
+      topic: to-decommission
+      jsonBody: false
+      partition: "0"
+      connectionBackoff:
+        duration: 10s
+        steps: 3
+        factor: 1
+        jitter: 0.2
\ No newline at end of file
diff --git a/k8s/events/decommission/status-emitter.yaml b/k8s/events/decommission/status-emitter.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7ab6b17737ffa2292f17d88d97fea2ea899bb605
--- /dev/null
+++ b/k8s/events/decommission/status-emitter.yaml
@@ -0,0 +1,32 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: decommission-status-emitter
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  dependencies:
+    - name: message
+      eventSourceName: decommission-status-tracker
+      eventName: decommissionStatus
+  triggers:
+    - template:
+        name: kafka
+        kafka:
+          url: {{ .Values.kafkaEndpoint }}
+          topic: decommissioned
+          payload:
+            - src:
+                dependencyName: message
+                dataKey: body.metadata.labels.claim-uuid
+                value: ""
+              dest: scriptTriggerId
+            - src:
+                dependencyName: message
+                value: "Succeeded"
+              dest: status
+            - src:
+                dependencyName: message
+                dataKey: body.metadata.deletionTimestamp
+                value: ""
+              dest: deletionTimestamp
\ No newline at end of file
diff --git a/k8s/events/decommission/status-source.yaml b/k8s/events/decommission/status-source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e9f3eda0976174ff608bf3690af7922c76147858
--- /dev/null
+++ b/k8s/events/decommission/status-source.yaml
@@ -0,0 +1,24 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: decommission-status-tracker
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  template:
+    serviceAccountName: claim-application-status
+  resource:
+    decommissionStatus:
+      namespace: argocd
+      group: argoproj.io
+      version: v1alpha1
+      resource: applications
+      eventTypes:
+        - DELETE
+      filter:
+        afterStart: true
+        labels:
+          - key: track-events
+            operation: "=="
+            value: "claim-application"
+
diff --git a/k8s/events/eventbus.yaml b/k8s/events/eventbus.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7ed73ad67a0cd130e5e24a6b5c097e77f9f87319
--- /dev/null
+++ b/k8s/events/eventbus.yaml
@@ -0,0 +1,10 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventBus
+metadata:
+  name: provisioner
+  namespace: argoev
+spec:
+  nats:
+    native:
+      replicas: 2
+      auth: token
diff --git a/k8s/events/provision/sensor.yaml b/k8s/events/provision/sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1aeafa660210d1488c23cd12f09b8dcb25f8ad4e
--- /dev/null
+++ b/k8s/events/provision/sensor.yaml
@@ -0,0 +1,123 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: to-provision-wf
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  template:
+    serviceAccountName: operate-workflow
+  dependencies:
+    - name: message
+      eventSourceName: kafka-to-provision
+      eventName: provisionRequest
+  triggers:
+    - template:
+        name: argo-workflow-trigger
+        argoWorkflow:
+          operation: submit
+          source:
+            resource:
+              apiVersion: argoproj.io/v1alpha1
+              kind: Workflow
+              metadata:
+                generateName: workflow-gitops-
+                namespace: argowf
+              spec:
+                imagePullSecrets:
+                  - name: ec-pull-secret
+                volumes:
+                  - name: repos
+                    emptyDir: {}
+                serviceAccountName: cli
+                entrypoint: main
+                workflowMetadata:
+                  labels:
+                    track-workflow: "true"
+                    workflow-type: to-provision
+                  labelsFrom:
+                    scriptTriggerId:
+                      expression: workflow.parameters.scriptTriggerId
+                arguments:
+                  parameters:
+                    - name: headers
+                      value: default-is-overriden
+                    - name: scriptTriggerId
+                      value: default-is-overriden
+                    - name: body
+                      value: default-is-overriden
+                templates:
+                  - name: main
+                    inputs:
+                      artifacts:
+                        - name: data-repo
+                          path: repos/data
+                          git:
+                            repo: http://gitea-http.gitea.svc.cluster.local:3000/gitops_test/data-repo.git
+                            revision: "master"
+                        - name: management-repo
+                          path: /repos/management
+                          git:
+                            repo: http://gitea-http.gitea.svc.cluster.local:3000/gitops_test/management-repo.git
+                            revision: "master"
+                      parameters:
+                        - name: headers
+                          value: "'{{workflow.parameters.headers}}'"
+                        - name: scriptTriggerId
+                          value: "'{{workflow.parameters.scriptTriggerId}}'"
+                        - name: body
+                          value: "'{{workflow.parameters.body}}'"
+                    container:
+                      image: code.europa.eu:4567/simpl/simpl-open/development/infrastructure/infrastructure-crossplane/to-provision-workflow:v0.2.1
+                      env:
+                        - name: GIT_USER
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: username
+                        - name: GIT_PASSWORD
+                          valueFrom:
+                            secretKeyRef:
+                              name: gitea-secret
+                              key: password
+                      command: [sh, -c]
+                      args: ['
+                          echo --- provisioning request with ID: {{inputs.parameters.scriptTriggerId}};
+                          echo ---ls ../work---;
+                          ls;
+                          echo ---ls ../repos---;
+                          ls ../repos;
+                          python doesntexist.py;
+                          python main.py {{inputs.parameters.scriptTriggerId}} {{inputs.parameters.body}} || exit $?;
+                          git config --global user.email "workflow@argo.kube";
+                          git config --global user.name "gitops_test";
+                          echo ---commit data changes---;
+                          git -C ../repos/data checkout master;
+                          git -C ../repos/data/claims add -A && git -C ../repos/data commit -m "add UUID {{inputs.parameters.scriptTriggerId}}";
+                          git -C ../repos/data push http://$GIT_USER:$GIT_PASSWORD@gitea-http.gitea.svc.cluster.local:3000/gitops_test/data-repo.git;
+                          echo ---commit management changes---;
+                          git -C ../repos/management checkout master;
+                          git -C ../repos/management/applications add -A && git -C ../repos/management commit -m "add UUID {{inputs.parameters.scriptTriggerId}}";
+                          git -C ../repos/management push http://$GIT_USER:$GIT_PASSWORD@gitea-http.gitea.svc.cluster.local:3000/gitops_test/management-repo.git;
+                        ']
+                      volumeMounts:
+                        - name: repos
+                          mountPath: /repos
+                      workingDir: /work
+          parameters:
+            - src:
+                dependencyName: message
+                dataKey: headers
+              dest: spec.arguments.parameters.0.value
+            - src:
+                dependencyName: message
+                dataKey: headers.scriptTriggerId
+                value: dummy
+              dest: spec.arguments.parameters.1.value
+            - src:
+                dependencyName: message
+                dataKey: body
+              dest: spec.arguments.parameters.2.value
+      retryStrategy:
+        steps: 2
+        duration: 30s
\ No newline at end of file
diff --git a/k8s/events/provision/source.yaml b/k8s/events/provision/source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..26ea9cbc3567be863e33a06a5246ec7b76aee4e4
--- /dev/null
+++ b/k8s/events/provision/source.yaml
@@ -0,0 +1,18 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: kafka-to-provision
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  kafka:
+    provisionRequest:
+      url: {{ .Values.kafkaEndpoint }}
+      topic: to-provision
+      jsonBody: false
+      partition: "0"
+      connectionBackoff:
+        duration: 10s
+        steps: 3
+        factor: 1
+        jitter: 0.2
\ No newline at end of file
diff --git a/k8s/events/provision/status-emitter.yaml b/k8s/events/provision/status-emitter.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..65fd351f3d1c7618a83250ddb8e5e1f097077d6f
--- /dev/null
+++ b/k8s/events/provision/status-emitter.yaml
@@ -0,0 +1,44 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: to-provision-wf-status-emitter
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  dependencies:
+    - name: wf-status
+      eventSourceName: to-provision-wf-status-tracker
+      eventName: toProvisionWorkflow
+  triggers:
+    - template:
+        name: kafka
+        kafka:
+          url: {{ .Values.kafkaEndpoint }}
+          topic: provisioned
+          partition: 0
+          payload:
+            - src:
+                dependencyName: wf-status
+                dataKey: body.metadata.name
+                value: "None"
+              dest: name
+            - src:
+                dependencyName: wf-status
+                dataKey: "body.metadata.labels.workflows\\.argoproj\\.io/phase"
+                value: "Unknown"
+              dest: phase
+            - src:
+                dependencyName: wf-status
+                dataKey: "body.metadata.labels.workflows\\.argoproj\\.io/completed"
+                value: "false"
+              dest: completed
+            - src:
+                dependencyName: wf-status
+                dataKey: "body.metadata.labels.scriptTriggerId"
+                value: ""
+              dest: scriptTriggerId
+            - src:
+                dependencyName: wf-status
+                dataKey: body.status.message
+                value: ""
+              dest: message
\ No newline at end of file
diff --git a/k8s/events/provision/status-source.yaml b/k8s/events/provision/status-source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f95be3aabf2576e856e33b9e96fbbd84d660f889
--- /dev/null
+++ b/k8s/events/provision/status-source.yaml
@@ -0,0 +1,27 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: claim-application-status-tracker
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  template:
+    serviceAccountName: claim-application-status
+  resource:
+    claimApplicationStatus:
+      namespace: argocd
+      group: argoproj.io
+      version: v1alpha1
+      resource: applications
+      eventTypes:
+        - UPDATE
+      filter:
+        afterStart: true
+        labels:
+          - key: track-events
+            operation: "=="
+            value: "claim-application"
+          - key: provisioning-status
+            operation: "!="
+            value: "finalized"
+
diff --git a/k8s/events/provision/workflow-status-sensor.yaml b/k8s/events/provision/workflow-status-sensor.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..75b9b988f4ccf69116958925422018af762f2587
--- /dev/null
+++ b/k8s/events/provision/workflow-status-sensor.yaml
@@ -0,0 +1,175 @@
+apiVersion: argoproj.io/v1alpha1
+kind: Sensor
+metadata:
+  name: claim-application-status-wf
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  template:
+    serviceAccountName: operate-workflow
+  dependencies:
+    - name: message
+      eventSourceName: claim-application-status-tracker
+      eventName: claimApplicationStatus
+  triggers:
+    - template:
+        name: argo-workflow-trigger
+        argoWorkflow:
+          operation: submit
+          source:
+            resource:
+              apiVersion: argoproj.io/v1alpha1
+              kind: Workflow
+              metadata:
+                generateName: workflow-claim-application-status
+                namespace: argowf
+              spec:
+                serviceAccountName: cli
+                entrypoint: main
+                workflowMetadata:
+                arguments:
+                  parameters:
+                    - name: body
+                      value: default-is-overriden
+                templates:
+                  - name: main
+                    steps:
+                      - - name: validate
+                          template: validate-status
+                          arguments:
+                            parameters:
+                              - name: message
+                                value: "{{workflow.parameters.body}}"
+                      - - name: label
+                          template: done-label
+                          arguments:
+                            parameters:
+                              - name: UUID
+                                value: "{{steps.validate.outputs.result}}"
+                      - - name: parse-application
+                          template: parse-application
+                          arguments:
+                            parameters:
+                              - name: resource
+                                value: "{{steps.label.outputs.parameters.application-resource}}"
+                      - - name: parse-claim
+                          template: parse-claim
+                          arguments:
+                            parameters:
+                              - name: claim-reference
+                                value: "{{steps.parse-application.outputs.result}}"
+                      - - name: payload
+                          template: payload
+                          arguments:
+                            parameters:
+                              - name: resource
+                                value: "{{steps.parse-claim.outputs.parameters.claim-resource}}"
+                      - - name: message
+                          template: message
+                          arguments:
+                            parameters:
+                              - name: payload
+                                value: "{{steps.payload.outputs.result}}"
+                  - name: validate-status
+                    inputs:
+                      parameters:
+                        - name: message
+                    script:
+                      image: python:alpine3.10
+                      command: [python]
+                      source: |
+                        import json
+                        rawstr = r'''{{inputs.parameters.message}}'''
+                        d = json.loads(rawstr)
+                        try:
+                          app_status = d['status']
+                          app_meta = d['metadata']
+                          app_health = app_status['health']['status']
+                          app_sync = app_status['sync']['status']
+                          # Application only tracks the Claim, so one resource should be present
+                          claim = app_status['resources'][0]
+                          claim_health = claim['health']['status']
+                          claim_sync = claim['status']
+                          claim_id = app_meta['labels']['claim-uuid']
+                          assert app_health == "Healthy" and claim_health == "Healthy" and app_sync == "Synced" and claim_sync == "Synced"
+                          print(f"{claim_id}")
+                        except (KeyError, IndexError):
+                          raise ValueError("Not all status fields available")
+                  - name: done-label
+                    inputs:
+                      parameters:
+                        - name: UUID
+                    script:
+                      image: bitnami/kubectl:latest
+                      command: [sh]
+                      source: |
+                        echo "patching application with label claim-uuid:{{inputs.parameters.UUID}}"
+                        kubectl label -n argocd applications crossplane-claim-{{inputs.parameters.UUID}} provisioning-status="finalized"
+                        kubectl get -n argocd applications --selector=claim-uuid={{inputs.parameters.UUID}} -o json > /tmp/resource.json
+                    outputs:
+                      parameters:
+                        - name: application-resource
+                          valueFrom:
+                            path: /tmp/resource.json
+                  - name: parse-application
+                    inputs:
+                      parameters:
+                        - name: resource
+                    script:
+                      image: python:alpine3.10
+                      command: [python]
+                      source: |
+                          import json
+                          rawstr = r'''{{inputs.parameters.resource}}'''
+                          d = json.loads(rawstr)
+                          claim_kind = d['items'][0]['metadata']['labels']['claim-kind']
+                          claim_selector = d['items'][0]['metadata']['labels']['claim-uuid']
+                          print(f"{claim_kind} --selector=uuid={claim_selector}")
+                  - name: parse-claim
+                    inputs:
+                      parameters:
+                        - name: claim-reference
+                    script:
+                      image: bitnami/kubectl:latest
+                      command: [sh]
+                      source: |
+                        kubectl get -n crossplane-system {{inputs.parameters.claim-reference}}
+                        kubectl get -n crossplane-system -o json {{inputs.parameters.claim-reference}} > /tmp/resource.json
+                    outputs:
+                      parameters:
+                        - name: claim-resource
+                          valueFrom:
+                            path: /tmp/resource.json
+                  - name: payload
+                    inputs:
+                      parameters:
+                        - name: resource
+                    script:
+                      image: python:alpine3.10
+                      command: [python]
+                      source: |
+                        import json
+                        rawstr = r'''{{inputs.parameters.resource}}'''
+                        d = json.loads(rawstr)
+                        payload = {}
+                        payload["vmIps"] = d["items"][0]["status"]["vmIps"]
+                        payload["status"] = "Provisioning finalized successfully"
+                        payload["scriptTriggerId"] = d["items"][0]["metadata"]["labels"]["uuid"]
+                        print(json.dumps(payload).replace('"', '\\"'))
+                  - name: message
+                    inputs:
+                      parameters:
+                        - name: payload
+                    script:
+                      image: confluentinc/cp-kafkacat:7.1.14
+                      command: [sh]
+                      source: |
+                        echo {{inputs.parameters.payload}} | kafkacat -P -b {{ .Values.kafkaEndpoint }} -t provisioned -J
+          parameters:
+            - src:
+                dependencyName: message
+                dataKey: body
+              dest: spec.arguments.parameters.0.value
+      retryStrategy:
+        steps: 2
+        duration: 30s
\ No newline at end of file
diff --git a/k8s/events/provision/workflow-status-source.yaml b/k8s/events/provision/workflow-status-source.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..86441f1dd666c346d5470d9dc90917c7f6459d9c
--- /dev/null
+++ b/k8s/events/provision/workflow-status-source.yaml
@@ -0,0 +1,27 @@
+apiVersion: argoproj.io/v1alpha1
+kind: EventSource
+metadata:
+  name: to-provision-wf-status-tracker
+  namespace: argoev
+spec:
+  eventBusName: provisioner
+  template:
+    serviceAccountName:  operate-workflow
+  resource:
+    toProvisionWorkflow:
+      namespace: argowf
+      group: argoproj.io
+      version: v1alpha1
+      resource: workflows
+      eventTypes:
+        - ADD
+        - UPDATE
+      filter:
+        afterStart: true
+        labels:
+          - key: track-workflow
+            operation: "=="
+            value: "true"
+          - key: workflow-type
+            operation: "=="
+            value: to-provision
diff --git a/k8s/provider-ionos-configuration.yaml b/k8s/provider-ionos-configuration.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e4eda6e78fbb316c3c6f3de33ca959c496dbea1e
--- /dev/null
+++ b/k8s/provider-ionos-configuration.yaml
@@ -0,0 +1,12 @@
+apiVersion: ionoscloud.crossplane.io/v1alpha1
+kind: ProviderConfig
+metadata:
+  name: example
+  namespace: crossplane-system
+spec:
+  credentials:
+    source: Secret
+    secretRef:
+      namespace: crossplane-system
+      name: ionos-provider
+      key: credentials
diff --git a/k8s/rbac/argocd-application-rbac.yaml b/k8s/rbac/argocd-application-rbac.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8a7c71fc9a5661d1b71f87fc1cddfce68caa574f
--- /dev/null
+++ b/k8s/rbac/argocd-application-rbac.yaml
@@ -0,0 +1,62 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: view-application
+  namespace: argocd
+rules:
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - applications
+    verbs:
+      - list
+      - get
+      - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: view-application
+  namespace: argocd
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: view-application
+subjects:
+- kind: ServiceAccount
+  name: claim-application-status
+  namespace: argoev
+- kind: ServiceAccount
+  name: operate-workflow
+  namespace: argoev
+- kind: ServiceAccount
+  name: cli
+  namespace: argowf
+
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: patch-application
+  namespace: argocd
+rules:
+  - apiGroups:
+      - argoproj.io
+    resources:
+      - applications
+    verbs:
+      - patch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: patch-application
+  namespace: argocd
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: patch-application
+subjects:
+- kind: ServiceAccount
+  name: cli
+  namespace: argowf
diff --git a/k8s/rbac/crossplane-composites.yaml b/k8s/rbac/crossplane-composites.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4c80c05587417b72fa791491d8ae1ae52637b85d
--- /dev/null
+++ b/k8s/rbac/crossplane-composites.yaml
@@ -0,0 +1,15 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: view-composite-status-events
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: crossplane-view
+subjects:
+  - kind: ServiceAccount
+    name: composite-status
+    namespace: argoev
+  - kind: ServiceAccount
+    name: cli
+    namespace: argowf
\ No newline at end of file
diff --git a/k8s/workflows/cli-token.yaml b/k8s/workflows/cli-token.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5aabb14b129585b8b9e8869711943c16d9fa5299
--- /dev/null
+++ b/k8s/workflows/cli-token.yaml
@@ -0,0 +1,7 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  name: argocli.service-account-token
+  annotations:
+    kubernetes.io/service-account.name: argocli
+type: kubernetes.io/service-account-token
\ No newline at end of file
diff --git a/package/apis/demo/definition.yaml b/package/apis/demo/definition.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6de7c2ee9badbbc23e62178da18963dc1a23b0e4
--- /dev/null
+++ b/package/apis/demo/definition.yaml
@@ -0,0 +1,72 @@
+apiVersion: apiextensions.crossplane.io/v1
+kind: CompositeResourceDefinition
+metadata:
+  name: xserversinstances.platform.example.org
+spec:
+  defaultCompositeDeletePolicy: Foreground
+  group: platform.example.org
+  names:
+    kind: XServerInstance
+    plural: xserversinstances
+  claimNames:
+    kind: ServerInstance
+    plural: serversinstances
+  versions:
+    - name: v1alpha1
+      served: true
+      referenceable: true
+      schema:
+        openAPIV3Schema:
+          type: object
+          description: A XServersInstance is a composite resource
+          properties:
+            spec:
+              type: object
+              properties:
+                parameters:
+                  type: object
+                  properties:
+                    datacenterName:
+                      type: string
+                    datacenterLocation:
+                      type: string
+                      enum: [es/vit, de/txl]
+                    datacenterDescription:
+                      type: string
+                    serverName:
+                      type: string
+                    cores:
+                      type: integer
+                      minimum: 1
+                      maximum: 4
+                    ram:
+                      type: integer
+                      minimum: 1024
+                      maximum: 8192
+                    cpuFamily:
+                        type: string
+                        enum: [INTEL_ICELAKE, AMD_EPYC]
+                    cloudConfig:
+                      type: string
+                  required:
+                    - datacenterName
+                    - datacenterLocation
+                    - serverName
+                    - cores
+                    - ram
+                    - cpuFamily
+              required:
+                - parameters
+            status:
+              type: object
+              properties:
+                vmIps:
+                  type: array
+                  items:
+                    type: string
+                  minItems: 2
+                  maxItems: 2
+                datacenterId:
+                  type: string
+                volumeId:
+                  type: string
\ No newline at end of file
diff --git a/package/apis/demo/ionos.yaml b/package/apis/demo/ionos.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d15f786f6f2a018a056eea4ea81b4a45d4e80b19
--- /dev/null
+++ b/package/apis/demo/ionos.yaml
@@ -0,0 +1,197 @@
+apiVersion: apiextensions.crossplane.io/v1
+kind: Composition
+metadata:
+  name: example
+  labels:
+    crossplane.io/xrd: xserversinstances.platform.example.org
+    provider: ionoscloud
+spec:
+  writeConnectionSecretsToNamespace: infrastructure
+  compositeTypeRef:
+    apiVersion: platform.example.org/v1alpha1
+    kind: XServerInstance
+  resources:
+    #  0
+    - name: datacenter
+      base:
+        apiVersion: compute.ionoscloud.crossplane.io/v1alpha1
+        kind: Datacenter
+        managementPolicies:
+          - "*"
+        spec:
+          forProvider:
+            name: exampleDatacenter
+            location: us/las
+            description: test
+          providerConfigRef:
+            name: example
+      patches:
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.datacenterLocation
+          toFieldPath: spec.forProvider.location
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.datacenterName
+          toFieldPath: spec.forProvider.name
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.datacenterDescription
+          toFieldPath: spec.forProvider.description
+        - type: ToCompositeFieldPath
+          fromFieldPath: status.atProvider.datacenterId
+          toFieldPath: status.datacenterId
+    #  1
+    - name: server1
+      base:
+        apiVersion: compute.ionoscloud.crossplane.io/v1alpha1
+        kind: Server
+        managementPolicies:
+          - "*"
+        spec:
+          forProvider:
+            datacenterConfig:
+              datacenterIdRef:
+                name: datacenter
+            name: server1
+            volumeConfig:
+              volumeIdRef:
+                name: volume1
+            cores: 1
+            ram: 1024
+            availabilityZone: AUTO
+            cpuFamily: INTEL_ICELAKE
+          providerConfigRef:
+            name: example
+      patches:
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.serverName
+          toFieldPath: spec.forProvider.name
+          transforms:
+            - type: string
+              string:
+                fmt: "%s_1"
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.cores
+          toFieldPath: spec.forProvider.cores
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.ram
+          toFieldPath: spec.forProvider.ram
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.cpuFamily
+          toFieldPath: spec.forProvider.cpuFamily
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.resourceRefs[0].name
+          toFieldPath: spec.forProvider.datacenterConfig.datacenterIdRef.name
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.resourceRefs[5].name
+          toFieldPath: spec.forProvider.volumeConfig.volumeIdRef.name
+    #  2
+    - name: lan1
+      base:
+        apiVersion: compute.ionoscloud.crossplane.io/v1alpha1
+        kind: Lan
+        managementPolicies:
+          - "*"
+        spec:
+          forProvider:
+            name: lan1
+            public: true
+            datacenterConfig:
+              datacenterIdRef:
+                name: datacenter
+          providerConfigRef:
+            name: example
+      patches:
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.resourceRefs[0].name
+          toFieldPath: spec.forProvider.datacenterConfig.datacenterIdRef.name
+    #  3
+    - name: ipblock1
+      base:
+        apiVersion: compute.ionoscloud.crossplane.io/v1alpha1
+        kind: IPBlock
+        managementPolicies:
+          - "*"
+        spec:
+          forProvider:
+            name: ipblock1
+            size: 2
+            location: us/las
+          providerConfigRef:
+            name: example
+      patches:
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.datacenterLocation
+          toFieldPath: spec.forProvider.location
+        - type: ToCompositeFieldPath
+          fromFieldPath: status.atProvider.ips
+          toFieldPath: status.vmIps
+    #  4
+    - name: nic1
+      base:
+        apiVersion: compute.ionoscloud.crossplane.io/v1alpha1
+        kind: Nic
+        managementPolicies:
+          - "*"
+        spec:
+          forProvider:
+            name: Nic1
+            dhcp: true
+            ipsConfigs:
+              ips:
+                - 0.0.0.0
+                - 0.0.0.0
+            datacenterConfig:
+              datacenterIdRef:
+                name: datacenter
+            serverConfig:
+              serverIdRef:
+                name: server1
+            lanConfig:
+              lanIdRef:
+                name: lan1
+          providerConfigRef:
+            name: example
+      patches:
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.resourceRefs[0].name
+          toFieldPath: spec.forProvider.datacenterConfig.datacenterIdRef.name
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.resourceRefs[1].name
+          toFieldPath: spec.forProvider.serverConfig.serverIdRef.name
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.resourceRefs[2].name
+          toFieldPath: spec.forProvider.lanConfig.lanIdRef.name
+        - type: FromCompositeFieldPath
+          fromFieldPath: status.vmIps
+          toFieldPath: spec.forProvider.ipsConfigs.ips
+    #  5
+    - name: volume1
+      base:
+        apiVersion: compute.ionoscloud.crossplane.io/v1alpha1
+        kind: Volume
+        managementPolicies:
+          - "*"
+        spec:
+          forProvider:
+            name: volume1
+            size: 5
+            type: SSD Standard
+            bus: VIRTIO
+            availabilityZone: AUTO
+            imageAlias: ubuntu:22.04
+            imagePassword: testpassword1234
+            userData: foo
+            datacenterConfig:
+              datacenterIdRef:
+                name: datacenter
+          providerConfigRef:
+            name: example
+      patches:
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.resourceRefs[0].name
+          toFieldPath: spec.forProvider.datacenterConfig.datacenterIdRef.name
+        - type: FromCompositeFieldPath
+          fromFieldPath: spec.parameters.cloudConfig
+          toFieldPath: spec.forProvider.userData
+        - type: ToCompositeFieldPath
+          fromFieldPath: status.atProvider.volumeId
+          toFieldPath: status.volumeId
diff --git a/package/crossplane.yaml b/package/crossplane.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..6afa4405c52148af54e440ffd38fdfb098e670a2
--- /dev/null
+++ b/package/crossplane.yaml
@@ -0,0 +1,20 @@
+apiVersion: meta.pkg.crossplane.io/v1
+kind: Configuration
+metadata:
+  name: simpl-config
+  annotations:
+    meta.crossplane.io/maintainer: SIMPL Infrastructure Team
+    meta.crossplane.io/source: "https://github.com/cbeti-ionos/crossplane-multicloud"
+    meta.crossplane.io/license: MIT
+    meta.crossplane.io/description: Catalogue offerings demo in IonosCloud
+    meta.crossplane.io/readme: A Configuration package demo that contains Definitions and Compositions for provisioning Catalogue offerings in IonosCloud
+    meta.crossplane.io/version: 0.3.6
+
+spec:
+  crossplane:
+    version: ">=v1.16.0"
+  dependsOn:
+  - provider: ghcr.io/ionos-cloud/crossplane-provider-ionoscloud
+    version: ">=v1.1.3"
+
+
diff --git a/package/examples/demo/ionos.yaml b/package/examples/demo/ionos.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..2dbd5d8fb7b2c49d6223ad38cede93fc74ac3e66
--- /dev/null
+++ b/package/examples/demo/ionos.yaml
@@ -0,0 +1,14 @@
+apiVersion: platform.example.org/v1alpha1
+kind: ServerInstance
+metadata:
+  namespace: infrastructure
+  name: offering-name-medium-instance-example
+spec:
+  parameters:
+    datacenterName: crossplane_datacenter_medium_example
+    datacenterDescription: testExampleDescription
+    datacenterLocation: es/vit
+    serverName: server
+    cores: 2
+    ram: 2048
+    cpuFamily: INTEL_ICELAKE
diff --git a/package/examples/demo/ionos_template.yaml b/package/examples/demo/ionos_template.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..630c7a5abfce01f0ca64982092ebb74d3cd7b0a2
--- /dev/null
+++ b/package/examples/demo/ionos_template.yaml
@@ -0,0 +1,18 @@
+apiVersion: platform.example.org/v1alpha1
+kind: ServerInstance
+metadata:
+  namespace: infrastructure
+  name: offering-name-medium-instance-{UUID}
+  labels:
+    uuid: "{UUID}"
+    reference-kind: xserversinstances
+spec:
+  parameters:
+    datacenterName: crossplane_datacenter_medium-{UUID}
+    datacenterDescription: testExampleDescription
+    datacenterLocation: es/vit
+    serverName: server
+    cores: 2
+    ram: 2048
+    cpuFamily: INTEL_ICELAKE
+    cloudConfig: I2Nsb3VkLWNvbmZpZwpzc2hfcHdhdXRoOiB0cnVlCnVzZXJzOgotIGRlZmF1bHQKLSBuYW1lOiB2ODZsNDFLTDE4CiAgcGFzc3dkOiAkNiRyb3VuZHM9NDA5NiRyY1J3eUhUbGZJTlZqOXY3JEdxdzZkbmNLRjlkdy9ra25DakxOR0I1NUtWcXRMcC5Mek54MjF0ZUwyL2FBY1JqbDZEUDA5R3JDZ0x3encxRHpwcEVuc0NQSE5LRFBaZy9HV0NwQ0ouCiAgc2hlbGw6IC9iaW4vYmFzaAogIGxvY2tfcGFzc3dkOiBmYWxzZQogIGNocGFzc3dkOgogICAgZXhwaXJlOiBmYWxzZQogIHN1ZG86IEFMTD0oQUxMKSBOT1BBU1NXRDpBTEwKICBncm91cHM6IHVzZXJzLCBhZG1pbgo=
\ No newline at end of file
diff --git a/setup.sh b/setup.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2bd1c148d4465b5692ba92cde2de07af8f3d5d4f
--- /dev/null
+++ b/setup.sh
@@ -0,0 +1,16 @@
+NS=infrastructure
+kubectl create namespace $NS 
+kubectl create -n $NS secret docker-registry "ec-pull-secret"  --docker-server="code.europa.eu:4567" --docker-username="$EC_USERNAME" --docker-password="$EC_PASSWORD" 
+kubectl create -n $NS secret generic gitea-secret --from-literal=username=gitops_test --from-literal=password=test1234
+kubectl create -n $NS secret generic kafka-secret --from-literal=username=demo --from-literal=password=demo-password
+kubectl create -n $NS secret generic ionos-provider --from-literal=credentials="{\"token\":\"${IONOS_TOKEN}\"}"
+helm install provisioner-dependencies -n $NS charts/dependencies
+sleep 60
+helm install provisioner-resources -n $NS charts/resources
+
+# Use when installing locally to get access tokens and forward service ports
+echo "Bearer $(kubectl get -n $NS secret cli.service-account-token -o=jsonpath='{.data.token}' | base64 --decode)" > argowftoken
+kubectl get -n $NS secret argocd-initial-admin-secret  -o jsonpath="{.data.password}" | base64 -d > argopw
+# kubectl port-forward -n $NS svc/argocd-server 8888:443
+# kubectl port-forward -n $NS svc/argowf-argo-workflows-server 8777:2746
+# kubectl port-forward -n $NS svc/gitea-http 8333:3000
\ No newline at end of file
diff --git a/workflow-images/to-provision/Dockerfile b/workflow-images/to-provision/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..81777c5ec72c2eab5c69025ce85271488f767a37
--- /dev/null
+++ b/workflow-images/to-provision/Dockerfile
@@ -0,0 +1,10 @@
+FROM python:3
+
+WORKDIR /work
+
+COPY requirements.txt ./
+RUN pip install --no-cache-dir -r requirements.txt
+
+COPY . .
+
+ENTRYPOINT ["python", "./main.py"]
diff --git a/workflow-images/to-provision/main.py b/workflow-images/to-provision/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..a5db1f6cc29bb3d892aceaa2a2914b357d803e42
--- /dev/null
+++ b/workflow-images/to-provision/main.py
@@ -0,0 +1,73 @@
+import sys
+import os
+import base64
+import yaml
+from pathlib import Path
+
+# This is the default setting, if you change it in the workflow, it must be changed here as well
+LOGFILE = "/dev/termination-log"
+SCRIPTS_PATH = "/repos/data/claims"
+APPLICATIONS_PATH = "/repos/management/applications"
+APPLICATION_TEMPLATE_PATH ="/repos/management/data-application-template.yaml"
+CLAIM_KIND_REF_LABEL = "reference-kind"
+KIND_REF_PLACEHOLDER = "KIND"
+UUID_PLACEHOLDER = "UUID"
+
+def write_termination_log(msg, echo_stdout=True):
+    if echo_stdout:
+        print(msg)
+    with open(LOGFILE, mode="a", encoding="utf-8") as logfile:
+        print(msg, file=logfile)
+
+if len(sys.argv) != 3:
+    msg = "Parser received wrong number of arguments:" + f"{len(sys.argv)-1}, <provisioningRequestId> and <body> are required"
+    sys.exit(100)
+UUID = sys.argv[1]
+message = sys.argv[2]
+
+script_path = f"{SCRIPTS_PATH}/claim_{UUID}/claim_{UUID}.yaml"
+print(f"Verifying claim duplication:\n{script_path}")
+if Path(script_path).exists():
+    msg = f"CLAIM ID DUPLICATION: claim with id {UUID} already exists!"
+    write_termination_log(msg)
+    sys.exit(101)
+os.mkdir(f"{SCRIPTS_PATH}/claim_{UUID}")
+
+application_path = f"{APPLICATIONS_PATH}/application_{UUID}/application_{UUID}.yaml"
+print(f"Verifying application duplication:\n{application_path}")
+if Path(application_path).exists():
+    msg = f"APPLICATION ID DUPLICATION: application with id {UUID} already exists!"
+    write_termination_log(msg)
+    sys.exit(102)
+os.mkdir(f"{APPLICATIONS_PATH}/application_{UUID}")
+
+try:
+    b64decoded = base64.standard_b64decode(message)
+    decoded = b64decoded.decode("utf-8")
+    script_content = decoded.format(UUID=UUID)
+except Exception as e:
+    msg = f"Cannot decode deployment manifest from message body"
+    write_termination_log(msg)
+    sys.exit(103)
+
+with open(script_path, mode="w", encoding="utf-8") as claim_file:
+    claim_file.write(script_content)
+print(f"\n---[claim {UUID} created]---\n")
+
+###TODO Embed the application template to get rid of this read
+application_content = ""
+with open(APPLICATION_TEMPLATE_PATH, mode="r", encoding="utf-8") as template_file:
+    template = template_file.read()
+    try:
+        l = yaml.safe_load(script_content)
+        reference_kind = l["metadata"]["labels"][CLAIM_KIND_REF_LABEL]
+    except Exception as e:
+        msg = f"Cannot retrieve claim kind reference label from manifest"
+        write_termination_log(msg)
+        sys.exit(104)
+    application_content = template.format(**{UUID_PLACEHOLDER:UUID,KIND_REF_PLACEHOLDER:reference_kind})
+
+with open(application_path, mode="w", encoding="utf-8") as application_file:
+    application_file.write(application_content)
+print(f"---[application {UUID} created]---\n")
+
diff --git a/workflow-images/to-provision/requirements.txt b/workflow-images/to-provision/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..03edd27bb4904653cc75004b1d0102dff706a261
--- /dev/null
+++ b/workflow-images/to-provision/requirements.txt
@@ -0,0 +1 @@
+pyaml>=6.0.2
\ No newline at end of file