news 2026/9/25 3:09:30

BAML C NuGet 包冒烟测试全解析:精确版本恢复、RID 门禁与多形态部署验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
BAML C NuGet 包冒烟测试全解析:精确版本恢复、RID 门禁与多形态部署验证
  • 编程语言
  • AI Agent
  • 编译器
  • CLI
  • 人工智能

【免费下载链接】baml

The programming language for agents

项目地址:https://gitcode.com/gh_mirrors/ba/baml
点击查看免费下载

baml-bridge 是 BAML(The programming language for agents)为 C# 生成的客户端提供的托管运行时桥接包(PackageId为baml-bridge)。由于它既要承载跨平台的原生库(bridge_cffi.dll/libbridge_cffi.dylib/libbridge_cffi.so),又要保证包内依赖与打包形态在真实消费场景中不出问题,仓库在 bridge_csharp/tests/Baml.Bridge.NuGetPackageSmoke 下维护了一套专门的 NuGet 包冒烟测试。本文以该测试目录的 README.md 为骨架,结合 verify.sh、verify-deployment.sh 等脚本源码,完整拆解这套冒烟测试的验证维度、执行流程与底层机制,帮助读者理解"一个 NuGet 包如何被端到端地验证为可发布状态"。

测试定位:只验证打包,不重复测语言特性

在深入脚本之前,先明确这套测试的边界。README 开宗明义地指出:

这些脚本使用稳定的basic_callsAPI 测试打包。语言特性覆盖属于普通 C# SDK 测试套件。

这意味着:

  • 测试对象是打包形态:NuGet 包本身的结构、原生资产的放置、恢复(restore)、发布(publish)以及最终可执行行为,而不是 BAML 语言特性的正确性;
  • 使用最小稳定的 API 面:测试只调用一个最小的basic_calls函数,用它代表"生成代码 + 托管桥 + 原生桥"的完整链路;
  • 语言特性的深度验证(如流式、媒体、类型系统等)由 bridge_csharp/tests 下的其他探针(Probe)项目负责,例如Baml.Bridge.Stream.Tests、Baml.Bridge.GeneratedContract.Tests、Baml.Bridge.HostCallable.Tests等。

整套冒烟测试由两个脚本组成:

脚本职责
verify.sh为每个 RID 恢复并执行确切版本的包;同时检查包选择、不支持的 RID 诊断、NativeAOT 诊断、版本不匹配行为、包卫生(package hygiene)
verify-deployment.sh检查**裁剪(trimmed)与单文件(single-file)**两种部署形态下的产物形状与运行正确性

冒烟测试的固定骨架:fixture、消费者工程与探测程序

两个脚本共用一套固定的测试物料,理解它们是读懂脚本的前提。

1. BAML 源文件 fixture

测试使用的 BAML 源位于 sdk_tests/crates/csharp/basic_calls/baml_src/ns_csharp_basic_calls/main.baml:

function basic_calls( flag: bool, count: int, ratio: float, text: string, nullable: string?, ) -> string { text }

这个函数刻意覆盖了bool、int、float、string与可空string?五种基础类型的参数往返,返回值直接透传text,方便在探测程序中做严格相等断言。配套的 baml.toml 声明了 C# 生成器配置:

[package] name = "csharp-basic-calls" [generator.csharp] output_type = "csharp" output_dir = "." naming_convention = "language"

2. 探测程序 Program.cs

Program.cs 通过生成的CsharpBasicCalls命名空间分别做一次同步和一次异步调用,验证参数能原样往返:

using CsharpBasicCalls; const string Text = "héllo\0雪"; string synchronous = Functions.BasicCalls( flag: true, count: 42, ratio: 1.25, text: Text, nullable: null); if (synchronous != Text) { throw new InvalidOperationException("packaged synchronous primitive result changed"); } string asynchronous = await Functions.BasicCallsAsync( flag: false, count: -17, ratio: -2.5, text: Text, nullable: "present"); if (asynchronous != Text) { throw new InvalidOperationException("packaged asynchronous primitive result changed"); } Console.WriteLine("csharp_nuget_package_smoke=ok");

注意两点:

  • 文本特意使用了含\0与多字节 UTF-8 字符(é、雪)的字符串,用于验证原生桥接层对字符串编解码没有破坏;
  • 程序成功跑完才会输出csharp_nuget_package_smoke=ok,因此脚本对输出做grep -Fx精确匹配即等价于断言"整个调用链路正常"。

