Security and synthetic data
Synthetic data statement
Section titled “Synthetic data statement”Everything in this repository is synthetic. The generator creates fictional stores, generic medications, dates, and anonymous fill events from a fixed seed. There are no patients, prescribers, members, addresses, health records, real customer names, or PHI.
# Synthetic data
Everything in this folder is synthetic. It was produced by a seeded random generator and describes fictional stores, generic medication names, and anonymous fill events. There are no patients, prescribers, members, addresses, or health records, and the repository is not meant to hold PHI. Don't add real data here, even for a quick test.
## What's here
| Path | What it is ||---|---|| `generated/dim_date.csv` | One row per day, 2024-01-01 to 2025-12-31 (731 rows). || `generated/dim_store.csv` | 12 fictional stores in four regions. || `generated/dim_med.csv` | 60 generic medications in eight therapeutic categories. Codes like `M001` aren't real drug codes. || `generated/fact_rx_fill.csv` | About 41,500 fill events, new and refill. || `schema/tables.json` | Column names, types, and descriptions for every file. |
The column names are short, database-style codes on purpose (`rgn`, `ther_cat`, `proc_mins`, `fill_typ`). The baseline semantic model copies them as-is, and the labs turn them into business names with Copilot's help.The security policy says the same thing and sets the boundary for the repo:
## This repository holds synthetic data only
Everything in this repository is synthetic. The "Contoso Pharmacy" stores, medications, and prescription fills are generated by `tools/python/pharmacy_demo/datagen.py` from a fixed seed. There are no patients, prescribers, people, or health records of any kind.
**Do not use this repository, its scripts, or its workflows to store or process protected health information (PHI), personal data, or customer data.** It isn't designed, reviewed, or configured for that.
## What must never be committed
- Credentials, tokens, client secrets, certificates, or connection strings.- Tenant IDs, workspace IDs, capacity IDs, subscription IDs, or object IDs.- Real customer names, internal URLs, or screenshots from a real tenant.- Power BI Desktop local files: `.pbi/localSettings.json`, `.pbi/cache.abf`, `*.pbix`.
`scripts/Invoke-Validation.ps1` runs an identifier guard that fails on GUIDs, email addresses, and secret-like strings outside an allowlist (`rules/identifier-allowlist.yaml`). CI runs the same guard plus gitleaks. GitHub secret scanning and push protection are enabled on the upstream repository.
## Configuration
Every configuration file in the repo uses placeholders such as `<your-workspace-name>`. The demo needs no Fabric tenant, capacity, workspace, or service principal. If you extend it to deploy to Fabric, use workload identity federation (OIDC) from GitHub Actions and GitHub environments with required reviewers, and keep all identifiers in environment variables or secrets.Not for real health data
Section titled “Not for real health data”Do not use this repository, scripts, workflows, issues, screenshots, or lab site to store or process real health data, personal data, customer data, tenant IDs, workspace IDs, capacity IDs, subscription IDs, object IDs, secrets, internal URLs, or real account screenshots.
If you adapt the pattern for real data, do it in a separate private repository with your organization’s security review, data handling rules, governance, and deployment controls.
No secrets committed
Section titled “No secrets committed”Configuration files use placeholders and prompt inputs instead of literal secrets. For example, MCP settings should use ${input:...} or environment variables where values are needed. The cloud-agent MCP template contains no secrets and marks cloud Power BI Modeling MCP as read-only for this lab.
{ "$comment": "Template for Copilot cloud agent MCP configuration. Paste the mcpServers object into your repository's Settings > Copilot > Coding agent > MCP configuration. It contains no secrets. The cloud agent runs on Linux without Power BI Desktop. Power BI Modeling MCP ships a Linux build and can open a PBIP folder, but this lab hasn't verified that on the cloud agent, so it's read-only here and the cloud agent labs don't depend on it.", "mcpServers": { "powerbi-modeling-mcp": { "type": "local", "command": "npx", "args": [ "-y", "@microsoft/powerbi-modeling-mcp@0.5.0-beta.13", "--start", "--readonly" ],Secret scanning and push protection
Section titled “Secret scanning and push protection”The upstream public repository has GitHub secret scanning and push protection enabled. Local validation also runs hygiene checks that look for secret-like strings, GUIDs, email addresses, forbidden files, and PHI-like columns outside the allowlist.
Run the same validation before opening a PR:
pwsh ./scripts/Invoke-Validation.ps1 -Only hygieneCI runs the full validation on pull requests and pushes to main.
Dependency review
Section titled “Dependency review”The CI workflow includes GitHub dependency review on pull requests and fails on moderate or higher severity when dependency manifests change.
# Warns instead of failing until the maintainer has pushed the checkpoint tags. - name: Checkpoint tags if: runner.os == 'Linux' run: ./scripts/lab/Test-CheckpointTags.ps1 -AllowMissing
site: name: Lab site build runs-on: ubuntu-latest timeout-minutes: 15Least-privilege workflow permissions
Section titled “Least-privilege workflow permissions”Workflows use read-only repository permissions unless a job needs more. The cloud setup workflow grants contents: read so setup can install and validate before the agent starts.
permissions: contents: read
jobs: copilot-setup-steps: runs-on: ubuntu-latest timeout-minutes: 20 permissions: contents: readHooks as guardrails
Section titled “Hooks as guardrails”Hooks block or flag risky agent actions. The repo hook configuration runs before tool use, after tool use, and at session boundaries. On Windows it calls PowerShell. On Linux and macOS it calls bash.
{ "version": 1, "hooks": { "sessionStart": [ { "type": "command", "bash": "./scripts/hooks/run-hook.sh session-start", "powershell": "pwsh -NoProfile -File ./scripts/hooks/run-hook.ps1 -HookEvent session-start", "cwd": ".", "timeoutSec": 20 } ], "preToolUse": [ { "type": "command", "bash": "./scripts/hooks/run-hook.sh pre-tool-use", "powershell": "pwsh -NoProfile -File ./scripts/hooks/run-hook.ps1 -HookEvent pre-tool-use", "cwd": ".", "timeoutSec": 20 } ], "postToolUse": [ { "type": "command", "bash": "./scripts/hooks/run-hook.sh post-tool-use", "powershell": "pwsh -NoProfile -File ./scripts/hooks/run-hook.ps1 -HookEvent post-tool-use", "cwd": ".", "timeoutSec": 30 } ], "sessionEnd": [ { "type": "command", "bash": "./scripts/hooks/run-hook.sh session-end", "powershell": "pwsh -NoProfile -File ./scripts/hooks/run-hook.ps1 -HookEvent session-end", "cwd": ".", "timeoutSec": 10 } ] }The hooks are guardrails, not a replacement for review. You still inspect diffs, run validation, and use pull requests.
Tool approval
Section titled “Tool approval”Copilot tool calls can read, edit, run commands, or call MCP tools depending on the selected agent and surface. Read the tool request before approving it. Prefer custom agents with narrow tool lists when a task does not need broad access.
Site privacy
Section titled “Site privacy”The lab site stores progress in browser local storage. It has no analytics and no third-party scripts. Static assets are bundled with the site.
Reporting a vulnerability
Section titled “Reporting a vulnerability”Report security issues privately through GitHub’s Report a vulnerability button on the repository Security tab. Do not open a public issue for a vulnerability. The security policy says you should receive an acknowledgement within five business days.
## Reporting a vulnerability
Please report security issues privately through GitHub's "Report a vulnerability" button on the Security tab of this repository. Don't open a public issue. You'll get an acknowledgement within five business days.