Skip to content

Commit 8d1cffd

Browse files
committed
Orbit kapısını yoruma uydur, yerel Worker'ı çalışır hale getir
identity.ts'teki yorum "ORBIT_ISSUER tanımlanır tanımlanmaz yerel geliştirme yolu kapanır" diyordu ama koşul `ORBIT_ISSUER && ORBIT_AUDIENCE` idi ve üretimde tam olarak bu boşluk açıktı: ISSUER secret olarak yazılmış, AUDIENCE hiç tanımlanmamış, dolayısıyla akış Orbit bloğunu atlayıp dev dalına düşüyordu. DEV_PUBLISH_TOKEN üretimde olmadığı için sonuç 401'di — yani kusur görünmüyordu ve o token eklendiği gün sessizce açılacaktı. Kapı artık yalnız ORBIT_ISSUER. Eksik AUDIENCE başka bir yola sapmıyor, 503 ile duruyor. identity-tests.mjs bu garantiyi koda bağlıyor (9 vaka, test:orbit içinde koşuyor). Eski koşul geri konduğunda hedef vaka düşüyor — mutasyonla doğrulandı, dosya yedekten geri yüklendi. Yerel wrangler dev'in çökme nedeni de bulundu: yerel D1'e göçler hiç uygulanmamış, site_state tablosu yok, her sayfa 500. `npm run dev:ssr` derleme + göç + sunucuyu tek komutta yapıyor; README bunu ve atlanınca çıkan hatayı yazıyor.
1 parent 7a3121b commit 8d1cffd

4 files changed

Lines changed: 129 additions & 6 deletions

File tree

‎README.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,15 @@ skip themselves when it is absent.
292292
## Development commands
293293

