Authenticated Repo Permission Baseline
On-demand flow lists every repo the service account can access via Lists All Repositories For The Authenticated User, writes to Excel Online, and flags any where the account unexpectedly has admin rights.
Provided as-is, without warranty of any kind. Review and test each pattern in a non-production environment before deploying it to live automations. See our Terms.
Overview
Authenticated Repo Permission Baseline is an on-demand governance flow that enumerates every GitHub repository the configured service account can reach, captures a full permission snapshot to an Excel Online (Business) workbook, and sends an HTML alert email whenever the account has unexpectedly been granted admin rights on a repo.
The flow is solution-aware: all tenant-specific values (SharePoint site, Excel drive/file/table IDs, alert recipient, GitHub visibility/affiliation filters) live in Dataverse environment variables, so the same managed solution can be promoted across environments without editing the flow itself. It ships in the Off state so an admin can populate env vars before turning it on.
Use Case
Service-account sprawl is the most common source of silent over-permissioning in GitHub orgs. A token issued for "CI can push to one repo" gets copied into a second automation, that automation is granted admin so it can manage webhooks, and two years later the account silently has admin on dozens of repos. This flow creates a point-in-time baseline you can schedule weekly (or run on demand after a new integration is added) to answer one question: what does this account actually have access to right now, and where does it have more access than it should?
The Excel workbook becomes the audit artifact; the alert email is what wakes somebody up when the answer changes.
The flow is ideal for teams that:
- IT admins and security engineers auditing GitHub service-account permissions
- Platform teams that need a periodic baseline of repo access for their CI/automation accounts
- Orgs tracking permission drift on long-lived integration tokens
- Compliance reviewers who need a point-in-time audit artifact (Excel workbook) of repo access
Flow Architecture
Manually trigger a flow
Manual triggerOn-demand instant trigger. Swap for a Recurrence trigger to run on a schedule (see Customizations).
Initialize environment-variable inputs
Initialize variable (x7)Read the seven flowlibs_RepoBaseline* env vars into local variables: Visibility, Affiliation, SharePointSite, ExcelDriveId, ExcelFileId, ExcelTable, AlertEmail.
Initialize working counters
Initialize variable (x2)varAdminRepoCount (int, starts at 0) and varAdminRepoRows (string, empty) — used to accumulate admin-repo findings while iterating.
List authenticated user repositories
GitHub - GetUserReposCalls List All Repositories For The Authenticated User with the visibility and affiliation values supplied by env vars. Returns every repo the configured GitHub identity can see.
For each repository
Apply to eachFor each repo returned by GitHub: write a baseline row to the Excel workbook, then check whether the authenticated account has admin permission and append an HTML row + increment the counter if so.
Append baseline row to Excel
Excel Online (Business) - AddRowV2Inside the foreach. Writes RepoName, FullName, Owner, Private, AdminPermission, PushPermission, PullPermission, HtmlUrl, and CapturedAtUtc (utcNow()) to the configured table in the Excel workbook.
If admin permission is true
If conditionInside the foreach. Tests coalesce(items('For_Each_Repository')?['permissions']?['admin'], false) — only the true branch does work; the false branch is a no-op.
Environment Variables
| Schema name | Type | Default | Description |
|---|---|---|---|
| flowlibs_RepoBaselineVisibility | String | all | GitHub repo visibility filter passed to List All Repositories. Accepts all, public, or private. |
| flowlibs_RepoBaselineAffiliation | String | owner,collaborator,organization_member | Comma-separated GitHub affiliation filter (no spaces) — controls which relationships count toward the enumeration. |
| flowlibs_RepoBaselineSharePointSite | String | https://your-tenant.sharepoint.com/sites/FlowLibs | SharePoint site URL hosting the Excel workbook. Used as the source parameter for the Excel Online action. |
| flowlibs_RepoBaselineExcelDriveId | String | <configure> | Drive ID of the document library that holds the Excel workbook. Set post-import to the real drive ID. |
| flowlibs_RepoBaselineExcelFileId | String | <configure> | File (item) ID of the Excel workbook. Set post-import to the real item ID. |
| flowlibs_RepoBaselineExcelTable | String | RepoBaseline | Table name inside the workbook. Create the table first with columns: RepoName, FullName, Owner, Private, AdminPermission, PushPermission, PullPermission, HtmlUrl, CapturedAtUtc. |
| flowlibs_RepoBaselineAlertEmail | String | alerts@yourcompany.com | Recipient(s) for admin-rights alerts. Comma-separated list supported. |
Connectors & Connections
| Connector | API name | Actions used |
|---|---|---|
| GitHub | shared_github | GetUserRepos (Lists repos the authenticated GitHub identity can see) |
| Excel Online (Business) | shared_excelonlinebusiness | AddRowV2 (Appends one row per repo to the baseline workbook table) |
| Office 365 Outlook | shared_office365 | SendEmailV2 (High-importance HTML alert when admin rights are detected) |
Note — All connections are referenced as solution connection references; the flow is portable between environments as long as a connection is mapped at import time.
Customization Guide
Almost every realistic variant of this flow can be implemented by changing environment variable values. A few cases require small edits inside the flow definition — those are called out explicitly below.
- Run it on a schedule
- Swap the Manual trigger for a Recurrence trigger. Weekly on Monday 06:00 UTC is a reasonable default — long enough to catch permission drift, short enough that the audit trail isn't useless.
- Promote the alert recipient to a distribution list
- flowlibs_RepoBaselineAlertEmail accepts comma-separated addresses. Add a security distribution list and the repo owner's team alias so admin-rights findings reach the right humans.
- Add a delta threshold
- Currently any admin repo triggers the alert. To alert only when admin count changes, add a Get rows (Excel) step before the loop that reads the previous run's summary, compare varAdminRepoCount to the previous value, and short-circuit the If when unchanged.
- Switch to org-scoped enumeration
- GetUserRepos returns only what the authenticated user can see. To enumerate a specific org's full repo list regardless of the account's visibility, replace the action with an HTTP call to GET https://api.github.com/orgs/{org}/repos?per_page=100 using the GitHub connector's raw HTTP pattern (or a paginated custom connector).
- Capture more signal per repo
- The Excel row schema is lean on purpose. If you want webhook-level detail, add a nested GET /repos/{owner}/{repo}/hooks call inside the foreach and a second Excel table — but beware of the per-run action quota on the API-connection tier.
- Route the alert to Teams instead of email
- Replace SendEmailV2 with PostMessageToConversation from the Microsoft Teams connector and pass the same HTML body as an Adaptive Card fact set.
Key Expressions
The flow is intentionally light on Power Fx / WDL gymnastics — the heaviest expressions are the branch-name concatenation and the approval outcome check. They are listed below in the order they appear in the flow.
EXPR.01Admin-permission check
Condition expression guarded by coalesce — protects against repos that return a null permissions object on some cross-org collaborations.
EXPR.02HTML table row builder
AppendToStringVariable expression that builds one HTML <tr> per admin repo. Inline styles are kept in the real action — omitted here for readability.
EXPR.03Alert subject
Subject of the alert email — embeds the admin repo count for at-a-glance triage.
EXPR.04Captured-at timestamp (ISO UTC)
Written into the CapturedAtUtc column on every Excel row so each baseline snapshot is timestamped.
EXPR.05Email header date (human-readable)
Rendered into the HTML email body header so reviewers know when the baseline was captured.
Comments
Sign in to join the conversation.
Sign inNo comments yet. Be the first to share your experience with this flow.