@nitra/cursor 3.13.0 → 3.14.1
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 +16 -0
- package/package.json +1 -1
- package/rules/js-lint/coverage/coverage.mjs +41 -13
- package/rules/k8s/js/manifests.mjs +127 -0
- package/rules/k8s/k8s.mdc +17 -0
- package/rules/k8s/policy/hasura_configmap/hasura_configmap.rego +4 -0
- package/scripts/dispatcher/lib/review.mjs +12 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.14.1] - 2026-06-02
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- flow review: рецензент верифікує cross-file твердження читанням (Read) — промпт дозволяє/зобов'язує дочитувати referenced-файли/spec точково, репортувати лише те, що вносить diff (не преіснуючі баги сусідів), і не видавати нефальсифіковних findings «з diff не видно». Зменшує хибні findings.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- coverage-gate: запускати Stryker із локально встановленого @stryker-mutator/core (резолв через package.json у node_modules пакета, bin запускається напряму через node-shebang), а не через npx/bunx — ті тягнуть core у власний кеш без vitest-runner, тож plugin-discovery падав 'Cannot find TestRunner plugin vitest' і flow verify coverage-gate червонів. Працює й з worktree без власного node_modules.
|
|
12
|
+
|
|
13
|
+
## [3.14.0] - 2026-06-02
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- k8s hasura_configmap: base/dev ConfigMap Hasura-Deployment має містити HASURA_GRAPHQL_ENABLED_APIS="metadata,graphql,pgdump" (точний рядок). Кожен не-base overlay (k8s/<env>/, env≠base/dev), що успадковує Hasura-base, має у kustomization.yaml перевизначати цей ключ до "metadata,graphql" (без pgdump) патчем JSON6902/Strategic Merge на ConfigMap — нова cross-file перевірка validateHasuraOverlayEnabledApisOverride
|
|
18
|
+
|
|
3
19
|
## [3.13.0] - 2026-06-02
|
|
4
20
|
|
|
5
21
|
### Changed
|
package/package.json
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
import { spawnSync } from 'node:child_process'
|
|
10
10
|
import { existsSync, readFileSync } from 'node:fs'
|
|
11
11
|
import { mkdtemp, readFile, rm } from 'node:fs/promises'
|
|
12
|
+
import { createRequire } from 'node:module'
|
|
12
13
|
import { tmpdir } from 'node:os'
|
|
13
|
-
import { isAbsolute, join, relative } from 'node:path'
|
|
14
|
+
import { dirname, isAbsolute, join, relative } from 'node:path'
|
|
14
15
|
|
|
15
16
|
import { resolveAllJsRoots } from '../../../scripts/utils/resolve-js-root.mjs'
|
|
16
17
|
import { addCoverage, addMutation } from '../../test/coverage/coverage.mjs'
|
|
@@ -239,6 +240,32 @@ export function parseStrykerReport(report, jsRoot) {
|
|
|
239
240
|
* (типовий патерн monorepo, де тести зосереджені в одному пакеті); пустий lcov
|
|
240
241
|
* у такому випадку сигналізує "no tests" → collectOneRoot пропускає workspace.
|
|
241
242
|
*/
|
|
243
|
+
/**
|
|
244
|
+
* Шлях до локально встановленого Stryker core-bin (поряд із плагінами на кшталт
|
|
245
|
+
* `@stryker-mutator/vitest-runner`). Запуск саме його через `node` — не `npx`/`bunx` —
|
|
246
|
+
* дає Stryker побачити локальні плагіни при plugin-discovery.
|
|
247
|
+
* @returns {string | null} абсолютний шлях `bin/stryker.js` або `null`, якщо не встановлено
|
|
248
|
+
*/
|
|
249
|
+
/** Мемо: `undefined` — ще не обчислено; `string`/`null` — результат. */
|
|
250
|
+
let strykerBinCache
|
|
251
|
+
|
|
252
|
+
function resolveLocalStrykerBin() {
|
|
253
|
+
if (strykerBinCache !== undefined) return strykerBinCache
|
|
254
|
+
try {
|
|
255
|
+
// `exports` у core НЕ відкриває `./bin/stryker.js`, тож резолвимо package.json
|
|
256
|
+
// (доступний) і беремо шлях bin звідти. Ключ bin зазвичай `stryker`; як запас —
|
|
257
|
+
// перше значення map'и.
|
|
258
|
+
const require = createRequire(import.meta.url)
|
|
259
|
+
const pkgJsonPath = require.resolve('@stryker-mutator/core/package.json')
|
|
260
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf8'))
|
|
261
|
+
const binRel = typeof pkg.bin === 'string' ? pkg.bin : (pkg.bin?.stryker ?? Object.values(pkg.bin ?? {})[0])
|
|
262
|
+
strykerBinCache = binRel ? join(dirname(pkgJsonPath), binRel) : null
|
|
263
|
+
} catch {
|
|
264
|
+
strykerBinCache = null
|
|
265
|
+
}
|
|
266
|
+
return strykerBinCache
|
|
267
|
+
}
|
|
268
|
+
|
|
242
269
|
const defaultRunner = {
|
|
243
270
|
runJsCoverage({ cwd, lcovDir, base }) {
|
|
244
271
|
// base !== undefined ⇔ --changed-режим: vitest сам рахує зачеплені змінами тести
|
|
@@ -261,20 +288,21 @@ const defaultRunner = {
|
|
|
261
288
|
return r.status ?? 1
|
|
262
289
|
},
|
|
263
290
|
runStryker({ cwd, mutate }) {
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
// `
|
|
270
|
-
//
|
|
291
|
+
// Plugin-discovery Stryker (`@stryker-mutator/*`) globиться відносно CORE-install-каталогу
|
|
292
|
+
// (`core/dist/src/di/plugin-loader.js` → `../../../../../@stryker-mutator/*`). Тож core
|
|
293
|
+
// МАЄ вантажитись із проєктного `node_modules`, де поряд лежить `@stryker-mutator/vitest-runner`.
|
|
294
|
+
// `npx`/`bunx` тягнуть core у власний кеш (`_npx/<hash>`, `bunx-temp`) БЕЗ плагінів → воркери
|
|
295
|
+
// падають `Cannot find TestRunner plugin "vitest"`. Тому резолвимо локальний core-bin через
|
|
296
|
+
// `import.meta.url` (модуль у `npm/` → кореневий `node_modules` пакета; працює й з worktree без
|
|
297
|
+
// власного node_modules) і запускаємо його через `node`. Fallback на `npx`, якщо не встановлено.
|
|
271
298
|
// mutate (непорожній) ⇔ --changed-режим: мутуємо лише змінені production-файли цього root.
|
|
272
299
|
const mutateArgs = mutate && mutate.length > 0 ? ['--mutate', mutate.join(',')] : []
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
300
|
+
const strykerBin = resolveLocalStrykerBin()
|
|
301
|
+
// Запускаємо bin НАПРЯМУ (його shebang `#!/usr/bin/env node` → завжди node, навіть якщо
|
|
302
|
+
// coverage.mjs стартував під bun, де `process.execPath` вказував би на bun). Fallback на npx.
|
|
303
|
+
const r = strykerBin
|
|
304
|
+
? spawnSync(strykerBin, ['run', ...mutateArgs], { cwd, stdio: 'inherit', env: process.env })
|
|
305
|
+
: spawnSync('npx', ['@stryker-mutator/core', 'run', ...mutateArgs], { cwd, stdio: 'inherit', env: process.env })
|
|
278
306
|
return r.status ?? 1
|
|
279
307
|
}
|
|
280
308
|
}
|
|
@@ -2358,6 +2358,7 @@ export const HASURA_REQUIRED_ENV_KEYS = [
|
|
|
2358
2358
|
'HASURA_GRAPHQL_ENABLE_RELAY',
|
|
2359
2359
|
'HASURA_GRAPHQL_ENABLE_TELEMETRY',
|
|
2360
2360
|
'HASURA_GRAPHQL_ENABLED_LOG_TYPES',
|
|
2361
|
+
'HASURA_GRAPHQL_ENABLED_APIS',
|
|
2361
2362
|
'HASURA_GRAPHQL_DISABLE_EVENTING'
|
|
2362
2363
|
]
|
|
2363
2364
|
|
|
@@ -4929,6 +4930,130 @@ async function validateProdKustomizationOverrides(root, yamlFilesAbs, fail, pass
|
|
|
4929
4930
|
}
|
|
4930
4931
|
}
|
|
4931
4932
|
|
|
4933
|
+
/** Очікуване `HASURA_GRAPHQL_ENABLED_APIS` у non-base/dev overlay (без `pgdump` — він лише для base/dev). */
|
|
4934
|
+
const HASURA_OVERLAY_ENABLED_APIS = 'metadata,graphql'
|
|
4935
|
+
|
|
4936
|
+
/** JSON-Pointer ключа `HASURA_GRAPHQL_ENABLED_APIS` у `data` ConfigMap (для JSON6902-патчів). */
|
|
4937
|
+
const HASURA_ENABLED_APIS_DATA_POINTER = '/data/HASURA_GRAPHQL_ENABLED_APIS'
|
|
4938
|
+
|
|
4939
|
+
/**
|
|
4940
|
+
* Чи дерево kustomization (`resources` / `bases` / `components` / `crds`, рекурсивно) містить
|
|
4941
|
+
* **Hasura-Deployment** у шарі base (образ `hasura/graphql-engine`). Маркер того, що overlay успадковує
|
|
4942
|
+
* Hasura-ConfigMap з pgdump-значенням `ENABLED_APIS` і має його перевизначити.
|
|
4943
|
+
* @param {string} kustAbs kustomization.yaml
|
|
4944
|
+
* @param {string} rootNorm нормалізований корінь репо
|
|
4945
|
+
* @returns {Promise<boolean>} true, якщо в успадкованому base є Hasura-Deployment
|
|
4946
|
+
*/
|
|
4947
|
+
export async function kustomizationTreeHasHasuraDeployment(kustAbs, rootNorm) {
|
|
4948
|
+
const visited = new Set()
|
|
4949
|
+
const paths = await collectYamlAbsPathsFromKustomizationTree(kustAbs, rootNorm, visited)
|
|
4950
|
+
const rootResolved = resolve(rootNorm)
|
|
4951
|
+
for (const abs of paths) {
|
|
4952
|
+
const rel = (relative(rootResolved, abs) || '').replaceAll('\\', '/')
|
|
4953
|
+
if (!isK8sYamlUnderBaseDirectory(rel)) continue
|
|
4954
|
+
const roots = await readK8sYamlDocumentRootsForInventory(abs)
|
|
4955
|
+
if (roots.some(o => isHasuraDeploymentManifest(o))) return true
|
|
4956
|
+
}
|
|
4957
|
+
return false
|
|
4958
|
+
}
|
|
4959
|
+
|
|
4960
|
+
/**
|
|
4961
|
+
* Значення, яке inline-`patch` присвоює `data.HASURA_GRAPHQL_ENABLED_APIS`. Підтримка двох форматів:
|
|
4962
|
+
* **JSON6902** (`op` add/replace на `/data/HASURA_GRAPHQL_ENABLED_APIS`) і **Strategic Merge**
|
|
4963
|
+
* (`data.HASURA_GRAPHQL_ENABLED_APIS`). Зовнішні patch-файли (`patches[].path`) не охоплені — Plan B trade-off.
|
|
4964
|
+
* @param {string} patchText вміст поля `patch`
|
|
4965
|
+
* @returns {string | null} присвоєне значення (рядок) або null, якщо patch не чіпає цей ключ
|
|
4966
|
+
*/
|
|
4967
|
+
export function enabledApisValueFromPatchText(patchText) {
|
|
4968
|
+
const t = typeof patchText === 'string' ? patchText.trim() : ''
|
|
4969
|
+
if (t === '') return null
|
|
4970
|
+
let parsed
|
|
4971
|
+
try {
|
|
4972
|
+
for (const d of parseAllDocuments(t)) {
|
|
4973
|
+
if (d.errors.length === 0) {
|
|
4974
|
+
parsed = d.toJSON()
|
|
4975
|
+
break
|
|
4976
|
+
}
|
|
4977
|
+
}
|
|
4978
|
+
} catch {
|
|
4979
|
+
return null
|
|
4980
|
+
}
|
|
4981
|
+
if (Array.isArray(parsed)) {
|
|
4982
|
+
for (const item of parsed) {
|
|
4983
|
+
if (item === null || typeof item !== 'object' || Array.isArray(item)) continue
|
|
4984
|
+
const rec = /** @type {Record<string, unknown>} */ (item)
|
|
4985
|
+
const op = typeof rec.op === 'string' ? rec.op.trim().toLowerCase() : ''
|
|
4986
|
+
const path = typeof rec.path === 'string' ? normalizeJsonPatchPath(rec.path) : ''
|
|
4987
|
+
if ((op === 'add' || op === 'replace') && path === HASURA_ENABLED_APIS_DATA_POINTER) {
|
|
4988
|
+
return typeof rec.value === 'string' ? rec.value : JSON.stringify(rec.value)
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
return null
|
|
4992
|
+
}
|
|
4993
|
+
if (parsed === null || typeof parsed !== 'object') return null
|
|
4994
|
+
const data = /** @type {Record<string, unknown>} */ (parsed).data
|
|
4995
|
+
if (data === null || typeof data !== 'object' || Array.isArray(data)) return null
|
|
4996
|
+
const d = /** @type {Record<string, unknown>} */ (data)
|
|
4997
|
+
if (!Object.hasOwn(d, 'HASURA_GRAPHQL_ENABLED_APIS')) return null
|
|
4998
|
+
const v = d.HASURA_GRAPHQL_ENABLED_APIS
|
|
4999
|
+
return typeof v === 'string' ? v : JSON.stringify(v)
|
|
5000
|
+
}
|
|
5001
|
+
|
|
5002
|
+
/**
|
|
5003
|
+
* Значення, яке `patches[]` kustomization присвоюють `data.HASURA_GRAPHQL_ENABLED_APIS` на цілі **ConfigMap**.
|
|
5004
|
+
* Повертає значення першого patch-а, що чіпає цей ключ, або null, якщо такого немає.
|
|
5005
|
+
* @param {Record<string, unknown>} kust об'єкт kustomization.yaml
|
|
5006
|
+
* @returns {string | null} присвоєне значення або null
|
|
5007
|
+
*/
|
|
5008
|
+
export function hasuraEnabledApisOverrideValue(kust) {
|
|
5009
|
+
const patches = kust.patches
|
|
5010
|
+
if (!Array.isArray(patches)) return null
|
|
5011
|
+
for (const p of patches) {
|
|
5012
|
+
if (p === null || typeof p !== 'object' || Array.isArray(p)) continue
|
|
5013
|
+
const pr = /** @type {Record<string, unknown>} */ (p)
|
|
5014
|
+
if (typeof pr.patch !== 'string') continue
|
|
5015
|
+
if (resolvePatchTargetKind(pr) !== 'ConfigMap') continue
|
|
5016
|
+
const v = enabledApisValueFromPatchText(pr.patch)
|
|
5017
|
+
if (v !== null) return v
|
|
5018
|
+
}
|
|
5019
|
+
return null
|
|
5020
|
+
}
|
|
5021
|
+
|
|
5022
|
+
/**
|
|
5023
|
+
* Для кожного **non-base/dev** overlay `kustomization.yaml`, що успадковує Hasura-base (Deployment з
|
|
5024
|
+
* `hasura/graphql-engine`), вимагає у `patches[]` перевизначення **`data.HASURA_GRAPHQL_ENABLED_APIS`**
|
|
5025
|
+
* до **`"metadata,graphql"`** (pgdump лишається строго для base/dev) (k8s.mdc). `kind: Component`
|
|
5026
|
+
* пропускається (env-неутральне джерело, не overlay).
|
|
5027
|
+
* @param {string} root корінь репозиторію
|
|
5028
|
+
* @param {string[]} yamlFilesAbs yaml під k8s
|
|
5029
|
+
* @param {(msg: string) => void} fail callback при помилці
|
|
5030
|
+
* @param {(msg: string) => void} passFn callback при успіху
|
|
5031
|
+
*/
|
|
5032
|
+
async function validateHasuraOverlayEnabledApisOverride(root, yamlFilesAbs, fail, passFn) {
|
|
5033
|
+
const rootNorm = resolve(root)
|
|
5034
|
+
const kustFiles = yamlFilesAbs.filter(abs => basename(abs) === 'kustomization.yaml')
|
|
5035
|
+
for (const kustAbs of kustFiles) {
|
|
5036
|
+
const rel = (relative(rootNorm, kustAbs) || kustAbs).replaceAll('\\', '/')
|
|
5037
|
+
const segment = k8sEnvSegmentFromRelPath(rel)
|
|
5038
|
+
if (segment === null || segment === 'base' || segment === 'dev') continue
|
|
5039
|
+
const kust = await readFirstYamlObject(kustAbs)
|
|
5040
|
+
if (kust === null || kust.kind === 'Component') continue
|
|
5041
|
+
if (!(await kustomizationTreeHasHasuraDeployment(kustAbs, rootNorm))) continue
|
|
5042
|
+
const value = hasuraEnabledApisOverrideValue(kust)
|
|
5043
|
+
if (value === HASURA_OVERLAY_ENABLED_APIS) {
|
|
5044
|
+
passFn(`${rel}: overlay '${segment}' перевизначає HASURA_GRAPHQL_ENABLED_APIS="${HASURA_OVERLAY_ENABLED_APIS}" (k8s.mdc)`)
|
|
5045
|
+
} else if (value === null) {
|
|
5046
|
+
fail(
|
|
5047
|
+
`${rel}: overlay '${segment}' має у patches[] перевизначати data.HASURA_GRAPHQL_ENABLED_APIS до "${HASURA_OVERLAY_ENABLED_APIS}" (pgdump лише для base/dev) (k8s.mdc)`
|
|
5048
|
+
)
|
|
5049
|
+
} else {
|
|
5050
|
+
fail(
|
|
5051
|
+
`${rel}: overlay '${segment}' patch data.HASURA_GRAPHQL_ENABLED_APIS має бути "${HASURA_OVERLAY_ENABLED_APIS}" (зараз: ${JSON.stringify(value)}) (k8s.mdc)`
|
|
5052
|
+
)
|
|
5053
|
+
}
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
|
|
4932
5057
|
/**
|
|
4933
5058
|
* Шукає HPA за `scaleTargetRef.name` серед документів.
|
|
4934
5059
|
* @param {Record<string, unknown>[]} hpaDocs масив HPA-документів
|
|
@@ -6626,5 +6751,7 @@ export async function check(cwd = process.cwd()) {
|
|
|
6626
6751
|
|
|
6627
6752
|
await validateProdKustomizationOverrides(root, yamlFiles, fail, pass)
|
|
6628
6753
|
|
|
6754
|
+
await validateHasuraOverlayEnabledApisOverride(root, yamlFiles, fail, pass)
|
|
6755
|
+
|
|
6629
6756
|
return reporter.getExitCode()
|
|
6630
6757
|
}
|
package/rules/k8s/k8s.mdc
CHANGED
|
@@ -303,6 +303,7 @@ spec:
|
|
|
303
303
|
- **`HASURA_GRAPHQL_ENABLE_RELAY`** зі значенням **`"false"`**;
|
|
304
304
|
- **`HASURA_GRAPHQL_ENABLE_TELEMETRY`** зі значенням **`"false"`**;
|
|
305
305
|
- **`HASURA_GRAPHQL_ENABLED_LOG_TYPES`** зі значенням **`"startup,http-log"`** (точний рядок);
|
|
306
|
+
- **`HASURA_GRAPHQL_ENABLED_APIS`** зі значенням **`"metadata,graphql,pgdump"`** (точний рядок) — **значення для base/dev**;
|
|
306
307
|
- **`HASURA_GRAPHQL_DISABLE_EVENTING`** — ключ обов'язковий, значення довільне (за замовчуванням **`"true"`**).
|
|
307
308
|
|
|
308
309
|
Точні умови перевірки — rego-пакет **`k8s.hasura_configmap`** (cross-file прив'язка ConfigMap↔Deployment — у `rules/k8s/js/manifests.mjs`).
|
|
@@ -313,9 +314,25 @@ data:
|
|
|
313
314
|
HASURA_GRAPHQL_ENABLE_RELAY: 'false'
|
|
314
315
|
HASURA_GRAPHQL_ENABLE_TELEMETRY: 'false'
|
|
315
316
|
HASURA_GRAPHQL_ENABLED_LOG_TYPES: 'startup,http-log'
|
|
317
|
+
HASURA_GRAPHQL_ENABLED_APIS: 'metadata,graphql,pgdump'
|
|
316
318
|
HASURA_GRAPHQL_DISABLE_EVENTING: 'true'
|
|
317
319
|
```
|
|
318
320
|
|
|
321
|
+
### `HASURA_GRAPHQL_ENABLED_APIS` поза base/dev
|
|
322
|
+
|
|
323
|
+
`pgdump` дозволено **лише** для **base**/**dev**. Кожен **не-base** overlay (`k8s/<env>/`, де `<env>` ≠ `base`/`dev`), що успадковує Hasura-base, **зобов'язаний** у своєму **`kustomization.yaml`** перевизначити `HASURA_GRAPHQL_ENABLED_APIS` до **`"metadata,graphql"`** (без `pgdump`) — патчем JSON6902 або Strategic Merge на ціль **ConfigMap**. Перевірка — cross-file у `rules/k8s/js/manifests.mjs` (`validateHasuraOverlayEnabledApisOverride`); `kind: Component` пропускається.
|
|
324
|
+
|
|
325
|
+
```yaml title="k8s/prod/kustomization.yaml"
|
|
326
|
+
patches:
|
|
327
|
+
- target:
|
|
328
|
+
kind: ConfigMap
|
|
329
|
+
name: db-h
|
|
330
|
+
patch: |
|
|
331
|
+
- op: replace
|
|
332
|
+
path: /data/HASURA_GRAPHQL_ENABLED_APIS
|
|
333
|
+
value: metadata,graphql
|
|
334
|
+
```
|
|
335
|
+
|
|
319
336
|
## Kustomize: структура каталогів (`base` / overlays)
|
|
320
337
|
|
|
321
338
|
Трансформуй дерева **`**/k8s`**, щоб **винести спільне** через [Kustomize](https://kustomize.io/): один канонічний **`base`** і тонкі **overlays** для інших середовищ.
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
# "HASURA_GRAPHQL_ENABLE_RELAY" → "false"
|
|
7
7
|
# "HASURA_GRAPHQL_ENABLE_TELEMETRY" → "false"
|
|
8
8
|
# "HASURA_GRAPHQL_ENABLED_LOG_TYPES" → "startup,http-log" (точний рядок)
|
|
9
|
+
# "HASURA_GRAPHQL_ENABLED_APIS" → "metadata,graphql,pgdump" (точний рядок;
|
|
10
|
+
# це значення для base/dev. Не-base overlay-и мають зводити його до "metadata,graphql"
|
|
11
|
+
# патчем у kustomization.yaml — перевіряє JS `validateHasuraOverlayEnabledApisOverride`)
|
|
9
12
|
# "HASURA_GRAPHQL_DISABLE_EVENTING" → null (ключ обов'язковий,
|
|
10
13
|
# значення довільне; за замовчуванням рекомендовано "true")
|
|
11
14
|
#
|
|
@@ -39,6 +42,7 @@ required_env := {
|
|
|
39
42
|
"HASURA_GRAPHQL_ENABLE_RELAY": "false",
|
|
40
43
|
"HASURA_GRAPHQL_ENABLE_TELEMETRY": "false",
|
|
41
44
|
"HASURA_GRAPHQL_ENABLED_LOG_TYPES": "startup,http-log",
|
|
45
|
+
"HASURA_GRAPHQL_ENABLED_APIS": "metadata,graphql,pgdump",
|
|
42
46
|
"HASURA_GRAPHQL_DISABLE_EVENTING": null,
|
|
43
47
|
}
|
|
44
48
|
|
|
@@ -33,8 +33,9 @@ export function diffFromBase(base, run, cwd) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
* Промпт adversarial
|
|
37
|
-
*
|
|
36
|
+
* Промпт adversarial-рецензента. Фокус — diff, але рецензент працює у робочій теці
|
|
37
|
+
* репо й має інструмент `Read`, тож cross-file твердження мусить верифікувати читанням.
|
|
38
|
+
* Для high-risk додає безпекову лінзу.
|
|
38
39
|
* @param {string} diff текст diff
|
|
39
40
|
* @param {string} [risk] low|med|high — фокус перевірки
|
|
40
41
|
* @returns {string} промпт
|
|
@@ -45,11 +46,19 @@ export function reviewerPrompt(diff, risk) {
|
|
|
45
46
|
? 'ОСОБЛИВА УВАГА БЕЗПЕЦІ: auth/доступи, секрети/токени, ін\'єкції, валідація входу, незворотні операції.'
|
|
46
47
|
: ''
|
|
47
48
|
return [
|
|
48
|
-
'Ти — прискіпливий adversarial-рецензент. Знайди баги, ризики й smells
|
|
49
|
+
'Ти — прискіпливий adversarial-рецензент. Знайди баги, ризики й smells, які ВНОСИТЬ або зачіпає цей diff.',
|
|
50
|
+
'Якщо тобі доступний інструмент Read — ти в робочій теці репо: читай ТОЧКОВО потрібні referenced-файли' +
|
|
51
|
+
' (викликану функцію, інший модуль, spec/plan, конфіг), щоб ПЕРЕВІРИТИ cross-file твердження перед репортом.' +
|
|
52
|
+
' Якщо Read недоступний — рецензуй лише diff.',
|
|
53
|
+
'Сусідні файли читай ДЛЯ КОНТЕКСТУ й верифікації, а не щоб шукати в них окремі преіснуючі баги:' +
|
|
54
|
+
' репортуй лише те, що вносить/ламає цей diff.',
|
|
55
|
+
'НЕ видавай нефальсифіковних findings виду «з diff не видно / не показано / можливо» —' +
|
|
56
|
+
' або підтверди читанням файлу, або відкинь. Кожен finding має бути перевірним фактом.',
|
|
49
57
|
lens,
|
|
50
58
|
'Поверни ЛИШЕ JSON-масив: [{ "severity": "high|med|low", "file": "...", "issue": "...", "suggestion": "..." }].',
|
|
51
59
|
'Якщо проблем нема — поверни [].',
|
|
52
60
|
'',
|
|
61
|
+
'DIFF (фокус рецензування):',
|
|
53
62
|
diff.slice(0, DIFF_LIMIT)
|
|
54
63
|
]
|
|
55
64
|
.filter(Boolean)
|