3. 消费者工程 Baml.Bridge.NuGetPackageSmoke.csproj

Baml.Bridge.NuGetPackageSmoke.csproj 模拟一个真实的下游应用工程:

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net10.0</TargetFramework> <LangVersion>14.0</LangVersion> <Nullable>enable</Nullable> <ImplicitUsings>enable</ImplicitUsings> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> <Deterministic>true</Deterministic> <AssemblyName>Baml.Bridge.NuGetPackageSmoke</AssemblyName> <BamlBridgePackageVersion Condition="'$(BamlBridgePackageVersion)' == ''">0.15.0</BamlBridgePackageVersion> </PropertyGroup> <ItemGroup> <PackageReference Include="baml-bridge" Version="[$(BamlBridgePackageVersion)]" /> </ItemGroup> </Project>

关键设计:

  • 精确版本锁定:Version="[$(BamlBridgePackageVersion)]"中的方括号表示"仅此版本、不允许浮动解析",配合-p:BamlBridgePackageVersion=$version把待测包版本精确注入;
  • 严格编译:TreatWarningsAsErrors让任何编译警告都成为失败信号;
  • 确定性构建:Deterministic=true与打包侧保持一致,便于比对产物。

4. 产品源映射 NuGet.Config

NuGet.Config 使用了packageSourceMapping,把包来源严格隔离:

<configuration> <packageSources> <clear /> <add key="baml-product" value="%BAML_CSHARP_PRODUCT_FEED%" /> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" /> </packageSources> <packageSourceMapping> <packageSource key="baml-product"> <package pattern="baml-bridge" /> </packageSource> <packageSource key="nuget.org"> <package pattern="Google.*" /> <package pattern="Microsoft.*" /> </packageSource> </packageSourceMapping> </configuration>
  • baml-bridge只能来自环境变量BAML_CSHARP_PRODUCT_FEED指向的本地产品源,杜绝意外从 nuget.org 拉取到同名旧包;
  • 依赖的Google.Protobuf等传递依赖只能来自 nuget.org;
  • <clear />确保不继承全局用户级源配置,测试环境干净可复现。

verify.sh:为每个 RID 验证确切包的完整生命周期

verify.sh 是主冒烟脚本。其用法为:

verify.sh <exact-package> [rid] [canonical-native-name] [generated-source-root]
参数含义默认值
exact-package待测.nupkg的绝对路径必填
rid目标 Runtime Identifierlinux-x64
canonical-native-name该 RID 下期望的原生库文件名libbridge_cffi.so
generated-source-root已生成的*.g.cs源码根(省略则自动生成)空(自动生成)

此外还支持一个独立子命令:

verify.sh --verify-repository-paths <repository-root> <publish-dir>

下面按验证维度拆解。

1. 版本提取与校验

脚本从 nupkg(本质是 zip)中解压baml-bridge.nuspec,用正则提取<version>标签:

version="$(unzip -p "$package" baml-bridge.nuspec \ | sed -n 's#.*<version>\([^<]*\)</version>.*#\1#p')" if [[ ! "$version" =~ ^[0-9A-Za-z][0-9A-Za-z.+-]*$ ]]; then echo "exact package contains an invalid or missing version: $version" >&2 exit 1 fi

版本字符串必须符合 NuGet 版本字符集,否则直接判定失败。

2. 生成 BAML 客户端源码(fixture 代码生成)

若未提供generated-source-root,脚本会在baml_language目录下用baml_cli从 fixture 重新生成 C# 代码:

(cd "$language_root" && cargo run --quiet -p baml_cli -- \ generate --from "$fixture")

随后把生成结果中的全部*.g.cs文件复制到消费者工程的baml_sdk/目录,并对文件清单做一次diff -u,确保"消费者拿到的生成文件集合"与"代码生成器刚产出的文件集合"完全一致。同时脚本检查两个关键文件必须存在:

  • Baml/Generated/BamlProgram.g.cs
  • CsharpBasicCalls/Functions.g.cs

3. 干净消费者环境与包选择检查

脚本在mktemp -d的临时目录里构造feed、consumer、packages三层结构:把待测包复制进产品源,把消费者工程、NuGet.Config、Program.cs、生成源码复制进消费者目录。随后执行带 RID 的 restore:

