Commit graph

467 commits

Author SHA1 Message Date
yhd
1049a267fb feat(auth): add local registration toggle and OAuth failure logging
Deployments that only allow third-party sign-up can now disable local
registration end to end: the register endpoint returns 403 when
skillhub.auth.local.registration-enabled is false, and the web UI hides
the entry when SKILLHUB_WEB_REGISTRATION_ENABLED is false. Also log
OAuth2 login failures so callback errors are diagnosable from server
logs. Fixes the runtime-config entrypoint so registration defaults are
actually exported to envsubst.

Signed-off-by: yhd <yhd4711499@live.com>
2026-08-14 22:18:06 +08:00
yhd
94baeb5544 fix(auth): force https scheme for requests matching the public base URL
Higress terminates TLS and forwards plain HTTP without a usable
X-Forwarded-Proto, so {baseUrl} expansion produced http:// OAuth2
redirect URIs and Secure session cookies were dropped. Rewrite the
scheme to https when the request host matches skillhub.public.base-url.

Signed-off-by: yhd <yhd4711499@live.com>
2026-08-14 22:18:05 +08:00
yhd
e192b94d19 fix(auth): align Feishu OAuth with current official protocol docs
Addresses review on PR #696:

1. The authorize step now uses the currently documented endpoint
   https://accounts.feishu.cn/open-apis/authen/v1/authorize with standard
   OAuth2 parameters (client_id, optional scope), so the legacy
   app_id/no-scope URI rewrite in SkillHubOAuth2AuthorizationRequestResolver
   is removed. The authorize host is overridable via
   OAUTH2_FEISHU_AUTHORIZE_URI; token and userinfo endpoints stay on
   OAUTH2_FEISHU_BASE_URI.

2. FeishuClaimsExtractor no longer claims emailVerified: Feishu emails are
   admin-imported and carry no real-time verification signal, so
   emailVerified is always false. EMAIL_DOMAIN policy matches the email
   domain only and is unaffected.

Signed-off-by: yhd <yhd4711499@live.com>
2026-08-14 22:18:04 +08:00
yhd
b4388ee2a5 feat(auth): add Feishu OAuth2 login provider
Feishu deviates from standard OAuth2: the authorize endpoint requires
app_id instead of client_id, userinfo returns a {code, msg, data}
envelope with errors reported as HTTP 200, and the token endpoint uses
client_secret_post. Reuse the Spring oauth2Login pipeline and override
only the userinfo loading step via a ProviderOAuth2UserService extension
point, keeping GitHub/GitLab behavior unchanged. Bindings use open_id
as subject; union_id is kept in extra for future cross-app migration.

