Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d0b6953
docs: clarify released installation and upgrade paths
DavidHLP Oct 27, 2026
f62cba8
ci: require isolated business acceptance and verified release packaging
DavidHLP Oct 27, 2026
baba7e7
fix(ci): align startup contracts with safe install entry points
DavidHLP Oct 27, 2026
2b1a97d
fix(ci): seed fresh acceptance through canonical startup
DavidHLP Oct 27, 2026
5fa8f21
test(acceptance): prepare persisted hidden judge fixtures
DavidHLP Oct 27, 2026
adc1f9e
fix(release): require canonical CI and existing promoted tags
DavidHLP Oct 27, 2026
e0738cf
fix(release): format digest readback across buildx versions
DavidHLP Oct 27, 2026
06f6696
test(acceptance): capture redacted authentication failure codes
DavidHLP Oct 27, 2026
9efd63c
test(acceptance): verify protected sessions and bounded auth replay
DavidHLP Oct 27, 2026
b7ab732
fix(auth): refresh CSRF header before authenticated replay
DavidHLP Oct 27, 2026
7db26ba
fix(acceptance): type replay headers and bound PM2 sockets
DavidHLP Oct 27, 2026
06afe9f
docs: record mutation replay and acceptance fixes
DavidHLP Oct 27, 2026
73f2352
test(acceptance): refresh fixture session after permission changes
DavidHLP Oct 27, 2026
e9f532d
test(acceptance): diagnose owner failures without publishing secrets
DavidHLP Oct 27, 2026
61d90b7
test(acceptance): classify redacted RPC failures and construct fixtur…
DavidHLP Oct 27, 2026
8169584
fix: gate owner readiness on RPC discovery and preserve server errors
DavidHLP Oct 27, 2026
effb087
test: bind supply-chain contract to reserved owner versions
DavidHLP Oct 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/_acceptance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Real acceptance
on:
workflow_call: {}
permissions:
contents: read
jobs:
migration-safety:
name: Fresh and upgrade migration safety
runs-on: ubuntu-latest
timeout-minutes: 35
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: jdx/mise-action@fc42bcc7ddbf51124c30f95a877a0c5168a3bfde # v5.2.1
- uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0
with:
distribution: temurin
java-version: '17'
cache: maven
- name: Real MySQL fresh/upgrade/backfill/backup/FK and isolation drill
run: bash scripts/dev/owner-migration-safety-integration-test.sh
business:
name: Clean install and real business lifecycle
needs: migration-safety
runs-on: ubuntu-latest
timeout-minutes: 60
env:
ACCEPTANCE_DISPOSABLE: 'true'
MISE_HTTP_TIMEOUT: 5m
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: ./.github/actions/setup-frontend
- uses: jdx/mise-action@fc42bcc7ddbf51124c30f95a877a0c5168a3bfde # v5.2.1
- uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0
with:
distribution: temurin
java-version: '17'
cache: maven
- name: Prepare pinned local test tools
run: |
npm install --global pm2@6.0.8
mise install java@zulu-17.68.203.0
pnpm exec playwright install --with-deps chromium
- name: Fresh isolated install and real browser/Judge acceptance
run: bash scripts/ci/business-acceptance.sh
- name: Preserve reports without credentials or raw service logs
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
with:
name: real-business-acceptance
path: |
.local/acceptance/installation.json
.local/browser-acceptance/report.json
.local/browser-business-acceptance/report.json
if-no-files-found: warn
retention-days: 14
11 changes: 9 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
contract: ${{ steps.select.outputs.contract }}
docker: ${{ steps.select.outputs.docker }}
agent: ${{ steps.select.outputs.agent }}
acceptance: ${{ steps.select.outputs.acceptance }}
release: ${{ steps.select.outputs.release }}
full: ${{ steps.select.outputs.full }}
steps:
Expand Down Expand Up @@ -119,9 +120,15 @@ jobs:
if: ${{ !cancelled() && needs.changes.outputs.agent == 'true' }}
uses: ./.github/workflows/_agent.yml