env -u BAML_BRIDGE_CSHARP_NATIVE_LIBRARY \ NUGET_PACKAGES="$dotnet_packages" \ dotnet restore "$project" --runtime "$rid" --configfile "$config" \ -p:NuGetAudit=false \ -p:BamlBridgePackageVersion="$version"

这里的"包选择检查"包含三层含义:

  • 解析结果唯一:restore 完成后,全局包目录$packages/baml-bridge下只允许存在一个*.nupkg(test "$restored_product_package_count" -eq 1);
  • 解析到的是确切包:把该 nupkg 与传入的exact-package做cmp字节级比对,证明消费端恢复到的就是待测产物,而非其他来源的版本;
  • 源映射生效:正因为NuGet.Config把baml-bridge锁定到产品源,包选择才可控、可比对。

顺带一提,restore 前还会清空环境变量BAML_BRIDGE_CSHARP_NATIVE_LIBRARY——这是为了让测试验证"原生库完全由 NuGet 包提供"的路径,而不是被外部环境变量覆盖。

4. 发布(publish)与原生资产一致性

restore 通过后,进行框架依赖(--self-contained false)的 Release 发布:

env -u BAML_BRIDGE_CSHARP_NATIVE_LIBRARY \ NUGET_PACKAGES="$dotnet_packages" \ dotnet publish "$project" \ --configuration Release \ --runtime "$rid" \ --self-contained false \ --no-restore \ --output "$publish" \ -p:NuGetAudit=false \ -p:BamlBridgePackageVersion="$version"

随后三项断言:

  1. 发布目录中原生库文件恰好一个(native_count -eq 1),且文件名就是canonical_native;
  2. 从 nupkg 中unzip -p出的runtimes/$rid/native/$canonical_native与发布产物做cmp,证明"包内原生资产 → 消费端运行时文件"的传递无损;
  3. 实际运行发布出的程序,grep -Fx 'csharp_nuget_package_smoke=ok',证明端到端调用成功。

5. 不支持的 RID 诊断(BAML0010)

脚本故意用不支持的 RIDlinux-s390x再次 build,期望构建失败且日志包含诊断码BAML0010:

if env NUGET_PACKAGES="$dotnet_packages" \ dotnet build "$project" --configuration Release --runtime linux-s390x \ --no-restore -p:NuGetAudit=false \ -p:BamlBridgePackageVersion="$version" \ > "$work/unsupported-rid.log" 2>&1; then echo "build unexpectedly accepted an unsupported RID" >&2 exit 1 fi if ! grep -F 'BAML0010' "$work/unsupported-rid.log"; then ...

该诊断由打包进包的buildTransitive/baml-bridge.targets触发。其源模板在 baml-bridge.targets.in:

<Target Name="BamlRejectUnsupportedRuntimeIdentifiers" BeforeTargets="PrepareForBuild"> <ItemGroup> <_BamlRequestedRid Include="$(RuntimeIdentifier)" Condition="'$(RuntimeIdentifier)' != ''" /> <_BamlRequestedRid Include="$(RuntimeIdentifiers)" Condition="'$(RuntimeIdentifiers)' != ''" /> <_BamlSupportedRid Include="@BAML_SUPPORTED_RIDS@" /> <_BamlUnsupportedRid Include="@(_BamlRequestedRid)" /> <_BamlUnsupportedRid Remove="@(_BamlSupportedRid)" /> </ItemGroup> <Error Condition="'@(_BamlUnsupportedRid)' != ''" Code="BAML0010" Text="baml-bridge does not support RuntimeIdentifier(s) @(_BamlUnsupportedRid, ', '). Supported RIDs: @(_BamlSupportedRid, ', ')." /> </Target>

@BAML_SUPPORTED_RIDS@占位符在打包时由 pack-product.sh 依据 platforms.json 中的 C# RID 集合替换,从而保证"门禁清单"与"实际打包的原生资产清单"始终同源。

6. NativeAOT 诊断(BAML0019)

同样,脚本用-p:PublishAot=true再次 build,期望失败且日志包含BAML0019。对应门禁也在 baml-bridge.targets.in:

