Greentic Secrets — What Changed & Why

A plain-language walkthrough of the secrets consolidation and the cloud-webhook fix.

✓ Consolidation merged  ·  Cloud-webhook fix implemented & hardened (1 PR awaiting merge)

Last updated 2026-06-16

The short version

Two things happened, both about secrets (sensitive values like signing keys and webhook tokens that the worker needs but must never be hard-coded):

First, what is a "secret" here?

A secret is any sensitive value the digital worker needs at run time but that must stay hidden — for example:

Signing key

Used to sign/verify tokens (a raw HMAC key). If leaked, anyone could forge a valid token.

Webhook secret

A per-channel token (Telegram, Slack, etc.). Incoming messages carry it so the worker knows the call is genuine.

Greentic stores each secret under a structured address (a URI), so every part of the system can find the same value the same way:

secrets://+ env/ tenant/ _  (team)/ category/ name

The team slot uses a literal underscore _ as the "no specific team" placeholder — consistently everywhere. Making that consistent was one of the goals.

Problem 1 — the same logic was copy-pasted in three places

Three different programs all needed to build that address, normalize names, and generate random secret values:

ProgramIts job
greentic-setupThe wizard that collects secrets from the operator.
greentic-deployerThe tool that pushes a deployment to the cloud (AWS / Azure / GCP).
greentic-startThe runtime that actually runs the flows and reads the secrets back.
Imagine three teams each keeping their own private copy of the company address book. The day one team edits a rule — say, "blank team becomes _" — the other two copies are now subtly wrong. Calls go to the wrong place. That is exactly how secret-address bugs were sneaking in.

The fix: one shared library

All the shared logic moved into the foundation crate greentic-secrets. The three programs now call that one library instead of each carrying a copy:

setup deployer start → all call → greentic-secrets (one source of truth)

What moved in: the name canonicalizer, the team placeholder (_), the address builder, the secret-value generator, and the secret://secrets:// reference converter. Each program still parses its own pack files, but it parses them into the shared model.

Problem 2 — the bug that started all of this

This is the one that mattered most. A webhook secret for a chat channel worked perfectly when you ran everything on your own machine, but vanished on a cloud deploy.

Why it broke

When you deploy to the cloud, the deployer copies your secrets up to the cloud secret manager. To know which secrets to copy, it read each pack's list of "required secrets". But a per-channel webhook secret is special:

So the deployer's secret scan looked in the wrong place for a thing that wasn't on its list — and never found it. Result:

webhook secret created locally✓ works on your machine
cloud deploy✗ secret never uploaded → cloud worker rejects incoming messages

The fix (PR #317)

The deployer now does three small, surgical things during a cloud deploy:

Deliberately not done: minting brand-new random secrets at deploy time (that would change the key on every deploy). The bug was "we never looked," not "we never generated." And no foundation-library changes were needed — the fix lives entirely in the deployer.

Status of every change

PRRepoWhat it doesStatus
#89greentic-secretsMove all shared secret logic into the foundation libraryMERGED + published
#316greentic-deployerUse the shared library for namingMERGED
#262greentic-startUse the shared library for namingMERGED
#148greentic-setupUse the shared library for namingMERGED
#317greentic-deployerUpload per-channel webhook secrets on cloud deployOPEN — ready to merge

PR #317 has been through an adversarial code review (Codex), every finding addressed or consciously skipped, a simplification pass, and the full local CI gate is green (format + lint + all tests; 31/31 in the affected module). It just needs your manual merge — auto-merge is intentionally off.

What is intentionally left for later

These are not bugs — they're deeper improvements we chose to defer so the urgent fix could land cleanly:

Is everything ready?

The consolidation is done and merged. The original cloud-webhook bug — the thing that kicked this off — is fixed, reviewed, hardened, and fully tested. The only remaining step is merging PR #317 (a one-click action you control). Everything beyond that is optional, deferred enhancement, not outstanding breakage.

Generated for an internal review of the Greentic secrets work · branch feat/cloud-promote-endpoint-webhooks · consolidation publish greentic-secrets-* 1.1.0-dev.27563392344.