diff --git a/plugins/power-pages/.claude-plugin/plugin.json b/plugins/power-pages/.claude-plugin/plugin.json index 38a41fe07..2e3a10a68 100644 --- a/plugins/power-pages/.claude-plugin/plugin.json +++ b/plugins/power-pages/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "power-pages", - "version": "1.2.3", + "version": "1.3.0", "description": "Create and deploy Power Pages sites using modern development approaches. Supports code sites (SPAs) with React, Angular, Vue, or Astro, with more site types coming soon.", "author": { "name": "Microsoft", diff --git a/plugins/power-pages/AGENTS.md b/plugins/power-pages/AGENTS.md index f1abc77fd..86047fe0b 100644 --- a/plugins/power-pages/AGENTS.md +++ b/plugins/power-pages/AGENTS.md @@ -14,7 +14,7 @@ Read `PLUGIN_DEVELOPMENT_GUIDE.md` for UX and reliability standards when creatin - **Power Pages config loading** must reuse `scripts/lib/powerpages-config.js` anywhere a script reads `.powerpages-site` table-permission or site-setting YAML. Keep that module focused on loading/parsing code-site config only; put validation or business rules in separate validator modules. - **Script changes require tests** — Whenever you add a new script or modify an existing script, add or update `node:test` coverage under `scripts/tests/`. Prefer one `*.test.js` file per script/module being tested, and keep the test command passing: `node --test plugins/power-pages/scripts/tests/` (Node's built-in runner discovers `*.test.js` files under the given directory). Validator changes are not an exception; they must always ship with test coverage. - **Dataverse-backed validation** must stay opt-in for local runs only. Do not require live Dataverse connectivity in CI workflows or default test runs; gate it behind explicit local flags such as `--validate-dataverse-relationships`. -- **Azure CLI `--allow-no-subscriptions`** — pass this flag on AAD-only `az` operations (`az account get-access-token`, `az login`, `az account show`) so the plugin works for users whose Microsoft account has no Azure subscription. Do NOT add it to subscription-scoped commands (`az keyvault create|list`, `az group ...`, `az resource ...`) — those genuinely require a subscription. Reuse the shared `getAuthToken` helper in `scripts/lib/validation-helpers.js` instead of shelling out to `az` directly. +- **Azure CLI `--allow-no-subscriptions`** — this flag is only valid on `az login`. Other `az` subcommands (`az account get-access-token`, `az account show`, etc.) reject it as an unrecognized argument and exit 2, so do NOT add it to anything other than `az login`. When the user is not logged in to the Azure CLI, suggest plain `az login` first; only suggest `az login --allow-no-subscriptions` as a fallback if they don't have any associated Azure subscription, since that variant lets subscription-less accounts sign in and still mint AAD-scoped Dataverse/Power Platform tokens via subsequent `az account get-access-token` calls. Reuse the shared `getAuthToken` helper in `scripts/lib/validation-helpers.js` instead of shelling out to `az` directly. - **Reference docs** shared across skills live in `references/` — reference via `${CLAUDE_PLUGIN_ROOT}/references/` paths, don't duplicate. - **Templates** use `__PLACEHOLDER__` tokens (e.g., `__SITE_NAME__`) replaced during scaffolding. The `gitignore` file is stored without the dot prefix and renamed to `.gitignore` during scaffolding. - **Hooks** are defined centrally in `hooks/hooks.json`, using `PostToolUse` with matcher `Skill` so validation runs when a tracked Power Pages skill completes. diff --git a/plugins/power-pages/scripts/lib/validation-helpers.js b/plugins/power-pages/scripts/lib/validation-helpers.js index 123078e1d..a9979d6de 100644 --- a/plugins/power-pages/scripts/lib/validation-helpers.js +++ b/plugins/power-pages/scripts/lib/validation-helpers.js @@ -94,13 +94,16 @@ const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12 /** * Gets an Azure CLI access token for the given resource URL. - * `--allow-no-subscriptions` lets accounts without an Azure subscription mint AAD-scoped Dataverse/PP tokens. + * The `--allow-no-subscriptions` flag is only valid on `az login` (other `az` + * subcommands reject it as an unrecognized argument), so it must not be passed + * here. Accounts without a subscription can still mint AAD-scoped tokens after + * signing in via `az login --allow-no-subscriptions`. * @returns {string|null} Access token, or null if unavailable */ function getAuthToken(resourceUrl) { try { return execSync( - `az account get-access-token --resource "${resourceUrl}" --allow-no-subscriptions --query accessToken -o tsv`, + `az account get-access-token --resource "${resourceUrl}" --query accessToken -o tsv`, { encoding: 'utf8', timeout: 15000 } ).trim(); } catch { diff --git a/plugins/power-pages/scripts/tests/validation-helpers.test.js b/plugins/power-pages/scripts/tests/validation-helpers.test.js index bcd1ec79b..ca8f8e2ec 100644 --- a/plugins/power-pages/scripts/tests/validation-helpers.test.js +++ b/plugins/power-pages/scripts/tests/validation-helpers.test.js @@ -5,7 +5,7 @@ const childProcess = require('child_process'); const helpersPath = path.join(__dirname, '..', 'lib', 'validation-helpers.js'); -test('getAuthToken passes --allow-no-subscriptions to az', (t) => { +test('getAuthToken calls az account get-access-token without --allow-no-subscriptions (only az login accepts that flag)', (t) => { const originalExecSync = childProcess.execSync; let capturedCommand = null; @@ -26,6 +26,6 @@ test('getAuthToken passes --allow-no-subscriptions to az', (t) => { assert.equal(token, 'fake-token-value'); assert.match(capturedCommand, /^az account get-access-token /); - assert.match(capturedCommand, /--allow-no-subscriptions/); + assert.doesNotMatch(capturedCommand, /--allow-no-subscriptions/); assert.match(capturedCommand, /--resource "https:\/\/example\.crm\.dynamics\.com"/); }); diff --git a/plugins/power-pages/skills/activate-site/SKILL.md b/plugins/power-pages/skills/activate-site/SKILL.md index 8649ba742..f89a28720 100644 --- a/plugins/power-pages/skills/activate-site/SKILL.md +++ b/plugins/power-pages/skills/activate-site/SKILL.md @@ -81,7 +81,7 @@ pac auth who Verify the user is logged in to Azure CLI (the activation scripts acquire tokens internally): ```bash -az account show --allow-no-subscriptions +az account show ``` **If `az` is not installed or not logged in**: Instruct the user to install Azure CLI and run `az login --allow-no-subscriptions` (this form works whether or not the user has an Azure subscription — the activation flow only needs an AAD token).