### Windows runner.env configuration Source: https://github.com/zixiao-labs/wuling-devops/blob/main/runners/runner-clients/README.md Configuration file for Windows static machine installation. Write this to C:\ProgramData\wuling-runner\runner.env after installing the setup.exe and minting a registration token. ```plaintext WULING_RUNNER_SERVER_URL=https://wuling.example.com WULING_RUNNER_REGISTRATION_TOKEN=wlreg_... ``` -------------------------------- ### Deploy wuling binaries to non-NixOS host with systemd Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Builds the wuling-api and wuling-migrate binaries with Nix, copies them to a remote host, and installs the provided systemd unit. The unit reads /etc/wuling/wuling.env, so copy env.example there and fill it in. ```bash # 用 Nix 构出二进制(任意有 nix 的机器) nix build .#wuling-api nix build .#wuling-migrate # 拷过去 scp result-*/bin/wuling-* user@host:/usr/local/bin/ # 用我们的 systemd unit sudo cp deploy/production/systemd/wuling-api.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now wuling-api ``` -------------------------------- ### First startup with docker-compose.prod.yml Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md First startup sequence for Docker Compose: create persistent volumes, start services, run database migration, and verify health. Requires ports 80/443 reachable for Caddy to obtain Let's Encrypt certificates via HTTP-01. ```bash # 1. 建两个持久卷(compose 会自动创建,但显式创建可以指定挂载点) docker volume create wuling-pg docker volume create wuling-repos docker volume create wuling-caddy-data # 2. 启动 docker compose -f docker-compose.prod.yml up -d # 3. 初始化数据库 docker compose -f docker-compose.prod.yml exec api wuling-migrate # 4. 测一下 curl -sf https://${WULING_DOMAIN:-localhost}/healthz ``` -------------------------------- ### Start Artifact Service locally Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/artifacts.md Command to run the wuling-artifacts service locally with specific environment variables for token, provider, and storage directory. ```bash WULING_ARTIFACTS_INTERNAL_TOKEN=dev-token \ WULING_ARTIFACTS_STORAGE_PROVIDER=local \ WULING_ARTIFACTS_LOCAL_DIR=./var/artifacts \ go run ./cmd/wuling-artifacts ``` -------------------------------- ### Deploy Kubernetes manifests with kubectl apply -k Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Deploy the Kubernetes manifests in the k8s/ directory. First copy the secret example and replace jwt-secret and pg-password with strong random values, then update the ingress domain, apply with kubectl apply -k, and run the migration command. ```bash # 1. 改 secret cp k8s/secret.example.yaml k8s/secret.yaml # 把 jwt-secret / pg-password 改成强随机值 # 2. 改 ingress 里的域名 # 3. 起 kubectl apply -k deploy/production/k8s/ # 4. 跑 migrate kubectl -n wuling exec deploy/wuling-api -- wuling-migrate ``` -------------------------------- ### Matrix build with `strategy.matrix` for Node.js versions Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/pipelines/quick-start.md Use `strategy.matrix` to run tests in parallel across multiple Node.js versions and platforms. The example defines a matrix with Node.js 20 and 22, then uses `${{ matrix.node }}` to set the `node-version` for `actions/setup-node@v4`. ```yaml strategy: matrix: node: ["20", "22"] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: ${{ matrix.node }} ``` -------------------------------- ### Reference Wuling flake in NixOS configuration Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Adds the Wuling flake as an input and wires its default NixOS module into a host configuration. The example targets x86_64-linux and includes the local host.nix module. ```nix # flake.nix(系统配置) { inputs.wuling.url = "github:zixiao-labs/Wuling-DevOps"; outputs = { self, nixpkgs, wuling, ... }: { nixosConfigurations.devops-host = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ wuling.nixosModules.default ./host.nix ]; }; }; } ``` -------------------------------- ### PyPI private registry configuration and commands Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/unified-supply-chain-security.md Configure pip to use the Wuling private PyPI index and upload packages with twine. The pip.conf sets the extra-index-url with a token, and the commands upload and install packages. ```ini # pip.conf / environment [global] extra-index-url = https://__token__:${WULING_PYPI_TOKEN}@{host}/registry/pypi/{org}/{project}/simple/ ``` ```bash twine upload --repository-url "{base}/registry/pypi/{org}/{project}/" dist/* pip install --extra-index-url "https://__token__:…@…" ``` -------------------------------- ### PUT /api/v1/orgs/{org}/projects/{project}/repos/{repo}/github-link Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/github-integration.md Binds a GitHub repository to a Wuling project. Requires maintainer identity. The control plane automatically uses the GitHub App JWT to query the repository installation, so no `installation_id` is needed from the user. ```APIDOC ## [PUT] /api/v1/orgs/{org}/projects/{project}/repos/{repo}/github-link ### Description Binds a GitHub repository to a Wuling project. Requires maintainer identity. The control plane automatically uses the GitHub App JWT to query the repository installation, so no `installation_id` is needed from the user. ### Method PUT ### Endpoint /api/v1/orgs/{org}/projects/{project}/repos/{repo}/github-link ### Parameters #### Path Parameters - **org** (string) - Required - Organization name. - **project** (string) - Required - Project name. - **repo** (string) - Required - Repository name. #### Request Body - **owner** (string) - Required - GitHub repository owner. - **name** (string) - Required - GitHub repository name. ### Request Example { "owner": "acme", "name": "app" } ### Response #### Success Response (200) - **status** (string) - Indicates the binding was successful. #### Response Example { "status": "ok" } ### Error Handling - **400** - App not installed or not granted access to the repository. Response includes the public installation URL: `https://github.com/apps/wuling-devops/installations/new`. ``` -------------------------------- ### npm private registry configuration and commands Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/unified-supply-chain-security.md Configure npm to use the Wuling private registry for a given org and project. The .npmrc sets the registry scope and token, while the commands publish and install packages against that registry. ```ini # ~/.npmrc 或项目 .npmrc @{scope}:registry={base}/registry/npm/{org}/{project}/ {base}/registry/npm/{org}/{project}/:_authToken=${WULING_NPM_TOKEN} always-auth=true ``` ```bash npm publish --registry "{base}/registry/npm/{org}/{project}/" npm install @scope/pkg --registry "{base}/registry/npm/{org}/{project}/" ``` -------------------------------- ### GET /v1/blobs/{key} Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/artifacts.md Internal Blob API to retrieve a blob. Requires an internal token. The key must follow the format `projects/{project_id}/packages/{package_id}/{version}` or `pipeline-cache/{org_id}/{project_id}/{repo_id}/{entry_id}.cache`. The service rejects empty segments, absolute paths, `..`, and the reserved `.metadata` segment. ```APIDOC ## GET /v1/blobs/{key} ### Description Internal Blob API to retrieve a blob. Requires an internal token. The key must follow the format `projects/{project_id}/packages/{package_id}/{version}` or `pipeline-cache/{org_id}/{project_id}/{repo_id}/{entry_id}.cache`. The service rejects empty segments, absolute paths, `..`, and the reserved `.metadata` segment. ### Method GET ### Endpoint /v1/blobs/{key} ### Parameters #### Path Parameters - **key** (string) - Required - The blob key. ### Headers - **Authorization** (string) - Required - Bearer token with the internal token. ### Response #### Success Response (200) - **body** (binary) - The blob content. #### Response Example (binary content) ``` -------------------------------- ### Prepare .env from env.example Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Prepares the production environment by copying env.example to .env and editing required variables. At minimum, change WULING_JWT_SECRET and WULING_DOMAIN. Do not commit the real .env file. ```bash cd deploy/production cp env.example .env # 用编辑器打开 .env,至少改 WULING_JWT_SECRET / WULING_DOMAIN ``` -------------------------------- ### Fully open demo deployment env vars Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md Recommended environment variables for a fully open teaching or demo instance. Approval is disabled and OAuth is optional. Do not use this configuration in production. ```bash WULING_AUTH_REQUIRE_APPROVAL=false # OAuth 可选 ``` -------------------------------- ### PATCH /api/v1/runner/jobs/{id}/steps/{number} Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines.md Reports a step-level status change (start, end, or conclusion). ```APIDOC ## PATCH /api/v1/runner/jobs/{id}/steps/{number} ### Description Reports a step-level status change (start, end, or conclusion). ### Method PATCH ### Endpoint /api/v1/runner/jobs/{id}/steps/{number} ### Parameters #### Path Parameters - **id** (string) - Required - The job ID. - **number** (integer) - Required - The step number. #### Request Body - **status** (string) - Required - The new step status (e.g., "started", "completed", "failed"). ### Request Example { "status": "completed" } ### Response #### Success Response (200) - **status** (string) - "ok" #### Response Example { "status": "ok" } ### Notes - Authentication: Bearer token with the runner token. ``` -------------------------------- ### GET /healthz Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/artifacts.md Health check endpoint for the artifact service. It verifies that the service is running and that the configured storage bucket is accessible. ```APIDOC ## GET /healthz ### Description Health check endpoint for the artifact service. It verifies that the service is running and that the configured storage bucket is accessible. ### Method GET ### Endpoint /healthz ### Response #### Success Response (200) - **status** (string) - Service health status. #### Response Example { "status": "ok" } ``` -------------------------------- ### Configure rust-toolchain.toml Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/pipelines/rust-xtask.md 定义 Rust 工具链版本、配置项及组件,供 actions/setup-rust 读取。 ```toml # rust-toolchain.toml [toolchain] channel = "1.85.0" profile = "minimal" components = ["clippy", "rustfmt"] ``` -------------------------------- ### 本地开发预览命令 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/help-center.md 在 frontend 目录下运行开发服务器,修改内容后支持热重载。 ```bash cd frontend npm run dev # 打开 http://localhost:3000/help ``` -------------------------------- ### Use built-in actions with `actions/setup-node@v4` and `actions/cache@v4` Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/pipelines/quick-start.md Use built-in GitHub Actions-style actions by referencing the full action name and version. `actions/setup-node@v4` accepts `cache` values `npm`, `pnpm`, or `yarn`; `actions/setup-rust` does not enable Rust caching despite its `cache` input. For sharing directories across elastic or isolated runners, use `actions/cache@v4`, which writes to the remote Artifact Service via the Wuling API. ```yaml steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "22" cache: npm - run: npm ci && npm test ``` -------------------------------- ### Build Nix flake outputs for wuling-api, wuling-migrate, and wuling-frontend Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Builds the three flake outputs from the repository root: the wuling-api binary, the wuling-migrate tool, and the wuling-frontend static folder. The comments show the expected result paths. ```bash nix build .#wuling-api # → result/bin/wuling-api nix build .#wuling-migrate # → result/bin/wuling-migrate nix build .#wuling-frontend # → result/ (静态文件夹) ``` -------------------------------- ### Enable wuling service and PostgreSQL in host.nix Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Enables the wuling service in host.nix with domain, HTTP/SSH addresses, a Unix-socket Postgres URL, and a JWT secret file path. Also enables PostgreSQL with a wuling database and user, and opens firewall ports 80, 443, and 2222. ```nix { ... }: { services.wuling = { enable = true; domain = "devops.example.com"; httpAddr = ":8080"; sshAddr = ":2222"; # Postgres 推荐用同机的 services.postgresql 起,连串走 Unix socket databaseUrl = "postgres:///wuling?host=/run/postgresql"; # 强烈建议把 JWT secret 用 sops/agenix 注入;这里只是示意 jwtSecretFile = "/run/secrets/wuling-jwt"; # 仓库与 SSH host key 的持久路径 repoRoot = "/var/lib/wuling/repos"; sshHostKeyFile = "/var/lib/wuling/ssh/host_ed25519"; frontend.enable = true; # 用 nginx 静态托管 dist/ reverseProxy = "caddy"; # 'caddy' | 'nginx' | 'none' }; services.postgresql = { enable = true; ensureDatabases = [ "wuling" ]; ensureUsers = [ { name = "wuling"; ensureDBOwnership = true; } ]; }; # 防火墙 networking.firewall.allowedTCPPorts = [ 80 443 2222 ]; } ``` -------------------------------- ### 配置 xtask alias 的 .cargo/config.toml Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines-rust-xtask.md 在 workspace 的 .cargo/config.toml 中定义 xtask alias,使 `cargo xtask ci` 可执行。推荐将自动化命令放入 xtask crate,并确保命令不依赖未声明的本机路径、交互式提示或长效凭据。 ```toml # .cargo/config.toml [alias] xtask = "run --package xtask --" ``` -------------------------------- ### 注册自托管 Runner 命令 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/runners.md 在目标机器上执行此命令以注册 Runner。需要替换 为实际令牌,并可根据需要调整 --name 和 --labels。 ```bash wuling-runner \ --server-url https://your-host \ --registration-token \ --name my-runner \ --labels linux,docker ``` -------------------------------- ### Create `.wuling/workflows/ci.yml` with a basic CI workflow Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/pipelines/quick-start.md Create this file at `.wuling/workflows/ci.yml` to define a CI workflow that triggers on pushes to `main` and pull requests. Replace `` with the actual origin of your Wuling DevOps site before committing and pushing. ```yaml # yaml-language-server: $schema=https:///.well-known/wuling/schemas/v1/workflow.json name: CI on: push: branches: [main] pull_request: jobs: build: runs-on: [linux] steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: "22" cache: npm - name: Test run: npm ci && npm test ``` -------------------------------- ### 克隆仓库并推送新分支 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/git.md 克隆 SSH 仓库,创建新分支并推送,用于后续创建合并请求。 ```bash git clone git@your-host:my-org/my-project/my-repo.git cd my-repo git checkout -b feature/my-change git push -u origin feature/my-change ``` -------------------------------- ### 使用 actions/cache 配置远端 CI 缓存 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/pipelines/remote-cache.md 在 CI 工作流中使用内置 actions/cache 缓存构建目录,使 static、ephemeral 和 isolated Runner 能命中同一仓库缓存。path 必须是 workspace 相对路径,key 支持 runner.os 和 hashFiles,restore-keys 按声明顺序前缀匹配。完全命中 key 时不重复上传,未命中或只命中 restore-key 时在 job 成功后发布 primary key。 ```yaml steps: - uses: actions/checkout@v4 - uses: actions/cache@v4 with: path: | target .ci-cache key: rust-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-${{ hashFiles('rust-toolchain.toml') }} restore-keys: | rust-${{ runner.os }}- - run: cargo test --locked ``` -------------------------------- ### 工作流语法示例(.wuling/workflows/*.yml) Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines.md GitHub Actions 风格的工作流文件示例,展示 `on` 触发条件、`jobs` 定义、`runs-on` 标签、`resource` 档位、`container` 镜像、`env`、`steps` 中的 `uses` 与 `run`,以及 `needs` 依赖。`resource` 是武陵扩展,默认 `medium`;`runs-on` 标签必须全部满足;机密以进程环境变量注入。 ```yaml name: CI on: push: branches: [main, "release/*"] pull_request: workflow_dispatch: # 允许手动触发 jobs: build: runs-on: [linux, docker] # 标签;runner 必须满足全部标签 resource: medium # 武陵扩展:low | medium | high(默认 medium) container: node:20 # step 在此镜像内执行;缺省用 runner 默认镜像 env: CI: "true" steps: - name: Checkout uses: actions/checkout@v4 # 内置 checkout + setup-node/setup-rust 等 - name: Install & build run: | npm ci npm run build # 机密以进程环境变量注入,脚本里直接写 $NPM_TOKEN(见 §4) test: needs: [build] # DAG 依赖;build 成功后才跑 runs-on: [linux] resource: low steps: - run: npm test ``` -------------------------------- ### 配置注册审批环境变量 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md 通过环境变量控制注册审批的开启状态及 OAuth 自动批准行为。 ```bash # 默认值 = true。设为 false 完全关闭审批。 WULING_AUTH_REQUIRE_APPROVAL=true # GitHub OAuth 的账号绕过审批(默认 false,所有人都要审)。 WULING_AUTH_OAUTH_AUTO_APPROVE=false ``` -------------------------------- ### Linux 工作流:Rust CI 使用 exclusive 模式 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines-rust-xtask.md Linux 工作流示例,使用 exclusive 模式独占 Runner,适合修改共享工具链状态或 Docker daemon 的构建。actions/setup-rust 会设置 RUSTUP_HOME、CARGO_HOME 和 Cargo bin 目录,toolchain 设为 file 以读取 rust-toolchain.toml。 ```yaml name: Rust CI on: [push, pull_request] jobs: check: runs-on: [linux, docker] resource: medium execution: mode: exclusive container: rust:1.85-bookworm steps: - uses: actions/checkout@v4 - uses: actions/setup-rust@v1 with: toolchain: file - run: cargo xtask ci ``` -------------------------------- ### VS Code settings.json 配置 yaml.schemas Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/pipelines/overview.md 在业务仓库创建 .vscode/settings.json,将工作流路径关联到 schema,并关联 runner-config.yaml。需替换 为实际站点,安装 Red Hat YAML 扩展后重新打开 YAML 文件生效。 ```json { "yaml.schemas": { "https:///.well-known/wuling/schemas/v1/workflow.json": [ ".wuling/workflows/*.yml", ".wuling/workflows/*.yaml" ], "https:///.well-known/wuling/schemas/v1/runner-config.json": "runner-config.yaml" } } ``` -------------------------------- ### 回滚:Docker Compose 与 kubectl Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/RELEASE.md 回滚到上一个版本:Docker Compose 通过设置 WULING_TAG 环境变量,k8s 通过 kubectl set image 更新镜像 tag。 ```bash WULING_TAG=v0.1.9 docker compose -f deploy/docker-compose.prod.yml up -d ``` ```bash kubectl -n wuling set image deploy/wuling-api api=ghcr.io/zixiao-labs/wuling-api:v0.1.9 ``` -------------------------------- ### 切一个 release:git tag 驱动发布 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/RELEASE.md 切一个 release 的完整命令序列:确保 main 分支最新且 CI 全绿,选择 semver 版本号,打 annotated tag 并推送。推送后触发 release.yml 工作流。 ```bash git checkout main git pull --ff-only # 1. 选 version 号 — semver # v0.2.0 — Stage 1 GA / 显著功能 # v0.2.1 — bug fix # v0.3.0-rc.1 — pre-release(CI 也会处理,但 GitHub 上会标 "Pre-release") TAG=v0.2.0 # 2. 打 annotated tag git tag -a "$TAG" -m "Wuling DevOps $TAG" # 3. 推 git push origin "$TAG" ``` -------------------------------- ### Upgrade with docker compose pull and migrate Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Upgrade procedure: pull new images, run wuling-migrate before every upgrade, then restart services. Always run the migration step before upgrading. ```bash # 拉新镜像 docker compose -f docker-compose.prod.yml pull # 跑 migrate(每次升级前都跑一次) docker compose -f docker-compose.prod.yml run --rm api wuling-migrate # 重启 docker compose -f docker-compose.prod.yml up -d ``` -------------------------------- ### Windows 工作流:Rust Windows CI 使用 isolated 模式 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines-rust-xtask.md Windows 工作流示例,使用 isolated 模式为每个任务创建临时 Runner VM,必须显式指定 pool。该模式增加启动时间和费用,适合需要强边界或不可信构建的场景。注意 Windows 宿主执行 MSVC target,且不依赖上一台 VM 的磁盘。 ```yaml name: Rust Windows CI on: workflow_dispatch: jobs: test: runs-on: [windows] resource: medium execution: mode: isolated pool: aws-windows steps: - uses: actions/checkout@v4 - uses: actions/setup-rust@v1 with: toolchain: file - name: Test run: | cargo xtask ci ``` -------------------------------- ### Linux 验证内网连通性 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/pipelines/light-server-networking.md 在 Linux Runner 镜像中验证 DNS 解析、HTTPS 健康检查和端口连通性。使用 getent hosts、curl --fail 和 nc -vz 检查 wuling.internal.example。 ```bash getent hosts wuling.internal.example curl --fail https://wuling.internal.example/healthz nc -vz wuling.internal.example 443 ``` -------------------------------- ### Docker/OCI registry login and image commands Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/unified-supply-chain-security.md Log in to the Wuling Docker registry and tag, push, and pull OCI images. Uses the WULING_REGISTRY_TOKEN for authentication. ```bash echo "$WULING_REGISTRY_TOKEN" | docker login "{host}" -u "{username}" --password-stdin docker tag local:img "{host}/oci/{org}/{project}/{name}:{tag}" docker push "{host}/oci/{org}/{project}/{name}:{tag}" docker pull "{host}/oci/{org}/{project}/{name}:{tag}" ``` -------------------------------- ### Backup and restore Postgres with backup.sh and restore.sh Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md Backup and restore the Postgres database. The backup script is intended to run daily at 02:30 and outputs a gzipped SQL file to /var/backups/wuling/. The restore script takes the backup file path as an argument for disaster recovery. ```bash # 每天凌晨 02:30 跑 deploy/production/postgres/backup.sh # 输出 /var/backups/wuling/wuling-YYYYMMDD-HHMM.sql.gz # 灾难恢复 deploy/production/postgres/restore.sh /var/backups/wuling/wuling-20260513-0230.sql.gz ``` -------------------------------- ### 调用仓库绑定 API Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/github-check-monitoring.md 以组织 maintainer 身份通过 API 将 GitHub 仓库绑定到武陵项目。控制面会自动获取 installation_id,无需手动查找。 ```http PUT /api/v1/orgs/{org}/projects/{project}/repos/{repo}/github-link Content-Type: application/json Authorization: Bearer { "owner": "acme", "name": "app" } ``` -------------------------------- ### Deploy on Linux or macOS Source: https://github.com/zixiao-labs/wuling-devops/blob/main/README.md Executes the production deployment script for Linux and macOS environments using curl. ```bash curl https://raw.githubusercontent.com/zixiao-labs/Wuling-DevOps/refs/heads/main/prod-deploy.sh | bash ``` -------------------------------- ### Deploy on Windows Server Source: https://github.com/zixiao-labs/wuling-devops/blob/main/README.md Executes the production deployment script for Windows Server environments using PowerShell. ```powershell irm https://raw.githubusercontent.com/zixiao-labs/Wuling-DevOps/refs/heads/main/prod-deploy.ps1 | iex ``` -------------------------------- ### 使用环境变量启动 Runner Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/runners.md 当已有持久 Runner token 时,可通过环境变量启动 Runner,无需注册命令。 ```bash WULING_RUNNER_SERVER_URL=https://your-host \ WULING_RUNNER_TOKEN= \ wuling-runner ``` -------------------------------- ### Internal small team deployment env vars Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md Recommended environment variables for an internal team of up to 20 people. With OAuth left empty, only local password registration is available; approval is required because registration volume is low. ```bash WULING_AUTH_REQUIRE_APPROVAL=true WULING_AUTH_OAUTH_AUTO_APPROVE=false # OAuth 留空 → 仅本地密码注册 ``` -------------------------------- ### 校验产物:sha256sum 与 docker inspect Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/RELEASE.md 校验发布产物:下载二进制和 SHA256 校验文件并用 sha256sum 验证;拉取镜像并用 docker image inspect 检查 digest。 ```bash curl -LO https://github.com/zixiao-labs/Wuling-DevOps/releases/download/v0.2.0/wuling-api-linux-amd64.tar.gz curl -LO https://github.com/zixiao-labs/Wuling-DevOps/releases/download/v0.2.0/wuling-api-linux-amd64.tar.gz.sha256 sha256sum -c wuling-api-linux-amd64.tar.gz.sha256 ``` ```bash docker pull ghcr.io/zixiao-labs/wuling-api:v0.2.0 docker image inspect --format '{{.Id}}' ghcr.io/zixiao-labs/wuling-api:v0.2.0 ``` -------------------------------- ### Configure GitHub OAuth environment variables in deploy/production/.env Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md Minimal environment variable configuration for GitHub OAuth in deploy/production/.env. The redirect URL must exactly match the callback URL configured in the GitHub OAuth App; do not add trailing slashes, query strings, or fragments. The client secret is shown only once at creation and must be stored securely. ```bash WULING_OAUTH_GITHUB_CLIENT_ID=Ov23liXXXXXXXXXXXXXX # Paste the OAuth App client secret from GitHub here — NOT a Personal Access # Token (PATs start with `ghp_` / `github_pat_` and won't work for OAuth). WULING_OAUTH_GITHUB_CLIENT_SECRET= WULING_OAUTH_GITHUB_REDIRECT_URL=https://devops.example.com/api/v1/auth/oauth/github/callback # WULING_OAUTH_FRONTEND_BASE_URL=https://devops.example.com # 同域部署可省略 ``` -------------------------------- ### 构建与预渲染命令 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/help-center.md 执行构建及预渲染操作,用于生成生产环境所需的静态文件并校验 Service Worker 配置。 ```bash npm run build # dist/ + dist-help/ npm run help:smoke # 预渲染到 dist/help/ 并校验 sw.js 绕过 /help ``` -------------------------------- ### 架构图:端口与组件关系 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/deploy/production/README.md 展示生产环境的架构,包括 TLS 反向代理、API 服务、Postgres 和持久卷,以及端口映射。 ```text ┌─────────────────────────────┐ │ 浏览器 / git client / SSH │ └──────────────┬──────────────┘ │ ┌────────────────┴───────────────┐ │ TLS 反向代理 (Caddy / Nginx) │ :80 → 重定向到 :443 │ ─ HTTPS / HTTP-01 自动证书 │ :443 → 内部 :8080 │ ─ 透传 *.git/ 给 API │ └────────────────┬───────────────┘ │ 8080 (HTTP) ┌────────────────┴───────────────┐ │ wuling-api(cgo + libgit2) │ │ ─ /api/v1/* │ │ ─ /{org}/{project}/{repo}.git/ │ │ ─ embedded Git SSH 2222 (TCP) │ ←─── 外网直接暴露 2222 └────────┬─────────────┬──────────┘ │ │ ┌────────┴────┐ ┌─────┴────────────┐ │ Postgres 18 │ │ /var/lib/wuling/ │ │ (持久卷) │ │ repos (持久卷) │ └─────────────┘ └──────────────────┘ static frontend (Nasti build → dist/) — Caddy 直接吐 / nginx 静态托管 help (/help/*) — 预渲染静态页(dist/help/**);/help/search 可选走 Node SSR ``` -------------------------------- ### 审批管理 API 操作 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md 使用管理员 JWT 通过 API 列出待审核用户、批准用户或提升用户权限。 ```bash # 列出待审核 curl -H "Authorization: Bearer $ADMIN_JWT" \ "https://devops.example.com/api/v1/admin/users?status=pending" # 批准用户 X curl -X PATCH -H "Authorization: Bearer $ADMIN_JWT" \ -H "Content-Type: application/json" \ -d '{"approval_status":"approved"}' \ "https://devops.example.com/api/v1/admin/users/$USER_ID" # 提升为 admin curl -X PATCH -H "Authorization: Bearer $ADMIN_JWT" \ -H "Content-Type: application/json" \ -d '{"is_admin":true}' \ "https://devops.example.com/api/v1/admin/users/$USER_ID" ``` -------------------------------- ### Register and run wuling-runner with registration token Source: https://github.com/zixiao-labs/wuling-devops/blob/main/runners/runner-clients/README.md Registers and runs the runner with a one-time registration token. The token is minted by an org maintainer in the UI or injected by the autoscaler via cloud-init. The --concurrency flag runs N jobs in parallel. ```sh wuling-runner \ --server-url https://wuling.example.com \ --registration-token wlreg_xxx \ --labels linux,docker \ --concurrency 2 ``` -------------------------------- ### Build wuling-runner with cargo build --release Source: https://github.com/zixiao-labs/wuling-devops/blob/main/runners/runner-clients/README.md Builds the wuling-runner binary in release mode. The resulting binary is located at target/release/wuling-runner. ```sh cargo build --release # binary: target/release/wuling-runner ``` -------------------------------- ### Markdown Front matter 配置 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/help-center.md 每个帮助文档文件必须以 YAML front matter 开头,用于定义页面标题、侧边栏分组及排序。 ```markdown --- title: 页面标题 group: 分组名 order: 10 description: 用于 SEO 与搜索摘要的简短描述。 --- 正文… ``` -------------------------------- ### 固定 Rust 工具链的 rust-toolchain.toml Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines-rust-xtask.md 在仓库根目录创建此文件,指定 channel、profile、components 和 targets。建议固定 release 版本(如 1.85.0)以保证构建可重复,避免仅使用 stable 导致未来工具链变更影响历史构建。 ```toml [toolchain] channel = "1.85.0" profile = "minimal" components = ["clippy", "rustfmt"] targets = ["x86_64-unknown-linux-gnu"] ``` -------------------------------- ### PUT /v1/blobs/{key} Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/artifacts.md Internal Blob API to store an immutable blob. Requires an internal token. The key must follow the format `projects/{project_id}/packages/{package_id}/{version}` or `pipeline-cache/{org_id}/{project_id}/{repo_id}/{entry_id}.cache`. The service rejects empty segments, absolute paths, `..`, and the reserved `.metadata` segment. ```APIDOC ## PUT /v1/blobs/{key} ### Description Internal Blob API to store an immutable blob. Requires an internal token. The key must follow the format `projects/{project_id}/packages/{package_id}/{version}` or `pipeline-cache/{org_id}/{project_id}/{repo_id}/{entry_id}.cache`. The service rejects empty segments, absolute paths, `..`, and the reserved `.metadata` segment. ### Method PUT ### Endpoint /v1/blobs/{key} ### Parameters #### Path Parameters - **key** (string) - Required - The blob key. ### Headers - **Authorization** (string) - Required - Bearer token with the internal token. ### Response #### Success Response (200) - **status** (string) - Success status. #### Response Example { "status": "ok" } ``` -------------------------------- ### HEAD /v1/blobs/{key} Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/artifacts.md Internal Blob API to check the existence of a blob. Requires an internal token. The key must follow the format `projects/{project_id}/packages/{package_id}/{version}` or `pipeline-cache/{org_id}/{project_id}/{repo_id}/{entry_id}.cache`. The service rejects empty segments, absolute paths, `..`, and the reserved `.metadata` segment. ```APIDOC ## HEAD /v1/blobs/{key} ### Description Internal Blob API to check the existence of a blob. Requires an internal token. The key must follow the format `projects/{project_id}/packages/{package_id}/{version}` or `pipeline-cache/{org_id}/{project_id}/{repo_id}/{entry_id}.cache`. The service rejects empty segments, absolute paths, `..`, and the reserved `.metadata` segment. ### Method HEAD ### Endpoint /v1/blobs/{key} ### Parameters #### Path Parameters - **key** (string) - Required - The blob key. ### Headers - **Authorization** (string) - Required - Bearer token with the internal token. ### Response #### Success Response (200) - **status** (string) - Existence status. #### Response Example { "status": "exists" } ``` -------------------------------- ### runner-config.yaml 的 YAML Language Server modeline Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/runners.md 在 runner-config.yaml 首行添加此 modeline,可在任意 config 仓库中获得 schema 补全和结构检查。将 替换为实际站点 origin。 ```yaml # yaml-language-server: $schema=https:///.well-known/wuling/schemas/v1/runner-config.json ``` -------------------------------- ### 数据库审批相关字段迁移 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md 用于在 users 表中添加审批状态、备注、批准时间和批准人字段的 SQL 语句。 ```sql ALTER TABLE users ADD COLUMN approval_status TEXT NOT NULL DEFAULT 'pending' CHECK (approval_status IN ('pending', 'approved', 'rejected')); ALTER TABLE users ADD COLUMN approval_note TEXT NOT NULL DEFAULT ''; ALTER TABLE users ADD COLUMN approved_at TIMESTAMPTZ; ALTER TABLE users ADD COLUMN approved_by UUID REFERENCES users(id) ON DELETE SET NULL; ``` -------------------------------- ### 组件信任与数据流 Mermaid 图 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/unified-supply-chain-security.md Mermaid 流程图展示组件间数据流与信任关系:编辑器验证签名与 CRL,CI 请求签名,API 管理元数据与 blob 加密,客户端通过原生协议访问制品,签名私钥加密存储于 KMS,OrgAdmin 管理 DEK 策略与云凭证,平台管理负责证书生命周期。 ```mermaid flowchart LR Editor[Kaltsit_Editor] -->|verify_sig_CRL| TrustBundle[Trust_Roots_Bundle] CI[Pipeline_Runner] -->|sign_request| CodeSign[wuling_codesign] API[wuling_api] -->|metadata_RBAC| API API -->|blob_enc| Artifacts[wuling_artifacts] Clients[npm_pip_cargo_docker] -->|native_protocols| Artifacts CodeSign -->|encrypted_privkeys| KMS[Platform_Key_Vault] OrgAdmin[OrgAdmin_plus_2FA] -->|DEK_policy| Artifacts OrgAdmin -->|Cloud_AKSK| CredVault[Cloud_Credentials_Vault] PlatMgmt[Platform_Management_plus_2FA] -->|cert_lifecycle| CodeSign ``` -------------------------------- ### Run wuling-runner with persistent token via environment variables Source: https://github.com/zixiao-labs/wuling-devops/blob/main/runners/runner-clients/README.md Runs the runner with an existing persistent runner token (wlrt_…). All flags have WULING_RUNNER_* environment equivalents. ```sh WULING_RUNNER_SERVER_URL=https://wuling.example.com \ WULING_RUNNER_TOKEN=wlrt_xxx \ wuling-runner ``` -------------------------------- ### Company with GitHub SSO deployment env vars Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md Recommended environment variables for a company with GitHub single sign-on. Password registrations still require approval to prevent public scraping, while GitHub-authenticated users are auto-approved. Optionally, a reverse proxy can IP-allowlist /api/v1/auth/register to disable password registration entirely. ```bash WULING_AUTH_REQUIRE_APPROVAL=true WULING_AUTH_OAUTH_AUTO_APPROVE=true # 已经被 GitHub 验证过了 WULING_OAUTH_GITHUB_CLIENT_ID=... WULING_OAUTH_GITHUB_CLIENT_SECRET=... WULING_OAUTH_GITHUB_REDIRECT_URL=https://devops.example.com/api/v1/auth/oauth/github/callback ``` -------------------------------- ### Cargo private registry configuration and commands Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/unified-supply-chain-security.md Configure Cargo to use the Wuling private registry and publish or add crates with it. The config.toml defines the sparse index URL, and the commands use the wuling registry. ```toml # .cargo/config.toml [registries.wuling] index = "sparse+{base}/registry/cargo/{org}/{project}/" ``` ```bash cargo publish --registry wuling cargo add --registry wuling ``` -------------------------------- ### POST /api/v1/orgs/{org}/projects/{project}/packages/{package_id}/uploads Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/artifacts.md User-facing upload endpoint for artifacts. The version is passed as a required query parameter. The request body must be `multipart/form-data` with a single `file` field. The main API streams the file to the artifact service without buffering the entire file in memory or on disk. Requires project `developer` or higher role. ```APIDOC ## POST /api/v1/orgs/{org}/projects/{project}/packages/{package_id}/uploads ### Description User-facing upload endpoint for artifacts. The version is passed as a required query parameter. The request body must be `multipart/form-data` with a single `file` field. The main API streams the file to the artifact service without buffering the entire file in memory or on disk. Requires project `developer` or higher role. ### Method POST ### Endpoint /api/v1/orgs/{org}/projects/{project}/packages/{package_id}/uploads ### Parameters #### Path Parameters - **org** (string) - Required - Organization identifier. - **project** (string) - Required - Project identifier. - **package_id** (string) - Required - Package identifier. #### Query Parameters - **version** (string) - Required - Version of the artifact. #### Request Body - **file** (file) - Required - The file to upload. ### Request Example (multipart/form-data with file field) ### Response #### Success Response (200) - **size** (integer) - File size in bytes. - **sha256** (string) - SHA-256 hash of the file. - **content_type** (string) - Content type of the file. - **original_filename** (string) - Original filename. #### Response Example { "size": 12345, "sha256": "...", "content_type": "application/octet-stream", "original_filename": "artifact.zip" } ``` -------------------------------- ### SQL 手动提升管理员 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/auth.md 在审批开启的情况下,通过 SQL 手动将第一个注册用户提升为管理员并标记为已批准。 ```sql UPDATE users SET is_admin = TRUE, approval_status = 'approved', approved_at = now() WHERE username = 'YOUR_USERNAME'; ``` -------------------------------- ### Workflow 缓存配置示例 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines-cache.md 在 workflow 中使用 actions/cache 插件配置缓存路径、主键和恢复键。path 支持多行路径,key 和 restore-keys 用于匹配缓存版本。 ```yaml jobs: test: runs-on: [linux] steps: - uses: actions/checkout@v4 - uses: actions/cache@v4 with: path: | target .ci-cache key: rust-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}-${{ hashFiles('rust-toolchain.toml') }} restore-keys: | rust-${{ runner.os }}- rust- - run: cargo test --locked ``` -------------------------------- ### Verify private connectivity from Windows with Resolve-DnsName, Test-NetConnection, and Invoke-WebRequest Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/pipelines-light-server-networking.md Windows equivalent of the Linux connectivity checks. Confirms DNS resolution, TCP reachability on port 443, and HTTPS access to the /healthz endpoint. ```powershell Resolve-DnsName wuling.internal.example Test-NetConnection wuling.internal.example -Port 443 Invoke-WebRequest https://wuling.internal.example/healthz -UseBasicParsing ``` -------------------------------- ### 紧急 hotfix:从 tag 创建分支并推送 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/docs/RELEASE.md 紧急 hotfix 流程:从上一个 release tag 创建 hotfix 分支,修改代码后打 tag 并推送,之后 cherry-pick 回 main。 ```bash git checkout v0.2.0 git checkout -b hotfix/v0.2.1 # 改代码、做提交… git tag -a v0.2.1 -m "hotfix: …" git push origin hotfix/v0.2.1 v0.2.1 # 之后 cherry-pick 回 main ``` -------------------------------- ### 生成 SSH 密钥并查看公钥 Source: https://github.com/zixiao-labs/wuling-devops/blob/main/frontend/src/help/content/git.md 生成 ed25519 密钥并输出公钥内容,用于粘贴到用户设置中的 SSH 密钥页面。 ```bash ssh-keygen -t ed25519 -C "you@example.com" cat ~/.ssh/id_ed25519.pub ```