Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions deploy/miniapp-market/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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、官网
Expand Down
6 changes: 6 additions & 0 deletions deploy/skin-market/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions src/crates/services/miniapp-market-service/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ struct ListingQuery {
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
struct OAuthStartQuery {
#[serde(alias = "return_to")]
return_to: Option<String>,
}

Expand Down Expand Up @@ -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::<OAuthStartQuery>::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([
Expand Down
8 changes: 7 additions & 1 deletion src/miniapp-market-web/src/api.test.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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',
);
});
});
2 changes: 1 addition & 1 deletion src/miniapp-market-web/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion src/skin-market-web/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)}`;
}
2 changes: 1 addition & 1 deletion src/skin-market-web/src/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
);
});

Expand Down