Signed-off-by: yhd <yhd4711499@live.com>
2026-08-14 22:18:02 +08:00
XiaoSeS
d2403bb591
feat(namespace): add admin namespace management
Some checks failed
Security / Dependency Review (push) Has been cancelled
Security / CodeQL (java-kotlin) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
Security / CodeQL (python) (push) Has been cancelled
Closes #580
2026-08-12 12:39:24 +08:00
XiaoSeS
81be20a6b5
fix(namespace): let super admin view namespaces (#705)
Some checks failed
Security / Dependency Review (push) Waiting to run
Security / CodeQL (java-kotlin) (push) Waiting to run
Security / CodeQL (javascript-typescript) (push) Waiting to run
Security / CodeQL (python) (push) Waiting to run
Deploy Docs / build (push) Has been cancelled
Deploy Docs / Deploy (push) Has been cancelled
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-11 16:04:28 +08:00
XiaoSeS
00f55c2db3 feat(search): surface compliance mappings in discovery
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-07 16:37:07 +08:00
XiaoSeS
da5c3cba3b feat(search): index compliance snapshot mappings
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-07 15:46:06 +08:00
XiaoSeS
a7b25b072b feat(metadata): expose compliance snapshots in version views
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-07 15:46:06 +08:00
XiaoSeS
725bbe165b feat(metadata): add x-astron compliance snapshot
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-07 15:46:06 +08:00
XiaoSeS
5e3f4e72e7 fix(deploy): keep PR 576 backport focused
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-06 19:05:36 +08:00
XiaoSeS
d0b7a7c5d4 fix(deploy): backport sub-path runtime fixes to PR 576
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-06 18:59:37 +08:00
philsun
34f244e7a4 feat(web): support configurable base-path deployment
Signed-off-by: philsun <xinyi.sun@daocloud.io>
2026-08-05 12:50:26 +08:00
XiaoSeS
51ff9b99d2
Merge pull request #684 from iflytek/fix/search-rebuild-observability-597
fix(search): observe label search rebuild failures
2026-08-04 17:42:17 +08:00
XiaoSeS
27113ce60c
fix(api): map Spring MVC client errors to 4xx (#685)
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-04 17:16:09 +08:00
XiaoSeS
b6cd414588 fix(search): observe label search rebuild failures
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-04 11:17:38 +08:00
XiaoSeS
55e5c1e10e
feat(observability): add generic request correlation and tracing foundation (#664)
* feat(observability): establish request correlation boundary

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* feat(observability): add selectable tracing modes

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* feat(observability): propagate async trace context

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* docs(observability): document tracing deployment modes

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* fix(observability): tighten tracing integration boundaries

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* fix(observability): harden operational log privacy

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* feat(observability): propagate message trace context

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* fix(observability): document message propagation semantics

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* test(auth): isolate security context between tests

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* fix(observability): skip otlp exporter without endpoint

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-04 10:26:42 +08:00
FenjuFu
34dc4fa29c fix(compat): percent-encode ClawHub download redirect Location
Downloading a skill whose slug is non-ASCII (e.g. a Chinese name) through
the ClawHub CLI compatibility route failed: the 302 Location header was
built by string-concatenating the raw slug, and Tomcat encodes header
values as ISO-8859-1, so a character outside 0-255 makes it drop the
Location header entirely and the download breaks. The skillhub CLI path
was unaffected because it doesn't go through this redirect.

Build the Location with UriComponentsBuilder.pathSegment(...).encode(), so
each segment is percent-encoded while the '/' separators stay literal.
"需求" becomes %E9%9C%80%E6%B1%82 and the header is ISO-8859-1-writable.

Fixes #658

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-08-02 02:18:36 +08:00
XiaoSeS
31d037de02 test(bootstrap): cover builtin skill upgrade conflicts
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-31 19:08:32 +08:00
XiaoSeS
5f7c48b7a4 feat(bootstrap): publish starter skills in runtime manifest
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-31 18:27:25 +08:00
XiaoSeS
b20ad397ad Merge codex/builtin-skills-content into codex/builtin-skills-release
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-31 18:27:25 +08:00
wowo-zZ
7885cc568b feat(builtin-skills): add reviewed starter collection
Signed-off-by: wowo-zZ <zhenggui5228@126.com>
2026-07-31 14:22:23 +08:00
wowo-zZ
7f934e63ab feat(bootstrap): verify built-in skill artifacts
Signed-off-by: wowo-zZ <zhenggui5228@126.com>
2026-07-31 11:14:42 +08:00
XiaoSeS
b264f3a0d2 fix(governance): safely delete version dependencies
Remove terminal review tasks before deleting an allowed skill version. Lock all versions of the aggregate in stable order so concurrent deletes preserve the last-version invariant and return business errors instead of 500 responses.

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-30 17:52:08 +08:00
wowo-zZ
0bf822290b feat(builtin-skills): add reviewed starter collection
Signed-off-by: wowo-zZ <zhenggui5228@126.com>
2026-07-30 15:54:09 +08:00
XiaoSeS
3db3c9685f feat(redis): complete cluster connection support
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-29 17:36:06 +08:00
XiaoSeS
dad3c15f92 chore(redis): merge current main for cluster support
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-29 16:11:31 +08:00
XiaoSeS
2854b26b5d fix(helm): resolve deployment review blockers
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-29 14:04:26 +08:00
XiaoSeS
e72c17b09f chore(helm): merge current main for validation
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-29 13:49:18 +08:00
XiaoSeS
9f602f8184
Merge pull request #480 from yaffir/main
fix(auth): hide placeholder OAuth providers
2026-07-29 09:00:19 +08:00
XiaoSeS
7872e64177
Merge pull request #609 from iflytek/fix/auth-revoked-token-validation
test(auth): cover revoked CLI token lifecycles
2026-07-29 03:37:47 +08:00
XiaoSeS
19c3070291
Merge pull request #607 from gale-popai/fix/device-auth-redis-typing
fix(auth): read device-code state via ObjectMapper conversion, not cast
2026-07-29 03:37:25 +08:00
XiaoSeS
c5a2b18fd9
Merge pull request #592 from shychee/fix/label-search-sync-async
fix(search): rebuild search index asynchronously after label change
2026-07-28 23:35:11 +08:00
XiaoSeS
155ab8f6d5 fix(auth): hide placeholder OAuth providers
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-28 22:16:45 +08:00
ylhu16
fab07cbc92 Merge remote-tracking branch 'origin/main' into review/pr480-20260728 2026-07-28 22:10:53 +08:00
gale-popai
d977ea9dc4
fix(api): tell callers why a request was forbidden (#610)
* fix(api): tell callers why a request was forbidden

The scope filter already computes an exact reason ("Missing API token
scope: skill:delete", "API token cannot access endpoint: /x") and the
access-denied handler discarded it, returning a bare "Forbidden" for
every case: missing scope, endpoint closed to API tokens, and paths
that simply don't exist. Clients cannot tell those apart, so they
guess — the published CLI reports every 403 as "token may lack
required scope", which sent us debugging token scopes for an hour when
the real causes were a revoked token and a mistyped namespace path.

The reason now rides in the response via a new error.forbidden.detail
message (en + zh), and is logged alongside the exception type.

Signed-off-by: Gal Eyal <gal.e@popai.health>

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(api): safely expose API token denial reasons

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-28 17:42:20 +08:00
Gal Eyal
8435ee1ab1 fix(auth): read device-code state via ObjectMapper conversion, not cast
The shared RedisTemplate uses GenericJackson2JsonRedisSerializer with
the application ObjectMapper, which embeds no type information, so
stored DeviceCodeData deserializes as a LinkedHashMap. The typed casts
in pollToken and authorizeDeviceCode then throw ClassCastException on
every call, making the whole device authorization flow unusable
(every poll returns 500).

Convert the raw value with ObjectMapper.convertValue instead of
casting; this reads both the current untyped map format and any typed
format, so no stored-data migration is needed. Adds bean setters to
DeviceCodeData for map conversion and regression tests that feed the
service exactly what Redis returns in production (untyped maps).

Fixes #604

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Gal Eyal <gal.e@popai.health>
2026-07-28 10:27:37 +03:00
dongmucat
5012b31af2 test(auth): cover CLI session fallback (#605)
Signed-off-by: dongmucat <1127093059@qq.com>
2026-07-28 15:22:11 +08:00
FenjuFu
4fdc7e3dc5
fix(publish): delete review tasks of any status when replacing a version (#601)
Some checks are pending
Deploy Docs / build (push) Waiting to run
Deploy Docs / Deploy (push) Blocked by required conditions
Security / Dependency Review (push) Waiting to run
Security / CodeQL (java-kotlin) (push) Waiting to run
Security / CodeQL (javascript-typescript) (push) Waiting to run
Security / CodeQL (python) (push) Waiting to run
* fix(publish): delete review tasks of any status when replacing a version

Re-uploading a rejected version under the same version number returned
HTTP 500. deleteReplaceableVersionArtifacts only removed a PENDING review
task, but a rejected version owns a REJECTED one; that row kept a foreign
key on the skill_version, so the subsequent delete hit a constraint
violation that surfaced as a 500.

Delete every review task attached to the version instead.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>

* test(publish): drop the spring-test dependency from the new test

skillhub-domain has no spring-test on its test classpath, so
ReflectionTestUtils does not resolve there. Use plain JDK reflection for
setting the generated id and invoking the private method.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>

* fix(publish): constrain rejected version replacement

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* test(publish): verify replaced review is deleted

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

* test(e2e): use generated API response types

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

---------

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-07-28 13:57:35 +08:00
dongmucat
726eeac8b2 test(auth): cover token replay and private search (#605)
Signed-off-by: dongmucat <1127093059@qq.com>
2026-07-28 13:52:26 +08:00
dongmucat
06cecd4237 test(auth): cover restricted CLI read authorization (#605)
Signed-off-by: dongmucat <1127093059@qq.com>
2026-07-28 12:51:09 +08:00
dongmucat
52843c8020 fix(test): assert CLI download media type (#605)
Signed-off-by: dongmucat <1127093059@qq.com>
2026-07-28 12:16:28 +08:00
dongmucat
83b621880e test(auth): cover persisted CLI token states (#605)
Signed-off-by: dongmucat <1127093059@qq.com>
2026-07-28 12:03:24 +08:00
shychee
de033da537 fix(search): make index writes REQUIRES_NEW to survive async caller-runs fallback
The @Async rebuildSkill fix relied on a fresh thread giving a clean
transaction boundary. But skillhubEventExecutor uses CallerRunsPolicy:
under saturation the rejected task runs on the caller (request) thread,
back inside the afterCommit synchronization phase — the original failure
context where the @Transactional index write is silently dropped.

Mark SearchIndexService.index as REQUIRES_NEW so it always suspends any
lingering post-commit synchronization and commits in its own transaction,
independent of whether the async dispatch actually happened.

Add regression tests: detach removes the label keyword, and a synchronous
rebuild inside the afterCommit phase still persists the document (fails
without REQUIRES_NEW).

Signed-off-by: shychee <shychee96@gmail.com>
2026-07-22 18:54:38 +08:00
shychee
74bad000e3 fix(search): rebuild search index asynchronously after label change
Attaching or detaching a skill label triggers a search index rebuild via
an afterCommit callback. Because LabelSearchSyncService.rebuildSkill ran
synchronously on the request thread, the @Transactional index write
executed inside the already-committed transaction-synchronization phase
and was silently dropped -- the search document was never written, so
label keywords never became searchable.

Move rebuildSkill onto the skillhubEventExecutor with @Async (matching the
existing rebuildSkills batch path) so the rebuild runs on a fresh thread
and transaction. Add an integration test that fails on the old synchronous
path and passes with the async fix.

Signed-off-by: shychee <shychee96@gmail.com>
2026-07-22 18:38:00 +08:00
lhb6540
5d379dcaaf fix(helm): 修正组件启停与依赖配置并增加 values 校验
在配置进入 Kubernetes 前完成父 Chart 校验,并补齐剩余的依赖配置契约。

- 让 Service、HPA 和 PDB 正确遵循组件启用状态
- 校验 Ingress、自动扩缩容、外部依赖和共享存储的组合配置
- 增加 values.schema.json 和 Helm 配置契约测试并接入 CI
- 统一 PostgreSQL Primary 与 Read Replica 的 max_connections 配置
- 修正 Redis Sentinel 节点、依赖等待和独立密码配置
- 允许覆盖依赖等待容器镜像,支持完整私有镜像仓库部署
- 兼容现代与旧式 IngressClass,并支持多域名 TLS 和证书 SAN
- 增加 GitOps 稳定 Secret 模式,阻止离线渲染产生随机凭据漂移
- 引用用户可控的 ConfigMap 字符串,并推导 TLS 安全 Cookie 和设备认证默认值
- 补充 Sentinel、RWX 存储、TLS Cookie、PVC 保留、私有镜像和 GitOps 文档
- 增加 Redis 数据密码与 Sentinel 密码分离的应用配置测试

已通过 Helm 严格 lint、渲染场景、配置契约测试、kubeconform、后端测试套件和 Sentinel 专项配置测试。

Signed-off-by: lhb6540 <lhb6540@gmail.com>
2026-07-15 17:19:24 +08:00
dongmucat
3a254d7524 fix(auth): guard SUPER_ADMIN role mutations
Signed-off-by: dongmucat <1127093059@qq.com>
2026-07-01 16:23:45 +08:00
dongmucat
8413ee3950
Merge pull request #554 from iflytek/fix/auth-password-settings
Some checks failed
Security / Dependency Review (push) Has been cancelled
Security / CodeQL (java-kotlin) (push) Has been cancelled
Security / CodeQL (javascript-typescript) (push) Has been cancelled
fix(auth): restore password settings access
2026-06-24 10:50:26 +08:00
dongmucat
e501be9cf8 feat(promotion): improve promotion review dashboard
Signed-off-by: dongmucat <1127093059@qq.com>
2026-06-24 09:28:43 +08:00
dongmucat
665ee0499a feat(auth): add ISSUE-60 password capability field
Signed-off-by: dongmucat <1127093059@qq.com>
2026-06-22 12:40:01 +08:00