diff --git a/.dockerignore b/.dockerignore
index 44a42d80f..80946a347 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -21,4 +21,8 @@
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
-LICENSE
\ No newline at end of file
+LICENSE
+
+# 仓库根本地配置与 IDE 用户状态不进入构建上下文(镜像配置来自 GameFrameX.Config/json 与运行时挂载)
+Configs/
+Server.sln.DotSettings.user
\ No newline at end of file
diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml
index 70d4f1398..e3189467d 100644
--- a/.github/workflows/docs-publish.yml
+++ b/.github/workflows/docs-publish.yml
@@ -8,14 +8,16 @@ on:
jobs:
build:
runs-on: ubuntu-latest
+ permissions:
+ contents: write
steps:
- name: Checkout Repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Setup .NET Core
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
@@ -31,7 +33,7 @@ jobs:
docfx build docfx.json
- name: Deploy to GitHub Pages
- uses: peaceiris/actions-gh-pages@v3
+ uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/_site
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 58089c07f..df9af6399 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,8 +9,12 @@ on:
jobs:
release:
+ # GITHUB_TOKEN 权限由复用工作流内部统一声明(contents: write / packages: write),调用方无需重复声明。
uses: GameFrameX/public-github-actions/.github/workflows/publish-dotnet-release.yml@main
with:
dotnet_version: "10.0.x"
version_props_path: "Version.props"
+ # 上游 publish-dotnet-release.yml 未声明 on.workflow_call.secrets
+ # (NUGET_API_KEY / DOCKERHUB_* / BLUESKY_APP_PASSWORD 靠 inherit 透传),
+ # 改显式列表会导致发布链路拿不到凭据;如需收敛,先在 public-github-actions 补 secrets 声明。
secrets: inherit
diff --git a/.github/workflows/sonar-issues.yml b/.github/workflows/sonar-issues.yml
index 9429e5861..e23a35168 100644
--- a/.github/workflows/sonar-issues.yml
+++ b/.github/workflows/sonar-issues.yml
@@ -23,4 +23,5 @@ jobs:
sonar_organization: ${{ vars.SONAR_ORGANIZATION || 'gameframex' }}
sonar_branch: main
github_repository: ${{ github.repository }}
- secrets: inherit
+ secrets:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
index 4acc4b026..03206c563 100644
--- a/.github/workflows/sync.yml
+++ b/.github/workflows/sync.yml
@@ -5,10 +5,16 @@ on:
branches: [main]
workflow_dispatch:
+# 镜像同步仅需读取仓库信息(Gitee/CNB 推送走专用 token)
+permissions:
+ contents: read
+
jobs:
sync:
uses: GameFrameX/public-github-actions/.github/workflows/sync.yml@main
with:
target_branch: ${{ github.ref_name }}
repository_name: ${{ github.repository }}
+ # 上游 sync.yml 未声明 on.workflow_call.secrets(GITEE/CNB token 靠 inherit 透传),
+ # 改显式列表会导致同步链路拿不到凭据;如需收敛,先在 public-github-actions 补 secrets 声明。
secrets: inherit
diff --git a/.github/workflows/topology-equivalence.yml b/.github/workflows/topology-equivalence.yml
index 5d6aa18bb..f5d989b00 100644
--- a/.github/workflows/topology-equivalence.yml
+++ b/.github/workflows/topology-equivalence.yml
@@ -17,6 +17,8 @@ on:
jobs:
topology-equivalence:
runs-on: ubuntu-latest
+ permissions:
+ contents: read
services:
mongo:
image: mongo:7
@@ -44,10 +46,10 @@ jobs:
GAMEFRAMEX_TEST_POSTGRESQL_CONNECTION_STRING: 'Host=localhost;Port=5432;Username=postgres;Password=postgres;Database=postgres'
steps:
- name: Checkout Repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v7
- name: Setup .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v6
with:
dotnet-version: 10.0.x
diff --git a/.gitignore b/.gitignore
index 399adfb6f..9cce5578a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,8 @@ gfx-doc
# C221:gfx-role 模板产出的 .proto 源暂存(移入 Protobuf 仓后即弃,不入库)
scripts/scaffold-out/
+
+# 本地环境变量(compose 凭据注入用),不入库
+.env
+.env.*
+!.env.example
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e09ac4920..4fbc57fe5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,13 @@
* GameFrameX.Foundation.Logger ≥ 4.1.1 的 nuspec 无条件声明 MongoDB.Driver 与 Serilog.Sinks.MongoDB(运行时 IsWriteToMongoDb 默认关闭)。已解除——Foundation 5.0.0 将 Mongo/Loki sink 拆为可选组件包,随 C224 全量升级后传递依赖归零,验证 feed 补丁包不再需要
## [Unreleased]
+### Security(仓库与部署面修复)
+
+* 默认编排与 CI 供应链收紧:docker-compose.yml 的 Mongo 端口绑定 127.0.0.1;docker-compose.multi.yml 12 个实例的 TCP/HTTP 端口改由生成器统一绑定 127.0.0.1;GitHub Actions 升级至当前最新 major(actions/checkout v7、actions/setup-dotnet v6、peaceiris/actions-gh-pages v4),docs-publish / topology-equivalence / sync 显式声明最小 permissions,sonar-issues 改显式传 SONAR_TOKEN(release / sync 因上游 public-github-actions 未声明 on.workflow_call.secrets 暂保留 secrets: inherit,已在文件内注释说明);.gitignore 补 .env / .env.* 排除;.dockerignore 排除仓库根 Configs/ 与 IDE 用户设置;deploy-game.sh 含凭据请求体改用 mktemp 私有临时文件并 trap 退出清理(不再落可预测的 /tmp/deploy-body.json)
+
+### Changed
+
+* Dockerfile 构建层优化:restore 前先分层 COPY 全部工程与属性文件(仅项目结构/版本清单变化才重新 restore,源码变更实测 restore 层命中 CACHED);删除 final 阶段重复的 publish COPY;热更 DLL 同步移除 `|| true` 吞错(glob 未匹配或复制失败改为构建期 fail fast);scripts/acceptance.sh 仓库根改为按脚本自身位置推导并修正解决方案为 Server.slnx(原硬编码个人绝对路径且引用已不存在的 Server.sln)
### Fixed
* HTTP 请求管线正确性与响应一致性(C458,GFX-1180,GitHub #926):ProtoBuf 成功响应写出前更正 Content-Type 为 `application/x-protobuf`(原恒为 JSON,按媒体类型分派的客户端/网关解析二进制体失败);参数字典改 OrdinalIgnoreCase 并同步把 Query 提取改 TryAdd——大小写差异同名键(Query↔Body、Query↔Query)一律显式 `ParamErr` 拒绝,消除「被校验/被签名的 Query 值被 Body 静默覆盖」窗口;非 JSON 对象 Body(null 字面量/数组/标量/空体)以参数错误拒绝(新键 `Network.Http.RequestBodyNotJsonObject`),不再落入顶层 catch 记服务器错误日志;非 GET 缺 Content-Type 改统一 JSON envelope;DataAnnotations 校验失败业务码由字面量 400 统一为 `GameHttpStatusCode.ParamErr`;Swagger 路由匹配改末段精确比较(互为后缀命令不再错配文档,驼峰路由可匹配)且 GET 参数必填性跟随 `RequiredAttribute`;AOP 拒绝且未自行写响应时管线回写校验失败 envelope(契约写入 `IHttpAopHandler.Run`);`CheckSign` 缺 sign/timestamp 改本地化消息。对外破坏性:依赖 `code == 400` 判定校验失败的客户端改判 `code == 13`;`HttpStatusMessage.Success`/`NotFoundCommand`/`CheckFailedCommand` 及孤儿键 `Network.Http.NotFoundCommand`/`CheckFailedCommand` 删除(公共 API,下游如有引用需迁移)。
diff --git a/Dockerfile b/Dockerfile
index b352aa1ed..05ca3bfcc 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,9 +6,46 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
-COPY . .
+# 先复制 restore 所需的工程与属性文件:仅当项目结构/版本清单变化时才重新 restore,源码变更不再使依赖层缓存失效
+COPY Directory.Build.props Directory.Build.targets Version.props global.json ./
+COPY Capability/GameFrameX.Capability.Hosting.Abstractions/GameFrameX.Capability.Hosting.Abstractions.csproj Capability/GameFrameX.Capability.Hosting.Abstractions/
+COPY Capability/GameFrameX.Capability.Hosting.AdminApi/GameFrameX.Capability.Hosting.AdminApi.csproj Capability/GameFrameX.Capability.Hosting.AdminApi/
+COPY Capability/GameFrameX.Capability.Hosting.Core/GameFrameX.Capability.Hosting.Core.csproj Capability/GameFrameX.Capability.Hosting.Core/
+COPY Capability/GameFrameX.Capability.Online.Abstractions/GameFrameX.Capability.Online.Abstractions.csproj Capability/GameFrameX.Capability.Online.Abstractions/
+COPY Capability/GameFrameX.Capability.Online.Assets/GameFrameX.Capability.Online.Assets.csproj Capability/GameFrameX.Capability.Online.Assets/
+COPY Capability/GameFrameX.Capability.Online.Competition/GameFrameX.Capability.Online.Competition.csproj Capability/GameFrameX.Capability.Online.Competition/
+COPY Capability/GameFrameX.Capability.Online.Foundation/GameFrameX.Capability.Online.Foundation.csproj Capability/GameFrameX.Capability.Online.Foundation/
+COPY Capability/GameFrameX.Capability.Online.Match/GameFrameX.Capability.Online.Match.csproj Capability/GameFrameX.Capability.Online.Match/
+COPY Capability/GameFrameX.Capability.Online.Matchmaking/GameFrameX.Capability.Online.Matchmaking.csproj Capability/GameFrameX.Capability.Online.Matchmaking/
+COPY Capability/GameFrameX.Capability.Online.Operations/GameFrameX.Capability.Online.Operations.csproj Capability/GameFrameX.Capability.Online.Operations/
+COPY Capability/GameFrameX.Capability.Online.Persistence/GameFrameX.Capability.Online.Persistence.csproj Capability/GameFrameX.Capability.Online.Persistence/
+COPY Capability/GameFrameX.Capability.Online.Social/GameFrameX.Capability.Online.Social.csproj Capability/GameFrameX.Capability.Online.Social/
+COPY GameFrameX.Apps/GameFrameX.Apps.csproj GameFrameX.Apps/
+COPY GameFrameX.Architecture.Analyzers/GameFrameX.Architecture.Analyzers.csproj GameFrameX.Architecture.Analyzers/
+COPY GameFrameX.Client/GameFrameX.Client.csproj GameFrameX.Client/
+COPY GameFrameX.Config/GameFrameX.Config.csproj GameFrameX.Config/
+COPY GameFrameX.Core/GameFrameX.Core.csproj GameFrameX.Core/
+COPY GameFrameX.DataBase/GameFrameX.DataBase.csproj GameFrameX.DataBase/
+COPY GameFrameX.DataBase.Mongo/GameFrameX.DataBase.Mongo.csproj GameFrameX.DataBase.Mongo/
+COPY GameFrameX.DataBase.PostgreSql/GameFrameX.DataBase.PostgreSql.csproj GameFrameX.DataBase.PostgreSql/
+COPY GameFrameX.DataBase.Sqlite/GameFrameX.DataBase.Sqlite.csproj GameFrameX.DataBase.Sqlite/
+COPY GameFrameX.Discovery/GameFrameX.Discovery.csproj GameFrameX.Discovery/
+COPY GameFrameX.Hotfix/GameFrameX.Hotfix.csproj GameFrameX.Hotfix/
+COPY GameFrameX.Hotfix.WrapperGenerator/GameFrameX.Hotfix.WrapperGenerator.csproj GameFrameX.Hotfix.WrapperGenerator/
+COPY GameFrameX.Launcher/GameFrameX.Launcher.csproj GameFrameX.Launcher/
+COPY GameFrameX.Localization/GameFrameX.Localization.csproj GameFrameX.Localization/
+COPY GameFrameX.Network.Abstractions/GameFrameX.Network.Abstractions.csproj GameFrameX.Network.Abstractions/
+COPY GameFrameX.Network/GameFrameX.Network.csproj GameFrameX.Network/
+COPY GameFrameX.Network.HTTP/GameFrameX.Network.HTTP.csproj GameFrameX.Network.HTTP/
+COPY GameFrameX.Network.RemoteMessaging/GameFrameX.Network.RemoteMessaging.csproj GameFrameX.Network.RemoteMessaging/
+COPY GameFrameX.Proto/GameFrameX.Proto.csproj GameFrameX.Proto/
+COPY GameFrameX.ProtoBuf.Net/GameFrameX.ProtoBuf.Net.csproj GameFrameX.ProtoBuf.Net/
+COPY GameFrameX.StartUp/GameFrameX.StartUp.csproj GameFrameX.StartUp/
+COPY GameFrameX.Templates/GameFrameX.Templates.csproj GameFrameX.Templates/
+COPY GameFrameX.Utility/GameFrameX.Utility.csproj GameFrameX.Utility/
RUN dotnet restore "GameFrameX.Launcher/GameFrameX.Launcher.csproj"
RUN dotnet restore "GameFrameX.Hotfix/GameFrameX.Hotfix.csproj"
+COPY . .
WORKDIR "/src/GameFrameX.Launcher"
RUN dotnet build "GameFrameX.Launcher.csproj" -c $BUILD_CONFIGURATION -o /app/build
@@ -32,15 +69,12 @@ COPY GameFrameX.Config/json ./json
RUN mkdir -p /app/hotfix
COPY --from=publish /app/build/hotfix/ /app/hotfix/
# 热更依赖加载逻辑默认从 /app 根目录查找引用程序集,这里同步 DLL 到根目录
-RUN cp -f /app/hotfix/*.dll /app/ || true
+RUN cp -f /app/hotfix/*.dll /app/
# 切换到root用户:创建数据目录(归属 $APP_UID,非 root 运行用户可写——SQLite 缺省文件 data/gameframex.db 落此)、写入入口脚本并赋权
USER root
RUN mkdir -p /app/data && chmod 755 /app/data && chown $APP_UID:0 /app/data
-# 复制发布文件
-COPY --from=publish /app/publish .
-
# 单一镜像多角色:镜像不固化、不检查任何业务参数。
# 启动参数由 GAMEFRAMEX_SERVER_ARGS 环境变量原样透传(含 --ServerType / --DataBaseUrl 等完整参数),
# 未设置时不传参数,由应用默认逻辑启动首个可用服务器。
diff --git a/GameFrameX.Network.RemoteMessaging/Transport/DeflateMessageCompressionAlgorithm.cs b/GameFrameX.Network.RemoteMessaging/Transport/DeflateMessageCompressionAlgorithm.cs
index 6bb7fd651..e42d412f2 100644
--- a/GameFrameX.Network.RemoteMessaging/Transport/DeflateMessageCompressionAlgorithm.cs
+++ b/GameFrameX.Network.RemoteMessaging/Transport/DeflateMessageCompressionAlgorithm.cs
@@ -81,7 +81,7 @@ public byte[] Compress(byte[] input)
/// 允许的最大解压输出字节数 / Maximum allowed decompressed output length in bytes
/// 解压后的原始字节数组 / The decompressed byte array
/// 压缩数据非法、损坏、截断或解压输出超过上限时抛出 / Thrown when the data is invalid, corrupted, truncated, or exceeds the output limit
- public byte[] Decompress(byte[] input, long maxOutputLength)
+ public byte[] Decompress(byte[] input, long maxOutputLength = CompressionHelper.DefaultMaxDecompressedOutputLength)
{
return CompressionHelper.Decompress(input, maxOutputLength);
}
diff --git a/GameFrameX.Utility/NetHelper.cs b/GameFrameX.Utility/NetHelper.cs
index 6a9ecec39..f31af6bb7 100644
--- a/GameFrameX.Utility/NetHelper.cs
+++ b/GameFrameX.Utility/NetHelper.cs
@@ -654,21 +654,23 @@ public static async Task IsNetworkReachableAsync(string host, int timeout
}
using (var ping = new Ping())
- using (var timeoutCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
- timeoutCancellationTokenSource.CancelAfter(timeout);
- try
- {
- var reply = await ping.SendPingAsync(host, timeout).WaitAsync(timeoutCancellationTokenSource.Token);
- return reply.Status == IPStatus.Success;
- }
- catch (OperationCanceledException)
+ using (var timeoutCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
{
- return false;
- }
- catch
- {
- return false;
+ timeoutCancellationTokenSource.CancelAfter(timeout);
+ try
+ {
+ var reply = await ping.SendPingAsync(host, timeout).WaitAsync(timeoutCancellationTokenSource.Token);
+ return reply.Status == IPStatus.Success;
+ }
+ catch (OperationCanceledException)
+ {
+ return false;
+ }
+ catch
+ {
+ return false;
+ }
}
}
}
diff --git a/build/deploy-game.sh b/build/deploy-game.sh
index eff03148e..a936bb76d 100755
--- a/build/deploy-game.sh
+++ b/build/deploy-game.sh
@@ -81,6 +81,11 @@ DEPLOY_GAME_PORTS=$(echo "${DEPLOY_GAME_PORTS}" | jq -c .)
DEPLOY_GAME_VOLUMES=$(echo "${DEPLOY_GAME_VOLUMES}" | jq -c .)
DEPLOY_GAME_ENVIRONMENTS=$(echo "${DEPLOY_GAME_ENVIRONMENTS}" | jq -c .)
+# 请求体含明文仓库凭据:用 mktemp 私有临时文件(0600),退出时无条件清理
+DEPLOY_BODY_FILE=$(mktemp "${TMPDIR:-/tmp}/deploy-game-body.XXXXXX")
+DEPLOY_RESP_FILE=$(mktemp "${TMPDIR:-/tmp}/deploy-game-resp.XXXXXX")
+trap 'rm -f "${DEPLOY_BODY_FILE}" "${DEPLOY_RESP_FILE}"' EXIT
+
jq -n \
--arg image_name "${IMAGE_NAME}" \
--arg tag "${TAG}" \
@@ -117,21 +122,21 @@ jq -n \
ports: $ports,
volumes: $volumes,
environments: $environments
-}' > /tmp/deploy-body.json
+}' > "${DEPLOY_BODY_FILE}"
echo "[DEPLOY] 部署 Game 服务器"
echo "[DEPLOY] 请求地址: ${DEPLOY_API_URL}"
echo "[DEPLOY] 请求参数:"
-jq '.Auth.Password = "****"' /tmp/deploy-body.json
+jq '.Auth.Password = "****"' "${DEPLOY_BODY_FILE}"
echo ""
-HTTP_CODE=$(curl -s --max-time 180 -o /tmp/deploy-resp.txt -w "%{http_code}" -X POST "${DEPLOY_API_URL}" \
+HTTP_CODE=$(curl -s --max-time 180 -o "${DEPLOY_RESP_FILE}" -w "%{http_code}" -X POST "${DEPLOY_API_URL}" \
-H "Content-Type: application/json; charset=UTF-8" \
- -d @/tmp/deploy-body.json)
+ -d @"${DEPLOY_BODY_FILE}")
echo "[DEPLOY] HTTP ${HTTP_CODE}"
echo "[DEPLOY] 响应内容:"
-cat /tmp/deploy-resp.txt
+cat "${DEPLOY_RESP_FILE}"
echo ""
if [ "${HTTP_CODE}" -ge 200 ] && [ "${HTTP_CODE}" -lt 300 ]; then
diff --git a/docker-compose.multi.yml b/docker-compose.multi.yml
index 750a0d9f8..da4ebf69a 100644
--- a/docker-compose.multi.yml
+++ b/docker-compose.multi.yml
@@ -43,8 +43,8 @@ services:
GameFrameX__AdvertisePort: "29400"
GameFrameX__RoleInstanceId: "2001"
ports:
- - "49400:29400"
- - "48081:28081"
+ - "127.0.0.1:49400:29400"
+ - "127.0.0.1:48081:28081"
volumes:
- "./running-multi/social-1/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -74,8 +74,8 @@ services:
GameFrameX__AdvertisePort: "29401"
GameFrameX__RoleInstanceId: "2002"
ports:
- - "49401:29401"
- - "48083:28083"
+ - "127.0.0.1:49401:29401"
+ - "127.0.0.1:48083:28083"
volumes:
- "./running-multi/social-2/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -109,8 +109,8 @@ services:
GameFrameX__AdvertisePort: "29100"
GameFrameX__RoleInstanceId: "1001"
ports:
- - "49100:29100"
- - "48080:28080"
+ - "127.0.0.1:49100:29100"
+ - "127.0.0.1:48080:28080"
volumes:
- "./running-multi/game-1/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -144,8 +144,8 @@ services:
GameFrameX__AdvertisePort: "29101"
GameFrameX__RoleInstanceId: "1002"
ports:
- - "49101:29101"
- - "48082:28082"
+ - "127.0.0.1:49101:29101"
+ - "127.0.0.1:48082:28082"
volumes:
- "./running-multi/game-2/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -179,8 +179,8 @@ services:
GameFrameX__AdvertisePort: "29102"
GameFrameX__RoleInstanceId: "1003"
ports:
- - "49102:29102"
- - "48084:28084"
+ - "127.0.0.1:49102:29102"
+ - "127.0.0.1:48084:28084"
volumes:
- "./running-multi/game-3/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -214,8 +214,8 @@ services:
GameFrameX__AdvertisePort: "29103"
GameFrameX__RoleInstanceId: "1004"
ports:
- - "49103:29103"
- - "48086:28086"
+ - "127.0.0.1:49103:29103"
+ - "127.0.0.1:48086:28086"
volumes:
- "./running-multi/game-4/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -249,8 +249,8 @@ services:
GameFrameX__AdvertisePort: "29104"
GameFrameX__RoleInstanceId: "1005"
ports:
- - "49104:29104"
- - "48088:28088"
+ - "127.0.0.1:49104:29104"
+ - "127.0.0.1:48088:28088"
volumes:
- "./running-multi/game-5/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -284,8 +284,8 @@ services:
GameFrameX__AdvertisePort: "29105"
GameFrameX__RoleInstanceId: "1006"
ports:
- - "49105:29105"
- - "48090:28090"
+ - "127.0.0.1:49105:29105"
+ - "127.0.0.1:48090:28090"
volumes:
- "./running-multi/game-6/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -319,8 +319,8 @@ services:
GameFrameX__AdvertisePort: "29106"
GameFrameX__RoleInstanceId: "1007"
ports:
- - "49106:29106"
- - "48092:28092"
+ - "127.0.0.1:49106:29106"
+ - "127.0.0.1:48092:28092"
volumes:
- "./running-multi/game-7/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -354,8 +354,8 @@ services:
GameFrameX__AdvertisePort: "29107"
GameFrameX__RoleInstanceId: "1008"
ports:
- - "49107:29107"
- - "48094:28094"
+ - "127.0.0.1:49107:29107"
+ - "127.0.0.1:48094:28094"
volumes:
- "./running-multi/game-8/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -389,8 +389,8 @@ services:
GameFrameX__AdvertisePort: "29108"
GameFrameX__RoleInstanceId: "1009"
ports:
- - "49108:29108"
- - "48096:28096"
+ - "127.0.0.1:49108:29108"
+ - "127.0.0.1:48096:28096"
volumes:
- "./running-multi/game-9/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
@@ -424,8 +424,8 @@ services:
GameFrameX__AdvertisePort: "29109"
GameFrameX__RoleInstanceId: "1010"
ports:
- - "49109:29109"
- - "48098:28098"
+ - "127.0.0.1:49109:29109"
+ - "127.0.0.1:48098:28098"
volumes:
- "./running-multi/game-10/logs:/app/data/logs"
- "./GameFrameX.Config/json:/app/Configs:ro"
diff --git a/docker-compose.yml b/docker-compose.yml
index b4408306c..e81a8eb9e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,7 +4,7 @@ services:
container_name: gfx-mongo
restart: unless-stopped
ports:
- - "37017:27017"
+ - "127.0.0.1:37017:27017"
healthcheck:
test: [ "CMD", "mongosh", "--quiet", "--eval", "db.runCommand({ ping: 1 }).ok" ]
interval: 5s
diff --git a/scripts/acceptance.sh b/scripts/acceptance.sh
index 84fc7d312..8338954e6 100755
--- a/scripts/acceptance.sh
+++ b/scripts/acceptance.sh
@@ -2,9 +2,9 @@
set -u
-ROOT_DIR="/Users/blank/Documents/GithubWorks/GameFrameX/Server"
+ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
TEST_PROJECT="Tests/GameFrameX.Tests/GameFrameX.Tests.csproj"
-SOLUTION="Server.sln"
+SOLUTION="Server.slnx"
REMOTE_FILTER="FullyQualifiedName~RemoteMessaging"
MODE="fast"
diff --git a/scripts/multi/generate-docker-compose-multi.py b/scripts/multi/generate-docker-compose-multi.py
index a388bb007..534a3d2ac 100755
--- a/scripts/multi/generate-docker-compose-multi.py
+++ b/scripts/multi/generate-docker-compose-multi.py
@@ -13,7 +13,7 @@
端口编号方案与退役前的静态形态逐实例一致,
生成结果直接写入 docker-compose.multi.yml 与 Configs/multi/;重复执行输出幂等。
-未认证的 MongoDB 仅绑定 127.0.0.1,避免向外部接口暴露可读写的数据面。
+未认证的 MongoDB 与各实例服务端口(TCP/HTTP)均仅绑定宿主 127.0.0.1,避免向外部网卡暴露可读写的数据面与管理接口。
用法::
@@ -197,8 +197,8 @@ def render_instance_service_body(instance: dict, role_name: str, social_services
f" GameFrameX__AdvertisePort: \"{instance['inner_port']}\"",
f" GameFrameX__RoleInstanceId: \"{instance['instance_id']}\"",
" ports:",
- f" - \"{instance['host_inner_port']}:{instance['inner_port']}\"",
- f" - \"{instance['host_http_port']}:{instance['http_port']}\"",
+ f" - \"127.0.0.1:{instance['host_inner_port']}:{instance['inner_port']}\"",
+ f" - \"127.0.0.1:{instance['host_http_port']}:{instance['http_port']}\"",
" volumes:",
f" - \"./running-multi/{instance['service']}/logs:/app/data/logs\"",
" - \"./GameFrameX.Config/json:/app/Configs:ro\"",