ci: backend verification, security and Renovate #1 #5 #6 #9

Merged
ksv741 merged 1 commits from codex/ci-security-renovate into main 2026-09-13 20:03:55 +03:00
7 changed files with 190 additions and 52 deletions
+31
View File
@@ -0,0 +1,31 @@
name: Backend security
on:
push:
branches:
- '**'
pull_request:
schedule:
- cron: '17 5 * * *'
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: https://github.com/actions/checkout@v4
with:
fetch-depth: 0
- name: Record checked revision
run: git rev-parse HEAD
- name: Scan history with Gitleaks 8.30.1
run: |
curl --fail --location --silent --show-error https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz -o /tmp/gitleaks.tar.gz
echo '551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb /tmp/gitleaks.tar.gz' | sha256sum --check
mkdir -p /tmp/gitleaks-bin
tar -xzf /tmp/gitleaks.tar.gz -C /tmp/gitleaks-bin gitleaks
/tmp/gitleaks-bin/gitleaks git --log-opts=--all --redact=100 --no-banner
- uses: https://github.com/actions/setup-node@v4
with:
node-version-file: .nvmrc
- name: Audit runtime and development dependencies
run: npm audit --include=dev --audit-level=low
+33
View File
@@ -0,0 +1,33 @@
name: Backend verify
on:
push:
branches:
- '**'
jobs:
verify:
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: https://github.com/actions/checkout@v4
with:
path: backend
- name: Checkout frontend contract
run: git clone --depth 1 --branch main https://git.personal.ksv741.ru/WealthLedger/frontend.git ../frontend
- name: Record checked revisions
run: |
git rev-parse HEAD
git -C ../frontend rev-parse HEAD
- uses: https://github.com/actions/setup-node@v4
with:
node-version-file: backend/.nvmrc
- run: npm ci
- name: Generate Prisma client before typechecks
run: npx --no-install prisma generate
- name: Run all backend gates
run: npm run verify
- name: Run isolated SQLite and runtime OpenAPI suites
run: npm run test:e2e
+17
View File
@@ -0,0 +1,17 @@
# Reviewed historical false positives only; new commits remain scanned.
# Test fixtures: base64 of the deterministic string 0123456789abcdef repeated twice.
25d7c5780b60343fecb4f1ae9a30392776eb5aec:src/config/env.validation.spec.ts:generic-api-key:30
31cbba8654f01adf11c52e12c2b286200d6cad7d:src/config/env.validation.spec.ts:generic-api-key:10
31cbba8654f01adf11c52e12c2b286200d6cad7d:src/config/env.validation.spec.ts:generic-api-key:17
31cbba8654f01adf11c52e12c2b286200d6cad7d:src/config/env.validation.spec.ts:generic-api-key:42
31cbba8654f01adf11c52e12c2b286200d6cad7d:test/e2e-env.cjs:generic-api-key:4
326fb67def9b3878d5447ef838ae96d50bf493d6:src/tbank/brokerage-operations.service.spec.ts:generic-api-key:15
34c2b79e276c9575996604f3f862bc866cfe44e7:src/tbank/upcoming-events.service.spec.ts:generic-api-key:15
c0a4a9388074bdce20138dd5649805ed24a9e9fa:src/tbank/brokerage-accounts.service.spec.ts:generic-api-key:12
ce24a84b7fb48091d2b91836eb7b702a2f811c96:test/e2e-env.cjs:generic-api-key:16
dfca11c81f7e6dadce3ca6f961d265c5e3f8ff8e:src/tbank/portfolio.service.spec.ts:generic-api-key:16
# Historical .env.example JWT_SECRET is an explicit replace-with placeholder.
4cbfc2621cfc54df3d09786905130c28a2323a04:.env.example:generic-api-key:4
# Historical CircleCI badge copied verbatim from nestjs/typescript-starter README.
# Verified against https://github.com/nestjs/typescript-starter/blob/master/README.md
f8dcfb71c1767696a9aa6741ddaf6575416c901e:README.md:generic-api-key:5
+22
View File
@@ -37,6 +37,28 @@ threshold. `npm run test:e2e` отдельно проверяет все HTTP su
выполните обе команды. Результаты — в
[remediation registry](../docs/development/audit-remediation.md).
### CI и обновления зависимостей
`.gitea/workflows/verify.yml` запускает `npm ci`, генерацию Prisma client,
`npm run verify` и `npm run test:e2e` на каждом push ветки. Frontend snapshot
берётся из `main` соседнего репозитория; лог сохраняет оба SHA. Изменение
контракта согласуется с этой frontend revision. Успешный unit gate не заменяет
SQLite/e2e; ошибка любой suite завершает job с FAIL.
`security.yml` сканирует всю Git-историю Gitleaks 8.30.1 с полностью скрытыми
значениями и выполняет `npm audit --include=dev --audit-level=low` при push,
PR и ежедневно. `.gitleaksignore` перечисляет только проверенные исторические
совпадения: детерминированные fixtures, placeholder и badge из Nest starter.
Новые коммиты этими исключениями не покрываются.
Renovate группирует minor/patch updates, а major требует согласования в
Dependency Dashboard. Автоматический merge не включён. Overrides в
`package.json` закрывают advisories транзитивных `multer`, `deepmerge-ts`,
`mysql2` и `js-yaml`; удаляйте их, когда родительские пакеты примут исправленные
версии. Совместимость Prisma override проверяется генерацией и SQLite migrations.
Required checks настраиваются отдельно в Gitea: наличие workflow само по себе
не блокирует merge.
Общий `tsconfig.json` включает `strict: true` и `noFallthroughCasesInSwitch`
для приложения, тестов и сборок. ESLint запрещает non-null assertions
(`value!`) и definite-assignment assertions (`field!: Type`).
+52 -51
View File
@@ -1595,9 +1595,9 @@
}
},
"node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
"version": "3.15.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.1.tgz",
"integrity": "sha512-S99WuO3HlhO3XN41EtYUNl9zzXjoJx7QvmipxsJVxtCBT0YHEFy+iOJhjSvrmV12nYhWpZaM8lPHkJm0yUMbag==",
"version": "3.15.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz",
"integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -6254,13 +6254,23 @@
}
},
"node_modules/deepmerge-ts": {
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz",
"integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==",
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-8.0.2.tgz",
"integrity": "sha512-uqbvqLUMrc6p0MO+WBRtTxY55hmyh94WRwI5a++PZe54X+bfVh59FSN7uWCBCW1CCVjzjnrwzfI8zidE2obMMw==",
"devOptional": true,
"funding": [
{
"type": "ko-fi",
"url": "https://ko-fi.com/rebeccastevens"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/deepmerge-ts"
}
],
"license": "BSD-3-Clause",
"engines": {
"node": ">=16.0.0"
"node": ">=16.9.0"
}
},
"node_modules/defaults": {
@@ -6303,16 +6313,6 @@
"node": ">=0.4.0"
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
"devOptional": true,
"license": "Apache-2.0",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -7170,9 +7170,9 @@
"license": "MIT"
},
"node_modules/fast-uri": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
"integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz",
"integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==",
"devOptional": true,
"funding": [
{
@@ -8990,9 +8990,9 @@
"license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
"integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
"integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"dev": true,
"funding": [
{
@@ -9728,9 +9728,9 @@
"license": "MIT"
},
"node_modules/multer": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.2.0.tgz",
"integrity": "sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/multer/-/multer-2.3.0.tgz",
"integrity": "sha512-cjNbm3sttszgZeGfJR124D+jFEfkXCVAsoPBmFn9X7UxmDSFHWqE2CoEj0vrmSpuAFnqWR1Szcm9QTsiHr60Xw==",
"license": "MIT",
"dependencies": {
"append-field": "^1.0.0",
@@ -9800,24 +9800,25 @@
}
},
"node_modules/mysql2": {
"version": "3.15.3",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz",
"integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==",
"version": "3.24.4",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.24.4.tgz",
"integrity": "sha512-A2olluVlj0mvgyIRRISMEzXc51m+21mRtcMVjJyIpt2GG98+XrC9m9HzsqcMsX2LcnfccJvY5NB22g8fENBnOA==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"aws-ssl-profiles": "^1.1.1",
"denque": "^2.1.0",
"aws-ssl-profiles": "^1.1.2",
"generate-function": "^2.3.1",
"iconv-lite": "^0.7.0",
"long": "^5.2.1",
"lru.min": "^1.0.0",
"named-placeholders": "^1.1.3",
"seq-queue": "^0.0.5",
"sqlstring": "^2.3.2"
"iconv-lite": "^0.7.3",
"long": "^5.3.2",
"lru.min": "^1.1.4",
"named-placeholders": "^1.1.6",
"sql-escaper": "^1.5.1"
},
"engines": {
"node": ">= 8.0"
},
"peerDependencies": {
"@types/node": ">= 8"
}
},
"node_modules/named-placeholders": {
@@ -10803,9 +10804,9 @@
"license": "MIT"
},
"node_modules/qs": {
"version": "6.15.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz",
"integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==",
"version": "6.16.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz",
"integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==",
"license": "BSD-3-Clause",
"dependencies": {
"es-define-property": "^1.0.1",
@@ -11229,12 +11230,6 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/seq-queue": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==",
"devOptional": true
},
"node_modules/serve-static": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
@@ -11479,14 +11474,20 @@
"dev": true,
"license": "BSD-3-Clause"
},
"node_modules/sqlstring": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
"node_modules/sql-escaper": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/sql-escaper/-/sql-escaper-1.5.1.tgz",
"integrity": "sha512-4toX5E1fQbBrpfXidaHnF0669nkAdETeIPTs2SUjxxD7RRIs9ICG4gtpmfc68JCEKehsdwLFqBu9VlQqZ1P1gg==",
"devOptional": true,
"license": "MIT",
"engines": {
"node": ">= 0.6"
"bun": ">=1.0.0",
"deno": ">=2.0.0",
"node": ">=12.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/mysqljs/sql-escaper?sponsor=1"
}
},
"node_modules/stack-utils": {
+9
View File
@@ -88,6 +88,15 @@
"overrides": {
"@nestjs/swagger@11.4.5": {
"js-yaml": "5.2.3"
},
"@nestjs/platform-express": {
"multer": "2.3.0"
},
"@prisma/config@7.9.1": {
"deepmerge-ts": "8.0.2"
},
"prisma": {
"mysql2": "3.24.4"
}
},
"jest": {
+26 -1
View File
@@ -1,3 +1,28 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":semanticCommitTypeAll(chore)"
],
"timezone": "Europe/Moscow",
"labels": [
"dependencies"
],
"dependencyDashboard": true,
"rangeStrategy": "bump",
"packageRules": [
{
"matchUpdateTypes": [
"minor",
"patch"
],
"groupName": "non-major dependencies"
},
{
"matchUpdateTypes": [
"major"
],
"dependencyDashboardApproval": true
}
]
}