Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
8bd88b2
CH-243: Make route pattern customizable
iamludal Feb 27, 2026
61961bb
Include forward slash in route pattern regex
iamludal Feb 28, 2026
8dde96f
Fix indent
iamludal Feb 28, 2026
4238c75
Add documentation
iamludal Feb 28, 2026
6a7d566
Fix linting
iamludal Mar 1, 2026
3dc0062
Try fix nil pointer
iamludal Mar 1, 2026
af4a92e
Fix nil pointer
iamludal Mar 1, 2026
0ae1782
Add router path matcher Traefik annotation
iamludal Mar 1, 2026
56439ab
Add configurable gatekeeper secret key secret. If no
Mar 6, 2026
1932760
Merge branch 'develop' into feature/CH-224
Mar 6, 2026
382e4c3
feat: define annotations based on ingress class
iamludal Mar 9, 2026
cab5ceb
Merge branch 'CH-243-customizable-route-pattern' into develop
filippomc Mar 9, 2026
59ecd9f
Merge branch 'feature/CH-224' of github.com:MetaCell/cloud-harness in…
filippomc Mar 9, 2026
ee02cae
CH-243 support for traefik routes
filippomc Mar 9, 2026
3a707cc
CH-224 Use secret for gateway encryption code
filippomc Mar 9, 2026
1bccfff
CH-243 path generation fix
filippomc Mar 9, 2026
ad29c79
CH-224 GK helm template fix
filippomc Mar 9, 2026
9360472
CH-224 GK helm template fix
filippomc Mar 9, 2026
b08d271
CH-243 post refactoring issue with certificates fix
filippomc Mar 9, 2026
54b73e9
CH-248 external database configuration
filippomc Mar 9, 2026
bc505ba
CH-248 add endpoint to test the external db
filippomc Mar 9, 2026
7ea8c0f
CH-224 GK encryption key to AES-256
filippomc Mar 9, 2026
c8a7208
CH-248 add test coverage for CI/CD secret set
filippomc Mar 9, 2026
7387a1d
CH-248 fix helm templates guard
filippomc Mar 9, 2026
1ee00c5
CH-248 fix helm templates guard
filippomc Mar 9, 2026
be1d737
CH-248 fix helm templates guard
filippomc Mar 9, 2026
71b1f26
CH-243 ingress root path fix
filippomc Mar 9, 2026
5274ec8
chore: linting and test related fixes
filippomc Mar 10, 2026
d8cb7fe
chore: Python code linting fix
filippomc Mar 10, 2026
cc5b125
chore: Update docs and default sample configuration
filippomc Mar 10, 2026
e94a771
Update CH default image version to 4.6.0
Mar 10, 2026
244e206
CH-248 #840 chore: rename connect string variable
filippomc Mar 10, 2026
88c9596
Merge branch 'feature/gateway-updates' of github.com:MetaCell/cloud-h…
filippomc Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/instructions/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ Verify which application/components is in scope and read specific prompt instruc

Check best practices in every instruction file in scope and docs and apply them when writing code or performing code reviews.
Use reference for any questions regarding project structure, development workflow, and best practices.
If you have any doubts about where to find information, ask for clarification before proceeding.
If you have any doubts about where to find information, ask for clarification before proceeding.

