PRIVATE WINGET REPOSITORY

Your own winget source, and only yours.

Attestree is a self-hosted winget repository that speaks the native winget REST protocol — so your endpoints resolve packages from a source you run, containing only the versions you approved. With a detonation host attached, an installer is served only once a sandbox verified it, or on Community Edition once you accept it unverified. Without one, nothing is verified, so by default no version is served.

Free Community Edition — self-host up to 200 endpoints, no Azure required

THE SOURCE ITSELF

A real REST source, not a repackaging script.

Winget resolves packages over a documented REST protocol. Attestree answers it directly, so the native client on your endpoints talks to your server the same way it would talk to the public source — no wrapper, no re-authoring manifests, no second package format to maintain.

GET /manifestSearch

The search endpoint winget calls to resolve a name. Yours answers from your catalog, so a package you never admitted simply does not exist to the fleet.

GET /packageManifests/{PackageIdentifier}

The manifest fetch. Returns the version your ring policy sets for that endpoint, with each installer’s SHA-256 pinned. With per-box serving on, it offers that endpoint only the installer verified for its architecture and install scope (or, on Community Edition, one you accepted), or nothing while that installer waits for verification.

Token-scoped per endpoint

Every endpoint gets its own feed token. Revoke one at decommission and that machine stops resolving packages, without touching the rest of the fleet.

WHY NOT JUST HOST A FEED

Hosting the packages is the easy half.

A feed answers "where from". It cannot answer "is this safe".

Hosting your own source controls provenance of delivery — nothing more. It does not inspect what the installer does. With a detonation host attached, the sandbox runs each installer your endpoints need, per architecture and install scope, before any endpoint is served it, and Attestree records the behaviour and the verdict. The feed is the delivery half; the gate is the half that decides.

The bytes can be yours, not the vendor’s CDN.

For every version detonated with the byte store on, the feed serves the attested installer bytes itself, over your LAN, pinned to the exact SHA-256 that was detonated. That takes the vendor download URL out of the install path for those versions — which is what makes a blocked CDN, a strict proxy, or a same-version republish a non-event rather than an outage. A version attested before the byte store was set up, or one whose kept bytes were cleaned up after it left every ring, still downloads from the vendor URL, under the same SHA-256 pin.

Machine scope and user scope, both first class.

Most self-hosted winget setups run as SYSTEM and quietly break on per-user apps. Attestree treats scope as an attested catalog property and installs user-scope packages into the actual user’s profile — not SYSTEM’s.

A private repository only helps if the public one is switched off.

Standing up your own source does nothing while endpoints can still reach winget’s default community source and the Microsoft Store source. Disabling those is a Group Policy and Intune job — the DesktopAppInstaller ADMX, an allowed-sources policy, and a source lockdown that survives a user re-adding one.

How to fence it
FAQ

Straight answers.

What is a private winget repository?

It is a winget source you host yourself, instead of pointing your fleet at the public community repository. Winget speaks a documented REST protocol — a search endpoint and a manifest endpoint — so any server that implements it can act as a source. A private winget repo lets you decide which packages and which exact versions exist for your machines at all. Attestree implements that protocol and adds the part a plain feed does not have: an ingest gate that, with a detonation host attached, detonates and attests each installer your endpoints need before any endpoint is served it.

Is this a real winget REST source, or a wrapper around winget-cli?

It is a real REST source. The control plane answers the documented winget source endpoints — information, manifestSearch and packageManifests — so the native winget client on your endpoints talks to it directly, with no wrapper script and no repackaging. Each endpoint authenticates with its own feed token.

How is this different from ProGet, Azure Artifacts, or winget-cli-restsource?

Those host a feed. That is a genuinely useful thing, and if all you need is somewhere to put manifests, they do it. What none of them do is inspect the artifact: there is no sandbox detonation, no CycloneDX SBOM generated at ingest, and no attestation recording what the installer actually did when it ran. Attestree records that attestation for each installer it detonates, and its source serves only the versions you promoted. Without a detonation host, nothing is verified, so by default Attestree serves no winget version.

Can I run an offline or air-gapped winget repository?

Your endpoints can be, and that is usually the half that matters: when every version they install was detonated with its bytes retained, endpoints resolve packages and download installers entirely from your server, so their egress collapses to a single allowlisted host instead of a fan of vendor CDNs. A version your server holds no bytes for — attested before the byte store was set up, or cleaned up after it left every ring — still downloads from its vendor host, and the architecture page lists every host by flow. The control plane is a different story, and we would rather be blunt than sell you something that does not exist. Ingest reaches out — it fetches the manifest and the installer so they can be detonated — so the server needs upstream access at admission time. You move the egress rather than eliminating it. A genuinely air-gapped deployment, where nothing reaches out at all, is not something we ship today.

Does it handle per-user applications, or only machine-wide installs?

Both, and the per-user case is the one most self-hosted setups get wrong. Running winget as SYSTEM installs a per-user application into SYSTEM’s own profile, where the person who asked for it will never see it. Attestree carries scope as an attested property of the package, installs user-scope apps into the real user’s profile, and attributes each copy to the user who actually has it. When nobody is logged on, it holds honestly and retries rather than reporting a success that is not there.

What happens when someone runs winget install for a package you never approved?

It does not resolve, because the package does not exist in your source — but the request is recorded rather than silently dropped. Blocked demand becomes catalog signal: you can see what people are asking for and decide whether to ingest it, instead of finding out when someone files a ticket or installs it from a browser download.