Skip to content

Security and synthetic data

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.

data/README.md (lines 1-15)
# 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:

SECURITY.md (lines 3-20)
## 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.

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.

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.

config/cloud-agent-mcp.template.json (lines 1-12)
{
"$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"
],

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:

Terminal window
pwsh ./scripts/Invoke-Validation.ps1 -Only hygiene

CI runs the full validation on pull requests and pushes to main.

The CI workflow includes GitHub dependency review on pull requests and fails on moderate or higher severity when dependency manifests change.

.github/workflows/ci.yml (lines 80-88)
# 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: 15

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.

.github/workflows/copilot-setup-steps.yml (lines 13-21)
permissions:
contents: read
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read

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.

.github/hooks/guardrails.json (lines 1-40)
{
"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.

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.

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.

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.

SECURITY.md (lines 22-24)
## 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.