### Development principles
- Follow the best practices and coding style guidelines outlined in the documentation and instruction files.
- Configuration is set on values.yaml files and injected into the application via Helm templates and Kubernetes manifests. Do not hardcode configuration values directly into the application code or templates.
- Structured configuration can be injected via resources, that are process by helm templates and loaded as ConfigMaps automatically. See for instance `applications/accounts/deploy/resources/realm.json`
- The cloud harness configuration API is handled by the models library and defined as [openapi spec](../../libraries/models/api/openapi.yaml). Use `harness-generate models` to generate the models library after making changes to the spec.
16 changes: 16 additions & 0 deletions applications/samples/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,22 @@ paths:
description: |
Check if the token is valid
x-openapi-router-controller: samples.controllers.auth_controller
/db-connect-string:
get:
tags:
- database
summary: Get database connection string
operationId: get_db_connect_string
description: Returns the database connection string for the current application.
responses:
"200":
description: Database connection string returned successfully
content:
application/json:
schema:
type: string
"500":
description: Error retrieving database connection string
/sampleresources:
summary: Path used to manage the list of sampleresources.
description: >-
Expand Down
22 changes: 13 additions & 9 deletions applications/samples/backend/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
connexion[swagger-ui,flask,uvicorn]>=3.0.0,<4.0.0
swagger-ui-bundle>=1.1.0
python_dateutil>=2.9.0
setuptools>=21.0.0
uvicorn
# Following some unnecessary requirements to make sure they can be installed
psycopg2-binary
sqlalchemy<2.0.0
scipy
connexion[swagger-ui] >= 2.6.0; python_version>="3.6"
# 2.3 is the last version that supports python 3.4-3.5
connexion[swagger-ui] <= 2.3.0; python_version=="3.5" or python_version=="3.4"
# prevent breaking dependencies from advent of connexion>=3.0
connexion[swagger-ui] <= 2.14.2; python_version>"3.4"
# connexion requires werkzeug but connexion < 2.4.0 does not install werkzeug
# we must peg werkzeug versions below to fix connexion
# https://github.com/zalando/connexion/pull/1044
werkzeug == 0.16.1; python_version=="3.5" or python_version=="3.4"
swagger-ui-bundle >= 0.0.2
python_dateutil >= 2.6.0
setuptools >= 21.0.0
Flask == 2.1.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import connexion
from typing import Dict
from typing import Tuple
from typing import Union

from samples.models.get_db_connect_string200_response import GetDbConnectString200Response # noqa: E501
from samples import util


def get_db_connect_string(): # noqa: E501
"""Get database connection string

Returns the database connection string for the current application. # noqa: E501


:rtype: Union[GetDbConnectString200Response, Tuple[GetDbConnectString200Response, int], Tuple[GetDbConnectString200Response, int, Dict[str, str]]
"""
from cloudharness.applications import get_current_configuration
config = get_current_configuration()
return config.get_db_connection_string()
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import List


def info_from_bearerAuth(token):
"""
Check and retrieve authentication information from custom bearer token.
Returned value will be passed in 'token_info' parameter of your operation function, if there is one.
'sub' or 'uid' will be set in 'user' parameter of your operation function, if there is one.

:param token Token provided by Authorization header
:type token: str
:return: Decoded token information or None if token is invalid
:rtype: dict | None
"""
return {'uid': 'user_id'}


def info_from_cookieAuth(api_key, required_scopes):
"""
Check and retrieve authentication information from api_key.
Returned value will be passed in 'token_info' parameter of your operation function, if there is one.
'sub' or 'uid' will be set in 'user' parameter of your operation function, if there is one.

:param api_key API key provided by Authorization header
:type api_key: str
:param required_scopes Always None. Used for other authentication method
:type required_scopes: None
:return: Information attached to provided api_key or None if api_key is invalid or does not allow access to called API
:rtype: dict | None
"""
return {'uid': 'user_id'}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from datetime import date, datetime # noqa: F401

from typing import List, Dict # noqa: F401

from samples.models.base_model import Model
from samples import util


class GetDbConnectString200Response(Model):
"""NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).

Do not edit the class manually.
"""

def __init__(self, connect_string=None): # noqa: E501
"""GetDbConnectString200Response - a model defined in OpenAPI

:param connect_string: The connect_string of this GetDbConnectString200Response. # noqa: E501
:type connect_string: str
"""
self.openapi_types = {
'connect_string': str
}

self.attribute_map = {
'connect_string': 'connect_string'
}

self._connect_string = connect_string

@classmethod
def from_dict(cls, dikt) -> 'GetDbConnectString200Response':
"""Returns the dict as a model

:param dikt: A dict.
:type: dict
:return: The get_db_connect_string_200_response of this GetDbConnectString200Response. # noqa: E501
:rtype: GetDbConnectString200Response
"""
return util.deserialize_model(dikt, cls)

@property
def connect_string(self) -> str:
"""Gets the connect_string of this GetDbConnectString200Response.


:return: The connect_string of this GetDbConnectString200Response.
:rtype: str
"""
return self._connect_string

