Commit graph

588 commits

Author SHA1 Message Date
XiaoSeS
f87849fe3e
feat(auth): unified identity core with LEGACY/SHADOW/ACTIVE rollout (#874)
## Summary

Introduces the unified enterprise identity core (R1-A) with LEGACY, SHADOW, and ACTIVE rollout modes, the organization domain model, external identity V2 foundation, and OAuth login routing through the identity core.

## Changes

- **Identity Core** (`skillhub-auth/federation/*`): ExternalIdentityLoginModule, IdentityLoginGuard, IdentityCorrelationPolicy, ProfileAuthorityResolver with LEGACY/SHADOW/ACTIVE mode switching
- **Organization Foundation**: Organization, OrganizationDomain, OrganizationMembership, OrganizationRoleBinding domain model with domain-proof verification
- **External Identity V2**: ExternalIdentity, PreProvisionedLoginSubject, LegacyIdentityBindingDualReader for dual-read compatibility
- **OAuth Routing**: OAuthLoginFlowService routes GitHub/GitLab OAuth through the unified identity core, hardened return-to handling
- **Migrations**: V60-V65 (organization foundation, audit log context, external identity V2, preprovisioned login subject, login correlation policy, legacy backfill)

## Review

-  160 files, +10,311/-26
-  Default LEGACY mode: zero behavior change
-  ACTIVE mode: GitHub & GitLab OAuth login chains verified end-to-end (local staging)
-  SQL migrations V60-V65 applied successfully on PostgreSQL 16
-  Backend tests: 1,010 tests, 0 failures (Java 21)
-  CI: Server Unit Tests  | Web Build  | Docs Build  | E2E  | RISC-V  | DCO 
-  2 minor fixes applied: OAuthIdentityCoreException explicit handling, public OAuth browser endpoint routing

## Rollout

See `openspec/changes/enterprise-identity-platform/rollout-plan.md`.

Made with [Proma](https://proma.cool) · [GitHub](https://github.com/proma-ai/Proma)
2026-09-18 14:34:37 +08:00
XiaoSeS
3680a31a94
fix(skills): serialize concurrent version yank (#875)
* fix(skills): serialize concurrent version yank

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

* test(skills): assert single yank audit and event under contention

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

* test(skills): isolate concurrent yank fixtures

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

* test(skills): verify typed yank event once

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

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-18 09:34:09 +08:00
thiagonogueira
217e7f4042
feat(skills): let skill owners yank a published version (#866)
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 (python) (push) Waiting to run
Security / CodeQL (javascript-typescript) (push) Waiting to run
* feat(auth): expose skill lifecycle routes to API tokens

With an API token, v0.2.19 can remove a whole skill (DELETE
/api/v1/skills/{ns}/{slug} with skill:delete) but cannot archive or
unarchive a skill, nor delete a single draft/rejected version. Those
three routes are opened by AUTHORIZATION_POLICIES (authenticated
fallback) yet have no entry in API_TOKEN_POLICIES, so a bearer request
falls through to "unsupported" and is rejected with 403.

That contradicts the contract written above SESSION_ONLY_ROUTES in
RouteSecurityPolicyRegistry: bearer tokens are rejected on exactly the
listed session-only routes and nowhere else, and anything else the
authorization list opens must be reachable with a token holding the
required scope.

Add API-token policies for both the /api/v1 and /api/web prefixes that
SkillLifecycleController serves:

- POST .../skills/{ns}/{slug}/archive and .../unarchive require
  skill:publish. They are owner-level operations, gated by the same
  assertCanManageLifecycle check as publishing, so they sit at the same
  scope tier.
- DELETE .../skills/{ns}/{slug}/versions/{version} requires
  skill:delete, matching the existing whole-skill delete.

Whole-skill DELETE on /api/web stays session-only as documented; the
new version-delete pattern does not overlap it. No scope allow-list
exists outside the registry (TokenController and ApiTokenScopeService
accept any scope string), so no other change is needed for tokens to
carry these scopes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdnYX4jTS3JwMMP9JCGxzU

* feat(skills): let skill owners yank a published version

Yanking a published version is only available through
POST /api/v1/admin/skills/versions/{versionId}/yank, which is
session-only (SESSION_ONLY_ROUTES covers /api/v1/admin/**) and requires
SKILL_ADMIN or SUPER_ADMIN. A skill owner therefore cannot pull a
broken release themselves, neither from the web surface nor from a
script holding an API token.

In package registries yank is an act of the publisher: `cargo yank`
and PyPI's "yank release" are performed by the package owner, not by a
registry admin, because the goal is to stop new installs of a bad
release while keeping the artifact available for lock files. SkillHub
already lets owners archive, unarchive, rerelease and delete draft
versions through SkillLifecycleController under the
assertCanManageLifecycle rule (owner, or namespace ADMIN/OWNER); yank
belongs on the same surface with the same rule.

Changes:

- SkillGovernanceService: add an owner-checked yankVersion(skill,
  version, actor, roles, ip, ua, reason) that runs
  assertCanManageLifecycle and then the same yank logic as the admin
  variant, now shared in yankVersionInternal. The admin entry point is
  unchanged for AdminSkillController.
- SkillLifecycleAppService / GovernanceWorkflowAppService: resolve
  skill and version by namespace/slug/version, delegate to the new
  domain method, and return SkillLifecycleMutationResponse with action
  YANK and the resulting version status. The YANK_SKILL_VERSION audit
  record and SkillVersionYankedEvent are emitted by the domain service
  exactly as for the admin path.
- SkillLifecycleController: POST /{namespace}/{slug}/versions/{version}/yank
  on both /api/v1/skills and /api/web/skills, optional body
  AdminSkillActionRequest (reason).
- RouteSecurityPolicyRegistry: require skill:yank for the new route on
  both prefixes, so tokens can reach it as the SESSION_ONLY_ROUTES
  comment promises for every route the authorization list opens. The
  admin yank stays session-only. No allow-list of scopes exists outside
  the registry; the docs' scope enumeration is updated to include
  skill:yank.
- Tests: RouteSecurityPolicyRegistryTest (scope required on both
  prefixes, admin route still closed), SkillGovernanceServiceTest
  (owner and namespace ADMIN allowed, MEMBER forbidden, unpublished
  rejected), SkillLifecycleControllerTest (envelope with and without
  body).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdnYX4jTS3JwMMP9JCGxzU

* fix(auth): complete API token lifecycle access

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

* fix(skills): align owner lifecycle token access

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

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: Thiago Nascimento Nogueira <thiago.nascimento.nogueira@emeal.nttdata.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-17 18:48:05 +08:00
thiagonogueira
a59b11b2f0
feat(auth): expose skill lifecycle routes to API tokens (#865)
* feat(auth): expose skill lifecycle routes to API tokens

With an API token, v0.2.19 can remove a whole skill (DELETE
/api/v1/skills/{ns}/{slug} with skill:delete) but cannot archive or
unarchive a skill, nor delete a single draft/rejected version. Those
three routes are opened by AUTHORIZATION_POLICIES (authenticated
fallback) yet have no entry in API_TOKEN_POLICIES, so a bearer request
falls through to "unsupported" and is rejected with 403.

That contradicts the contract written above SESSION_ONLY_ROUTES in
RouteSecurityPolicyRegistry: bearer tokens are rejected on exactly the
listed session-only routes and nowhere else, and anything else the
authorization list opens must be reachable with a token holding the
required scope.

Add API-token policies for both the /api/v1 and /api/web prefixes that
SkillLifecycleController serves:

- POST .../skills/{ns}/{slug}/archive and .../unarchive require
  skill:publish. They are owner-level operations, gated by the same
  assertCanManageLifecycle check as publishing, so they sit at the same
  scope tier.
- DELETE .../skills/{ns}/{slug}/versions/{version} requires
  skill:delete, matching the existing whole-skill delete.

Whole-skill DELETE on /api/web stays session-only as documented; the
new version-delete pattern does not overlap it. No scope allow-list
exists outside the registry (TokenController and ApiTokenScopeService
accept any scope string), so no other change is needed for tokens to
carry these scopes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DdnYX4jTS3JwMMP9JCGxzU

* fix(auth): complete API token lifecycle access

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

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
Co-authored-by: Thiago Nascimento Nogueira <thiago.nascimento.nogueira@emeal.nttdata.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-17 18:17:45 +08:00
Danny
7cf9f22182
feat(cli): add OAuth device flow login (#857)
* feat(cli): add OAuth device flow login

Signed-off-by: Danny5487401 <64348131+Danny5487401@users.noreply.github.com>

* fix(cli): avoid browser launch in headless login

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

* fix(cli): complete device flow runtime path

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

---------

Signed-off-by: Danny5487401 <64348131+Danny5487401@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-09-17 16:29:20 +08:00
XiaoSeS
b4779735bd
feat(suite): publish suites from multi-skill bundles 2026-09-17 11:16:39 +08:00
XiaoSeS
e86c28e3db Merge remote-tracking branch 'origin/pr/844' into codex/validate/pr844-20260910 2026-09-10 16:06:53 +08:00
XiaoSeS
52d899257f
Merge pull request #845 from iflytek/codex/feat/cue-omni-reader-builtin-20260910
feat(starter): add Cue Omni Reader built-in skill
2026-09-10 15:22:42 +08:00
XiaoSeS
7c5b50571b feat(starter): add Cue Omni Reader built-in skill
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-10 14:33:47 +08:00
XiaoSeS
3cbfbc095a feat(starter): initialize SandBase from immutable CDN
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-10 14:31:47 +08:00
XiaoSeS
7d0aedb8d3 test(starter): cover built-in download failure isolation
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-10 11:39:30 +08:00
XiaoSeS
802f8f886f feat(starter): publish Zero Slop runtime package
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-10 11:17:25 +08:00
XiaoSeS
24f07913ac test(suite): cover version validation entry points
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-10 09:13:41 +08:00
XiaoSeS
83ff64d76a fix(suite): validate portable version tokens
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 20:52:15 +08:00
XiaoSeS
d9696be9e4 merge main into feature/skill-suites
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 20:37:53 +08:00
XiaoSeS
0dd694859a fix(suite): close final review gaps
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 20:36:49 +08:00
XiaoSeS
d824a0498c
fix(skill): harden SkillHub CLI guide bootstrap (#842)
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(skill): harden SkillHub CLI guide bootstrap

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

* test(web): support exact preview browser checks

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

* test(skill): enforce guide safety contracts

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

* fix(skill): verify CLI package provenance

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

* test(web): align CLI provenance assertions

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

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 20:25:50 +08:00
XiaoSeS
496e60e08a Merge remote-tracking branch 'origin/main' into feature/skill-suites-signed-final
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>

# Conflicts:
#	web/src/app/router.tsx
#	web/src/pages/search.tsx
2026-09-09 18:47:31 +08:00
XiaoSeS
beecc34b88
feat(web): unify landing, dashboard, and paginated lists (#825)
* feat(web): unify landing and dashboard experience

Closes #824

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

* fix(web): clamp skill card summaries

Keep skill grids compact by reserving a stable three-line summary region while exposing the full description via the title attribute.

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

* test(web): align e2e with redesigned experience

Update real-service E2E assertions for the current landing and dashboard flows, and make settings card headings distinct from their page headings.

Made-with: Proma

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

* Revert "test(web): align e2e with redesigned experience"

This reverts commit 3f78115277.

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

* fix(web): align dashboard layout footer spacing

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

* fix(web): restore footer access links

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

* fix(web): link footer API to Swagger UI

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

* fix(web): refine footer resource links

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

* fix(web): link landing CTA to open source resources

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

* fix(frontend): restore responsive navigation contracts

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

* fix(web): wrap narrow search controls

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

* test(web): derive landing guide origin

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

* fix(web): remove landing statistics strip

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

* test(web): align landing guide assertion

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

* fix(web): address follow-up review feedback

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

* fix(web): update landing CLI version

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

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 18:31:18 +08:00
XiaoSeS
ce4590c50f Merge remote-tracking branch 'origin/main' into feature/skill-suites-signed-final
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 18:23:05 +08:00
XiaoSeS
bf1b293e1f fix(suite): address final review findings
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 18:20:39 +08:00
XiaoSeS
acf4448c6f feat(skill): use latest CLI with registry fallback
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 17:17:26 +08:00
XiaoSeS
f5c554c9bd feat(skill): make first-party CLI own skillhub command
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 15:08:42 +08:00
XiaoSeS
03c1537408 fix(cli): reject stale suite upgrades
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 14:50:42 +08:00
XiaoSeS
d15b2583bc test(suite): cover boundary and multi-target rollback
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 14:37:47 +08:00
XiaoSeS
8c0b853023 fix(suite): close rollout and concurrency gaps
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 13:54:59 +08:00
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
0ce9b8e35a chore(skill): register skillhub cli builtin package
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-09 09:24:21 +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
702a1cc34f perf(governance): batch hidden skill summaries
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-08 11:32:20 +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
1ea1c0867f test(builtin-skills): avoid manifest size coupling
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-04 15:56:00 +08:00
XiaoSeS
9761205e77 feat(builtin-skills): publish plugin scanner artifact
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-04 15:51:31 +08:00
XiaoSeS
7d9ea67169 test(builtin-skills): derive collection size from catalog
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-04 15:25:02 +08:00
XiaoSeS
1b7e679d45 fix(security): include csrf token in scan retry
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-03 19:46:13 +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