294294
```bash
295-
# Run the Astro dev server
295+
# Run the Astro dev server (static preview, no Worker bindings)
296296
npm run dev
297297

298+
# Run the deployed Worker locally, with D1/R2 bindings and server routes.
299+
# This also applies pending migrations to the LOCAL database — skipping that
300+
# step leaves the local D1 empty and every page fails with
301+
# "no such table: site_state".
302+
npm run dev:ssr
303+
298304
# Build the static site
299305
npm run build
300306

‎package.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
},
1616
"scripts": {
1717
"dev": "astro dev",
18+
"dev:ssr": "npm run build:ssr && npm run dev:db && wrangler dev --config wrangler.ssr.jsonc",
19+
"dev:db": "wrangler d1 migrations apply haber --local --config wrangler.ssr.jsonc",
1820
"build": "astro build",
1921
"build:ssr": "astro build --config astro.config.ssr.mjs",
2022
"deploy": "wrangler deploy --config wrangler.ssr.jsonc",
@@ -29,7 +31,7 @@
2931
"haber:ayna": "node scripts/haber-ayna.mjs",
3032
"haber:ayna:kuru": "node scripts/haber-ayna.mjs --kuru",
3133
"test:newsroom": "newsroom/.venv/bin/python -m pytest newsroom/tests",
32-
"test:orbit": "node worker/tools/orbit-token-tests.mjs && node worker/tools/orbit-giris-tests.mjs",
34+
"test:orbit": "node worker/tools/orbit-token-tests.mjs && node worker/tools/orbit-giris-tests.mjs && node worker/tools/identity-tests.mjs",
3335
"quality": "npm run test:newsroom && npm run test:orbit && npm run typecheck && npm run build"
3436
},
3537
"dependencies": {

‎worker/src/identity.ts‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,18 @@ export async function authenticate(request: Request, env: AuthEnv): Promise<Auth
246246
};
247247
}
248248

249-
if (env.ORBIT_ISSUER && env.ORBIT_AUDIENCE) {
249+
/* Kapı `ORBIT_ISSUER`: tanımlıysa bu bloktan CANLI ÇIKIŞ YOK, yani aşağıdaki
250+
* yerel geliştirme dalına düşmek imkânsız. Koşul önceden
251+
* `ORBIT_ISSUER && ORBIT_AUDIENCE` idi ve üretimde tam olarak bu boşluk
252+
* açıktı: `ORBIT_ISSUER` tanımlı, `ORBIT_AUDIENCE` tanımlı değil, dolayısıyla
253+
* blok atlanıp dev dalına düşülüyordu. `DEV_PUBLISH_TOKEN` tanımlı olmadığı
254+
* için sonuç 401'di — ama yukarıdaki yorumun verdiği "Orbit tanımlanır
255+
* tanımlanmaz dev yolu kapanır" garantisi yürürlükte değildi. Eksik ayar
256+
* artık sessizce başka bir yola sapmıyor, 503 ile duruyor. */
257+
if (env.ORBIT_ISSUER) {
258+
if (!env.ORBIT_AUDIENCE) {
259+
return { ok: false, status: 503, error: "Orbit yapılandırması eksik: ORBIT_AUDIENCE tanımlı değil" };
260+
}
250261
const verified = await verifyOrbitToken(token, env.ORBIT_ISSUER, env.ORBIT_AUDIENCE);
251262
if ("error" in verified) return { ok: false, ...verified };
252263

@@ -273,9 +284,10 @@ export async function authenticate(request: Request, env: AuthEnv): Promise<Auth
273284
};
274285
}
275286

276-
/* Orbit yapılandırılmamış: yalnız yerel geliştirme yolu. Bu dal üretimde
277-
* çalışmamalı ve `ORBIT_ISSUER` tanımlanır tanımlanmaz kendiliğinden
278-
* devre dışı kalır — unutulup açık kalabilecek ayrı bir bayrak yok. */
287+
/* Orbit yapılandırılmamış: yalnız yerel geliştirme yolu. Buraya ancak
288+
* `ORBIT_ISSUER` HİÇ tanımlı değilken gelinir — yukarıdaki blok tanımlıysa
289+
* her durumda kendi içinde sonuçlanıyor. Unutulup açık kalabilecek ayrı bir
290+
* bayrak yok. */
279291
if (env.DEV_PUBLISH_TOKEN && timingSafeEqual(token, env.DEV_PUBLISH_TOKEN)) {
280292
return {
281293
ok: true,

‎worker/tools/identity-tests.mjs‎

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/* `authenticate` yol seçimini sınar.
2+
*
3+
* Bu dosya bir yorumun verdiği sözü koda bağlamak için var. `identity.ts`
4+
* "Orbit tanımlanır tanımlanmaz yerel geliştirme yolu kapanır" diyordu ama
5+
* koşul `ORBIT_ISSUER && ORBIT_AUDIENCE` olduğu için üretimde tam tersi
6+
* geçerliydi: ISSUER vardı, AUDIENCE yoktu, akış dev dalına düşüyordu.
7+
* `DEV_PUBLISH_TOKEN` tanımlı olmadığı için kimse fark etmedi — yani kusur
8+
* bir gün o token eklendiğinde sessizce açılacaktı.
9+
*
10+
* En önemli vaka bu yüzden "eksik ayar + geçerli dev token" vakası: garanti
11+
* tutuyorsa oradan kimlik ÇIKMAMALI.
12+
*/
13+
import { authenticate } from "../src/identity.ts";
14+
15+
const DEV = "dev-token-123";
16+
17+
/* `first()` her zaman null döner: yayıncı anahtarı yolunun veritabanına
18+
* gittiğini ama eşleşme bulamadığını temsil ediyor. Yol seçimini sınıyoruz,
19+
* satır okumayı değil. */
20+
const bosDB = { prepare: () => ({ bind: () => ({ first: async () => null }) }) };
21+
22+
const istek = (token) =>
23+
new Request("https://haber.sametbasbug.dev/api/publish", {
24+
method: "POST",
25+
headers: token ? { authorization: `Bearer ${token}` } : {},
26+
});
27+
28+
const results = [];
29+
function check(label, actual, expected) {
30+
const ok = actual === expected;
31+
results.push({ ok, label });
32+
console.log(`${ok ? " ok " : "FAIL "}${label.padEnd(52)} ${String(actual).padEnd(46)} beklenen: ${expected}`);
33+
}
34+
const outcome = (r) => (r.ok ? `ok via=${r.identity.via}` : `${r.status} ${r.error}`);
35+
36+
console.log("── Orbit kapısı ──");
37+
{
38+
/* DÜZELTMENİN TA KENDİSİ: eksik AUDIENCE dev dalını açmamalı. */
39+
const r = await authenticate(istek(DEV), {
40+
DB: bosDB, ORBIT_ISSUER: "https://orbit.sametbasbug.dev", DEV_PUBLISH_TOKEN: DEV,
41+
});
42+
check("eksik ORBIT_AUDIENCE dev yolunu açmıyor", outcome(r), "503 Orbit yapılandırması eksik: ORBIT_AUDIENCE tanımlı değil");
43+
}
44+
{
45+
/* Orbit tam yapılandırılmış: geçersiz token dev token'ıyla AYNI olsa bile
46+
* Orbit doğrulamasında kalmalı, dev dalına düşmemeli. */
47+
const r = await authenticate(istek(DEV), {
48+
DB: bosDB,
49+
ORBIT_ISSUER: "https://orbit.sametbasbug.dev",
50+
ORBIT_AUDIENCE: "haber.sametbasbug.dev",
51+
DEV_PUBLISH_TOKEN: DEV,
52+
});
53+
check("Orbit açıkken dev token Orbit'te reddediliyor", r.ok, false);
54+
check(" ve dev yoluna düşmüyor", r.status === 401 || r.status === 503, true);
55+
}
56+
57+
console.log("\n── yerel geliştirme yolu ──");
58+
{
59+
const r = await authenticate(istek(DEV), { DB: bosDB, DEV_PUBLISH_TOKEN: DEV });
60+
check("ORBIT_ISSUER yokken dev token geçiyor", outcome(r), "ok via=shared-secret");
61+
}
62+
{
63+
const r = await authenticate(istek("baska"), { DB: bosDB, DEV_PUBLISH_TOKEN: DEV });
64+
check("yanlış dev token reddediliyor", outcome(r), "401 yetkisiz");
65+
}
66+
{
67+
const r = await authenticate(istek(DEV), { DB: bosDB });
68+
check("DEV_PUBLISH_TOKEN yoksa reddediliyor", outcome(r), "401 yetkisiz");
69+
}
70+
71+
console.log("\n── başlık ──");
72+
{
73+
const r = await authenticate(istek(null), { DB: bosDB, DEV_PUBLISH_TOKEN: DEV });
74+
check("başlıksız istek reddediliyor", outcome(r), "401 yetkilendirme başlığı yok");
75+
}
76+
77+
console.log("\n── yayıncı anahtarı ──");
78+
{
79+
/* Anahtar öneki tanınıyor ve VERİTABANINA gidiliyor; eşleşme yoksa 401.
80+
* Önemli olan bu yolun Orbit kapısından bağımsız çalışmaya devam etmesi —
81+
* geçiş sırasında ikisi birden ayakta kalmalı. */
82+
const r = await authenticate(istek("hbr_pub_v1_xxx"), {
83+
DB: bosDB, ORBIT_ISSUER: "https://orbit.sametbasbug.dev", ORBIT_AUDIENCE: "haber.sametbasbug.dev",
84+
});
85+
check("anahtar yolu Orbit açıkken de deneniyor", outcome(r), "401 yetkisiz");
86+
}
87+
{
88+
const bulanDB = {
89+
prepare: () => ({
90+
bind: () => ({
91+
first: async () => ({ subject: "asteria", author: "Asteria AI", may_write_brief: 1, may_publish: 1, disabled_at: null }),
92+
}),
93+
}),
94+
};
95+
const r = await authenticate(istek("hbr_pub_v1_xxx"), {
96+
DB: bulanDB, ORBIT_ISSUER: "https://orbit.sametbasbug.dev", ORBIT_AUDIENCE: "haber.sametbasbug.dev",
97+
});
98+
check("geçerli anahtar Orbit açıkken de kabul", outcome(r), "ok via=publisher-key");
99+
}
100+
101+
const failed = results.filter((r) => !r.ok);
102+
console.log(`\n${results.length - failed.length}/${results.length} geçti`);
103+
if (failed.length) { console.error("düşenler: " + failed.map((f) => f.label).join(", ")); process.exit(1); }

0 commit comments

Comments
 (0)