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\"",