acceptance:
name: Real acceptance
needs: changes
if: ${{ !cancelled() && needs.changes.outputs.acceptance == 'true' }}
uses: ./.github/workflows/_acceptance.yml

ci-ok:
name: ci-ok
needs: [changes, governance, security, backend, frontend, contract, docker, agent]
needs: [changes, governance, security, backend, frontend, contract, docker, agent, acceptance]
if: ${{ always() }}
runs-on: ubuntu-latest
timeout-minutes: 5
Expand All @@ -135,7 +142,7 @@ jobs:
- name: Verify every selected gate succeeded
env:
RESULTS: ${{ toJSON(needs) }}
SELECTED: '{"backend":"${{ needs.changes.outputs.backend }}","console":"${{ needs.changes.outputs.console }}","management":"${{ needs.changes.outputs.management }}","landing":"${{ needs.changes.outputs.landing }}","contract":"${{ needs.changes.outputs.contract }}","docker":"${{ needs.changes.outputs.docker }}","agent":"${{ needs.changes.outputs.agent }}"}'
SELECTED: '{"backend":"${{ needs.changes.outputs.backend }}","console":"${{ needs.changes.outputs.console }}","management":"${{ needs.changes.outputs.management }}","landing":"${{ needs.changes.outputs.landing }}","contract":"${{ needs.changes.outputs.contract }}","docker":"${{ needs.changes.outputs.docker }}","agent":"${{ needs.changes.outputs.agent }}","acceptance":"${{ needs.changes.outputs.acceptance }}"}'
run: python3 scripts/ci/check-results.py

publish:
Expand Down
29 changes: 22 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,24 @@

## Unreleased

This is release-candidate preparation, not an official stable release or a
production-readiness declaration.
No next release has been published from this development branch.

- Reserve backend owner versions `1.0.5` for the next complete source-matched image set.
- Gate Admin/Submission readiness on required RPC discovery without retrying writes.
- Preserve server errors on internal App error dispatches while ordinary routes remain authenticated.

- Clarify release-pinned installation versus existing-environment upgrades.
- Add selected real business/migration acceptance to the CI summary gate.
- Reattach the rotated CSRF token when replaying an authenticated mutation after
access-token refresh; preserve the request body and account binding.
- Keep disposable PM2 socket paths short when acceptance runs in nested worktrees.
- Prepare repeatable eight-asset packages only from complete verified image evidence;
external tag/Release publication still requires separate human authorization.

## [1.0.4](https://github.com/DavidHLP/UltiCode/releases/tag/v1.0.4) — 2026-10-27

Published from `465b9fd031f2c398f39f4696d8b33360f635ed5d`. This release is not a
production-readiness certification.

- Normalize Management problem difficulty at the API boundary, with regression tests.
- Restore database-generated problem IDs with an additive owner migration;
Expand All @@ -29,8 +45,7 @@ The Agent remains experimental and disabled by default. Tests using scripted
models do not establish real-model quality, budget readiness or production
acceptance. Local Docker/browser evidence is scoped to disposable local services.

Before an official release, retain the tested source commit, successful CI and
real-service acceptance evidence, full signed nine-service digest manifest,
SBOM/provenance/scan evidence and release notes as durable assets. The source-only
bundle is not deployment input. Production deployment, release publication and
branch-protection changes require separate approval.
The published release retains the exact source, complete nine-service digest
manifest, signed SBOM/provenance/scan evidence and checksums as eight durable
assets. Main CI/publication and independent verification passed. Existing
immutable tags were preserved; no business production deployment was performed.
54 changes: 9 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,58 +50,22 @@ The screenshots below are the design and regression reference screenshots mainta
### 1. Get the project

```bash
git clone https://github.com/DavidHLP/UltiCode.git
git clone --branch v1.0.4 https://github.com/DavidHLP/UltiCode.git
cd UltiCode
```

### 2. Prepare the environment
### 2. Choose the installation path before creating configuration

