初始提交:DSH 多租户平台(dshs)

This commit is contained in:
admin committed 2026-09-13 16:18:10 +08:00
commit 43976fea6a
167 files changed
+24456

No files matched your search

+141
View File
@@ -0,0 +1,141 @@
# 供应链 CI:构建两个镜像 → 功能冒烟 → Trivy 高危阻断 → push 到 ACR。
#
# 单 job(build-and-scan):镜像在 job 内 build + load,冒烟 + Trivy 过后,
# master 推送时再 tag + push 到阿里云 ACR(用 ACR_USERNAME / ACR_PASSWORD
# secret)。仓库:registry.example.com/dsh/
name: build
on:
push:
branches: [master]
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
build-and-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install + typecheck
run: |
npm ci
npm run typecheck
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build control-plane image
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile
push: false
load: true
tags: dshs:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build dsh image
uses: docker/build-push-action@v6
with:
context: .
file: Dockerfile.dsh
push: false
load: true
tags: dsh:ci
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Smoke — control plane (bootstrap-admin + serve)
run: |
# bootstrap-admin as the non-root image user (uid 65532), default data root.
docker run --rm dshs:ci bootstrap-admin \
--username admin --password 'ci-test-pass-123'
# Boot the server and publish 3080 so the host can reach it, then probe.
docker run --rm -d --name dsh-cp -p 3080:3080 dshs:ci \
--host 0.0.0.0 --port 3080
for i in $(seq 1 30); do
curl -fsS http://127.0.0.1:3080/ >/dev/null 2>&1 && break
sleep 1
done
# On failure, surface the server logs before the step aborts.
curl -fsS http://127.0.0.1:3080/ >/dev/null || { docker logs dsh-cp; exit 1; }
echo "control plane serving OK"
docker logs dsh-cp
docker stop dsh-cp
- name: Smoke — dsh resolves runtime plugin
run: |
# A patch referencing dshs/runtime must resolve and load:
# the plugin's apply() logs "[dshs-runtime] role=...".
# printf (not a here-doc) so the YAML stays at column 0 inside a
# literal block scalar.
printf '%s\n' \
'- insert:' \
' - id: dshs-runtime' \
' name: dshs/runtime' \
> /tmp/patch.yml
# Foreground + bounded timeout so an early exit still leaves logs.
# DSH_HOME mirrors the production layout (§4.3) so the parent-dir
# walk reaches /var/lib/dshs/node_modules; run as root so
# dsh can create that tree (the per-user uid is set by the Pod spec
# at deploy time, not exercised here).
timeout 25 docker run --rm --user 0 \
-v /tmp/patch.yml:/tmp/patch.yml:ro \
-e DSH_HOME=/var/lib/dshs/users/smoke/home \
dsh:ci --profile web --patch /tmp/patch.yml --host 127.0.0.1 --port 8080 \
> /tmp/dsh.log 2>&1 || true
cat /tmp/dsh.log
grep -q 'dshs-runtime' /tmp/dsh.log
echo "runtime plugin resolved OK"
- name: Trivy — control plane
uses: aquasecurity/[email protected]
with:
image-ref: dshs:ci
severity: HIGH,CRITICAL
exit-code: 1
# 只阻断「可修复」的高危;收紧为 false 则连不可修复的也拦。
ignore-unfixed: true
- name: Trivy — dsh
uses: aquasecurity/[email protected]
with:
image-ref: dsh:ci
severity: HIGH,CRITICAL
exit-code: 1
ignore-unfixed: true
# --- push to ACR (master push / manual dispatch on master only) ---
- name: Login to ACR
if: github.ref == 'refs/heads/master'
uses: docker/login-action@v3
with:
registry: registry.example.com
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- name: Push control plane to ACR
if: github.ref == 'refs/heads/master'
run: |
docker tag dshs:ci \
registry.example.com/dsh/dshs:0.2.0
docker push \
registry.example.com/dsh/dshs:0.2.0
- name: Push dsh to ACR
if: github.ref == 'refs/heads/master'
run: |
docker tag dsh:ci \
registry.example.com/dsh/dsh:0.1.1-rc.2
docker push \
registry.example.com/dsh/dsh:0.1.1-rc.2