Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d3d0c2d8e9 | |||
| d965413a9d | |||
| 29e4527745 | |||
| f2d5d296e2 | |||
| afc44ebbf8 | |||
| 1ef1c0e456 | |||
| f182211601 | |||
| 5d46d3ada0 | |||
| e98dd8b0a2 |
@@ -1,6 +1,6 @@
|
|||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
name: pieced-operator
|
name: pieced-operator
|
||||||
description: PieCed IT tenant lifecycle operator
|
description: PieCed IT tenant lifecycle operator
|
||||||
version: 0.1.37
|
version: 0.1.46
|
||||||
appVersion: "0.1.37"
|
appVersion: "0.1.46"
|
||||||
type: application
|
type: application
|
||||||
|
|||||||
@@ -1,5 +1,18 @@
|
|||||||
# The package catalog is deployed as a ConfigMap in the operator namespace.
|
# The package catalog is deployed as a ConfigMap in the operator namespace.
|
||||||
# To update packages, edit the catalog data below and upgrade the Helm release.
|
# To update packages, edit the catalog data below and upgrade the Helm release.
|
||||||
|
#
|
||||||
|
# Categories:
|
||||||
|
# - core — toggles platform-level OpenClaw behaviour (heartbeat, cron,
|
||||||
|
# active-memory, voice) via config_patch. No channel bindings,
|
||||||
|
# no skills.
|
||||||
|
# - channel — adds a messaging channel (Telegram, Discord, …).
|
||||||
|
# - skill — adds a ClawHub or pack: skill ref to the OpenClawInstance.
|
||||||
|
#
|
||||||
|
# Quiet hours are not exposed as a separate package — in OpenClaw they live
|
||||||
|
# under the heartbeat config (via the active-window setting and via
|
||||||
|
# HEARTBEAT.md content rules). When we expose a tenant-tunable time range
|
||||||
|
# in the portal, it will become additional fields on core-heartbeat rather
|
||||||
|
# than its own package.
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
@@ -10,6 +23,185 @@ metadata:
|
|||||||
data:
|
data:
|
||||||
catalog.yaml: |
|
catalog.yaml: |
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# CORE — platform behaviour toggles. Patched into OCI config.raw via
|
||||||
|
# config_patch (deep-merged on top of the operator's safe defaults).
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
core-heartbeat:
|
||||||
|
name: Heartbeat (Proactive Checks)
|
||||||
|
category: core
|
||||||
|
description: >
|
||||||
|
Periodic agent run (default every 30 min) that lets the assistant
|
||||||
|
check inbox, calendar, and other configured sources and message
|
||||||
|
you proactively when something needs attention. Without this, the
|
||||||
|
assistant only responds when you message it first.
|
||||||
|
# OpenClaw 2026.x ships heartbeat ON by default (30m, or 1h on
|
||||||
|
# Anthropic OAuth) when agents.defaults.heartbeat is absent —
|
||||||
|
# see issues openclaw/openclaw#64293, #19445, #8123. The builder
|
||||||
|
# accordingly writes `every: "0m"` (the known off-switch) into
|
||||||
|
# the baseline configRaw. core-heartbeat's config_patch below
|
||||||
|
# overlays the 30m cadence on top of that. The actual checklist
|
||||||
|
# the heartbeat reads lives in workspace HEARTBEAT.md (seeded
|
||||||
|
# separately via spec.workspaceFiles); without a HEARTBEAT.md
|
||||||
|
# the heartbeat fires harmlessly and replies HEARTBEAT_OK.
|
||||||
|
#
|
||||||
|
# Quiet hours: OpenClaw supports both a config-level activeHours
|
||||||
|
# window under agents.defaults.heartbeat (skipped outside the
|
||||||
|
# window) and in-content rules inside HEARTBEAT.md. Neither is
|
||||||
|
# exposed in the portal yet — when added, they become extra
|
||||||
|
# fields on this package, not a separate core-quiet-hours
|
||||||
|
# package.
|
||||||
|
config_patch:
|
||||||
|
agents:
|
||||||
|
defaults:
|
||||||
|
heartbeat:
|
||||||
|
every: "30m"
|
||||||
|
|
||||||
|
core-cron:
|
||||||
|
name: Scheduled Tasks (Cron)
|
||||||
|
category: core
|
||||||
|
description: >
|
||||||
|
Allow the assistant to run scheduled tasks (daily briefings,
|
||||||
|
recurring reminders, periodic reports). Off by default. When
|
||||||
|
off, the agent's cron tool stays available but no scheduled
|
||||||
|
job ever fires.
|
||||||
|
# Flips the cron scheduler on. Default base configRaw sets
|
||||||
|
# cron.enabled=false (see builder.go), so this overlay only
|
||||||
|
# writes true when the package is enabled. Job storage lives on
|
||||||
|
# the tenant PVC at ~/.openclaw/cron/jobs.json by default.
|
||||||
|
config_patch:
|
||||||
|
cron:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
core-active-memory:
|
||||||
|
name: Active Memory
|
||||||
|
category: core
|
||||||
|
description: >
|
||||||
|
Lets the assistant recall stable preferences, recurring habits,
|
||||||
|
and long-term context from past conversations during a chat.
|
||||||
|
Uses an extra sub-agent turn per inbound message to query the
|
||||||
|
memory store. Direct-message sessions only — group and channel
|
||||||
|
sessions stay deterministic. Trades a small amount of token
|
||||||
|
cost for continuity and personalisation.
|
||||||
|
# OpenClaw 2026.5.x ships Active Memory as a plugin under
|
||||||
|
# plugins.entries.active-memory with a two-gate activation model:
|
||||||
|
# (1) the plugin must be enabled, (2) the request must be an
|
||||||
|
# eligible direct-chat session. Scoped to "main" agent and
|
||||||
|
# "direct" chat types for safe-default behaviour. The recall
|
||||||
|
# model inherits the session's chat model when available; the
|
||||||
|
# modelFallback is used only when nothing else resolves and
|
||||||
|
# should be present in LiteLLM. Adjust as needed for the
|
||||||
|
# platform's default cheap model.
|
||||||
|
config_patch:
|
||||||
|
plugins:
|
||||||
|
entries:
|
||||||
|
active-memory:
|
||||||
|
enabled: true
|
||||||
|
config:
|
||||||
|
enabled: true
|
||||||
|
agents: ["main"]
|
||||||
|
allowedChatTypes: ["direct"]
|
||||||
|
modelFallback: "pieced-mini"
|
||||||
|
queryMode: "recent"
|
||||||
|
promptStyle: "balanced"
|
||||||
|
timeoutMs: 15000
|
||||||
|
maxSummaryChars: 220
|
||||||
|
persistTranscripts: false
|
||||||
|
logging: false
|
||||||
|
|
||||||
|
core-voice:
|
||||||
|
name: Voice Interaction
|
||||||
|
category: core
|
||||||
|
description: >
|
||||||
|
Speech-to-text on incoming voice notes, automatic text-to-speech
|
||||||
|
on replies, and interactive Talk mode. Audio is routed through
|
||||||
|
PieCed's LiteLLM gateway so STT/TTS spend is tracked per-tenant
|
||||||
|
alongside chat usage. Inbound TTS uses kani-tts; Talk mode uses
|
||||||
|
kokoro-fastapi; STT uses self-hosted Whisper (faster-whisper-
|
||||||
|
large-v3). All three are private to the cluster.
|
||||||
|
# PHASE B — wired in. Toggling this package now installs the full
|
||||||
|
# voice surface into the tenant's OpenClawInstance config:
|
||||||
|
#
|
||||||
|
# - messages.tts: auto TTS on inbound replies, routed to
|
||||||
|
# `pieced-tts-inbound` (kani-tts behind LiteLLM).
|
||||||
|
# - talk: interactive Talk mode, routed to `pieced-tts-talk`
|
||||||
|
# (kokoro-fastapi behind LiteLLM). `interruptOnSpeech: true`
|
||||||
|
# so the agent stops talking when the user starts talking.
|
||||||
|
# - tools.media.audio: STT for inbound voice notes, capped at
|
||||||
|
# 20 MiB per message, routed to `pieced-stt` (whisper-openai
|
||||||
|
# behind LiteLLM).
|
||||||
|
#
|
||||||
|
# Provider config notes
|
||||||
|
# ---------------------
|
||||||
|
# `models.providers.openai` is declared here with no chat models
|
||||||
|
# (`models: []`) — its only role is to give the STT block under
|
||||||
|
# `tools.media.audio` a place to resolve its apiKey/baseUrl from.
|
||||||
|
# The agent's primary chat model still lives under
|
||||||
|
# `models.providers.litellm` (set in builder.go base) and is
|
||||||
|
# unaffected by this patch — deep-merge adds `openai` as a
|
||||||
|
# sibling provider, not a replacement.
|
||||||
|
#
|
||||||
|
# `allowPrivateNetwork: true` on the openai provider is required
|
||||||
|
# because the LiteLLM endpoint is a `http://*.svc` private-
|
||||||
|
# network address. Without it OpenClaw refuses the outbound
|
||||||
|
# call as a private-network destination.
|
||||||
|
#
|
||||||
|
# `${LITELLM_API_KEY}` is supplied via the tenant's envFrom
|
||||||
|
# secretRef (see builder.go), populated by ESO from
|
||||||
|
# secret/data/tenants/<ns>/litellm.
|
||||||
|
#
|
||||||
|
# Network policy
|
||||||
|
# --------------
|
||||||
|
# Audio traffic shares the existing LiteLLM egress hole in the
|
||||||
|
# per-tenant CiliumNetworkPolicy (toEndpoints inference ns,
|
||||||
|
# port 4000). No additional CNP rule needed — voice routes
|
||||||
|
# through the same gateway as chat completions.
|
||||||
|
config_patch:
|
||||||
|
models:
|
||||||
|
providers:
|
||||||
|
openai:
|
||||||
|
apiKey: "${LITELLM_API_KEY}"
|
||||||
|
baseUrl: "http://litellm.inference.svc:4000/v1"
|
||||||
|
models: []
|
||||||
|
request:
|
||||||
|
allowPrivateNetwork: true
|
||||||
|
messages:
|
||||||
|
tts:
|
||||||
|
auto: "inbound"
|
||||||
|
provider: "openai"
|
||||||
|
providers:
|
||||||
|
openai:
|
||||||
|
apiKey: "${LITELLM_API_KEY}"
|
||||||
|
baseUrl: "http://litellm.inference.svc:4000/v1"
|
||||||
|
model: "pieced-tts-inbound"
|
||||||
|
voice: "alloy"
|
||||||
|
talk:
|
||||||
|
provider: "openai"
|
||||||
|
providers:
|
||||||
|
openai:
|
||||||
|
apiKey: "${LITELLM_API_KEY}"
|
||||||
|
baseUrl: "http://litellm.inference.svc:4000/v1"
|
||||||
|
model: "pieced-tts-talk"
|
||||||
|
voice: "af_bella"
|
||||||
|
interruptOnSpeech: true
|
||||||
|
tools:
|
||||||
|
media:
|
||||||
|
audio:
|
||||||
|
enabled: true
|
||||||
|
maxBytes: 20971520
|
||||||
|
models:
|
||||||
|
- provider: "openai"
|
||||||
|
model: "pieced-stt"
|
||||||
|
baseUrl: "http://litellm.inference.svc:4000/v1"
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# CHANNELS — messaging integrations. Each ships a Channels map that
|
||||||
|
# the builder copies into config.channels, env_vars for credentials,
|
||||||
|
# and bindings so messages route to the default agent.
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
telegram:
|
telegram:
|
||||||
name: Telegram
|
name: Telegram
|
||||||
category: channel
|
category: channel
|
||||||
@@ -62,51 +254,216 @@ data:
|
|||||||
2. Create app, add bot, copy token and app ID
|
2. Create app, add bot, copy token and app ID
|
||||||
3. Invite bot to server with messages scope
|
3. Invite bot to server with messages scope
|
||||||
|
|
||||||
email:
|
# =====================================================================
|
||||||
name: Email (Gmail)
|
# SKILLS — ClawHub skill installs. Operator passes each entry through
|
||||||
category: channel
|
# to spec.skills on the OpenClawInstance.
|
||||||
description: Email integration via Gmail IMAP/SMTP
|
# =====================================================================
|
||||||
channels:
|
|
||||||
email:
|
|
||||||
enabled: true
|
|
||||||
settings:
|
|
||||||
provider: gmail
|
|
||||||
env_vars:
|
|
||||||
- name: EMAIL_ADDRESS
|
|
||||||
secret_key: address
|
|
||||||
vault_path_suffix: email
|
|
||||||
- name: EMAIL_APP_PASSWORD
|
|
||||||
secret_key: app-password
|
|
||||||
vault_path_suffix: email
|
|
||||||
bindings:
|
|
||||||
- match:
|
|
||||||
channel: email
|
|
||||||
egress_rules:
|
|
||||||
- host: imap.gmail.com
|
|
||||||
port: 993
|
|
||||||
- host: smtp.gmail.com
|
|
||||||
port: 465
|
|
||||||
|
|
||||||
web-search:
|
git-cli:
|
||||||
name: Web Search
|
name: Git CLI
|
||||||
category: skill
|
category: skill
|
||||||
description: Web search via internal SearXNG
|
description: >
|
||||||
|
Use git from the assistant's shell (clone, commit, push, pull,
|
||||||
|
diff, log, status). For private repositories, configure
|
||||||
|
credentials in your workspace.
|
||||||
skills:
|
skills:
|
||||||
- "pack:openclaw/skills/web-search@latest"
|
- "openlang-cn/git-cli"
|
||||||
|
egress_rules:
|
||||||
|
- host: github.com
|
||||||
|
port: 443
|
||||||
|
- host: gitlab.com
|
||||||
|
port: 443
|
||||||
|
|
||||||
|
github:
|
||||||
|
name: GitHub (gh CLI)
|
||||||
|
category: skill
|
||||||
|
description: >
|
||||||
|
Interact with GitHub repositories via the gh CLI — issues, PRs,
|
||||||
|
CI runs, releases, gists. Requires a personal access token.
|
||||||
|
skills:
|
||||||
|
- "steipete/github"
|
||||||
|
env_vars:
|
||||||
|
- name: GH_TOKEN
|
||||||
|
secret_key: token
|
||||||
|
vault_path_suffix: github
|
||||||
|
required: true
|
||||||
|
egress_rules:
|
||||||
|
- host: api.github.com
|
||||||
|
port: 443
|
||||||
|
- host: github.com
|
||||||
|
port: 443
|
||||||
|
- host: codeload.github.com
|
||||||
|
port: 443
|
||||||
|
customer_instructions: |
|
||||||
|
1. Open https://github.com/settings/tokens
|
||||||
|
2. Generate a fine-grained personal access token with the
|
||||||
|
repo scopes you want the assistant to use.
|
||||||
|
3. Copy the token (it is shown only once).
|
||||||
|
|
||||||
|
gitea:
|
||||||
|
name: Gitea
|
||||||
|
category: skill
|
||||||
|
description: >
|
||||||
|
Interact with a Gitea instance — repositories, issues, PRs,
|
||||||
|
releases. Defaults to the PieCed-platform Gitea at
|
||||||
|
git.c5ai.ch; supply your own GITEA_URL if you host elsewhere.
|
||||||
|
skills:
|
||||||
|
- "ericxliu1990/gitea"
|
||||||
|
env_vars:
|
||||||
|
- name: GITEA_URL
|
||||||
|
default: "https://git.c5ai.ch"
|
||||||
|
- name: GITEA_TOKEN
|
||||||
|
secret_key: token
|
||||||
|
vault_path_suffix: gitea
|
||||||
|
required: true
|
||||||
|
egress_rules:
|
||||||
|
- host: git.c5ai.ch
|
||||||
|
port: 443
|
||||||
|
customer_instructions: |
|
||||||
|
1. Log in to your Gitea instance (default https://git.c5ai.ch).
|
||||||
|
2. Go to Settings → Applications → Generate New Token.
|
||||||
|
3. Grant the scopes you want the assistant to use (repo, issue,
|
||||||
|
user — minimum needed for most workflows).
|
||||||
|
4. Copy the token.
|
||||||
|
|
||||||
|
whisper-self-hosted:
|
||||||
|
name: Whisper (Self-Hosted Transcription)
|
||||||
|
category: skill
|
||||||
|
description: >
|
||||||
|
Transcribe audio files via the platform's self-hosted Whisper
|
||||||
|
ASR instance. Useful for ad-hoc transcription tasks initiated
|
||||||
|
from chat; channel-level voice intake is handled separately by
|
||||||
|
the Voice CORE feature.
|
||||||
|
skills:
|
||||||
|
- "xavjer/openclaw-self-hosted-whisper"
|
||||||
|
env_vars:
|
||||||
|
- name: WHISPER_URL
|
||||||
|
default: "http://whisper-asr.whisper-asr.svc.cluster.local:9000"
|
||||||
|
|
||||||
|
searxng-local-search:
|
||||||
|
name: Web Search (SearXNG)
|
||||||
|
category: skill
|
||||||
|
description: >
|
||||||
|
Privacy-respecting web search via the platform's internal
|
||||||
|
SearXNG instance. Search the web, images, news, and more
|
||||||
|
without external API calls or trackers.
|
||||||
|
skills:
|
||||||
|
- "noblepayne/searxng-local-search"
|
||||||
env_vars:
|
env_vars:
|
||||||
- name: SEARXNG_URL
|
- name: SEARXNG_URL
|
||||||
default: "http://searxng.searxng.svc.cluster.local:8080"
|
default: "http://searxng.searxng.svc.cluster.local:8080"
|
||||||
egress_rules: []
|
|
||||||
|
|
||||||
document-processing:
|
gog:
|
||||||
name: Document Processing
|
name: Google Workspace (Gog)
|
||||||
category: skill
|
category: skill
|
||||||
description: PDF, DOCX, spreadsheet processing
|
description: >
|
||||||
|
Bundled access to Gmail, Calendar, Drive, Docs, Sheets, and
|
||||||
|
Contacts via Google OAuth. Setup requires a Google Cloud
|
||||||
|
project and an OAuth client. NOTE: OAuth flow is not yet
|
||||||
|
self-service in the portal — contact PieCed support for
|
||||||
|
credentials onboarding.
|
||||||
skills:
|
skills:
|
||||||
- "pack:openclaw/skills/document-processing@latest"
|
- "steipete/gog"
|
||||||
init_deps:
|
env_vars:
|
||||||
apt:
|
- name: GOG_CLIENT_ID
|
||||||
- pandoc
|
secret_key: client-id
|
||||||
- libreoffice-writer-nogui
|
vault_path_suffix: gog
|
||||||
- ffmpeg
|
required: true
|
||||||
egress_rules: []
|
- name: GOG_CLIENT_SECRET
|
||||||
|
secret_key: client-secret
|
||||||
|
vault_path_suffix: gog
|
||||||
|
required: true
|
||||||
|
- name: GOG_REFRESH_TOKEN
|
||||||
|
secret_key: refresh-token
|
||||||
|
vault_path_suffix: gog
|
||||||
|
required: true
|
||||||
|
egress_rules:
|
||||||
|
- host: oauth2.googleapis.com
|
||||||
|
port: 443
|
||||||
|
- host: www.googleapis.com
|
||||||
|
port: 443
|
||||||
|
- host: gmail.googleapis.com
|
||||||
|
port: 443
|
||||||
|
- host: calendar.googleapis.com
|
||||||
|
port: 443
|
||||||
|
- host: drive.googleapis.com
|
||||||
|
port: 443
|
||||||
|
- host: docs.googleapis.com
|
||||||
|
port: 443
|
||||||
|
- host: sheets.googleapis.com
|
||||||
|
port: 443
|
||||||
|
- host: people.googleapis.com
|
||||||
|
port: 443
|
||||||
|
customer_instructions: |
|
||||||
|
Google Workspace integration uses OAuth and requires manual
|
||||||
|
onboarding for now. Please open a support ticket to start
|
||||||
|
the setup process — we will exchange the client credentials
|
||||||
|
and a refresh token offline, then enable this package on
|
||||||
|
your tenant.
|
||||||
|
disclaimer: >
|
||||||
|
By enabling Google Workspace integration you authorize PieCed
|
||||||
|
to access Gmail, Calendar, Drive, Docs, Sheets, and Contacts
|
||||||
|
on your behalf. Data flows through Google's APIs subject to
|
||||||
|
Google's terms.
|
||||||
|
|
||||||
|
mail:
|
||||||
|
name: Email (IMAP / SMTP)
|
||||||
|
category: skill
|
||||||
|
description: >
|
||||||
|
Read, search, and manage email via IMAP; send via SMTP. Works
|
||||||
|
with Gmail (with an app password), Outlook, Fastmail, and any
|
||||||
|
standard IMAP/SMTP host. Replaces the previous Gmail-only
|
||||||
|
channel.
|
||||||
|
skills:
|
||||||
|
- "ivangdavila/mail"
|
||||||
|
env_vars:
|
||||||
|
- name: IMAP_HOST
|
||||||
|
secret_key: imap-host
|
||||||
|
vault_path_suffix: mail
|
||||||
|
required: true
|
||||||
|
- name: IMAP_USER
|
||||||
|
secret_key: imap-user
|
||||||
|
vault_path_suffix: mail
|
||||||
|
required: true
|
||||||
|
- name: IMAP_PASS
|
||||||
|
secret_key: imap-pass
|
||||||
|
vault_path_suffix: mail
|
||||||
|
required: true
|
||||||
|
- name: SMTP_HOST
|
||||||
|
secret_key: smtp-host
|
||||||
|
vault_path_suffix: mail
|
||||||
|
required: true
|
||||||
|
- name: SMTP_USER
|
||||||
|
secret_key: smtp-user
|
||||||
|
vault_path_suffix: mail
|
||||||
|
required: true
|
||||||
|
- name: SMTP_PASS
|
||||||
|
secret_key: smtp-pass
|
||||||
|
vault_path_suffix: mail
|
||||||
|
required: true
|
||||||
|
# The mail skill connects to tenant-supplied IMAP/SMTP servers on
|
||||||
|
# ports 993 / 465 / 587. The hostnames are not known at catalog
|
||||||
|
# time, so we open these ports to "world" rather than declaring
|
||||||
|
# FQDNs. Trade-off accepted for pilot — see catalog.EgressRule
|
||||||
|
# for the rule shape and rationale.
|
||||||
|
egress_rules:
|
||||||
|
- port: 993
|
||||||
|
world: true
|
||||||
|
- port: 465
|
||||||
|
world: true
|
||||||
|
- port: 587
|
||||||
|
world: true
|
||||||
|
customer_instructions: |
|
||||||
|
1. For Gmail: enable 2-Step Verification, then create an App
|
||||||
|
Password at https://myaccount.google.com/apppasswords and
|
||||||
|
use it as both IMAP and SMTP password.
|
||||||
|
2. For Outlook/Microsoft 365 with MFA: generate an app
|
||||||
|
password under your account's security settings.
|
||||||
|
3. For other providers: refer to their IMAP/SMTP documentation
|
||||||
|
for host names and ports.
|
||||||
|
4. Typical IMAP_HOST values: imap.gmail.com, outlook.office365.com.
|
||||||
|
5. Typical SMTP_HOST values: smtp.gmail.com, smtp.office365.com.
|
||||||
|
disclaimer: >
|
||||||
|
The assistant gains read/write access to the mailbox you
|
||||||
|
configure. Use a dedicated address rather than a personal
|
||||||
|
inbox if you want to limit scope.
|
||||||
|
|||||||
@@ -87,6 +87,18 @@ spec:
|
|||||||
suspend:
|
suspend:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: Stops reconciliation without deleting resources.
|
description: Stops reconciliation without deleting resources.
|
||||||
|
openClawImage:
|
||||||
|
type: object
|
||||||
|
description: >
|
||||||
|
Per-tenant override for the OpenClaw container image
|
||||||
|
tag. When unset, the operator uses the platform
|
||||||
|
default from the pieced-openclaw-config ConfigMap.
|
||||||
|
Set by platform admins via the portal; customer-
|
||||||
|
facing onboarding does not expose this field.
|
||||||
|
properties:
|
||||||
|
tag:
|
||||||
|
type: string
|
||||||
|
description: Image tag (e.g. "2026.4.22").
|
||||||
status:
|
status:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{{/*
|
||||||
|
Platform-wide default OpenClaw image tag. Used by the operator when a
|
||||||
|
PiecedTenant has no explicit `spec.openClawImage.tag` override.
|
||||||
|
|
||||||
|
Tag-only by design — see internal/openclawconfig/loader.go for
|
||||||
|
rationale (single image-selector field avoids SSA field-ownership
|
||||||
|
ambiguity). For reproducibility-critical deployments, pin by using
|
||||||
|
an immutable release tag.
|
||||||
|
|
||||||
|
If `defaultTag` is empty (or this ConfigMap doesn't exist), the
|
||||||
|
operator falls back to a hardcoded built-in version.
|
||||||
|
|
||||||
|
Tenants without an `openClawImage` override automatically follow
|
||||||
|
changes to this ConfigMap on the next reconcile — the operator
|
||||||
|
watches it and re-enqueues affected tenants.
|
||||||
|
*/}}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: pieced-openclaw-config
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: pieced-operator
|
||||||
|
data:
|
||||||
|
defaultTag: {{ .Values.openClaw.defaultTag | quote }}
|
||||||
@@ -8,9 +8,17 @@ metadata:
|
|||||||
app.kubernetes.io/name: pieced-operator
|
app.kubernetes.io/name: pieced-operator
|
||||||
rules:
|
rules:
|
||||||
# --- PiecedTenant CRD ---
|
# --- PiecedTenant CRD ---
|
||||||
|
# `delete` is required so the operator can self-initiate the post-
|
||||||
|
# 60-day cleanup of suspended tenants (Bug 37b). Without it, the
|
||||||
|
# `r.Delete(ctx, tenant)` call in the suspend block fails with a
|
||||||
|
# 403 every reconcile cycle while the tenant sits past its
|
||||||
|
# retention window. Until then this verb wasn't strictly needed —
|
||||||
|
# the customer/portal initiated CR deletes, and the operator's
|
||||||
|
# finalizer ran cleanup; only with operator-initiated deletion did
|
||||||
|
# the missing verb become a problem.
|
||||||
- apiGroups: ["pieced.ch"]
|
- apiGroups: ["pieced.ch"]
|
||||||
resources: ["piecedtenants"]
|
resources: ["piecedtenants"]
|
||||||
verbs: ["get", "list", "watch", "update", "patch"]
|
verbs: ["get", "list", "watch", "update", "patch", "delete"]
|
||||||
- apiGroups: ["pieced.ch"]
|
- apiGroups: ["pieced.ch"]
|
||||||
resources: ["piecedtenants/status"]
|
resources: ["piecedtenants/status"]
|
||||||
verbs: ["get", "update", "patch"]
|
verbs: ["get", "update", "patch"]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
image:
|
image:
|
||||||
repository: registry.c5ai.ch/pieced/pieced-operator
|
repository: registry.c5ai.ch/pieced/pieced-operator
|
||||||
tag: "0.1.37"
|
tag: "0.1.46"
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
imagePullSecrets:
|
imagePullSecrets:
|
||||||
@@ -56,3 +56,23 @@ serviceAccount:
|
|||||||
# Network policy — restrict operator egress to only what it needs
|
# Network policy — restrict operator egress to only what it needs
|
||||||
networkPolicy:
|
networkPolicy:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
|
# OpenClaw image default (Feature: per-tenant version overrides).
|
||||||
|
#
|
||||||
|
# Materialised as the `pieced-openclaw-config` ConfigMap, which the
|
||||||
|
# operator reads on every reconcile. Per-tenant overrides set via the
|
||||||
|
# portal (PiecedTenant.spec.openClawImage.tag) take precedence over
|
||||||
|
# this default for the affected tenants.
|
||||||
|
#
|
||||||
|
# We support tag-only (not digest) by design — a single image-selector
|
||||||
|
# field avoids SSA field-ownership ambiguity when switching values,
|
||||||
|
# and the downstream OpenClaw operator handles a tag-only image spec
|
||||||
|
# unambiguously. For reproducibility-critical deployments, pin by
|
||||||
|
# using an immutable release tag.
|
||||||
|
#
|
||||||
|
# Empty defaultTag falls back to the operator's built-in version.
|
||||||
|
# Admins can edit this value at runtime via the portal admin UI;
|
||||||
|
# the resulting ConfigMap edits trigger reconciles for every tenant
|
||||||
|
# that doesn't have its own override.
|
||||||
|
openClaw:
|
||||||
|
defaultTag: "2026.4.22"
|
||||||
|
|||||||
Reference in New Issue
Block a user