@connect_string.setter
def connect_string(self, connect_string: str):
"""Sets the connect_string of this GetDbConnectString200Response.


:param connect_string: The connect_string of this GetDbConnectString200Response.
:type connect_string: str
"""

self._connect_string = connect_string
19 changes: 18 additions & 1 deletion applications/samples/backend/samples/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ tags:
- description: ""
name: resource
paths:
/db-connect-string:
get:
description: Returns the database connection string for the current application.
operationId: get_db_connect_string
responses:
"200":
content:
application/json:
schema:
type: string
description: Database connection string returned successfully
"500":
description: Error retrieving database connection string
summary: Get database connection string
tags:
- database
x-openapi-router-controller: samples.controllers.database_controller
/error:
get:
operationId: error
Expand Down Expand Up @@ -336,4 +353,4 @@ components:
in: cookie
name: kc-access
type: apiKey
x-apikeyInfoFunc: samples.controllers.security_controller_.info_from_cookieAuth
x-apikeyInfoFunc: cloudharness.auth.decode_token
10 changes: 8 additions & 2 deletions applications/samples/deploy/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ harness:
size: 10Mi
usenfs: false
auto: true
port: 8080
port: 8080
gateway:
path: /
pathType: Prefix
proxy:
gatekeeper:
replicas: 1
Expand Down Expand Up @@ -96,4 +99,7 @@ harness:

dockerfile:
buildArgs:
TEST_ARGUMENT: example value
TEST_ARGUMENT: example value
database:
type: postgres
connect_string: "test connection string"
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
networks:
- ch
restart: always
image: quay.io/gogatekeeper/gatekeeper:2.14.3
image: quay.io/gogatekeeper/gatekeeper:4.6.0
expose:
- '8080'
- '8443'
Expand Down
14 changes: 14 additions & 0 deletions deployment-configuration/helm/templates/auto-deployments.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ spec:
mountPath: "/opt/cloudharness/resources/secrets/{{ .app.harness.name }}"
readOnly: true
{{- end }}
{{- if kindIs "map" .app.harness.database }}
{{- if and (hasKey .app.harness.database "connect_string") .app.harness.database.connect_string }}
- name: db-external
mountPath: "/opt/cloudharness/resources/db"
readOnly: true
{{- end }}
{{- end }}
volumes:
- name: cloudharness-allvalues
configMap:
Expand Down Expand Up @@ -169,6 +176,13 @@ spec:
secret:
secretName: {{ .app.harness.deployment.name }}
{{- end }}
{{- if kindIs "map" .app.harness.database }}
{{- if and (hasKey .app.harness.database "connect_string") .app.harness.database.connect_string }}
- name: db-external
secret:
secretName: {{ printf "%s-db" .app.harness.deployment.name }}
{{- end }}
{{- end }}
---
{{- end }}

