ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

OpenShell Provider Discovery 与归一化:openshell-providers 的职责、数据模型与安全注入设计

OpenShell Provider Discovery 与归一化:openshell-providers 的职责、数据模型与安全注入设计 【免费下载链接】OpenShellOpenShell is the safe, private runtime for autonomous AI agents.项目地址https://gitcode.com/gh_mirrors/op/OpenShell点击查看免费下载OpenShell 作为自治 AI Agent 的安全私有运行时需要把 API 密钥、令牌等凭证安全地提供给沙箱内运行的 agent 子进程。openshell-providers正是这一环节的凭证发现与归一化crate它从环境变量与已知配置中发现本地凭证、把发现结果归一化为结构化的 provider 记录并借助声明式的 provider profile 把凭证只投递到被授权的最小范围。读完本文你将掌握该 crate 的职责边界、发现算法、环境注入插件机制、profile 导入工作流以及它在 gateway / sandbox supervisor / 路由器之间的安全边界设计。一、crate 在 OpenShell 中的定位一条完整的凭证链路crates/openshell-providers/README.md开篇给出了这条链路的分工Gateway持久化 provider 记录provider recordsSandbox supervisor从 gateway 获取已解析的 provider 环境并把凭证注入 agent 子进程本 crate 只负责 provider 相关的**发现discovery与归一化normalization**逻辑把 provider 专属的解析规则从 CLI 与 gateway 的控制流中剥离出来。也就是说openshell-providers是凭证链路中的中间加工厂上游是本地环境/配置中的原始凭据下游是 supervisor 注入沙箱的最终环境变量。它不直接接触持久化、授权、注入和路由这些分别由 gateway、sandbox supervisor 与路由器负责。从源码结构看该 crate 在crates/openshell-providers/Cargo.toml中依赖openshell-core复用其 proto 类型Provider、ProviderProfile等与openshell-policy复用 L7 端点语义校验并通过serde/serde_json/serde_yml支持 YAML 与 JSON 两种 profile 格式。二、职责边界该做什么不该做什么原 README 明确列出四类职责与四类非职责这是理解该 crate 架构意图的钥匙。Responsibility职责从环境变量与已知配置文件中发现本地凭证把发现到的数据归一化为 provider 记录把 provider 专属的解析规则收敛在 provider 模块中避免记录logging凭证值。Non-Responsibility非职责持久化 provider 记录授权 provider 的增删改查CRUD把凭证注入沙箱子进程路由推理请求。这些能力分别由 gateway、sandbox supervisor 和路由器拥有。源码印证了这一设计crate 根模块crates/openshell-providers/src/lib.rs导出的公开 API 只有DiscoveryContext、discover_from_profile、discover_with_spec、一组 profile 解析/序列化函数以及ProviderRegistry这个内部兼容适配器——它刻意没有提供任何持久化或注入 API。这种只加工、不落库、不注入的边界带来两个工程收益一是 provider 专属规则可以独立演进而不污染 gateway 控制流二是凭证在 crate 内始终以结构化值存在调用方负责展示时的脱敏天然降低了误打日志的风险。三、核心数据模型3.1 发现结果DiscoveredProvidercrates/openshell-providers/src/lib.rs中定义了发现流程的输出pub struct DiscoveredProvider { pub credentials: HashMapString, String, pub config: HashMapString, String, }credentials按环境变量名索引的凭据值如GITHUB_TOKEN、OPENAI_API_KEYconfig与凭据无关的 provider 配置如 Vertex 的VERTEX_AI_PROJECT_ID、VERTEX_AI_REGION。DiscoveredProvider::is_empty()用于判定什么都没发现——这是发现函数返回None的依据。3.2 简化发现规格ProviderDiscoverySpecpub struct ProviderDiscoverySpec { pub id: static str, pub credential_env_vars: static [static str], }这是面向遗留/兼容路径的极简规格只需声明 provider id 与要扫描的凭据环境变量列表。3.3 声明式 profileProviderTypeProfile与简化规格相对现代发现是profile 驱动的。核心类型ProviderTypeProfile定义在crates/openshell-providers/src/profiles.rs字段包括id、display_name、description、category身份与分类ProviderProfileCategory如inference、source_controlcredentials: VecCredentialProfile凭据声明集合endpoints: VecEndpointProfile该 profile 允许访问的网络端点及 L7 规则binaries: VecBinaryProfile允许触达这些端点的进程二进制路径最小权限控制点discovery: DiscoveryProfile声明发现阶段要扫描哪些凭据inference_capable: bool是否具备推理能力resource_version、annotations、source、scope元数据字段。每个CredentialProfile由profiles.rs定义关键字段包括字段含义name凭据的语义名如api_token供discovery.credentials引用env_vars该凭据可能来自的环境变量列表可多选按序扫描required是否为必需凭据auth_style认证风格如bearerheader_name/query_param注入时放置凭据的 HTTP 头或查询参数refresh可选凭证刷新配置见下文运行时刷新path_template带{credential}占位符的路径模板token_grant可选令牌授权配置DiscoveryProfile则只含一个credentials: VecString字段列出发现阶段应扫描的凭据名——它必须引用credentials列表中已声明的名字否则发现会返回错误见 4.2 节。profile 与 proto 之间通过from_proto/to_proto双向无损转换ProviderTypeProfile::from_proto/to_proto并支持network_policy_rule()把端点/二进制降级为NetworkPolicyRule供网络策略 JIT 组合使用。注释明确指出这些 DTO 与proto/sandbox.proto中的网络策略 proto 镜像同步gRPC 导入与 CLI YAML 导入必须保持同一份策略意图。四、发现流程从环境变量到结构化记录4.1 上下文抽象DiscoveryContext发现逻辑不直接读std::env而是通过 trait 抽象注入环境来源pub trait DiscoveryContext { fn env_var(self, key: str) - OptionString; }crates/openshell-providers/src/context.rs同时提供了RealDiscoveryContext基于std::env::var用于生产测试则使用MockDiscoveryContext见test_helpers.rs构造受控环境这让发现算法可以在不依赖真实环境的前提下被精确测试。4.2 两种发现入口入口一discover_with_specdiscovery.rs——针对ProviderDiscoverySpec逐个扫描credential_env_vars命中非空值就写入credentials全部为空则返回None。入口二discover_from_profileprofile 驱动discovery.rs——算法更细致遍历profile.discovery.credentials中的每个凭据名在profile.credentials中按name精确查找找不到则返回ProviderError::UnknownDiscoveryCredential携带profile_id与credential_name从源码看这是配置错误而非静默忽略对每个凭据的env_vars逐个扫描去重HashSet并跳过空串命中非空值即写入credentialsor_insert语义保证首个非空值生效Vertex 特例当profile.id google-vertex-ai时额外扫描VERTEX_AI_CONFIG_KEY_NAMES配置键VERTEX_AI_PROJECT_ID、VERTEX_AI_REGION、GOOGLE_VERTEX_AI_BASE_URL、VERTEX_AI_BASE_URL、VERTEX_AI_PUBLISHER见lib.rs的常量定义写入discovered.config结果为空则返回None否则返回Some(DiscoveredProvider)。值得注意的细节空值与纯空白值!value.trim().is_empty()会被跳过同一个环境变量被多个凭据共享时只扫描一次多个环境变量指向同一凭据时or_insert保证第一个命中的值生效且不互相覆盖。这些行为都有对应单元测试背书见下文第七节。五、环境注入ProviderRegistry与 Provider 插件虽然注入本身是 sandbox supervisor 的职责但provider 专属的环境投影规则仍留在本 crate 内通过ProviderPlugin接口表达lib.rstrait ProviderPlugin: Send Sync { fn id(self) - static str; fn inject_env(self, _provider: Provider, _env: mut HashMapString, String) {} }ProviderRegistry::new()默认注册两个插件GoogleCloudProvideridgoogle-cloud与VertexProvideridgoogle-vertex-ai并按profile 解析出的精确 id 命中插件无别名表的规则工作inject_env_for_profile_id。源码注释明确说明这是为兼容既有 Google Cloud / Vertex 记录的内部兼容适配器公开的 provider 发现是 profile 驱动的。Google Cloud 插件providers/google_cloud.rs的投影行为把config.project_id投影到 GCP 项目 id 的所有别名环境变量如GCP_PROJECT_ID、GOOGLE_CLOUD_PROJECT常量来自openshell_core::google_cloud把config.region投影到区域别名如CLOUD_ML_REGION、GCP_LOCATION无条件注入GCE_METADATA_HOSTOpenShell 的 GCE 元数据模拟器地址——这使沙箱内的 gcloud、google-cloud-* 库无需修改即可用 ADC 方式取到凭据把config.service_account_email投影到GCP_SERVICE_ACCOUNT_EMAIL等别名不覆盖已存在的环境变量or_insert_with并跳过空配置值。Vertex 插件providers/vertex.rs额外投影ANTHROPIC_VERTEX_PROJECT_IDAnthropic CLI 的 Vertex 项目别名与VERTEX_LOCATIONGOOSE_PROVIDERgcp_vertex_ai推理标记。这些行为全部由单元测试锁定例如injects_project_id_aliases、does_not_overwrite_existing_env、skips_empty_config_values可以在providers/google_cloud.rs与providers/vertex.rs的测试模块中查看。六、声明式 Provider Profile导入工作流与最小权限6.1 示例 profile 与导入命令仓库根目录的providers/目录存放着一组可审阅的示例 profileanthropic.yaml、aws.yaml、aws-bedrock.yaml、claude-code.yaml、codex.yaml、copilot.yaml、cursor.yaml、deepinfra.yaml、github.yaml、google-cloud.yaml、google-vertex-ai.yaml、nvidia.yaml、openai.yaml、pypi.yaml等。providers/README.md明确说明OpenShell 不会把这些示例编译进任何二进制gateway 也不会自行加载它们——gateway 的 profile 目录里只有运维人员显式导入的内容。导入单个 profileopenshell provider profile lint -f providers/github.yaml openshell provider profile import -f providers/github.yaml --global或导入整个目录openshell provider profile import --from providers --global去掉--global则导入到当前 workspace。相关 CLI 实现在crates/openshell-cli/src/commands/下profile 解析/序列化 API 由profiles.rs提供parse_profile_yaml、parse_profile_json、profile_to_yaml、profile_to_json、validate_profile_set等。6.2 导入前必读binaries是最小权限控制点providers/README.md反复强调一个易踩的坑每个 profile 的binaries列表决定哪些进程可以触达它的端点。示例 profile 中的路径基于特定参考镜像布局如/sandbox/.venv、/app/.venv、/usr/lib/node_modules/...原样导入到不同镜像后profile 会匹配不到任何进程——目录里虽然还挂着这个 provider但凭据永不注入、流量被拒绝。因此复制文件后按你自己的镜像布局修改binaries与endpoints再导入若与示例存在分歧给副本一个独立的id避免目录混淆保持binaries尽量窄放宽它等于牺牲二进制级最小权限这一凭据注入的安全基石endpoints只声明凭据应触达的主机——凭据只会发送给其 profile 声明的端点导入前务必执行openshell provider profile lint。以providers/github.yaml为例它声明GITHUB_TOKEN/GH_TOKEN以 bearer 形式只发往api.github.comREST 与 GraphQL 只读与github.com仅 clone/fetchPOST /**/git-upload-pack放行、push 的git-receive-pack保持拒绝binaries只列/usr/bin/gh、/usr/local/bin/gh、/usr/bin/git、/usr/local/bin/git。也就是说即使沙箱里存在别的进程持有令牌网络策略也不会放行它去访问 GitHub。再如providers/openai.yamlOPENAI_API_KEY只发往api.openai.combinaries只列 curl 的常见路径——OpenAI 兼容服务请单独建 profile不要改指这个是文件头注释中明确的约定。6.3 发现与刷新凭据可以从网关铸造profile 不只是静态读取环境变量还支持网关侧凭证刷新。看providers/google-cloud.yaml的两个凭据service_account_tokenstrategy: google_service_account_jwt——网关用服务账号私钥签发 JWT 并换取访问令牌输出到GCP_SA_ACCESS_TOKENadc_tokenstrategy: oauth2_refresh_token——网关用 gcloud ADC 的client_id/client_secret/refresh_token换取访问令牌输出到GCP_ADC_ACCESS_TOKEN。两处refresh均声明token_url、scopes、refresh_before_seconds: 300、max_lifetime_seconds: 3600且material中private_key、client_secret、refresh_token标记为secret: true——这些刷新原料只留在网关永远不会注入沙箱沙箱里只出现铸造好的短时访问令牌。刷新材料由openshell provider refresh configure配置。这与 README 的 Security Notes 一脉相承。profiles.rs中ProviderTypeProfile::allows_empty_provider_credentials()与allows_runtime_provider_credentials()正是为这种场景设计的当所有必需凭据都能在运行时解析如由网关铸造、或全部可选时允许创建无初始静态凭据的 provider。七、安全设计结构化的值不落日志的秘密原 README 的 Security Notes 是必须逐字继承的约束Provider 数据常含 API 密钥、bearer 令牌或本地账号配置。发现代码应返回结构化值不打印或 trace 秘密。展示 provider 数据的调用方默认必须脱敏敏感字段。结合源码可以梳理出这条安全原则的落实方式发现阶段discover_with_spec/discover_from_profile只把值写进HashMap全程没有任何日志/println/tracing 语句discovery.rs全文可验证刷新阶段secret: true的 material私钥、client_secret、refresh_token不进入注入环境只作为网关铸造原料注入阶段插件用or_insert_with不覆盖已有环境变量且跳过空白值避免把脏数据投影进沙箱展示阶段README 明确要求调用方默认脱敏——这是 CLI 输出层crates/openshell-cli/src/output.rs等展示路径的设计约束。八、测试与验证行为被单元测试锁定openshell-providers的发现算法有完整单元测试discovery.rs测试模块profile_discovery_scans_referenced_credential_env_vars只扫描discovery.credentials引用到的凭据的环境变量设置CUSTOM_API_TOKEN而CUSTOM_API_KEY缺失时只发现前者profile_discovery_ignores_empty_values_and_returns_none_when_empty纯空白值被忽略全空返回Noneprofile_discovery_rejects_unknown_credential_references引用未声明的凭据名返回ProviderError::UnknownDiscoveryCredentialvertex_profile_discovery_includes_supported_configurationVertex 配置键VERTEX_AI_PROJECT_ID/VERTEX_AI_REGION被归入config而非credentials。Google Cloud 与 Vertex 插件的投影行为同样由测试锁定覆盖项目 id 别名、区域别名、元数据主机、服务账号邮箱、不覆盖已有环境变量、跳过空配置见providers/google_cloud.rs与providers/vertex.rs。另外example_profiles.rs在example-profiles特性仅从[dev-dependencies]启用下读取源码树中的providers/目录作为 gateway 与 CLI 集成测试的运维已导入夹具——让示例 profile 始终与解析逻辑保持同步、不漂移。九、小结一条可审计的凭证最小化链路从端到端看openshell-providers把本地凭据 → 结构化 provider 记录 → 网关铸造/持久化 → 沙箱注入这条链路的规则面收拢在一个 crate 里发现只认环境变量profile 声明的、非空的结果永远是结构化的DiscoveredProviderprovider 专属解析收敛在providers/子模块与 profile DTO 中CLI 与 gateway 控制流保持干净凭据去向由endpointsbinaries双重最小权限约束刷新原料secret标记且不注入沙箱全程不打印、不 trace 秘密展示层默认脱敏。如果你要在自己的镜像里接入新 provider正确姿势是复制providers/下对应示例 → 按镜像布局改binaries、按需收窄endpoints、必要时改id→openshell provider profile lint校验 →openshell provider profile import导入 → 用openshell sandbox create --provider name -- smoke-test验证。这一工作流既保证了配置可审阅也让每一次凭证授予都落在可审计的最小权限边界内。赞分享【免费下载链接】OpenShellOpenShell is the safe, private runtime for autonomous AI agents.项目地址https://gitcode.com/gh_mirrors/op/OpenShell点击查看免费下载相关推荐OpenShell CLIopenshell完整使用指南沙箱生命周期、网关注册、策略与 Provider 管理实战OpenShell CLIopenshell完整使用指南沙箱生命周期、网关注册、策略与 Provider 管理实战 导读 openshell 是 OpOpenShell Helm Chart 部署指南在 Kubernetes 上安装与配置 OpenShell 网关OpenShell Helm Chart 部署指南在 Kubernetes 上安装与配置 OpenShell 网关 导读 本文以 deploy/helm/oppixelmatch中的模块化设计函数拆分与职责单一原则pixelmatch中的模块化设计函数拆分与职责单一原则 在前端图像处理领域高效的像素级比较工具往往需要在性能与可维护性之间取得平衡。pixelmatch作图像处理上一篇解决符号链接搜索困扰fzf中排除软链接的终极方案下一篇告别重复劳动Swag注释自动化的宏定义高级技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表