Commit graph

642 commits

Author SHA1 Message Date
AI Assistant
9747740a6e docs: append new QA pairs to FAQ 2026-04-03 13:11:40 +08:00
XiaoSeS
c0f790079d
docs: add Kubernetes deployment guide with overlays structure (#219)
* docs: simplify runtime script usage

Unify to use runtime.sh for all deployment commands, removing the
distinction between "official images" and "Aliyun mirror". The --aliyun
parameter is preserved for users in China to specify the mirror.

Changes:
- Remove runtime-github.sh references, use runtime.sh uniformly
- Default command uses GHCR images
- Add --aliyun parameter for China users
- Update README.md, README_zh.md, and docs/skillhub/ quickstart files

* docs: consolidate documentation links with clear descriptions

Merge the two documentation links into a single "Documentation" section
with clear descriptions of each:
- User Guide: skill publishing, search, CLI usage
- Developer Docs: architecture, API reference, deployment

This makes it easier for users to find the right documentation.

* docs: consolidate documentation links with clear descriptions

Merge the two documentation links into a single "Documentation" section
with clear descriptions of each:
- User Guide: skill publishing, search, CLI usage
- Developer Docs: architecture, API reference, deployment

This makes it easier for users to find the right documentation.

* fix: include --home parameter in shutdown command

When starting with a custom --home directory, the generated shutdown
command now includes the same --home parameter to ensure it can find
the correct compose files.

* docs: add Kubernetes deployment guide with overlays structure

- Restructure k8s configs with base/overlays pattern for flexibility
- Add overlays/with-infra for full deployment (PostgreSQL + Redis)
- Add overlays/external for external database scenarios
- Add comprehensive ConfigMap with bootstrap admin settings
- Fix health check path to /actuator/health (auth issue)
- Add SKILLHUB_API_UPSTREAM env for frontend
- Set SESSION_COOKIE_SECURE=false for HTTP environments
- Add Chinese and English documentation in docs/skillhub/

* docs: update k8s README with complete config reference
2026-04-02 21:01:28 +08:00
XiaoSeS
37c25c3f91
docs: simplify runtime script usage (#217)
* docs: simplify runtime script usage

Unify to use runtime.sh for all deployment commands, removing the
distinction between "official images" and "Aliyun mirror". The --aliyun
parameter is preserved for users in China to specify the mirror.

Changes:
- Remove runtime-github.sh references, use runtime.sh uniformly
- Default command uses GHCR images
- Add --aliyun parameter for China users
- Update README.md, README_zh.md, and docs/skillhub/ quickstart files

* docs: consolidate documentation links with clear descriptions

Merge the two documentation links into a single "Documentation" section
with clear descriptions of each:
- User Guide: skill publishing, search, CLI usage
- Developer Docs: architecture, API reference, deployment

This makes it easier for users to find the right documentation.

* docs: consolidate documentation links with clear descriptions

Merge the two documentation links into a single "Documentation" section
with clear descriptions of each:
- User Guide: skill publishing, search, CLI usage
- Developer Docs: architecture, API reference, deployment

This makes it easier for users to find the right documentation.

* fix: include --home parameter in shutdown command

When starting with a custom --home directory, the generated shutdown
command now includes the same --home parameter to ensure it can find
the correct compose files.
2026-04-02 20:59:49 +08:00
XiaoSeS
612b69c2f9
fix: add --public-url parameter for docker deployment (#216)
* docs: add VitePress bilingual documentation site

- Add VitePress-based documentation with Chinese (root) and English (/en/) locales
- Include 6 feature guides: skill-publish, skill-discovery, namespace, review, scanner, social
- Add quickstart, introduction, and FAQ pages
- Include AI-generated diagrams and screenshots
- Add GitHub Pages deployment workflow
- Add Makefile targets: docs-dev, docs-build, docs-preview

* docs: rename docs/claude to docs/skillhub

- Rename documentation directory from docs/claude to docs/skillhub
- Update Makefile paths for docs-dev, docs-build, docs-preview
- Update GitHub workflow paths for deploy-docs.yml

* fix: add enablement parameter to auto-enable GitHub Pages

* Revert "fix: add enablement parameter to auto-enable GitHub Pages"

This reverts commit 11096b1a9b.

* docs: add documentation link to README

Add link to GitHub Pages documentation (https://iflytek.github.io/skillhub/)
under Quick Start section in both English and Chinese README files.

* fix: add --public-url parameter for docker deployment

- Add --public-url parameter to runtime.sh for configuring public access URL
- Create skill.md.template for dynamic URL substitution at container startup
- Update getBaseUrl() to fallback to window.location.host when appBaseUrl is localhost
- Update landing-quick-start.tsx to dynamically generate agent command URL
- Add commandTemplate to i18n files for URL placeholder support
- Update README.md and README_zh.md with deployment parameter documentation

Fixes: Docker deployment shows localhost in install commands and skill.md
2026-04-02 17:52:42 +08:00
dongmucat
cbc1ef25f7
chore: update .gitignore to include .codex directory (#211) 2026-04-02 15:04:37 +08:00
yun-zhi-ztl
dce445a1e8
organize .gitignore (#206)
* organize .gitignore

* stop ignoring CODE_OF_CONDUCT.md

---------

Co-authored-by: yun-zhi-ztl <yunzhi@yunzhideMac-mini.local>
2026-04-02 13:51:23 +08:00
XiaoSeS
1233354087
docs: add VitePress bilingual documentation site (#208)
* docs: add VitePress bilingual documentation site

- Add VitePress-based documentation with Chinese (root) and English (/en/) locales
- Include 6 feature guides: skill-publish, skill-discovery, namespace, review, scanner, social
- Add quickstart, introduction, and FAQ pages
- Include AI-generated diagrams and screenshots
- Add GitHub Pages deployment workflow
- Add Makefile targets: docs-dev, docs-build, docs-preview

* docs: rename docs/claude to docs/skillhub

- Rename documentation directory from docs/claude to docs/skillhub
- Update Makefile paths for docs-dev, docs-build, docs-preview
- Update GitHub workflow paths for deploy-docs.yml
2026-04-02 13:43:55 +08:00
wowo-zZ
e5fb133653 docs: update README formatting 2026-04-01 21:49:30 +08:00
Seasoning
3e4a4bc463 docs: Improve the user manual for regular users (#197)
* docs: Improve the user manual for regular users

* docs: Align the document title and fix formatting issues in the example
2026-04-01 15:12:51 +08:00
dongmucat
50a6c4b7fe test(e2e,ci): migrate web e2e to real API and add PR e2e workflow (#198)
* chore(workflow): align local hooks and e2e guidance

* test(e2e): expand reusable api mock helpers

* test(skill): stabilize share button e2e assertions

* chore(test): add e2e make target and tune playwright workers

* test(web): expand e2e coverage and smoke suite

* test(e2e): migrate to real API flows and add request-based data builder

* ci(e2e): add PR workflow for real-service frontend e2e

* ci(e2e): install playwright chromium in PR workflow

* test(e2e): relax timeout and force single worker in CI

* test(e2e): stabilize not-found assertions and harden CI session bootstrap

* chore(agents): align tester role with web/e2e workflow
2026-04-01 14:41:23 +08:00
eryuan
5d7bee2c58 Pr/fix sse timeout global exception handler (#178)
* feat : 调整本地开发环境

* feat : 调整sse 超时 GlobalExceptionHandler 拦截异常

See :
rg.springframework.web.context.request.async.AsyncRequestTimeoutException: null
	at org.springframework.web.context.request.async.TimeoutDeferredResultProcessingInterceptor.handleTimeout(TimeoutDeferredResultProcessingInterceptor.java:42) ~[spring-web-6.1.4.jar:6.1.4]
	at org.springframework.web.context.request.async.DeferredResultInterceptorChain.triggerAfterTimeout(DeferredResultInterceptorChain.java:81) ~[spring-web-6.1.4.jar:6.1.4]
	at org.springframework.web.context.request.async.WebAsyncManager.lambda$startDeferredResultProcessing$5(WebAsyncManager.java:430) ~[spring-web-6.1.4.jar:6.1.4]
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) ~[na:na]
	at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.onTimeout(StandardServletAsyncWebRequest.java:149) ~[spring-web-6.1.4.jar:6.1.4]
	at org.apache.catalina.core.AsyncListenerWrapper.fireOnTimeout(AsyncListenerWrapper.java:44) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.core.AsyncContextImpl.timeout(AsyncContextImpl.java:136) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:135) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:243) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:57) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
	at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]

* Revert "feat : 调整sse 超时 GlobalExceptionHandler 拦截异常"

This reverts commit 6f0cea85b5daac47025767efe1bd90565b5da469.

* Revert "feat : 调整本地开发环境"

This reverts commit 0695a3d7c823491ce5c83aabe3660ba9997f28c5.

* feat : 调整sse 超时 GlobalExceptionHandler 拦截异常

See :
rg.springframework.web.context.request.async.AsyncRequestTimeoutException: null
    at org.springframework.web.context.request.async.TimeoutDeferredResultProcessingInterceptor.handleTimeout(TimeoutDeferredResultProcessingInterceptor.java:42) ~[spring-web-6.1.4.jar:6.1.4]
    at org.springframework.web.context.request.async.DeferredResultInterceptorChain.triggerAfterTimeout(DeferredResultInterceptorChain.java:81) ~[spring-web-6.1.4.jar:6.1.4]
    at org.springframework.web.context.request.async.WebAsyncManager.lambda$startDeferredResultProcessing$5(WebAsyncManager.java:430) ~[spring-web-6.1.4.jar:6.1.4]
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) ~[na:na]
    at org.springframework.web.context.request.async.StandardServletAsyncWebRequest.onTimeout(StandardServletAsyncWebRequest.java:149) ~[spring-web-6.1.4.jar:6.1.4]
    at org.apache.catalina.core.AsyncListenerWrapper.fireOnTimeout(AsyncListenerWrapper.java:44) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.catalina.core.AsyncContextImpl.timeout(AsyncContextImpl.java:136) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:135) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:243) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:57) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63) ~[tomcat-embed-core-10.1.19.jar:10.1.19]
    at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]

