From acdf4e9f7619e82f2aae642f3f8e5316db8d0619 Mon Sep 17 00:00:00 2001 From: Mahesh-Kete Date: Tue, 30 Jun 2026 16:32:25 +0530 Subject: [PATCH 1/3] [LM-325] : added user attribution to Package Firewall MDM scripts (bash + PowerShell, all ecosystems) --- package-firewall/README.md | 3 +- package-firewall/bash/README.md | 4 +- package-firewall/bash/generate.sh | 36 +++++++++------ package-firewall/bash/lib/common.sh | 39 ++++++++++++++++ package-firewall/bash/templates/envsh.sh | 26 +++++++++-- package-firewall/bash/templates/go.sh | 8 +++- package-firewall/bash/templates/python.sh | 11 ++++- package-firewall/bash/templates/testing.sh | 34 ++++++++++++++ package-firewall/powershell/generate.ps1 | 45 ++++++++----------- package-firewall/powershell/lib/common.ps1 | 27 +++++++++++ .../powershell/templates/envvars.ps1 | 42 ++++++++++++----- package-firewall/powershell/templates/go.ps1 | 8 +++- .../powershell/templates/python.ps1 | 11 ++++- package-firewall/shared/blocks/envsh.txt | 9 ---- package-firewall/shared/blocks/goenv.txt | 2 +- .../shared/blocks/mavensettings.txt | 2 +- package-firewall/shared/blocks/npmrc.txt | 3 +- package-firewall/shared/blocks/pipconf.txt | 2 +- package-firewall/shared/blocks/uvtoml.txt | 2 +- package-firewall/shared/blocks/yarnrc.txt | 2 +- 20 files changed, 235 insertions(+), 81 deletions(-) create mode 100644 package-firewall/bash/templates/testing.sh delete mode 100644 package-firewall/shared/blocks/envsh.txt diff --git a/package-firewall/README.md b/package-firewall/README.md index 5fa25df..50acf3e 100644 --- a/package-firewall/README.md +++ b/package-firewall/README.md @@ -34,7 +34,6 @@ Both the bash and PowerShell generators read block content from `shared/blocks/` ``` shared/blocks/ -├── envsh.txt ← ~/.config/endor/env.sh content (bash only) ├── npmrc.txt ← .npmrc content ├── yarnrc_classic.txt ← .yarnrc content (yarn 1.x) ├── yarnrc.txt ← .yarnrc.yml content (yarn 2+) @@ -46,6 +45,8 @@ shared/blocks/ Edit these files to customise what gets written to developer machines. The orchestration scripts (`templates/*.sh` / `templates/*.ps1`) control which files get written and in what order. +> **User attribution:** the `${ENDOR_*}` credential values referenced by these blocks (e.g. `${ENDOR_ATTR_USER}`, `${ENDOR_AUTH_B64}`) are computed **at install time** on each developer's machine — see `bash/templates/testing.sh` and `powershell/templates/envvars.ps1`. This stamps `@` onto each firewall request (shown as **User** in the log) without per-user API keys. `~/.config/endor/env.sh` is generated from those values by `bash/templates/envsh.sh`. + --- ## Generated output diff --git a/package-firewall/bash/README.md b/package-firewall/bash/README.md index 6398c3a..19d3300 100644 --- a/package-firewall/bash/README.md +++ b/package-firewall/bash/README.md @@ -28,7 +28,6 @@ bash/ └── endor-remove.sh ../shared/blocks/ ← edit these to customise what gets written to config files -├── envsh.txt ← ~/.config/endor/env.sh content ├── npmrc.txt ← ~/.npmrc content ├── yarnrc_classic.txt ← ~/.yarnrc (yarn 1.x) content ├── yarnrc.txt ← ~/.yarnrc.yml (yarn 2+) content @@ -203,7 +202,6 @@ To change what gets written to a config file on target machines, edit the releva | File | Written to | |---|---| -| `../shared/blocks/envsh.txt` | `~/.config/endor/env.sh` | | `../shared/blocks/npmrc.txt` | `~/.npmrc` | | `../shared/blocks/yarnrc_classic.txt` | `~/.yarnrc` (yarn 1.x) | | `../shared/blocks/yarnrc.txt` | `~/.yarnrc.yml` (yarn 2+) | @@ -212,6 +210,8 @@ To change what gets written to a config file on target machines, edit the releva | `../shared/blocks/goenv.txt` | `~/.config/go/env` | | `../shared/blocks/mavensettings.txt` | `~/.m2/settings.xml` | +`~/.config/endor/env.sh` is no longer a static block — it is generated by `templates/envsh.sh` from the user-attribution credentials computed at install time in `templates/testing.sh` (which derives `${ENDOR_ATTR_USER}` etc. from `@`). + To change orchestration logic (which files get written, in what order, with what warnings), edit the relevant `templates/*.sh` file directly. Both support `{{PLACEHOLDER}}` substitution at generation time and `${ENDOR_VAR}` env var references at runtime: diff --git a/package-firewall/bash/generate.sh b/package-firewall/bash/generate.sh index e704b2a..bfc404a 100755 --- a/package-firewall/bash/generate.sh +++ b/package-firewall/bash/generate.sh @@ -49,21 +49,26 @@ SHARED_BLOCKS_DIR="$SCRIPT_DIR/../shared/blocks" FQDN="${ENDOR_FQDN:-https://factory.endorlabs.com}" # ─── Compute derived values ──────────────────────────────────────────────────── +# Credentials are NOT precomputed here. The per-machine attributed username +# (@) only exists on the developer's machine, so all auth +# values are computed at install time by templates/testing.sh. Only credential-free +# values (hosts, registry URLs) are derived here. FQDN_HOST="${FQDN#https://}" FQDN_HOST="${FQDN_HOST#http://}" TRUSTED_HOST="${FQDN_HOST%%:*}" NPM_REGISTRY_URL="${FQDN}/v1/namespaces/${ENDOR_NAMESPACE}/firewall/npm/" NPM_REGISTRY_HOST="${FQDN_HOST}/v1/namespaces/${ENDOR_NAMESPACE}/firewall/npm/" -NPM_AUTH_B64=$(printf '%s' "${ENDOR_API_KEY_ID}:${ENDOR_API_SECRET}" | base64 | tr -d '\n') -API_SECRET_B64=$(printf '%s' "${ENDOR_API_SECRET}" | base64 | tr -d '\n') - PYPI_URL="${FQDN}/v1/namespaces/${ENDOR_NAMESPACE}/firewall/pypi/simple/" -PIP_INDEX_URL="https://${ENDOR_API_KEY_ID}:${ENDOR_API_SECRET}@${FQDN_HOST}/v1/namespaces/${ENDOR_NAMESPACE}/firewall/pypi/simple/" - -GO_PROXY_URL="https://${ENDOR_API_KEY_ID}:${ENDOR_API_SECRET}@${FQDN_HOST}/v1/namespaces/${ENDOR_NAMESPACE}/firewall/go/,direct" MAVEN_REGISTRY_URL="${FQDN}/v1/namespaces/${ENDOR_NAMESPACE}/firewall/maven/" +# npm rejects self-signed TLS by default; relax it only for a localhost firewall +# (local testing). Empty for any real (staging/prod) host. +case "$TRUSTED_HOST" in + localhost|127.0.0.1|::1) NPM_STRICT_SSL="strict-ssl=false" ;; + *) NPM_STRICT_SSL="" ;; +esac + # ─── Output directory ───────────────────────────────────────────────────────── OUT_DIR="${SCRIPT_DIR}/out/${ENDOR_NAMESPACE}" mkdir -p "$OUT_DIR" @@ -75,15 +80,12 @@ substitute() { -e "s|{{API_KEY_ID}}|${ENDOR_API_KEY_ID}|g" \ -e "s|{{API_SECRET}}|${ENDOR_API_SECRET}|g" \ -e "s|{{FQDN}}|${FQDN}|g" \ + -e "s|{{FQDN_HOST}}|${FQDN_HOST}|g" \ -e "s|{{NPM_REGISTRY_URL}}|${NPM_REGISTRY_URL}|g" \ -e "s|{{NPM_REGISTRY_HOST}}|${NPM_REGISTRY_HOST}|g" \ - -e "s|{{NPM_AUTH_B64}}|${NPM_AUTH_B64}|g" \ - -e "s|{{API_SECRET_B64}}|${API_SECRET_B64}|g" \ + -e "s|{{NPM_STRICT_SSL}}|${NPM_STRICT_SSL}|g" \ -e "s|{{PYPI_URL}}|${PYPI_URL}|g" \ - -e "s|{{PIP_INDEX_URL}}|${PIP_INDEX_URL}|g" \ - -e "s|{{ENDOR_PYPI_URL}}|${PIP_INDEX_URL}|g" \ -e "s|{{TRUSTED_HOST}}|${TRUSTED_HOST}|g" \ - -e "s|{{GO_PROXY_URL}}|${GO_PROXY_URL}|g" \ -e "s|{{MAVEN_REGISTRY_URL}}|${MAVEN_REGISTRY_URL}|g" } @@ -111,10 +113,10 @@ emit_block_assignment() { # emit_all_blocks # Emits all block variable assignments into the generated script. # Edit shared/blocks/*.txt to change shared config content. -# Edit templates/envsh.txt to change the bash-only env var block. +# The env.sh block is built at runtime by templates/envsh.sh, from the +# attribution credentials computed in templates/testing.sh. emit_all_blocks() { echo "# ── Block content (from shared/blocks/) ─────────────────────────────────────" - emit_block_assignment "ENVSH_BLOCK" "$SHARED_BLOCKS_DIR/envsh.txt" emit_block_assignment "NPMRC_BLOCK" "$SHARED_BLOCKS_DIR/npmrc.txt" emit_block_assignment "YARNRC_CLASSIC_BLOCK" "$SHARED_BLOCKS_DIR/yarnrc_classic.txt" emit_block_assignment "YARNRC_BLOCK" "$SHARED_BLOCKS_DIR/yarnrc.txt" @@ -192,6 +194,9 @@ build_script() { { script_header "$output" "$description" + echo "# ── User attribution (credentials computed at install time) ──────────────────" + substitute < "$TMPL_DIR/testing.sh" + echo "" emit_all_blocks echo "# ════════════════════════════════════════════════════════════════════════════" echo "# Env setup" @@ -247,6 +252,9 @@ build_remove_script "$OUT_DIR/endor-remove.sh" { script_header "$OUT_DIR/endor-all.sh" \ "Configures all package managers for Endor Package Firewall. Covers: npm · pnpm · yarn classic · yarn 2+ · bun · pip · uv · poetry · go · maven" + echo "# ── User attribution (credentials computed at install time) ──────────────────" + substitute < "$TMPL_DIR/testing.sh" + echo "" emit_all_blocks echo "# ════════════════════════════════════════════════════════════════════════════" echo "# Env setup" @@ -295,7 +303,7 @@ echo " All scripts accept --dry-run to preview changes without writing anythin echo " Upload to your MDM tool. Each script is self-contained and idempotent." echo "" echo " To customise: edit shared/blocks/*.txt (shared config content)" -echo " or templates/envsh.txt (bash env var block)" +echo " or templates/testing.sh (user-attribution credential block)" echo " or templates/*.sh (orchestration logic)" echo "" echo " Re-running overwrites the same output directory." diff --git a/package-firewall/bash/lib/common.sh b/package-firewall/bash/lib/common.sh index 4268106..490c703 100644 --- a/package-firewall/bash/lib/common.sh +++ b/package-firewall/bash/lib/common.sh @@ -24,6 +24,45 @@ ENDOR_BLOCK_END="# ===== END ENDOR PACKAGE FIREWALL =====" ENDOR_XML_BLOCK_START="" ENDOR_XML_BLOCK_END="" +# ── User attribution helpers ────────────────────────────────────────────────── +# These let the generated scripts stamp @ onto each +# package-firewall request WITHOUT issuing per-user API keys. The label is encoded +# into the Basic-auth username; the firewall decodes it, authenticates with the +# real shared API key, and records the label on the firewall log (shown as "User"). +# The label is client-supplied and UNVERIFIED — telemetry only, never an authz signal. + +# endor_b64 — portable base64 with no line wrapping (reads stdin). +# GNU coreutils wraps at 76 cols unless -w0; BSD/macOS prints one line. +endor_b64() { + if base64 --help 2>&1 | grep -q -- '-w'; then + base64 -w0 + else + base64 | tr -d '\n' + fi +} + +# endor_urlenc_b64 — percent-encode a base64 string for use in URL userinfo. +# '+', '/' and '=' would otherwise break URL parsing; the tool decodes userinfo +# before building the Basic header, so the firewall still receives the raw base64. +endor_urlenc_b64() { + printf '%s' "$1" | sed -e 's/+/%2B/g' -e 's#/#%2F#g' -e 's/=/%3D/g' +} + +# endor_host_label — a stable, human-readable machine name for attribution. +endor_host_label() { + scutil --get ComputerName 2>/dev/null || hostname 2>/dev/null || echo unknown +} + +# endor_attr_username