mirror of
https://github.com/swissmakers/infram.git
synced 2026-05-08 22:49:00 +02:00
Maintain container security, add deb-check script and update vulnerable libs
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
name: Security Audit
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: "0 3 * * 1"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run container-only dependency audit
|
||||
env:
|
||||
SECURITY_FAIL_ON: high
|
||||
run: ./scripts/ci-security.sh audit
|
||||
|
||||
- name: Generate SBOM artifacts
|
||||
run: SECURITY_GENERATE_SBOM=1 ./scripts/ci-security.sh audit
|
||||
|
||||
- name: Upload security artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: security-artifacts
|
||||
path: artifacts/security/
|
||||
if-no-files-found: warn
|
||||
@@ -1,3 +1,6 @@
|
||||
.pnpm-store
|
||||
.tools
|
||||
|
||||
# Logs
|
||||
data/logs
|
||||
logs
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
FROM node:22-alpine AS client-builder
|
||||
|
||||
WORKDIR /app
|
||||
RUN apk upgrade --no-cache
|
||||
|
||||
COPY vendor/guacamole-client/guacamole-common-js/ ./vendor/guacamole-client/guacamole-common-js/
|
||||
|
||||
@@ -17,6 +18,7 @@ FROM node:22-alpine AS server-builder
|
||||
ARG VERSION
|
||||
|
||||
WORKDIR /app
|
||||
RUN apk upgrade --no-cache
|
||||
|
||||
RUN apk add --no-cache \
|
||||
python3 py3-pip py3-setuptools \
|
||||
@@ -32,6 +34,7 @@ RUN for i in 1 2 3; do yarn install --production --frozen-lockfile --network-tim
|
||||
COPY server/ server/
|
||||
|
||||
FROM node:22-alpine AS guacd-builder
|
||||
RUN apk upgrade --no-cache
|
||||
|
||||
RUN apk add --no-cache \
|
||||
cairo-dev jpeg-dev libpng-dev ossp-uuid-dev \
|
||||
@@ -56,6 +59,7 @@ RUN cd guacamole-server \
|
||||
&& strip /install/usr/local/sbin/guacd /install/usr/local/lib/*.so.* 2>/dev/null || true
|
||||
|
||||
FROM node:22-alpine
|
||||
RUN apk upgrade --no-cache
|
||||
|
||||
RUN apk add --no-cache \
|
||||
cairo jpeg libpng ossp-uuid \
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
.PHONY: security-update security-audit security-all security-sbom
|
||||
|
||||
security-update:
|
||||
./scripts/ci-security.sh update
|
||||
|
||||
security-audit:
|
||||
./scripts/ci-security.sh audit
|
||||
|
||||
security-all:
|
||||
./scripts/ci-security.sh all
|
||||
|
||||
security-sbom:
|
||||
SECURITY_GENERATE_SBOM=1 ./scripts/ci-security.sh audit
|
||||
@@ -105,6 +105,42 @@ The server listens on port 6989 by default. You can modify this behavior using e
|
||||
- Docker container isolation
|
||||
- Oauth 2.0 OpenID Connect SSO
|
||||
|
||||
### Container-Only Security Pipeline
|
||||
|
||||
You can run dependency updates and vulnerability audits without installing Node.js, Yarn, pnpm, Flutter or Cargo on your host.
|
||||
Only Docker or Podman is required.
|
||||
|
||||
```sh
|
||||
# Update dependency locks (root/client/landing/connector) in containers
|
||||
make security-update
|
||||
|
||||
# Run vulnerability audits with fail-on threshold (default: high)
|
||||
make security-audit
|
||||
|
||||
# Update + audit in one run
|
||||
make security-all
|
||||
|
||||
# Audit + SBOM generation
|
||||
make security-sbom
|
||||
```
|
||||
|
||||
Equivalent npm scripts are available:
|
||||
|
||||
```sh
|
||||
yarn security:update
|
||||
yarn security:audit
|
||||
yarn security:all
|
||||
yarn security:sbom
|
||||
```
|
||||
|
||||
Useful environment variables:
|
||||
|
||||
- `SECURITY_FAIL_ON` (`none|critical|high|moderate|low|info`, default: `high`)
|
||||
- `SECURITY_GENERATE_SBOM` (`1` to enable SBOM output under `artifacts/security/`)
|
||||
- `SECURITY_NODE_IMAGE` (override Node image, default: `node:22-bookworm-slim`)
|
||||
- `SECURITY_SYFT_IMAGE` (override Syft image, default: `anchore/syft:latest`)
|
||||
- `SECURITY_DRY_RUN` (`1` to print container commands without executing)
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"auditSummary","data":{"vulnerabilities":{"info":0,"low":0,"moderate":0,"high":0,"critical":0},"dependencies":419,"devDependencies":0,"optionalDependencies":0,"totalDependencies":419}}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"auditSummary","data":{"vulnerabilities":{"info":0,"low":0,"moderate":0,"high":0,"critical":0},"dependencies":12,"devDependencies":0,"optionalDependencies":0,"totalDependencies":12}}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"actions": [],
|
||||
"advisories": {},
|
||||
"muted": [],
|
||||
"metadata": {
|
||||
"vulnerabilities": {
|
||||
"info": 0,
|
||||
"low": 0,
|
||||
"moderate": 0,
|
||||
"high": 0,
|
||||
"critical": 0
|
||||
},
|
||||
"dependencies": 336,
|
||||
"devDependencies": 0,
|
||||
"optionalDependencies": 0,
|
||||
"totalDependencies": 336
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"auditSummary","data":{"vulnerabilities":{"info":0,"low":0,"moderate":0,"high":0,"critical":0},"dependencies":771,"devDependencies":0,"optionalDependencies":0,"totalDependencies":771}}
|
||||
+6
-3
@@ -35,10 +35,10 @@
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-i18next": "^16.5.5",
|
||||
"react-i18next": "^16.5.6",
|
||||
"react-router-dom": "^7.13.1",
|
||||
"react-use-websocket": "^4.13.0",
|
||||
"simple-icons": "^16.10.0",
|
||||
"simple-icons": "^16.11.0",
|
||||
"ua-parser-js": "^2.0.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -46,12 +46,15 @@
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint": "^10.0.3",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.2",
|
||||
"globals": "^17.4.0",
|
||||
"sass-embedded": "^1.97.3",
|
||||
"vite": "^7.3.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"dompurify": "^3.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
+556
-663
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,6 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2"
|
||||
"@tauri-apps/cli": "^2.10.1"
|
||||
}
|
||||
}
|
||||
|
||||
+59
-59
@@ -2,74 +2,74 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@tauri-apps/cli-darwin-arm64@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.9.6.tgz#bb1576a6567db0d331e34d2322dc6aebde6681e8"
|
||||
integrity sha512-gf5no6N9FCk1qMrti4lfwP77JHP5haASZgVbBgpZG7BUepB3fhiLCXGUK8LvuOjP36HivXewjg72LTnPDScnQQ==
|
||||
"@tauri-apps/cli-darwin-arm64@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.10.1.tgz#7abb013926613555559cce1583ab6521e07b997c"
|
||||
integrity sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ==
|
||||
|
||||
"@tauri-apps/cli-darwin-x64@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.9.6.tgz#7beb6ba8218002d7e160764326ce03407e76305d"
|
||||
integrity sha512-oWh74WmqbERwwrwcueJyY6HYhgCksUc6NT7WKeXyrlY/FPmNgdyQAgcLuTSkhRFuQ6zh4Np1HZpOqCTpeZBDcw==
|
||||
"@tauri-apps/cli-darwin-x64@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.10.1.tgz#cd1abd24782d488d0ee26f15015016b83a5b4bde"
|
||||
integrity sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw==
|
||||
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.9.6.tgz#523ddcd86a99bdda5156bd9de96dfd3e4fa75b7f"
|
||||
integrity sha512-/zde3bFroFsNXOHN204DC2qUxAcAanUjVXXSdEGmhwMUZeAQalNj5cz2Qli2elsRjKN/hVbZOJj0gQ5zaYUjSg==
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.10.1.tgz#9afdc71d24d44941d76fdc353f4401e82e9ccac5"
|
||||
integrity sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w==
|
||||
|
||||
"@tauri-apps/cli-linux-arm64-gnu@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.9.6.tgz#60b4cbd4b8b97c5f5be6cc70fa75455b5a6d6292"
|
||||
integrity sha512-pvbljdhp9VOo4RnID5ywSxgBs7qiylTPlK56cTk7InR3kYSTJKYMqv/4Q/4rGo/mG8cVppesKIeBMH42fw6wjg==
|
||||
"@tauri-apps/cli-linux-arm64-gnu@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.10.1.tgz#3a0a1e31eda8f01b69db09179094e0dc7ff5bb60"
|
||||
integrity sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA==
|
||||
|
||||
"@tauri-apps/cli-linux-arm64-musl@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.9.6.tgz#ce5e5396db6c7f22b80154757479b1486163364a"
|
||||
integrity sha512-02TKUndpodXBCR0oP//6dZWGYcc22Upf2eP27NvC6z0DIqvkBBFziQUcvi2n6SrwTRL0yGgQjkm9K5NIn8s6jw==
|
||||
"@tauri-apps/cli-linux-arm64-musl@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.10.1.tgz#6fc7e74e4a6053dd64b81dfdaf9dbabb6df31971"
|
||||
integrity sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg==
|
||||
|
||||
"@tauri-apps/cli-linux-riscv64-gnu@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.9.6.tgz#aa8ec23d62cbb85a75c3e172637e78f485dbfcf8"
|
||||
integrity sha512-fmp1hnulbqzl1GkXl4aTX9fV+ubHw2LqlLH1PE3BxZ11EQk+l/TmiEongjnxF0ie4kV8DQfDNJ1KGiIdWe1GvQ==
|
||||
"@tauri-apps/cli-linux-riscv64-gnu@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.10.1.tgz#9a5d3bb8efb17ef65146d0f319c6cf212e2a724a"
|
||||
integrity sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw==
|
||||
|
||||
"@tauri-apps/cli-linux-x64-gnu@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.9.6.tgz#036c0463c5eee2298ed6ca8cb2838738816c7290"
|
||||
integrity sha512-vY0le8ad2KaV1PJr+jCd8fUF9VOjwwQP/uBuTJvhvKTloEwxYA/kAjKK9OpIslGA9m/zcnSo74czI6bBrm2sYA==
|
||||
"@tauri-apps/cli-linux-x64-gnu@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.10.1.tgz#cf54e3754d2a54894323840aef1f9789888e0d57"
|
||||
integrity sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw==
|
||||
|
||||
"@tauri-apps/cli-linux-x64-musl@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.9.6.tgz#62b05db3d28b0f12c150836a387bd572de44f5be"
|
||||
integrity sha512-TOEuB8YCFZTWVDzsO2yW0+zGcoMiPPwcUgdnW1ODnmgfwccpnihDRoks+ABT1e3fHb1ol8QQWsHSCovb3o2ENQ==
|
||||
"@tauri-apps/cli-linux-x64-musl@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.10.1.tgz#dc4bd17e812b448b3ccec0684f336f19fb47b069"
|
||||
integrity sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ==
|
||||
|
||||
"@tauri-apps/cli-win32-arm64-msvc@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.9.6.tgz#01f69ba09a6581e70bdfa206c5801b64b329d28d"
|
||||
integrity sha512-ujmDGMRc4qRLAnj8nNG26Rlz9klJ0I0jmZs2BPpmNNf0gM/rcVHhqbEkAaHPTBVIrtUdf7bGvQAD2pyIiUrBHQ==
|
||||
"@tauri-apps/cli-win32-arm64-msvc@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.10.1.tgz#2f398fb17f4665fefe5b8cb21566cde7062236f5"
|
||||
integrity sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg==
|
||||
|
||||
"@tauri-apps/cli-win32-ia32-msvc@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.9.6.tgz#b36c60db5119d74f126d4c4d8288d1c6ae4b45f0"
|
||||
integrity sha512-S4pT0yAJgFX8QRCyKA1iKjZ9Q/oPjCZf66A/VlG5Yw54Nnr88J1uBpmenINbXxzyhduWrIXBaUbEY1K80ZbpMg==
|
||||
"@tauri-apps/cli-win32-ia32-msvc@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.10.1.tgz#ffcbc2fa6a1d71f0b38672ea3468c07581f5cfaf"
|
||||
integrity sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw==
|
||||
|
||||
"@tauri-apps/cli-win32-x64-msvc@2.9.6":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.9.6.tgz#d58c9f8af835b7e4fc30e201e979342c70bea426"
|
||||
integrity sha512-ldWuWSSkWbKOPjQMJoYVj9wLHcOniv7diyI5UAJ4XsBdtaFB0pKHQsqw/ItUma0VXGC7vB4E9fZjivmxur60aw==
|
||||
"@tauri-apps/cli-win32-x64-msvc@2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.10.1.tgz#75a3842ecab5e13b15ad2eead4c1b9cc3916e78d"
|
||||
integrity sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg==
|
||||
|
||||
"@tauri-apps/cli@^2":
|
||||
version "2.9.6"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-2.9.6.tgz#f15ae8e03bf48308055c15ab25b439bed9906bc9"
|
||||
integrity sha512-3xDdXL5omQ3sPfBfdC8fCtDKcnyV7OqyzQgfyT5P3+zY6lcPqIYKQBvUasNvppi21RSdfhy44ttvJmftb0PCDw==
|
||||
"@tauri-apps/cli@^2.10.1":
|
||||
version "2.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-2.10.1.tgz#d9b0290f03d569e10eb349a0bb72f448880bf9d7"
|
||||
integrity sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g==
|
||||
optionalDependencies:
|
||||
"@tauri-apps/cli-darwin-arm64" "2.9.6"
|
||||
"@tauri-apps/cli-darwin-x64" "2.9.6"
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf" "2.9.6"
|
||||
"@tauri-apps/cli-linux-arm64-gnu" "2.9.6"
|
||||
"@tauri-apps/cli-linux-arm64-musl" "2.9.6"
|
||||
"@tauri-apps/cli-linux-riscv64-gnu" "2.9.6"
|
||||
"@tauri-apps/cli-linux-x64-gnu" "2.9.6"
|
||||
"@tauri-apps/cli-linux-x64-musl" "2.9.6"
|
||||
"@tauri-apps/cli-win32-arm64-msvc" "2.9.6"
|
||||
"@tauri-apps/cli-win32-ia32-msvc" "2.9.6"
|
||||
"@tauri-apps/cli-win32-x64-msvc" "2.9.6"
|
||||
"@tauri-apps/cli-darwin-arm64" "2.10.1"
|
||||
"@tauri-apps/cli-darwin-x64" "2.10.1"
|
||||
"@tauri-apps/cli-linux-arm-gnueabihf" "2.10.1"
|
||||
"@tauri-apps/cli-linux-arm64-gnu" "2.10.1"
|
||||
"@tauri-apps/cli-linux-arm64-musl" "2.10.1"
|
||||
"@tauri-apps/cli-linux-riscv64-gnu" "2.10.1"
|
||||
"@tauri-apps/cli-linux-x64-gnu" "2.10.1"
|
||||
"@tauri-apps/cli-linux-x64-musl" "2.10.1"
|
||||
"@tauri-apps/cli-win32-arm64-msvc" "2.10.1"
|
||||
"@tauri-apps/cli-win32-ia32-msvc" "2.10.1"
|
||||
"@tauri-apps/cli-win32-x64-msvc" "2.10.1"
|
||||
|
||||
@@ -93,3 +93,16 @@ services:
|
||||
+ infram-net:
|
||||
+ enable_ipv6: true
|
||||
```
|
||||
|
||||
## Security Maintenance (Container-Only)
|
||||
|
||||
For dependency updates and vulnerability scans, you can run the built-in container pipeline:
|
||||
|
||||
```sh
|
||||
make security-update
|
||||
make security-audit
|
||||
make security-all
|
||||
make security-sbom
|
||||
```
|
||||
|
||||
This only requires Docker or Podman on the host. The required Node/Yarn/pnpm tooling is executed inside ephemeral containers.
|
||||
|
||||
+12
-12
@@ -10,23 +10,23 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^7.1.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^7.1.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.1.0",
|
||||
"@fortawesome/react-fontawesome": "^3.1.1",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react-router-dom": "^7.12.0",
|
||||
"sass": "^1.97.2"
|
||||
"@fortawesome/fontawesome-svg-core": "^7.2.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^7.2.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^7.2.0",
|
||||
"@fortawesome/react-fontawesome": "^3.2.0",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-router-dom": "^7.13.1",
|
||||
"sass": "^1.97.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/react": "^19.2.14",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^5.1.2",
|
||||
"eslint": "^9.39.2",
|
||||
"@vitejs/plugin-react": "^5.1.4",
|
||||
"eslint": "^10.0.3",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.4.26",
|
||||
"eslint-plugin-react-refresh": "^0.5.2",
|
||||
"vite": "^7.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+592
-659
File diff suppressed because it is too large
Load Diff
+25
-7
@@ -6,20 +6,22 @@
|
||||
"author": "Swissmakers GmbH",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@simplewebauthn/server": "^13.2.2",
|
||||
"@simplewebauthn/server": "^13.2.3",
|
||||
"archiver": "^7.0.1",
|
||||
"axios": "^1.13.5",
|
||||
"axios": "^1.13.6",
|
||||
"bcrypt": "^6.0.0",
|
||||
"decompress": "^4.2.1",
|
||||
"esbuild": "^0.27.3",
|
||||
"express": "^5.2.1",
|
||||
"express-jsdoc-swagger": "^1.8.0",
|
||||
"express-rate-limit": "^8.2.1",
|
||||
"express-rate-limit": "^8.3.0",
|
||||
"express-ws": "^5.0.2",
|
||||
"glob": "^13.0.6",
|
||||
"joi": "^18.0.2",
|
||||
"js-yaml": "^4.1.1",
|
||||
"ldapts": "^8.1.7",
|
||||
"openid-client": "^6.8.2",
|
||||
"sequelize": "^6.37.7",
|
||||
"sequelize": "^6.37.8",
|
||||
"sharp": "^0.34.5",
|
||||
"speakeasy": "^2.0.0",
|
||||
"sqlite3": "^5.1.7",
|
||||
@@ -34,7 +36,7 @@
|
||||
"dotenv": "^17.3.1",
|
||||
"nodemon": "^3.1.14",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitepress-openapi": "^0.1.15"
|
||||
"vitepress-openapi": "^0.1.17"
|
||||
},
|
||||
"scripts": {
|
||||
"dev:server": "nodemon --ignore docs --ignore vendor --ignore client --ignore mobile --ignore data server/index.js",
|
||||
@@ -44,6 +46,22 @@
|
||||
"docs:openapi": "node scripts/generate-openapi.js",
|
||||
"docs:dev": "yarn docs:openapi && vitepress dev docs",
|
||||
"docs:build": "yarn docs:openapi && vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
}
|
||||
"docs:preview": "vitepress preview docs",
|
||||
"security:update": "./scripts/ci-security.sh update",
|
||||
"security:audit": "./scripts/ci-security.sh audit",
|
||||
"security:all": "./scripts/ci-security.sh all",
|
||||
"security:sbom": "SECURITY_GENERATE_SBOM=1 ./scripts/ci-security.sh audit"
|
||||
},
|
||||
"resolutions": {
|
||||
"tar": "^7.5.10",
|
||||
"@tootallnate/once": "^3.0.1",
|
||||
"esbuild": "^0.25.0",
|
||||
"glob": "^11.1.0",
|
||||
"minimatch": "^10.2.3",
|
||||
"qs": "^6.14.2",
|
||||
"lodash": "^4.17.23",
|
||||
"dottie": "^2.0.7",
|
||||
"fast-xml-parser": "^5.3.8"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
||||
Executable
+302
@@ -0,0 +1,302 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
MODE="${1:-all}"
|
||||
FAIL_ON="${SECURITY_FAIL_ON:-high}"
|
||||
NODE_IMAGE="${SECURITY_NODE_IMAGE:-docker.io/library/node:22-bookworm-slim}"
|
||||
SYFT_IMAGE="${SECURITY_SYFT_IMAGE:-docker.io/anchore/syft:latest}"
|
||||
ARTIFACT_DIR="${SECURITY_ARTIFACT_DIR:-${PROJECT_ROOT}/artifacts/security}"
|
||||
GENERATE_SBOM="${SECURITY_GENERATE_SBOM:-0}"
|
||||
DRY_RUN="${SECURITY_DRY_RUN:-0}"
|
||||
|
||||
RUNTIME=""
|
||||
VOLUME_SUFFIX=""
|
||||
|
||||
log() {
|
||||
echo "[security] $*"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "[security] ERROR: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage: ./scripts/ci-security.sh [update|audit|all]
|
||||
|
||||
Environment variables:
|
||||
SECURITY_FAIL_ON Severity threshold for failing audit (default: high)
|
||||
Allowed: none|critical|high|moderate|low|info
|
||||
SECURITY_NODE_IMAGE Node container image (default: node:22-bookworm-slim)
|
||||
SECURITY_SYFT_IMAGE Syft container image (default: anchore/syft:latest)
|
||||
SECURITY_ARTIFACT_DIR Output folder for reports (default: artifacts/security)
|
||||
SECURITY_GENERATE_SBOM Set to 1 to generate SBOM files
|
||||
SECURITY_DRY_RUN Set to 1 to print commands without executing
|
||||
EOF
|
||||
}
|
||||
|
||||
detect_runtime() {
|
||||
if command -v podman >/dev/null 2>&1; then
|
||||
RUNTIME="podman"
|
||||
VOLUME_SUFFIX=":Z"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
RUNTIME="docker"
|
||||
VOLUME_SUFFIX=""
|
||||
return 0
|
||||
fi
|
||||
|
||||
fail "Neither podman nor docker is available on PATH."
|
||||
}
|
||||
|
||||
run_node_container() {
|
||||
local workdir="$1"
|
||||
local cmd="$2"
|
||||
|
||||
local runtime_args=(run --rm -v "${PROJECT_ROOT}:/workspace${VOLUME_SUFFIX}" -w "${workdir}")
|
||||
if [[ "${RUNTIME}" == "podman" ]]; then
|
||||
runtime_args+=(--userns=keep-id)
|
||||
fi
|
||||
|
||||
if [[ "${DRY_RUN}" == "1" ]]; then
|
||||
log "DRY RUN: ${RUNTIME} ${runtime_args[*]} ${NODE_IMAGE} sh -lc \"${cmd}\""
|
||||
return 0
|
||||
fi
|
||||
|
||||
"${RUNTIME}" "${runtime_args[@]}" "${NODE_IMAGE}" sh -lc "${cmd}"
|
||||
}
|
||||
|
||||
run_syft_container() {
|
||||
local output_path="$1"
|
||||
local target_path="$2"
|
||||
|
||||
local runtime_args=(run --rm -v "${PROJECT_ROOT}:/workspace${VOLUME_SUFFIX}" -w /workspace)
|
||||
if [[ "${RUNTIME}" == "podman" ]]; then
|
||||
runtime_args+=(--userns=keep-id)
|
||||
fi
|
||||
|
||||
if [[ "${DRY_RUN}" == "1" ]]; then
|
||||
log "DRY RUN: ${RUNTIME} ${runtime_args[*]} ${SYFT_IMAGE} ${target_path} -o spdx-json=${output_path}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
"${RUNTIME}" "${runtime_args[@]}" "${SYFT_IMAGE}" "${target_path}" -o "spdx-json=${output_path}"
|
||||
}
|
||||
|
||||
prepare_artifacts() {
|
||||
mkdir -p "${ARTIFACT_DIR}"
|
||||
}
|
||||
|
||||
to_container_path() {
|
||||
local host_path="$1"
|
||||
if [[ "${host_path}" == "${PROJECT_ROOT}"* ]]; then
|
||||
printf "/workspace%s" "${host_path#${PROJECT_ROOT}}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
fail "SECURITY_ARTIFACT_DIR must be inside ${PROJECT_ROOT} when using containerized commands."
|
||||
}
|
||||
|
||||
extract_yarn_counts() {
|
||||
local jsonl_file="$1"
|
||||
python3 -c '
|
||||
import json
|
||||
import sys
|
||||
|
||||
file = sys.argv[1]
|
||||
summary = None
|
||||
with open(file, "r", encoding="utf-8") as handle:
|
||||
for line in handle:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
obj = json.loads(line)
|
||||
except Exception:
|
||||
continue
|
||||
if obj.get("type") == "auditSummary":
|
||||
summary = (obj.get("data") or {}).get("vulnerabilities")
|
||||
|
||||
if not summary:
|
||||
print(f"Missing yarn audit summary in {file}", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
values = [
|
||||
int(summary.get("info", 0)),
|
||||
int(summary.get("low", 0)),
|
||||
int(summary.get("moderate", 0)),
|
||||
int(summary.get("high", 0)),
|
||||
int(summary.get("critical", 0)),
|
||||
]
|
||||
print(" ".join(str(v) for v in values), end="")
|
||||
' "${jsonl_file}"
|
||||
}
|
||||
|
||||
extract_pnpm_counts() {
|
||||
local json_file="$1"
|
||||
python3 -c '
|
||||
import json
|
||||
import sys
|
||||
|
||||
file = sys.argv[1]
|
||||
with open(file, "r", encoding="utf-8") as handle:
|
||||
obj = json.load(handle)
|
||||
|
||||
vulns = ((obj.get("metadata") or {}).get("vulnerabilities"))
|
||||
if not vulns:
|
||||
print(f"Missing pnpm audit summary in {file}", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
values = [
|
||||
int(vulns.get("info", 0)),
|
||||
int(vulns.get("low", 0)),
|
||||
int(vulns.get("moderate", 0)),
|
||||
int(vulns.get("high", 0)),
|
||||
int(vulns.get("critical", 0)),
|
||||
]
|
||||
print(" ".join(str(v) for v in values), end="")
|
||||
' "${json_file}"
|
||||
}
|
||||
|
||||
should_fail_by_threshold() {
|
||||
local info="$1"
|
||||
local low="$2"
|
||||
local moderate="$3"
|
||||
local high="$4"
|
||||
local critical="$5"
|
||||
|
||||
case "${FAIL_ON}" in
|
||||
none) return 1 ;;
|
||||
critical) (( critical > 0 )) ;;
|
||||
high) (( high > 0 || critical > 0 )) ;;
|
||||
moderate) (( moderate > 0 || high > 0 || critical > 0 )) ;;
|
||||
low) (( low > 0 || moderate > 0 || high > 0 || critical > 0 )) ;;
|
||||
info) (( info > 0 || low > 0 || moderate > 0 || high > 0 || critical > 0 )) ;;
|
||||
*) fail "Invalid SECURITY_FAIL_ON='${FAIL_ON}'. Use none|critical|high|moderate|low|info." ;;
|
||||
esac
|
||||
}
|
||||
|
||||
run_update() {
|
||||
log "Running dependency update pipeline in containers..."
|
||||
|
||||
run_node_container "/workspace" \
|
||||
"corepack enable && corepack prepare yarn@1.22.22 --activate && yarn upgrade --latest && yarn install"
|
||||
|
||||
run_node_container "/workspace/client" \
|
||||
"corepack enable && corepack prepare yarn@1.22.22 --activate && yarn upgrade --latest && yarn install"
|
||||
|
||||
run_node_container "/workspace/landing" \
|
||||
"corepack enable && COREPACK_ENABLE_PROJECT_SPEC=0 corepack pnpm up --latest --store-dir /workspace/.pnpm-store"
|
||||
|
||||
run_node_container "/workspace/connector" \
|
||||
"corepack enable && corepack prepare yarn@1.22.22 --activate && yarn upgrade --latest && yarn install"
|
||||
}
|
||||
|
||||
run_audit() {
|
||||
log "Running vulnerability audits (threshold: ${FAIL_ON})..."
|
||||
prepare_artifacts
|
||||
|
||||
local root_jsonl="${ARTIFACT_DIR}/root-yarn-audit.jsonl"
|
||||
local client_jsonl="${ARTIFACT_DIR}/client-yarn-audit.jsonl"
|
||||
local connector_jsonl="${ARTIFACT_DIR}/connector-yarn-audit.jsonl"
|
||||
local landing_json="${ARTIFACT_DIR}/landing-pnpm-audit.json"
|
||||
local container_artifact_dir
|
||||
container_artifact_dir="$(to_container_path "${ARTIFACT_DIR}")"
|
||||
|
||||
run_node_container "/workspace" \
|
||||
"corepack enable && corepack prepare yarn@1.22.22 --activate && yarn install --frozen-lockfile && (yarn audit --level low --json || true) > '${container_artifact_dir}/root-yarn-audit.jsonl'"
|
||||
run_node_container "/workspace/client" \
|
||||
"corepack enable && corepack prepare yarn@1.22.22 --activate && yarn install --frozen-lockfile && (yarn audit --level low --json || true) > '${container_artifact_dir}/client-yarn-audit.jsonl'"
|
||||
run_node_container "/workspace/connector" \
|
||||
"corepack enable && corepack prepare yarn@1.22.22 --activate && yarn install --frozen-lockfile && (yarn audit --level low --json || true) > '${container_artifact_dir}/connector-yarn-audit.jsonl'"
|
||||
run_node_container "/workspace/landing" \
|
||||
"corepack enable && COREPACK_ENABLE_PROJECT_SPEC=0 corepack pnpm install --frozen-lockfile --store-dir /workspace/.pnpm-store && (COREPACK_ENABLE_PROJECT_SPEC=0 corepack pnpm audit --json || true) > '${container_artifact_dir}/landing-pnpm-audit.json'"
|
||||
|
||||
if [[ "${DRY_RUN}" == "1" ]]; then
|
||||
log "Dry-run enabled: skipping audit report parsing and threshold enforcement."
|
||||
return 0
|
||||
fi
|
||||
|
||||
local root_counts client_counts connector_counts landing_counts
|
||||
root_counts="$(extract_yarn_counts "${root_jsonl}")"
|
||||
client_counts="$(extract_yarn_counts "${client_jsonl}")"
|
||||
connector_counts="$(extract_yarn_counts "${connector_jsonl}")"
|
||||
landing_counts="$(extract_pnpm_counts "${landing_json}")"
|
||||
|
||||
local info low moderate high critical
|
||||
read -r info low moderate high critical <<<"${root_counts}"
|
||||
log "root: info=${info} low=${low} moderate=${moderate} high=${high} critical=${critical}"
|
||||
if should_fail_by_threshold "${info}" "${low}" "${moderate}" "${high}" "${critical}"; then
|
||||
fail "root audit exceeded threshold '${FAIL_ON}'"
|
||||
fi
|
||||
|
||||
read -r info low moderate high critical <<<"${client_counts}"
|
||||
log "client: info=${info} low=${low} moderate=${moderate} high=${high} critical=${critical}"
|
||||
if should_fail_by_threshold "${info}" "${low}" "${moderate}" "${high}" "${critical}"; then
|
||||
fail "client audit exceeded threshold '${FAIL_ON}'"
|
||||
fi
|
||||
|
||||
read -r info low moderate high critical <<<"${connector_counts}"
|
||||
log "connector: info=${info} low=${low} moderate=${moderate} high=${high} critical=${critical}"
|
||||
if should_fail_by_threshold "${info}" "${low}" "${moderate}" "${high}" "${critical}"; then
|
||||
fail "connector audit exceeded threshold '${FAIL_ON}'"
|
||||
fi
|
||||
|
||||
read -r info low moderate high critical <<<"${landing_counts}"
|
||||
log "landing: info=${info} low=${low} moderate=${moderate} high=${high} critical=${critical}"
|
||||
if should_fail_by_threshold "${info}" "${low}" "${moderate}" "${high}" "${critical}"; then
|
||||
fail "landing audit exceeded threshold '${FAIL_ON}'"
|
||||
fi
|
||||
}
|
||||
|
||||
generate_sbom() {
|
||||
if [[ "${GENERATE_SBOM}" != "1" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Generating SBOM artifacts..."
|
||||
prepare_artifacts
|
||||
run_syft_container "/workspace/artifacts/security/sbom-root.spdx.json" "dir:/workspace"
|
||||
run_syft_container "/workspace/artifacts/security/sbom-client.spdx.json" "dir:/workspace/client"
|
||||
run_syft_container "/workspace/artifacts/security/sbom-landing.spdx.json" "dir:/workspace/landing"
|
||||
run_syft_container "/workspace/artifacts/security/sbom-connector.spdx.json" "dir:/workspace/connector"
|
||||
}
|
||||
|
||||
main() {
|
||||
detect_runtime
|
||||
log "Using runtime: ${RUNTIME}"
|
||||
|
||||
case "${MODE}" in
|
||||
update)
|
||||
run_update
|
||||
generate_sbom
|
||||
;;
|
||||
audit)
|
||||
run_audit
|
||||
generate_sbom
|
||||
;;
|
||||
all)
|
||||
run_update
|
||||
run_audit
|
||||
generate_sbom
|
||||
;;
|
||||
-h|--help|help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
fail "Unknown mode '${MODE}'."
|
||||
;;
|
||||
esac
|
||||
|
||||
log "Completed successfully."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user