@cogenta/core 0.4.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3532 -0
- package/dist/config/env.d.ts +21 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +72 -0
- package/dist/config/env.js.map +1 -1
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +1 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/load-config.d.ts +9 -0
- package/dist/config/load-config.d.ts.map +1 -1
- package/dist/config/load-config.js +39 -15
- package/dist/config/load-config.js.map +1 -1
- package/dist/config/resolve-config.d.ts.map +1 -1
- package/dist/config/resolve-config.js +39 -0
- package/dist/config/resolve-config.js.map +1 -1
- package/dist/config/schema.d.ts +49 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +149 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/config/secret-hygiene.d.ts +55 -0
- package/dist/config/secret-hygiene.d.ts.map +1 -0
- package/dist/config/secret-hygiene.js +94 -0
- package/dist/config/secret-hygiene.js.map +1 -0
- package/dist/config/types.d.ts +166 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +4 -0
- package/dist/config/types.js.map +1 -1
- package/dist/drivers/index.d.ts +1 -1
- package/dist/drivers/index.d.ts.map +1 -1
- package/dist/drivers/index.js.map +1 -1
- package/dist/drivers/registry.d.ts.map +1 -1
- package/dist/drivers/registry.js +15 -8
- package/dist/drivers/registry.js.map +1 -1
- package/dist/drivers/types.d.ts +23 -0
- package/dist/drivers/types.d.ts.map +1 -1
- package/dist/errors/codes.d.ts +1 -1
- package/dist/errors/codes.d.ts.map +1 -1
- package/dist/errors/codes.js +244 -0
- package/dist/errors/codes.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/logger/error-log.d.ts +48 -0
- package/dist/logger/error-log.d.ts.map +1 -0
- package/dist/logger/error-log.js +57 -0
- package/dist/logger/error-log.js.map +1 -0
- package/dist/logger/index.d.ts +2 -0
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +1 -0
- package/dist/logger/index.js.map +1 -1
- package/dist/media/exif.d.ts +46 -0
- package/dist/media/exif.d.ts.map +1 -0
- package/dist/media/exif.js +291 -0
- package/dist/media/exif.js.map +1 -0
- package/dist/media/folder-path.d.ts +16 -0
- package/dist/media/folder-path.d.ts.map +1 -0
- package/dist/media/folder-path.js +51 -0
- package/dist/media/folder-path.js.map +1 -0
- package/dist/media/folder-store.d.ts +26 -0
- package/dist/media/folder-store.d.ts.map +1 -0
- package/dist/media/folder-store.js +361 -0
- package/dist/media/folder-store.js.map +1 -0
- package/dist/media/index.d.ts +5 -2
- package/dist/media/index.d.ts.map +1 -1
- package/dist/media/index.js +4 -1
- package/dist/media/index.js.map +1 -1
- package/dist/media/sql-fragments.d.ts +19 -0
- package/dist/media/sql-fragments.d.ts.map +1 -0
- package/dist/media/sql-fragments.js +29 -0
- package/dist/media/sql-fragments.js.map +1 -0
- package/dist/media/store.d.ts +1 -0
- package/dist/media/store.d.ts.map +1 -1
- package/dist/media/store.js +175 -20
- package/dist/media/store.js.map +1 -1
- package/dist/media/types.d.ts +148 -0
- package/dist/media/types.d.ts.map +1 -1
- package/dist/queue/bullmq.d.ts +4 -0
- package/dist/queue/bullmq.d.ts.map +1 -1
- package/dist/queue/bullmq.js +53 -10
- package/dist/queue/bullmq.js.map +1 -1
- package/dist/queue/database.d.ts.map +1 -1
- package/dist/queue/database.js +32 -11
- package/dist/queue/database.js.map +1 -1
- package/dist/queue/types.d.ts +19 -0
- package/dist/queue/types.d.ts.map +1 -1
- package/dist/rate-limit/index.d.ts +21 -0
- package/dist/rate-limit/index.d.ts.map +1 -0
- package/dist/rate-limit/index.js +25 -0
- package/dist/rate-limit/index.js.map +1 -0
- package/dist/rate-limit/memory.d.ts +17 -0
- package/dist/rate-limit/memory.d.ts.map +1 -0
- package/dist/rate-limit/memory.js +61 -0
- package/dist/rate-limit/memory.js.map +1 -0
- package/dist/rate-limit/redis.d.ts +55 -0
- package/dist/rate-limit/redis.d.ts.map +1 -0
- package/dist/rate-limit/redis.js +134 -0
- package/dist/rate-limit/redis.js.map +1 -0
- package/dist/rate-limit/types.d.ts +52 -0
- package/dist/rate-limit/types.d.ts.map +1 -0
- package/dist/rate-limit/types.js +2 -0
- package/dist/rate-limit/types.js.map +1 -0
- package/dist/version.d.ts +39 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +84 -0
- package/dist/version.js.map +1 -0
- package/package.json +3 -2
package/dist/config/schema.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { CACHE_DRIVERS, DATABASE_DRIVERS, EMBEDDINGS_PROVIDERS, IMAGE_GENERATION_PROVIDERS, QUEUE_DRIVERS, STORAGE_DRIVERS, VECTOR_DRIVERS, } from './types.js';
|
|
2
|
+
import { CACHE_DRIVERS, DATABASE_DRIVERS, EMBEDDINGS_PROVIDERS, IMAGE_GENERATION_PROVIDERS, PAYMENT_DRIVERS, QUEUE_DRIVERS, RATE_LIMIT_DRIVERS, STORAGE_DRIVERS, VECTOR_DRIVERS, } from './types.js';
|
|
3
3
|
const nonEmpty = z.string().min(1);
|
|
4
4
|
// Every object is strict: a typo in a key is an error, never a silently ignored
|
|
5
5
|
// setting. Config drift between staging and production is the daily pain this
|
|
@@ -45,6 +45,10 @@ const queueSchema = z.strictObject({
|
|
|
45
45
|
driver: z.enum(QUEUE_DRIVERS).default('auto'),
|
|
46
46
|
url: nonEmpty.optional(),
|
|
47
47
|
});
|
|
48
|
+
const rateLimitSchema = z.strictObject({
|
|
49
|
+
driver: z.enum(RATE_LIMIT_DRIVERS).default('auto'),
|
|
50
|
+
url: nonEmpty.optional(),
|
|
51
|
+
});
|
|
48
52
|
const storageSchema = z.strictObject({
|
|
49
53
|
driver: z.enum(STORAGE_DRIVERS).default('auto'),
|
|
50
54
|
bucket: nonEmpty.optional(),
|
|
@@ -82,6 +86,21 @@ const corsSchema = z
|
|
|
82
86
|
error: 'credentials cannot be combined with the "*" origin — every browser refuses that pair',
|
|
83
87
|
path: ['credentials'],
|
|
84
88
|
});
|
|
89
|
+
/**
|
|
90
|
+
* Audit-log retention (T09-01 / fiche 21 task 5's retention half —
|
|
91
|
+
* `AuditLog.prune()` existed since that fiche with no caller anywhere in
|
|
92
|
+
* the codebase).
|
|
93
|
+
*
|
|
94
|
+
* Absent `retainDays` — the default — means the log grows without bound,
|
|
95
|
+
* exactly the behaviour before this setting existed: unlike the 404 log or
|
|
96
|
+
* analytics events, an audit trail disappearing on a schedule nobody asked
|
|
97
|
+
* for is a worse default than a bigger database, so `cogenta serve` never
|
|
98
|
+
* purges unless a site opts in. `0` is the explicit, documented way to say
|
|
99
|
+
* "never purge" out loud rather than by omission.
|
|
100
|
+
*/
|
|
101
|
+
const auditRetentionSchema = z.strictObject({
|
|
102
|
+
retainDays: z.number().int().nonnegative().max(3650).optional(),
|
|
103
|
+
});
|
|
85
104
|
const securitySchema = z.strictObject({
|
|
86
105
|
cors: corsSchema.prefault({}),
|
|
87
106
|
/**
|
|
@@ -106,6 +125,26 @@ const securitySchema = z.strictObject({
|
|
|
106
125
|
hstsIncludeSubDomains: z.boolean().default(true),
|
|
107
126
|
/** How long a public page may be cached, in seconds. */
|
|
108
127
|
pageMaxAge: z.number().int().nonnegative().max(86_400).default(60),
|
|
128
|
+
audit: auditRetentionSchema.prefault({}),
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* The log of public URLs that answered a 404 (fiche 12 task 1).
|
|
132
|
+
*
|
|
133
|
+
* On by default, because an unresolved 404 is the daily nuisance no CMS
|
|
134
|
+
* should make an editor discover by luck. Everything it keeps is bounded on
|
|
135
|
+
* purpose: `maxPaths` is the hard cap on distinct paths tracked at once — an
|
|
136
|
+
* anonymous scanner can produce thousands of unique URLs a minute, and
|
|
137
|
+
* without a ceiling this log would be a disk-exhaustion vector any visitor
|
|
138
|
+
* could trigger — and `retainDays` is how long a path is kept since it was
|
|
139
|
+
* last requested. Neither an IP address nor a user agent is ever a field
|
|
140
|
+
* here, on any path: `AGENTS.md` § Logs forbids personal data outright, and
|
|
141
|
+
* the path plus its referrer already answer the only question this log
|
|
142
|
+
* exists for ("what should I redirect?").
|
|
143
|
+
*/
|
|
144
|
+
const notFoundLogSchema = z.strictObject({
|
|
145
|
+
enabled: z.boolean().default(true),
|
|
146
|
+
maxPaths: z.number().int().positive().max(100_000).default(2000),
|
|
147
|
+
retainDays: z.number().int().positive().max(3650).default(30),
|
|
109
148
|
});
|
|
110
149
|
/**
|
|
111
150
|
* Outbound content-lifecycle webhooks (L14 task 1).
|
|
@@ -120,6 +159,18 @@ const webhooksSchema = z.strictObject({
|
|
|
120
159
|
/** Absolute `http(s)` URLs. Empty — the default — means no webhook is sent. */
|
|
121
160
|
endpoints: z.array(z.url()).default([]),
|
|
122
161
|
});
|
|
162
|
+
/**
|
|
163
|
+
* Analytics events retention (fiche 27 task 3).
|
|
164
|
+
*
|
|
165
|
+
* 400 days by default — long enough that "compare this year to last year" (a
|
|
166
|
+
* real question a site owner asks) still has data on both sides, short
|
|
167
|
+
* enough that the events table cannot grow forever on a busy site. `cogenta
|
|
168
|
+
* serve` purges past this every day; there is no way to disable purging
|
|
169
|
+
* outright, only to choose how long to keep.
|
|
170
|
+
*/
|
|
171
|
+
const analyticsSchema = z.strictObject({
|
|
172
|
+
retainDays: z.number().int().positive().max(3650).default(400),
|
|
173
|
+
});
|
|
123
174
|
const embeddingsSchema = z.strictObject({
|
|
124
175
|
provider: z.enum(EMBEDDINGS_PROVIDERS).default('local'),
|
|
125
176
|
model: nonEmpty.default('all-MiniLM-L6-v2'),
|
|
@@ -165,6 +216,94 @@ const billingSchema = z.strictObject({
|
|
|
165
216
|
taxId: nonEmpty.optional(),
|
|
166
217
|
footer: nonEmpty.optional(),
|
|
167
218
|
});
|
|
219
|
+
/**
|
|
220
|
+
* The scheduled-task clock (fiche 28 task 5).
|
|
221
|
+
*
|
|
222
|
+
* `'internal'` (the default) is `cogenta serve`'s own `setInterval` loop —
|
|
223
|
+
* the same shape every other recurring job in this codebase has always
|
|
224
|
+
* used, and the right choice for a process that stays up. `'external-cron'`
|
|
225
|
+
* is `docs/hebergement-mutualise.md`'s target: a host that recycles the
|
|
226
|
+
* process between requests, where an in-memory timer never fires reliably.
|
|
227
|
+
* In that mode `cogenta serve` registers every task but never ticks its own
|
|
228
|
+
* clock — only `cogenta cron`, called from the panel's own cron, drains due
|
|
229
|
+
* tasks. The admin screen reads this setting to say which mode is active,
|
|
230
|
+
* rather than guessing from whether a tick has happened recently.
|
|
231
|
+
*/
|
|
232
|
+
const schedulerSchema = z.strictObject({
|
|
233
|
+
mode: z.enum(['internal', 'external-cron']).default('internal'),
|
|
234
|
+
});
|
|
235
|
+
/**
|
|
236
|
+
* Scheduled full-site backups, riding the same clock as every other
|
|
237
|
+
* maintenance task (fiche 28 task 1's "sauvegarde planifiée", reusing
|
|
238
|
+
* `@cogenta/export`'s `createBackup` — the exact function `cogenta backup
|
|
239
|
+
* create` already calls by hand). Off by default: a backup file is
|
|
240
|
+
* unbounded disk usage a site did not ask for, and `dir` defaults to
|
|
241
|
+
* `.cogenta/backups` — the same directory the manual command writes to, so
|
|
242
|
+
* `cogenta backup list` shows scheduled and manual backups side by side.
|
|
243
|
+
*/
|
|
244
|
+
const backupSchema = z.strictObject({
|
|
245
|
+
enabled: z.boolean().default(false),
|
|
246
|
+
intervalHours: z
|
|
247
|
+
.number()
|
|
248
|
+
.int()
|
|
249
|
+
.positive()
|
|
250
|
+
.max(24 * 30)
|
|
251
|
+
.default(24),
|
|
252
|
+
/** Files kept before the oldest is pruned. */
|
|
253
|
+
keep: z.number().int().positive().max(365).default(10),
|
|
254
|
+
dir: nonEmpty.default('.cogenta/backups'),
|
|
255
|
+
});
|
|
256
|
+
/**
|
|
257
|
+
* The writing assistant's spending cap (fiche 30 task 3).
|
|
258
|
+
*
|
|
259
|
+
* A non-null default rather than "unlimited": the lot's own pitfall is exact
|
|
260
|
+
* — "le coût est invisible jusqu'à la facture", and a service billed per token
|
|
261
|
+
* left uncapped by default is the wrong default for a CMS that ships with AI
|
|
262
|
+
* off. One million tokens a month is generous for a single site's editors
|
|
263
|
+
* while still being a real ceiling, not a decoration.
|
|
264
|
+
*/
|
|
265
|
+
const assistantSchema = z.strictObject({
|
|
266
|
+
monthlyTokenLimit: z.number().int().positive().default(1_000_000),
|
|
267
|
+
});
|
|
268
|
+
/**
|
|
269
|
+
* OpenTelemetry tracing (fiche L22 task 5). No `otlpHeaders` field, on
|
|
270
|
+
* purpose (rule R7, `SECRET_KEYS` in `env.ts` refuses it before this schema
|
|
271
|
+
* even parses) — those come from `COGENTA_OTLP_HEADERS`/
|
|
272
|
+
* `OTEL_EXPORTER_OTLP_HEADERS` only. `otlpEndpoint` absent means local
|
|
273
|
+
* collection only: the recent-events buffer behind the admin's
|
|
274
|
+
* "Exploitation" screen always works with nothing configured here (R1).
|
|
275
|
+
*/
|
|
276
|
+
const observabilitySchema = z.strictObject({
|
|
277
|
+
serviceName: nonEmpty.default('cogenta'),
|
|
278
|
+
otlpEndpoint: z.url().optional(),
|
|
279
|
+
});
|
|
280
|
+
/**
|
|
281
|
+
* Contract E's payment gateway choice (fiche 34 task 3).
|
|
282
|
+
*
|
|
283
|
+
* No `secretKey` or `webhookSecret` field, on purpose (rule R7, same shape as
|
|
284
|
+
* `llmSchema`'s missing `apiKey`): Stripe's credentials come from
|
|
285
|
+
* `COGENTA_PAYMENT_STRIPE_SECRET_KEY`/`COGENTA_PAYMENT_STRIPE_WEBHOOK_SECRET`
|
|
286
|
+
* only, and `SECRET_KEYS` (`env.ts`) refuses either one written here before
|
|
287
|
+
* this schema is even parsed. `testMode` defaults `true`: a shop that has not
|
|
288
|
+
* deliberately flipped it to production cannot silently start taking real
|
|
289
|
+
* money, matching the fiche's "le mode test doit être criant".
|
|
290
|
+
*/
|
|
291
|
+
const paymentSchema = z.strictObject({
|
|
292
|
+
driver: z.enum(PAYMENT_DRIVERS).default('auto'),
|
|
293
|
+
testMode: z.boolean().default(true),
|
|
294
|
+
manualInstructions: nonEmpty.optional(),
|
|
295
|
+
});
|
|
296
|
+
/**
|
|
297
|
+
* Google Search Console OAuth (fiche 70 task 4, ADR-0032). No fields at all —
|
|
298
|
+
* the app's own OAuth client id/secret are both secrets (rule R7) and come
|
|
299
|
+
* from `COGENTA_SEARCH_CONSOLE_CLIENT_ID`/`COGENTA_SEARCH_CONSOLE_CLIENT_SECRET`
|
|
300
|
+
* only, refused here by `SECRET_KEYS` (`env.ts`) exactly like `payment`'s own
|
|
301
|
+
* Stripe/PayPal keys. Everything per-site — whether a site has connected, and
|
|
302
|
+
* which GSC property it queries — lives in the database
|
|
303
|
+
* (`@cogenta/schema`'s `search-console-store.ts`), never here: this section
|
|
304
|
+
* exists only so the *installation* can offer the connector at all.
|
|
305
|
+
*/
|
|
306
|
+
const searchConsoleSchema = z.strictObject({});
|
|
168
307
|
// `prefault` rather than `default`: an omitted section is parsed as `{}` so the
|
|
169
308
|
// per-field defaults inside it apply, instead of being replaced wholesale.
|
|
170
309
|
export const configSchema = z.strictObject({
|
|
@@ -172,14 +311,23 @@ export const configSchema = z.strictObject({
|
|
|
172
311
|
database: databaseSchema,
|
|
173
312
|
cache: cacheSchema.prefault({}),
|
|
174
313
|
queue: queueSchema.prefault({}),
|
|
314
|
+
rateLimit: rateLimitSchema.prefault({}),
|
|
175
315
|
storage: storageSchema.prefault({}),
|
|
176
316
|
security: securitySchema.prefault({}),
|
|
317
|
+
notFoundLog: notFoundLogSchema.prefault({}),
|
|
177
318
|
webhooks: webhooksSchema.prefault({}),
|
|
319
|
+
analytics: analyticsSchema.prefault({}),
|
|
178
320
|
llm: llmSchema.optional(),
|
|
179
321
|
embeddings: embeddingsSchema.prefault({}),
|
|
180
322
|
imageGeneration: imageGenerationSchema.optional(),
|
|
181
323
|
vector: vectorSchema.prefault({}),
|
|
182
324
|
billing: billingSchema.optional(),
|
|
325
|
+
scheduler: schedulerSchema.prefault({}),
|
|
326
|
+
backup: backupSchema.prefault({}),
|
|
327
|
+
assistant: assistantSchema.prefault({}),
|
|
328
|
+
payment: paymentSchema.prefault({}),
|
|
329
|
+
observability: observabilitySchema.prefault({}),
|
|
330
|
+
searchConsole: searchConsoleSchema.prefault({}),
|
|
183
331
|
});
|
|
184
332
|
/**
|
|
185
333
|
* Renders Zod issues as `field: reason`, one per line, so the user sees every
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detects, but never blocks, the two secret-hygiene gaps fiche 23 names as
|
|
3
|
+
* open (audit follow-up to L10 task 6 / `docs/hebergement-mutualise.md`):
|
|
4
|
+
* `create-cogenta` used to write a database URL — password included — into
|
|
5
|
+
* `cogenta.config.mjs` in the clear, and the generated `.env` (which holds
|
|
6
|
+
* `COGENTA_AUTH_SIGNING_KEY`) was written without a restrictive file mode, so
|
|
7
|
+
* another tenant on shared hosting could read it.
|
|
8
|
+
*
|
|
9
|
+
* `SECRET_KEYS` (`env.ts`) cannot simply gain `database.url`: unlike an API
|
|
10
|
+
* key, a database URL is legitimately present in the file for the common
|
|
11
|
+
* case — a SQLite path, or a Postgres URL with no password at all (peer
|
|
12
|
+
* trust, a local dev server) — so refusing it outright at `resolveConfig`
|
|
13
|
+
* would break every SQLite site, which is Cogenta's zero-config default.
|
|
14
|
+
* What *is* always wrong is a URL that embeds real credentials: that half is
|
|
15
|
+
* detected here and **surfaced**, on the ops-settings mirror (fiche 23 task
|
|
16
|
+
* 5's literal ask — "détecter et signaler"), never turned into a hard
|
|
17
|
+
* refusal that would regress a legitimate config.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* `true` when `value` parses as a URL carrying a non-empty username or
|
|
21
|
+
* password. A bare path (`./data.db`, `:memory:`) or a URL with no userinfo
|
|
22
|
+
* (`postgres://localhost/db`) is `false` — there is nothing secret to leak.
|
|
23
|
+
*/
|
|
24
|
+
export declare function urlHasEmbeddedCredentials(value: string): boolean;
|
|
25
|
+
export interface SecretHygieneReport {
|
|
26
|
+
/** `true` when the raw config file sets `database.url` to a URL carrying real credentials. */
|
|
27
|
+
readonly databaseUrlHasCredentialsInFile: boolean;
|
|
28
|
+
/** The `.env` file `loadConfig` looked for next to the config, or `null` when there is no config file. */
|
|
29
|
+
readonly envFilePath: string | null;
|
|
30
|
+
/**
|
|
31
|
+
* `true` when `.env` grants read access to the file's group or to anyone
|
|
32
|
+
* else on the machine — exactly what a shared-hosting neighbour would use.
|
|
33
|
+
* `null` when there is no `.env` file, or the platform's permission bits
|
|
34
|
+
* are not the POSIX ones this check reads (win32).
|
|
35
|
+
*/
|
|
36
|
+
readonly envFileReadableByOthers: boolean | null;
|
|
37
|
+
}
|
|
38
|
+
/** Reads the raw, unresolved `database.url` a config file declares, or `undefined` for none. */
|
|
39
|
+
export declare function rawDatabaseUrl(input: unknown): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* `true` when `mode` (a POSIX file mode, as `fs.Stats.mode` reports it)
|
|
42
|
+
* grants read access to its group or to "other" — the two bits that matter
|
|
43
|
+
* on a shared host, where every tenant's process runs as a different,
|
|
44
|
+
* unprivileged user. Pure and platform-independent so the actual security
|
|
45
|
+
* arithmetic — which bits mean "someone else can read this" — is tested
|
|
46
|
+
* directly, without a real file or a real POSIX host.
|
|
47
|
+
*/
|
|
48
|
+
export declare function hasGroupOrOtherRead(mode: number): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Builds the report `loadConfig` attaches to `LoadedConfig`. `rawConfig` is
|
|
51
|
+
* the *unresolved* file contents (before `resolveConfig` strips anything) —
|
|
52
|
+
* the same object `findSecretsInFile` already inspects.
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildSecretHygieneReport(rawConfig: unknown, envFilePath: string | null, envFileExists: boolean): Promise<SecretHygieneReport>;
|
|
55
|
+
//# sourceMappingURL=secret-hygiene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-hygiene.d.ts","sourceRoot":"","sources":["../../src/config/secret-hygiene.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAOhE;AAED,MAAM,WAAW,mBAAmB;IAClC,8FAA8F;IAC9F,QAAQ,CAAC,+BAA+B,EAAE,OAAO,CAAA;IACjD,0GAA0G;IAC1G,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC;;;;;OAKG;IACH,QAAQ,CAAC,uBAAuB,EAAE,OAAO,GAAG,IAAI,CAAA;CACjD;AAMD,gGAAgG;AAChG,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAMjE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGzD;AAqBD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,OAAO,EAClB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,aAAa,EAAE,OAAO,GACrB,OAAO,CAAC,mBAAmB,CAAC,CAQ9B"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import process from 'node:process';
|
|
3
|
+
/**
|
|
4
|
+
* Detects, but never blocks, the two secret-hygiene gaps fiche 23 names as
|
|
5
|
+
* open (audit follow-up to L10 task 6 / `docs/hebergement-mutualise.md`):
|
|
6
|
+
* `create-cogenta` used to write a database URL — password included — into
|
|
7
|
+
* `cogenta.config.mjs` in the clear, and the generated `.env` (which holds
|
|
8
|
+
* `COGENTA_AUTH_SIGNING_KEY`) was written without a restrictive file mode, so
|
|
9
|
+
* another tenant on shared hosting could read it.
|
|
10
|
+
*
|
|
11
|
+
* `SECRET_KEYS` (`env.ts`) cannot simply gain `database.url`: unlike an API
|
|
12
|
+
* key, a database URL is legitimately present in the file for the common
|
|
13
|
+
* case — a SQLite path, or a Postgres URL with no password at all (peer
|
|
14
|
+
* trust, a local dev server) — so refusing it outright at `resolveConfig`
|
|
15
|
+
* would break every SQLite site, which is Cogenta's zero-config default.
|
|
16
|
+
* What *is* always wrong is a URL that embeds real credentials: that half is
|
|
17
|
+
* detected here and **surfaced**, on the ops-settings mirror (fiche 23 task
|
|
18
|
+
* 5's literal ask — "détecter et signaler"), never turned into a hard
|
|
19
|
+
* refusal that would regress a legitimate config.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* `true` when `value` parses as a URL carrying a non-empty username or
|
|
23
|
+
* password. A bare path (`./data.db`, `:memory:`) or a URL with no userinfo
|
|
24
|
+
* (`postgres://localhost/db`) is `false` — there is nothing secret to leak.
|
|
25
|
+
*/
|
|
26
|
+
export function urlHasEmbeddedCredentials(value) {
|
|
27
|
+
try {
|
|
28
|
+
const url = new URL(value);
|
|
29
|
+
return url.username !== '' || url.password !== '';
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function isPlainObject(value) {
|
|
36
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
37
|
+
}
|
|
38
|
+
/** Reads the raw, unresolved `database.url` a config file declares, or `undefined` for none. */
|
|
39
|
+
export function rawDatabaseUrl(input) {
|
|
40
|
+
if (!isPlainObject(input))
|
|
41
|
+
return undefined;
|
|
42
|
+
const database = input['database'];
|
|
43
|
+
if (!isPlainObject(database))
|
|
44
|
+
return undefined;
|
|
45
|
+
const url = database['url'];
|
|
46
|
+
return typeof url === 'string' ? url : undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `true` when `mode` (a POSIX file mode, as `fs.Stats.mode` reports it)
|
|
50
|
+
* grants read access to its group or to "other" — the two bits that matter
|
|
51
|
+
* on a shared host, where every tenant's process runs as a different,
|
|
52
|
+
* unprivileged user. Pure and platform-independent so the actual security
|
|
53
|
+
* arithmetic — which bits mean "someone else can read this" — is tested
|
|
54
|
+
* directly, without a real file or a real POSIX host.
|
|
55
|
+
*/
|
|
56
|
+
export function hasGroupOrOtherRead(mode) {
|
|
57
|
+
// group-read (0o040) or other-read (0o004).
|
|
58
|
+
return (mode & 0o044) !== 0;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `path`'s mode, read from disk, or `null` on a platform whose permission
|
|
62
|
+
* model this check does not understand (win32 — ACLs, not POSIX rwx bits;
|
|
63
|
+
* Node synthesises a `mode` there rather than reporting a real one, and
|
|
64
|
+
* reporting `false` would claim a guarantee that platform cannot make) or
|
|
65
|
+
* when the file cannot be stat'd at all. Read-only by design: fixing the
|
|
66
|
+
* mode is `create-cogenta`'s job at write time (`scaffold.ts`), not
|
|
67
|
+
* something a running server silently changes under an operator's file.
|
|
68
|
+
*/
|
|
69
|
+
async function isReadableByOthers(path) {
|
|
70
|
+
if (process.platform === 'win32')
|
|
71
|
+
return null;
|
|
72
|
+
try {
|
|
73
|
+
const info = await stat(path);
|
|
74
|
+
return hasGroupOrOtherRead(info.mode);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Builds the report `loadConfig` attaches to `LoadedConfig`. `rawConfig` is
|
|
82
|
+
* the *unresolved* file contents (before `resolveConfig` strips anything) —
|
|
83
|
+
* the same object `findSecretsInFile` already inspects.
|
|
84
|
+
*/
|
|
85
|
+
export async function buildSecretHygieneReport(rawConfig, envFilePath, envFileExists) {
|
|
86
|
+
const url = rawDatabaseUrl(rawConfig);
|
|
87
|
+
const path = envFileExists ? envFilePath : null;
|
|
88
|
+
return {
|
|
89
|
+
databaseUrlHasCredentialsInFile: url !== undefined && urlHasEmbeddedCredentials(url),
|
|
90
|
+
envFilePath: path,
|
|
91
|
+
envFileReadableByOthers: path === null ? null : await isReadableByOthers(path),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=secret-hygiene.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-hygiene.js","sourceRoot":"","sources":["../../src/config/secret-hygiene.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACvC,OAAO,OAAO,MAAM,cAAc,CAAA;AAElC;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAa;IACrD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,OAAO,GAAG,CAAC,QAAQ,KAAK,EAAE,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAA;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAgBD,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC7E,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAC3C,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,CAAA;IAClC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAA;IAC9C,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3B,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;AAClD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,4CAA4C;IAC5C,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAA;AAC7B,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,kBAAkB,CAAC,IAAY;IAC5C,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,OAAO,IAAI,CAAA;IAC7C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAA;QAC7B,OAAO,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,SAAkB,EAClB,WAA0B,EAC1B,aAAsB;IAEtB,MAAM,GAAG,GAAG,cAAc,CAAC,SAAS,CAAC,CAAA;IACrC,MAAM,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA;IAC/C,OAAO;QACL,+BAA+B,EAAE,GAAG,KAAK,SAAS,IAAI,yBAAyB,CAAC,GAAG,CAAC;QACpF,WAAW,EAAE,IAAI;QACjB,uBAAuB,EAAE,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,kBAAkB,CAAC,IAAI,CAAC;KAC/E,CAAA;AACH,CAAC"}
|
package/dist/config/types.d.ts
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
export declare const DATABASE_DRIVERS: readonly ['postgres', 'mysql', 'sqlite'];
|
|
2
2
|
export declare const CACHE_DRIVERS: readonly ['auto', 'redis', 'file', 'memory'];
|
|
3
3
|
export declare const QUEUE_DRIVERS: readonly ['auto', 'redis', 'database'];
|
|
4
|
+
/** Per-API-key request quota (fiche 20 task 3). `auto` prefers Redis, falling back to the in-process counter (R1). */
|
|
5
|
+
export declare const RATE_LIMIT_DRIVERS: readonly ['auto', 'redis', 'memory'];
|
|
4
6
|
export declare const STORAGE_DRIVERS: readonly ['auto', 's3', 'local'];
|
|
5
7
|
export declare const EMBEDDINGS_PROVIDERS: readonly ['local', 'openai'];
|
|
6
8
|
/** Image generation vendors (L18 task 4). Never one hardcoded vendor. */
|
|
7
9
|
export declare const IMAGE_GENERATION_PROVIDERS: readonly ['openai', 'stability'];
|
|
8
10
|
/** Where embeddings are kept (L18 tasks 1/5). `auto` lets the registry choose, optimal first. */
|
|
9
11
|
export declare const VECTOR_DRIVERS: readonly ['auto', 'pgvector', 'file', 'memory'];
|
|
12
|
+
/** Contract E's payment gateway (fiche 34 task 3). `auto` prefers Stripe or PayPal, whichever has real credentials configured, falling back to bank transfer (R1). */
|
|
13
|
+
export declare const PAYMENT_DRIVERS: readonly ['auto', 'stripe', 'paypal', 'manual'];
|
|
10
14
|
export type DatabaseDriverName = (typeof DATABASE_DRIVERS)[number];
|
|
11
15
|
export type CacheDriverName = (typeof CACHE_DRIVERS)[number];
|
|
12
16
|
export type QueueDriverName = (typeof QUEUE_DRIVERS)[number];
|
|
17
|
+
export type RateLimitDriverName = (typeof RATE_LIMIT_DRIVERS)[number];
|
|
13
18
|
export type StorageDriverName = (typeof STORAGE_DRIVERS)[number];
|
|
14
19
|
export type EmbeddingsProvider = (typeof EMBEDDINGS_PROVIDERS)[number];
|
|
15
20
|
export type ImageGenerationProvider = (typeof IMAGE_GENERATION_PROVIDERS)[number];
|
|
16
21
|
export type VectorDriverName = (typeof VECTOR_DRIVERS)[number];
|
|
22
|
+
export type PaymentDriverName = (typeof PAYMENT_DRIVERS)[number];
|
|
17
23
|
/**
|
|
18
24
|
* What a user writes in `cogenta.config.ts`. Everything but `site` and
|
|
19
25
|
* `database` is optional, and no field here may hold a secret — those come from
|
|
@@ -44,6 +50,15 @@ export interface CogentaConfigInput {
|
|
|
44
50
|
readonly driver?: QueueDriverName;
|
|
45
51
|
readonly url?: string;
|
|
46
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* Per-API-key request quota (fiche 20 task 3, R1). `auto` — the default —
|
|
55
|
+
* prefers Redis when one is configured and falls back to an in-process
|
|
56
|
+
* counter otherwise, so the limiter works on a site with no Redis at all.
|
|
57
|
+
*/
|
|
58
|
+
readonly rateLimit?: {
|
|
59
|
+
readonly driver?: RateLimitDriverName;
|
|
60
|
+
readonly url?: string;
|
|
61
|
+
};
|
|
47
62
|
readonly storage?: {
|
|
48
63
|
readonly driver?: StorageDriverName;
|
|
49
64
|
readonly bucket?: string;
|
|
@@ -78,6 +93,26 @@ export interface CogentaConfigInput {
|
|
|
78
93
|
readonly hstsIncludeSubDomains?: boolean;
|
|
79
94
|
/** How long a public page may be cached, in seconds. */
|
|
80
95
|
readonly pageMaxAge?: number;
|
|
96
|
+
/**
|
|
97
|
+
* Audit-log retention (T09-01). Absent — the default — means the log
|
|
98
|
+
* grows without bound, unchanged from before this field existed. `0` is
|
|
99
|
+
* the explicit way to say "never purge" rather than leaving it absent.
|
|
100
|
+
*/
|
|
101
|
+
readonly audit?: {
|
|
102
|
+
readonly retainDays?: number;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The log of public URLs that answered a 404 (fiche 12 task 1). On by
|
|
107
|
+
* default; every field bounds how much this ever keeps (see the schema
|
|
108
|
+
* comment in `schema.ts` for why). Never carries an IP or a user agent.
|
|
109
|
+
*/
|
|
110
|
+
readonly notFoundLog?: {
|
|
111
|
+
readonly enabled?: boolean;
|
|
112
|
+
/** Distinct paths tracked before new ones stop being recorded. */
|
|
113
|
+
readonly maxPaths?: number;
|
|
114
|
+
/** Days a path is kept since it was last requested. */
|
|
115
|
+
readonly retainDays?: number;
|
|
81
116
|
};
|
|
82
117
|
/**
|
|
83
118
|
* Where a content-lifecycle webhook is sent (L14 task 1).
|
|
@@ -88,6 +123,17 @@ export interface CogentaConfigInput {
|
|
|
88
123
|
readonly webhooks?: {
|
|
89
124
|
readonly endpoints?: readonly string[];
|
|
90
125
|
};
|
|
126
|
+
/**
|
|
127
|
+
* Self-hosted, cookie-free page-view analytics (`@cogenta/analytics`, fiche
|
|
128
|
+
* 27 task 3). The only knob a site owner has: how long a raw event row is
|
|
129
|
+
* kept before `cogenta serve`'s daily sweep purges it. The events table is
|
|
130
|
+
* the largest table on a site with real traffic (fiche 27's own piège), so
|
|
131
|
+
* there is no way to switch purging off entirely — only how long to wait.
|
|
132
|
+
*/
|
|
133
|
+
readonly analytics?: {
|
|
134
|
+
/** Days an event row is kept, counted from when it was recorded. */
|
|
135
|
+
readonly retainDays?: number;
|
|
136
|
+
};
|
|
91
137
|
readonly llm?: {
|
|
92
138
|
readonly provider?: string;
|
|
93
139
|
readonly model?: string;
|
|
@@ -132,6 +178,58 @@ export interface CogentaConfigInput {
|
|
|
132
178
|
/** Legal footer printed on every invoice page: payment terms, mentions. */
|
|
133
179
|
readonly footer?: string;
|
|
134
180
|
};
|
|
181
|
+
/** The scheduled-task clock (fiche 28 task 5). `'internal'` by default — see the schema comment for what `'external-cron'` changes. */
|
|
182
|
+
readonly scheduler?: {
|
|
183
|
+
readonly mode?: 'internal' | 'external-cron';
|
|
184
|
+
};
|
|
185
|
+
/** Scheduled full-site backups (fiche 28 task 1). Off by default. */
|
|
186
|
+
readonly backup?: {
|
|
187
|
+
readonly enabled?: boolean;
|
|
188
|
+
readonly intervalHours?: number;
|
|
189
|
+
readonly keep?: number;
|
|
190
|
+
readonly dir?: string;
|
|
191
|
+
};
|
|
192
|
+
/** The writing assistant's spending cap (fiche 30 task 3). Absent means the default cap applies — never "unlimited". */
|
|
193
|
+
readonly assistant?: {
|
|
194
|
+
readonly monthlyTokenLimit?: number;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* OpenTelemetry tracing (fiche L22 task 5). Whether collection actually
|
|
198
|
+
* runs, and the log level it runs at, are **not** here — those are
|
|
199
|
+
* editorial (`observability.enabled`/`observability.logLevel` in
|
|
200
|
+
* `SITE_SETTINGS_REGISTRY`, changeable from the admin with no restart).
|
|
201
|
+
* This section only holds what an infra operator wires once: where to
|
|
202
|
+
* export to. There is no `otlpHeaders` field, on purpose (rule R7, same
|
|
203
|
+
* shape as `payment`'s missing `stripeSecretKey`): a header commonly
|
|
204
|
+
* carries a bearer token for the OTLP backend, so it comes from
|
|
205
|
+
* `COGENTA_OTLP_HEADERS`/`OTEL_EXPORTER_OTLP_HEADERS` only.
|
|
206
|
+
*/
|
|
207
|
+
readonly observability?: {
|
|
208
|
+
readonly serviceName?: string;
|
|
209
|
+
/** Absent means "local collection only" (R1) — no external exporter runs. */
|
|
210
|
+
readonly otlpEndpoint?: string;
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Which payment gateway a shop uses (contract E, fiche 34 task 3).
|
|
214
|
+
*
|
|
215
|
+
* There is no `secretKey`, `webhookSecret`, `clientId`, `clientSecret` or
|
|
216
|
+
* `webhookId` field here, on purpose (rule R7): Stripe's credentials come
|
|
217
|
+
* from `COGENTA_PAYMENT_STRIPE_SECRET_KEY` and
|
|
218
|
+
* `COGENTA_PAYMENT_STRIPE_WEBHOOK_SECRET` only, PayPal's from
|
|
219
|
+
* `COGENTA_PAYMENT_PAYPAL_CLIENT_ID`, `COGENTA_PAYMENT_PAYPAL_CLIENT_SECRET`
|
|
220
|
+
* and `COGENTA_PAYMENT_PAYPAL_WEBHOOK_ID`, and the admin payment screen
|
|
221
|
+
* shows their *presence*, never their value. `testMode` is a declared
|
|
222
|
+
* intent an operator sets deliberately — it does not infer test vs. live
|
|
223
|
+
* from the shape of a key, so a shop that switches gateway modes without
|
|
224
|
+
* updating this flag gets a loud, visible mismatch rather than a silent
|
|
225
|
+
* one.
|
|
226
|
+
*/
|
|
227
|
+
readonly payment?: {
|
|
228
|
+
readonly driver?: PaymentDriverName;
|
|
229
|
+
readonly testMode?: boolean;
|
|
230
|
+
/** Shown to the shopper by the bank-transfer driver. Free text, per site. Not a secret. */
|
|
231
|
+
readonly manualInstructions?: string;
|
|
232
|
+
};
|
|
135
233
|
}
|
|
136
234
|
/**
|
|
137
235
|
* What the rest of Cogenta consumes: every field resolved, defaults applied,
|
|
@@ -163,6 +261,10 @@ export interface CogentaConfig {
|
|
|
163
261
|
readonly driver: QueueDriverName;
|
|
164
262
|
readonly url: string | undefined;
|
|
165
263
|
};
|
|
264
|
+
readonly rateLimit: {
|
|
265
|
+
readonly driver: RateLimitDriverName;
|
|
266
|
+
readonly url: string | undefined;
|
|
267
|
+
};
|
|
166
268
|
readonly storage: {
|
|
167
269
|
readonly driver: StorageDriverName;
|
|
168
270
|
readonly bucket: string | undefined;
|
|
@@ -194,6 +296,16 @@ export interface CogentaConfig {
|
|
|
194
296
|
readonly hstsMaxAge: number;
|
|
195
297
|
readonly hstsIncludeSubDomains: boolean;
|
|
196
298
|
readonly pageMaxAge: number;
|
|
299
|
+
readonly audit: {
|
|
300
|
+
/** `undefined` (absent) and `0` both mean "never purge" — see the input type's comment. */
|
|
301
|
+
readonly retainDays: number | undefined;
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
/** The log of public URLs that answered a 404 (fiche 12 task 1). Resolved, defaults applied. */
|
|
305
|
+
readonly notFoundLog: {
|
|
306
|
+
readonly enabled: boolean;
|
|
307
|
+
readonly maxPaths: number;
|
|
308
|
+
readonly retainDays: number;
|
|
197
309
|
};
|
|
198
310
|
/**
|
|
199
311
|
* `secret` is `undefined` until `COGENTA_WEBHOOK_SECRET` is set. Whoever
|
|
@@ -204,6 +316,10 @@ export interface CogentaConfig {
|
|
|
204
316
|
readonly endpoints: readonly string[];
|
|
205
317
|
readonly secret: string | undefined;
|
|
206
318
|
};
|
|
319
|
+
/** The events-table retention window (fiche 27 task 3). Resolved, default applied. */
|
|
320
|
+
readonly analytics: {
|
|
321
|
+
readonly retainDays: number;
|
|
322
|
+
};
|
|
207
323
|
/** Absent when no provider is configured. The CMS works without AI (rule R2). */
|
|
208
324
|
readonly llm: {
|
|
209
325
|
readonly provider: string;
|
|
@@ -239,6 +355,56 @@ export interface CogentaConfig {
|
|
|
239
355
|
readonly taxId: string | undefined;
|
|
240
356
|
readonly footer: string | undefined;
|
|
241
357
|
} | undefined;
|
|
358
|
+
/** The scheduled-task clock (fiche 28 task 5). Resolved, defaults applied. */
|
|
359
|
+
readonly scheduler: {
|
|
360
|
+
readonly mode: 'internal' | 'external-cron';
|
|
361
|
+
};
|
|
362
|
+
/** Scheduled full-site backups (fiche 28 task 1). Resolved, defaults applied. */
|
|
363
|
+
readonly backup: {
|
|
364
|
+
readonly enabled: boolean;
|
|
365
|
+
readonly intervalHours: number;
|
|
366
|
+
readonly keep: number;
|
|
367
|
+
readonly dir: string;
|
|
368
|
+
};
|
|
369
|
+
/** The writing assistant's spending cap (fiche 30 task 3), always resolved — never absent. */
|
|
370
|
+
readonly assistant: {
|
|
371
|
+
readonly monthlyTokenLimit: number;
|
|
372
|
+
};
|
|
373
|
+
/** OpenTelemetry tracing (fiche L22 task 5), always resolved — never absent (R1: local collection needs no export target at all). */
|
|
374
|
+
readonly observability: {
|
|
375
|
+
readonly serviceName: string;
|
|
376
|
+
/** `undefined` means no OTLP exporter runs — the local exporter (recent-events buffer, NDJSON) still does. */
|
|
377
|
+
readonly otlpEndpoint: string | undefined;
|
|
378
|
+
/** `undefined` until `COGENTA_OTLP_HEADERS`/`OTEL_EXPORTER_OTLP_HEADERS` is set. */
|
|
379
|
+
readonly otlpHeaders: Readonly<Record<string, string>> | undefined;
|
|
380
|
+
};
|
|
381
|
+
/** Contract E's payment gateway (fiche 34 task 3), always resolved — never absent (a shop with no key still takes bank transfers, R1/R2). */
|
|
382
|
+
readonly payment: {
|
|
383
|
+
readonly driver: PaymentDriverName;
|
|
384
|
+
readonly testMode: boolean;
|
|
385
|
+
readonly manualInstructions: string | undefined;
|
|
386
|
+
/** `undefined` until `COGENTA_PAYMENT_STRIPE_SECRET_KEY` is set. Never round-tripped to any admin response — only its presence is. */
|
|
387
|
+
readonly stripeSecretKey: string | undefined;
|
|
388
|
+
/** `undefined` until `COGENTA_PAYMENT_STRIPE_WEBHOOK_SECRET` is set. */
|
|
389
|
+
readonly stripeWebhookSecret: string | undefined;
|
|
390
|
+
/** `undefined` until `COGENTA_PAYMENT_PAYPAL_CLIENT_ID` is set. Never round-tripped to any admin response — only its presence is. */
|
|
391
|
+
readonly paypalClientId: string | undefined;
|
|
392
|
+
/** `undefined` until `COGENTA_PAYMENT_PAYPAL_CLIENT_SECRET` is set. */
|
|
393
|
+
readonly paypalClientSecret: string | undefined;
|
|
394
|
+
/** `undefined` until `COGENTA_PAYMENT_PAYPAL_WEBHOOK_ID` is set. */
|
|
395
|
+
readonly paypalWebhookId: string | undefined;
|
|
396
|
+
};
|
|
397
|
+
/**
|
|
398
|
+
* Google Search Console OAuth (fiche 70 task 4, ADR-0032), always
|
|
399
|
+
* resolved — never absent (R1/R2: a site with no OAuth app configured
|
|
400
|
+
* simply offers no connector, the rest of the SEO screen is unaffected).
|
|
401
|
+
*/
|
|
402
|
+
readonly searchConsole: {
|
|
403
|
+
/** `undefined` until `COGENTA_SEARCH_CONSOLE_CLIENT_ID` is set — the whole connector is unreachable until then. */
|
|
404
|
+
readonly clientId: string | undefined;
|
|
405
|
+
/** `undefined` until `COGENTA_SEARCH_CONSOLE_CLIENT_SECRET` is set. Never round-tripped to any admin response. */
|
|
406
|
+
readonly clientSecret: string | undefined;
|
|
407
|
+
};
|
|
242
408
|
}
|
|
243
409
|
/** A read-only view of the process environment. */
|
|
244
410
|
export type Environment = Readonly<Record<string, string | undefined>>;
|