Prerequisites: Docker Compose v2, mise, Node.js 22.x (22.22.2 or newer on that line for the locked frontend dependencies), pnpm 11.0.0, PM2, plus `curl`, `timeout`, and `openssl`. Frontend CI selects Node 22.x and pins pnpm 11.0.0; the app manifests' `>=22.12.0` minimum alone does not cover every locked dependency. Backend startup runs through the repository's `services/mvnw` and the mise-managed Zulu Java 17. See [development prerequisites](docs/DEVELOPMENT.md#前置条件) for Dev Container toolchain selection and rebuild guidance.
The current release is [v1.0.4 (2026-10-27)](https://github.com/DavidHLP/UltiCode/releases/tag/v1.0.4).
Normal installations should pin a release; contributors can use `main` in a separate checkout.

Contributors can also use Dev Containers / Codespaces directly; creating the container only installs dependencies and then runs the unit gate by default — it does not start the full stack:
- **Deploy published images:** start with [release installation](docs/OPERATIONS.md#从已发布发行版安装). Download all assets, verify checksums and nine-image signature evidence, then prepare host TLS/Judge prerequisites and deployment approval.
- **Fresh local development:** open the [empty-volume installation guide](docs/DEVELOPMENT.md#干净卷首次安装仅本机-disposable-开发环境) while `.env` is still absent. That entry owns configuration generation, migration, backfill/parity, cutover and first startup. Do not run `init-env.sh` before it.
- **Existing configuration, databases or volumes:** preserve them and use the [upgrade and rollback entry](docs/OPERATIONS.md#升级与回滚入口). Never treat them as empty volumes, recreate configuration with `--force`, or only change a cutover marker.

```bash
./ulticode doctor --json
```

```bash
./scripts/dev/init-env.sh
```

### 3. Finish the database preparation

> **Required reading for the first start**
>
> `init-env.sh` generates `SUBMISSION_CUTOVER_COMPLETE` as `false`. Both `dev-lite` and `dev-full` require `APP_SUBMISSION_ROUTING_MODE=remote` and a completed Submission cutover marker; the startup scripts refuse to run when either is missing.
>
> Read [Database migrations](docs/OPERATIONS.md#数据库迁移与-owner-收敛) first, and complete migration and verification according to the authorized cutover/backfill runbook. Do not skip the checks by only changing the marker.

### 4. Start the development environment

Once the preparation above is done, choose a mode:

| Mode | Search | Frontends |
| --- | --- | --- |
| `dev-lite` | Database-backed search; no Search worker | Not started by default |
| `dev-full` | Indexed search with the Search worker | Both frontends started |

```bash
./scripts/dev/up.sh --mode dev-lite
```

`dev-lite` uses database search, does not start the Search worker, and does not start either frontend by default; run the following when you need the browser UI:

```bash
./scripts/dev/up.sh --frontend-only
```

`dev-full` enables indexed search, the Search worker, and both frontends, still behind the same cutover gate:

```bash
./scripts/dev/up.sh --mode dev-full
```
Source development requires Docker Compose v2, mise-managed Zulu Java 17, Node.js 22.x (at least 22.22.2), pnpm 11.0.0, PM2, `curl`, `timeout` and `openssl`. Dev Containers prepare tooling and unit validation; they do not start the business stack. See [local development](docs/DEVELOPMENT.md#本地开发) for exact prerequisites, scopes, readiness and troubleshooting.

Once the frontends are running: [Console](http://localhost:9002) · [Management](http://localhost:9003). See [Local development](docs/DEVELOPMENT.md#本地开发) for scopes, logs, and troubleshooting entry points.
After completing the selected entry, local frontends are [Console](http://localhost:9002) and [Management](http://localhost:9003). Use the supported launcher rather than starting Maven/PM2 directly around its preparation and safety gates.

<details>
<summary>Optional Core pilot and rollback notes</summary>
Expand Down
55 changes: 9 additions & 46 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,59 +50,22 @@ UltiCode 是一个全栈在线编程平台,提供题库、竞赛、在线评
### 1. 获取项目

```bash
git clone https://github.com/DavidHLP/UltiCode.git
git clone --branch v1.0.4 https://github.com/DavidHLP/UltiCode.git
cd UltiCode
```

### 2. 准备环境
### 2. 在生成配置前选择安装路径

前置条件:Docker Compose v2、mise、Node.js 22.x(当前锁定前端依赖要求该系列至少 22.22.2)、pnpm 11.0.0、PM2,以及 `curl`、`timeout`、`openssl`。前端 CI 选择 Node 22.x 并固定 pnpm 11.0.0;应用 manifest 的 `>=22.12.0` 下限不足以覆盖全部锁定依赖。后端启动由仓库内 `services/mvnw` 和 mise 管理的 Zulu Java 17 执行。Dev Container 的工具链选择与重建说明见[开发前置条件](docs/DEVELOPMENT.md#前置条件)。
当前发行版是 [v1.0.4(2026-10-27)](https://github.com/DavidHLP/UltiCode/releases/tag/v1.0.4)。
普通使用者应固定发行版,不直接跟随 `main`;贡献者可在独立 checkout 使用 `main`。

贡献者也可以直接使用 Dev Containers/Codespaces;创建容器只安装依赖,
随后默认执行 unit 验证,不自动启动全栈:
- **下载发行版镜像部署**:从[发行版安装](docs/OPERATIONS.md#从已发布发行版安装)开始,下载全部资产、验证校验和与九镜像签名证据,再准备主机 TLS/Judge 和部署审批。
- **全新本机开发环境**:在 `.env` 尚不存在时进入[干净卷首次安装](docs/DEVELOPMENT.md#干净卷首次安装仅本机-disposable-开发环境)。该入口负责生成配置、迁移、backfill/parity、cutover 与首次启动;不要提前运行 `init-env.sh`。
- **已有配置、数据库或卷**:保留它们,先阅读[升级与回滚](docs/OPERATIONS.md#升级与回滚入口)。不得把已有环境当成空卷,也不要使用 `--force` 重建配置或只修改 cutover marker。

```bash
./ulticode doctor --json
```

```bash
./scripts/dev/init-env.sh
```

### 3. 完成数据库准备

> **首次启动必读**
>
> `init-env.sh` 会把 `SUBMISSION_CUTOVER_COMPLETE` 生成为 `false`。`dev-lite` 和 `dev-full` 都要求 `APP_SUBMISSION_ROUTING_MODE=remote` 与已完成的 Submission cutover marker;未满足时启动脚本会拒绝执行。
>
> 请先阅读[数据库迁移](docs/OPERATIONS.md#数据库迁移与-owner-收敛),按授权的 cutover/backfill runbook 完成迁移与验证。不要仅修改标记来跳过检查。

### 4. 启动开发环境

完成上述准备后,选择适合的模式:

| 模式 | 搜索 | 前端 |
| --- | --- | --- |
| `dev-lite` | 数据库 Search,不启动 Search Worker | 默认不启动 |
| `dev-full` | 索引 Search,启用 Search Worker | 启动两个前端 |

```bash
./scripts/dev/up.sh --mode dev-lite
```

`dev-lite` 使用数据库 Search、不启动 Search worker,默认不启动两个前端;需要浏览器界面可另运行:

```bash
./scripts/dev/up.sh --frontend-only
```

`dev-full` 会启用 indexed Search、Search worker 和两个前端,但仍受同一 cutover gate 保护:

```bash
./scripts/dev/up.sh --mode dev-full
```
本机源码开发需要 Docker Compose v2、mise 管理的 Zulu Java 17、Node.js 22.x(至少 22.22.2)、pnpm 11.0.0、PM2、`curl`、`timeout` 和 `openssl`。Dev Container 只准备工具链和 unit 验证,不自动启动业务栈。精确前置条件、scope、readiness 与排障见[本地开发](docs/DEVELOPMENT.md#本地开发)。

前端启动后访问:[Console 用户端](http://localhost:9002) · [Management 管理端](http://localhost:9003)。更多 scope、日志与排障入口见[本地开发](docs/DEVELOPMENT.md#本地开发)。
完成所选入口后,开发前端为 [Console](http://localhost:9002) 与 [Management](http://localhost:9003)。不要通过直接启动 Maven/PM2 绕过 launcher 的准备和安全门禁。

<details>
<summary>可选 Core 试点与回滚说明</summary>
Expand Down
10 changes: 6 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Security policy

UltiCode is under active development. This repository has no published stable
GitHub Release or production security certification. Reports against the current
`main` branch are welcome; include the exact commit or immutable image digest.
The Agent is experimental and disabled by default.
[v1.0.4](https://github.com/DavidHLP/UltiCode/releases/tag/v1.0.4) was published on
2026-10-27. Security reports for this release and current `main` are welcome;
include the exact commit or immutable image digest. Older releases may require an
upgrade before a fix can be evaluated. Fixes may land on `main` and a later
release; no LTS/backport window, response-time SLA or production security
certification is promised. The Agent remains experimental and disabled by default.

## Private reporting

Expand Down
2 changes: 1 addition & 1 deletion docker/sandbox/harness/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ build_java() {
mkdir -p "${STAGING}/java"
(
cd "${SCRIPT_DIR}/java"
mvn -B -q -DskipTests test-compile
"${MAVEN_BIN:-${SANDBOX_DIR}/../../services/mvnw}" -B -q -DskipTests test-compile
cp -r target/classes/. "${STAGING}/java/"
)
echo "[build.sh] java: $(ls "${STAGING}/java" | wc -l) class files"
Expand Down
32 changes: 32 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,38 @@ RPC 返回失败值前显式标记写事务回滚,避免子项拒绝后留下
Admin description readback 映射 nested detail,不能把读取已存在题目或单独 Judge
验收当成创建/编辑验收。fresh/upgrade ID 与外键保持检查属于真实 MySQL migration drill。

### CI 真实安装与业务门禁

`Real acceptance` 是 `ci-ok` 的必需选择门禁:runtime/frontend/安装工具变化与所有
release-selected/full runs 都必须成功,不能把 skipped/cancelled 当成通过。文档元数据
变化不会误触发镜像发布。工作流先运行现有 MySQL fresh/upgrade/FK、backfill、backup
和权限隔离 drill,然后在独立 runner 顺序运行 `scripts/ci/business-acceptance.sh`。

业务入口只接受没有 `.env`、默认端口空闲、本机 Unix Docker endpoint 的新 checkout,
并要求 `ACCEPTANCE_DISPOSABLE=true`。它创建唯一 Compose project 和独立 PM2 home,
通过现有 launcher 准备 canonical migrations,执行全部 backfill/parity/cutover 检查后
才导出完成标记。每个 JVM 有 heap 上限;不会并行启动多个本机 acceptance stack。
不使用生产 secret、生产数据、mock API 或付费模型。

HTTP 存活不代表 Dubbo 接口已被消费者发现。Admin readiness 额外检查 ProblemAdminReadPort
与 TestCaseOwnerPort 的实际 consumer invoker;缺失时返回 503。Submission 在两分钟的
有界发现期限内检查 ProblemFactsPort 与 SubmissionUserReadPort,成功后才输出 launcher
使用的就绪标记;超时则启动失败。检查只读取发现状态,不调用业务 RPC 或重试写入。
launcher 记录本次启动前日志偏移,旧标记不会被当成本次成功。

测试账号仅由 disposable dev bootstrap 与 Auth registration 创建。Manager 的直接权限
通过真实 Auth API 临时授予并过期,不改全局 role policy;Console participant 保持 USER。
随后执行基础与扩展 browser scripts,覆盖 AC/WA、重判、完整 admin create/edit/readback、
非法子项事务回滚、contest 提交及最终排名。只上传排除凭据的 JSON 报告,不上传 `.env`、
cookies、源码、PM2 state 或原始服务日志。退出时仅停止该测试 project/home,保留本机卷供
诊断;GitHub hosted runner 生命周期负责回收其临时磁盘。

本机重现需在新 checkout 安装锁定依赖、PM2 与 Playwright Chromium,然后运行:

```bash
ACCEPTANCE_DISPOSABLE=true bash scripts/ci/business-acceptance.sh
```

### 已准备环境启动

```bash
Expand Down
Loading
Loading