feat(k3s): support env:// credentials and improve stale config cleanup on security_shield_v2

This commit is contained in:
stevef 2026-04-13 19:55:58 +02:00
parent 6b040ef853
commit f7c4820a84
4 changed files with 34 additions and 6 deletions

View file

@ -46,7 +46,7 @@ data:
},
"telegram": {
"enabled": true,
"token": "file://secrets/telegram-token",
"token": "env://PICOCLAW_TELEGRAM_TOKEN",
"base_url": "",
"proxy": "",
"allow_from": [
@ -258,7 +258,7 @@ data:
"model_name": "gemini-flash",
"model": "openai/gemini-3-flash-preview",
"api_base": "https://generativelanguage.googleapis.com/v1beta/openai/",
"api_key": "env://GOOGLE_API_KEY",
"api_key": "env://PICOCLAW_GOOGLE_API_KEY",
"request_timeout": 300
},
{

View file

@ -24,7 +24,9 @@ spec:
- |
mkdir -p /home/picoclaw/.picoclaw
echo "Syncing config.json from ConfigMap..."
grep "GOOGLE" /config-source/config.json
cp /config-source/config.json /home/picoclaw/.picoclaw/config.json
rm -f /home/picoclaw/.picoclaw/secure.yaml /home/picoclaw/.picoclaw/.security.yml
# Ensure the agent has write permissions to its home volume
chown -R 1000:1000 /home/picoclaw/.picoclaw
volumeMounts:
@ -43,6 +45,16 @@ spec:
value: /home/picoclaw/.picoclaw
- name: PICOCLAW_GATEWAY_HOST
value: "0.0.0.0"
- name: PICOCLAW_GOOGLE_API_KEY
valueFrom:
secretKeyRef:
name: picoclaw-secrets
key: GOOGLE_API_KEY
- name: PICOCLAW_TELEGRAM_TOKEN
valueFrom:
secretKeyRef:
name: picoclaw-secrets
key: telegram-token
volumeMounts:
- name: picoclaw-data
mountPath: /home/picoclaw/.picoclaw

View file

@ -225,12 +225,16 @@ func (s *SecureString) UnmarshalJSON(value []byte) error {
}
func (s SecureString) MarshalYAML() (any, error) {
// Preserve raw value if it is already a reference (enc:// or file://)
if strings.HasPrefix(s.raw, credential.EncScheme) || strings.HasPrefix(s.raw, credential.FileScheme) {
// Preserve raw value if it is already a reference (enc://, file://, or env://)
if strings.HasPrefix(s.raw, credential.EncScheme) ||
strings.HasPrefix(s.raw, credential.FileScheme) ||
strings.HasPrefix(s.raw, credential.EnvScheme) {
return s.raw, nil
}
// If resolved is a reference format (e.g. set via Set), copy back to raw
if strings.HasPrefix(s.resolved, credential.EncScheme) || strings.HasPrefix(s.resolved, credential.FileScheme) {
if strings.HasPrefix(s.resolved, credential.EncScheme) ||
strings.HasPrefix(s.resolved, credential.FileScheme) ||
strings.HasPrefix(s.resolved, credential.EnvScheme) {
s.raw = s.resolved
return s.raw, nil
}
@ -280,7 +284,9 @@ func resolveKey(v string) (string, error) {
if resolver == nil {
resolver = credential.NewResolver("")
}
if strings.HasPrefix(v, "enc://") || strings.HasPrefix(v, "file://") {
if strings.HasPrefix(v, credential.EncScheme) ||
strings.HasPrefix(v, credential.FileScheme) ||
strings.HasPrefix(v, credential.EnvScheme) {
decrypted, err := resolver.Resolve(v)
if err != nil {
logger.Errorf("Resolve error: %v", err)

View file

@ -77,6 +77,7 @@ const picoclawHome = "PICOCLAW_HOME"
const (
FileScheme = "file://"
EncScheme = "enc://"
EnvScheme = "env://"
hkdfInfo = "picoclaw-credential-v1"
saltLen = 16
@ -149,6 +150,15 @@ func (r *Resolver) Resolve(raw string) (string, error) {
return resolveEncrypted(raw)
}
if strings.HasPrefix(raw, EnvScheme) {
envVar := strings.TrimPrefix(raw, EnvScheme)
val := os.Getenv(envVar)
if val == "" {
return "", fmt.Errorf("credential: environment variable %q not set", envVar)
}
return strings.TrimSpace(val), nil
}
// Plaintext credential — return unchanged.
return raw, nil
}