add read only live runtime drift probe
This commit is contained in:
@@ -1,19 +1,37 @@
|
||||
{
|
||||
"date": "2026-09-06",
|
||||
"url": "https://ihaleist.com",
|
||||
"base": "https://ihaleist.com",
|
||||
"readOnly": true,
|
||||
"checkedAt": "2026-09-06T16:13:35.286Z",
|
||||
"checks": {
|
||||
"apiHealth": {"status": 200, "body": {"ok": true}},
|
||||
"apiReady": {"status": 404, "body": {"success": false, "error": "not found"}},
|
||||
"securityHeadersObserved": {
|
||||
"apiHealth": {
|
||||
"access-control-allow-origin": "*",
|
||||
"home": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"x-content-type-options": null,
|
||||
"referrer-policy": null,
|
||||
"permissions-policy": null
|
||||
}
|
||||
},
|
||||
"servedAsset": "/assets/index-BtYUXYcw.js"
|
||||
"health": {
|
||||
"status": 200,
|
||||
"headers": {
|
||||
"x-content-type-options": null,
|
||||
"referrer-policy": null,
|
||||
"permissions-policy": null
|
||||
}
|
||||
},
|
||||
"scope": "Read-only live probe; no login, mutation, payment, message, or tender submission performed.",
|
||||
"interpretation": "Live deployment does not yet contain the local readiness endpoint or the local API security headers. Deployment remains pending."
|
||||
"ready": {
|
||||
"status": 404,
|
||||
"headers": {
|
||||
"x-content-type-options": null,
|
||||
"referrer-policy": null,
|
||||
"permissions-policy": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"pass": false,
|
||||
"missingHeaders": [
|
||||
"x-content-type-options",
|
||||
"referrer-policy",
|
||||
"permissions-policy"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2200,3 +2200,9 @@ Doğrulama: browser QA başarılı; analitik erişilebilirlik kontrolü, ICS, ç
|
||||
Belge son kullanma uyarısı artık “bugün” anahtarını UTC tarihinden değil İstanbul tarihinden üretiyor. Yalnız tarih içeren son kullanma değerleri `+03:00` gece yarısı olarak ayrıştırılıyor; böylece Türkiye’de gün değişimi sırasında 30 gün/son kullanma uyarısı bir gün kaymıyor. Geçersiz tarih sessizce yaklaşan belge olarak sayılmıyor.
|
||||
|
||||
Doğrulama: 293 otomatik test ve üretim derlemesi başarılı. Gece yarısı sınırı için gerçek saat kontrollü tarayıcı kabulü ayrıca yapılmalı.
|
||||
|
||||
### 2026-09-06 · Tekrarlanabilir canlı drift probe’u
|
||||
|
||||
`npm run qa:live -- https://ihaleist.com` komutu eklendi. Probe yalnızca ana sayfa, `/api/health` ve `/api/ready` uç noktalarını GET ile kontrol ediyor; authentication, veri yazma, ödeme veya sağlayıcı çağrısı yapmıyor. Ana sayfa ve health için güvenlik başlıklarını da zorunlu tutup JSON kanıtı `qa-live-runtime.json` içine yazıyor.
|
||||
|
||||
6 Eylül 2026 çalıştırmasında ana sayfa ve health 200, readiness 404 döndü; üç güvenlik başlığı canlı yanıtlarda bulunmadı. Probe bu nedenle beklenen şekilde başarısız oldu. Bu sonuç yerel düzeltmelerin canlıya alınmadığını gösteren drift kanıtıdır.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"qa:browser": "node tests/browser-acceptance.mjs",
|
||||
"qa:live": "node tests/live-runtime-probe.mjs",
|
||||
"preview": "vite preview",
|
||||
"server": "node server/index.js",
|
||||
"test": "node --test tests/*.test.mjs"
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Read-only production drift probe. No authentication, writes, payments or
|
||||
// provider calls are performed. It intentionally fails when a required
|
||||
// deployment contract is missing.
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
|
||||
const base = String(process.argv[2] || process.env.IHALEIST_LIVE_URL || 'https://ihaleist.com').replace(/\/$/, '');
|
||||
const timeoutMs = 15_000;
|
||||
const requiredHeaders = ['x-content-type-options', 'referrer-policy', 'permissions-policy'];
|
||||
const checks = {};
|
||||
|
||||
async function probe(path) {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
try {
|
||||
const response = await fetch(base + path, { signal: controller.signal, redirect: 'manual' });
|
||||
return {
|
||||
status: response.status,
|
||||
headers: Object.fromEntries(requiredHeaders.map(name => [name, response.headers.get(name)])),
|
||||
};
|
||||
} catch (error) {
|
||||
return { error: error.name === 'AbortError' ? `timeout after ${timeoutMs}ms` : error.message };
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
checks.home = await probe('/');
|
||||
checks.health = await probe('/api/health');
|
||||
checks.ready = await probe('/api/ready');
|
||||
const missingHeaders = requiredHeaders.filter(name => checks.home?.headers?.[name] == null || checks.health?.headers?.[name] == null);
|
||||
const report = {
|
||||
base,
|
||||
readOnly: true,
|
||||
checkedAt: new Date().toISOString(),
|
||||
checks,
|
||||
pass: checks.home?.status === 200 && checks.health?.status === 200 && checks.ready?.status === 200 && missingHeaders.length === 0,
|
||||
missingHeaders,
|
||||
};
|
||||
|
||||
await mkdir('docs/quality/evidence', { recursive: true });
|
||||
await writeFile('docs/quality/evidence/qa-live-runtime.json', JSON.stringify(report, null, 2) + '\n');
|
||||
console.log(JSON.stringify(report));
|
||||
if (!report.pass) process.exitCode = 1;
|
||||
Reference in New Issue
Block a user