Commit graph

260 commits

Author SHA1 Message Date
XiaoSeS
2e0cd691aa fix(suite): align super admin member selection
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 13:54:59 +08:00
XiaoSeS
a4b35b236a fix(suite): bind exact members and protect local installs
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 13:54:59 +08:00
XiaoSeS
d0e8c168fa feat(suite): require and expose entry skill
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 13:54:59 +08:00
XiaoSeS
859987e3bb feat(suite): add first-class skill suites
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 19:30:57 +08:00
XiaoSeS
25e18e047c
Merge pull request #829 from iflytek/codex/feat/issue-819-hidden-skill-restore-20260908
fix(governance): restore hidden skill management
2026-09-08 14:35:22 +08:00
XiaoSeS
a6aa073627 fix(validation): preserve wrapper expression boundaries
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 12:25:29 +08:00
XiaoSeS
52969c997c fix(validation): classify bare secrets by file context
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 12:17:03 +08:00
XiaoSeS
8f9db2ada7 fix(validation): scan all sensitive assignments
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 12:03:56 +08:00
XiaoSeS
9d0431f7d3 fix(validation): preserve credential literal boundaries
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 11:45:48 +08:00
XiaoSeS
7c62aa218a fix(validation): avoid regex stack overflow
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 11:34:51 +08:00
XiaoSeS
4efd6c6366 refactor(governance): page hidden skill queries
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 11:27:36 +08:00
XiaoSeS
927780db46 fix(governance): exclude hidden skills from owner list
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 11:19:06 +08:00
XiaoSeS
824a992afc fix(validation): ignore credential expressions
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 11:17:22 +08:00
XiaoSeS
5c5634dd22 fix(governance): restore hidden skill management
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 11:15:04 +08:00
XiaoSeS
fd932cc160 fix(security): require explicit retry locking
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-03 19:45:44 +08:00
XiaoSeS
6770be22c5 test(security): verify retry row locking
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-03 19:45:44 +08:00
XiaoSeS
697bb952a4 fix(security): harden scan retry lifecycle
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-03 19:45:44 +08:00
XiaoSeS
680a5d1b94 feat(security): retry failed scans
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-03 19:45:16 +08:00
XiaoSeS
8b09c23dc4 fix(scanner): make terminal failures recoverable
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-03 19:32:37 +08:00
XiaoSeS
45d341f144
feat(review): add skill comments and user feedback (#793)
* feat(review): add skill review domain model

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

* feat(review): expose skill reviews in API and UI

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

* fix(review): preserve moderation under concurrent edits

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

* fix(review): scope concurrent write conflicts

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

* fix(review): restore web build compatibility

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

* fix(review): keep author cleanup available

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

* fix(review): preserve author cleanup access

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

* fix(review): require review score contract

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

* test(review): strengthen failure and concurrency coverage

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

* test(review): tighten persistence assertions

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

* test(review): disambiguate repository ports

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

* fix(review): enable request validation

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

* test(review): align validation and postgres coverage

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

* test(namespace): verify invalid batch has no side effects

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

* test(web): align accessibility and plural assertions

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

* test(i18n): require complete plural references

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

* fix(review): wrap editor actions on mobile

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

* fix(review): wrap long mobile labels

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

* fix(review): disable edits for archived skills

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

* fix(review): enforce archived mutation guard

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

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-02 11:15:52 +08:00
XiaoSeS
3e77365a5d fix(review): complete progress history workflow
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-01 17:53:41 +08:00
XiaoSeS
7995c00683 feat(review): add author review progress and attempt history
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-01 17:53:41 +08:00
XiaoSeS
a73997c672
Merge pull request #784 from iflytek/fix/concurrent-publish-coordinate-race
fix(publish): return deterministic conflict on concurrent coordinate race
2026-08-31 18:47:19 +08:00
XiaoSeS
182f7bacef fix(publish): flush concurrent coordinate writes
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-31 16:30:33 +08:00
XiaoSeS
d1cd3d2afe
Merge pull request #782 from FenjuFu/fix/audit-detail-json
fix(audit): render audit detail JSON with Jackson instead of string concatenation
2026-08-31 15:24:06 +08:00
XiaoSeS
49ef09d989
Merge pull request #773 from FenjuFu/fix/publish-case-insensitive-whitelist
fix(publish): match allowed filenames case-insensitively
2026-08-31 15:19:52 +08:00
FenjuFu
d224c5a8ba fix(publish): return deterministic conflict on concurrent coordinate race
Concurrent publishes for the same (namespace_id, slug, owner_id) or
(skill_id, version) coordinate both pass the check-then-create reads and
race on the database unique constraints. The losing request surfaced an
unhandled DataIntegrityViolationException as HTTP 500.

Translate the constraint violation at both insert points into a
deterministic DomainBadRequestException (error.skill.publish.concurrentConflict),
matching the existing idiom in LabelDefinitionService/ReviewService/
PromotionService. No same-transaction re-read is attempted, so the losing
publish rolls back cleanly and returns a retryable conflict instead of a 500.

Add the i18n key (en/zh) and two unit tests covering the skill-insert and
version-insert races.

Closes #617

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-08-31 14:27:45 +08:00
XiaoSeS
9f3b10d27a test(publish): cover case-insensitive whitelist variants
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-31 14:00:45 +08:00
FenjuFu
215ab11b09 fix(audit): render audit detail JSON with Jackson instead of concatenation
audit_log.detail_json is a JSONB column, so the value has to be valid
JSON or the insert fails. It was built by string concatenation at every
call site, with three inconsistent levels of escaping: none at all in
ClawHubCompatAppService, DeviceAuthWebController, LabelAdminAppService
and SkillLabelAppService; quotes only in ReviewPortalAppService,
SkillLifecycleAppService, NamespaceGovernanceService and
SkillGovernanceService; quotes and backslashes in
PromotionPortalAppService.escapeJson.

None of the three escapes control characters, which JSON forbids raw
inside a string. A reviewer pressing Enter in a review comment therefore
produced a payload PostgreSQL rejects, and because the audit write
happens after the domain mutation, the review was already approved when
the request returned 500.

Add AuditDetail, which renders the payload through Jackson, and route
all 29 construction sites through it. 17 of those interpolate a string
value and are the actual defect surface; the numeric and constant ones
are converted too so there is one way to build audit detail and no
hand-rolled example left to copy.

SkillHardDeleteService.toAuditPayload already did this correctly with a
LinkedHashMap and an ObjectMapper; AuditDetail is that shape extracted.
The service itself is left alone rather than changing its constructor
signature for no behavior gain.

Output is byte-identical for values that were already escaped correctly,
so the existing exact-string assertions in AdminSearchControllerTest and
PromotionPortalAppServiceTest are unchanged. null still means "no
detail": the builder returns null rather than {} when no field is set.

Addresses the JSON half of #615. The transaction half -- the domain
mutation and the audit write not sharing one transaction -- is a
separate design decision about whether an audit failure should roll back
a review, and is not bundled here.

Signed-off-by: FenjuFu <fufenjupku@gmail.com>
2026-08-30 18:39:48 +08:00
XiaoSeS
2babc0935b fix(cli): add namespace sync manifest endpoint
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-29 14:06:34 +08:00
FenjuFu
e9ac6c162a fix(publish): match allowed filenames case-insensitively
Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-08-28 17:57:01 +08:00
XiaoSeS
f993ad6533
Merge pull request #712 from Vast-Stars/feat/personal-namespace-provisioning
feat(namespace): auto-provision a personal namespace on registration
2026-08-28 17:04:21 +08:00
XiaoSeS
eeb63613f2 fix(namespace): enable personal provisioning by default 2026-08-28 16:42:26 +08:00
XiaoSeS
ee0f0763db refactor(namespace): keep personal provisioning configuration-only 2026-08-28 15:55:29 +08:00
XiaoSeS
7beb1be356 fix(namespace): skip system accounts during provisioning 2026-08-28 15:27:39 +08:00
XiaoSeS
04bb414b37 fix(namespace): use stable random personal namespace slugs 2026-08-28 15:19:56 +08:00
XiaoSeS
dc31bb97f4 Revert "feat(namespace): backfill personal namespaces for existing accounts"
This reverts commit 2d50437e4f.
2026-08-28 15:19:56 +08:00
XiaoSeS
fbf6887e9d Revert "fix(namespace): stop the backfill from querying with a null keyword"
This reverts commit 639e081ca7.
2026-08-28 15:19:56 +08:00
XiaoSeS
eba2762b5b Revert "feat(namespace): let operators choose which namespaces new accounts join"
This reverts commit a9e7f43e5a.
2026-08-28 15:19:56 +08:00
XiaoSeS
c825d896a4
Merge pull request #762 from FenjuFu/fix/code-scanning-alerts-2026-08
fix(security): resolve CodeQL findings
2026-08-28 10:22:04 +08:00
XiaoSeS
a3d1b4c9c5 test(subscription): remove unrelated confirm-publish assertions
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-27 16:56:01 +08:00
XiaoSeS
126f01d75e fix(subscription): retain yank visibility context
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-27 16:50:37 +08:00
XiaoSeS
1331667496 fix(subscription): reuse visibility policy and localize denial
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-27 16:45:55 +08:00
千乘妍 (Xiaoyaner)
bacfd58aa0 fix: emit confirm-publish events with permission-aware subscriber fanout
Signed-off-by: 千乘妍 (Xiaoyaner) <258399167+xiaoyaner0201@users.noreply.github.com>
2026-08-27 16:43:32 +08:00
FenjuFu
36967794d1 fix(security): resolve CodeQL findings
Use a bounded safe YAML constructor, remove the polynomial placeholder regex, keep public label access GET-only with CSRF protection, validate CLI callbacks as loopback URL objects, and use cryptographic UUIDs for E2E identities.

Signed-off-by: FenjuFu <92919259+FenjuFu@users.noreply.github.com>
2026-08-27 15:16:54 +08:00
bbdu3
95e630c096
fix(scan): prevent scan tasks from being lost after transaction commit
Some checks are pending
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
Preserve scan delivery on lock contention through the retry path and add reclaim regression coverage.
2026-08-26 17:46:16 +08:00
FenjuFu
91d0ae1504
feat(api): return skill labels from the skill listing endpoints on request (#730)
* feat(api): return skill labels from the skill listing endpoints on request

Skill labels were reachable only one skill at a time, through
/api/{v1,web}/skills/{namespace}/{slug}/labels, so a client rendering a list had
to issue a follow-up request per row.

Add includeLabels=true to GET /api/v1/skills and GET /api/web/skills. The labels
array is populated only when the parameter is set and left out of the payload
otherwise, so existing responses are byte-identical.

Labels for the whole page are resolved by SkillLabelProjectionService in three
queries — assignments, definitions, translations — rather than three per skill.

Closes #710

Signed-off-by: FenjuFu <fufenjupku@gmail.com>

* fix(api): use include parameter for skill labels

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

* test(api): reject unsupported include before search

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

---------

Signed-off-by: FenjuFu <fufenjupku@gmail.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-25 13:49:24 +08:00
XiaoSeS
15ce199e1a
fix(publish): emit event on confirm publish (#738)
Some checks are pending
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
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-21 17:52:25 +08:00
FenjuFu
51457bfa2c
fix(security): 扫描任务改为事务提交后发布 (Closes #612) (#733)
* fix(security): publish scan task after transaction commit

SecurityScanService.triggerScan is @Transactional but published the Redis
Stream scan task inline, before the transaction committed. The stream
consumer could receive the task before the skill_version / security_audit
rows were visible, fail with "SkillVersion not found" / "SecurityAudit not
found", exhaust its immediate retries while the publishing transaction was
still open, and leave the committed version stuck in SCANNING.

Defer the publish to an afterCommit transaction synchronization so the
consumer only ever sees the task once the rows are committed and visible; on
rollback the task is never published. Falls back to an inline publish when
called outside a transaction.

Closes #612

Signed-off-by: FenjuFu <fufenjupku@gmail.com>

* test(security): cover scan task after-commit publishing

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

* refactor(security): hide scan publish transaction callback

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

---------

Signed-off-by: FenjuFu <fufenjupku@gmail.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-08-21 14:18:40 +08:00
青柠
a9e7f43e5a feat(namespace): let operators choose which namespaces new accounts join
A deployment that stands up its own organisation-wide namespace — to use
instead of the built-in global one — finds it invisible to everybody. The
namespace listing only returns namespaces the caller belongs to, and the
only thing that ever added members automatically was hard-wired to the slug
"global".

Make that list a setting. namespace.default-membership holds the slugs every
newly activated account is enrolled in, defaulting to ["global"], which is
what every deployment did before. Publishing only requires membership of any
role, so being enrolled is enough to publish there; no extra grant needed.

GlobalNamespaceMembershipService becomes DefaultNamespaceMembershipService,
since it no longer means one specific namespace.

Where the strictness sits:

- Saving validates every slug resolves to an ACTIVE namespace, so a typo
  fails at the moment an administrator makes it.
- Enrolling tolerates a slug that no longer resolves: it logs and skips.
  A namespace that was deleted or renamed must not cost somebody their
  login.

Adding a namespace to the list after people have signed up leaves them out,
the same trap the personal-namespace work hit, so this ships with the same
preview-then-apply backfill.

Verified against a real PostgreSQL, end to end: create a namespace, reject an
unknown slug, save with whitespace and duplicates and see them normalised,
preview, apply, re-preview showing nothing left, and a fresh registration
landing in the global namespace, the new shared one, and its own personal one
at once.
2026-08-16 20:31:46 +08:00