Skip to content

Commit 1fd3bab

Browse files
committed
ci: publish to Marketplace with a PAT instead of Entra OIDC
The blinkk publisher is owned by a personal Microsoft account, so the OIDC service principal cannot be added as a publisher member (TF14045 / InvalidAccessException). Switch release-ci.mjs to vsce publish --pat (VSCE_PAT, falling back to AZURE_PAT), drop the azure/login step and id-token permission, exclude .env and dev files from the VSIX, and update the publishing docs.
1 parent ee97b93 commit 1fd3bab

4 files changed

Lines changed: 61 additions & 140 deletions

File tree

.github/workflows/release.yml

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ permissions:
1616
# Required by changesets to push the version commit and open the release PR.
1717
contents: write
1818
pull-requests: write
19-
# Required to mint a short-lived Microsoft Entra ID token via OIDC for
20-
# azure/login (no stored Marketplace PAT).
21-
id-token: write
2219

2320
jobs:
2421
release:
@@ -59,23 +56,11 @@ jobs:
5956
pnpm test
6057
pnpm run build
6158
62-
# Sign in to Microsoft Entra ID via OIDC workload identity federation.
63-
# This stores a short-lived credential that `vsce publish
64-
# --azure-credential` (DefaultAzureCredential) uses to authenticate to the
65-
# Marketplace. No long-lived PAT is stored. Skipped when these repo
66-
# variables are unset (e.g. on the version-PR run, where nothing is
67-
# published).
68-
- name: Azure login (OIDC)
69-
if: vars.AZURE_CLIENT_ID != ''
70-
uses: azure/login@v2
71-
with:
72-
client-id: ${{ vars.AZURE_CLIENT_ID }}
73-
tenant-id: ${{ vars.AZURE_TENANT_ID }}
74-
allow-no-subscriptions: true
75-
7659
# When there are pending changesets, this opens (or updates) a
7760
# "Version Packages" PR. When that PR is merged, this step instead runs
78-
# the `publish` command to package and publish the extension.
61+
# the `publish` command to package and publish the extension. Publishing
62+
# authenticates to the Marketplace with the VSCE_PAT secret (a Marketplace
63+
# PAT with the Marketplace > Manage scope).
7964
- name: Create Release Pull Request or Publish
8065
id: changesets
8166
uses: changesets/action@v1
@@ -86,5 +71,7 @@ jobs:
8671
title: 'ci: release'
8772
env:
8873
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
89-
# Open VSX still uses a token (it is not part of Entra ID); optional.
74+
# Marketplace PAT used by `vsce publish` (Marketplace > Manage scope).
75+
VSCE_PAT: ${{ secrets.VSCE_PAT }}
76+
# Open VSX still uses its own token; optional.
9077
OVSX_PAT: ${{ secrets.OVSX_PAT }}

.vscodeignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,18 @@ eslint.config.js
1212
.editorconfig
1313
.gitignore
1414
.github/**
15+
docs/**
16+
scripts/**
17+
.changeset/**
18+
CHANGELOG.md
19+
CONTRIBUTING.md
20+
SECURITY.md
1521
pnpm-lock.yaml
1622
pnpm-workspace.yaml
1723
package-lock.json
1824
.npmrc
25+
.env
26+
.env.*
1927
**/*.map
2028
**/*.ts
2129
**/.DS_Store

docs/PUBLISHING.md

Lines changed: 28 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,138 +1,54 @@
1-
# Publishing setup (Microsoft Entra ID, no PAT)
1+
# Publishing setup (Marketplace PAT)
22

3-
This repo publishes to the VS Code Marketplace from GitHub Actions using
4-
**Microsoft Entra ID workload identity federation (OIDC)** — there is no
5-
long-lived Personal Access Token stored anywhere. (Global Azure DevOps PATs are
6-
retired on December 1, 2026.)
3+
This repo publishes to the VS Code Marketplace from GitHub Actions using a
4+
**Marketplace Personal Access Token (PAT)** stored as the `VSCE_PAT` repo
5+
secret. `vsce publish --pat` uses it to authenticate.
6+
7+
> A previous iteration used Microsoft Entra ID / OIDC workload identity
8+
> federation. That path requires adding a service principal as a member of the
9+
> publisher, which is not supported when the publisher is owned by a personal
10+
> Microsoft account. The PAT flow below works regardless.
711
812
How it works at release time:
913

