# VC-085 · Eksik ortam ayarı uygulamayı sessizce yanlış çalışma kipine geçiriyor

Dağıtımda zorunlu ortam değişkeni eksik kalıyor ama uygulama geliştirme varsayılanıyla açılıyor. Sağlık kontrolü başarılı görünürken kayıtlar kalıcı depoya gitmiyor ve süreç kapanınca kaybolabiliyor.

- Önem: YÜKSEK. Etkisi orta. Her gün, sıradan kullanımda tetiklenir.
- Önem notu: Eksik ayarla her başlangıçta bellek deposuna geçen ve yeni kayıtları kalıcı tutmayan akış temel alınır. Etki veri miktarına bağlıdır. Varsayılan kip yetkiyi veya gerçek ödeme davranışını değiştiriyorsa önem ayrıca yükselir.
- Eksen ve kategori: Sağlamlık, 12 Hata yolları ve dış çağrılar
- Yığın: Node.js, Her yığın
- Yapay zekâ kodunda: ölçülmedi. Dayanak: uzman görüşü.
- Ne zaman bakılır: İlk yayından önce, Her ay
- CWE: CWE-455
- Checklist ifadesi: Eksik bir ortam ayarı uygulamayı başlamadan durduruyor.
- Son inceleme: 4 Ekim 2026, Komünite editörlüğü
- Adres: https://vibecheck.komunite.com.tr/madde/ortam-degiskeni-eksikken-yanlis-kipte-aciliyor

## 60 saniyelik kontrol

Yalnız kendi uygulamanda ya da yazılı izin aldığın sistemde dene. Bu bir sızma testi değildir.

1. Zorunlu ortam ayarlarına eklenen geliştirme varsayılanlarını bul.
2. Yapay ortam nesnesinde bir zorunlu anahtarı sil ve başlangıcın durduğunu doğrula.
3. Boş, yanlış türde ve çelişen kip değerlerini ayrı ayrı dene.
4. Hata mesajının yalnız alan adını gösterdiğini ve sır değerini içermediğini kontrol et.
5. Geçerli üretim ve açıkça seçilmiş geliştirme ayarının çalıştığını doğrula.

## Ne oluyor

Uygulama geliştirirken kalıcı veritabanı olmadan açılabilsin diye bellek deposu ekleniyor. Ortam ayarı yoksa bu depo seçiliyor. Yerelde kullanışlı olan varsayılan dağıtıma da taşınıyor. Üretim ayarlarından biri eksik kaldığında sunucu yine açılıyor, sağlık kontrolü yanıt veriyor ve ilk kayıt ekranda görünüyor. Süreç yeniden başlayınca kayıt kalıcı depoda bulunamıyor.

Başlangıcın başarılı olması, uygulamanın amaçlanan kipte çalıştığını göstermiyor. Kod eksik ayarı bir tercih gibi ele almış oluyor. Dağıtım hatası görünür bir başlangıç hatası yerine sessiz davranış değişikliğine dönüşüyor. Kullanıcı ilk işlemi tamamladığında sorun fark edilmezse yeni veriler yanlış yere yazılmaya devam edebilir.

Eksiklik yalnız anahtarın hiç bulunmaması değildir. Boş değer, yanlış yazılmış kip veya birbirine uymayan ayarlar da aynı sonucu doğurabilir. Üretim kipi seçilmişken bellek deposuna izin vermek buna örnektir. Ayarların tek tek biçimi kadar birlikte anlamı da doğrulanmalıdır. Bu doğrulama istek kabulünden önce yapılırsa yanlış kipte çalışan süreç kullanıcının işini üstlenmez.

## Gerçek olay

Burada belirli bir dağıtım kazası anlatılmıyor. [CWE-455](https://cwe.mitre.org/data/definitions/455.html), başlangıç sırasında güvenlikle ilgili hata oluşmasına rağmen uygun biçimde durmayan veya davranışını değiştirmeyen ürünü ele alır. Her isteğe bağlı ayar eksikliği bu sınıfa girmez. Maddenin somut örneği, gerekli kalıcı depolamanın yanlış kip yüzünden devre dışı kalmasıdır.

[Node ortam değişkeni belgesi](https://nodejs.org/api/environment_variables.html), ortam değerlerinin metin olarak ele alındığını açıklar. [Zod şema API'si](https://zod.dev/api) bu değerlerin ve aralarındaki koşulların doğrulanmasını sağlar. Yerel deney gerçek ortam dosyası veya sır okumaz. Yapay ayar nesneleri kullanır ve geçersiz ayarda sunucu başlatma bağdaştırıcısının çağrılmadığını kontrol eder.

## Yapay zekâ bunu neden üretiyor

**Yerel kolaylık üretim varsayımına dönüşür.** Ajan örneği hemen çalıştırmak için eksik bağlantıyı bellek deposuyla tamamlayabilir. Bu kararın yalnız geliştirmeye ait olduğu kodda ifade edilmezse aynı seçim dağıtımda da geçerli olur. Uygulama açıldığı için eksik yapılandırma geçici olarak görünmez hale gelir ve yanlış kip olağan davranış sanılabilir.

**Ortam metni tür sanılır.** Ajan sayısal veya boolean görünen değeri doğrudan koşulda kullanabilir. Metin olarak gelen değer beklenen türle aynı değildir. Örneğin boş olmayan bir yanlış değerin doğruluk dönüşümü farklı sonuç verebilir. Şema açık değer kümesi seçtiğinde bu belirsizlik azalır. Dönüşüm kuralları değişkenin ürün anlamına göre yazılmalıdır.

**Anahtarlar ayrı ayrı incelenir.** Veritabanı adresi biçim olarak doğru, çalışma kipi de geçerli olabilir. Yine de seçilen kipin gerektirdiği başka alan eksik kalabilir. Ajan her alanı tek başına kontrol ettiğinde bu ilişkiyi atlayabilir. Üretim ve kalıcı depo koşulu gibi alanlar arası kurallar ayrı ifade edilmelidir.

**Başlangıç sırası unutulur.** Doğrulama fonksiyonu yazılmış olsa bile sunucu başladıktan sonra veya ilk istekte çağrılabilir. Böylece hazır sinyali ile gerçek çalışma hazırlığı ayrılır. Kodun varlığı kadar çağrıldığı nokta da önemlidir. Bunlar olası üretim mekanizmalarıdır. AI araçlarının eğitim verisi veya bu hatayı üretme sıklığı hakkında ölçülmüş sonuç sunulmuyor.

## Etki

Yeni kayıtlar yanlış depoya gidebilir ve süreç kapanınca kaybolabilir. Birden fazla uygulama örneği varsa her birinin ayrı belleği farklı sonuç gösterebilir. Kullanıcı bir istekte gördüğü veriyi başka istekte bulamayabilir. Destek ekibi dağıtımın sağlıklı göründüğünü görürken verinin nerede tutulduğunu araştırmak zorunda kalır.

Yanlış kip başka davranışları da etkileyebilir. Test bildirimi, sahte ödeme veya devre dışı yetki kontrolü gibi tercihler üretime taşınmış olabilir. Bu örnek o sistemleri kurmaz ve bu etkilerin gerçekleştiğini iddia etmez. Önem değerlendirmesi, eksik ayarın gerçekten hangi davranışı değiştirdiğine dayanmalıdır. Görsel bir tercihin varsayılanı aynı risk değildir.

## Nasıl anlarsın

Ortam okumalarını ve `||` veya `??` ile eklenen varsayılanları bul. Her varsayılanın üretimde de kabul edilip edilmediğini belirle. Ayarlar farklı dosyalarda tekrar okunuyorsa aynı eksikliğin farklı kararlar üretip üretmediğini kontrol et. Başlangıç doğrulamasının istek kabulünden önce çağrıldığına bak.

Yerel testte gerekli bir anahtarı sil, boş değer ver ve kipleri çeliştir. Başlatma adımı çalışmamalıdır. Ardından geçerli üretim ayarı ve açıkça seçilmiş geliştirme ayarıyla olumlu yolu dene. Hata mesajını da incele. Bağlantı adresi parola içerebileceği için ham değerleri veya bütün ortam nesnesini çıktıya yazdırma. Alan adı genellikle eksikliği bulmak için yeterlidir.

## Nasıl düzeltirsin

1. **Ayar sözleşmesini topla.** Zorunlu anahtarları, izinli değerleri ve alanlar arası koşulları tek yerde tanımla. Örnekte çalışma kipi ve depo kipi açık enum değerleridir. Geliştirme seçimi de kendiliğinden oluşmaz, ayarda belirtilir.
2. **Sessiz dönüşü kaldır.** Üretimde kalıcı depo gerektiren akış, eksik bağlantıda bellek deposuna geçmesin. Yanlış yazılmış kip de reddedilsin. Güvenli ve isteğe bağlı varsayılanları bu karardan ayrı değerlendir.
3. **Önce doğrula, sonra başlat.** İyi örnekte `start` önce şemayı çalıştırır. Hata varsa başlatma bağdaştırıcısına ulaşmaz. Geçerli sonuç dondurulmuş nesne olarak döner. Gerçek uygulamanın geri kalanı da doğrudan ortamı tekrar okumak yerine bu nesneyi kullanmalıdır.
4. **Biçimle bağlantıyı ayır.** Örnek PostgreSQL adres biçimini ve kip ilişkisini kontrol eder. Adresin erişilebilirliğini, hesabın doğru projeye ait olduğunu veya şemanın hazır bulunduğunu kanıtlamaz. Bunlar uygun başlangıç ve dağıtım kontrolleriyle ayrıca doğrulanmalıdır.

## Bir daha olmasın

Yeni zorunlu ayar eklenince eksik değer testini de ekle. Dağıtım şablonu, yerel örnek ayar ve doğrulama şemasını aynı değişiklikte güncel tut.

## Sınır

Bu madde eksik veya bozuk ayarın sessizce yanlış kipi seçmesini kapsar. Sırların saklanması, doğru projeye bağlantı ve çalışan yayının ortamı ayrı kontrollerdir. Test gerçek sunucu açmaz veya veritabanına bağlanmaz. Belgelenmiş, güvenli ve isteğe bağlı bir varsayılan tek başına bulgu değildir.

## Düzeltme kodları

### Node.js: Başlangıç ayarını şemayla doğrula

Önce:

```js
// config/baslangic.js, açıklama amaçlı. Gerçek sır veya bağlantı yok.
export function loadConfig(env) {
  // Eksik dağıtım ayarı geliştirme kolaylığıyla örtülüyor.
  return Object.freeze({
    APP_ENV: env.APP_ENV || 'development',
    STORAGE_MODE: env.STORAGE_MODE || 'memory',
    DATABASE_URL: env.DATABASE_URL || '',
  });
}
export function start(env, listen) {
  const config = loadConfig(env);
  return listen(config);
}
// Sunucu açıldığı için yayın başarılı görünebilir.
// Bellekteki kayıtlar süreç kapanınca kalıcı depoda bulunmaz.
```

Sonra:

```js
// config/baslangic.js, açıklama amaçlı. Zod 4, gerçek sır veya bağlantı yok.
import { z } from 'zod';
const schema = z.object({
  APP_ENV: z.enum(['production', 'development']),
  STORAGE_MODE: z.enum(['database', 'memory']),
  DATABASE_URL: z.string().optional(),
}).superRefine((value, ctx) => {
  if (value.APP_ENV === 'production' && value.STORAGE_MODE !== 'database') {
    ctx.addIssue({ code: 'custom', path: ['STORAGE_MODE'], message: 'Kalıcı depolama gerekli' });
  }
  if (value.STORAGE_MODE === 'database') {
    try {
      const url = new URL(value.DATABASE_URL);
      if (!['postgres:', 'postgresql:'].includes(url.protocol) || !url.hostname) throw new Error();
    } catch {
      ctx.addIssue({ code: 'custom', path: ['DATABASE_URL'], message: 'Bağlantı adresi gerekli' });
    }
  }
});
export function loadConfig(env) {
  const result = schema.safeParse({
    APP_ENV: env.APP_ENV, STORAGE_MODE: env.STORAGE_MODE, DATABASE_URL: env.DATABASE_URL,
  });
  if (!result.success) {
    const fields = [...new Set(result.error.issues.map(issue => issue.path.join('.')))];
    throw new Error(`Yapılandırma geçersiz: ${fields.join(', ')}`);
  }
  return Object.freeze(result.data);
}
export function start(env, listen) {
  const config = loadConfig(env); // İstek kabulünden önce doğrula.
  return listen(config);
}
// Şema bağlantının erişilebilirliğini veya doğru projeye ait olduğunu kanıtlamaz.
```

Düzeltmeyi kanıtlayan test:

```js
// config/baslangic.test.mjs, açıklama amaçlı. Yalnız yapay ortam nesneleri.
import test from 'node:test';
import assert from 'node:assert/strict';
const { start, loadConfig } = await import(process.env.ORNEK_DOSYA);
test('eksik veya çelişen ayar istek kabulünden önce durur', () => {
  let starts = 0;
  const listen = config => { starts++; return config; };
  const valid = { APP_ENV: 'production', STORAGE_MODE: 'database',
    DATABASE_URL: 'postgresql://demo:synthetic-only@db.example.invalid/catalog' };
  for (const env of [{}, { ...valid, APP_ENV: undefined },
    { ...valid, STORAGE_MODE: undefined }, { ...valid, STORAGE_MODE: 'memory' },
    { ...valid, DATABASE_URL: '' }, { ...valid, APP_ENV: 'prod' },
    { ...valid, DATABASE_URL: 'https://example.invalid' }]) {
    assert.throws(() => start(env, listen), /Yapılandırma geçersiz/);
  }
  assert.equal(starts, 0);
  assert.deepEqual(start(valid, listen), valid);
  assert.equal(starts, 1);
  assert.equal(loadConfig({ APP_ENV: 'development', STORAGE_MODE: 'memory' }).STORAGE_MODE, 'memory');
  assert.throws(() => loadConfig({ ...valid, DATABASE_URL: 'yapay-gizli-isaret' }), error => {
    assert.ok(!error.message.includes('yapay-gizli-isaret'));
    return true;
  });
});
```

## Ajan kuralı (AGENTS.md)

```md
## Eksik ayar yanlış kipi açıyor (vibecheck VC-085)
- Zorunlu çalışma ayarlarını istek kabulünden önce doğrula.
- Eksik üretim ayarını geliştirme varsayılanıyla doldurma.
- Kipler arasındaki çelişkileri şemada reddet.
- Ortam değerlerini açık tür ve değer kurallarıyla ayrıştır.
- Yapılandırma hatasında sır değerlerini yazdırma.
- Geçerli ayarı çalışma boyunca tek doğrulanmış nesneden oku.
```

## Kaynaklar

1. [Node.js Environment Variables](https://nodejs.org/api/environment_variables.html), Node.js
2. [Zod Defining Schemas](https://zod.dev/api), Zod
3. [CWE-455: Non-exit on Failed Initialization](https://cwe.mitre.org/data/definitions/455.html), MITRE

---

vibecheck · Komünite editörlüğü. Metin CC BY 4.0, prompt ve kural parçaları MIT-0. Kaynak: https://vibecheck.komunite.com.tr/madde/ortam-degiskeni-eksikken-yanlis-kipte-aciliyor
