diff --git a/deploy/miniapp-market/README.md b/deploy/miniapp-market/README.md index 2a64ce1c99..80d9d27bea 100644 --- a/deploy/miniapp-market/README.md +++ b/deploy/miniapp-market/README.md @@ -28,6 +28,11 @@ MiniApp 市场网页源码在 `src/miniapp-market-web/`,后端入口在 不要单独上传 `dist/`,也不要在服务器上直接改源码。 +Skin 市场复用本服务的 GitHub OAuth、桌面 token 和 Web 会话别名。修改 +`miniapp-market-service/src/auth.rs`、`routes.rs` 或 OAuth 回跳参数时,必须同时 +验证 Skin 的“我的投稿”和“审核”接口;Skin 容器只能通过它自己的部署手册和 +专用 checkout 更新,不能从 MiniApp Compose 项目重建。 + ## 生产边界 本目录只能部署 MiniApp 市场。不得修改、清理或重启现有 Relay、New API、官网 diff --git a/deploy/skin-market/README.md b/deploy/skin-market/README.md index 8017a5c086..b325b64168 100644 --- a/deploy/skin-market/README.md +++ b/deploy/skin-market/README.md @@ -23,6 +23,12 @@ use the MiniApp auth broker and a `/skin`-scoped alias of that broker's Web session. Unsafe browser requests require the matching CSRF alias. Never copy the MiniApp OAuth secret into the Skin environment. +The MiniApp identity service must run a commit that implements the same shared +account contract as Skin. Changes under `miniapp-market-service/src/auth.rs` or +its OAuth routes must be deployed with the MiniApp runbook before Skin is +considered healthy. Deploy the two containers separately from their dedicated +checkouts; do not recreate MiniApp from the Skin Compose project. + ## Agent safety contract 1. Deploy only a committed, explicit commit. Never build a dirty checkout or a diff --git a/src/crates/services/miniapp-market-service/src/routes.rs b/src/crates/services/miniapp-market-service/src/routes.rs index bc1ff08023..bfd4686714 100644 --- a/src/crates/services/miniapp-market-service/src/routes.rs +++ b/src/crates/services/miniapp-market-service/src/routes.rs @@ -70,6 +70,7 @@ struct ListingQuery { #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct OAuthStartQuery { + #[serde(alias = "return_to")] return_to: Option, } @@ -2053,6 +2054,17 @@ mod tests { use axum::http::HeaderValue; use std::collections::HashSet; + #[test] + fn oauth_start_query_accepts_canonical_and_legacy_return_target_names() { + for parameter in ["returnTo", "return_to"] { + let uri = format!("/auth/github/start?{parameter}=%2Fskin%2Fadmin") + .parse() + .unwrap(); + let Query(query) = Query::::try_from_uri(&uri).unwrap(); + assert_eq!(query.return_to.as_deref(), Some("/skin/admin")); + } + } + #[test] fn review_diff_covers_added_changed_and_removed_files() { let previous = BTreeMap::from([ diff --git a/src/miniapp-market-web/src/api.test.ts b/src/miniapp-market-web/src/api.test.ts index 1f144e1f87..7e24318b2e 100644 --- a/src/miniapp-market-web/src/api.test.ts +++ b/src/miniapp-market-web/src/api.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; import listingFixture from '../../shared/miniapp-market-contract-fixtures/listing-detail.json'; -import { downloadUrl } from './api'; +import { downloadUrl, loginUrl } from './api'; import type { MarketListingDetail } from './types'; const typedListingFixture: MarketListingDetail = listingFixture; @@ -16,4 +16,10 @@ describe('market API paths', () => { expect(typedListingFixture.permissions.node?.enabled).toBe(false); expect(typedListingFixture.releases[0].reviewBundleHash).toHaveLength(64); }); + + it('uses the broker camelCase return target contract', () => { + expect(loginUrl('/miniapp/admin')).toBe( + '/miniapp/api/v1/auth/github/start?returnTo=%2Fminiapp%2Fadmin', + ); + }); }); diff --git a/src/miniapp-market-web/src/api.ts b/src/miniapp-market-web/src/api.ts index e62cfda960..dcebaeb18b 100644 --- a/src/miniapp-market-web/src/api.ts +++ b/src/miniapp-market-web/src/api.ts @@ -136,7 +136,7 @@ export const marketApi = { }; export function loginUrl(returnTo = window.location.pathname): string { - return `${API}/auth/github/start?return_to=${encodeURIComponent(returnTo)}`; + return `${API}/auth/github/start?returnTo=${encodeURIComponent(returnTo)}`; } export function downloadUrl(slug: string, release: number): string { diff --git a/src/skin-market-web/src/account.ts b/src/skin-market-web/src/account.ts index e501cf7bfd..d6f8a8ffa2 100644 --- a/src/skin-market-web/src/account.ts +++ b/src/skin-market-web/src/account.ts @@ -66,5 +66,5 @@ export const sharedMarketAccountApi = { export function sharedMarketLoginUrl( returnTo = `${window.location.pathname}${window.location.search}`, ): string { - return `${SHARED_ACCOUNT_API_BASE}/auth/github/start?return_to=${encodeURIComponent(returnTo)}`; + return `${SHARED_ACCOUNT_API_BASE}/auth/github/start?returnTo=${encodeURIComponent(returnTo)}`; } diff --git a/src/skin-market-web/src/api.test.ts b/src/skin-market-web/src/api.test.ts index 18ba5c56f0..121a62c041 100644 --- a/src/skin-market-web/src/api.test.ts +++ b/src/skin-market-web/src/api.test.ts @@ -48,7 +48,7 @@ describe('Skin Market API paths', () => { it('uses the MiniApp auth broker and returns to the current Skin route', () => { expect(sharedMarketLoginUrl('/skin/appearances/ocean-night?q=dark')).toBe( - '/miniapp/api/v1/auth/github/start?return_to=%2Fskin%2Fappearances%2Focean-night%3Fq%3Ddark', + '/miniapp/api/v1/auth/github/start?returnTo=%2Fskin%2Fappearances%2Focean-night%3Fq%3Ddark', ); });