Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion plugins/power-pages/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 5 additions & 2 deletions plugins/power-pages/scripts/lib/validation-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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"/);
});
2 changes: 1 addition & 1 deletion plugins/power-pages/skills/activate-site/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
Loading