* fix(app): stabilize async timeout handling

---------

Co-authored-by: zhaieryuan <zhaieryuan@enn.cn>
Co-authored-by: wowo-zZ <zhenggui5228@126.com>
2026-03-31 11:20:42 +08:00
XiaoSeS
5842a02288 feat: support Unicode characters in skill slugs (#196)
* fix: increase nginx upload limit and filter Chrome DevTools logs

- Add client_max_body_size 100M to nginx config to allow large skill package uploads
- Silently handle Chrome DevTools .well-known requests to reduce log noise

Fixes #193

* feat(domain): add Unicode slug support with emoji validation

- Update SLUG_PATTERN to support Unicode letters (\p{L}), numbers (\p{N}), and symbols (\p{So})
- Add UPPERCASE_PATTERN to maintain lowercase-only validation
- Modify slugify() to preserve Unicode characters instead of replacing with hyphens
- Add 8 new test cases covering Chinese, Japanese, Korean, emoji, and mixed Unicode slugs
- Maintain backward compatibility with existing ASCII slug validation
- All 16 tests passing

Implements Phase 1 of unicode-slug-support-v1.0-prd.md

* feat(web): add URL encoding for Unicode slugs and improve monospace font support

- Encode skill slugs in all navigation URLs using encodeURIComponent
- Encode slugs in API client methods for proper HTTP request handling
- Update share button to generate properly encoded URLs
- Extend monospace font stack with system fonts for better Unicode support
- All frontend tests pass (506 tests)

Related to Unicode slug support PRD phase 2 and 3

* feat(web): regenerate API types for Unicode slug support

- Update OpenAPI schema types after backend slug validator changes
- Reflects new Unicode-aware slug pattern validation

* remove
2026-03-31 10:17:34 +08:00
XiaoSeS
3366d018dc fix: increase nginx upload limit and filter Chrome DevTools logs (#195)
* fix: increase nginx upload limit and filter Chrome DevTools logs

- Add client_max_body_size 100M to nginx config to allow large skill package uploads
- Silently handle Chrome DevTools .well-known requests to reduce log noise

Fixes #193

* remove
2026-03-31 09:38:51 +08:00
XiaoSeS
c23d0bbc4a feat: add scanner service to v0.2.0 release deployment (#189)
* feat(deploy): add scanner service to release deployment

- Add skill-scanner service to compose.release.yml (enabled by default)
- Add scanner image to CI publish-images workflow matrix
- Add --scanner-image and --no-scanner flags to runtime.sh
- Add scanner config to .env.release.example

* fix(docker): add skillhub-notification module to server Dockerfile

* fix(deploy): set scanner mode to upload for container deployment

* fix(deploy): use env override instead of persisting scanner disabled state
2026-03-30 19:01:51 +08:00
XiaoSeS
a14e2296ca Fix/allow xsd files (#191)
* feat(upload): allow xsd, xsl, dtd file types in skill packages

Add XML schema-related file extensions (.xsd, .xsl, .dtd) to the
upload allowlist and text content validation. Users uploading skills
with XML Schema files (e.g., Anthropic's docx skill) were getting
rejected because .xsd was not in the allowed extensions list.

Closes #165

* feat(upload): expand office file allowlist

* test(app): verify publish extension env override

* docs(readme): document upload allowlist override

* feat(upload): add legacy Office formats to upload allowlist

Add .doc, .xls, .ppt to SkillPackagePolicy.ALLOWED_EXTENSIONS so
users can upload skill packages containing legacy Office files.

* chore: remove v0.2.0 release notes draft

---------

Co-authored-by: wowo-zZ <zhenggui5228@126.com>
2026-03-30 18:25:19 +08:00
wowo
34de5bb53e feat(upload): allow xsd, xsl, dtd file types in skill packages (#185)
* feat(upload): allow xsd, xsl, dtd file types in skill packages

Add XML schema-related file extensions (.xsd, .xsl, .dtd) to the
upload allowlist and text content validation. Users uploading skills
with XML Schema files (e.g., Anthropic's docx skill) were getting
rejected because .xsd was not in the allowed extensions list.

Closes #165

* feat(upload): expand office file allowlist

* test(app): verify publish extension env override

* docs(readme): document upload allowlist override
2026-03-30 18:13:37 +08:00
wowo
1b7bd06685 feat(web): add skill share button with e2e tests (#181)
* test(web): add Playwright e2e testing framework

Add Playwright for end-to-end testing with initial test suites for search flow and network error handling. Also enhance unit tests for network error scenarios.

- Add @playwright/test dependency and npm scripts
- Configure Playwright with chromium browser and HTML reporter
- Add e2e tests for search flow and network error handling
- Update .gitignore to exclude Playwright generated files
- Add network error test cases to api-error unit tests

* feat(web): add skill share button to detail page

Add share button to skill detail page that copies skill info to clipboard. Share text includes skill name, short description (max 30 chars), and detail page URL.

Closes #168

* test(web): add e2e tests for skill share button

Add Playwright e2e tests to verify share button functionality including clipboard copy, text formatting, and state transitions.

* fix(web): fix share button e2e tests and document Playwright workflow

Fix 3 issues in share-button e2e tests:
- Use authenticated mock (skill detail page requires login)
- Add publishedVersion to skill factory (ShareButton render condition)
- Mock versions/files sub-resource APIs to prevent server errors
- Adjust description assertion for 30-char truncation logic

Add Playwright E2E section to CLAUDE.md documenting commands,
screenshot behavior, and test-results directory conventions.

E2E test results: 10/10 passed (Chromium, Playwright 1.58.2)
- network-error.spec.ts:  3/3 passed
- search-flow.spec.ts:    3/3 passed
- share-button.spec.ts:   4/4 passed

* refactor(web): improve share button layout and text format

- Remove description truncation, display full text
- Change share text format from 2 lines to 3 lines (name, description, URL)
- Replace Button component with custom styled native button
- Move ShareButton from card to below download button
- Update tests to match new 3-line format

* fix(web): handle clipboard copy failure in fallback path

- Check document.execCommand('copy') return value
- Throw error when copy fails in fallback path
- Ensure error is properly caught and displayed to user

Fixes issue where "复制 Token 失败,请重试" was shown but the
underlying failure was not properly detected in the fallback code path.

* refactor(web): modernize clipboard with useCopyToClipboard hook

- Add useCopyToClipboard React hook for cleaner state management
- Migrate all copy buttons to use the new hook
- Remove repetitive useState + setTimeout patterns across 7 files
- Simplify clipboard.ts by removing excessive diagnostic logging
- Keep copyToClipboard utility for special cases (file-preview-dialog)

Benefits:
- More idiomatic React code with custom hook
- Consistent 2-second auto-reset behavior
- Reduced code duplication
- Better separation of concerns

* test(web): fix api-error tests and exclude e2e from vitest

- Set i18n language to 'zh' in api-error.test.ts beforeEach
- Add vitest config to exclude e2e directory from unit tests
- All 506 tests now pass

---------

Co-authored-by: xiose <huyanlin@nuaa.edu.cn>
2026-03-30 14:04:52 +08:00
XiaoSeS
0a8c02c647 fix: enable bootstrap admin by default for zero-config quickstart (#175) 2026-03-27 19:00:24 +08:00
dongmucat
1aae926944 fix(web): improve network error message with i18n
- Replace hardcoded 'Network error' with i18n key 'apiError.networkError'
- Add dedicated handler for status 0 in handleApiError
- Add test case for network error scenario

Closes #160
2026-03-27 18:50:38 +08:00
dongmucat
3ac66fb6d9 feat: add ignore .claude/ 2026-03-27 17:04:56 +08:00
dongmucat
79d39b35ce feat: add ignore .claude 2026-03-27 17:04:56 +08:00
dongmucat
782af73e4a chore(workflow): enhance dev workflow with PR template and Playwright MCP
- 在 skillhub-dev-workflow skill 中增加"阶段七 — 提交 Pull Request"
- 添加结构化 PR 模板,包含概述、变更内容、质量门禁、安全考虑、测试说明
- 为 Claude Code 创建对应的 skill 版本(.claude/skills/)
- 配置 Playwright MCP 服务器用于 E2E 测试
- 更新 .gitignore 以支持 .claude/ 目录和 *.local.json 文件
2026-03-27 17:04:56 +08:00
XiaoSeS
1237d42119 Webclient fix (#173)
* fix(scanner): wire timeout config and create dedicated scanner HttpClient

- Create scanner-specific HttpClient bean with proper timeout configuration
- Wire SkillScannerProperties.connectTimeoutMs (5s) and readTimeoutMs (5min) into WebClient
- Add logging for timeout configuration verification
- Fix cloud environment 5-second timeout issue by ensuring responseTimeout is properly applied

The previous global WebClient.Builder configuration was not being used correctly,
causing scanner requests to timeout after 5 seconds in cloud environment.
This fix creates a dedicated HttpClient for scanner with explicit timeout settings.

* refactor(webclient): use WebClientCustomizer and add scanner connection pool

- Replace singleton WebClient.Builder bean with WebClientCustomizer
  (follows Spring Boot best practice for prototype-scoped builder)
- Add connection pool config to scanner HttpClient (maxConn=10,
  maxIdleTime=20s, evictInBackground=30s) to prevent stale connections
- Add connectTimeout to global WebClient config

* fix(skill): use system default timezone for auto-generated version numbers

- Change AUTO_VERSION_FORMATTER from UTC to ZoneId.systemDefault()
- Version format yyyyMMdd.HHmmss now uses server's local timezone
- Update test to validate format instead of exact value (timezone-independent)

This allows the service to adapt to deployment location:
- Deployed in China → uses Asia/Shanghai timezone
- Deployed in US → uses US timezone
- Follows server's system timezone configuration
2026-03-27 15:41:58 +08:00
wowo
fb9b11e750 fix: 修复发布skill时版本时间戳时区错误 (#171)
将自动版本号的时间戳从 UTC 时区改为北京时区 (Asia/Shanghai)。

修复 #169
2026-03-27 15:21:17 +08:00
XiaoSeS
90c1f3c805 fix(scanner): wire timeout config and create dedicated scanner HttpClient (#166)
- Create scanner-specific HttpClient bean with proper timeout configuration
- Wire SkillScannerProperties.connectTimeoutMs (5s) and readTimeoutMs (5min) into WebClient
- Add logging for timeout configuration verification
- Fix cloud environment 5-second timeout issue by ensuring responseTimeout is properly applied

The previous global WebClient.Builder configuration was not being used correctly,
causing scanner requests to timeout after 5 seconds in cloud environment.
This fix creates a dedicated HttpClient for scanner with explicit timeout settings.
2026-03-27 11:16:07 +08:00
XiaoSeS
175eb8e1ae fix(scanner): stage upload bundles from object storage (#164)
* fix(scanner): stage upload bundles from object storage

* fix(web): wrap long skill detail values
2026-03-26 17:08:23 +08:00
XiaoSeS
86b4d0508b fix(skill): defer version storage deletion until commit (#162)
* fix(skill): resolve duplicate result error when deleting skill with shared namespace+slug

V13 migration changed the unique constraint from (namespace_id, slug) to
(namespace_id, slug, owner_id), allowing multiple skills with the same
namespace+slug but different owners. The findByNamespaceSlugAndSlug query
returned Optional<Skill> which threw IncorrectResultSizeDataAccessException
when 2 rows matched.

Changed the query to return List<Skill> and added ownerId query param to
DELETE endpoints so the frontend can specify exactly which skill to delete.

* fix(review): keep failed scans reviewable and expose feedback

* fix(skill-delete): delete skills by id

* fix(skill): defer version storage deletion until commit
2026-03-26 13:54:30 +08:00
XiaoSeS
a78684ce44 Fix/skill delete duplicate result (#159)
* fix(skill): resolve duplicate result error when deleting skill with shared namespace+slug

V13 migration changed the unique constraint from (namespace_id, slug) to
(namespace_id, slug, owner_id), allowing multiple skills with the same
namespace+slug but different owners. The findByNamespaceSlugAndSlug query
returned Optional<Skill> which threw IncorrectResultSizeDataAccessException
when 2 rows matched.

Changed the query to return List<Skill> and added ownerId query param to
DELETE endpoints so the frontend can specify exactly which skill to delete.

* fix(review): keep failed scans reviewable and expose feedback
2026-03-25 16:15:50 +08:00
XiaoSeS
6020006a25 fix: scanner redis sentinel, publish flush, version delete, clipboard fallback (#157)
* fix(scanner): migrate scan stream to redisson

* fix(web): update security audit pending labels

* fix(scanner): support redis sentinel in redisson config

* fix(db): allow deleting skill versions with audit history

* fix(publish): flush replaced versions before recreation

* fix(i18n): localize agent setup command in Chinese locale

Translate the agent quick-start prompt from English to Chinese and add
a test to verify both locale strings.

* fix(clipboard): add fallback for insecure contexts

navigator.clipboard is undefined in HTTP/iframe/WebView contexts,
causing TypeError on copy. Extract copyToClipboard() utility with
execCommand fallback and apply across all 6 call sites.
2026-03-24 20:26:50 +08:00
FenjuFu
37c188ab7d Update README_zh.md
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-03-24 20:11:37 +08:00
FenjuFu
ac34b3da6b Correct links and formatting in README.md
Fixed links and formatting for AstronClaw and Loomy sections.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-03-24 20:11:37 +08:00
FenjuFu
754d3845fa Update AstronClaw link in README_zh.md
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-03-24 20:11:37 +08:00
FenjuFu
91a511d0a7 Fix link formatting for AstronClaw section
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-03-24 20:11:37 +08:00
FenjuFu
4e71b8b9f8 Fix AstronClaw link in README.md
Updated the AstronClaw link to point to the correct URL.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-03-24 20:11:37 +08:00
FenjuFu
2d5d9a443c docs: update AstronClaw and Loomy integration descriptions 2026-03-24 20:11:37 +08:00
XiaoSeS
0fcc40cd4c fix(scanner): support redis sentinel in redisson config (#154)
* fix(scanner): migrate scan stream to redisson

* fix(web): update security audit pending labels

* fix(scanner): support redis sentinel in redisson config
2026-03-24 15:54:39 +08:00
XiaoSeS
747f649fb7 fix: migrate scanner stream to redisson and refine audit status labels` (#153)
* fix(scanner): migrate scan stream to redisson

* fix(web): update security audit pending labels
2026-03-24 14:56:16 +08:00
vsxd
eda8764b30 fix: db migration script version 2026-03-23 20:23:50 +08:00
yun-zhi-ztl
3110020ff9 merge: pull request #122 from iflytek/feature/notification-system
feat(notification): add in-app notifications with hardened delivery
2026-03-23 20:01:36 +08:00
yun-zhi-ztl
798038fcc1 fix(dev): ignore invalid backend pid files 2026-03-23 17:14:16 +08:00
yun-zhi-ztl
3f7145a843 Merge remote-tracking branch 'origin/main' into feature/notification-system 2026-03-23 17:12:13 +08:00
dongmucat
e5a3aa6006 test(web): add colocated frontend coverage
变更摘要:
- 将前端测试共置到 web/src,保留并迁移 app 样式相关用例
- 为 pages、features、shared UI 与 hooks 补齐大范围 Vitest 覆盖
- 强化 governance、file preview、namespace header 与 API client 的关键分支测试
- 重新验证 pnpm run test 与 pnpm run typecheck,当前均已通过

关键文件:
- web/src/pages/dashboard/governance.test.ts
- web/src/features/governance/governance-inbox.test.ts
- web/src/features/skill/file-preview-dialog.test.ts
- web/src/features/namespace/namespace-header.test.ts
- web/src/api/client.test.ts
2026-03-23 16:13:34 +08:00
yun-zhi-ztl
a3d7a81d0c chore(notification): sync main and expand regression coverage 2026-03-23 15:04:47 +08:00
XiaoSeS
ee33505b7c feat: File Browser Sidebar with Preview, Security Audit UI, and Syntax Highlighting (#145)
* feat(security): extend scanner config with full analyzer options

Integrate skill-scanner's 8 analysis engines and policy configuration
into SkillHub's config system. Operators can now control behavioral,
LLM, Meta, AI Defense, VirusTotal, and trigger analyzers via
application.yml or environment variables.

Changes:
- Add Analyzers and Policy nested classes to SkillScannerProperties
- Create ScanOptions record to encapsulate analyzer flags
- Update SkillScannerService to pass options in /scan body and /scan-upload query params
- Wire ScanOptions through SkillScannerConfig and SkillScannerAdapter
- Extend application.yml with full scanner config block and env var overrides
- Update all tests to verify new configuration flow

All tests pass.

* feat(security): add domain model and integrate scan into publish flow

Add SCANNING/SCAN_FAILED status to SkillVersionStatus. Introduce
SecurityScanService, SecurityScanner port, ScanTask, SecurityAudit
and related domain types. Wire scan trigger into SkillPublishService
so non-auto-publish versions enter scanning when scanner is enabled,
falling back to review task creation when disabled.

* feat(security): add infra layer for scanner HTTP client and adapters

Add WebClient-based HttpClient abstraction with WebClientHttpClient
implementation. Add SkillScannerApiResponse record, SecurityScanException,
and SecurityAuditJpaRepository. Add webflux and test dependencies to
infra module.

* feat(security): add Redis stream consumers, audit API, and DB migration

Add AbstractStreamConsumer base class, ScanTaskConsumer for processing
scan results from Redis stream, and RedisScanTaskProducer. Add
RedisStreamConfig for stream/group initialization. Add SecurityAudit
REST controller and DTO. Add V35 Flyway migration for security_audits
table.

* feat(security): add scanner config to application profiles

Add scanner enabled flag to application-local.yml and
application-test.yml. Enable behavioral analyzer by default
in application.yml.

* feat(deploy): add skill-scanner to docker-compose and k8s manifests

Add skill-scanner service to docker-compose.yml with health check.
Add scanner k8s deployment, service, and configmap entries. Wire
scanner env vars into Makefile dev-all flow. Add verify-scanner.sh
script for post-deploy validation.

* docs(security): add scanner documentation suite

Add scanner docs: configuration guide, failure impact analysis,
monitoring guide, improvement recommendations, custom rules guide,
and skill-vetter rules conversion example. Update deployment docs
with scanner section. Add security-scanning overview and PRD.

* feat(security): add skill-vetter custom rule examples

Add example Regex and YARA rules derived from skill-vetter RED FLAGS
in scanner/examples/vetter-rules/. Includes 7 Regex rules
(signatures-append.yaml) and 3 YARA rules (skillhub_vetter.yara)
covering agent memory theft, IP-based exfiltration, and browser
data theft detection.

* feat(security): add scanner Docker build context

Add Dockerfile for cisco-ai-skill-scanner container and
.env.example with LLM configuration placeholders.

* fix(security): align Finding mapping with scanner API response schema

SkillScannerApiResponse.Finding used incorrect field names (message,
location.file, location.line, code_snippet) that did not match the
scanner's actual JSON output (description, file_path, line_number,
snippet), causing all four fields to deserialize as null.

Flatten Finding to match scanner API: remove nested Location, rename
fields to description/file_path/line_number/snippet. Add skill_name
and timestamp to SkillScannerApiResponse. Extend SecurityFinding with
remediation, analyzer, and metadata fields to capture LLM analyzer
output. Retain 8-arg compact constructor for backward compatibility.

* chore(security): add debug logging to scanner response mapping

Log raw scanner API response and mapped SecurityFinding fields
side-by-side to help verify data consistency between scanner
output and database records.

* feat(security): add multi-scanner support and soft delete for security audits

- Add ScannerType enum for type-safe scanner identification
- Update V35 migration to support multiple scanners and soft delete
- Remove CASCADE delete, use code-level soft delete (deleted_at)
- Add repository methods for querying latest audit by scanner type
- Update SecurityScanService to handle scanner type parameter
- Integrate soft delete in SkillHardDeleteService
- Update all tests to use ScannerType enum

This enables multiple scanner integrations (skill-scanner, future LLM/compliance scanners)
and preserves complete audit history through soft deletion.

* feat(security): add security audit UI to review detail and skill detail pages

Display security scan results on the review detail page (full audit
section with collapsible findings) and the skill detail sidebar (compact
summary with dialog for details).  Handles empty/404 gracefully by
returning null, avoids loading shimmer flicker, and separates lifecycle
action buttons with a visual divider.

* docs(security): add security audit UI PRD

* docs(prd): add related documents section to file browser sidebar PRD

* feat(skill): add file tree builder utility

Implement buildFileTree function to convert flat SkillFile[] into hierarchical tree structure.
- Nodes sorted alphabetically by path
- Support for nested directories
- Each node includes depth, type, and path information
- Includes comprehensive test coverage

* feat(skill): add file type detection utilities

Implement utilities for file type detection and preview capability checks:
- isPreviewable: checks if file can be previewed based on extension and size
- canPreviewFile: provides detailed reason when file cannot be previewed
- getFileTypeLabel: returns human-readable file type labels
- getFileIcon: maps file types to appropriate Lucide icons
- Supports 1MB max file size limit
- Comprehensive test coverage for all functions

* feat(skill): add file tree node component

Implement recursive FileTreeNodeComponent with:
- Expand/collapse functionality for directories
- File and directory icons from Lucide React
- Hover effects showing file sizes
- Proper indentation based on depth
- Support for nested directory structures

* refactor(skill): upgrade file tree to hierarchical structure

Replace flat file list with tree structure:
- Use buildFileTree to convert flat files into hierarchy
- Integrate FileTreeNodeComponent for rendering
- Update onFileClick to accept FileTreeNode instead of SkillFile
- Add file count badge in header
- Root-level directories expanded by default

* feat(skill): add file preview dialog component

Implement FilePreviewDialog with:
- Markdown rendering via existing MarkdownRenderer
- Plain text/code display with monospace font
- Non-previewable file message with download button
- Copy-to-clipboard and download actions in header
- File path display in footer
- Loading and error states

* feat(i18n): add file tree and preview translations

Add Chinese and English translations for:
- File browser title
- Preview error messages (load failure, too large, binary, unsupported)
- Download file button

* feat(skill): integrate file preview into skill detail page

- Add useSkillFile hook for fetching arbitrary file content
- Add file preview state, click handler, and download handler
- Pass onFileClick to FileTree for opening preview dialog
- Add FilePreviewDialog to skill detail page

* feat(review): add file reading API endpoint

Add GET /api/v1/reviews/{id}/file?path=... for reading single files
from the review-bound skill version:
- ReviewController: new endpoint with path traversal validation
- GovernanceWorkflowAppService: route method for review file access
- ReviewSkillDetailAppService: authorization and delegation
- SkillQueryService: getFileContentByVersionId for direct version access

* feat(review): integrate file preview into review detail

- Add useReviewFile hook for fetching review file content
- Add file preview state and handlers to ReviewSkillDetailSection
- Pass reviewId prop for API calls
- Add FilePreviewDialog to review detail expanded section
- Update review-detail.tsx to pass taskId as reviewId

* fix(test): update test mocks for file preview hooks

- Add useSkillFile mock to skill-detail.test.tsx
- Add useQuery mock to @tanstack/react-query mock
- Add useReviewFile mock to review-skill-detail-section.test.tsx
- Fix SkillFile test fixtures to include all required properties
- Remove unused imports in test and component files

* fix(skill): use DomainBadRequestException for version not found

Replace DomainNotFoundException with DomainBadRequestException in
getFileContentByVersionId to match existing patterns and imports.

* feat(skill): add file tree sidebar with file sizes

- Move file tree to right sidebar for persistent visibility
- Display file sizes always visible (not just on hover)
- Keep Files tab showing the same tree structure
- Add scrollable container with max-height for long file lists

* fix(skill): improve file tree sidebar UI and UX

- Remove redundant title from file tree sidebar
- Adjust scrollbar placement with proper flex layout
- Sort folders first, then files (both alphabetically)
- Collapse all folders by default for cleaner initial view
- Increase dialog width to max-w-5xl and height to 90vh
- Remove duplicate close button (X icon)
- Add hover effects to action buttons
- Use flexbox for proper content scrolling
- Allow .pyc files in backend configuration

Fixes:
1. File tree sidebar now has cleaner layout without title
2. Scrollbar properly contained within card
3. Folders appear before files in tree
4. All folders collapsed by default
5. Preview dialog wider and more usable
6. Single close method (ESC or click outside)
7. Action buttons have visual feedback on hover

* fix(skill): refine file tree sidebar and preview dialog

1. Default all folders to collapsed state
2. File tree sidebar now uses Card+bare pattern matching SecurityAuditSummary
   - Scrollbar inside the card content area instead of wrapping the tree
   - Consistent padding and header layout with other sidebar cards
3. Preview dialog close button fixed:
   - Hide DialogContent's built-in close button via [&>button]:hidden
   - Add X button in the header row, same level as copy/download
   - All action buttons share consistent hover animation (opacity transition)
4. Sort directories before files at every tree level
5. Update tests for new directory-first sort order

* feat(skill): collapsible file browser, wider dialog, button animations

1. File browser sidebar now supports expand/collapse toggle
   - Click the header row to toggle visibility
   - ChevronUp/Down icon indicates state
   - Default expanded on page load

2. File preview dialog widened to 72rem (was 5xl/64rem)
   - Uses w-[min(calc(100vw-2rem),72rem)] for responsive max

3. Header action buttons now have micro-interactions:
   - Copy/Download: scale up on hover, scale down on click
   - Close (X): rotates 90° on hover with destructive tint
   - All buttons: opacity 60→100 transition on hover

* feat(skill): chevron animation, button effects, download path hint, review sidebar

1. File browser chevron: single ChevronDown with rotate-180 CSS transition
   instead of swapping two icons — smooth 200ms rotation animation

2. Preview dialog action button animations:
   - Copy icon: active:scale-125 feedback on click
   - Download icon: hover:translate-y-0.5 subtle downward motion
   - Close icon: hover:rotate-90 with destructive tint (unchanged)

3. Download tooltip now shows full file path:
   "下载 src/prompts/system.md" instead of generic "下载文件"
   - New i18n keys: filePreview.downloadHint, filePreview.copy, filePreview.close

4. Review detail page now has a sidebar file browser:
   - Two-column layout (main content + lg:w-80 sidebar)
   - File tree sourced from reviewSkillDetail.files (active review version)
   - Collapsible with same chevron animation as skill detail page
   - Shows active version badge below file tree
   - File preview uses review file API (/reviews/{id}/file?path=...)
   - Test mocks updated for new useReviewFile dependency

* fix(skill): download shows filename, copy rotates with success toast

1. Download button tooltip/text now shows actual filename:
   "下载 README.md" instead of generic path
   - i18n key changed from {{path}} to {{name}}

2. Copy button animation reworked to rotation:
   - idle: hover:rotate-180 on the Copy icon
   - click: animate-spin during clipboard write
   - done: swap to green Check icon for 1.5s, then reset

3. Copy success toast notification:
   - Shows "已复制到剪贴板" / "Copied to clipboard" via toast.success
   - New i18n key: filePreview.copySuccess

* fix(skill): set download attribute so browser saves with original filename

The <a> element was missing the download attribute, causing the browser
to derive the filename from the URL path segment (/file?path=...) which
always resolved to "file". Now explicitly sets link.download = node.name
so the saved file uses the original name (e.g. README.md, config.json).

Applied to all three download handlers:
- skill-detail.tsx (skill version file)
- review-detail.tsx (review sidebar file)
- review-skill-detail-section.tsx (review expanded section file)

* feat(skill): add icons to all sidebar card headers

Add Lucide icons to each sidebar section for visual consistency
with the existing SecurityAuditSummary (Shield) and file browser (Folder):

- Terminal: Install command
- Clock: Pending review (amber-colored to match card theme)
- RefreshCw: Lifecycle management
- Tag: Label management (in SkillLabelPanel component)
- ArrowUpCircle: Promotion
- ShieldCheck: Governance

All icons use the same pattern: w-4 h-4 text-muted-foreground
placed inside a flex row with gap-2 before the section title.

* fix(skill): allow owners to preview all version statuses

When a skill has only a REJECTED version, the detail page crashed with
400 "版本未发布" because assertPreviewAccessible() only allowed PUBLISHED
and PENDING_REVIEW(owner). The frontend fallback to versions[0] would
pick the REJECTED version and fail all file/readme queries.

Backend changes:
- assertPreviewAccessible(): now allows owners and namespace admins to
  preview ANY version status (DRAFT, REJECTED, YANKED, SCANNING, etc.)
  via canManageRestrictedSkill() check. Also passes userNsRoles so
  namespace admin role is respected, not just owner.
- resolveOwnerPendingPreview(): expanded from PENDING_REVIEW-only to
  include all non-published, non-yanked statuses so headlineVersion
  resolves correctly for owners with REJECTED/DRAFT/SCANNING versions.

Frontend changes:
- isOwnerPreviewResolution(): relaxed from checking PENDING_REVIEW
  specifically to checking any non-PUBLISHED status, matching the
  backend's broader projection.

Fixes: owner viewing skill with only REJECTED version → 400 error
Also fixes: DRAFT-only, SCANNING-only, SCAN_FAILED-only scenarios

* docs(requirements): add comprehensive requirements for file preview syntax highlighting

Generated complete documentation suite including:
- Core PRD (clarity score: 95/100)
- Constraints specification (8 business rules)
- Impact analysis (8 risks identified)
- Acceptance cases (25 test cases: 10 positive, 5 error, 7 boundary, 3 security)
- Test plan (100% coverage)

Mode: Quick (3 clarification rounds)
Complexity: Simple (3.5 days estimated)

* feat(skill): add syntax highlighting for code file preview

Implement syntax highlighting for code files in the file preview dialog:
- Add CodeRenderer component using lowlight (highlight.js wrapper via rehype-highlight)
- Add getLanguageForHighlight() to map file extensions to highlight.js languages
- Support 20+ languages: Python, JS/TS, Java, Go, Rust, C/C++, Ruby, PHP, Shell, JSON, YAML, XML, etc.
- Apply 500KB threshold for syntax highlighting (larger files show plain text)
- Maintain visual consistency with Markdown code blocks
- Auto-adapt to light/dark theme using existing CSS variables
- Add lowlight as direct dependency to enable programmatic syntax highlighting

Implements solution 1 from PRD (reuse rehype-highlight infrastructure).

* fix(security): resolve security audit FK constraint and stale query issues

Backend:
- Add hardDeleteByVersionId to physically remove audit records before
  deleting skill versions (fixes FK constraint violation on hard delete)
- Add softDeleteByVersionId calls in SkillGovernanceService and
  SkillPublishService version deletion paths
- Add V36 migration to convert security_audit TIMESTAMP columns to
  TIMESTAMPTZ matching project convention
- Update tests to verify audit cleanup in all deletion flows

Frontend:
- Prevent stale API calls after skill deletion by gating all query
  hooks with a skillDeleted flag that disables them immediately
- Move cache cleanup from useDeleteSkill onSuccess to the handler
  to avoid refetching while the component is still mounted

* fix(skill): handle SCANNING and SCAN_FAILED statuses across all pages

Backend:
- Include SCANNING/SCAN_FAILED in version listing filters so owners
  can see versions being scanned
- Add explicit lifecycle sort priority for scanner statuses
- Allow deletion of SCAN_FAILED versions alongside DRAFT and REJECTED

Frontend:
- Add i18n labels and CSS classes for SCANNING/SCAN_FAILED in my-skills
- Add localized version status labels in skill-detail version list
- Hide archive button when no published version exists (my-skills and
  skill-detail)
- Allow deleting SCAN_FAILED versions from skill-detail

* gitignore
2026-03-23 14:38:47 +08:00
vsxd
fcfd9b203b fix(review): add pagination and time sorting to audit queues 2026-03-23 14:32:54 +08:00
vsxd
91f547d883 fix(staging): align smoke admin creds and validate label limits 2026-03-23 13:59:45 +08:00
vsxd
ddf9e6e1d2 refactor: address code review findings from 2026-03-22
Implements 6 high-priority improvements from code review:

Backend:
- Make label business limits configurable via application.yml (max-definitions, max-per-skill)

Frontend:
- Split use-skill-queries.ts into domain-specific modules (label/namespace/user/skill)
- Enable @typescript/no-explicit-any as warning and clean up 10 any types
- Unify API error handling by removing unwrap() in favor of fetchJson()

Testing:
- Add label system scenarios to smoke test script
- Add 6 new tests for label management UI (validation, rendering)

All tests passing: 301 backend, 129 frontend
2026-03-23 13:48:23 +08:00
yun-zhi-ztl
6e8b257abb feat(notification): add in-app notifications and harden delivery 2026-03-23 12:31:28 +08:00
XiaoSeS
3bc97ff1b8 feat(security): add security scanning system with multi-scanner support and frontend UI (#144)
* feat(security): extend scanner config with full analyzer options

Integrate skill-scanner's 8 analysis engines and policy configuration
into SkillHub's config system. Operators can now control behavioral,
LLM, Meta, AI Defense, VirusTotal, and trigger analyzers via
application.yml or environment variables.

Changes:
- Add Analyzers and Policy nested classes to SkillScannerProperties
- Create ScanOptions record to encapsulate analyzer flags
- Update SkillScannerService to pass options in /scan body and /scan-upload query params
- Wire ScanOptions through SkillScannerConfig and SkillScannerAdapter
- Extend application.yml with full scanner config block and env var overrides
- Update all tests to verify new configuration flow

All tests pass.

* feat(security): add domain model and integrate scan into publish flow

Add SCANNING/SCAN_FAILED status to SkillVersionStatus. Introduce
SecurityScanService, SecurityScanner port, ScanTask, SecurityAudit
and related domain types. Wire scan trigger into SkillPublishService
so non-auto-publish versions enter scanning when scanner is enabled,
falling back to review task creation when disabled.

* feat(security): add infra layer for scanner HTTP client and adapters

Add WebClient-based HttpClient abstraction with WebClientHttpClient
implementation. Add SkillScannerApiResponse record, SecurityScanException,
and SecurityAuditJpaRepository. Add webflux and test dependencies to
infra module.

* feat(security): add Redis stream consumers, audit API, and DB migration

Add AbstractStreamConsumer base class, ScanTaskConsumer for processing
scan results from Redis stream, and RedisScanTaskProducer. Add
RedisStreamConfig for stream/group initialization. Add SecurityAudit
REST controller and DTO. Add V35 Flyway migration for security_audits
table.

* feat(security): add scanner config to application profiles

Add scanner enabled flag to application-local.yml and
application-test.yml. Enable behavioral analyzer by default
in application.yml.

* feat(deploy): add skill-scanner to docker-compose and k8s manifests

Add skill-scanner service to docker-compose.yml with health check.
Add scanner k8s deployment, service, and configmap entries. Wire
scanner env vars into Makefile dev-all flow. Add verify-scanner.sh
script for post-deploy validation.

* docs(security): add scanner documentation suite

Add scanner docs: configuration guide, failure impact analysis,
monitoring guide, improvement recommendations, custom rules guide,
and skill-vetter rules conversion example. Update deployment docs
with scanner section. Add security-scanning overview and PRD.

* feat(security): add skill-vetter custom rule examples

Add example Regex and YARA rules derived from skill-vetter RED FLAGS
in scanner/examples/vetter-rules/. Includes 7 Regex rules
(signatures-append.yaml) and 3 YARA rules (skillhub_vetter.yara)
covering agent memory theft, IP-based exfiltration, and browser
data theft detection.

* feat(security): add scanner Docker build context

Add Dockerfile for cisco-ai-skill-scanner container and
.env.example with LLM configuration placeholders.

* fix(security): align Finding mapping with scanner API response schema

SkillScannerApiResponse.Finding used incorrect field names (message,
location.file, location.line, code_snippet) that did not match the
scanner's actual JSON output (description, file_path, line_number,
snippet), causing all four fields to deserialize as null.

Flatten Finding to match scanner API: remove nested Location, rename
fields to description/file_path/line_number/snippet. Add skill_name
and timestamp to SkillScannerApiResponse. Extend SecurityFinding with
remediation, analyzer, and metadata fields to capture LLM analyzer
output. Retain 8-arg compact constructor for backward compatibility.

* chore(security): add debug logging to scanner response mapping

Log raw scanner API response and mapped SecurityFinding fields
side-by-side to help verify data consistency between scanner
output and database records.

* feat(security): add multi-scanner support and soft delete for security audits

- Add ScannerType enum for type-safe scanner identification
- Update V35 migration to support multiple scanners and soft delete
- Remove CASCADE delete, use code-level soft delete (deleted_at)
- Add repository methods for querying latest audit by scanner type
- Update SecurityScanService to handle scanner type parameter
- Integrate soft delete in SkillHardDeleteService
- Update all tests to use ScannerType enum

This enables multiple scanner integrations (skill-scanner, future LLM/compliance scanners)
and preserves complete audit history through soft deletion.

* feat(security): add security audit UI to review detail and skill detail pages

Display security scan results on the review detail page (full audit
section with collapsible findings) and the skill detail sidebar (compact
summary with dialog for details).  Handles empty/404 gracefully by
returning null, avoids loading shimmer flicker, and separates lifecycle
action buttons with a visual divider.

* docs(security): add security audit UI PRD

* fix(security): replace LocalDateTime with Instant in security audit and align controller test with list API

SecurityAudit and SecurityScanService used LocalDateTime.now() which
violated the project time guardrail. Replaced with Instant and
Clock.systemUTC() to match existing conventions.

Also fixed SecurityAuditControllerTest to mock the correct repository
method (findLatestActiveByVersionId) and assert against the list
response shape.

* test(security): add useQuery mock for security audit components in frontend tests

The SecurityAuditSummary and SecurityAuditSection components use
useQuery via useSecurityAudits hook, which was missing from the
@tanstack/react-query mocks in skill-detail and review-detail tests.
2026-03-23 09:56:03 +08:00
vsxd
45ef31b12f fix(label): refresh i18n label queries and visible filters 2026-03-20 17:14:23 +08:00