fix(auth): enable local bootstrap admin by default (#141)

* feat(profile): add field policy config and GET response

Add per-field edit policy configuration (editable, requiresReview) to
application.yml and expose it in the GET /api/v1/user/profile response
via a new fieldPolicies map, enabling the frontend to dynamically render
fields based on backend-driven policies.

* feat(profile): implement mixed submission in PATCH

Split profile update changes by per-field policy: fields without
requiresReview apply immediately, fields with requiresReview enter
the pending queue. Return PARTIALLY_APPLIED status with appliedFields
and pendingFields maps when both paths trigger in a single request.

* feat(web): rewrite profile page with dynamic fields

Render profile fields dynamically from backend fieldPolicies, with
whole-page read/edit mode toggle. Handle APPLIED, PENDING_REVIEW, and
PARTIALLY_APPLIED responses. Add i18n keys for review hints and
partial-apply toasts in both en and zh.

* merge: resolve deepwiki.yml conflict with package-lock.json fix

* api schema

* fix(profile): align moderation defaults and tests

* ci(deepwiki): run crawler on release publish

* fix(auth): enable local bootstrap admin by default
This commit is contained in:
XiaoSeS 2026-03-20 16:10:20 +08:00 committed by GitHub
parent 611d67f845
commit b9b8ca22f1
10 changed files with 131 additions and 7 deletions

View file

@ -99,18 +99,26 @@ Then open:
- Web UI: `http://localhost:3000`
- Backend API: `http://localhost:8080`
Local profile seeds two mock-auth users automatically:
By default, `make dev-all` starts the backend with the `local` profile.
In that mode, local development keeps the mock-auth users below and also
creates a password-based bootstrap admin account by default:
- `local-user` for normal publishing and namespace operations
- `local-admin` with `SUPER_ADMIN` for review and admin flows
Use them with the `X-Mock-User-Id` header in local development.
The backend can bootstrap a local-login super admin for first-time access
when you explicitly set `BOOTSTRAP_ADMIN_ENABLED=true`:
The local bootstrap admin is enabled by default in `application-local.yml`:
- username: `BOOTSTRAP_ADMIN_USERNAME` (`admin` by default)
- password: `BOOTSTRAP_ADMIN_PASSWORD` (`ChangeMe!2026` by default)
- password: `BOOTSTRAP_ADMIN_PASSWORD`
In local app-level fallback it is `ChangeMe!2026`.
- For local source startup, set the environment variable
`BOOTSTRAP_ADMIN_ENABLED=false` before starting the backend.
- For container or release environments, configure the same value in
`.env.release` or the Compose environment.
- The shipped release template still uses `replace-this-admin-password` and
must be changed before first login.
Stop everything with:

View file

@ -67,12 +67,22 @@ curl -fsSL https://imageless.oss-cn-beijing.aliyuncs.com/runtime.sh | sh -s -- u
### 默认账户
本地开发环境提供两个模拟用户:
默认执行 `make dev-all` 时,后端以 `local` profile 启动。
在这个模式下,本地开发会保留下面两个模拟用户,同时默认创建一个可账号密码登录的 bootstrap 管理员:
- `local-user` — 普通用户,用于发布和命名空间操作
- `local-admin` — 超级管理员,用于审核和管理流程
在本地开发中使用 `X-Mock-User-Id` 请求头切换用户。
本地 bootstrap 管理员默认已在 `application-local.yml` 中开启,本地登录账号来自以下配置:
- 用户名:`BOOTSTRAP_ADMIN_USERNAME`,默认是 `admin`
- 密码:`BOOTSTRAP_ADMIN_PASSWORD`
- 本地应用默认回退值是 `ChangeMe!2026`
- 本地源码启动如需关闭自动创建,请在启动后端前设置环境变量
`BOOTSTRAP_ADMIN_ENABLED=false`
- 容器或发布环境则在 `.env.release` 或 Compose 环境变量中配置该值
- 发布模板 `.env.release.example` 里的占位值仍然是 `replace-this-admin-password`
### 停止服务

View file

@ -60,6 +60,7 @@
- `BOOTSTRAP_ADMIN_ENABLED=true`
- `BOOTSTRAP_ADMIN_USERNAME`
- `BOOTSTRAP_ADMIN_PASSWORD`
- 从 `.env.release.example` 复制时,初始占位值是 `replace-this-admin-password`
建议:
@ -210,6 +211,7 @@ docker compose --env-file .env.release -f compose.release.yml up -d
- 按云厂商 OSS / S3 兼容参数填写 `SKILLHUB_STORAGE_S3_*`
- 设置非默认的 `POSTGRES_PASSWORD`
- 如果要启用首登管理员,再额外设置 `BOOTSTRAP_ADMIN_ENABLED=true` 与非默认的 `BOOTSTRAP_ADMIN_PASSWORD`
- 不要直接保留模板里的 `replace-this-admin-password`
3. 启动前校验
- 运行 `make validate-release-config`
- 确认没有 `replace-me``change-this-*``ChangeMe!2026` 之类的占位值

View file

@ -49,6 +49,15 @@ Two mock users are available in local mode (no password needed):
| `local-user` | Regular user | `X-Mock-User-Id: local-user` |
| `local-admin` | Super admin | `X-Mock-User-Id: local-admin` |
Local development also creates a password-based bootstrap admin by default.
Use `BOOTSTRAP_ADMIN_USERNAME` / `BOOTSTRAP_ADMIN_PASSWORD` to log in through
the normal local account form. The default local fallback credentials are
`admin` / `ChangeMe!2026`.
To disable it for local source startup, set the environment variable
`BOOTSTRAP_ADMIN_ENABLED=false` before starting the backend.
For container or release environments, set the same value in `.env.release`
or the Compose environment.
### Useful commands
| Command | Description |

View file

@ -34,7 +34,7 @@ make dev-all
## 开发用户
本地开发环境预置了两个测试用户:
默认本地开发环境预置了两个模拟测试用户:
| 用户 | 角色 | 说明 |
|------|------|------|
@ -42,6 +42,14 @@ make dev-all
| `local-admin` | 超级管理员 | 拥有所有权限,包括审核和用户管理 |
使用 `X-Mock-User-Id` 请求头在本地开发中模拟用户登录。
本地开发环境还会默认创建可密码登录的 bootstrap 管理员账号:
- 用户名:`admin`
- 密码:`ChangeMe!2026`
本地源码启动如需覆盖或关闭,请在启动后端前设置 `BOOTSTRAP_ADMIN_*`
环境变量。
容器或发布环境则通过 `.env.release` 或 Compose 环境变量配置。
## 常用命令

View file

@ -55,6 +55,7 @@ curl -i http://127.0.0.1:8080/actuator/health
## 首登配置
1. 使用 `BOOTSTRAP_ADMIN_USERNAME``BOOTSTRAP_ADMIN_PASSWORD` 登录
`.env.release.example` 复制配置时,默认占位值是 `replace-this-admin-password`,需要先改掉
2. 立即修改管理员密码
3. 配置企业 SSO可选
4. 创建团队命名空间

View file

@ -34,7 +34,7 @@ After successful startup, you can access through the following addresses:
## Development Users
The local development environment comes with two test users:
By default, the local development environment comes with two mock test users:
| User | Role | Description |
|------|------|-------------|
@ -42,6 +42,16 @@ The local development environment comes with two test users:
| `local-admin` | Super admin | Has all permissions including review and user management |
Use the `X-Mock-User-Id` request header to simulate user login in local development.
The local development environment also creates a password-based bootstrap
admin by default:
- username: `admin`
- password: `ChangeMe!2026`
For local source startup, override or disable it with `BOOTSTRAP_ADMIN_*`
environment variables before starting the backend.
For container or release environments, configure the same values in
`.env.release` or the Compose environment.
## Common Commands

View file

@ -55,6 +55,7 @@ curl -i http://127.0.0.1:8080/actuator/health
## First Login Configuration
1. Login with `BOOTSTRAP_ADMIN_USERNAME` and `BOOTSTRAP_ADMIN_PASSWORD`
When copied from `.env.release.example`, the shipped placeholder is `replace-this-admin-password`, so change it before first login
2. Change admin password immediately
3. Configure enterprise SSO (optional)
4. Create team namespaces

View file

@ -27,6 +27,9 @@ skillhub:
auth:
mock:
enabled: true
bootstrap:
admin:
enabled: ${BOOTSTRAP_ADMIN_ENABLED:true}
profile:
moderation:
machine-review: ${SKILLHUB_PROFILE_MACHINE_REVIEW_ENABLED:true}

View file

@ -0,0 +1,72 @@
package com.iflytek.skillhub.config;
import com.iflytek.skillhub.bootstrap.BootstrapAdminProperties;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.env.SystemEnvironmentPropertySource;
import org.springframework.core.io.ClassPathResource;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class BootstrapAdminPropertiesBindingTest {
@Test
void defaultConfig_keepsBootstrapAdminDisabled() throws IOException {
BootstrapAdminProperties properties = bindProperties(
List.of("application.yml"),
Map.of()
);
assertFalse(properties.isEnabled());
}
@Test
void localProfile_enablesBootstrapAdminByDefault() throws IOException {
BootstrapAdminProperties properties = bindProperties(
List.of("application-local.yml", "application.yml"),
Map.of()
);
assertTrue(properties.isEnabled());
}
@Test
void localProfile_allowsEnvironmentVariablesToDisableBootstrapAdmin() throws IOException {
BootstrapAdminProperties properties = bindProperties(
List.of("application-local.yml", "application.yml"),
Map.of("BOOTSTRAP_ADMIN_ENABLED", "false")
);
assertFalse(properties.isEnabled());
}
private BootstrapAdminProperties bindProperties(List<String> resourceNames,
Map<String, Object> envVars) throws IOException {
ConfigurableEnvironment environment = new StandardEnvironment();
environment.getPropertySources().addFirst(new SystemEnvironmentPropertySource("test-env", envVars));
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
for (String resourceName : resourceNames) {
List<org.springframework.core.env.PropertySource<?>> propertySources = loader.load(
resourceName,
new ClassPathResource(resourceName)
);
for (org.springframework.core.env.PropertySource<?> propertySource : propertySources) {
environment.getPropertySources().addLast(propertySource);
}
}
ConfigurationPropertySources.attach(environment);
return Binder.get(environment)
.bind("skillhub.bootstrap.admin", BootstrapAdminProperties.class)
.orElseThrow(() -> new IllegalStateException("Failed to bind bootstrap admin properties"));
}
}