<Target Name="BamlRejectUnsupportedNativeAot" BeforeTargets="PrepareForBuild" Condition="'$(PublishAot)' == 'true'"> <Error Code="BAML0019" Text="baml-bridge does not support NativeAOT in v1. Use a normal, trimmed, single-file, or trimmed single-file JIT publish instead." /> </Target>

这条诊断明确表达了当前版本(v1)的策略:原生桥暂不支持 NativeAOT,用户应改用普通 JIT、裁剪、单文件或"裁剪 + 单文件"的发布形态——而这些形态正是 verify-deployment.sh 要逐一验证的对象。

7. 版本不匹配行为

脚本构造一个不存在的版本9999.0.0,用-p:BamlBridgePackageVersion=9999.0.0在独立目录(独立的NUGET_PACKAGES)执行 restore,期望失败,并且错误日志中必须包含该版本号:

mismatch_version="9999.0.0" if env NUGET_PACKAGES="$dotnet_mismatch_packages" \ dotnet restore "$mismatch/Baml.Bridge.NuGetPackageSmoke.csproj" \ --configfile "$mismatch/NuGet.Config" \ -p:NuGetAudit=false \ -p:BamlBridgePackageVersion="$mismatch_version" \ > "$work/mismatch.log" 2>&1; then echo "restore unexpectedly accepted a mismatched package version" >&2 exit 1 fi grep -F "$mismatch_version" "$work/mismatch.log"

这个用例验证的是:当精确版本不可用时,restore 必须硬失败并明确报出版本号,而不是静默降级、回退到浮动解析或复用旧缓存。这是发布一致性至关重要的行为契约。

8. 包卫生检查(package hygiene)

"包卫生"是 README 特别点名的验证维度,脚本从两个方向检查:

(a)干净消费者目录(restore 前):消费者目录内不得出现*.proto、*.baml、*.toml、*.bin等源码或运行时资产——这些只应存在于 SDK 开发环境,绝不允许混入"仅消费包"的用户工程:

if find "$consumer" -type f \ \( -name '*.proto' -o -name '*.baml' -o -name '*.toml' -o -name '*.bin' \) \ | grep -q .; then echo "clean consumer contains a forbidden source/runtime asset" >&2 exit 1 fi

(b)发布目录(publish 后):不得出现*.proto、*.baml、baml-cli*、baml.toml、*.csproj:

if find "$publish" -type f \ \( -name '*.proto' -o -name '*.baml' -o -name 'baml-cli*' \ -o -name 'baml.toml' -o -name '*.csproj' \) \ | grep -q .; then echo "published consumer contains a forbidden source/tooling asset" >&2 exit 1 fi

(c)仓库路径泄漏检查:通过--verify-repository-paths子命令(verify_repository_paths函数),用grep -r -a -F -l扫描发布目录,确保其中不含仓库根路径字符串。实现上特意在仓库根后补/(repository_path_prefix="${repository_root%/}/"),防止/work这类短挂载点误伤/worker.rs之类的无关路径段。这条防线是为了防止构建机路径(如/data/.../baml)被编译进产物而泄露到用户环境。

9. 成功信号

所有检查通过后,脚本输出一行固定的成功标记:

csharp_nuget_package_smoke=ok

CI 只需对输出做精确匹配即可判定该 RID 的包验证通过。

verify-deployment.sh:裁剪与单文件部署形态验证

verify-deployment.sh 专门回答一个问题:在裁剪(trimmed)和单文件(single-file)发布下,原生库资产与程序是否依然正确。其用法固定为 4 个必填参数:

verify-deployment.sh <exact-package> <rid> <canonical-native-name> <generated-source-root>

与 verify.sh 不同,这里要求generated-source-root已存在(不再自动生成),且生成源码整目录复制进消费者(cp -R .../baml_sdk/),并在脚本内直接生成一份含BAML_CSHARP_PRODUCT_FEED环境变量引用的 NuGet.Config。

1. 三种发布形态矩阵

脚本覆盖了"裁剪 × 单文件 × 原生库打包方式"的组合矩阵,共 5 个发布产物:

发布形态PublishTrimmedTrimModePublishSingleFileIncludeNativeLibrariesForSelfExtract原生库位置
裁剪侧车(trimmed sidecar)truelinkfalse—输出目录旁文件
单文件侧车(single-file sidecar,未裁剪)false—truefalse输出目录旁文件
单文件侧车(single-file sidecar,裁剪)truelinktruefalse输出目录旁文件
单文件自解压(self-extract,未裁剪)false—truetrue打进单文件 bundle
单文件自解压(self-extract,裁剪)truelinktruetrue打进单文件 bundle

