Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/marketplace-identity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ name: Resolve Marketplace Identity

on:
workflow_dispatch:
inputs:
verify_marketplace_access:
description: Verify that the managed identity can publish for the configured Publisher
required: false
default: false
type: boolean

permissions:
contents: read
Expand Down Expand Up @@ -55,3 +61,13 @@ jobs:
''
('`{0}`' -f $profile.id)
) | Add-Content -Path $env:GITHUB_STEP_SUMMARY
- name: Verify Marketplace publishing permission
if: ${{ inputs.verify_marketplace_access }}
shell: pwsh
env:
PUBLISHER: ${{ vars.VSCODE_MARKETPLACE_PUBLISHER }}
run: |
if ([string]::IsNullOrWhiteSpace($env:PUBLISHER)) {
throw 'Set the VSCODE_MARKETPLACE_PUBLISHER repository variable before verifying Marketplace access.'
}
npx --yes @vscode/vsce@3.9.2 verify-pat --azure-credential $env:PUBLISHER
22 changes: 18 additions & 4 deletions docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,22 @@ az role assignment create \
--scope "/subscriptions/$SUBSCRIPTION_ID"
```

3. 为该身份创建 GitHub Environment 专用的联合凭据。Issuer、Subject 和 Audience 必须逐字一致;Environment 名称由工作流固定为 `marketplace-release`:
3. 查询仓库当前使用的 OIDC Subject 前缀,再为该身份创建 GitHub Environment 专用的联合凭据。Issuer、Subject 和 Audience 必须与 GitHub 实际签发的断言逐字一致;本仓库使用包含组织与仓库数字 ID 的稳定前缀,Environment 名称固定为 `marketplace-release`:

```bash
gh api repos/realSilasYang/CodeBookmark/actions/oidc/customization/sub

az identity federated-credential create \
--name GitHub-CodeBookmark-marketplace-release \
--identity-name CodeBookmarkMarketplacePublisher \
--resource-group CodeBookmark-Publishing \
--issuer https://token.actions.githubusercontent.com \
--subject repo:realSilasYang/CodeBookmark:environment:marketplace-release \
--subject repo:realSilasYang@64590265/CodeBookmark@1308408396:environment:marketplace-release \
--audiences api://AzureADTokenExchange
```

不要根据仓库显示名称自行拼接 Subject。若 GitHub 返回的 `sub_claim_prefix` 与上例不同,应以实际返回值加上 `:environment:marketplace-release`;Azure 登录错误中的 `presented assertion subject` 也可以用于逐字核对。

4. 在 GitHub 仓库创建名为 `marketplace-release` 的 Environment。工作流将发布 Job 绑定到此 Environment,因而 OIDC 令牌的 Subject 只能匹配上面的联合凭据:

```bash
Expand All @@ -121,14 +125,24 @@ gh variable set AZURE_TENANT_ID --repo realSilasYang/CodeBookmark --body "<托
gh variable set AZURE_SUBSCRIPTION_ID --repo realSilasYang/CodeBookmark --body "<Azure subscriptionId>"
```

6. 在 GitHub Actions 中手动运行 `Resolve Marketplace Identity` 工作流。它只登录 Entra、调用 Azure DevOps Profile API,并把非机密的 Marketplace identity resource ID 写入运行摘要,不会构建或发布扩展。也可以从终端触发:
6. 在 GitHub Actions 中手动运行 `Resolve Marketplace Identity` 工作流。它只登录 Entra、调用 Azure DevOps Profile API,并把非机密的 Marketplace identity resource ID 写入运行摘要,不会构建或发布扩展。首次运行不启用权限验证,也可以从终端触发:

```bash
gh workflow run marketplace-identity.yml --repo realSilasYang/CodeBookmark
gh workflow run marketplace-identity.yml \
--repo realSilasYang/CodeBookmark \
-f verify_marketplace_access=false
```

7. 从该工作流的 Summary 复制 identity resource ID,在 [Visual Studio Marketplace 管理页](https://marketplace.visualstudio.com/manage)打开 Publisher `realSilasYang`,使用这个 ID 添加成员并授予 `Contributor` 角色。这里不能使用 Azure 门户中的资源名称、客户端 ID 或对象 ID 代替。只有该身份已经加入 Marketplace Publisher,`--azure-credential` 才有发布权限。

8. 再次运行同一工作流并启用权限验证。它会调用 `vsce verify-pat --azure-credential` 验证托管身份确实具有 Publisher 发布权限,但不会上传或修改扩展;只有本次运行完整成功后,才创建正式版本标签:

```bash
gh workflow run marketplace-identity.yml \
--repo realSilasYang/CodeBookmark \
-f verify_marketplace_access=true
```

`AZURE_CLIENT_ID`、`AZURE_TENANT_ID` 和 `AZURE_SUBSCRIPTION_ID` 是资源标识,不是凭据。`azure/login` 在每次运行时使用 GitHub OIDC 换取短期令牌,`vsce` 再从已登录的 Azure CLI 会话取得该令牌。仓库不需要 Actions Secret;不要添加长期发布令牌或客户端密钥作为兼容路径。

配置完成后,可在创建正式标签前从 Actions 页面手动检查 Release 工作流配置,但不要用虚假版本标签测试发布。正式发布失败时先修正身份、变量或 Publisher 权限,再重新运行原工作流。
Expand Down
7 changes: 7 additions & 0 deletions scripts/verify-release-readiness.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,13 +175,20 @@ const marketplaceIdentityWorkflow = read(
path.join('.github', 'workflows', 'marketplace-identity.yml')
)
assert.match(marketplaceIdentityWorkflow, /workflow_dispatch:/)
assert.match(marketplaceIdentityWorkflow, /verify_marketplace_access:/)
assert.match(marketplaceIdentityWorkflow, /environment: marketplace-release/)
assert.match(marketplaceIdentityWorkflow, /id-token: write/)
assert.match(marketplaceIdentityWorkflow, /uses: azure\/login@v2/)
assert.match(marketplaceIdentityWorkflow, /app\.vssps\.visualstudio\.com\/_apis\/profile\/profiles\/me/)
assert.match(marketplaceIdentityWorkflow, /499b84ac-1321-427f-aa17-267ca6975798/)
assert.match(marketplaceIdentityWorkflow, /GITHUB_STEP_SUMMARY/)
assert.match(marketplaceIdentityWorkflow, /@vscode\/vsce@3\.9\.2 verify-pat --azure-credential/)
assert.match(marketplaceIdentityWorkflow, /VSCODE_MARKETPLACE_PUBLISHER/)
assert.doesNotMatch(marketplaceIdentityWorkflow, /VSCE_PAT|secrets\.|--pat\b/)
assert.match(
read(path.join('docs', 'RELEASING.md')),
/repo:realSilasYang@64590265\/CodeBookmark@1308408396:environment:marketplace-release/
)
assert.match(releaseWorkflow, /tags:[\s\S]*- v\*/)
assert.match(releaseWorkflow, /GITHUB_REF_NAME/)
assert.match(releaseWorkflow, /VSCODE_MARKETPLACE_PUBLISHER/)
Expand Down
Loading