Commit graph

1502 commits

Author SHA1 Message Date
XiaoSeS
5bfc51946c
Merge pull request #925 from X77seven/fix/minio-image-source
fix(deploy): repoint MinIO runtime image to pgsty/silo
2026-10-08 15:20:01 +08:00
XiaoSeS
ee57b85aec fix(deploy): pin Helm image and preserve mirror alias
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-10-08 11:25:46 +08:00
X77
a9f5f0efa3 fix(deploy): repoint MinIO runtime image to pgsty/silo
quay.io/minio/minio returns 401 Unauthorized for anonymous pulls on every
tag, so PR E2E (Real Services) and the Helm S3 smoke test fail before any
test runs. MinIO deleted minio/minio from Docker Hub on 2026-09-11 and
quay.io started requiring authentication on 2026-09-24.

Repoint the three runtime surfaces to pgsty/silo, a maintained MinIO fork
(AGPLv3 - same license as the image currently in use). It is a drop-in:
identical env vars, ports and command. Verified on a GitHub Actions runner
with SkillHub's exact configuration (health endpoints 200, S3 round trip
mb/put/get/ls/rb all pass).

- docker-compose.yml
- deploy/runtime-mirror-images.txt
- charts/skillhub/tests/install-upgrade-smoke.sh

Signed-off-by: X77 <1494159925@qq.com>
2026-10-08 10:51:33 +08:00
XiaoSeS
735259728f
Merge pull request #904 from iflytek/docs/weekly-w39-official-signed
Some checks failed
Deploy Docs / build (push) Has been cancelled
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
Deploy Docs / Deploy (push) Has been cancelled
docs(weekly): publish 2026-W39 report
2026-09-24 18:29:41 +08:00
XiaoSeS
903228b350 docs(weekly): publish 2026-W39 report
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 18:24:38 +08:00
XiaoSeS
455cbb5ba5
Merge pull request #902 from iflytek/feature/enterprise-login-r1b2-org-admin
feat(auth): add organization creation control plane slice
2026-09-24 15:58:57 +08:00
dongmucat
0fd222d1e7
Merge pull request #879 from iflytek/feature/scanner-2-1-upgrade
fix(scanner): harden Scanner 2.1 integration
2026-09-24 15:47:20 +08:00
XiaoSeS
17273bb6ca docs(auth): decouple organization APIs from OIDC controls
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 15:44:56 +08:00
XiaoSeS
1e2de2798b test(auth): verify organization creation rollback
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 15:14:16 +08:00
dongmucat
9f92debf00 fix(scanner): redact mounted route findings
Signed-off-by: dongmucat <1127093059@qq.com>
2026-09-24 15:01:28 +08:00
XiaoSeS
52e4e052a1 feat(auth): add organization creation control plane slice
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 14:43:17 +08:00
XiaoSeS
39a7081ff4
Merge pull request #901 from iflytek/feature/login-page-refresh-pr
feat(auth): refresh login and registration entry
2026-09-24 14:08:33 +08:00
XiaoSeS
e0c5f7597d test(auth): expect home after registration
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 13:53:00 +08:00
XiaoSeS
69192fcf9b test(auth): match theme toggle accessible name
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 13:35:31 +08:00
XiaoSeS
f9e9496053 test(auth): stabilize registration layout screenshot
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 13:35:31 +08:00
XiaoSeS
3000375515 test(auth): cover registration viewport and artwork loading
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 13:35:31 +08:00
XiaoSeS
f8148f28f6 test(auth): cover direct routing and login layout boundaries
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 13:35:30 +08:00
XiaoSeS
e4ee6b6d9a fix(auth): keep login available during session check failures
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 13:35:30 +08:00
XiaoSeS
8249e84454 fix(auth): hide password routing implementation details
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 11:22:43 +08:00
XiaoSeS
0e9d2e2d3e fix(auth): redirect signed-in visitors away from login
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 11:22:43 +08:00
XiaoSeS
5be60043d5 test(auth): select password field precisely
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 10:32:21 +08:00
XiaoSeS
5aea7345b8 test(auth): cover registration and runtime return navigation
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 10:21:38 +08:00
XiaoSeS
1aa8d7bc85 fix(auth): guard registration OAuth hint and return paths
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 10:09:55 +08:00
XiaoSeS
5a8b796d03 fix(auth): defer organization discovery until backend contract
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 09:48:56 +08:00
XiaoSeS
5d4b40a5e5 fix(auth): return to origin or home after login
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-24 09:37:15 +08:00
XiaoSeS
ff077bfbe7 fix(auth): hide unavailable method catalog warning
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-23 17:12:34 +08:00
XiaoSeS
c8e6988485 feat(auth): refresh login and registration entry
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-23 17:02:50 +08:00
XiaoSeS
e8fad5962e
fix(web): refresh API proxy DNS after backend redeploy (#900)
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
* fix(web): refresh API proxy DNS after backend redeploy

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

* test(web): stabilize DNS replacement coverage

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

* test(web): allow early resolver refresh after DNS change

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

* test(web): use dynamic ports for nginx smoke

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

---------

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-23 15:51:08 +08:00
XiaoSeS
ed2ff97d00
Merge pull request #897 from iflytek/feature/enterprise-login-r1b1
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
feat(auth): add organization control-plane read APIs
2026-09-22 17:52:22 +08:00
XiaoSeS
da317d94e9 feat(auth): add organization control-plane read APIs
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 16:38:10 +08:00
XiaoSeS
5f91069cc2
Merge pull request #876 from strawberryOJam/main
docs(readme): fix backend development command
2026-09-22 16:13:27 +08:00
XiaoSeS
cc6e998ea1
Merge pull request #896 from iflytek/feat/identity-provider-adapter-contracts
feat(auth): add identity provider adapter contracts
2026-09-22 16:13:20 +08:00
XiaoSeS
5c629f7cfa
Merge pull request #878 from iflytek/codex/handle/issues-861-853-20260918
feat(builtin-skills): add orca replay and yylo ledger tasks
2026-09-22 16:02:38 +08:00
XiaoSeS
17da5d1e3f feat(auth): validate built-in adapter contracts
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 15:55:56 +08:00
XiaoSeS
4f06e69224 feat(auth): define enterprise identity contracts
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 15:36:55 +08:00
XiaoSeS
5aa038d188 fix(builtin-skills): accept immutable CDN UUID filenames
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 15:27:13 +08:00
XiaoSeS
3de0b94a9a
fix(auth): harden oauth token and claim logging (#895)
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 15:24:31 +08:00
strawberryOJam
9991938983
Merge branch 'iflytek:main' into main 2026-09-22 13:02:30 +08:00
XiaoSeS
8498fd047f
Merge pull request #880 from iflytek/feature/dingtalk-public-provider
feat(auth): add DingTalk as a public login provider (R1-A2)
2026-09-22 11:02:22 +08:00
XiaoSeS
50e7427596 docs(deploy): complete DingTalk private deployment guide
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 10:47:28 +08:00
XiaoSeS
00033b1b92 docs(deploy): document DingTalk egress requirements
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 10:47:28 +08:00
XiaoSeS
36f5f06d9c fix(auth): diagnose DingTalk userinfo failures
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-22 10:47:28 +08:00
XiaoSeS
ca4de37d08 docs(deploy): add DingTalk provider acceptance steps
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 16:08:32 +08:00
XiaoSeS
1297e87c5a fix(deploy): complete DingTalk runtime configuration
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 15:15:41 +08:00
XiaoSeS
d92e1f8216 fix(auth): preserve provider token routing and error bounds
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 15:15:41 +08:00
XiaoSeS
b1f1b18737 fix(auth): stop the DingTalk callback being routed to the OIDC provider
The DingTalk login could not complete. Adding openid to the authorization
request's scope set avoided the nonce at the authorize step but broke the
callback: OAuth2LoginAuthenticationProvider.authenticate returns null when
getScopes() contains "openid", handing the exchange to
OidcAuthorizationCodeAuthenticationProvider, which fails with
invalid_id_token because DingTalk returns no id_token. Neither the token
client nor the user service was ever reached. spring-security-oauth2-jose is
on the runtime classpath, so that provider is registered.

The scope now goes onto the outgoing authorization URI directly, leaving
getScopes() empty. Both openid-keyed mechanisms are then avoided: no nonce,
because the registration still declares no scope in configuration, and no
OIDC routing, because the request carries no openid scope.

The previous test asserted getScopes() contains "openid" -- the exact state
that breaks the callback -- so it locked the bug in. It now asserts the
inverse, and restoring the old implementation makes it fail.

Also switches the registration from client-authentication-method: none to
client-secret-post. "none" made Spring apply PKCE and emit a code_challenge
that DingTalkTokenResponseClient cannot answer, since its JSON token request
sends no code_verifier. It was also semantically wrong: DingTalk is a
confidential client that carries its secret in the request body.

Verified against a local staging instance: the authorization URI now carries
scope=openid with no nonce and no code_challenge, and a callback with a fake
code fails in the token exchange with no OIDC provider involvement in the
logs.

Drops SUBJECT_ATTRIBUTE, which lost its last reference when the user service
stopped pre-resolving the subject.

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 15:15:41 +08:00
XiaoSeS
629c1ced55 fix(auth): bound the DingTalk token response and log a rejected login
Two gaps from reviewing this batch against the Feishu adapter it mirrors.

The token exchange had no response size limit while the userinfo call did,
so the same hostile or misconfigured endpoint was bounded on one call and
unbounded on the other. Adds the same 64 KB cap through a RestTemplate
interceptor, which keeps the existing tests working against an injected
template. buildRestTemplate becomes package-visible so one test can exercise
the production template, cap included; removing the interceptor makes that
test fail.

A missing unionId threw without logging, unlike the equivalent Feishu
branch. This is a reachable failure -- DingTalk omits unionId for some app
configurations -- and an operator seeing every login rejected needs to know
why. Logs the claim name only, which says nothing about the user.

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 15:15:41 +08:00
XiaoSeS
75c7f9a880 feat(deploy): wire DingTalk credentials into the release surfaces
Adds the DingTalk credentials to every path that actually delivers
configuration: compose.release.yml (which has no env_file, so variables must
be listed explicitly), the Helm secret template and values, the k8s
deployment and its secret example. validate-release-config.sh gains DingTalk
in its provider loop, so a half-configured pair is rejected the same way.

Documents the three-stage strategy contract in the authentication design: a
table mapping each deviation -- authorize parameters, token exchange,
userinfo loading -- to its interface and current implementations, plus the
rule that a provider must never make account decisions itself.

Deployment notes and both FAQs now cover DingTalk, including the shared trap
with Feishu: their emails are admin-recorded and never confirmed, so
emailVerified is always false and an EMAIL_DOMAIN access policy would reject
every login through either provider.

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 15:15:41 +08:00
XiaoSeS
96f244b416 feat(auth): add DingTalk as a public login provider
Adds DingTalk (钉钉) as a public sign-in option: it authenticates a SkillHub
platform account and nothing more. No Organization membership, no directory
sync, no Namespace grants.

DingTalk deviates from standard OAuth at all three stages, one strategy each:

- authorize: its endpoint wants scope=openid, but declaring that scope in
  configuration makes Spring treat the registration as OIDC and attach a
  nonce, which DingTalk rejects. The scope is added by
  DingTalkAuthorizationRequestCustomizer instead, keeping this a plain OAuth2
  client. A test asserts the scope is present and the nonce is not.
- token: credentials go in a JSON body rather than a form, handled by
  DingTalkTokenResponseClient.
- userinfo: the token travels in x-acs-dingtalk-access-token rather than
  Authorization: Bearer.

Subject and email semantics, which decide whether a login can reach an
existing account:

- unionId is the only accepted subject. DingTalk also returns openId and
  userId, but they must not act as fallbacks: openId is scoped per app and
  userId per organization, so a login falling back to either would bind a
  different identity than a later login carrying unionId, splitting one
  person across two platform accounts.
- A blank or missing unionId fails the login.
- emailVerified is always false. DingTalk returns the email an organization
  admin recorded without attesting the user controls it.

The userinfo service only fetches attributes; account matching, provisioning
and session creation stay with the unified identity core. The reference
implementation called OAuthLoginFlowService.authenticate() from inside
loadUser, which decided the account before the core's gate ran.

Operational bounds match the Feishu adapter: connect and read timeouts, a
64 KB response cap, error descriptions and logs carrying only the exception
class or provider error code, and no logging in the claims extractor.
Unused PII is dropped rather than carried into the principal -- notably
mobile and stateCode.

Adds ProviderStrategyWiringTest, which loads the real application context.
The unit tests call package-visible constructors and so cannot catch Spring
wiring faults; a component with two constructors and no @Autowired marker
unit-tests green and then fails at startup. That happened during this work.

Adapted from the implementation in #467 by @konglong87, re-extracted onto
current main with the subject, structure and bounds changes above.

Part of R1-A2 (public Provider adapters) per
openspec/changes/enterprise-identity-platform/rollout-plan.md.

Co-authored-by: konglong87 <konglong87@users.noreply.github.com>
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 15:15:41 +08:00
XiaoSeS
5c92c9eeed feat(auth): let providers override token exchange and authorization params
Extends the per-provider strategy pattern from the userinfo step to the two
earlier stages of the authorization-code flow, so a provider whose endpoints
deviate from the standard contract needs no branch in shared code:

- ProviderTokenResponseClient for a non-standard token exchange, dispatched
  by DispatchingTokenResponseClient because Spring's tokenEndpoint accepts
  only one client
- ProviderAuthorizationRequestCustomizer for authorization parameters,
  dispatched through the resolver's existing customizer hook

Registrations without an override keep the standard Spring behaviour.

Together with ProviderOAuth2UserService this covers all three stages where
a provider can deviate: authorize, token, userinfo. Account decisions stay
outside these hooks, in the unified identity core.

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
2026-09-21 15:15:40 +08:00