公共发布参数非常严格:

common=( --configuration Release --runtime "$rid" --self-contained true --no-restore -p:NuGetAudit=false -p:BamlBridgePackageVersion="$version" -p:SuppressTrimAnalysisWarnings=false -p:TrimmerSingleWarn=false -p:ILLinkTreatWarningsAsErrors=true ) trimmed=(-p:PublishTrimmed=true -p:TrimMode=link)

其中SuppressTrimAnalysisWarnings=false与ILLinkTreatWarningsAsErrors=true意味着任何裁剪分析警告都会让构建失败——这验证了Baml.Bridge本身是干净可裁剪的(其工程设置了IsTrimmable=true、EnableTrimAnalyzer=true,见 Baml.Bridge.csproj)。

2. 产物清单断言(inventory)

assert_single_file_inventory函数对单文件发布目录做白名单校验:目录下只允许存在可执行文件(Baml.Bridge.NuGetPackageSmoke)、*.pdb,以及(仅侧车模式下)一个canonical_native原生库;任何其他散落文件都视为失败:

case "$(basename "$file")" in Baml.Bridge.NuGetPackageSmoke|*.pdb) ;; "$canonical_native") test "$include_native" = true ;; *) echo "unexpected loose single-file publish asset: $file" >&2 return 1 ;; esac

3. 侧车模式运行验证(run_sidecar)

侧车模式下,原生库以独立文件形式与单文件程序共存。run_sidecar断言:输出目录恰好一个原生资产、路径就是$output/$canonical_native、且与包内runtimes/$rid/native/$canonical_native字节一致,最后运行程序并匹配csharp_nuget_package_smoke=ok。

4. 自解压模式运行验证(run_self_extract)

自解压模式下,原生库被嵌入单文件 bundle,因此输出目录中不应有任何原生资产(bundled_output_native数量为 0,assert_single_file_inventory "$output" false)。运行时通过DOTNET_BUNDLE_EXTRACT_BASE_DIR指定解压根目录:

env -u BAML_BRIDGE_CSHARP_NATIVE_LIBRARY \ DOTNET_BUNDLE_EXTRACT_BASE_DIR="$extraction_root" \ "$output/Baml.Bridge.NuGetPackageSmoke" \ | grep -Fx 'csharp_nuget_package_smoke=ok'

运行成功后,再检查解压目录中恰好出现一个、且与包内原生资产字节一致的文件。这验证了"嵌入式原生库被正确提取并可加载"。

5. 成功信号

全部形态通过后输出:

csharp_exact_package_deployment=normal_trimmed_and_single_file_shapes_ok

打包侧的契约支撑:pack-product.sh 与 platforms.json

