ADR-017: Environment And Secret Policy
Geliştirme · 0.0.0-dev
Yayın
- Doküman
- 0.0.0-dev
- Uygulama
- 0.0.0
Bu sayfa
- Uygulama
- 0.0.0
- Status: Accepted
- Date: 2026-08-18
- Roadmap task: F1-007
- Decision owners: security and platform maintainers
Context
Bölüm başlığı “Context”Munderecat will eventually need browser-public connection metadata, server-private credentials, pipeline configuration and deployment secrets. If variable names and exposure are introduced ad hoc, a privileged value can be bundled into browser JavaScript, committed in a dotenv file, printed in CI or silently become an undocumented machine prerequisite.
The current repository does not yet require any environment variable. The web application is an independent empty state, the Python root has no runtime dependency, and Supabase local configuration uses no secret substitution. Inventing URL/key placeholders now would describe a runtime contract that does not exist.
Next.js explicitly inlines NEXT_PUBLIC_ values into browser bundles. Supabase
supports secret references through env(NAME) and instructs projects not to
commit real dotenv files.
Official references:
Decision
Bölüm başlığı “Decision”Canonical Registry
Bölüm başlığı “Canonical Registry”config/environment-policy.yml is the canonical environment-variable
registry. A variable is registered in the same change that introduces its first
consumer. Every definition declares:
scope:browser,serverortooling,- whether it is sensitive,
- whether the consumer requires it,
- whether an empty local value is valid,
- a non-empty purpose description.
Browser variables must use NEXT_PUBLIC_ and can never be sensitive. Server
and tooling variables cannot use that prefix. Registration does not authorize a
value to appear in logs, evidence or version control.
The registry contains variable definitions only. Security boundaries are fixed
in the validator rather than configurable by the file being validated:
.env.example is the canonical example, NEXT_PUBLIC_ is the browser prefix,
the repository root is the scan boundary, generated directories are pruned and
the required .gitignore rules are constant. Unknown registry keys fail
validation, so a policy edit cannot weaken these controls.
The initial registry is intentionally empty. .env.example states that the
current runtime requires no variables and gives the registry-first rule.
Files And Version Control
Bölüm başlığı “Files And Version Control”- Root
.env.exampleis the only committed dotenv file. .env,.env.*and package-local variants are machine-local and ignored;.env.exampleis the sole explicit exception.- The example lists every registered name. Sensitive examples must have an empty value.
- Dotenv symlinks are forbidden because they can escape repository ownership or change validation between check and use.
- Secret files, DB URLs with passwords, keys and credentials are never retained in execution evidence.
Runtime Exposure
Bölüm başlığı “Runtime Exposure”NEXT_PUBLIC_means public, build-time browser data. It is not a mechanism for passing secrets.- Server and tooling secrets are read only by their owning runtime. No shared fallback value or hard-coded development secret is added to source.
- Committed Supabase config refers to future secrets only through
env(NAME). - Hosted environments receive values from their platform secret manager; production values are not distributed through repository dotenv files.
Validation Boundary
Bölüm başlığı “Validation Boundary”scripts/bootstrap/validate_local_config.rb validates the structured dotenv
contract. It:
- accepts no caller-supplied path,
- scans repository-owned paths while pruning VCS, dependency, build and cache directories,
- rejects malformed/duplicate assignments, unregistered names, noncanonical examples and file or directory symlinks,
- validates registry shape and browser/private invariants,
- validates the required
.gitignorerules, - outputs paths, names and error codes only, never values.
Each structured config file is opened with NOFOLLOW; its canonical path and
the open file descriptor’s device/inode identity must agree before bytes are
read. Validation therefore reads the file it inspected and refuses intermediate
directory redirects instead of following repository-external dotenv content.
This is not a general secret scanner. F1-012 owns content/signature scanning, Git-history-aware CI checks and enforcement outside structured dotenv files.
make config-check runs focused validator tests followed by repository
validation. make verify includes that target before existing lock and web
checks.
Consequences
Bölüm başlığı “Consequences”Benefits
Bölüm başlığı “Benefits”- Variable names, exposure and ownership become reviewable before values exist.
- Browser-secret mistakes fail structurally.
- The empty initial example remains truthful and avoids copy-pasted fake keys.
- Validation errors and CI evidence cannot leak local values.
- Future consumers extend one registry and one Make target.
- Adding a variable requires policy and example changes with its consumer.
- Strict parsing intentionally rejects shell-style
export, interpolation and permissive dotenv syntax; local files use simpleNAME=valueassignments. - Runtime-specific required-value validation still belongs to the consuming application or command.
- Broad secret detection remains incomplete until F1-012.
Alternatives Considered
Bölüm başlığı “Alternatives Considered”Predeclare Supabase Browser Variables
Bölüm başlığı “Predeclare Supabase Browser Variables”The legacy reader used public Supabase URL/key names, but the new web package does not consume them yet. Predeclaring them would create a false current contract and was rejected.
Commit Local Development Credentials
Bölüm başlığı “Commit Local Development Credentials”Known local passwords or anonymous keys can appear harmless, but normalize credential material in Git and can later be copied into non-local contexts. They were rejected; local tools generate or inject values at runtime.
Documentation-Only Policy
Bölüm başlığı “Documentation-Only Policy”Prose explains intent but cannot reject a private NEXT_PUBLIC_ variable,
unregistered local config or accidental value disclosure. A machine-readable
registry and validator are required.
Encrypted Dotenv In Git
Bölüm başlığı “Encrypted Dotenv In Git”Encrypted dotenv tooling can be useful for teams with established key distribution, but adds bootstrap and rotation machinery before Munderecat has a real secret consumer. It is deferred.
Revisit Conditions
Bölüm başlığı “Revisit Conditions”- The first real environment consumer requires richer types, conditional rules or runtime precedence validation.
- Hosted deployment selects a secret manager and needs a generated registry adapter.
- Native Next.js or Supabase behavior changes browser exposure or config secret substitution semantics.
- F1-012 secret scanning identifies a gap that belongs in the structured local config boundary.