From 846316cc4598fb40dfaad524958336021c8abc8f Mon Sep 17 00:00:00 2001 From: Conan Scott Date: Sun, 12 Apr 2026 11:26:36 +0000 Subject: [PATCH] Secure token migration: gateway-token, hooks-token, telegram-bot-token as OCP secrets + startup script patch for hooks.token --- manifests/deployment.yaml | 128 ++++++++++++-------------------------- 1 file changed, 41 insertions(+), 87 deletions(-) diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml index 39f264f..f48e1a5 100644 --- a/manifests/deployment.yaml +++ b/manifests/deployment.yaml @@ -17,93 +17,6 @@ spec: spec: serviceAccountName: openclaw - initContainers: - - name: secret-injector - image: default-route-openshift-image-registry.apps.lab.apilab.us/openclaw/openclaw:latest - command: ["/bin/sh", "-c"] - args: - - | - set -e - JS=/home/node/.openclaw/openclaw.json - GATEWAY_TOKEN=$(cat /run/secrets/gateway-token/token) - HOOKS_TOKEN=$(cat /run/secrets/hooks-token/token) - TELEGRAM_BOT_TOKEN=$(cat /run/secrets/telegram-bot-token/token) - - # Bootstrap a minimal config if none exists yet - if [ ! -f $JS ]; then - node /app/openclaw.mjs onboard --non-interactive --accept-risk \ - --gateway-port 18789 --gateway-bind lan \ - --skip-daemon --skip-channels --skip-skills --skip-health --skip-ui - fi - - # Patch openclaw.json with tokens sourced from OCP secrets - node -e " - const fs = require('fs'); - const gatewayToken = '$GATEWAY_TOKEN'; - const hooksToken = '$HOOKS_TOKEN'; - const telegramBotToken = '$TELEGRAM_BOT_TOKEN'; - - const d = JSON.parse(fs.readFileSync('$JS', 'utf8')); - - // Gateway token (env var) - d.gateway = d.gateway || {}; - d.gateway.token = gatewayToken; - - // Hooks token + mappings (idempotent) - if (!d.hooks || !d.hooks.token) { - d.hooks = { - enabled: true, - path: '/hooks', - token: hooksToken, - allowRequestSessionKey: false, - mappings: [ - { - id: 'ocp-alerts', - match: { path: '/ocp-alerts' }, - action: 'agent', - name: 'OCP Alerts', - sessionKey: 'hook:ocp-alerts', - messageTemplate: 'You are an OCP cluster alert analyst for a Single Node OpenShift lab. An alert has fired. Compose a brief narrative notification and reply with ONLY the notification text — no preamble, no markdown, no tool calls.\n\nAlert details:\n- Name: {{groupLabels.alertname}}\n- Namespace: {{commonLabels.namespace}}\n- Severity: {{commonLabels.severity}}\n- Status: {{status}}\n- Summary: {{commonAnnotations.summary}}\n\nRules:\n1. If alertname contains \'Watchdog\': reply NO_REPLY and nothing else.\n2. Classify and write one of:\n - ACTIONABLE firing: \"🔴 [pod/component] is [what\'s wrong] in [namespace]. [One sentence likely cause]. Would you like me to take action?\"\n - RESOLVED: \"✅ Good news — [what] in [namespace] has resolved.\"\n - INFORMATIONAL: \"â„šī¸ Heads up — [brief narrative].\"\n3. Plain text only. No bullet points. No markdown. Under 3 sentences.', - deliver: true, - allowUnsafeExternalContent: true, - channel: 'telegram', - to: '6479169830', - model: 'haiku', - timeoutSeconds: 60 - } - ] - }; - } - - // Telegram bot token - d.channels = d.channels || {}; - d.channels.telegram = d.channels.telegram || {}; - d.channels.telegram.botToken = telegramBotToken; - d.channels.telegram.enabled = true; - - fs.writeFileSync('$JS', JSON.stringify(d, null, 2)); - " - - echo "secret-injector: openclaw.json patched from OCP secrets" - volumeMounts: - - name: home - mountPath: /home/node - env: - - name: TZ - value: "Australia/Sydney" - resources: - requests: - cpu: "10m" - memory: "32Mi" - limits: - cpu: "100m" - memory: "64Mi" - securityContext: - runAsUser: 1000950000 - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: false - containers: - name: openclaw image: default-route-openshift-image-registry.apps.lab.apilab.us/openclaw/openclaw:latest @@ -117,6 +30,37 @@ spec: --gateway-port 18789 --gateway-bind lan \ --skip-daemon --skip-channels --skip-skills --skip-health --skip-ui fi + # Patch hooks.token from OCP secret if not already set (idempotent) + if ! grep -q '"token":' ~/.openclaw/openclaw.json 2>/dev/null; then + node -e " + const fs = require('fs'); + const d = JSON.parse(fs.readFileSync(process.env.HOME + '/.openclaw/openclaw.json', 'utf8')); + d.hooks = d.hooks || {}; + d.hooks.token = process.env.HOOKS_TOKEN; + d.hooks.enabled = true; + d.hooks.path = '/hooks'; + d.hooks.allowRequestSessionKey = false; + d.hooks.mappings = d.hooks.mappings || []; + if (!d.hooks.mappings.find(m => m.id === 'ocp-alerts')) { + d.hooks.mappings.push({ + id: 'ocp-alerts', + match: { path: '/ocp-alerts' }, + action: 'agent', + name: 'OCP Alerts', + sessionKey: 'hook:ocp-alerts', + messageTemplate: 'You are an OCP cluster alert analyst for a Single Node OpenShift lab. An alert has fired. Compose a brief narrative notification and reply with ONLY the notification text \u2014 no preamble, no markdown, no tool calls.\n\nAlert details:\n- Name: {{groupLabels.alertname}}\n- Namespace: {{commonLabels.namespace}}\n- Severity: {{commonLabels.severity}}\n- Status: {{status}}\n- Summary: {{commonAnnotations.summary}}\n\nRules:\n1. If alertname contains \'Watchdog\': reply NO_REPLY and nothing else.\n2. Classify and write one of:\n - ACTIONABLE firing: \"\ud83d\udfe1 [pod/component] is [what\'s wrong] in [namespace]. [One sentence likely cause]. Would you like me to take action?\"\n - RESOLVED: \"\u2705 Good news \u2014 [what] in [namespace] has resolved.\"\n - INFORMATIONAL: \"\u2139\ufe0f Heads up \u2014 [brief narrative].\"\n3. Plain text only. No bullet points. No markdown. Under 3 sentences.', + deliver: true, + allowUnsafeExternalContent: true, + channel: 'telegram', + to: '6479169830', + model: 'haiku', + timeoutSeconds: 60 + }); + } + fs.writeFileSync(process.env.HOME + '/.openclaw/openclaw.json', JSON.stringify(d, null, 2)); + console.log('hooks.token patched from HOOKS_TOKEN env var'); + " + fi exec node /app/openclaw.mjs gateway --port 18789 --bind lan ports: - name: gateway @@ -155,6 +99,16 @@ spec: secretKeyRef: name: minimax key: token + - name: HOOKS_TOKEN + valueFrom: + secretKeyRef: + name: hooks-token + key: token + - name: TELEGRAM_BOT_TOKEN + valueFrom: + secretKeyRef: + name: telegram-bot-token + key: token volumeMounts: - name: home mountPath: /home/node