
Corsair 集成 CircleCI从安装、认证到 65 个端点的完整实战指南【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsaircorsair-dev/circleci是 Corsair 官方为 CircleCI 提供的连接插件plugin它把 CircleCI 的 REST v2、REST v3、遗留 v1.1 与 GraphQL 四种 API 面统一封装为 65 个声明式的插件端点endpoint让你的 Agent 或应用可以通过一套统一的权限、审计与密钥管理机制安全地操作 CircleCI 的 contexts、pipelines、workflows、orbs、insights 等资源。读完本文你将掌握该插件的安装注册、API Key 认证方式、端点全貌与风险分级以及底层四传输一凭据的实现原理并能结合仓库源码理解每个端点背后的调用链。插件定位给 Agent 一个受管控的 CircleCI 控制面Corsair 的核心理念是Connect your users to their apps——把用户账号安全地连接到第三方应用。corsair-dev/circleci插件正是这一理念在持续集成/持续交付CI/CD领域的落地它不要求 Agent 直接持有 CircleCI Token而是由 Corsair 在租户tenant首次使用凭证时通过 API Key 认证模式提示用户录入凭据之后所有端点调用都由 Corsair 统一完成鉴权、审计与错误处理。从仓库的 packages/circleci/plugin-docs.yaml 可以看到其官方定位Continuous integration and delivery platform for automated testing and deployment pipelines面向自动化测试与部署流水线的持续集成和持续交付平台。插件以独立 npm 包形式发布当前版本0.1.1见 packages/circleci/package.json与corsair核心包及zod保持依赖关系。安装在 pnpm 工作区中安装pnpm add corsair-dev/circleci包本身是 ESM 模块入口为dist/index.js类型声明位于dist/index.d.ts见 packages/circleci/package.json 的exports字段。它声明了以下 peer 依赖安装时需确保满足corsair0.1.0zod^4.1.13注册插件接入 createCorsair安装后把circleci()插件工厂函数加入createCorsair的plugins数组。仓库中 demo/testing/src/server/corsair.ts 展示了标准的插件注册方式以该文件中的其他插件为例CircleCI 的注册方式一致import { circleci } from corsair-dev/circleci; import { createCorsair } from corsair; export const corsair createCorsair({ multiTenancy: false, database: sqlite, kek: process.env.CORSAIR_KEK!, permissions: { timeout: 10m, onTimeout: deny, }, plugins: [ circleci(), // 其他插件... ], });circleci()工厂函数接受可选的CircleCIPluginOptions定义见 packages/circleci/index.ts包括选项类型说明authTypeapi_key认证类型默认即api_keykeystring静态 API Key提供后端点调用直接使用该值跳过密钥存储hooks内部 hooks插件生命周期钩子errorHandlersCorsairErrorHandler自定义错误处理器会与插件内置的errorHandlers合并permissionsPluginPermissionsConfig针对嵌套端点的权限配置认证个人 API Token四传输通用Corsair 的认证模型是首次使用时提示租户录入凭据。插件声明的认证配置非常简洁见 packages/circleci/index.tsexport const circleCIAuthConfig { api_key: { account: [] as const }, } as const satisfies PluginAuthConfig;这意味着插件只支持api_key一种认证方式不区分多账号——所有租户共享当前用户这一个 CircleCI 身份。README 中也明确写道Auth: API key. Corsair prompts your tenant for credentials on first use.在 client.ts 中可以看到令牌的发送方式请求头携带Authorization: Bearer ${apiToken}。源码注释特别强调了一个关键约束——必须是personal API token个人令牌而非 project tokenCircleCI 官方 OpenAPI 规范的 security-scheme 说明明确指出 Project API tokens are not supported for API v2且该约束同样适用于 v3 与 v1.1已用同一个人令牌实测确认。令牌的读取策略在插件的keyBuilder中实现packages/circleci/index.ts如果传入了options.key则直接使用否则按api_key认证类型从 Corsair 的密钥存储中读取。端点全景65 个操作一表掌握README 的核心是一张端点清单。下表完整继承自 packages/circleci/README.md并按资源域分组Operation 即你在权限配置、审计事件中使用的操作 IDOperation ID 是端点全限定名Risk 为风险分级ContextsREST v2 形态OperationOperation IDRiskDescriptioncontexts.createcircleci.api.contexts.createwriteCreate a context (REST)contexts.createRestrictioncircleci.api.contexts.createRestrictionwriteAdd a restriction to a contextcontexts.deleteRestrictioncircleci.api.contexts.deleteRestrictiondestructiveRemove a restriction from a contextcontexts.getcircleci.api.contexts.getreadRetrieve a context by idcontexts.listEnvVarscircleci.api.contexts.listEnvVarsreadList a contexts environment variablescontexts.upsertEnvVarcircleci.api.contexts.upsertEnvVarwriteAdd or update a context environment variable (REST)ContextsGraphQL 形态OperationOperation IDRiskDescriptioncontextsGraphQL.createcircleci.api.contextsGraphQL.createwriteCreate a context (GraphQL)contextsGraphQL.deletecircleci.api.contextsGraphQL.deletedestructivePermanently delete a context and its environment variables (GraphQL)contextsGraphQL.querycircleci.api.contextsGraphQL.queryreadRetrieve a context by id (GraphQL)contextsGraphQL.removeEnvVarcircleci.api.contextsGraphQL.removeEnvVardestructiveRemove a context environment variable (GraphQL)contextsGraphQL.storeEnvVarcircleci.api.contextsGraphQL.storeEnvVarwriteAdd or update a context environment variable (GraphQL)Groups 与 Orb Allow-listOperationOperation IDRiskDescriptiongroups.createcircleci.api.groups.createwriteCreate an organization groupgroups.deletecircleci.api.groups.deletedestructivePermanently delete an organization groupgroups.getcircleci.api.groups.getreadRetrieve an organization groupgroups.listcircleci.api.groups.listreadList an organizations groupsorbAllowlist.createcircleci.api.orbAllowlist.createwriteAdd a URL orb allow-list entryorbAllowlist.deletecircleci.api.orbAllowlist.deletedestructiveRemove a URL orb allow-list entryInsightsOperationOperation IDRiskDescriptioninsights.branchescircleci.api.insights.branchesreadList branches with workflow runsinsights.flakyTestscircleci.api.insights.flakyTestsreadGet flaky tests for a projectinsights.orgSummarycircleci.api.insights.orgSummaryreadGet org-wide summary metrics with trendsinsights.pagesSummarycircleci.api.insights.pagesSummaryreadGet summary metrics and trends for a projectinsights.planMetricscircleci.api.insights.planMetricsreadGet plan/credit-usage metrics by project and org for a date range (same route as insights.orgSummary)insights.projectWorkflowscircleci.api.insights.projectWorkflowsreadGet summary metrics for all of a projects workflowsJobsv1.1 形态OperationOperation IDRiskDescriptionjobs.getArtifactscircleci.api.jobs.getArtifactsreadList a jobs stored artifacts by numberjobs.getDetailscircleci.api.jobs.getDetailsreadFetch a jobs status, timing and executor by numberjobs.getTestMetadatacircleci.api.jobs.getTestMetadatareadFetch a jobs stored test results by numberNamespace 与 OrbsOperationOperation IDRiskDescriptionnamespace.deletecircleci.api.namespace.deletedestructivePermanently delete a namespace and all its orbsnamespace.deleteAliascircleci.api.namespace.deleteAliasdestructiveRemove a namespace alias (GraphQL)namespace.queryExistscircleci.api.namespace.queryExistsreadCheck whether a namespace name existsnamespace.renamecircleci.api.namespace.renamewriteRename a namespaceorbAllowlist.createcircleci.api.orbAllowlist.createwriteAdd a URL orb allow-list entryorbAllowlist.deletecircleci.api.orbAllowlist.deletedestructiveRemove a URL orb allow-list entryorbs.getDetailscircleci.api.orbs.getDetailsreadFetch an orbs metadata and versionsorbs.getVersioncircleci.api.orbs.getVersionreadFetch one orb versionorbs.listCategoriescircleci.api.orbs.listCategoriesreadList orb categoriesorbs.listNamespaceOrbscircleci.api.orbs.listNamespaceOrbsreadList orbs in a namespaceorbs.listOrbscircleci.api.orbs.listOrbsreadList orbs across the registryorbs.queryCategoryIdcircleci.api.orbs.queryCategoryIdreadFetch a categorys id by nameorbs.queryExistscircleci.api.orbs.queryExistsreadCheck whether an orb existsorbs.queryIdcircleci.api.orbs.queryIdreadFetch an orbs id by nameorbs.queryLatestVersioncircleci.api.orbs.queryLatestVersionreadFetch an orbs latest published versionorbs.querySourcecircleci.api.orbs.querySourcereadFetch an orb versions source YAMLorbs.validateConfigcircleci.api.orbs.validateConfigreadValidate orb YAMLOrganization、Pipelines 与 Pipeline DefinitionsOperationOperation IDRiskDescriptionorganization.getcircleci.api.organization.getreadRetrieve an organization by id (GraphQL)pipelineDefinitions.getcircleci.api.pipelineDefinitions.getreadRetrieve a pipeline definitionpipelineDefinitions.listcircleci.api.pipelineDefinitions.listreadList a projects pipeline definitionspipelines.getConfigcircleci.api.pipelines.getConfigreadFetch a pipelines configpipelines.listcircleci.api.pipelines.listreadList pipelines for an organizationpipelines.listForProjectcircleci.api.pipelines.listForProjectreadList a projects pipelinespipelines.triggercircleci.api.pipelines.triggerwriteStart a new pipeline run on a branch or tagProject 环境变量与 ProjectsOperationOperation IDRiskDescriptionprojectEnvVars.createcircleci.api.projectEnvVars.createwriteCreate a project environment variableprojectEnvVars.deletecircleci.api.projectEnvVars.deletedestructiveDelete a project environment variableprojectEnvVars.listcircleci.api.projectEnvVars.listreadList a projects environment variablesprojects.createcircleci.api.projects.createwriteFollow a repository as a new projectprojects.deletecircleci.api.projects.deletedestructivePermanently remove a project and its settingsprojects.getcircleci.api.projects.getreadRetrieve a project by slugRunners、Schedules 与 Usage ExportOperationOperation IDRiskDescriptionrunners.listcircleci.api.runners.listreadList self-hosted runnersschedules.listcircleci.api.schedules.listreadList a projects scheduled pipeline triggersusageExport.createcircleci.api.usageExport.createwriteCreate a usage export jobusageExport.getcircleci.api.usageExport.getreadRetrieve a usage export jobUser 与 WorkflowsOperationOperation IDRiskDescriptionuser.getCurrentcircleci.api.user.getCurrentreadRead the authenticated users own profileuser.getInfocircleci.api.user.getInforeadRead another users profile by iduser.listCollaborationscircleci.api.user.listCollaborationsreadList organizations the caller can collaborate onworkflows.getSummarycircleci.api.workflows.getSummaryreadGet metrics and trends for a workflowworkflows.listByPipelineIdcircleci.api.workflows.listByPipelineIdreadList a pipelines workflowsworkflows.listJobscircleci.api.workflows.listJobsreadGet summary metrics for a workflows jobsworkflows.listTestMetricscircleci.api.workflows.listTestMetricsreadGet test metrics for a workflow端点实现深潜从操作 ID 到 HTTP 调用插件把每个操作 ID 映射到具体的端点实现全部定义在 packages/circleci/index.ts 的circleCIEndpointsNested中并配套三层注册表endpointSchemasindex.ts为每个操作 ID 绑定 zod 输入/输出 schema实现运行时校验endpointMetaindex.ts声明每个操作的riskLevel与描述这是权限系统与审计的依据CircleCIEndpoints类型index.ts为每个端点提供严格的 TypeScript 类型。以pipelines.trigger为例endpoints/pipelines.ts其实现首先通过 zod 校验projectSlug/branch/tag/parameters输入然后调用circleCICall向POST /project/{project-slug}/pipeline发出请求最后写入一条审计事件。源码注释披露了一个重要的路由决策选用/project/{slug}/pipeline而非/pipeline/run因为前者直接接收branch/tag/parameters与目录描述吻合后者要求预先存在的definition_id目录从未提及。再如contexts.createendpoints/contexts.ts请求体为{ name, owner: { id, type } }其中ownerType取值organization或accountCircleCI Server 场景响应结果会被缓存到本地数据库实体表并写入审计日志。数据镜像与审计只镜像稳定实体插件并不是简单转发请求——它把部分结果镜像mirror到本地数据库以便 Agent 后续可以离线查询。从源码结构看镜像策略是有选择的镜像对象contexts、groups、projects、project env vars、pipeline definitions、schedules 等稳定实体对应 packages/circleci/schema/database.ts 中的实体定义contexts.create/contexts.get在调用后都会执行cacheEntity(ctx.db.contexts, ...)见 endpoints/contexts.ts不镜像对象pipelines、workflows、jobs 被视为事务性数据永远实时读写见 endpoints/pipelines.ts 的注释orbs 目录是共享公共目录而非本账号数据同样不镜像见 endpoints/orbs.ts。每个端点执行后都会通过logEventFromContext记录一条审计事件operation ID 前缀为circleci.*敏感字段如环境变量值会被排除在审计载荷之外——contexts.upsertEnvVar的审计只记录contextId与variable绝不记录 valueendpoints/contexts.ts。底层原理四种传输、一个凭据这是该插件最具技术价值的部分。与大多数单 API 面的插件不同CircleCI 插件的 65 个操作横跨四种不同的 API 传输全部实现在 packages/circleci/client.ts传输Base URL覆盖的操作域特性REST v2https://circleci.com/api/v2contexts、pipelines、workflows、insights 等官方文档化、有公开 OpenAPI 规范REST v3https://circleci.com/api/v3orbs 注册表、namespaces、jobs、artifacts、runners无公开规范JSON:API 风格{data: ...}信封遗留 v1.1https://circleci.com/api/v1.1按 build number 定位的 job 详情/artifacts/tests唯一能按普通数字编号访问 job 的传输GraphQLhttps://circleci.com/graphql-unstablecontexts、orbs、organization 的 GraphQL 形态内省introspection被禁用schema 靠实测反推四个传输共享同一个个人 API Token这正是四传输一凭据的含义。源码注释详尽记录了各传输的确认过程v3 面通过阅读 CircleCI 官方开源 CLIcircleci-cli的internal/apiclient/*.go并结合实测反推GraphQL 面在禁用内省的前提下通过 field-not-found 与 missing-argument 错误信息反推 schema。几个值得注意的实现细节v3 列表分页makeCircleCIV3ListRequestclient.ts保留 JSON:API 的page.next/page.prev游标返回{items, page}信封对不符合预期形状的响应直接抛错而非静默返回空数组避免把响应无法解析误报为结果为零。v1.1 的安全约束jobs.getDetails等操作按project/{vcs}/{org}/{project}/{build_num}定位 jobendpoints/shared.ts。响应中的all_commit_details字段包含触发提交的作者邮箱源码特意不把它声明为类型化字段、不镜像、不写入日志endpoints/types.ts——这是本插件对敏感 PII 的硬约束。GraphQL 的 200 错误GraphQL 传输用原生fetch而非共享request助手因为 GraphQL 以HTTP 200 errors[]报告失败走共享助手会把 GraphQL 级错误误判为成功client.ts。风险分级read / write / destructive 的判定逻辑每个操作被标记为read、write或destructive之一见 packages/circleci/index.ts 的说明注释这是 Corsair 权限系统的基础。判定原则值得理解destructiveCircleCI 无法撤销的操作——删除 context、project、group、namespace连同其全部 orbs、restriction、环境变量这些都没有软删除或回收站write其余一切会改变状态的操作特例pipelines.trigger虽看起来只是触发但被归为write而非read——因为重放它会改变结果每次调用都会新起一次构建与 Habitica 插件的任务计分端点同理。错误处理与限流按传输分治packages/circleci/error-handlers.ts 定义了完整的错误分类体系覆盖两类错误REST 传输抛出的CircleCIAPIError携带 HTTP status以及 GraphQL 传输抛出的CircleCIGraphQLError携带errors[]无 status。Handler匹配规则重试策略RATE_LIMIT_ERRORstatus 429或 GraphQL 消息含 429最多 3 次优先遵循服务器Retry-AfterAUTH_ERRORstatus 401不重试PERMISSION_ERRORstatus 403或 GraphQL 消息含 permission denied不重试NOT_FOUND_ERRORstatus 404不重试GRAPHQL_ERROR其他CircleCIGraphQLError不重试DEFAULT兜底不重试源码注释披露了实测结论CircleCI 的 403 同时覆盖权限不足与对象不存在——对真实已删除的 context 与从未存在的 id 做并排测试两者都返回 403 Forbidden因此该插件把 context 路由上的 403 理解为不可访问涵盖两种成因。限流配置定义在 client.ts基于实测响应头x-ratelimit-limit: 300每窗口 300 次请求启用重试、初始延迟 1000ms、退避倍数 2并监听retry-after/x-ratelimit-remaining/x-ratelimit-limit响应头。值得注意的是x-ratelimit-reset的行为被实测为窗口长度而非倒计时因此故意未配置resetTime避免喂错字段。Webhooks当前无README 明确声明No webhooks.插件工厂中webhooks: {}、webhookSchemas: {}均为空见 packages/circleci/index.ts。源码注释进一步解释了原因目录中列出的 65 个操作完全不涉及 CircleCI 的 webhook 事件投递pipeline/workflow 完成通知本插件甚至没有把 webhook 管理暴露为普通操作——因为目录从未要求它。这意味着目前 Agent 无法通过该插件订阅 CircleCI 的事件推送只能通过轮询pipelines.list/workflows.listByPipelineId等操作感知状态变化。质量保障测试覆盖插件自带完整的测试套件package.json的test脚本test:live用于真实 API 集成测试client.test.ts传输层v2/v3/v1.1/GraphQL请求构造与解包逻辑endpoints.test.ts各端点的输入校验与调用参数error-handlers.test.ts错误分类与重试策略schema.test.ts数据库 schema 与 zod schema 的一致性integration.test.ts真实 API 的端到端验证需配置 CircleCI 凭据。许可该插件以Apache-2.0协议开源。小结把 CircleCI 交给 Agent 的正确姿势corsair-dev/circleci的价值在于Agent 无需直接接触 CircleCI Token而是通过 Corsair 的租户级凭据管理与权限体系安全地调用覆盖 contexts、pipelines、workflows、orbs、insights 等资源的 65 个操作。底层四种传输、一个凭据的设计让 API 的复杂性被完全封装而 read/write/destructive 风险分级、审计日志、环境变量值永不入日志、403 即不可访问等安全细节使它特别适合多租户 AI Agent 场景。若要进一步深入可直接阅读 packages/circleci/client.ts、packages/circleci/endpoints/types.ts 与 packages/circleci/error-handlers.ts 三份核心文件。【免费下载链接】corsairConnect your users to their apps项目地址: https://gitcode.com/GitHub_Trending/corsa/corsair创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考