Skip to content

Commit 8251d2c

Browse files
authored
feat(model-apps): verify what persona security roles grant, + public-repo doc hygiene (#425)
* feat(model-apps): verify what persona security roles actually grant Two metadata-only verification gaps, both found while auditing what `verify` can and cannot prove. Neither needs a live browser or new infrastructure. 1. verify now proves what a persona role GRANTS, not just that it exists. The `role` check asserted only that a role ROW exists carrying the SDK ownership marker. It never looked at privileges - so a role created with the wrong access, or one whose privilege write failed after the row landed, verified clean. The new `role-privileges` check resolves each declared (entity, access) to its Dataverse PrivilegeId from the SAME metadata source the SDK writes against - EntityDefinitions(...)?$select=Privileges - and asserts the role holds it at AT LEAST the declared depth. SUBSET, not equality, and lib/role-privileges.js records why: appAccess injects appmodule read, unioned jobs escalate a shared entity+access to the max declared scope, and distinct entities can share ONE Dataverse privilege (a role holds one depth per privilege). Equality would fail on all three while telling us nothing true. Fails CLOSED on an unreadable role or table. The read deliberately does NOT go through sdk.fetchEntityMetadata: that returns a projected shape which drops Privileges entirely, so routing through it would have silently reported every privilege as unreadable. 2. personas[].jobs[].surfaces[] is checked instead of documentary. app-spec.js validated each entry as a non-empty string and stopped; spec-lint warned only when the array was EMPTY. So a job could name "My Open Work Orders" when no such view existed anywhere in the spec and every gate passed. lib/surface-resolver.js resolves each entry against the spec's own views, forms, pages (key OR name), dashboards, tables and sitemap titles. spec-lint WARNS on no match - a warning, never an error, because app-spec.js is loose on purpose: a surface may legitimately name an out-of-the-box artifact this spec does not author. verify adds a `job-surface` rollup - a PURE rollup over checks already computed, so it costs no extra reads - reporting a deployed failure as the job it broke ("persona P can no longer do job J") rather than only "view X is missing". Both wire into verifySpec's existing READER-GATED seam (the pattern entityRelationships / commandBar already use), so an existence-only reader behaves exactly as it did before.
1 parent 051c279 commit 8251d2c

62 files changed

Lines changed: 1768 additions & 361 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/validate-repository-metadata.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ jobs:
1010
runs-on: ubuntu-latest
1111
env:
1212
POWER_PLATFORM_SKILLS_TELEMETRY_POWER_PAGES_OPTOUT: "1"
13+
POWER_PLATFORM_SKILLS_TELEMETRY_MODEL_APPS_OPTOUT: "1"
1314
steps:
1415
- name: checkout
1516
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
@@ -36,3 +37,13 @@ jobs:
3637

3738
- name: validate-secure-process-execution
3839
run: node scripts/validate-secure-process-execution.js
40+
41+
# This repository is public, and the genpage eval fixtures are captured
42+
# agent transcripts that will faithfully record whatever live environment
43+
# an eval was run against. Guarding this in CI is the only reliable
44+
# control: a pasted transcript looks correct to a reviewer.
45+
- name: test-no-real-environments-validator
46+
run: node --test scripts/tests/validate-no-real-environments.test.js
47+
48+
- name: validate-no-real-environments
49+
run: node scripts/validate-no-real-environments.js

AGENTS.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,52 @@ This file provides guidance to AI Agents when working with code in this reposito
66

77
A **plugin marketplace** for Power Platform development by Microsoft. The Open Plugins marketplace manifest (`marketplace.json`) references individual plugins in `plugins/`. Each plugin has its own `AGENTS.md` with plugin-specific guidance.
88

9+
## This Repo Is PUBLIC — keep internal detail out of it
10+
11+
Everything here — code, docs, commit messages, PR descriptions, and branch names — is world-readable.
12+
Write for a reader outside Microsoft who cannot see any internal system.
13+
14+
**Do not commit:**
15+
16+
- **Internal hosts, repos or paths**`*.ghe.com` links, internal repo names, or a path into an
17+
internal repo's doc tree. Naming one discloses its existence and its structure.
18+
- **References to internal documents**, including indexes into them — "spec rank 14",
19+
"Group N P1", "(resolves C2, I1)", "see the R1 review". A reader who cannot open the document
20+
gets nothing from the pointer, and it advertises the document.
21+
- **Real environment, tenant or org identifiers** — Dataverse environment names/URLs, tenant GUIDs,
22+
subscription ids. These name real infrastructure. In examples use an obvious placeholder
23+
(`https://contoso.crm.dynamics.com`, `<envUrl>`); to record that something was live-verified, keep
24+
the **claim** and drop the environment ("live-verified", not "live-verified on <envname>").
25+
- **Internal review process** — who or which model reviewed something, how many rounds, internal
26+
finding ids. "Adversarially reviewed" is a useful signal; the rest is internal.
27+
- **Exploratory design docs for UNBUILT work** — roadmaps, prioritisation, and candid notes on
28+
limitations. A design doc for something that **shipped** is fine and often valuable (see
29+
`plugins/model-apps/docs/`); a proposal for something that has not is internal.
30+
- **Pointers to files that are not in the repo** — a citation nobody can resolve is noise at best.
31+
32+
**Fine to commit:** ADO / `AB#` work-item ids (opaque, and `AB#` is the standard Azure Boards ↔
33+
GitHub link syntax), and the location of a first-party source repo a maintainer needs in order to
34+
rebuild a vendored bundle. Both carry real "why" context and disclose no content.
35+
36+
**When you must record internal context**, put it in the PR conversation or an internal doc — not in
37+
a committed file. When editing an existing doc, keep this rule in mind for the lines around your
38+
change, not just the ones you add.
39+
40+
**CI enforcement (partial).** `node scripts/validate-no-real-environments.js` (wired into the
41+
`validate-repository-metadata` workflow) fails the build when a real Dataverse host, tenant, or
42+
previously-removed identifier appears under `plugins/model-apps/**` or `evals/model-apps/**`. It
43+
matches on *shape*`org<8 hex>` is what Dataverse auto-generates, so it is rejected even though it
44+
starts with the otherwise-allowed word `org` — rather than only re-catching known strings. Run it
45+
locally after touching eval fixtures or any file that quotes an environment URL.
46+
47+
The scan is **scoped to model-apps only**, and this is a real gap rather than an oversight: other
48+
plugins still carry pre-existing references of this class (for example real `org<8 hex>` orgs cited
49+
in power-pages provenance comments), so widening the scan today would fail unrelated PRs. Scrub a
50+
plugin first, then add it to `SCAN_PATHS`. The guard also cannot see the *local part* of a UPN, so
51+
`firstname.lastname@contoso.onmicrosoft.com` passes — use a role word (`maker@`, `tester@`).
52+
Captured `pac auth list` transcripts are the most common source of all three; when scrubbing one,
53+
prefer an **equal-length** placeholder so the fixed-width table stays aligned.
54+
955
## Repository Structure
1056

1157
```

evals/model-apps/app-builder/EVAL_GUIDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# App-Builder Offline Structural Eval Harness — Guide
22

33
> Companion to `evals/model-apps/genpage/EVAL_GUIDE.md`.
4-
> Source of truth: `plugins/model-apps/docs/app-builder-staged-flow-design.md` §13.
4+
> Source of truth: `plugins/model-apps/docs/app-builder-design.md` §13.
55
66
## What we evaluate
77

@@ -117,5 +117,5 @@ The live tier (`plugins/model-apps/scripts/smoke-eval.js`) is the thin live smok
117117
## Cross-links
118118

119119
- Plugin `AGENTS.md`*Eval Suite*
120-
- `plugins/model-apps/docs/app-builder-staged-flow-design.md` §13 — structural eval oracles
120+
- `plugins/model-apps/docs/app-builder-design.md` §13 — structural eval oracles
121121
- `evals/model-apps/genpage/EVAL_GUIDE.md` — the parallel eval suite for `/genpage`

evals/model-apps/genpage/fixtures/1-account-card-gallery/genpage-plan.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ D:\Projects\power-platform-skills\plugins\model-apps
1616

1717
## Environment
1818

19-
- Active Profile: aurora365-user1@auroratstgeo.onmicrosoft.com
20-
- URL: https://aurorabapenv4ab3f.crm10.dynamics.com/
19+
- Active Profile: contoso-user001@contosotest1.onmicrosoft.com
20+
- URL: https://contosobapenv0002.crm10.dynamics.com/
2121
- App: Sales Hub (12345678-1234-1234-1234-123456789abc)
2222
- Languages: English (1033) only
2323
- Solution: Default

evals/model-apps/genpage/fixtures/1-account-card-gallery/workflow-log.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
- (Run separately, not chained with &&)
1313

1414
### Auth check
15-
- `pac auth list` → active profile aurora365-user1@auroratstgeo.onmicrosoft.com
16-
- Active environment: https://aurorabapenv4ab3f.crm10.dynamics.com/ (reported to user)
15+
- `pac auth list` → active profile contoso-user001@contosotest1.onmicrosoft.com
16+
- Active environment: https://contosobapenv0002.crm10.dynamics.com/ (reported to user)
1717

1818
### Entity discovery
1919
- `pac model list-tables --search 'account'` — Account entity detected as existing (exact logical-name match: `account`)

evals/model-apps/genpage/fixtures/11-recruitment-multi-page/genpage-plan.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ D:\Projects\power-platform-skills\plugins\model-apps
1616

1717
## Environment
1818

19-
- Active Profile: aurora365-user1@auroratstgeo.onmicrosoft.com
20-
- URL: https://aurorabapenv4ab3f.crm10.dynamics.com/
19+
- Active Profile: contoso-user001@contosotest1.onmicrosoft.com
20+
- URL: https://contosobapenv0002.crm10.dynamics.com/
2121
- App: Recruitment Hub (44444444-3333-4444-5555-666666666666)
2222
- Languages: English (1033) only
2323
- Solution: Default

evals/model-apps/genpage/fixtures/11-recruitment-multi-page/workflow-log.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
- `pac help` → PAC CLI Version 2.11.0 (> 2.10.0 verified)
1212

1313
### Auth check
14-
- `pac auth list` → active profile aurora365-user1@auroratstgeo.onmicrosoft.com
15-
- Active environment: https://aurorabapenv4ab3f.crm10.dynamics.com/ (reported to user)
14+
- `pac auth list` → active profile contoso-user001@contosotest1.onmicrosoft.com
15+
- Active environment: https://contosobapenv0002.crm10.dynamics.com/ (reported to user)
1616

1717
### Entity discovery
1818
- `pac model list-tables --search 'contact,appointment'` — both entities detected as existing

evals/model-apps/genpage/fixtures/11-recruitment-pages-real/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ First real capture taken after the v2.2 planner-spec tightening landed.
66
## Source
77

88
Captured from a real `/genpage` session against
9-
`https://aurorabapenv610b3.crmtest.dynamics.com`. Driven by
9+
`https://contosobapenv0001.crmtest.dynamics.com`. Driven by
1010
`claude-sonnet-4-6` under the v2.1 plugin + v2.2 Phase 0.5 manifest generator
1111
+ v2.2 spec-tightening. Working dir was `D:/temp/recruitment-app/`.
1212

evals/model-apps/genpage/fixtures/11-recruitment-pages-real/genpage-plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ D:/temp/recruitment-app
1010
D:/Projects/power-platform-skills/plugins/model-apps
1111

1212
## Environment
13-
- URL: https://aurorabapenv610b3.crmtest.dynamics.com
13+
- URL: https://contosobapenv0001.crmtest.dynamics.com
1414
- App: create new: Recruitment App
1515
- Languages: English (1033) only
1616
- Solution: Crdec34

evals/model-apps/genpage/fixtures/11-recruitment-pages-real/workflow-log.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ PAC CLI Version 2.11.0+g06bb2eb (.NET 10.0.8)
1212

1313
`pac auth list`
1414
Index Active Kind Name User Cloud Type Environment Environment Url
15-
[1] UNIVERSAL akmaloo@microsoft.com Public OperatingSystem
16-
[2] UNIVERSAL aurorauser14@capintegration01.onmicrosoft.com Test User TMSBAPEnv5ee52 https://tmsbapenv5ee52.crmtest.dynamics.com/
17-
[3] * UNIVERSAL Aurora365-User1@auroratstgeo.onmicrosoft.com Test User AuroraBAPEnv610b3 https://aurorabapenv610b3.crmtest.dynamics.com/
15+
[1] UNIVERSAL developer@contoso.com Public OperatingSystem
16+
[2] UNIVERSAL fabrikamusr1@fabrikamtenant01.onmicrosoft.com Test User FabrikamEnv001 https://fabrikamenv001.crmtest.dynamics.com/
17+
[3] * UNIVERSAL Contoso-User001@contosotest1.onmicrosoft.com Test User ContosoBAPEnv0001 https://contosobapenv0001.crmtest.dynamics.com/
1818

19-
AskUserQuestion: Which environment should be used for the recruitment app? → [3] Aurora365-User1@auroratstgeo.onmicrosoft.comAuroraBAPEnv610b3 (currently active)
19+
AskUserQuestion: Which environment should be used for the recruitment app? → [3] Contoso-User001@contosotest1.onmicrosoft.comContosoBAPEnv0001 (currently active)
2020

2121
`pac auth select --index 3`
22-
New default profile: * UNIVERSAL : Aurora365-User1@auroratstgeo.onmicrosoft.com Test https://aurorabapenv610b3.crmtest.dynamics.com/
22+
New default profile: * UNIVERSAL : Contoso-User001@contosotest1.onmicrosoft.com Test https://contosobapenv0001.crmtest.dynamics.com/
2323

2424
`pac model list-languages`
2525
Found 1 enabled language(s):
@@ -75,7 +75,7 @@ User response: approved
7575
- Files written: package.json, genpage.d.ts (features: charts)
7676

7777
### Decisions
78-
- Environment: AuroraBAPEnv610b3 (https://aurorabapenv610b3.crmtest.dynamics.com/)
78+
- Environment: ContosoBAPEnv0001 (https://contosobapenv0001.crmtest.dynamics.com/)
7979
- PAC CLI: 2.11.0 (> 2.10.0 requirement met)
8080
- Node: v20.18.2
8181
- Languages: English only — no localization code needed

0 commit comments

Comments
 (0)