1014
1. The version PR merges to `main`.
11-
2. `.github/workflows/release.yml` runs `azure/login@v2` with OIDC, which
12-
exchanges a GitHub-issued token for a short-lived Microsoft Entra token.
13-
3. `vsce publish --azure-credential` uses that token to publish.
15+
2. `.github/workflows/release.yml` runs the changesets action, which calls
16+
`pnpm run release:ci`.
17+
3. `release-ci.mjs` packages the extension and runs `vsce publish --pat`,
18+
reading the token from `VSCE_PAT` (or `AZURE_PAT` as a fallback).
1419

1520
You only do the setup below **once**.
1621

1722
---
1823

19-
## Prerequisites
20-
21-
- An Azure subscription + Entra (Azure AD) tenant (a free Azure account is
22-
fine). Sign in: <https://portal.azure.com>.
23-
- The `blinkk` publisher created at
24-
<https://marketplace.visualstudio.com/manage> (publisher ID must equal
25-
`"publisher": "blinkk"` in `package.json`).
26-
- Azure CLI installed locally (`brew install azure-cli`) and `az login` done,
27-
**or** use the Azure Portal equivalents.
28-
- `gh` authenticated for setting the repo variables.
29-
30-
---
31-
32-
## 1. Create an Entra app registration
33-
34-
```bash
35-
az ad app create --display-name "vscode-agent-platform-connector-publisher"
36-
```
37-
38-
Note the `appId` (this is the **client ID**) from the output. Then create a
39-
service principal for it:
40-
41-
```bash
42-
APP_ID="<appId from above>"
43-
az ad sp create --id "$APP_ID"
44-
```
45-
46-
Get your tenant ID:
47-
48-
```bash
49-
az account show --query tenantId -o tsv
50-
```
51-
52-
## 2. Add a federated credential for this GitHub repo
53-
54-
This is what lets GitHub Actions authenticate as the app without a secret.
55-
Create a file `federated.json`:
56-
57-
```json
58-
{
59-
"name": "github-release-main",
60-
"issuer": "https://token.actions.githubusercontent.com",
61-
"subject": "repo:blinkk/vscode-agent-platform-connector:ref:refs/heads/main",
62-
"description": "GitHub Actions release workflow on main",
63-
"audiences": ["api://AzureADTokenExchange"]
64-
}
65-
```
66-
67-
```bash
68-
az ad app federated-credential create --id "$APP_ID" --parameters federated.json
69-
```
70-
71-
> The `subject` must exactly match the workflow's trigger. `ref:refs/heads/main`
72-
> covers pushes to `main` (which is where the publish step runs). If you later
73-
> publish from tags or environments, add additional federated credentials with
74-
> the matching subject (e.g. `repo:OWNER/REPO:environment:production`).
75-
76-
## 3. Authorize the identity in the Marketplace publisher
77-
78-
The Entra identity must be a member of the `blinkk` publisher with
79-
**Contributor**.
80-
81-
1. Go to <https://marketplace.visualstudio.com/manage/publishers/blinkk>.
82-
2. Open the **Members** (or **Security**) tab → **Add**.
83-
3. Add the app registration (search by its display name / client ID) and assign
84-
the **Contributor** role.
85-
86-
> If the Marketplace UI only lets you add users (not app registrations
87-
> directly), add the app's **service principal**; some tenants surface it by the
88-
> display name set in step 1.
89-
90-
## 4. Set the GitHub repo variables
91-
92-
These are **variables**, not secrets — they are identifiers, not credentials:
24+
## 1. Create a Marketplace PAT
9325

94-
```bash
95-
gh variable set AZURE_CLIENT_ID --repo blinkk/vscode-agent-platform-connector --body "$APP_ID"
96-
gh variable set AZURE_TENANT_ID --repo blinkk/vscode-agent-platform-connector --body "$(az account show --query tenantId -o tsv)"
97-
```
98-
99-
## 5. (Optional) Open VSX
100-
101-
Open VSX is not part of Entra ID and still uses a token. Create one at
102-
<https://open-vsx.org> (Settings → Access Tokens) and add it as a secret:
26+
1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. Sigin1. Sign in to 1. Sign in to 1-> **New 1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. Se1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. Sign in to 1. 1. Sign in to 1. Sign in to 1. Sign in to 1. Sign intore the PAT as a GitHub repo secret
10327

10428
```bash
105-
gh secret set OVSX_PAT --repo blinkk/vscode-agent-platform-connector
106-
```
107-
108-
If `OVSX_PAT` is unset, CI simply skips the Open VSX publish.
109-
110-
---
111-
112-
## Test the release flow
29+
gh secret set VSCE_PAT --repogh secret set VSCE_PAT --repogh secret set VSCE_PAT --repogh secret set VSC## 3gh secret set VSCE_PAT --repogh secret set VSCE_PAT --repogh secret set VSCEpegh secret set VSCE_PAT --repogh secret set VSCE_PAT --reecrgh secret set VSCE_PAT -et OVSXgh secret set VSCE_PAT --repogh-platgh secret set VSCE_PAT --repogh secret set VSCE_PAT --repogh secret set V.
30+
gh secret set VSCE_PAT -e flow
11331

