> For the complete documentation index, see [llms.txt](https://docs.we360.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.we360.ai/deployment-and-it-ops/deployment/agent-deployment-hub/verify-downloads.md).

# Verify Downloaded Installers

Verify a downloaded We360.ai MyZen installer before deploying it - check the publisher signature on Windows and macOS, and match the file against the published version and MD5 checksum.

Before you push an installer to a fleet, confirm two things about the file on disk:

1. **It came from us** - the file carries a valid publisher signature.
2. **It arrived intact** - its checksum matches the checksum we published for that build.

Both checks take under a minute and are worth running on every fresh download, especially for [mass deployment](/deployment-and-it-ops/deployment/agent-deployment-hub/mass-deployment.md) where one bad file reaches every endpoint.

{% hint style="info" %}
Always download from `https://portal.we360.ai` (or the portal URL issued for your deployment) over HTTPS. An installer obtained from a file-share, a chat attachment or a colleague's USB drive is exactly the case these checks exist for.
{% endhint %}

## Step 1 - Check the published version and checksum

Every installer on the download server has a companion metadata file at the same URL with `.version` appended. It is public, small, and lists the build version and the MD5 checksum of the installer:

{% tabs %}
{% tab title="Windows" %}

```powershell
Invoke-RestMethod "https://portal.we360.ai/static/installers/MyZenV2.msi.version"
```

{% endtab %}

{% tab title="macOS / Linux" %}

```bash
curl -s https://portal.we360.ai/static/installers/MyZenV2-arm64.pkg.version
```

{% endtab %}
{% endtabs %}

The response looks like this (extra build metadata fields may also be present):

```json
{
  "file": "MyZenV2-arm64.pkg",
  "version": "4.26.0-26222",
  "os": "macos",
  "arch": "arm64",
  "md5": "45c36169af2e0824bd5c2d3befd686c2"
}
```

Now compute the checksum of the file you downloaded and compare it to the `md5` value:

{% tabs %}
{% tab title="Windows" %}

```powershell
Get-FileHash .\MyZenV2.msi -Algorithm MD5 | Select-Object -ExpandProperty Hash
```

{% endtab %}

{% tab title="macOS" %}

```bash
md5 -q MyZenV2-arm64.pkg
```

{% endtab %}

{% tab title="Linux" %}

```bash
md5sum zs-amd64.sh
```

{% endtab %}
{% endtabs %}

The values must match, ignoring case. A mismatch usually means a truncated or interrupted download - delete the file and download it again. If it still does not match, do not install it; contact support.

{% hint style="info" %}
The `version` field also tells you which build you are about to deploy, which is the quickest way to confirm a download is current before a fleet-wide rollout.
{% endhint %}

## Step 2 - Check the publisher signature

### Windows (EXE and MSI)

The Windows installers are Authenticode-signed and timestamped, as are the executables they carry. Check the installer from PowerShell:

```powershell
Get-AuthenticodeSignature .\MyZenV2.msi | Format-List Status, SignatureType, SignerCertificate
```

Expected result:

| Field               | Expected value                                                                    |
| ------------------- | --------------------------------------------------------------------------------- |
| `Status`            | `Valid`                                                                           |
| `SignatureType`     | `Authenticode`                                                                    |
| Certificate subject | `CN=Zenstack Private Limited, O=Zenstack Private Limited, S=Madhya Pradesh, C=IN` |
| Certificate issuer  | `CN=Sectigo Public Code Signing CA E36, O=Sectigo Limited, C=GB`                  |

{% hint style="warning" %}
`Status` values other than `Valid` mean stop. `HashMismatch` means the file was modified after signing, `NotSigned` means it is not one of our published installers, and `UnknownError` on a machine with no internet access is usually a revocation-check failure - re-run the check from a machine that can reach the CA.
{% endhint %}

#### Checking the signature in the GUI (no PowerShell)

If you prefer to check by hand, or you are walking a colleague through it on a machine where scripts are restricted:

1. Right-click the downloaded `.exe` or `.msi` and choose **Properties**.
2. Open the **Digital Signatures** tab. If this tab is missing, the file is not signed - stop and re-download.
3. Under **Embedded Signatures**, confirm there is a row naming `Zenstack Private Limited`, with a `sha256` digest and a date in the **Timestamp** column.

![Windows file Properties dialog on the Digital Signatures tab, showing one embedded signature from Zenstack Private Limited with a sha256 digest and a timestamp](https://632025722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FicuEWisKb5zNsnnUwY1Y%2Fuploads%2Fgit-blob-af7a1907e9151fdd09d09a24f262b4c93e3bbd25%2Fwindows-properties-digital-signatures-tab.png?alt=media)

4. Select that row and click **Details**. The dialog must read **"This digital signature is OK."**, with **Name** showing `Zenstack Private Limited` and a **Countersignatures** entry from DigiCert - that countersignature is the trusted timestamp.

![Digital Signature Details dialog reading "This digital signature is OK" with signer Zenstack Private Limited, a signing time, and a DigiCert countersignature](https://632025722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FicuEWisKb5zNsnnUwY1Y%2Fuploads%2Fgit-blob-4e26a26ccd636ae904d586de02baa7d5773f3324%2Fwindows-digital-signature-details.png?alt=media)

5. Click **View Certificate**. On the **General** tab, **Issued to** must read `Zenstack Private Limited` and **Issued by** a Sectigo public code-signing CA. The **Certification Path** tab shows the full chain and should report "This certificate is OK".

![Certificate dialog General tab showing the certificate issued to Zenstack Private Limited by Sectigo Public Code Signing CA E36, with its validity dates](https://632025722-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FicuEWisKb5zNsnnUwY1Y%2Fuploads%2Fgit-blob-11aebceb4ebad9a4a128d41e3e5d67dcc6809db1%2Fwindows-signing-certificate-general.png?alt=media)

{% hint style="info" %}
An `.msi` shows the same information under **Embedded Signatures**; the empty **Catalog Signatures** list below it is normal and is not a problem. The certificate's validity dates are the dates the certificate is usable for signing - an installer signed while the certificate was valid keeps verifying after it expires, because of the timestamp.
{% endhint %}

Because the signature is timestamped, it stays valid after the signing certificate expires. A build signed today verifies years from now.

### macOS (PKG and DMG)

macOS installers are signed with an Apple-issued Developer ID certificate and notarized by Apple, with the notarization ticket stapled to the file so the check works offline.

```bash
pkgutil --check-signature MyZenV2-arm64.pkg
spctl -a -vv -t install MyZenV2-arm64.pkg
xcrun stapler validate MyZenV2-arm64.pkg
```

Expected output:

```
Package "MyZenV2-arm64.pkg":
   Status: signed by a developer certificate issued by Apple for distribution
   Notarization: trusted by the Apple notary service
   Certificate Chain:
    1. Developer ID Installer: Zenstack Private Limited (5KPT5U8WVR)
    2. Developer ID Certification Authority
    3. Apple Root CA

MyZenV2-arm64.pkg: accepted
source=Notarized Developer ID
origin=Developer ID Installer: Zenstack Private Limited (5KPT5U8WVR)

The validate action worked!
```

The team identifier in brackets - `5KPT5U8WVR` - is the value to match. For a `.dmg` or an extracted `.app`, use `codesign --verify --deep --strict --verbose=2 <path>` instead of `pkgutil`, and expect the same Developer ID identity.

#### Checking the signature in the GUI (Suspicious Package)

[Suspicious Package](https://mothersruin.com/software/SuspiciousPackage/) is a free macOS app that opens a `.pkg` without installing it. It is the usual choice for reviewing a package before deployment, because it shows the signature and the notarization status alongside everything the package would install.

1. Install Suspicious Package, then double-click the downloaded `.pkg` - it opens in Suspicious Package instead of the macOS Installer.
2. On the **Package Info** tab, check the signature summary: it must report the package as signed with a **Developer ID** certificate issued to `Zenstack Private Limited (5KPT5U8WVR)`, and as **notarized** by Apple.
3. Click through the signature entry to see the full certificate chain - `Developer ID Installer` -> `Developer ID Certification Authority` -> `Apple Root CA` - and the signing timestamp.
4. Anything else - unsigned, signed by an unexpected name, or not notarized - means the file is not one of our published installers. Delete it and download again.

The **All Files** and **All Scripts** tabs in the same window let a security reviewer see exactly what the package installs and which install scripts it runs, which is often what an internal review board asks for before a rollout.

{% hint style="info" %}
Without any extra software, double-clicking a signed `.pkg` opens the macOS Installer with a small lock icon in the title bar; clicking it shows the signing certificate. Suspicious Package is preferred because it never risks starting the installation.
{% endhint %}

{% hint style="warning" %}
`spctl` reporting `rejected` or `source=no usable signature`, or `stapler` reporting that the validate action failed, means the file is not a trusted copy of our installer. Delete it and download again from the portal.
{% endhint %}

### Linux

The Linux stealth installer is a shell script and is not code-signed. Verify it with the MD5 check in step 1, and download it only over HTTPS from the portal.

## Verifying stealth installers

Stealth installers are renamed to `<stealth_license_key>.<extension>` before use - see [Download Links & Utilities](/deployment-and-it-ops/deployment/agent-deployment-hub/download-links.md). Renaming does **not** affect any of these checks: the signature, the notarization ticket and the checksum all travel with the file contents, not the filename. You can verify before or after renaming, and both give the same result.

Two filename rules still matter, for reasons unrelated to signing:

* The name must be exactly the license key plus the extension. A duplicate-download suffix such as `zs-setup (1).exe` breaks the license the installer reads from its own filename.
* Verify the file you are about to distribute, not a re-saved copy. Re-zipping or re-exporting a PKG through an unpacking tool can drop the stapled notarization ticket.

## Where to go next

* [Download Links & Utilities](/deployment-and-it-ops/deployment/agent-deployment-hub/download-links.md) - the download URLs these checks apply to.
* [Windows Installation Validation](/deployment-and-it-ops/deployment/agent-deployment-hub/manual-installation/windows-validation.md) and [macOS Installation Validation](/deployment-and-it-ops/deployment/agent-deployment-hub/manual-installation/macos-validation.md) - what to check *after* the installer has run.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.we360.ai/deployment-and-it-ops/deployment/agent-deployment-hub/verify-downloads.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
