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.
Install / Use
npx skills add microsoft/power-platform-skills --skill audit-ppmpluginInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
LegalSupported Platforms
Our assessment of audit-ppmplugin
audit-ppmplugin scores 85/100 on our quality scale, 116th of 207 Legal skills we index.
Its SKILL.md is 22 KB long, well organised into 10 sections with 1 code example: a thorough specification that gives an agent plenty to work with.
It has 919 GitHub stars, a meaningful sign that others use it.
Maintenance, license and trust
- The repository was last updated 12 days ago, so audit-ppmplugin is actively maintained.
- It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
audit-ppmplugin compared with similar skills
All 4 of these similar skills score higher than audit-ppmplugin; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| audit-ppmplugin (this skill)by microsoft | 85 | 919 | 12d ago | SKILL.md |
| algorithmic-artby anthropics | 100 | 177.9k | 14d ago | SKILL.md |
| pptxby anthropics | 100 | 177.9k | 14d ago | SKILL.md |
| designby nextlevelbuilder | 100 | 130.2k | 15d ago | SKILL.md |
| ui-ux-pro-maxby nextlevelbuilder | 100 | 130.2k | 15d ago | SKILL.md |
Frequently asked questions
- How do I install audit-ppmplugin?
- Run
npx skills add microsoft/power-platform-skills --skill audit-ppmplugin. The install tabs above show the steps for each supported agent. - Which AI agents does audit-ppmplugin work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is audit-ppmplugin safe to use?
- It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is audit-ppmplugin still maintained?
- The repository was last updated 12 days ago, so audit-ppmplugin is actively maintained.
Skill content
View source on GitHubname: audit-ppmplugin
description: "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."
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Skill
model: sonnet
/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 §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
- Read
shared/shared-instructions.mdandshared/ppmplugin-format.md. - 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>.ppmpluginat 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.
- If the user passed a path, use it. If it's a directory, look for
- 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. |
- Extract the bundle to a fresh temp dir for inspection (read-only on the original):
work=$(mktemp -d); ( cd "$work" && jar xf "<abs path to .ppmplugin>" )$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): 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 (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 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) (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) — these bare names are both denylist-prone and collision-prone in the shared NativeModules namespace. (Heuristic, not the real list — DeviceInfo returned READY locally yet was server-rejected; this would have warned.) | WARNING |
| mf-methods | every receivers[].methods is present, non-empty, ≤32, each matches ^[a-zA-Z_$][a-zA-Z0-9_$]{0,127}$ | CRITICAL |
| mf-receiver-name | each receivers[].name matches the JS-identifier regex | CRITICAL |
| mf-version-present | version is a non-empty string | WARNING |
| mf-no-sdk-fields | NO entrypoints.js, entrypoints.ts, extension.js, extension.hbc, extensionClassName, jsLayer fields in the manifest. Our native-only policy, NOT a server gate — the wrap injector treats entrypoints.js as optional and accepts it; we flag it so the native-only bundle stays unambiguous. WARNING, not a block. | WARNING |
Note in the report that only a known subset of incompatible exact names is checked locally
(mf-reserved-exact-known), so a clean local result does not guarantee the upload service will
accept the name.
Step 4 — Category C: Manifest ↔ bundle consistency
The declared entrypoints must match the binaries actually in the zip — exactly. (/assemble-ppmplugin reconciles this at build time; auditing the finished bundle catches a hand-edited manifest or a hand-zipped bundle.)
| Check | Asserts | Severity |
|---|---|---|
| consistency-has-native | at least one of entrypoints.android / entrypoints.ios is declared (a manifest-only bundle has nothing to load) | CRITICAL |
| consistency-android-dex | if entrypoints.android declared → android/<entrypoints.android.dex> exists in the zip | CRITICAL |
| consistency-ios-framework | if entrypoints.ios declared → ios/<entrypoints.ios.framework>.framework/ exists in the zip (flat framework — see ios-flat-framework-not-xcframework in Category E) | CRITICAL |
| consistency-no-orphan | every android/ or ios/ slice in the zip is backed by a matching declared entrypoint (no undeclared binary the runtime won't route) | WARNING |
| consistency-packageClass-shape | entrypoints.android.packageClass is a fully-qualified Java class name (^([a-z][a-z0-9_]*\.)+[A-Z][A-Za-z0-9_]*$) | CRITICAL |
| dispatch-composite-key | the composite routing key <name>/<receivers[].name> is well-formed (both segments present, JS-identifier-safe suffix) — this is what a dispatcher PCF binds as ReceiverKey to reach NativeModules.<nativeModule>.<method> (format §2 — Runtime dispatch contract) | WARNING |
Step 5 — Category D: DEX integrity + SDK-leakage byte-scan (Android)
Only if entrypoints.android is declared. The DEX is loaded via DexClassLoader (format §5); these confirm it's loadable and free of SDK-era leakage. Use dexdump -l plain <dex> if available, else strings <dex> — both expose the string/type pool the checks scan.
| Check | Asserts | Severity |
|---|---|---|
| dex-magic | first bytes are dex\n03[5-9] (valid DEX) | CRITICAL |
| dex-has-packageClass | the entrypoints.android.packageClass type descriptor (Lcom/.../<Pascal>Package;) is in the DEX — otherwise runtime class loading fails | CRITICAL |
| dex-has-module-class | the module class descriptor is in the DEX | CRITICAL |
| dex-no-INativeExtension | NO INativeExtension, INativeOperation, INativeExtensionContext strings — SDK-era symbols in a native-only bundle. Cleanliness policy, not a server gate: the player ignores them (an old-pattern plugin still dispatches if its receivers[] map to real native modules), so surface it but don't block. | WARNING |
| dex-no-jslayer-loader | NO HermesBytecodeLoader, WrapPluginJsLayerLoader strings — a JS-layer loader has no place in a native-only DEX (same: flagged, not blocking). | WARNING |
| dex-no-sendAsync | NO sendAsync symbol — possible SDK transport leak | WARNING |
These SDK-leakage checks are the heart of the native-only contract: a clean compile can still pull these symbols in transitively. Scanning the built DEX is the only place they're catchable.
Step 6 — Category E: iOS framework structure (the wrap-CI gates)
Only if entrypoints.ios is declared. The CRITICAL set is exactly what the runtime's dlopen loading and wrap signing pipeline require. The umbrella header + module map are build hygiene only (the loader dlopens the binary; it never imports the module), so they're INFO — do not block a valid bundle on their absence.
| Check | Asserts | Severity |
|---|---|---|
| ios-flat-framework-not-xcframework | the bundle ships ios/<framework>.framework/ — NOT ios/<framework>.xcframework/. If an .xcframework is present, FAIL with the wrap-CI error verbatim ("Framework '<Name>.framework' not found in plugin") and the fix: rebuild with /build-ios-binary (device slice, flat framework — drop -create-xcframework). | CRITICAL |
| ios-binary-present | ios/<framework>.framework/<framework> (the Mach-O binary, named exactly <framework>) exists — the loader dlopens Frameworks/<framework>.framework/<framework>, so a missing or differently-named binary won't load | CRITICAL |
| ios-framework-has-infoplist | `ios/<framework>.framew
Truncated for display — read the full file on GitHub.
Related Skills
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
pptx
177.9kUse this skill any time a .pptx or .potx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx or .potx file (even if the extracted content will be used elsewhere, like in an em…
design
130.2kComprehensive design skill: brand identity, design tokens, UI styling, logo generation (55 styles, Gemini, Atlas Cloud, or MuAPI AI), corporate identity program (50 deliverables, CIP mockups), HTML presentations (Chart.js), banner design (22 styles, social/ads/web/print), icon design (15 styles, SVG…
ui-ux-pro-max
130.2kUI/UX design intelligence for web, mobile, and desktop. This skill should be used when designing, building, reviewing, or fixing interfaces, including pages, components, design systems, accessibility, interaction, responsive layout, typography, color, charts, and stack-specific UI implementation.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
