From be738e4c8a9fff3f2327c5200963f843518d0c49 Mon Sep 17 00:00:00 2001 From: Mahesh-Kete Date: Fri, 3 Jul 2026 16:08:09 +0530 Subject: [PATCH 1/3] [LM-325] Add user attribution (@) to bash Package Firewall MDM scripts --- package-firewall/bash/generate.sh | 31 ++++++++------- package-firewall/bash/lib/common.sh | 39 +++++++++++++++++++ .../bash/templates/credentials.sh | 34 ++++++++++++++++ package-firewall/bash/templates/envsh.sh | 30 ++++++++++++-- package-firewall/bash/templates/go.sh | 9 ++++- package-firewall/bash/templates/js.sh | 10 ++++- package-firewall/bash/templates/maven.sh | 13 +++++-- package-firewall/bash/templates/python.sh | 12 +++++- package-firewall/shared/blocks/envsh.txt | 5 ++- 9 files changed, 156 insertions(+), 27 deletions(-) create mode 100644 package-firewall/bash/templates/credentials.sh diff --git a/package-firewall/bash/generate.sh b/package-firewall/bash/generate.sh index e704b2a..40fb32d 100755 --- a/package-firewall/bash/generate.sh +++ b/package-firewall/bash/generate.sh @@ -49,20 +49,20 @@ SHARED_BLOCKS_DIR="$SCRIPT_DIR/../shared/blocks" FQDN="${ENDOR_FQDN:-https://factory.endorlabs.com}" # ─── Compute derived values ──────────────────────────────────────────────────── +# Attribution-dependent values are NOT precomputed here. The per-machine attributed +# username (@) only exists on the developer's machine, so +# those (ENDOR_ATTR_USER, ENDOR_AUTH_B64, ENDOR_PYPI_URL, ENDOR_GO_PROXY_URL) are +# computed at install time by templates/credentials.sh. Only machine-independent +# values 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/" +API_SECRET_B64=$(printf '%s' "${ENDOR_API_SECRET}" | base64 | tr -d '\n') # ─── Output directory ───────────────────────────────────────────────────────── OUT_DIR="${SCRIPT_DIR}/out/${ENDOR_NAMESPACE}" @@ -74,16 +74,13 @@ substitute() { -e "s|{{NAMESPACE}}|${ENDOR_NAMESPACE}|g" \ -e "s|{{API_KEY_ID}}|${ENDOR_API_KEY_ID}|g" \ -e "s|{{API_SECRET}}|${ENDOR_API_SECRET}|g" \ + -e "s|{{API_SECRET_B64}}|${API_SECRET_B64}|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|{{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,7 +108,9 @@ 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. +# envsh.txt (bash-only) holds runtime placeholders — its ${ENDOR_*} values are +# resolved at install time by templates/envsh.sh, from the attribution +# credentials computed in templates/credentials.sh. emit_all_blocks() { echo "# ── Block content (from shared/blocks/) ─────────────────────────────────────" emit_block_assignment "ENVSH_BLOCK" "$SHARED_BLOCKS_DIR/envsh.txt" @@ -192,6 +191,9 @@ build_script() { { script_header "$output" "$description" + echo "# ── User attribution (credentials computed at install time) ──────────────────" + substitute < "$TMPL_DIR/credentials.sh" + echo "" emit_all_blocks echo "# ════════════════════════════════════════════════════════════════════════════" echo "# Env setup" @@ -247,6 +249,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/credentials.sh" + echo "" emit_all_blocks echo "# ════════════════════════════════════════════════════════════════════════════" echo "# Env setup" @@ -295,7 +300,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/credentials.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