Expand Down
37 changes: 35 additions & 2 deletions deployment-configuration/helm/templates/auto-gatekeepers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ data:
forbidden-page: /templates/access-denied.html.tmpl
enable-default-deny: {{ $noWildcards }}
listen: 0.0.0.0:8080
enable-encrypted-token: false
enable-refresh-tokens: true
server-write-timeout: {{ .app.harness.proxy.timeout.send | default .root.Values.proxy.timeout.send | default 180 }}s
upstream-timeout: {{ .app.harness.proxy.timeout.read | default .root.Values.proxy.timeout.read | default 180 }}s
Expand All @@ -38,7 +39,6 @@ data:
tls-cert:
tls-private-key:
redirection-url: {{ ternary "https" "http" $tls }}://{{ .subdomain }}.{{ .root.Values.domain }}
encryption-key: AgXa7xRcoClDEU0ZDSH4X0XhL5Qy2Z2j
upstream-url: http://{{ .app.harness.service.name }}.{{ .app.namespace | default .root.Release.Namespace }}:{{ .app.harness.service.port | default 80}}
{{ if .app.harness.secured }}
{{ with .app.harness.uri_role_mapping }}
Expand Down Expand Up @@ -100,6 +100,34 @@ data:
</body>
</html>
---
{{- $gkSecretName := printf "%s-gk" .subdomain }}
{{- $existingGkSecret := (lookup "v1" "Secret" .root.Values.namespace $gkSecretName) }}
apiVersion: v1
kind: Secret
metadata:
name: {{ $gkSecretName }}
namespace: {{ .root.Values.namespace }}
labels:
app: {{ $gkSecretName }}
type: Opaque
stringData:
updated: {{ now | quote }}
{{- if .root.Values.proxy.gatekeeper.secret }}
encryption-key: {{ .root.Values.proxy.gatekeeper.secret | quote }}
{{- else }}
{{- $hasExisting := false }}
{{- if $existingGkSecret }}
{{- if eq (typeOf $existingGkSecret.data) (typeOf dict) }}
{{- if hasKey $existingGkSecret.data "encryption-key" }}
{{- $hasExisting = true }}
{{- end }}
{{- end }}
{{- end }}
{{- if not $hasExisting }}
encryption-key: {{ randAlphaNum 32 | quote }}
{{- end }}
{{- end }}
Comment on lines +103 to +129
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When an existing *-gk Secret is found, this template omits encryption-key from stringData. On helm upgrade this can clear the key from the Secret, breaking gatekeeper startup (the Deployment expects encryption-key). Prefer always rendering the key: use the provided .Values.proxy.gatekeeper.secret, else reuse the looked-up key (e.g. from $existingGkSecret.data["encryption-key"]), else generate a new one.

Copilot uses AI. Check for mistakes.
---
apiVersion: v1
kind: Service
metadata:
Expand Down Expand Up @@ -135,7 +163,7 @@ spec:
{{ include "deploy_utils.etcHosts" .root | indent 6 }}
containers:
- name: {{ .app.harness.service.name | quote }}
image: {{ .app.harness.proxy.gatekeeper.image | default .root.Values.proxy.gatekeeper.image | default "quay.io/gogatekeeper/gatekeeper:2.14.3" }}
image: {{ .app.harness.proxy.gatekeeper.image | default .root.Values.proxy.gatekeeper.image | default "quay.io/gogatekeeper/gatekeeper:4.6.0" }}
imagePullPolicy: IfNotPresent
{{ if .root.Values.local }}
securityContext:
Expand All @@ -147,6 +175,11 @@ spec:
value: /opt/proxy.yml
- name: PROXY_ENABLE_METRICS
value: "true"
- name: PROXY_ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: "{{ .subdomain }}-gk"
key: encryption-key
volumeMounts:
- name: "{{ .subdomain }}-gk-proxy-config"
mountPath: /opt/proxy.yml
Expand Down
21 changes: 21 additions & 0 deletions deployment-configuration/helm/templates/auto-secrets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,25 @@ stringData:
{{- end }}{{- end }}{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- define "deploy_utils.db_secret" }}
{{- $secret_name := printf "%s-db" .app.harness.deployment.name }}
apiVersion: v1
kind: Secret
metadata:
name: {{ $secret_name }}
namespace: {{ .root.Values.namespace }}
labels:
app: {{ .app.harness.deployment.name }}
type: Opaque
stringData:
connect_string: {{ .app.harness.database.connect_string | quote }}
---
{{- end }}
{{- range $app := .Values.apps }}
{{- if kindIs "map" $app.harness.database }}
{{- if and (hasKey $app.harness.database "connect_string") $app.harness.database.connect_string }}
{{- include "deploy_utils.db_secret" (dict "root" $ "app" $app) }}
{{- end }}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ spec:
solvers:
- http01:
ingress:
class: nginx
class: {{ .Values.ingress.ingressClass }}
{{ end }}
3 changes: 3 additions & 0 deletions deployment-configuration/helm/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ data:
{{- range $key, $val := .Values.apps }}
{{- $app := get $values_copy.apps $key }}
{{- $tmp := set $app.harness "secrets" dict }}
{{- if kindIs "map" $app.harness.database }}
{{- $tmp := unset $app.harness.database "connect_string" }}
{{- end }}
{{- end }}
{{ $values_copy | toYaml | indent 4 }}
Loading
Loading