# services/maintenance/apps/ariadne-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: ariadne namespace: maintenance spec: replicas: 1 revisionHistoryLimit: 3 selector: matchLabels: app: ariadne template: metadata: labels: app: ariadne annotations: prometheus.io/scrape: "true" prometheus.io/port: "8080" prometheus.io/path: "/metrics" maintenance.bstein.dev/restart-rev: "20260413-jenkins-api-2" vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "maintenance" vault.hashicorp.com/agent-requests-cpu: "25m" vault.hashicorp.com/agent-limits-cpu: "100m" vault.hashicorp.com/agent-requests-mem: "32Mi" vault.hashicorp.com/agent-limits-mem: "128Mi" vault.hashicorp.com/agent-inject-secret-ariadne-env.sh: "kv/data/atlas/maintenance/ariadne-db" vault.hashicorp.com/agent-inject-template-ariadne-env.sh: | {{ with secret "kv/data/atlas/maintenance/ariadne-db" }} export ARIADNE_DATABASE_URL="{{ .Data.data.database_url }}" export JENKINS_API_USER="{{ .Data.data.jenkins_api_user }}" export JENKINS_API_TOKEN="{{ .Data.data.jenkins_api_token }}" {{- if .Data.data.sonarqube_token }} export ARIADNE_HERMES_SONAR_TOKEN="{{ .Data.data.sonarqube_token }}" {{- end }} {{- if .Data.data.game_mode_hook_token }} export GAME_MODE_HOOK_TOKEN="{{ .Data.data.game_mode_hook_token }}" {{- end }} {{ end }} {{ with secret "kv/data/atlas/hermes/triage-api" }} export ARIADNE_HERMES_API_KEY="{{ .Data.data.api_key }}" {{ end }} {{ with secret "kv/data/atlas/hermes/developer-gitea" }} export ARIADNE_HERMES_GITEA_TOKEN="{{ .Data.data.token }}" {{ end }} {{ with secret "kv/data/atlas/portal/atlas-portal-db" }} export PORTAL_DATABASE_URL="{{ .Data.data.PORTAL_DATABASE_URL }}" {{ end }} {{ with secret "kv/data/atlas/portal/bstein-dev-home-keycloak-admin" }} export KEYCLOAK_ADMIN_CLIENT_SECRET="{{ .Data.data.client_secret }}" {{ end }} {{ with secret "kv/data/atlas/nextcloud/nextcloud-db" }} export NEXTCLOUD_DB_NAME="{{ .Data.data.database }}" export NEXTCLOUD_DB_USER="{{ index .Data.data "db-username" }}" export NEXTCLOUD_DB_PASSWORD="{{ index .Data.data "db-password" }}" {{ end }} {{ with secret "kv/data/atlas/nextcloud/nextcloud-admin" }} export NEXTCLOUD_ADMIN_USER="{{ index .Data.data "admin-user" }}" export NEXTCLOUD_ADMIN_PASSWORD="{{ index .Data.data "admin-password" }}" {{ end }} {{ with secret "kv/data/atlas/health/wger-admin" }} export WGER_ADMIN_USERNAME="{{ .Data.data.username }}" export WGER_ADMIN_PASSWORD="{{ .Data.data.password }}" {{ end }} {{ with secret "kv/data/atlas/finance/firefly-secrets" }} export FIREFLY_CRON_TOKEN="{{ .Data.data.STATIC_CRON_TOKEN }}" {{ end }} {{ with secret "kv/data/atlas/mailu/mailu-db-secret" }} export MAILU_DB_NAME="{{ .Data.data.database }}" export MAILU_DB_USER="{{ .Data.data.username }}" export MAILU_DB_PASSWORD="{{ .Data.data.password }}" {{ end }} {{ with secret "kv/data/atlas/mailu/mailu-initial-account-secret" }} export SMTP_HOST="mailu-front.mailu-mailserver.svc.cluster.local" export SMTP_PORT="587" export SMTP_STARTTLS="true" export SMTP_USE_TLS="false" export SMTP_USERNAME="no-reply-portal@bstein.dev" export SMTP_PASSWORD="{{ .Data.data.password }}" export SMTP_FROM="no-reply-portal@bstein.dev" export MAILU_SYSTEM_PASSWORD="{{ .Data.data.password }}" {{ end }} {{ with secret "kv/data/atlas/comms/mas-admin-client-runtime" }} export COMMS_MAS_ADMIN_CLIENT_SECRET="{{ .Data.data.client_secret }}" {{ end }} {{ with secret "kv/data/atlas/comms/atlasbot-credentials-runtime" }} export COMMS_BOT_PASSWORD="{{ index .Data.data "bot-password" }}" export COMMS_SEEDER_PASSWORD="{{ index .Data.data "seeder-password" }}" {{ end }} {{ with secret "kv/data/atlas/comms/synapse-admin" }} export COMMS_SYNAPSE_ADMIN_TOKEN="{{ .Data.data.access_token }}" {{ end }} {{ with secret "kv/data/atlas/comms/synapse-db" }} export COMMS_SYNAPSE_DB_PASSWORD="{{ .Data.data.POSTGRES_PASSWORD }}" {{ end }} {{ with secret "kv/data/atlas/vault/vault-oidc-config" }} export VAULT_OIDC_DISCOVERY_URL="{{ .Data.data.discovery_url }}" export VAULT_OIDC_CLIENT_ID="{{ .Data.data.client_id }}" export VAULT_OIDC_CLIENT_SECRET="{{ .Data.data.client_secret }}" export VAULT_OIDC_DEFAULT_ROLE="{{ .Data.data.default_role }}" export VAULT_OIDC_SCOPES="{{ .Data.data.scopes }}" export VAULT_OIDC_USER_CLAIM="{{ .Data.data.user_claim }}" export VAULT_OIDC_GROUPS_CLAIM="{{ .Data.data.groups_claim }}" {{- if .Data.data.token_policies }} export VAULT_OIDC_TOKEN_POLICIES="{{ .Data.data.token_policies }}" {{- else }} export VAULT_OIDC_TOKEN_POLICIES="default" {{- end }} export VAULT_OIDC_ADMIN_GROUP="{{ .Data.data.admin_group }}" export VAULT_OIDC_ADMIN_POLICIES="{{ .Data.data.admin_policies }}" {{- if .Data.data.admin_bound_claims }} export VAULT_OIDC_ADMIN_BOUND_CLAIMS="{{ .Data.data.admin_bound_claims }}" {{- else }} export VAULT_OIDC_ADMIN_BOUND_CLAIMS="{\"groups\":\"admin\"}" {{- end }} export VAULT_OIDC_DEV_GROUP="{{ .Data.data.dev_group }}" export VAULT_OIDC_DEV_POLICIES="{{ .Data.data.dev_policies }}" export VAULT_OIDC_USER_GROUP="{{ .Data.data.user_group }}" export VAULT_OIDC_USER_POLICIES="{{ .Data.data.user_policies }}" export VAULT_OIDC_REDIRECT_URIS="{{ .Data.data.redirect_uris }}" export VAULT_OIDC_BOUND_AUDIENCES="{{ .Data.data.bound_audiences }}" {{- if .Data.data.ui_default_auth_method }} export VAULT_UI_DEFAULT_AUTH_METHOD="{{ .Data.data.ui_default_auth_method }}" {{- else }} export VAULT_UI_DEFAULT_AUTH_METHOD="oidc" {{- end }} {{- if .Data.data.ui_default_auth_path }} export VAULT_UI_DEFAULT_AUTH_PATH="{{ .Data.data.ui_default_auth_path }}" {{- else }} export VAULT_UI_DEFAULT_AUTH_PATH="oidc" {{- end }} {{- if .Data.data.bound_claims_type }} export VAULT_OIDC_BOUND_CLAIMS_TYPE="{{ .Data.data.bound_claims_type }}" {{- else }} export VAULT_OIDC_BOUND_CLAIMS_TYPE="string" {{- end }} {{ end }} spec: serviceAccountName: ariadne nodeSelector: kubernetes.io/arch: arm64 node-role.kubernetes.io/worker: "true" affinity: nodeAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 preference: matchExpressions: - key: hardware operator: In values: ["rpi5"] - weight: 95 preference: matchExpressions: - key: kubernetes.io/hostname operator: NotIn values: - titan-13 - titan-14 - titan-15 - titan-17 - titan-19 - weight: 80 preference: matchExpressions: - key: atlas.bstein.dev/spillover operator: DoesNotExist - weight: 50 preference: matchExpressions: - key: hardware operator: In values: ["rpi4"] containers: - name: ariadne image: registry.bstein.dev/bstein/ariadne:latest imagePullPolicy: Always command: ["/bin/sh", "-c"] args: - >- . /vault/secrets/ariadne-env.sh && exec uvicorn ariadne.app:app --host 0.0.0.0 --port 8080 ports: - name: http containerPort: 8080 env: - name: KEYCLOAK_URL value: https://sso.bstein.dev - name: KEYCLOAK_REALM value: atlas - name: KEYCLOAK_CLIENT_ID value: bstein-dev-home - name: KEYCLOAK_EXTRA_CLIENT_IDS value: wolf - name: KEYCLOAK_ISSUER value: https://sso.bstein.dev/realms/atlas - name: KEYCLOAK_JWKS_URL value: http://keycloak.sso.svc.cluster.local/realms/atlas/protocol/openid-connect/certs - name: KEYCLOAK_ADMIN_URL value: http://keycloak.sso.svc.cluster.local - name: KEYCLOAK_ADMIN_REALM value: atlas - name: KEYCLOAK_ADMIN_CLIENT_ID value: bstein-dev-home-admin - name: PORTAL_PUBLIC_BASE_URL value: https://bstein.dev - name: ARIADNE_LOG_LEVEL value: INFO - name: ARIADNE_DB_POOL_MIN value: "0" - name: ARIADNE_DB_POOL_MAX value: "5" - name: ARIADNE_DB_CONNECT_TIMEOUT_SEC value: "5" - name: ARIADNE_DB_LOCK_TIMEOUT_SEC value: "5" - name: ARIADNE_DB_STATEMENT_TIMEOUT_SEC value: "30" - name: ARIADNE_DB_IDLE_IN_TX_TIMEOUT_SEC value: "10" - name: ARIADNE_RUN_MIGRATIONS value: "false" - name: PORTAL_ADMIN_USERS value: bstein - name: PORTAL_ADMIN_GROUPS value: admin - name: ACCOUNT_ALLOWED_GROUPS value: dev,admin - name: ALLOWED_FLAG_GROUPS value: demo,test,vaultwarden_grandfathered - name: DEFAULT_USER_GROUPS value: dev - name: MAILU_DOMAIN value: bstein.dev - name: MAILU_HOST value: mail.bstein.dev - name: MAILU_SYNC_URL value: http://ariadne.maintenance.svc.cluster.local/events - name: MAILU_EVENT_MIN_INTERVAL_SEC value: "10" - name: MAILU_SYSTEM_USERS value: no-reply-portal@bstein.dev,no-reply-vaultwarden@bstein.dev - name: MAILU_MAILBOX_WAIT_TIMEOUT_SEC value: "180" - name: MAILU_DB_HOST value: postgres-service.postgres.svc.cluster.local - name: MAILU_DB_PORT value: "5432" - name: NEXTCLOUD_NAMESPACE value: nextcloud - name: NEXTCLOUD_POD_LABEL value: app=nextcloud - name: NEXTCLOUD_CONTAINER value: nextcloud - name: NEXTCLOUD_EXEC_TIMEOUT_SEC value: "120" - name: NEXTCLOUD_URL value: https://cloud.bstein.dev - name: NEXTCLOUD_DB_HOST value: postgres-service.postgres.svc.cluster.local - name: NEXTCLOUD_DB_PORT value: "5432" - name: WGER_NAMESPACE value: health - name: WGER_USER_SYNC_WAIT_TIMEOUT_SEC value: "90" - name: WGER_POD_LABEL value: app=wger - name: WGER_CONTAINER value: wger - name: WGER_ADMIN_EMAIL value: brad@bstein.dev - name: FIREFLY_NAMESPACE value: finance - name: FIREFLY_USER_SYNC_WAIT_TIMEOUT_SEC value: "90" - name: FIREFLY_POD_LABEL value: app=firefly - name: FIREFLY_CONTAINER value: firefly - name: FIREFLY_CRON_BASE_URL value: http://firefly.finance.svc.cluster.local/api/v1/cron - name: FIREFLY_CRON_TIMEOUT_SEC value: "30" - name: VAULT_NAMESPACE value: vault - name: VAULT_ADDR value: http://vault.vault.svc.cluster.local:8200 - name: VAULT_K8S_ROLE value: vault-admin - name: VAULT_K8S_ROLE_TTL value: 1h - name: GAME_MODE_NODE_NAME value: titan-24 - name: GAME_MODE_DISPLACE_WORKLOADS value: "[]" - name: GAME_MODE_LEASE_NAMESPACE value: hermes - name: GAME_MODE_LEASE_NAME value: titan-24-gpu-owner - name: GAME_MODE_OLLAMA_URL value: http://hermes-gpu-handoff.hermes.svc.cluster.local:11434 - name: GAME_MODE_OLLAMA_MODEL value: flux-2-klein-4b-local - name: GAME_MODE_OLLAMA_REQUEST_TIMEOUT_SEC value: "900" - name: GAME_MODE_TRANSITION_TIMEOUT_SEC value: "900" - name: GAME_MODE_POLL_INTERVAL_SEC value: "1" - name: WOLF_OIDC_CLIENT_ID value: wolf - name: WOLF_OIDC_BASE_URL value: https://wolf.bstein.dev - name: WOLF_OIDC_VAULT_PATH value: game-stream/wolf-oidc - name: ARIADNE_SCHEDULE_WOLF_OIDC value: "17 */6 * * *" - name: WOLF_API_URL value: http://wolf-api.game-stream.svc.cluster.local:8088 - name: WOLF_GATEKEEPER_URL value: http://wolf-gatekeeper.game-stream.svc.cluster.local:8087 - name: GAME_STREAM_FIREWALL_UNLOCK_TTL_SEC value: "28800" - name: GAME_STREAM_MOONLIGHT_HOST value: moonlight.bstein.dev - name: GAME_STREAM_USER_GROUP value: game-stream-users - name: GAME_STREAM_ADMIN_GROUP value: admin - name: GAME_STREAM_PROFILE_GROUP_PREFIX value: game-stream-profile- - name: COMMS_NAMESPACE value: comms - name: COMMS_SYNAPSE_BASE value: http://othrys-synapse-matrix-synapse.comms.svc.cluster.local:8008 - name: COMMS_AUTH_BASE value: http://matrix-authentication-service.comms.svc.cluster.local:8080 - name: COMMS_MAS_ADMIN_API_BASE value: http://matrix-authentication-service.comms.svc.cluster.local:8081/api/admin/v1 - name: COMMS_MAS_TOKEN_URL value: http://matrix-authentication-service.comms.svc.cluster.local:8080/oauth2/token - name: COMMS_MAS_ADMIN_CLIENT_ID value: 01KDXMVQBQ5JNY6SEJPZW6Z8BM - name: COMMS_SERVER_NAME value: live.bstein.dev - name: COMMS_ROOM_ALIAS value: "#othrys:live.bstein.dev" - name: COMMS_ROOM_NAME value: Othrys - name: COMMS_PIN_MESSAGE value: "Invite guests: share https://live.bstein.dev/#/room/#othrys:live.bstein.dev?action=join and choose 'Continue' -> 'Join as guest'." - name: COMMS_SEEDER_USER value: othrys-seeder - name: COMMS_BOT_USER value: atlasbot - name: COMMS_SYNAPSE_DB_HOST value: postgres-service.postgres.svc.cluster.local - name: COMMS_SYNAPSE_DB_PORT value: "5432" - name: COMMS_SYNAPSE_DB_NAME value: synapse - name: COMMS_SYNAPSE_DB_USER value: synapse - name: COMMS_TIMEOUT_SEC value: "30" - name: COMMS_GUEST_STALE_DAYS value: "14" - name: VAULTWARDEN_NAMESPACE value: vaultwarden - name: VAULTWARDEN_POD_LABEL value: app=vaultwarden - name: VAULTWARDEN_POD_PORT value: "80" - name: VAULTWARDEN_SERVICE_HOST value: vaultwarden-service.vaultwarden.svc.cluster.local - name: VAULTWARDEN_ADMIN_SECRET_NAME value: vaultwarden-admin - name: VAULTWARDEN_ADMIN_SECRET_KEY value: ADMIN_TOKEN - name: VAULTWARDEN_ADMIN_SESSION_TTL_SEC value: "900" - name: VAULTWARDEN_ADMIN_RATE_LIMIT_BACKOFF_SEC value: "600" - name: VAULTWARDEN_RETRY_COOLDOWN_SEC value: "1800" - name: VAULTWARDEN_FAILURE_BAILOUT value: "2" - name: ARIADNE_PROVISION_POLL_INTERVAL_SEC value: "5" - name: ARIADNE_PROVISION_RETRY_COOLDOWN_SEC value: "30" - name: ARIADNE_SCHEDULE_TICK_SEC value: "5" - name: ARIADNE_SCHEDULE_MAILU_SYNC value: "30 4 * * *" - name: ARIADNE_SCHEDULE_NEXTCLOUD_SYNC value: "*/15 * * * *" - name: ARIADNE_SCHEDULE_NEXTCLOUD_CRON value: "*/5 * * * *" - name: ARIADNE_SCHEDULE_NEXTCLOUD_MAINTENANCE value: "30 4 * * *" - name: ARIADNE_SCHEDULE_VAULTWARDEN_SYNC value: "*/15 * * * *" - name: ARIADNE_SCHEDULE_WGER_USER_SYNC value: "*/15 * * * *" - name: ARIADNE_SCHEDULE_WGER_ADMIN value: "15 3 * * *" - name: ARIADNE_SCHEDULE_FIREFLY_USER_SYNC value: "*/15 * * * *" - name: ARIADNE_SCHEDULE_FIREFLY_CRON value: "0 3 * * *" - name: ARIADNE_SCHEDULE_POD_CLEANER value: "*/30 * * * *" - name: ARIADNE_SCHEDULE_OPENSEARCH_PRUNE value: "23 3 * * *" - name: ARIADNE_SCHEDULE_IMAGE_SWEEPER value: "0 */4 * * *" - name: ARIADNE_SCHEDULE_VAULT_K8S_AUTH value: "0 0 1 1 *" - name: ARIADNE_SCHEDULE_VAULT_OIDC value: "0 0 1 1 *" - name: ARIADNE_SCHEDULE_COMMS_GUEST_NAME value: "*/5 * * * *" - name: ARIADNE_SCHEDULE_COMMS_PIN_INVITE value: "0 0 1 * *" - name: ARIADNE_SCHEDULE_COMMS_RESET_ROOM value: "0 0 1 1 *" - name: ARIADNE_SCHEDULE_COMMS_SEED_ROOM value: "*/10 * * * *" - name: ARIADNE_SCHEDULE_CLUSTER_STATE value: "*/10 * * * *" - name: ARIADNE_CLUSTER_STATE_KEEP value: "720" - name: WELCOME_EMAIL_ENABLED value: "true" - name: K8S_API_TIMEOUT_SEC value: "5" - name: ARIADNE_VM_URL value: http://victoria-metrics-single-server.monitoring.svc.cluster.local:8428 - name: ARIADNE_CLUSTER_STATE_VM_TIMEOUT_SEC value: "30" - name: ARIADNE_ALERTMANAGER_URL value: http://alertmanager.monitoring.svc.cluster.local - name: OPENSEARCH_URL value: http://opensearch-master.logging.svc.cluster.local:9200 - name: OPENSEARCH_LIMIT_BYTES value: "1099511627776" - name: OPENSEARCH_INDEX_PATTERNS value: kube-*,journald-*,trace-analytics-* - name: METIS_BASE_URL value: http://metis.maintenance.svc.cluster.local - name: METIS_TIMEOUT_SEC value: "15" - name: ARIADNE_SCHEDULE_METIS_SENTINEL_WATCH value: "*/30 * * * *" - name: ARIADNE_SCHEDULE_JENKINS_BUILD_WEATHER value: "*/10 * * * *" - name: JENKINS_BASE_URL value: https://ci.bstein.dev - name: JENKINS_API_TIMEOUT_SEC value: "10" - name: ARIADNE_SCHEDULE_JENKINS_WORKSPACE_CLEANUP value: "45 */6 * * *" - name: ARIADNE_SCHEDULE_TESTING_TRIAGE value: "*/15 * * * *" - name: ARIADNE_SCHEDULE_HERMES_AUTOTRIAGE value: "* * * * *" - name: ARIADNE_HERMES_AUTOTRIAGE_ENABLED value: "true" - name: ARIADNE_HERMES_AUTOTRIAGE_JOB_ALLOWLIST value: hermes-triage-demo,hermes-code-demo,ariadne,lesavka,soteria,metis,ananke,pegasus,atlasbot,bstein-dev-home,data-prepper - name: ARIADNE_HERMES_AUTOREMEDIATION_ENABLED value: "true" - name: ARIADNE_HERMES_ALLOWED_ACTIONS value: repair_demo_fixture,retry_transient_infra,reclaim_workspace_storage,clear_stuck_agent_pods # Each classification maps to exactly one action id. A diagnosis # whose classification is absent here can never reach an action, # and a diagnosis asking for an action that is not its # classification's own is refused before anything runs. - name: ARIADNE_HERMES_ACTION_CLASSIFICATIONS value: known_demo_fixture_failure=repair_demo_fixture,transient_infra_failure=retry_transient_infra,workspace_storage_exhausted=reclaim_workspace_storage,jenkins_agent_provisioning_failure=clear_stuck_agent_pods # Adds a service's own namespace to log evidence alongside # jenkins, so a build failure that coincides with the service being # unhealthy carries some trace of the service. Only mapped jobs are # affected; of the triaged services only this one runs in-cluster. - name: ARIADNE_HERMES_JOB_NAMESPACES value: bstein-dev-home=bstein-dev-home - name: ARIADNE_HERMES_MIN_CONFIDENCE value: "0.85" - name: ARIADNE_HERMES_MAX_ACTIONS_PER_INCIDENT value: "1" - name: ARIADNE_HERMES_API_URL value: http://hermes.hermes.svc.cluster.local:8642 - name: ARIADNE_HERMES_RUN_TIMEOUT_SECONDS value: "420" - name: ARIADNE_HERMES_CODE_ENABLED value: "true" - name: ARIADNE_HERMES_CODE_JOB value: hermes-code-demo - name: ARIADNE_HERMES_CODE_OWNER value: bstein - name: ARIADNE_HERMES_CODE_REPO value: hermes-code-demo - name: ARIADNE_HERMES_CODE_BASE_BRANCH value: master - name: ARIADNE_HERMES_CODE_CANDIDATE_PATH value: src/discount.py - name: ARIADNE_HERMES_CODE_ALLOWED_PREFIXES value: src/ - name: ARIADNE_HERMES_CODE_ALLOWED_SUFFIXES value: .py - name: ARIADNE_HERMES_CODE_MAX_PATCH_BYTES value: "4000" - name: ARIADNE_HERMES_CODE_MAX_CHANGED_LINES value: "20" - name: ARIADNE_HERMES_GITEA_BASE_URL value: https://scm.bstein.dev # File a Gitea issue in the failing service's own repository when # triage concludes a human is needed. Opt-in per job: only jobs # mapped here can ever receive an issue. Deduplicated by # job+classification so a repeatedly failing job produces one # issue per kind of failure, not one per build. - name: ARIADNE_HERMES_ISSUES_ENABLED value: "true" - name: ARIADNE_HERMES_ISSUE_REPOS value: metis=atlas/metis,lesavka=bstein/lesavka,soteria=atlas/soteria,bstein-dev-home=bstein/bstein-dev-home,ariadne=atlas/ariadne,ananke=atlas/ananke,pegasus=atlas/pegasus,atlasbot=bstein/atlasbot - name: ARIADNE_HERMES_ISSUE_DEDUPE_SCOPE value: classification - name: ARIADNE_HERMES_ISSUE_MAX_PER_TICK value: "2" # Homegrown repositories that may receive a Hermes patch proposal. # Escalated incidents on these jobs get an issue AND, when the # evidence implicates source files, a pull request on a # hermes-repair/ branch. Path allowlists are per repo so a # proposal can only ever touch that repo's source tree. # Review capacity, not correctness: proposals are cheap to make # and expensive to read. Below this ceiling an open pull request on # a repository is no reason to withhold a fix for a different # failure; at it, new proposals wait. # What Hermes may be asked to propose a fix for. Deliberately not # in ARIADNE_HERMES_ALLOWED_ACTIONS: that list gates what Ariadne # executes on its own authority, whereas everything here becomes a # pull request a person reads before anything changes. - name: ARIADNE_HERMES_FIX_CATEGORIES value: sonarqube_issue,lint_violation,undefined_name,failing_assertion - name: ARIADNE_HERMES_CODE_MAX_OPEN_PROPOSALS value: "64" # The SonarQube sweep: the second way into the proposal flow. Triage # enters on a build failure; static analysis never fails anything, so # its findings would otherwise sit unread forever. From evidence # collection onward the path is identical, gates included. # Printed in every pull request Hermes proposes, so a reviewer can # open the run that wrote it rather than taking "Proposed by # Hermes" on trust. - name: ARIADNE_HERMES_UI_URL value: https://triage.bstein.dev - name: ARIADNE_HERMES_SONAR_ENABLED value: "true" - name: ARIADNE_HERMES_SONAR_URL value: http://sonarqube.quality.svc.cluster.local:9000 # The browsable console, printed in each proposal so the finding # that caused it is one click away. - name: ARIADNE_HERMES_SONAR_UI_URL value: https://quality.bstein.dev # sonar-project=jenkins-job. The job already carries the repository # mapping in ARIADNE_HERMES_CODE_REPOS, so there is no second place # for the two to disagree. Only projects whose job also has a write # allowlist in ARIADNE_HERMES_CODE_PREFIXES are listed: without one # nothing is patchable, so a sweep would spend a SonarQube call to # discover it has nowhere to write. That excludes ananke, pegasus, # atlasbot, data_prepper and titan_iac for now. - name: ARIADNE_HERMES_SONAR_PROJECTS value: ariadne=ariadne,metis=metis,soteria=soteria,bstein_home=bstein-dev-home,ananke=ananke,pegasus=pegasus,atlasbot=atlasbot # Hotspots are absent by construction - they need human review, not a # patch - so only findings with a code fix are ever requested. - name: ARIADNE_HERMES_SONAR_TYPES value: CODE_SMELL,BUG # One per project per hourly sweep across seven projects. Rule-level # dedupe means a project stops producing proposals once every rule # it has is already under review, so this is a ceiling rather than a # rate: the backlog cannot turn into a pull request queue nobody # drains. The 64-open-proposal ceiling still applies on top. # Findings with no possible patch become an issue carrying the fix # Hermes would make. Most of the backlog is refactors too diffuse # for an anchored patch, so without this the majority of what # SonarQube knows never reaches a maintainer at all. Deduped on the # rule, exactly like the pull requests. - name: ARIADNE_HERMES_SONAR_ADVICE_ENABLED value: "true" - name: ARIADNE_HERMES_SONAR_MAX_PER_SWEEP value: "7" # SonarQube's own effort estimate is the filter, not severity: it is # the closest proxy for the single anchored change the patch # validator can check. Anything it calls longer than this is a # refactor for a person. - name: ARIADNE_HERMES_SONAR_MAX_EFFORT_MINUTES value: "20" - name: ARIADNE_HERMES_CODE_REPOS value: metis=atlas/metis,lesavka=bstein/lesavka,soteria=atlas/soteria,bstein-dev-home=bstein/bstein-dev-home,ariadne=atlas/ariadne,ananke=atlas/ananke,pegasus=atlas/pegasus,atlasbot=bstein/atlasbot - name: ARIADNE_HERMES_CODE_BASE_BRANCHES value: metis=master,lesavka=master,soteria=main,bstein-dev-home=master,ariadne=master,ananke=main,pegasus=main,atlasbot=main - name: ARIADNE_HERMES_CODE_PREFIXES value: metis=cmd/|pkg/,lesavka=server/|client/|common/,soteria=cmd/|internal/,bstein-dev-home=backend/|frontend/,ariadne=ariadne/,ananke=cmd/|internal/,pegasus=backend/|frontend/,atlasbot=atlasbot/ - name: ARIADNE_HERMES_CODE_SUFFIXES value: metis=.go,lesavka=.rs,soteria=.go,bstein-dev-home=.py|.ts|.tsx|.js,ariadne=.py,ananke=.go,pegasus=.go|.ts|.tsx|.js,atlasbot=.py - name: ARIADNE_TESTING_TRIAGE_MODEL_URL value: http://hermes-model-gate.hermes.svc.cluster.local:11434 - name: ARIADNE_TESTING_TRIAGE_MODEL value: qwen2.5:14b-instruct-q4_0 - name: ARIADNE_TESTING_TRIAGE_MODEL_TIMEOUT_SEC value: "900" - name: JENKINS_WORKSPACE_NAMESPACE value: jenkins - name: JENKINS_WORKSPACE_PVC_PREFIX value: pvc-workspace- - name: JENKINS_WORKSPACE_CLEANUP_MIN_AGE_HOURS value: "24" - name: JENKINS_WORKSPACE_CLEANUP_DRY_RUN value: "false" - name: JENKINS_WORKSPACE_CLEANUP_MAX_DELETIONS_PER_RUN value: "20" - name: METRICS_PATH value: "/metrics" resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi # timeoutSeconds defaults to 1, which this pod cannot honour. The # auto-triage tick runs every minute and spends most of it waiting on # Jenkins, OpenSearch, Gitea and Hermes; against a 500m CPU limit the # event loop occasionally takes longer than a second to answer # /health. Three of those in a row and the kubelet kills a container # that is working perfectly well. Observed 11 times in 139 minutes, # each one dropping triage ticks for the length of a restart. # Startup is the other way this pod gets killed while healthy. It # runs migrations and builds its schedule before it listens, which # can take longer than liveness allows from initialDelaySeconds # alone, and the kubelet then reports "connection refused" and # restarts a pod that was simply still booting. A startupProbe gives # boot up to five minutes and only then hands over to liveness. startupProbe: httpGet: path: /health port: http periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 30 livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 5 readinessProbe: httpGet: path: /health port: http initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3