冒烟测试能成立,依赖打包侧已经产出了"正确结构"的包。从 pack-product.sh 可以看到与冒烟测试呼应的多重契约:

  • 八 RID 清单单一来源:[release/platforms.json](https://link.gitcode.com/i/430d52d1f1804fda081f06ffcc65bb95)中artifacts.csharp定义了每个目标的rid与native_asset,共 8 个:osx-arm64、osx-x64、linux-arm64、linux-musl-arm64、linux-x64、linux-musl-x64、win-x64、win-arm64(原生库分别对应libbridge_cffi.dylib/libbridge_cffi.so/bridge_cffi.dll)。这正是 verify.sh 逐 RID 循环的测试矩阵来源;
  • 原生资产完整性:打包前用sha256sum -c校验原生资产清单,并把runtimes/<rid>/native/<asset>路径集合与 platforms.json 生成的期望集合做diff -u;
  • 二进制卫生:用llvm-readobj/llvm-nm/llvm-objdump检查 ELF/Mach-O/COFF 格式、禁止调试段、禁止符号表、禁止 RPATH/RUNPATH,导出符号必须精确等于 release/bridge-cffi-public-exports.txt 允许清单;
  • 确定性打包:同一输入打两次包,经Baml.NuGetNormalizer规范化后必须cmp逐字节相同;
  • 包结构白名单:nupkg 条目集合被严格枚举为[Content_Types].xml、_rels/.rels、README.md、baml-bridge.nuspec、buildTransitive/baml-bridge.targets、lib/net10.0/Baml.Bridge.dll、core-properties 加上 8 个原生资产条目;
  • 依赖门禁:nuspec 必须含Google.Protobuf依赖,但Grpc.Tools(仅构建期工具)绝不允许泄漏进产品包依赖图。

冒烟测试脚本中对 nupkg 的unzip -p提取、cmp比对、发布目录清单扫描,正是从"消费端视角"反向验证这些打包契约在真实 restore/publish 流程中没有被破坏。

运行前提与限制

要让这两个脚本在自己环境跑通,需要满足以下前提(以当前仓库实际内容为准):

  • .NET SDK:目标框架为net10.0、LangVersion14.0,需要对应版本的 .NET SDK;
  • Rust 工具链:verify.sh 在未提供generated-source-root时会调用cargo run -p baml_cli生成代码,需要可用的 Rust 工具链与已解析的依赖;
  • 平台原生能力:验证某个 RID 需要在对应平台上运行(例如linux-s390x只用于负向诊断测试);Windows 下脚本通过RUNNER_OS判断并用cygpath -am转换路径;
  • 外部依赖:restore 过程中Google.Protobuf等传递依赖需要能访问 nuget.org;
  • 打包产物来源:脚本输入是"确切版本"的 nupkg(如baml-bridge.<version>.nupkg),该产物由打包管线(pack-product.sh + 发布计划)产出,冒烟测试本身不负责打包。

限制方面:脚本只覆盖basic_calls的最小 API 面;更深的语言特性(流式、媒体、动态类型等)需由 bridge_csharp/tests 下各 Probe/Tests 项目补充;当前 v1 明确不支持 NativeAOT,因此部署验证只覆盖 JIT 下的普通/裁剪/单文件组合。

总结:一套完整的"可发布性"验证闭环

从 README 的简短描述出发,结合脚本源码可以看到这套 NuGet 冒烟测试实际构成了一个多维闭环:

  1. 包选择正确性:restore 唯一命中确切包,源映射隔离生效;
  2. 资产传递完整性:包内runtimes/<rid>/native/原生库与发布产物逐字节一致;
  3. 门禁诊断有效性:BAML0010(不支持的 RID)、BAML0019(NativeAOT)在错误场景如约触发;
  4. 失败语义正确性:版本不匹配必须硬失败并报出版本号;
  5. 包卫生:无源码/工具资产泄漏,无仓库路径泄漏;
  6. 部署形态兼容性:普通、裁剪、单文件侧车、单文件自解压四种形态均能加载原生库并跑通端到端调用。

对于想要为 baml-bridge 的发布质量把关的开发者,这套测试既是"每个 RID 的可执行验收标准",也提供了一个可复用的范式:用一个最小稳定 API 面 + 严格产物清单 + 负向用例,把"包能不能被真实消费"验证到极致。

  • 编程语言
  • AI Agent
  • 编译器
  • CLI
  • 人工智能

【免费下载链接】baml

The programming language for agents

项目地址:https://gitcode.com/gh_mirrors/ba/baml
点击查看免费下载

相关推荐

上一篇:CAD Sketcher安装失败深度分析:如何彻底解决Blender插件依赖冲突问题
下一篇:Release v21.5.8:

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 3:08:44

单点登录故障韧性测试:SSO故障注入与恢复策略实践

你大概很难忘掉那个上午&#xff1a;全公司邮箱、代码仓库、内网Wiki、运营后台&#xff0c;一个接一个在你面前弹出“登录已过期&#xff0c;请重新登录”&#xff0c;然后无论你怎么填密码&#xff0c;页面都只会转圈圈。这不是你本地网络的问题&#xff0c;也不是哪一个业务…

作者头像 李华
网站建设 2026/9/25 3:06:41

Hermes Agent 命令行界面接入 TaoToken:config.toml 配置骨架与 CLI 验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/25 3:05:49

Meshery Catalog 实战:用 Pod Volume Mount SubPath 实现共享卷按需挂载

云原生微服务运维DevOps 【免费下载链接】meshery Meshery, the cloud native manager 项目地址&#xff1a; https://gitcode.com/GitHub_Trending/me/meshery 点击查看 免费下载 本指南围绕 Meshery Catalog 中的 Workloads 设计模式 Pod Volume Mount SubPath&#xff08;p…

作者头像 李华