Skip to main content
ClaudeWave
Skill808 repo starsupdated 3d ago

audit-ppmplugin

Statically audit a built `.ppmplugin` before wrap testing. Checks archive layout, manifest compatibility, bundle consistency, Android DEX integrity and SDK leakage, iOS framework structure, native source-to-receiver alignment, and the PCF composite-key/sendAsync transport contract. Reports CRITICAL, WARNING, and INFO findings with fixes routed to the owning stage; never modifies the archive. Requires `jar`; `dexdump` or `strings` improves DEX inspection. Run after /assemble-ppmplugin or standalone on an existing bundle.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/microsoft/power-platform-skills /tmp/audit-ppmplugin && cp -r /tmp/audit-ppmplugin/plugins/power-apps-mobile-extension/skills/audit-ppmplugin ~/.claude/skills/audit-ppmplugin
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# /audit-ppmplugin

The verification gate. `/assemble-ppmplugin` proves the bundle is *well-formed*; this skill proves it will *actually load and dispatch* on the wrap runtime. Most `.ppmplugin` failures are silent — the bundle uploads fine, then a method returns `native module 'X' not loaded`, the runtime cannot instantiate the package class, or the upload is rejected with `0x80040265` (canonical-prefix violation). Those cost a full wrap-build round-trip to discover. This skill surfaces them in seconds, on disk.

It is **read-only on the bundle** — it unzips to a temp dir for inspection and never mutates the `.ppmplugin`. Fixes route back upstream (`/generate-ppmplugin-manifest` for manifest issues, the build skills for binary issues), then re-assemble + re-audit.

Read [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md) §1 (layout), §3 (canonical-prefix), §4 (validator rules), §5 (Android DEX requirements) — this skill enforces all four against the *built artifact*.

## What this skill does NOT do
- Does not build, zip, or author anything — it inspects a finished `.ppmplugin`. Fixes are made upstream and re-assembled.
- Does not patch the zip in place — a bundle is an immutable deliverable; mutating it would desync it from the staged sources. It points at the upstream skill instead.
- Does not upload to Dataverse / wire into a canvas app (Stage 3 — deferred). "READY TO UPLOAD"
  means *passes local verification*, not *uploaded*.

---

## Step 1 — Read shared docs + resolve the artifact + prereqs

1. Read [`shared/shared-instructions.md`](../../shared/shared-instructions.md) and [`shared/ppmplugin-format.md`](../../shared/ppmplugin-format.md).
2. **Resolve the bundle to audit:**
   - If the user passed a path, use it. If it's a directory, look for `<dir>/*.ppmplugin` (prompt if multiple).
   - Else default to the assemble output: the single `ppmplugin/<name>.ppmplugin` at the repo root (the most-recently-built if several).
   - If none found, STOP with `NEEDS_CONTEXT: no .ppmplugin to audit — run /assemble-ppmplugin first, or pass a path`.
3. Prereq block (shared-instructions §9.2). **Policy: resolve, don't punt** (§1.5) — locate a tool by path before failing:

| Check | Verify | If missing |
|---|---|---|
| `jar` (JDK) | `jar --version` — used to list + extract the bundle | STOP `BLOCKED: jar not found — install a JDK (JDK 17)` |
| DEX scanner | `dexdump` (preferred — locate in Android SDK `build-tools/*/dexdump` like `/build-android-binary` resolves `$D8`); else `strings` (mac/linux ships it) | If neither: the DEX **string** checks degrade to WARNING ("DEX scan skipped — no dexdump/strings"); structural checks (magic, size) still run. On Windows without either, note the gap. |

4. **Extract** the bundle to a fresh temp dir for inspection (read-only on the original):
   ```bash
   work=$(mktemp -d); ( cd "$work" && jar xf "<abs path to .ppmplugin>" )
   ```
   ```powershell
   $work = New-Item -ItemType Directory -Force (Join-Path $env:TEMP "ppm-audit"); Push-Location $work; jar xf "<abs path>"; Pop-Location
   ```

Each subsequent step appends findings to a running list as `[SEVERITY] <check-id>: <result>`. Don't stop at the first CRITICAL — collect everything so the user fixes in one pass. Severities: **CRITICAL** (will fail at upload or on device — blocks), **WARNING** (likely-wrong, may still work), **INFO** (style / advisory).

---

## Step 2 — Category A: Zip structure

Listing comes from `jar tf "<.ppmplugin>"`. The bundle is **native-only** ([format §1](../../shared/ppmplugin-format.md)): `manifest.json` at root + only the declared `android/` / `ios/` slices.

