fix(shared): F-S-009 require PICLOUD_DEV_INSECURE_KEY acknowledgement for dev master key

PICLOUD_DEV_MODE=true alone fell through to a fully public deterministic
master key — SHA-256("picloud-dev-master-key-v1.1.7"). The warning was
correct but the gate was a single env var. An operator copying a dev
docker-compose file into prod silently encrypted everything with a
world-known key.

Require both:
- PICLOUD_DEV_MODE=true
- PICLOUD_DEV_INSECURE_KEY=i-understand-this-is-insecure

Without the literal-string acknowledgement, MasterKey::from_env returns
the new DevModeUnacknowledged error and the process refuses to start.
Production deployments aren't affected (they set PICLOUD_SECRET_KEY).

AUDIT.md anchor: F-S-009.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-07 20:43:17 +02:00
parent 4923fa89e3
commit fbbe7676ae

View File

@@ -144,6 +144,15 @@ pub enum MasterKeyError {
/// Decoded to the wrong number of bytes.
#[error("PICLOUD_SECRET_KEY must decode to exactly {KEY_LEN} bytes, got {0}")]
WrongLength(usize),
/// F-S-009: PICLOUD_DEV_MODE=true was set without PICLOUD_SECRET_KEY,
/// AND without the explicit PICLOUD_DEV_INSECURE_KEY acknowledgement.
#[error(
"PICLOUD_DEV_MODE=true without PICLOUD_SECRET_KEY requires an explicit acknowledgement. \
Set PICLOUD_DEV_INSECURE_KEY=i-understand-this-is-insecure to confirm — but never in \
production: the dev master key is a fully public deterministic value."
)]
DevModeUnacknowledged,
}
impl MasterKey {
@@ -189,6 +198,18 @@ impl MasterKey {
let dev_mode = std::env::var("PICLOUD_DEV_MODE")
.map(|v| is_truthy(&v))
.unwrap_or(false);
// F-S-009: PICLOUD_DEV_MODE alone falls through to a fully
// public deterministic key (the warning is correct but the gate
// is a single env var — copying a dev docker-compose file into
// prod silently encrypts everything with a world-known key).
// Require an explicit second knob acknowledging the risk before
// we accept dev mode without a real secret.
let dev_ack = std::env::var("PICLOUD_DEV_INSECURE_KEY")
.map(|v| v == "i-understand-this-is-insecure")
.unwrap_or(false);
if dev_mode && secret.as_deref().map(str::trim).unwrap_or("").is_empty() && !dev_ack {
return Err(MasterKeyError::DevModeUnacknowledged);
}
Self::resolve(secret.as_deref(), dev_mode)
}