Bootstrap Custo as the central distributor engine (MVP: AGENTS.md for module repos)#1
Bootstrap Custo as the central distributor engine (MVP: AGENTS.md for module repos)#1Marius Storhaug (MariusStorhaug) wants to merge 20 commits into
Conversation
Rewrite README to explain source-of-truth separation between MSXOrg/docs standards, initiative docs, and this distribution runtime. Add repo-root AGENTS.md with operator runbook for enabling live rollout. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Port Sync-Files.ps1 from PSModule/Distributor, generalized to read target organizations from config/targets.json instead of a hardcoded 'PSModule' owner. Add a JSON schema for the targets config. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Daily cron plus workflow_dispatch, mirroring PSModule/Distributor's GitHub App auth pattern via CUSTO_BOT_CLIENT_ID/PRIVATE_KEY secrets. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
First managed resource: a thin pointer AGENTS.md for PSModule module repos that references MSXOrg/docs and PSModule/docs instead of duplicating process text. Repositories opt in via Type=Module and SubscribeTo including 'AGENTS.md'. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
* During research on the GitHub module API surface (see PSModule/GitHub#653), I found that the current \PSModule/GitHub\ module uses -ApiEndpoint\ as the parameter name on \Invoke-GitHubAPI, not -Endpoint. PowerShell cannot resolve -Endpoint\ as a prefix abbreviation of -ApiEndpoint, so the three \Invoke-GitHubAPI\ calls in \scripts/Sync-Files.ps1\ will throw at runtime:
Affected lines — search for -Endpoint\ in the script (3 occurrences: PR list GET, PR create POST, label POST). Fix: change -Endpoint\ → -ApiEndpoint\ in all three calls. This was fixed in the parallel branch (PR #2, now closed) at commit \c0ce191. Related issues filed upstream:
|
Update Sync-Files.ps1 to use the current PSModule/GitHub parameter name (-ApiEndpoint) for PR lookup, PR creation, and label assignment. Behavior is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Switch sync target resolution to scope-based discovery. Add all-access mode (default) that enumerates all repositories visible to the app installation token and reads Type/SubscribeTo custom properties per repository. Keep organizations mode available for explicit filtering. Update targets schema/json and README accordingly. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add enterprise-level custom-property management for Type and SubscribeTo. Allowed values are now generated from the Repos tree and upserted via enterprise properties/schema endpoints before repository sync starts. Make this behavior config-driven in targets.json and document required app permissions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Introduce an explicit policy engine phase that runs enterprise controls before repository sync. In all-access mode, discovery is now grouped by organization to enforce enterprise -> organization -> repositories flow. Update README pipeline wording to match the new order. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add an enterprise-policy API helper that uses CUSTO_ENTERPRISE_PAT when present and falls back to GitHub App context otherwise. Wire enterprise custom-property sync to this helper, pass the optional secret into the workflow environment, and document the new secret. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Refactor Sync-Files to load and execute policy documents by layer (enterprise -> organization -> repository), separating policy capabilities from deployment configuration. Add initial policy documents for enterprise custom properties, enterprise rulesets, organization placeholder, and repository file subscription service. Keep repository sync capability explicit in policy documents. Update enterprise API auth strategy to prefer GitHub App context and fall back to CUSTO_ENTERPRISE_PAT only when app calls fail. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Introduce PolicyEngine/ with explicit separation between capabilities
and policies:
- Capabilities/{layer}/*.capability.json
- Policies/{enterprise}/{layer}/*.policy.json
Update sync runtime to load capabilities and validate policy docs
against supported capabilities, and resolve policy sets by enterprise
mapping from config/targets.json.
Migrate existing policy docs into the new hierarchy and update
documentation accordingly.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Build out explicit configuration for the two enterprise policy capabilities: - repo-custom-property: required/values-editability options - repo-rulesets: concrete starter ruleset payload config Update policy execution to consume the extended custom-property configuration fields and document the default enterprise policy files. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The auth-mode refactor misplaced the CapabilityCatalog parameter onto Sync-EnterpriseCustomPropertySchema (mandatory, never passed) while Invoke-PoliciesForScope referenced it without declaring it. Callers passed -CapabilityCatalog to a CmdletBinding function that rejected it, so the runtime failed on the first policy scope; even absent that, authMode was always null and fell back to github-app, so the enterprise-pat routing never executed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace line-based JSON comparison with recursive canonicalization (sorted keys) and a deep-subset check. Server-added fields and key ordering no longer register as drift, so enterprise property/ruleset PUTs only fire on real changes; array order remains significant. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Wrap the enterprise layer and each organization in try/catch so a single connect or traversal failure no longer aborts the whole fleet run; failures are recorded and counted (OrgsProcessed/OrgsFailed) and still fail the job at the end. Add Write-RunReport to emit a Markdown summary to GITHUB_STEP_SUMMARY (falls back to stdout locally). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add JSON Schemas for capability/policy documents; add Pester suites covering canonical diffing, subset drift detection, policy-path resolution, authMode routing, and conformance of every shipped capability/policy doc. Add a CI workflow running Pester + PSScriptAnalyzer (error severity) on push/PR. Also make the enterprise property GET catch blocks explicit rather than silently swallowing errors. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Correct the file-set layout description (no org dimension) and clarify all-access discovery (org installations, org repos only). Document the CUSTO_ENTERPRISE_PAT blast radius and mitigations, and the WhatIf/report/test-gate safety model. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The Resolve-PolicyLayerPaths and authMode routing tests hardcoded a C: drive and \C:\Users\marst\AppData\Local\Temp, which fail on the Linux CI runner (drive qualifier resolution and empty TEMP). Use System.IO.Path temp helpers so the suite passes on Windows and Linux. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Summary
Bootstraps
MSXOrg/Custoas the central managed-file distribution runtime for MSX initiatives,replacing
PSModule/Distributoras the engine. Ports the Distributor architecture, generalizes itto be org-agnostic, and ships the first managed resource: a thin-pointer
AGENTS.mdfor PSModulemodule repositories.
What's included
(standards in
MSXOrg/docs, initiative guidance in each initiative's docs repo, distributionruntime here).
AGENTS.md— repo-root agent onboarding pointer plus an operator runbook for enabling liverollout.
config/targets.json+ schema — target organizations as configuration, not hardcoded in thesync script. Defaults to
["PSModule"]for the MVP but any initiative can add its org here.scripts/Sync-Files.ps1— ported fromPSModule/Distributor, adapted to loop overconfigured target organizations instead of a hardcoded
PSModuleowner..github/workflows/sync-files.yml— daily scheduled sync +workflow_dispatch, same GitHubApp auth pattern as Distributor (
CUSTO_BOT_CLIENT_ID/CUSTO_BOT_PRIVATE_KEYsecrets).Repos/Module/AGENTS.md/AGENTS.md— the first managed file set: a thin pointer intoMSXOrg/docsandPSModule/docsrather than duplicated process text, matching the pattern usedby
PSModule/Template-PSModuleandPSModule/memory.Ready vs. blocked for live rollout
Ready:
schema checks pass).
config/targets.jsonchange.Blocked — no live sync can run yet:
CUSTO_BOT_CLIENT_ID/CUSTO_BOT_PRIVATE_KEYsecrets are not configured on this repo. Thepsmodule-s-custoGitHub App (app id1320343) is already installed on thePSModuleorganization, but its credentials live with
PSModule/Distributor, not here.SubscribeTocustom property updated to includeAGENTS.md.See
AGENTS.mdin this repo for the exact operator runbook.Next operator actions
CUSTO_BOT_CLIENT_ID/CUSTO_BOT_PRIVATE_KEYsecrets onMSXOrg/Custo(reuse orre-key the
psmodule-s-custoapp).Type = Moduleand addAGENTS.mdtoSubscribeToon repos that should receive it.Sync Managed Filesviaworkflow_dispatchas a dry run before relying on the dailyschedule.
PSModule/docsRepository-Defaults.mdtoreference Custo instead of
PSModule/Distributoronce this is live.Co-authored-by: Copilot App 223556219+Copilot@users.noreply.github.com