11432
1. Make a change + `pnpm changeset` + commit + push to `main`.
11533
2. CI opens a **"Version Packages"** PR.
116-
3. Merge it. CI bumps the version, then publishes to the Marketplace via OIDC.
34+
3. Merge it. CI bumps the version,3. Merge it. CI bumps the version,3.ia 3.e PAT.
11735
4. Confirm at
11836
<https://marketplace.visualstudio.com/items?itemName=blinkk.vscode-agent-platform-connector>.
11937

12038
## Manual publish (fallback)
12139

40+
Export the PAT (or put it in a gitignored `.env` as `VSCE_PAT` / `AZURE_PAT`),
41+
then run the publish script:
42+
12243
```bash
123-
az login
124-
pnpm version # if there are pending changesets
125-
pnpm release # vsce publish --azure-credential
126-
pnpm release:ovsx # optional, needs OVSX_PAT in env
44+
export VSCE_PAT=... # or AZURE_PAT
45+
node ./scripts/release-ci.mjs
12746
```
12847

12948
## Troubleshooting
13049

131-
- **`AADSTS70021: No matching federated identity record found`** — the
132-
`subject` in the federated credential doesn't match the workflow context.
133-
Verify it is exactly `repo:blinkk/vscode-agent-platform-connector:ref:refs/heads/main`.
134-
- **403/401 from the Marketplace** — the app registration isn't a Contributor
135-
member of the `blinkk` publisher, or the publisher ID doesn't match
136-
`package.json`.
137-
- **`azure/login` skipped**`AZURE_CLIENT_ID` repo variable is empty (the
138-
`if: vars.AZURE_CLIENT_ID != ''` guard); set it per step 4.
50+
- **`InvalidAccessException: The requested operation is not allowed`** - the PAT
51+
lacks the **Marketplace > Manage** scope, or the account is not a member of the
52+
`blinkk` publisher.
53+
- **`.env files should not be packaged`** - ensure `.env` is listed in
54+
`.vscodeignore` (it is). Never commit `.env`; it is gitignored.

scripts/release-ci.mjs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@
22
/**
33
* CI publish step invoked by changesets/action after a "Version Packages" PR
44
* merges. Packages the extension once, then publishes the resulting .vsix to:
5-
* - the VS Code Marketplace, via Microsoft Entra ID (the prior `azure/login`
6-
* OIDC step in the workflow provides the credential; vsce uses
7-
* DefaultAzureCredential with `--azure-credential`). No PAT required.
8-
* - Open VSX (optional; only when OVSX_PAT is set, since Open VSX is not part
9-
* of Entra ID).
5+
* - the VS Code Marketplace, via a Marketplace Personal Access Token in the
6+
* `VSCE_PAT` env var (or `AZURE_PAT` as a fallback). The PAT must belong to
7+
* an account that is a member of the target publisher with the
8+
* Marketplace > Manage scope.
9+
* - Open VSX (optional; only when OVSX_PAT is set, since Open VSX uses its own
10+
* token).
1011
*
11-
* For a manual publish from a workstation, run `az login` first (then this
12-
* script's vsce step authenticates the same way).
12+
* For a manual publish from a workstation, export VSCE_PAT (or AZURE_PAT)
13+
* first, then run this script.
1314
*/
1415
import {execFileSync} from 'node:child_process';
1516
import {readFileSync} from 'node:fs';
@@ -25,12 +26,21 @@ function run(cmd, args) {
2526
// 1. Build the .vsix once.
2627
run('pnpm', ['exec', 'vsce', 'package', '--no-dependencies', '-o', vsix]);
2728

28-
// 2. Publish to the VS Code Marketplace using Entra ID (no PAT).
29+
// 2. Publish to the VS Code Marketplace using a PAT.
30+
const pat = process.env.VSCE_PAT || process.env.AZURE_PAT;
31+
if (!pat) {
32+
throw new Error(
33+
'No Marketplace PAT found. Set VSCE_PAT (or AZURE_PAT) with a token that ' +
34+
'has the Marketplace > Manage scope, as a repo secret in CI or in the ' +
35+
'environment locally.'
36+
);
37+
}
2938
run('pnpm', [
3039
'exec',
3140
'vsce',
3241
'publish',
33-
'--azure-credential',
42+
'--pat',
43+
pat,
3444
'--no-dependencies',
3545
'--packagePath',
3646
vsix,

0 commit comments

Comments
 (0)