| Check | Asserts | Severity |
|---|---|---|
| `zip-manifest-at-root` | `manifest.json` is at the archive root | CRITICAL |
| `zip-only-native-slices` | top-level entries ⊆ { `manifest.json`, `android/`, `ios/` } | CRITICAL |
| `zip-no-ts-js-layer` | NO `src/`, `*.ts`, `*.tsx`, `*.js`, `extension.js`, `extension.hbc` anywhere — the bundle ships no TS/JS layer | CRITICAL |
| `zip-no-build-dirs` | NO `android-build/`, `ios-build/`, `node_modules/`, `dist/`, `build/` leaked in | CRITICAL |
| `zip-no-stray-files` | NO `META-INF/`, `.DS_Store`, dotfiles, nested `*.zip`/`*.ppmplugin` | WARNING |
| `zip-reasonable-size` | bundle < 50 MB (a larger one usually means React or node_modules got swept in) | WARNING |

A `src/` tree, an `extension.js`/`.hbc`, or any `*.ts` is **SDK-era / JS-layer leakage** — flag CRITICAL and point at [format §6](../../shared/ppmplugin-format.md) (the bundle is native binaries only).

---

## Step 3 — Category B: Manifest schema, validator rules + field leakage

Read the extracted `manifest.json`. Re-run **every** [`ppmplugin-format §4`](../../shared/ppmplugin-format.md) rule against the *built artifact* (defense in depth — the manifest may have been hand-edited after `/generate-ppmplugin-manifest`):

| Check | Asserts | Severity |
|---|---|---|
| `mf-name-shape` | `name` matches `^[a-z0-9][a-z0-9-]{0,63}$` | CRITICAL |
| `mf-canonical-prefix` | each `receivers[].nativeModule` starts with the canonical prefix of `name` (split on `-`/`_`, PascalCase each segment, join — [§3](../../shared/ppmplugin-format.md)) (Ordinal, case-sensitive) | CRITICAL |
| `mf-reserved-prefix` | no `nativeModule` starts with a reserved prefix (case-insensitive list in §4: `Microsoft`, `MS`, `Intune`, `Wrap`, `Pcf`, `PowerApps`, …) | CRITICAL |
| `mf-reserved-exact-known` | no `nativeModule` matches the locally checked incompatible-name subset (§4: `DeviceInfo`, `AuthenticationHelper`, `NetworkClient`, `DataverseOfflineProvider`, `IntuneMAM`). **Non-exhaustive**; fix = rename `getName()` to a non-reserved form (add `Module` suffix or a vendor prefix) and re-derive | CRITICAL |
| `mf-nativeModule-generic-noun` | `nativeModule` does NOT match the generic-platform-noun heuristic `^(Device\|Network\|File\|Audio\|Camera\|Sensor\|Location\|Storage\|Notification\|Bluetooth\|Wifi\|Media\|Photo\|Contact\|Calendar\|Battery)
add-data-sourceSkill

Guide the user to add a data source, connection, or API connector to a Canvas App via Power Apps Studio, then verify and continue. USE WHEN the user asks to add a data source, add a connection, add an API, add a connector, connect to SharePoint / Dataverse / SQL / Excel / OneDrive / Teams / Office 365, or any similar request to make new data available to the app. DO NOT USE WHEN the user is asking to list or describe existing data sources — call list_data_sources or list_apis directly instead.

canvas-appSkill

Creates or edits a Power Apps Canvas App through the Canvas Authoring MCP coauthoring session. Handles new app generation, direct targeted edits, complex multi-screen changes, responsive layout, per-screen self-QA, and compile-error convergence. Trigger on requests to create, build, generate, modify, update, change, fix, or edit a Canvas App or .pa.yaml files.

configure-canvas-mcpSkill

Configure the Canvas Authoring MCP server for the current coauthoring session. USE WHEN "configure MCP", "set up MCP server", "MCP not working", "connect Canvas Apps MCP", "canvas-authoring not available", "MCP not configured", "set up canvas apps".

generate-canvas-appSkill

[DEPRECATED — use canvas-app instead] Generate a complete Power Apps canvas app.

report-issueSkill

>

add-azuredevopsSkill

Adds Azure DevOps connector to a Power Apps code app. Use when querying work items, creating bugs, managing pipelines, or making ADO API calls.

add-connectorSkill

Use when adding a Power Platform connector to an Expo/React Native Power Apps mobile app and no dedicated mobile connector skill exists.

add-datasourceSkill

Use when adding an unspecified data source to an Expo/React Native Power Apps mobile app; routes to Dataverse, SharePoint, or another connector.