feat: initial commit — kubectl/configure, infisical/fetch-secret, helm/upgrade actions
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
# Docker Build and Push
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Build a Docker image and push it to the Gitea container registry
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `REGISTRY` | <p>Container registry hostname</p> | `false` | `gitea.pixelparasol.com` |
|
||||||
|
| `REGISTRY_USERNAME` | <p>Registry login username</p> | `false` | `deac` |
|
||||||
|
| `REGISTRY_TOKEN` | <p>Registry login token or password</p> | `true` | `""` |
|
||||||
|
| `IMAGE_PATH` | <p>Full registry image path (e.g. gitea.pixelparasol.com/stat-tackler/stat-tackler-api)</p> | `true` | `""` |
|
||||||
|
| `IMAGE_TAG` | <p>Tag to apply in addition to latest (e.g. stage-<sha>)</p> | `true` | `""` |
|
||||||
|
| `PLATFORMS` | <p>Comma-separated buildx platform list</p> | `false` | `linux/amd64,linux/arm/v7,linux/arm64` |
|
||||||
|
| `ARTIFACT_NAME` | <p>Name of the build artifact to download</p> | `false` | `dist` |
|
||||||
|
| `ARTIFACT_PATH` | <p>Destination path for the downloaded artifact</p> | `false` | `dist` |
|
||||||
|
| `TAG_LATEST` | <p>Also tag and push the image as latest</p> | `false` | `false` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
name: Docker Build and Push
|
||||||
|
description: Build a Docker image and push it to the Gitea container registry
|
||||||
|
inputs:
|
||||||
|
REGISTRY:
|
||||||
|
description: "Container registry hostname"
|
||||||
|
default: "gitea.pixelparasol.com"
|
||||||
|
REGISTRY_USERNAME:
|
||||||
|
description: "Registry login username"
|
||||||
|
default: "deac"
|
||||||
|
REGISTRY_TOKEN:
|
||||||
|
description: "Registry login token or password"
|
||||||
|
required: true
|
||||||
|
IMAGE_PATH:
|
||||||
|
description: "Full registry image path (e.g. gitea.pixelparasol.com/stat-tackler/stat-tackler-api)"
|
||||||
|
required: true
|
||||||
|
IMAGE_TAG:
|
||||||
|
description: "Tag to apply in addition to latest (e.g. stage-<sha>)"
|
||||||
|
required: true
|
||||||
|
PLATFORMS:
|
||||||
|
description: "Comma-separated buildx platform list"
|
||||||
|
default: "linux/amd64,linux/arm/v7,linux/arm64"
|
||||||
|
ARTIFACT_NAME:
|
||||||
|
description: "Name of the build artifact to download"
|
||||||
|
default: "dist"
|
||||||
|
ARTIFACT_PATH:
|
||||||
|
description: "Destination path for the downloaded artifact"
|
||||||
|
default: "dist"
|
||||||
|
TAG_LATEST:
|
||||||
|
description: "Also tag and push the image as latest"
|
||||||
|
default: "false"
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Login to Gitea Container Registry
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ inputs.REGISTRY }}
|
||||||
|
username: ${{ inputs.REGISTRY_USERNAME }}
|
||||||
|
password: ${{ inputs.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
- name: Download Build Artifact
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ inputs.ARTIFACT_NAME }}
|
||||||
|
path: ${{ inputs.ARTIFACT_PATH }}
|
||||||
|
|
||||||
|
- name: Docker Build and Push
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
TAGS="-t ${{ inputs.IMAGE_PATH }}:${{ inputs.IMAGE_TAG }}"
|
||||||
|
if [ "${{ inputs.TAG_LATEST }}" = "true" ]; then
|
||||||
|
TAGS="$TAGS -t ${{ inputs.IMAGE_PATH }}:latest"
|
||||||
|
fi
|
||||||
|
docker buildx build -f Dockerfile . \
|
||||||
|
--platform ${{ inputs.PLATFORMS }} \
|
||||||
|
--push \
|
||||||
|
$TAGS
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Create and Push Git Tag
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Creates and pushes a git tag in the current repository
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `tag` | <p>The tag name to create</p> | `true` | `""` |
|
||||||
|
| `token` | <p>Gitea token with repository write access</p> | `true` | `""` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
name: Create and Push Git Tag
|
||||||
|
description: Creates and pushes a git tag in the current repository
|
||||||
|
inputs:
|
||||||
|
tag:
|
||||||
|
description: "The tag name to create"
|
||||||
|
required: true
|
||||||
|
token:
|
||||||
|
description: "Gitea token with repository write access"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Create and push tag
|
||||||
|
shell: sh
|
||||||
|
env:
|
||||||
|
TAG: ${{ inputs.tag }}
|
||||||
|
TOKEN: ${{ inputs.token }}
|
||||||
|
run: |
|
||||||
|
git config user.email "gitea-actions@gitea.pixelparasol.com"
|
||||||
|
git config user.name "Gitea Actions"
|
||||||
|
git tag "${TAG}"
|
||||||
|
git push "https://gitea-actions:${TOKEN}@gitea.pixelparasol.com/${{ gitea.repository }}.git" "${TAG}"
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Helm Diff Deployment
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Diff a Helm chart for a deployment in a Kubernetes cluster
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `DEPLOYMENT_NAME` | <p>The Kubernetes Deployment to update</p> | `true` | `""` |
|
||||||
|
| `DEPLOYMENT_NAMESPACE` | <p>The Kubernetes namespace of the Deployment</p> | `true` | `""` |
|
||||||
|
| `IMAGE_PATH` | <p>The registry path to the image</p> | `true` | `""` |
|
||||||
|
| `IMAGE_TAG` | <p>The image tag to deploy</p> | `true` | `""` |
|
||||||
|
| `CONTAINER_NAME` | <p>The container component to update</p> | `true` | `""` |
|
||||||
|
| `VALUES_FILE` | <p>The values file to use</p> | `false` | `./helm/values.yaml` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
name: Helm Diff Deployment
|
||||||
|
description: Diff a Helm chart for a deployment in a Kubernetes cluster
|
||||||
|
inputs:
|
||||||
|
DEPLOYMENT_NAME:
|
||||||
|
description: "The Kubernetes Deployment to update"
|
||||||
|
required: true
|
||||||
|
DEPLOYMENT_NAMESPACE:
|
||||||
|
description: "The Kubernetes namespace of the Deployment"
|
||||||
|
required: true
|
||||||
|
IMAGE_PATH:
|
||||||
|
description: "The registry path to the image"
|
||||||
|
required: true
|
||||||
|
IMAGE_TAG:
|
||||||
|
description: "The image tag to deploy"
|
||||||
|
required: true
|
||||||
|
CONTAINER_NAME:
|
||||||
|
description: "The container component to update"
|
||||||
|
required: true
|
||||||
|
VALUES_FILE:
|
||||||
|
description: "The values file to use"
|
||||||
|
default: "./helm/values.yaml"
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Install Helm Diff
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
helm plugin list | grep -q diff || helm plugin install https://github.com/databus23/helm-diff
|
||||||
|
- name: Helm Diff
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
CMD="helm diff upgrade ${{ inputs.DEPLOYMENT_NAME }} ./helm -n ${{ inputs.DEPLOYMENT_NAMESPACE }} --values ${{ inputs.VALUES_FILE }} --set deploy.${{ inputs.CONTAINER_NAME }}.tag=${{ inputs.IMAGE_TAG }} --set image.repository=${{ inputs.IMAGE_PATH }} --context 5"
|
||||||
|
echo "Running: $CMD"
|
||||||
|
eval "$CMD"
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Helm Upgrade Deployment Image
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Set the image for a deployment in a Kubernetes
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `DEPLOYMENT_NAME` | <p>The Kubernetes Deployment to update</p> | `true` | `""` |
|
||||||
|
| `DEPLOYMENT_NAMESPACE` | <p>The Kubernetes namespace of the Deployment</p> | `true` | `""` |
|
||||||
|
| `IMAGE_PATH` | <p>The registry path to the image</p> | `true` | `""` |
|
||||||
|
| `IMAGE_TAG` | <p>The image tag to deploy</p> | `true` | `""` |
|
||||||
|
| `CONTAINER_NAME` | <p>The container component to update</p> | `true` | `""` |
|
||||||
|
| `VALUES_FILE` | <p>The values file to use</p> | `false` | `./helm/values.yaml` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
name: Helm Upgrade Deployment Image
|
||||||
|
description: Set the image for a deployment in a Kubernetes
|
||||||
|
inputs:
|
||||||
|
DEPLOYMENT_NAME:
|
||||||
|
description: "The Kubernetes Deployment to update"
|
||||||
|
required: true
|
||||||
|
DEPLOYMENT_NAMESPACE:
|
||||||
|
description: "The Kubernetes namespace of the Deployment"
|
||||||
|
required: true
|
||||||
|
IMAGE_PATH:
|
||||||
|
description: "The registry path to the image"
|
||||||
|
required: true
|
||||||
|
IMAGE_TAG:
|
||||||
|
description: "The image tag to deploy"
|
||||||
|
required: true
|
||||||
|
CONTAINER_NAME:
|
||||||
|
description: "The container component to update"
|
||||||
|
required: true
|
||||||
|
VALUES_FILE:
|
||||||
|
description: "The values file to use"
|
||||||
|
default: "./helm/values.yaml"
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Helm Set Image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
CMD="helm upgrade ${{ inputs.DEPLOYMENT_NAME }} ./helm -n ${{ inputs.DEPLOYMENT_NAMESPACE }} --values ${{ inputs.VALUES_FILE }} --set deploy.${{ inputs.CONTAINER_NAME }}.tag=${{ inputs.IMAGE_TAG }} --set image.repository=${{ inputs.IMAGE_PATH }}"
|
||||||
|
echo "Running: $CMD"
|
||||||
|
eval "$CMD"
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Helm Template Deployment
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Template a Helm chart for a deployment in a Kubernetes cluster
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `DEPLOYMENT_NAME` | <p>The Kubernetes Deployment to update</p> | `true` | `""` |
|
||||||
|
| `DEPLOYMENT_NAMESPACE` | <p>The Kubernetes namespace of the Deployment</p> | `true` | `""` |
|
||||||
|
| `IMAGE_PATH` | <p>The registry path to the image</p> | `true` | `""` |
|
||||||
|
| `IMAGE_TAG` | <p>The image tag to deploy</p> | `true` | `""` |
|
||||||
|
| `CONTAINER_NAME` | <p>The container component to update</p> | `true` | `""` |
|
||||||
|
| `VALUES_FILE` | <p>The values file to use</p> | `false` | `./helm/values.yaml` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
name: Helm Template Deployment
|
||||||
|
description: Template a Helm chart for a deployment in a Kubernetes cluster
|
||||||
|
inputs:
|
||||||
|
DEPLOYMENT_NAME:
|
||||||
|
description: "The Kubernetes Deployment to update"
|
||||||
|
required: true
|
||||||
|
DEPLOYMENT_NAMESPACE:
|
||||||
|
description: "The Kubernetes namespace of the Deployment"
|
||||||
|
required: true
|
||||||
|
IMAGE_PATH:
|
||||||
|
description: "The registry path to the image"
|
||||||
|
required: true
|
||||||
|
IMAGE_TAG:
|
||||||
|
description: "The image tag to deploy"
|
||||||
|
required: true
|
||||||
|
CONTAINER_NAME:
|
||||||
|
description: "The container component to update"
|
||||||
|
required: true
|
||||||
|
VALUES_FILE:
|
||||||
|
description: "The values file to use"
|
||||||
|
default: "./helm/values.yaml"
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Helm Template
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
CMD="helm template ${{ inputs.DEPLOYMENT_NAME }} ./helm -n ${{ inputs.DEPLOYMENT_NAMESPACE }} --values ${{ inputs.VALUES_FILE }} --set deploy.${{ inputs.CONTAINER_NAME }}.tag=${{ inputs.IMAGE_TAG }} --set image.repository=${{ inputs.IMAGE_PATH }}"
|
||||||
|
echo "Running: $CMD"
|
||||||
|
eval "$CMD"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# Helm Upgrade
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Login to an OCI registry, update chart dependencies, and run helm upgrade for the chart in the current directory
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `DEPLOYMENT_NAME` | <p>The Helm release name and target namespace</p> | `true` | `""` |
|
||||||
|
| `REGISTRY` | <p>OCI registry hostname for helm dependency login</p> | `true` | `""` |
|
||||||
|
| `REGISTRY_USERNAME` | <p>Username for OCI registry login</p> | `true` | `""` |
|
||||||
|
| `REGISTRY_TOKEN` | <p>Token for OCI registry login</p> | `true` | `""` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
name: Helm Upgrade
|
||||||
|
description: Login to an OCI registry, update chart dependencies, and run helm upgrade for the chart in the current directory
|
||||||
|
inputs:
|
||||||
|
DEPLOYMENT_NAME:
|
||||||
|
description: "The Helm release name and target namespace"
|
||||||
|
required: true
|
||||||
|
REGISTRY:
|
||||||
|
description: "OCI registry hostname for helm dependency login"
|
||||||
|
required: true
|
||||||
|
REGISTRY_USERNAME:
|
||||||
|
description: "Username for OCI registry login"
|
||||||
|
required: true
|
||||||
|
REGISTRY_TOKEN:
|
||||||
|
description: "Token for OCI registry login"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Helm OCI Login
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
echo "${{ inputs.REGISTRY_TOKEN }}" | helm registry login ${{ inputs.REGISTRY }} \
|
||||||
|
--username ${{ inputs.REGISTRY_USERNAME }} \
|
||||||
|
--password-stdin
|
||||||
|
|
||||||
|
- name: Helm Upgrade
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
helm dependency update
|
||||||
|
echo "Running: helm upgrade ${{ inputs.DEPLOYMENT_NAME }} ./ -n ${{ inputs.DEPLOYMENT_NAME }}"
|
||||||
|
helm upgrade ${{ inputs.DEPLOYMENT_NAME }} ./ -n ${{ inputs.DEPLOYMENT_NAME }}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Fetch Secret from Infisical
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Fetches a single secret value from Infisical using a machine identity token
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `INFISICAL_TOKEN` | <p>Machine identity access token</p> | `true` | `""` |
|
||||||
|
| `SECRET_NAME` | <p>The secret key to fetch</p> | `true` | `""` |
|
||||||
|
| `INFISICAL_HOST` | <p>Infisical API base URL</p> | `false` | `https://infisical.pixelparasol.com` |
|
||||||
|
| `WORKSPACE_ID` | <p>Infisical project UUID</p> | `false` | `""` |
|
||||||
|
| `ENVIRONMENT` | <p>Infisical environment slug</p> | `false` | `prod` |
|
||||||
|
| `SECRET_PATH` | <p>Folder path within the environment</p> | `false` | `/` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-outputs source="action.yml" -->
|
||||||
|
## Outputs
|
||||||
|
|
||||||
|
| name | description |
|
||||||
|
| --- | --- |
|
||||||
|
| `value` | <p>The fetched secret value</p> |
|
||||||
|
<!-- action-docs-outputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
name: Fetch Secret from Infisical
|
||||||
|
description: Fetches a single secret value from Infisical using a machine identity token
|
||||||
|
inputs:
|
||||||
|
INFISICAL_TOKEN:
|
||||||
|
description: "Machine identity access token"
|
||||||
|
required: true
|
||||||
|
SECRET_NAME:
|
||||||
|
description: "The secret key to fetch"
|
||||||
|
required: true
|
||||||
|
INFISICAL_HOST:
|
||||||
|
description: "Infisical API base URL"
|
||||||
|
required: false
|
||||||
|
default: "https://infisical.pixelparasol.com"
|
||||||
|
WORKSPACE_ID:
|
||||||
|
description: "Infisical project UUID"
|
||||||
|
required: true
|
||||||
|
ENVIRONMENT:
|
||||||
|
description: "Infisical environment slug"
|
||||||
|
required: false
|
||||||
|
default: "prod"
|
||||||
|
SECRET_PATH:
|
||||||
|
description: "Folder path within the environment"
|
||||||
|
required: false
|
||||||
|
default: "/"
|
||||||
|
outputs:
|
||||||
|
value:
|
||||||
|
description: "The fetched secret value"
|
||||||
|
value: ${{ steps.fetch.outputs.value }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Fetch secret
|
||||||
|
id: fetch
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
if ! command -v jq >/dev/null 2>&1; then
|
||||||
|
apk add --no-cache jq 2>/dev/null \
|
||||||
|
|| apt-get install -y -q --no-install-recommends jq 2>/dev/null \
|
||||||
|
|| { echo "Error: jq not available and could not be installed" >&2; exit 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
HTTP_STATUS=$(curl -s -o /tmp/_infisical_resp.json -w "%{http_code}" \
|
||||||
|
-H "Authorization: Bearer ${{ inputs.INFISICAL_TOKEN }}" \
|
||||||
|
"${{ inputs.INFISICAL_HOST }}/api/v3/secrets/raw/${{ inputs.SECRET_NAME }}?workspaceId=${{ inputs.WORKSPACE_ID }}&environment=${{ inputs.ENVIRONMENT }}&secretPath=${{ inputs.SECRET_PATH }}")
|
||||||
|
|
||||||
|
if [ "$HTTP_STATUS" != "200" ]; then
|
||||||
|
echo "Error: Infisical returned HTTP $HTTP_STATUS for secret '${{ inputs.SECRET_NAME }}'" >&2
|
||||||
|
echo "Response: $(cat /tmp/_infisical_resp.json)" >&2
|
||||||
|
rm -f /tmp/_infisical_resp.json
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RESPONSE=$(cat /tmp/_infisical_resp.json)
|
||||||
|
rm -f /tmp/_infisical_resp.json
|
||||||
|
|
||||||
|
VALUE=$(echo "$RESPONSE" | jq -r '.secret.secretValue')
|
||||||
|
|
||||||
|
if [ -z "$VALUE" ] || [ "$VALUE" = "null" ]; then
|
||||||
|
echo "Error: secret '${{ inputs.SECRET_NAME }}' is empty or not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DELIMITER="INFISICAL_EOF_$$"
|
||||||
|
echo "value<<${DELIMITER}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "$VALUE" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "${DELIMITER}" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Successfully fetched secret '${{ inputs.SECRET_NAME }}'"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Update Infra Version
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Updates the service tag in the stat-tackler-infra releases/versions.yaml
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `token` | <p>Gitea token with read/write access to the infra repo</p> | `true` | `""` |
|
||||||
|
| `service` | <p>Service name key in versions.yaml (e.g. stat-tackler-api)</p> | `true` | `""` |
|
||||||
|
| `tag` | <p>The image tag to set for the service</p> | `true` | `""` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
name: Update Infra Version
|
||||||
|
description: Updates the service tag in the stat-tackler-infra releases/versions.yaml
|
||||||
|
inputs:
|
||||||
|
token:
|
||||||
|
description: "Gitea token with read/write access to the infra repo"
|
||||||
|
required: true
|
||||||
|
service:
|
||||||
|
description: "Service name key in versions.yaml (e.g. stat-tackler-api)"
|
||||||
|
required: true
|
||||||
|
tag:
|
||||||
|
description: "The image tag to set for the service"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Clone infra repo
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
git clone https://gitea-actions:${{ inputs.token }}@gitea.pixelparasol.com/stat-tackler/stat-tackler-infra.git infra
|
||||||
|
|
||||||
|
- name: Install yq
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
|
||||||
|
chmod +x /usr/local/bin/yq
|
||||||
|
|
||||||
|
- name: Update tag in versions.yaml
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
cd infra
|
||||||
|
yq e ".services.${{ inputs.service }}.tag = \"${{ inputs.tag }}\"" -i releases/versions.yaml
|
||||||
|
|
||||||
|
- name: Commit and push
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
cd infra
|
||||||
|
git config user.email "gitea-actions@gitea.pixelparasol.com"
|
||||||
|
git config user.name "Gitea Actions"
|
||||||
|
git add releases/versions.yaml
|
||||||
|
git commit -m "chore: update ${{ inputs.service }} to ${{ inputs.tag }}"
|
||||||
|
git push
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Configure Kubectl
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Configure kubectl for use with Kubernetes
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `K8S_CONFIG` | <p>The RAW Kubernetes config</p> | `true` | `""` |
|
||||||
|
| `K8S_NAMESPACE` | <p>The K8S namespace</p> | `true` | `""` |
|
||||||
|
| `K8S_CONTEXT` | <p>The K8S context</p> | `true` | `""` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
name: Configure Kubectl
|
||||||
|
description: Configure kubectl for use with Kubernetes
|
||||||
|
inputs:
|
||||||
|
K8S_CONFIG:
|
||||||
|
description: "The RAW Kubernetes config"
|
||||||
|
required: true
|
||||||
|
K8S_NAMESPACE:
|
||||||
|
description: "The K8S namespace"
|
||||||
|
required: true
|
||||||
|
K8S_CONTEXT:
|
||||||
|
description: "The K8S context"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Configure kubectl
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
echo "Remove existing kubeconfig"
|
||||||
|
rm -f ~/.kube/config
|
||||||
|
|
||||||
|
echo "Re-creating .kube directory"
|
||||||
|
mkdir -p ~/.kube
|
||||||
|
|
||||||
|
echo "Set kubeconfig"
|
||||||
|
echo "${{ inputs.K8S_CONFIG }}" > ~/.kube/config
|
||||||
|
|
||||||
|
echo "Set kubeconfig context"
|
||||||
|
kubectl config set-context ${{ inputs.K8S_CONTEXT }} --cluster=${{ inputs.K8S_CONTEXT }} --namespace=${{ inputs.K8S_NAMESPACE }}
|
||||||
|
|
||||||
|
echo "Use kubeconfig context ${{ inputs.K8S_CONTEXT }}"
|
||||||
|
kubectl config use-context ${{ inputs.K8S_CONTEXT }}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Node Build
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Install dependencies, build, and upload a build artifact
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `INSTALL_CMD` | <p>Install command</p> | `false` | `npm ci` |
|
||||||
|
| `BUILD_SCRIPT` | <p>npm script to run for the main build</p> | `false` | `build:stage` |
|
||||||
|
| `EXTRA_BUILD_SCRIPT` | <p>Optional additional npm script to run after the main build</p> | `false` | `""` |
|
||||||
|
| `ARTIFACT_NAME` | <p>Name to give the uploaded artifact</p> | `false` | `dist` |
|
||||||
|
| `ARTIFACT_PATH` | <p>Path to upload as the artifact</p> | `false` | `dist` |
|
||||||
|
| `COPY_PRISMA_ENGINE` | <p>Copy the Prisma query engine binaries into the build directory</p> | `false` | `false` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
name: Node Build
|
||||||
|
description: Install dependencies, build, and upload a build artifact
|
||||||
|
inputs:
|
||||||
|
INSTALL_CMD:
|
||||||
|
description: "Install command"
|
||||||
|
default: "npm ci"
|
||||||
|
BUILD_SCRIPT:
|
||||||
|
description: "npm script to run for the main build"
|
||||||
|
default: "build:stage"
|
||||||
|
EXTRA_BUILD_SCRIPT:
|
||||||
|
description: "Optional additional npm script to run after the main build"
|
||||||
|
default: ""
|
||||||
|
ARTIFACT_NAME:
|
||||||
|
description: "Name to give the uploaded artifact"
|
||||||
|
default: "dist"
|
||||||
|
ARTIFACT_PATH:
|
||||||
|
description: "Path to upload as the artifact"
|
||||||
|
default: "dist"
|
||||||
|
COPY_PRISMA_ENGINE:
|
||||||
|
description: "Copy the Prisma query engine binaries into the build directory"
|
||||||
|
default: "false"
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v5
|
||||||
|
with:
|
||||||
|
node-version-file: package.json
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
shell: sh
|
||||||
|
run: ${{ inputs.INSTALL_CMD }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
npm run ${{ inputs.BUILD_SCRIPT }}
|
||||||
|
if [ -n "${{ inputs.EXTRA_BUILD_SCRIPT }}" ]; then
|
||||||
|
npm run ${{ inputs.EXTRA_BUILD_SCRIPT }}
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Copy Prisma Client Engine
|
||||||
|
if: inputs.COPY_PRISMA_ENGINE == 'true'
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
mkdir -p build/prisma
|
||||||
|
cp node_modules/.prisma/client/libquery_engine-* build/prisma/
|
||||||
|
|
||||||
|
- name: Upload Build Artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{ inputs.ARTIFACT_NAME }}
|
||||||
|
path: ${{ inputs.ARTIFACT_PATH }}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# test/npm
|
||||||
|
|
||||||
|
Composite action: install dependencies and run an npm test script.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| Input | Description | Default |
|
||||||
|
|---|---|---|
|
||||||
|
| `INSTALL_CMD` | Install command | `npm ci` |
|
||||||
|
| `TEST_SCRIPT` | npm script to run (must exist in `package.json`) | `test` |
|
||||||
|
| `WORKING_DIRECTORY` | Directory to run commands in | `.` |
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: stat-tackler/stat-tackler-infra/.gitea/actions/test/npm@main
|
||||||
|
with:
|
||||||
|
TEST_SCRIPT: test:unit
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common test scripts by project
|
||||||
|
|
||||||
|
| Project | Script | Runner |
|
||||||
|
|---|---|---|
|
||||||
|
| `stat-tackler-api` | `test` | Jest |
|
||||||
|
| `stat-tackler-scorekeeper` | `test:unit` | Vitest |
|
||||||
|
| `stat-tackler-scorekeeper` | `test:integration` | Vitest |
|
||||||
|
| `stat-tackler-scorekeeper` | `test:run` | Vitest (unit + integration) |
|
||||||
|
| `stat-tackler-scorekeeper` | `test:coverage` | Vitest |
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
name: NPM Test
|
||||||
|
description: Install dependencies and run npm tests
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
INSTALL_CMD:
|
||||||
|
description: "Install command"
|
||||||
|
default: "npm ci"
|
||||||
|
TEST_SCRIPT:
|
||||||
|
description: "npm script to run (must exist in package.json)"
|
||||||
|
default: "test"
|
||||||
|
WORKING_DIRECTORY:
|
||||||
|
description: "Directory to run commands in"
|
||||||
|
default: "."
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v5
|
||||||
|
with:
|
||||||
|
node-version-file: package.json
|
||||||
|
|
||||||
|
- name: Cache node_modules
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ${{ inputs.WORKING_DIRECTORY }}/node_modules
|
||||||
|
key: node-modules-${{ hashFiles(format('{0}/package-lock.json', inputs.WORKING_DIRECTORY)) }}
|
||||||
|
restore-keys: node-modules-
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
shell: sh
|
||||||
|
working-directory: ${{ inputs.WORKING_DIRECTORY }}
|
||||||
|
run: ${{ inputs.INSTALL_CMD }}
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
shell: sh
|
||||||
|
working-directory: ${{ inputs.WORKING_DIRECTORY }}
|
||||||
|
run: npm run ${{ inputs.TEST_SCRIPT }}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Trivy Scan Image
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Scan a container image with Trivy
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `IMAGE_PATH` | <p>The registry path to the image to scan</p> | `true` | `""` |
|
||||||
|
| `IMAGE_TAG` | <p>The image tag to scan</p> | `true` | `""` |
|
||||||
|
| `FAIL_HARD` | <p>Boolean: true will fail the build if vulnerabilities are found, false will not</p> | `false` | `false` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
name: Trivy Scan Image
|
||||||
|
description: Scan a container image with Trivy
|
||||||
|
inputs:
|
||||||
|
IMAGE_PATH:
|
||||||
|
description: "The registry path to the image to scan"
|
||||||
|
required: true
|
||||||
|
IMAGE_TAG:
|
||||||
|
description: "The image tag to scan"
|
||||||
|
required: true
|
||||||
|
FAIL_HARD:
|
||||||
|
description: "Boolean: true will fail the build if vulnerabilities are found, false will not"
|
||||||
|
required: false
|
||||||
|
default: 'false'
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Scan Container Registry Image
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
trivy image ${{ inputs.IMAGE_PATH }}:${{ inputs.IMAGE_TAG }} --report=all --exit-code=${{ contains(fromJSON('["true"]'), inputs.FAIL_HARD) && '1' || '0' }} --severity CRITICAL,HIGH
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Trivy Scan K8S Namespace
|
||||||
|
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Scan kubernetes namespace for vulnerabilities
|
||||||
|
<!-- action-docs-description source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
| name | description | required | default |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `NAMESPACE` | <p>The Kubernetes namespace to scan</p> | `true` | `""` |
|
||||||
|
<!-- action-docs-inputs source="action.yml" -->
|
||||||
|
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
|
## Runs
|
||||||
|
|
||||||
|
This action is a `composite` action.
|
||||||
|
<!-- action-docs-runs source="action.yml" -->
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
name: Trivy Scan K8S Namespace
|
||||||
|
description: Scan kubernetes namespace for vulnerabilities
|
||||||
|
inputs:
|
||||||
|
NAMESPACE:
|
||||||
|
description: "The Kubernetes namespace to scan"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: composite
|
||||||
|
steps:
|
||||||
|
- name: Scan Kubernetes Namespace
|
||||||
|
shell: sh
|
||||||
|
run: |
|
||||||
|
trivy k8s --namespace ${{ inputs.NAMESPACE }} --report=all all
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
ACTIONS := \
|
||||||
|
.gitea/actions/docker \
|
||||||
|
.gitea/actions/node \
|
||||||
|
.gitea/actions/git/create_tag \
|
||||||
|
.gitea/actions/helm/diff \
|
||||||
|
.gitea/actions/helm/set_deployment_image \
|
||||||
|
.gitea/actions/helm/template \
|
||||||
|
.gitea/actions/infra/update_version \
|
||||||
|
.gitea/actions/kubectl/configure \
|
||||||
|
.gitea/actions/trivy/image_scan \
|
||||||
|
.gitea/actions/trivy/namespace_scan
|
||||||
|
|
||||||
|
.PHONY: help docs
|
||||||
|
|
||||||
|
help: ## Show this help
|
||||||
|
@awk 'BEGIN {FS = ":.*##"; printf "Usage: make \033[36m<target>\033[0m [REGION=us-east-2]\n"} \
|
||||||
|
/^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0,5) } \
|
||||||
|
/^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-16s\033[0m %s\n", $$1, $$2 }' \
|
||||||
|
$(MAKEFILE_LIST)
|
||||||
|
|
||||||
|
##@ Setup
|
||||||
|
docs: ## Create litellm-secrets (prompts for master_key)
|
||||||
|
@for dir in $(ACTIONS); do \
|
||||||
|
echo "Generating docs for $$dir"; \
|
||||||
|
(cd $$dir && action-docs --no-banner --update-readme README.md); \
|
||||||
|
done
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# stat-tackler-infra
|
||||||
|
|
||||||
|
Central deployment repository for the stat-tackler platform. All production releases are coordinated from here.
|
||||||
|
|
||||||
|
## How to cut a production release
|
||||||
|
|
||||||
|
1. Update `releases/versions.yaml` with the semver tag you want deployed for each service.
|
||||||
|
2. Open a PR to `main` and merge it.
|
||||||
|
3. Publish a release in Gitea. The deploy workflow fires automatically and rolls out every service in the versions file.
|
||||||
|
|
||||||
|
To skip a service in a given release, comment it out in `versions.yaml`.
|
||||||
|
|
||||||
|
## Repository layout
|
||||||
|
|
||||||
|
```
|
||||||
|
.gitea/
|
||||||
|
actions/kubectl/configure/ # Reusable kubectl setup action
|
||||||
|
workflows/
|
||||||
|
deploy-prod.yaml # Coordinated production deployment
|
||||||
|
releases/
|
||||||
|
versions.yaml # Source of truth for what is deployed to production
|
||||||
|
```
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
| Service | Repo |
|
||||||
|
|---|---|
|
||||||
|
| API | `stat-tackler-api` |
|
||||||
|
| Auth UI | `stat-tackler-auth` |
|
||||||
|
| Scorekeeper UI | `stat-tackler-scorekeeper` |
|
||||||
|
| Admin UI | `stat-tackler-admin` |
|
||||||
|
| Marketing site | `stat-tackler-marketing` |
|
||||||
|
| Email relay | `stat-tackler-email-relay` |
|
||||||
|
| MCP server | `stat-tackler-mcp` |
|
||||||
|
|
||||||
|
Each service owns its own Helm chart (`./helm/`) and handles its own staging deploys. This repo only manages coordinated production releases.
|
||||||
|
|
||||||
|
## Runner requirements
|
||||||
|
|
||||||
|
The `helm` runner must have `helm`, `kubectl`, and `yq` available.
|
||||||
|
|
||||||
|
## Required secrets
|
||||||
|
|
||||||
|
| Secret | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `K8S_TROWBRIDGE_K0S0_CONFIG` | Kubeconfig for the production cluster |
|
||||||
|
| `REGISTRY_AGENT_TOKEN` | Gitea token with read access to all service repos and the container registry |
|
||||||
Reference in New Issue
Block a user