Skip to content

Strict env model, sensitive values never shown, and zerops_env action=request - #39

Merged
fxck merged 16 commits into
mainfrom
vault/strict
Oct 7, 2026
Merged

fxck merged 16 commits into
mainfrom
vault/strict

Conversation

@fxck

@fxck fxck commented Oct 7, 2026

Copy link
Copy Markdown
Member

zcp now acts as if Zerops' strict env isolation were on: a service reads only what its zerops.yml references. It also stops handing a person's sensitive values to the agent. This goes with Mate's vault, its new panel for a project's variables.

Security

  • Sensitive values were echoed in clear to the model wherever the token could read them. That covered zerops_discover includeEnvValues, the zerops_env set echo, and the preview diff of generate-dotenv / env plan. They are now masked as <redacted: sensitive> and flagged isSensitive.
  • classify_envs no longer drops the sensitive flag.
  • The export bundle never carries a sensitive value and never puts a value in a warning.

Strict model

  • Knowledge. Atoms, themes, the recipe brief and tool text now teach explicit references.
    • ${KEY} reads the service's own value, else Shared's; ${host_KEY} reads another service's.
    • At build, only Shared values and ${host_KEY} resolve.
    • KEY: ${KEY} gives the literal text (measured 2026-10-07). So an entry is named what the app reads, and the vault value carries another name: APP_KEY: ${APP_KEY_SECRET}.
  • zerops_env set takes sensitive on both scopes; when it's left out, the key's name decides. It restarts only the services whose deployed entries read the key and reports readers. When nothing reads the key, it restarts nothing and says a reference and a deploy are needed.
  • Deploy preflight fails a run.envVariables reference that nothing resolves.
  • zerops_env action=request asks the person for a value in Mate. It writes nothing; the value goes straight to the vault, never through the chat.
  • docs/spec-zerops-env-lifecycle.md records the 2026-10-07 measurements. docs/spec-mate.md §5.8 and §10.10 describe the vault and the strict model.

Verified

  • go test passes for internal/{ops,tools,content,platform,workflow}; make lint-local reports 0 issues.
  • Each fix was red first, then green.
  • TestInputSchemaByteBudget holds: the discover text was trimmed and zerops_env sits within its ceiling.

Open

  • Eval B3 env-service-scope-pair expects an unreferenced value after set; under the strict model it needs a reference.
  • R2 recovery reads ZEROPS_YAML, which app versions no longer carry.
  • generate-dotenv still merges every project value.
  • Recipes still rely on injection (Laravel APP_KEY in Shared with no reference). Recipes using KEY: ${KEY} break today.

🤖 Generated with Claude Code

fxck added 2 commits October 7, 2026 01:51
A value the platform holds with sensitive:true is a person's write-only
secret, yet a full token reads it back in clear and discover
includeEnvValues, the zerops_env set echo and the generate-dotenv preview
diff handed it to the model. RedactEnvValue (successor of
RedactCredentialValue) takes the row's flag and masks it as
<redacted: sensitive>; every presentation site routes through it and
annotates the key isSensitive. Internal value paths and the .env file
render keep the raw value.
@gitguardian

gitguardian Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

️✅ There are no secrets present in this pull request anymore.

If these secrets were true positive and are still valid, we highly recommend you to revoke them.
While these secrets were previously flagged, we no longer have a reference to the
specific commits where they were detected. Once a secret has been leaked into a git
repository, you should consider it compromised, even if it was deleted immediately.
Find here more information about risks.


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

fxck added 13 commits October 7, 2026 03:48
bundleProjectEnvsFromSource dropped the platform's sensitive flag, so a
sensitive project env classified plain-config rode into the export or
launch bundle verbatim. The flag now reaches the composer, which emits the
placeholder for a sensitive value in any bucket that would carry it. The
sentinel warning named the value it matched; it names the key only.
Under the strict env model a service's process reads exactly the entries
of its run.envVariables; a Shared, own or another service's value reaches
it only through an entry that references it. ServiceEnvScope classifies
every ${NAME} of a service's entries as zcp measured it live (entry chain,
self-shadow literal, own, Shared, ${host_KEY}, unresolved literal), and
EnvKeyReaders / ReadProjectEnvScopes answer which services read one key,
from the deployed rows.
A service-scope set was always written sensitive and a project-scope set
always plain. The set now takes an optional sensitive input for either
scope; left out, a key whose name reads as a secret (SECRET, TOKEN, KEY,
PASSWORD, PASS, DSN, PRIVATE, CREDENTIAL) is sensitive and any other plain.
Every write passes the flag explicitly, since an update without it turns a
sensitive value plain. The env schema's other descriptions are trimmed to
stay inside its byte budget.
A set or delete restarted every live runtime for a project key, and the
named service for its own key, as if Zerops injected every value. Under the
strict model a process reads only what its run.envVariables references, so
the restart targets are the readers: the runtimes whose deployed entries
reach the key directly, through a chain of entries, or as ${host_KEY}. The
response reports readers per key. Nothing reads it, nothing restarts, and
nextActions says how to reference it. A delete warns each reader that its
reference now reaches the app as the literal; a service whose rows cannot
be read is restarted in case it reads. The tool description states the
strict model.
The planted regression still forces the skipRestart branch of
applyAutoRestart; the patch is re-cut against the readers-based code and
the README names the unit test it now also breaks.
A ${NAME} in run.envVariables that is not another entry, the service's own
value, a Shared value or a platform key reaches the app as the literal
text. The deploy preflight now reads the project's Shared rows and the
target's own rows and fails such a reference, like the other broken-at-
runtime env checks; a failed read warns. ${host_KEY} stays the env_refs
check's and KEY: ${KEY} the self-shadow check's, whose message now states
the strict model: name the entry what the app reads, the value it
references differently.
The lifecycle spec gains §3b, how a run entry resolves under the strict
model zcp now acts on (renames, chains, own before Shared, KEY: ${KEY}
literal and poisoning, own values absent at build), and corrects what
changed: project-level sensitive persists, ZEROPS_YAML is gone from the
app-version rows, an update without sensitive turns a value plain, and
the duplicate-key guard is case-insensitive. Code comments that claimed
auto-inheritance or a non-persisting project flag follow.
Every value an app reads is a line in its zerops.yaml run.envVariables;
vault values (Shared, or the service's own) reach it only through one.
Since KEY: ${KEY} does not resolve yet, a line carries the name the app
reads and references a value of a different name. Secrets go in the vault
as sensitive, the person manages values in Mate's Vault panel or the
dashboard, and is never asked to paste one into the chat. The env atoms,
the knowledge themes and the recipe scaffold brief drop the auto-inject
advice; atom goldens regenerated.
A value only the person has (an API key, a password) is never asked for
in the chat. action=request validates the key, resolves the scope and
writes nothing: it answers requested {key, scope, sensitive} so Mate can
draw a field that writes straight to the vault, or alreadySet when the
key is in that vault, by presence only. The schema stays within its
byte ceiling (2546) by tightening the action and sensitive wording.
@fxck
fxck merged commit 78f4a63 into main Oct 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant