# VC-096 · Yedek dosyası var ama geri yükleme ve uygulamanın açılması hiç denenmemiş

Yedekleme işi başarılı görünüyor fakat dosyanın kullanılabilir olduğu sınanmıyor. Arıza anında eksik tablo, uyumsuz sürüm veya erişilemeyen anahtar geri dönüşü engelleyebiliyor.

- Önem: ORTA. Etkisi büyük. Nadiren tetiklenir.
- Önem notu: Veri kaybı sonrası ilk geri yükleme girişiminin başarısız olması esas alınır. Yeniden üretilebilen geçici veri için etki düşer. Kayıp verinin iş değeri ve dönüş için kabul edilen süre önemlidir.
- Eksen ve kategori: Sağlamlık, 15 Gözlem, yedek ve kurtarma
- Yığın: Her yığın
- Yapay zekâ kodunda: ölçülmedi. Dayanak: gerçek olay.
- Ne zaman bakılır: İlk yayından önce, Her ay
- CWE: yok. Geri yükleme tatbikatının yokluğu bir işletim süreci eksikliğidir. Doğrudan CWE eşlemesi yerine MITRE ATT&CK yedekleme rehberi kullanılır.
- Checklist ifadesi: Yedekten geri yükleme ayrı bir ortamda denenmiş ve uygulama o veriyle açılmış.
- Son inceleme: 4 Ekim 2026, Komünite editörlüğü
- Adres: https://vibecheck.komunite.com.tr/madde/yedekten-geri-yukleme-denenmemis

## 60 saniyelik kontrol

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

1. Son başarılı geri yükleme kaydının tarihini ve hedef ortamını bul.
2. Geri yüklenen uygulamada örnek bir kaydın okunabildiğini kontrol et.
3. Yedeğin zamanı ile son canlı kayıt arasındaki farkı belirle.
4. Gerekli anahtar ve dosyaların kurtarma planında bulunduğunu doğrula.

## Ne oluyor

Panelde yedekleme başarılı yazıyor. Dosya duruyor, boyutu da makul görünüyor. Bunlar geri dönebileceğin hissini verir. Fakat yedek almak ve o yedekten çalışan uygulama elde etmek ayrı işlerdir. Dosya eksik tablo içerebilir, gerekli rol başka yerde tutulabilir veya şifreleme anahtarı arıza sırasında erişilemez hale gelebilir. İlk gerçek geri yükleme denemen olay günü yapılırsa bu eksikleri o gün öğrenirsin.

Geri yükleme tatbikatı, yedeği ayrı bir hedefte açıp uygulamanın ihtiyaç duyduğu veriyi kullanmayı sınar. Yalnız komutun başarılı çıkmasını kontrol etmek yetmez. Beklenen kayıt, ilişki ve iş akışı da görünmelidir. Veritabanının açılması, dosya deposundaki eklerin veya dış hizmet ayarlarının geri geldiği anlamına gelmez.

Ayrıca iki farklı hedef gerekir. Ne kadar eski veriye dönmeyi kabul ediyorsun ve hizmeti ne kadar sürede açman gerekiyor? Bunlar sırasıyla kabul edilen veri kaybı aralığı ve kurtarma süresiyle ilgilidir. Tatbikat bu beklentileri gerçek gözlemle karşılaştırmanı sağlar. Küçük yerel örnek bütün sistemi ölçmez, ancak dosya varlığına duyulan yanlış güveni görünür kılar.

## Gerçek olay

GitLab, Ocak 2017'de yanlış sunucudaki verinin silinmesinden sonra beklenen dump yedeklerini bulamadığını açıkladı. Yedekleme komutunda sürüm uyuşmazlığı vardı ve hata bildirimleri alıcıya ulaşmıyordu. Kurtarma daha önce alınmış bir snapshot üzerinden yürütüldü. Birincil açıklama AI bağlantısı kurmuyor. Burada ortak desen, tanımlı kurtarma yolunun olay sırasında çalışacağının önceden yeterince doğrulanmamış olmasıdır. [GitLab olay incelemesi](https://about.gitlab.com/blog/postmortem-of-database-outage-of-january-31/)

MITRE ATT&CK yedekleme rehberi de kopyaların bütünlüğünü ve geri getirilebilirliğini düzenli geri yükleme denemeleriyle sınamayı öneriyor. [Yedekleme rehberi](https://attack.mitre.org/mitigations/M1053/) Bu bir işletim süreci eksikliğidir. Sırf standart alanını doldurmak için ilgisiz bir CWE numarası eşlemiyoruz. Olaydaki veri miktarını veya süreyi kendi uygulaman için tahmin olarak kullanmıyoruz.

## Yapay zekâ bunu neden üretiyor

**Model yedek alma komutunu tamamlar.** İstek otomatik yedekleme kurmaksa ajan zamanlanmış komut, dosya adı ve saklama dizini oluşturabilir. Çıktının var olması görevin kabul ölçütüne dönüşür. Fakat geri yükleme farklı araç, yetki ve ortam gerektirebilir. İstemde bu ikinci yol belirtilmediyse çözüm yedeğin üretildiği noktada sona erebilir. Kurtarma kabulü ayrıca tanımlanmalıdır.

**Başarılı çıkış kodu içeriğin yerine geçer.** Komutun hata vermemesi yararlı bir sinyaldir, ancak beklenen iş verisinin mevcut olduğunu tek başına göstermez. Ajan dosya boyutunu veya işlem sonucunu yeterli kanıt sayabilir. Eksik tablolu geçerli veritabanı bu denetimden geçer. Uygulamanın gerçek okuma yollarını temsil eden küçük kontroller bu boşluğu görünür kılar.

**Geliştirme ortamı bağımlılıkları gizler.** Yerel makinede kimlikler, uzantılar ve gerekli dosyalar zaten bulunur. Ajan aynı ortamda geri yükleme yaptığında eksik bağımlılıkları fark etmeyebilir. Gerçek arızada o makine veya hesap kullanılamayabilir. Tatbikatın ayrı hedefte ve kayıtlı kurulum adımlarıyla yapılması, kurtarma planının hangi dış şeylere bağlı olduğunu anlamayı sağlar.

**Kurtarma sözü ölçüm gibi yazılabilir.** Ajan planı anlattıktan sonra sistemi geri yüklenebilir diye niteleyebilir. Oysa bu ifade çalıştırılmamış adımlara dayanıyor olabilir. Raporun komut, veri zamanı, hedef ve sonuç kaydı istemesi bu karışıklığı azaltır. Bunlar olası üretim mekanizmalarına ilişkin çıkarımlardır. Belirli bir modelin bu hatayı ne sıklıkta yaptığını ölçtüğümüz anlamına gelmez.

## Etki

Geri yükleme yolu çalışmazsa veri kaybından sonra hizmeti açmak uzayabilir. Ekip hangi kopyanın doğru olduğunu araştırırken kullanıcı işlemleri durur. Yedeğin yaşı beklenenden fazlaysa yakın zamandaki kayıtları yeniden toplamak veya kaybı kabul etmek gerekebilir.

Yanlış tatbikat da zarar verebilir. Canlı hedefin üzerine geri yüklemek, dış bildirimleri yeniden göndermek veya özel veriyi açık bir test ortamına kopyalamak yeni sorun yaratır. Bu yüzden hedef ayrımı, erişim sınırı ve dış yan etkilerin kapatılması tatbikatın parçasıdır. İçerik yalnız yedeğin mevcut olmasına bakmaz.

## Nasıl anlarsın

Son başarılı tatbikatın kaydını bul. Hangi yedek hangi hedefe açıldı, hangi uygulama okuması geçti ve sonuç ne zaman alındı? Yalnız yedekleme işi günlüğü varsa geri dönüşün sınandığını söyleme. Veritabanı dışında dosya, anahtar, rol ve yapılandırma gereksinimlerini de yaz.

Yerel örnek gerçek SQLite yedeğini ayrı geçici dosyaya kopyalar. Bütünlük kontrolü yapar ve örnek siparişin tutarını okur. Test, yedek alındıktan sonra kaynak veriyi silerek sonucun canlı kaynaktan gelmediğini doğrular. Yanlış içerik ve bozuk dosya reddedilir. Bu küçük deney üretim kurtarma süresini ölçmez.

## Nasıl düzeltirsin

1. **Kurtarma hedefini belirle.** Kabul edilen veri kaybını ve dönüş süresini işin ihtiyacına göre yaz. Yedek sıklığını bu hedeflerle karşılaştır.
2. **Ayrı hedef hazırla.** Canlı bağlantıyı kullanma. Erişimi sınırla, e-posta ve webhook gibi dış yan etkileri kapat.
3. **Gerçek yedeği aç.** Araç sürümü, rol ve uzantı gereksinimlerini doğrula. PostgreSQL dump yöntemiyle bütün küme kapsamını aynı şey sayma. [SQL dump kapsamı](https://www.postgresql.org/docs/current/backup-dump.html)
4. **İşi doğrula.** Yalnız dosya sayısını değil, beklenen kayıtları ve temel uygulama okumalarını kontrol et. Başlangıç, bitiş ve sorunları kaydet.
5. **Eksikleri kapat.** Tatbikat başarısızsa yedek mevcut diye tamamlandı yazma. Eksik bileşeni ekleyip aynı yolu yeniden dene.

## Bir daha olmasın

Yedek biçimi veya uygulama şeması değiştiğinde kurtarma tatbikatını yenile. Son başarılı denemenin kanıtını yedekleme işinin durumundan ayrı tut.

## Sınır

Bu madde yedeğin canlı sistemle aynı token tarafından silinmesini veya yıkıcı migration onayını çözmez. Her sistem için aynı kurtarma süresi uygun değildir. Yerel örnek yalnız sentetik SQLite verisini doğrular. Bulut snapshot, dosya deposu, rol yetkileri ve anahtar kurtarma yolu kendi ortamında ayrıca sınanmalıdır. Yeniden üretilebilir önbellek için farklı bir kurtarma yaklaşımı belgelenebilir.

## Düzeltme kodları

### Node.js: Ayrı hedefte geri yükleme

Önce:

```js
// kurtarma/tatbikat.js, açıklama amaçlı. Yalnız sentetik SQLite yedeği.
import { statSync } from 'node:fs';
export function restoreDrill(backupPath, expected) {
  const file = statSync(backupPath);
  if (!file.isFile() || file.size === 0) {
    throw new Error('Yedek dosyası yok');
  }
  // Dosya boyutu, yedeğin açılabildiğini veya doğru veriyi içerdiğini göstermez.
  return { verified: true };
}
// expected geri yüklenmiş uygulamadan okunması gereken sentetik kayıtlardır.
// Kötü sürüm bu beklentiyi hiç incelemiyor.
// Kaynak veritabanının kendisinde deneme yapılmaz.
// Tatbikat sonucu üretim kurtarma süresi ölçümü sayılmaz.
// Gerçek yedekler erişimi sınırlı ayrı ortamda sınanmalıdır.
```

Sonra:

```js
// kurtarma/tatbikat.js, açıklama amaçlı. Yalnız sentetik SQLite yedeği.
import { copyFileSync, mkdtempSync, rmSync, constants } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { DatabaseSync } from 'node:sqlite';
import assert from 'node:assert/strict';
export function restoreDrill(backupPath, expected) {
  const dir = mkdtempSync(join(tmpdir(), 'vc96-restore-'));
  let restored;
  try {
    const target = join(dir, 'restored.db');
    copyFileSync(backupPath, target, constants.COPYFILE_EXCL);
    restored = new DatabaseSync(target, { readOnly: true });
    assert.equal(restored.prepare('PRAGMA quick_check').get().quick_check, 'ok');
    const rows = restored.prepare('SELECT id, total FROM orders ORDER BY id').all();
    assert.deepEqual(rows.map(row => ({ ...row })), expected);
    return { verified: true };
  } finally {
    restored?.close();
    rmSync(dir, { recursive: true, force: true });
  }
}
// Bir uygulama sorgusu örneği. Dosyalar, roller ve dış bağımlılıklar ayrıca sınanır.
```

Düzeltmeyi kanıtlayan test:

```js
// kurtarma/tatbikat.test.mjs, açıklama amaçlı. Gerçek yerel yedek kullanılır.
import test from 'node:test';
import assert from 'node:assert/strict';
import { DatabaseSync, backup } from 'node:sqlite';
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
const { restoreDrill } = await import(process.env.ORNEK_DOSYA);
test('yedek açılır, yanlış içerik ve bozuk dosya kabul edilmez', async () => {
  const dir = mkdtempSync(join(tmpdir(), 'vc96-test-'));
  const db = new DatabaseSync(':memory:');
  try {
    db.exec('CREATE TABLE orders(id INTEGER PRIMARY KEY, total INTEGER); INSERT INTO orders VALUES(1, 125)');
    const file = join(dir, 'backup.db');
    await backup(db, file);
    db.exec('DELETE FROM orders');
    assert.deepEqual(restoreDrill(file, [{ id: 1, total: 125 }]), { verified: true });
    assert.throws(() => restoreDrill(file, [{ id: 1, total: 999 }]));
    const broken = join(dir, 'broken.db');
    writeFileSync(broken, 'Boyutu var ama veritabanı değil');
    assert.throws(() => restoreDrill(broken, []));
    assert.equal(db.prepare('SELECT count(*) AS n FROM orders').get().n, 0);
  } finally { db.close(); rmSync(dir, { recursive: true, force: true }); }
});
```

## Ajan kuralı (AGENTS.md)

```md
## Yedekten dönüş denenmemiş (vibecheck VC-096)
- Yedekleri ayrı ve güvenli ortamda düzenli geri yükle.
- Uygulama düzeyinde veri ve ilişki kontrolleri yap.
- Yedeğin zamanını ve dönüş süresini kaydet.
- Tatbikatta dış yan etkileri kapat.
- Geri yükleme anahtarlarını ve yetkilerini ayrıca denetle.
```

## Kaynaklar

1. [Postmortem of database outage of January 31](https://about.gitlab.com/blog/postmortem-of-database-outage-of-january-31/), GitLab, 10 Şubat 2017
2. [Data Backup M1053](https://attack.mitre.org/mitigations/M1053/), MITRE ATT&CK
3. [SQL Dump](https://www.postgresql.org/docs/current/backup-dump.html), PostgreSQL
4. [Node.js SQLite parameter binding](https://nodejs.org/api/sqlite.html), Node.js

---

vibecheck · Komünite editörlüğü. Metin CC BY 4.0, prompt ve kural parçaları MIT-0. Kaynak: https://vibecheck.komunite.com.tr/madde/yedekten-geri-yukleme-denenmemis
