Greentic Secrets — What Changed & Why

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

✓ All 5 PRs merged across 4 repos — consolidation + cloud-webhook fix fully landed

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 doesSizeStatus
#89 greentic-secrets Foundation — move all shared secret logic into the library +2054 / −611 MERGED
Jun 15 17:14 · published 1.1.0-dev.27563392344
#316 greentic-deployer Consumer — use the shared library for naming +412 / −178 MERGED
Jun 15 17:57
#262 greentic-start Consumer — use the shared library for naming +117 / −186 MERGED
Jun 15 19:06
#148 greentic-setup Consumer — use the shared library for naming +27 / −58 MERGED
Jun 15 19:18
#317 greentic-deployer The bug fix — upload per-channel webhook secrets on cloud deploy +513 / −57 MERGED
Jun 16 06:33

5 PRs across 4 repos. Every one went through an adversarial code review (Codex) with each finding addressed or consciously skipped, plus a simplification pass, before merge. Click any PR number to open it on GitHub. PR #89 is the foundation; #316 / #262 / #148 are the three consumers retiring their duplicated logic; #317 is the original cloud-webhook bug fix.

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?

Yes — everything is merged and shipped. All five PRs are in: the consolidation (one source of truth) and the original cloud-webhook bug fix — the thing that kicked this off — are fixed, reviewed, hardened, tested, and merged. Nothing is outstanding. Everything beyond this is optional, deferred enhancement, not breakage.

Generated for an internal review of the Greentic secrets work · all 5 PRs merged 2026-06-15 → 2026-06-16 · consolidation publish greentic-secrets-* 1.1.0-dev.27563392344.