You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* feat(distribution): add enterprise bootstrap mirrors
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Redact bootstrap mirror output
Folds copilot-pull-request-reviewer follow-ups (credential redaction in mirror output, copy-pasteable self-update fallback, changelog placement).
Refs #1680
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix(install): do not send GitHub token to mirror hosts
install.sh attached the resolved GitHub token to APM_RELEASE_METADATA_URL
and APM_RELEASE_BASE_URL mirror requests, and install.ps1 leaked it on the
asset final-fallback and checksum-retry paths. Gate every auth attach on
mirror-env absence so the token rides only to the canonical GitHub /
configured GHES host, never to an operator mirror. The two scripts are now
symmetric. Adds static symmetry traps plus executable fail-closed exit-code
tests (no network) for the installer guards.
addresses CEO follow-up #1 (Auth Expert / Supply Chain) and Test Coverage
follow-up #3 on PR #1733.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs(install): clarify fail-closed GHES boundary and pip egress
Document that APM_NO_DIRECT_FALLBACK keys off the public github.com default:
a custom GHES GITHUB_URL still egresses to that host, so 'no direct fallback'
means no public fallback, not zero egress. Extend the no-egress smoke recipe
to wrap pip alongside curl so the PyPI fallback path is actually proven, and
note the token-to-canonical-host-only rule across installer and self-update
docs and the apm-guide usage doc.
addresses CEO follow-up #2 (Supply Chain), #4 (smoke pip path), and Doc
Writer nit on PR #1733.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(version-checker): use relative bootstrap_mirror import
Align version_checker.py with self_update.py: import the shared
bootstrap_mirror module via a package-relative path (from ..bootstrap_mirror)
for one consistent convention across both consumers.
addresses Python Architect nit on PR #1733.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: avoid auth header on release metadata mirrors
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: danielmeppiel <danielmeppiel@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
17
of `~/.hermes/config.yaml` (written atomically with `0o600` perms, preserving
18
18
unrelated config keys and refusing to overwrite a malformed file). `HERMES_HOME`
19
19
overrides the Hermes home directory. See the [Hermes integration guide](https://microsoft.github.io/apm/integrations/hermes/).
20
+
- Enterprise bootstrap mirror mode lets `install.sh`, `install.ps1`, and `apm self-update` use internal release, installer, and PyPI mirrors with fail-closed public fallback, and closes #1680. (#1733)
Copy file name to clipboardExpand all lines: docs/src/content/docs/getting-started/installation.md
+103-4Lines changed: 103 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -90,14 +90,113 @@ jobs:
90
90
|----------|---------|-------------|
91
91
| `APM_INSTALL_DIR` | `/usr/local/bin` (Unix) / `%LOCALAPPDATA%\Programs\apm\bin` (Windows) | Directory for the `apm` symlink / `apm.cmd` shim |
92
92
| `APM_LIB_DIR` | `$(dirname APM_INSTALL_DIR)/lib/apm` | *(Unix only)* Directory for the full binary bundle. Must end with `/apm` (for example, `/lib/apm`). The installer rejects shared directories (e.g. `$HOME/.local/share`) to prevent accidental data loss. |
93
-
| `GITHUB_URL` | `https://github.com` | Base GitHub URL (asset downloads **and** API host: `api.github.com`on github.com, `{GITHUB_URL}/api/v3` on GHES). Must be `https://`. |
93
+
| `GITHUB_URL` | `https://github.com` | Base GitHub URL (asset downloads **and** API host: `api.github.com`on github.com, `{GITHUB_URL}/api/v3` on GHES). Must be `https://` on Windows. |
94
94
| `APM_REPO` | `microsoft/apm` | Repository as `owner/name` |
95
95
| `VERSION` | *(latest)* | Pin a release tag (skips the **releases/latest** HTTP API). Must look like `v1.2.3` or `1.2.3`. |
96
+
| `APM_RELEASE_METADATA_URL` | *(unset)* | Exact mirror URL for release metadata, usually `latest.json` with at least `{"tag_name":"vX.Y.Z"}`. |
97
+
| `APM_RELEASE_BASE_URL` | *(unset)* | Base URL for release assets laid out as `{base}/{tag}/{asset}` and `{base}/{tag}/{asset}.sha256`. |
98
+
| `APM_INSTALLER_BASE_URL` | *(unset)* | Base URL containing `install.sh` and `install.ps1`; used by `apm self-update` and by your bootstrap one-liner. |
99
+
| `APM_PYPI_INDEX_URL` | *(unset)* | PyPI-compatible mirror used when the installer falls back to pip. |
100
+
| `APM_NO_DIRECT_FALLBACK` | *(unset)* | Set to `1` to fail closed when a mirror is missing or unreachable instead of using public GitHub, `aka.ms`, or PyPI. |
96
101
| `APM_SKIP_CHECKSUM` | *(unset)* | Windows only: set to `1` to skip `.sha256` verification on **pinned** installs (emergency only). |
97
102
98
-
> **Note - Unix (`install.sh`):** Latest-release discovery still calls `https://api.github.com/repos/.../releases/latest` unless `VERSION` is set. For GHES or mirrors with no access to `api.github.com`, pin `VERSION` so the script never hits that endpoint.
99
-
>
100
-
> **Note - Windows (`install.ps1`):** The **releases/latest** URL is derived from `GITHUB_URL`: `https://api.github.com` for GitHub.com, or `{GITHUB_URL}/api/v3` for GitHub Enterprise Server. Air-gapped runners should still set `VERSION` so the installer does not need the API at all. When `VERSION` is pinned, the release **`.sha256`** file is required unless you set **`APM_SKIP_CHECKSUM=1`** (emergency only).
103
+
### Enterprise bootstrap mirror mode
104
+
105
+
Mirror mode lets locked-down workstations install and update APM without direct public egress:
`APM_NO_DIRECT_FALLBACK=1`makes missing mirror settings and unreachable mirrors hard failures. It does not replace package-install proxying; keep using `PROXY_REGISTRY_URL` and `PROXY_REGISTRY_ONLY=1` for `apm install` dependencies.
144
+
145
+
#### What fail-closed does and does not cover
146
+
147
+
Fail-closed scoping keys off the public `github.com` default. The guard only blocks egress when the resolved host would be public GitHub (`github.com` / `api.github.com`), `aka.ms`, or public PyPI. It does **not** suppress egress to a custom `GITHUB_URL`: if you set a GHES host (for example `GITHUB_URL=https://github.corp.com`) together with `APM_NO_DIRECT_FALLBACK=1` and no release mirror, the installer still reaches that GHES host. This is intentional coexistence with GHES, but "no direct fallback" should not be read as "zero egress" -- it means "no fallback to public hosts". For true zero-egress, set the `APM_RELEASE_METADATA_URL` / `APM_RELEASE_BASE_URL` / `APM_INSTALLER_BASE_URL` / `APM_PYPI_INDEX_URL` mirrors so every request resolves to your internal hosts. The GitHub token is attached only when the request targets the canonical GitHub / configured GHES host; it is never sent to a mirror host.
148
+
149
+
Homebrew and Scoop mirror support is docs-only in this v0: mirror the tap or bucket with your package manager's normal enterprise controls, but the APM env vars above do not rewrite Homebrew or Scoop internals.
150
+
151
+
### No-egress smoke test
152
+
153
+
Run this on a disposable Linux or macOS runner. It starts a local mirror, wraps both `curl` and `pip` with deny-lists for public hosts, and expects the installer to fail only after downloading the fake archive. Any request to GitHub, `aka.ms`, PyPI, Homebrew, or Scoop fails the smoke test immediately. The `pip` wrapper makes the PyPI egress path explicit: pip fallback is gated by `APM_NO_DIRECT_FALLBACK` + `APM_PYPI_INDEX_URL`, so the wrapper proves pip cannot reach public PyPI even if the binary path falls back to it.
sh .apm-mirror-smoke/mirror/apm-install/install.sh || test $? -eq 1
197
+
```
198
+
199
+
For `apm self-update`, run `apm self-update --check` with the same env vars and verify your proxy, firewall, or CI egress logs show only the mirror host. Use a disposable runner for a full `apm self-update` because it executes the mirrored installer.
Copy file name to clipboardExpand all lines: docs/src/content/docs/reference/cli/self-update.md
+23-12Lines changed: 23 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -33,27 +33,38 @@ The command compares the installed version against the latest GitHub release and
33
33
Some package-manager distributions (for example, Homebrew) disable self-update at build time. In those builds, `apm self-update` prints a distributor-defined message (such as `brew upgrade apm`) and exits without running the installer. The startup update notification is also suppressed in those builds.
34
34
:::
35
35
36
-
## Air-gapped and GitHub Enterprise environments
36
+
## Enterprise bootstrap mirrors
37
37
38
-
`apm self-update` respects the same environment variables that `install.sh` honours
39
-
for air-gapped networks and GitHub Enterprise Server (GHE):
38
+
`apm self-update` uses the same mirror contract as the installer scripts. These variables are additive to the older `GITHUB_URL` / `APM_REPO` / `VERSION` flow:
40
39
41
40
| Variable | Default | Effect |
42
41
|----------|---------|--------|
43
-
|`GITHUB_URL`|`https://github.com`| Base URL of the GitHub host. When set to a GHE host (e.g. `https://gh.corp.com`), the version-check API uses `{GITHUB_URL}/api/v3` and the installer script is fetched from `{GITHUB_URL}/{APM_REPO}/raw/main/install.sh` (Unix) or `install.ps1` (Windows). |
44
-
|`APM_REPO`|`microsoft/apm`| Repository in `owner/repo` form. Overrides the default when using a fork or an internal mirror. |
45
-
|`VERSION`|_(unset)_| Pin a specific release (e.g. `v1.2.3`). Skips the GitHub API call entirely -- required for fully offline setups. The pinned version is passed through to the installer subprocess. |
42
+
|`APM_RELEASE_METADATA_URL`|_(unset)_| Exact URL for mirrored release metadata, usually a static `latest.json` with at least `{"tag_name":"vX.Y.Z"}`. Overrides GitHub release metadata lookup. |
43
+
|`APM_INSTALLER_BASE_URL`|_(unset)_| Base URL containing `install.sh` and `install.ps1`. `apm self-update` downloads the platform script from this base. |
44
+
|`APM_RELEASE_BASE_URL`|_(unset)_| Base URL containing release assets at `{base}/{tag}/{asset}`. The downloaded installer subprocess inherits this value. |
45
+
|`APM_PYPI_INDEX_URL`|_(unset)_| PyPI-compatible index used by installer pip fallback. |
46
+
|`APM_NO_DIRECT_FALLBACK`|_(unset)_| Set to `1` to fail closed instead of using public GitHub, `aka.ms`, or PyPI fallback. |
47
+
|`GITHUB_URL`|`https://github.com`| Legacy GitHub/GHES base URL. Still supported when mirror env vars are not set. |
48
+
|`APM_REPO`|`microsoft/apm`| Repository in `owner/repo` form for GitHub/GHES paths. |
49
+
|`VERSION`|_(unset)_| Pin a release tag and skip release metadata lookup. |
46
50
47
-
Examples:
51
+
Example:
48
52
49
53
```bash
50
-
# Air-gapped update: skip API, fetch installer from internal mirror
With `APM_NO_DIRECT_FALLBACK=1`, missing or unreachable mirror settings are hard failures with a non-zero exit. APM does not fall back to public GitHub, `aka.ms`, or PyPI in that mode.
65
+
66
+
Fail-closed scoping keys off the public `github.com` default: it blocks fallback to public hosts, not all egress. A custom `GITHUB_URL` (a GHES host) combined with `APM_NO_DIRECT_FALLBACK=1` and no release mirror still egresses to that GHES host -- this is intentional GHES coexistence. For zero public egress set the `APM_RELEASE_METADATA_URL` / `APM_RELEASE_BASE_URL` / `APM_INSTALLER_BASE_URL` / `APM_PYPI_INDEX_URL` mirrors. The GitHub token is sent only to the canonical GitHub / configured GHES host, never to a mirror host.
67
+
57
68
## Options
58
69
59
70
| Flag | Description |
@@ -104,7 +115,7 @@ The installer scripts accept a version pin via environment variable -- see [Quic
104
115
105
116
## Failure modes
106
117
107
-
If GitHub is unreachable, the download fails, or the installer exits non-zero, `apm self-update` exits with code `1` and prints the manual update command. Your existing binary is unaffected.
118
+
If GitHub or a configured mirror is unreachable, the download fails, or the installer exits non-zero, `apm self-update` exits with code `1` and prints the next mirror or manual update action. Your existing binary is unaffected.
0 commit comments