@cogenta/core 0.4.0 → 0.6.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +3479 -0
  2. package/dist/config/env.d.ts +21 -0
  3. package/dist/config/env.d.ts.map +1 -1
  4. package/dist/config/env.js +72 -0
  5. package/dist/config/env.js.map +1 -1
  6. package/dist/config/index.d.ts +2 -0
  7. package/dist/config/index.d.ts.map +1 -1
  8. package/dist/config/index.js +1 -0
  9. package/dist/config/index.js.map +1 -1
  10. package/dist/config/load-config.d.ts +9 -0
  11. package/dist/config/load-config.d.ts.map +1 -1
  12. package/dist/config/load-config.js +39 -15
  13. package/dist/config/load-config.js.map +1 -1
  14. package/dist/config/resolve-config.d.ts.map +1 -1
  15. package/dist/config/resolve-config.js +39 -0
  16. package/dist/config/resolve-config.js.map +1 -1
  17. package/dist/config/schema.d.ts +49 -0
  18. package/dist/config/schema.d.ts.map +1 -1
  19. package/dist/config/schema.js +149 -1
  20. package/dist/config/schema.js.map +1 -1
  21. package/dist/config/secret-hygiene.d.ts +55 -0
  22. package/dist/config/secret-hygiene.d.ts.map +1 -0
  23. package/dist/config/secret-hygiene.js +94 -0
  24. package/dist/config/secret-hygiene.js.map +1 -0
  25. package/dist/config/types.d.ts +166 -0
  26. package/dist/config/types.d.ts.map +1 -1
  27. package/dist/config/types.js +4 -0
  28. package/dist/config/types.js.map +1 -1
  29. package/dist/drivers/index.d.ts +1 -1
  30. package/dist/drivers/index.d.ts.map +1 -1
  31. package/dist/drivers/index.js.map +1 -1
  32. package/dist/drivers/registry.d.ts.map +1 -1
  33. package/dist/drivers/registry.js +15 -8
  34. package/dist/drivers/registry.js.map +1 -1
  35. package/dist/drivers/types.d.ts +23 -0
  36. package/dist/drivers/types.d.ts.map +1 -1
  37. package/dist/errors/codes.d.ts +1 -1
  38. package/dist/errors/codes.d.ts.map +1 -1
  39. package/dist/errors/codes.js +234 -0
  40. package/dist/errors/codes.js.map +1 -1
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +2 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/logger/error-log.d.ts +48 -0
  46. package/dist/logger/error-log.d.ts.map +1 -0
  47. package/dist/logger/error-log.js +57 -0
  48. package/dist/logger/error-log.js.map +1 -0
  49. package/dist/logger/index.d.ts +2 -0
  50. package/dist/logger/index.d.ts.map +1 -1
  51. package/dist/logger/index.js +1 -0
  52. package/dist/logger/index.js.map +1 -1
  53. package/dist/media/exif.d.ts +46 -0
  54. package/dist/media/exif.d.ts.map +1 -0
  55. package/dist/media/exif.js +291 -0
  56. package/dist/media/exif.js.map +1 -0
  57. package/dist/media/folder-path.d.ts +16 -0
  58. package/dist/media/folder-path.d.ts.map +1 -0
  59. package/dist/media/folder-path.js +51 -0
  60. package/dist/media/folder-path.js.map +1 -0
  61. package/dist/media/folder-store.d.ts +26 -0
  62. package/dist/media/folder-store.d.ts.map +1 -0
  63. package/dist/media/folder-store.js +361 -0
  64. package/dist/media/folder-store.js.map +1 -0
  65. package/dist/media/index.d.ts +5 -2
  66. package/dist/media/index.d.ts.map +1 -1
  67. package/dist/media/index.js +4 -1
  68. package/dist/media/index.js.map +1 -1
  69. package/dist/media/sql-fragments.d.ts +19 -0
  70. package/dist/media/sql-fragments.d.ts.map +1 -0
  71. package/dist/media/sql-fragments.js +29 -0
  72. package/dist/media/sql-fragments.js.map +1 -0
  73. package/dist/media/store.d.ts +1 -0
  74. package/dist/media/store.d.ts.map +1 -1
  75. package/dist/media/store.js +175 -20
  76. package/dist/media/store.js.map +1 -1
  77. package/dist/media/types.d.ts +148 -0
  78. package/dist/media/types.d.ts.map +1 -1
  79. package/dist/queue/bullmq.d.ts +4 -0
  80. package/dist/queue/bullmq.d.ts.map +1 -1
  81. package/dist/queue/bullmq.js +53 -10
  82. package/dist/queue/bullmq.js.map +1 -1
  83. package/dist/queue/database.d.ts.map +1 -1
  84. package/dist/queue/database.js +32 -11
  85. package/dist/queue/database.js.map +1 -1
  86. package/dist/queue/types.d.ts +19 -0
  87. package/dist/queue/types.d.ts.map +1 -1
  88. package/dist/rate-limit/index.d.ts +21 -0
  89. package/dist/rate-limit/index.d.ts.map +1 -0
  90. package/dist/rate-limit/index.js +25 -0
  91. package/dist/rate-limit/index.js.map +1 -0
  92. package/dist/rate-limit/memory.d.ts +17 -0
  93. package/dist/rate-limit/memory.d.ts.map +1 -0
  94. package/dist/rate-limit/memory.js +61 -0
  95. package/dist/rate-limit/memory.js.map +1 -0
  96. package/dist/rate-limit/redis.d.ts +55 -0
  97. package/dist/rate-limit/redis.d.ts.map +1 -0
  98. package/dist/rate-limit/redis.js +134 -0
  99. package/dist/rate-limit/redis.js.map +1 -0
  100. package/dist/rate-limit/types.d.ts +52 -0
  101. package/dist/rate-limit/types.d.ts.map +1 -0
  102. package/dist/rate-limit/types.js +2 -0
  103. package/dist/rate-limit/types.js.map +1 -0
  104. package/dist/version.d.ts +39 -0
  105. package/dist/version.d.ts.map +1 -0
  106. package/dist/version.js +84 -0
  107. package/dist/version.js.map +1 -0
  108. package/package.json +3 -2
@@ -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"}
@@ -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>>;