homebrew and js deloyment using only scripts

akamenev47
Contributor II

So, I have modified the classic LAPS API script to work over the new Jamf Pro UAPI (you can check it out it here: JAMF UAPI LAPS script ), did not realizing it will only work if jq binary is installed and working on the mac, so I am trying to put together a policy to install jq at enrollment complete and to push it to all the macs which don't have it currently installed.

 
What I have tried:
  1. Package the jr binary from my work mac, where jq is installed and working from /usr/local/bin/ using Composer
  2. To make sure it will be executable, I added "Execute Command" to the policy: chmod +x /usr/local/bin/jq​

 

 

But if I check for it via: which -a jq or try running curl with jq pipe - it can't find it...
I thought maybe $PATH is set incorrectly, but it looks alright to me:

 

 

 

 

akamenev@MacBook-Pro bin % ls -lh
total 0
lrwxr-xr-x 1 root wheel  89B Sep 22 17:41 authchanger -> /Library/Security/SecurityAgentPlugins/JamfConnectLogin.bundle/Contents/MacOS/authchanger
lrwxr-xr-x 1 root wheel  24B Sep 22 17:41 jamf -> /usr/local/jamf/bin/jamf
lrwxr-xr-x 1 root wheel  29B Sep 22 17:43 jamfAgent -> /usr/local/jamf/bin/jamfAgent
lrwxr-xr-x 1 root wheel  23B Sep 23 10:28 jq -> ../Cellar/jq/1.6/bin/jq
akamenev@MacBook-Pro bin % echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
akamenev@MacBook-Pro bin % which -a jq
jq not found

 

 

 

 

Am I missing something here? Or maybe someone had experience loading jq by itself?
Ahoy!
2 ACCEPTED SOLUTIONS

akamenev47
Contributor II

So, I was not able to extract jq or install jq by itself, but was able to trim autobrew script so it installs without the policy getting stuck and adding a Files and Processes > Execute Command, which successfully pushes jq and UAPI JSON is working now, whew!

 

Here is the trimmed autobrew script:

I have added to the script the permissions command:

 

currentuser=`stat -f "%Su" /dev/console`
chown -R $currentuser /usr/local/lib
#!/bin/sh
# AutoBrew - Install Homebrew with root
# Source: https://github.com/kennyb-222/AutoBrew/
# Author: Kenny Botelho
# Version: 1.2

# Set environment variables
HOME="$(mktemp -d)"
export HOME
export USER=root
export PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
BREW_INSTALL_LOG=$(mktemp)

# Get current logged in user
TargetUser=$(echo "show State:/Users/ConsoleUser" | \
    scutil | awk '/Name  && ! /loginwindow/ { print $3 }')

# Check if parameter passed to use pre-defined user
if [ -n "$3" ]; then
    # Supporting running the script in Jamf with no specialization via Self Service
    TargetUser=$3
elif [ -n "$1" ]; then
    # Fallback case for the command line initiated method
    TargetUser=$1
fi

# Ensure TargetUser isn't empty
if [ -z "${TargetUser}" ]; then
    /bin/echo "'TargetUser' is empty. You must specify a user!"
    exit 1
fi

# Verify the TargetUser is valid
if /usr/bin/dscl . -read "/Users/${TargetUser}" 2>&1 >/dev/null; then
    /bin/echo "Validated ${TargetUser}"
else
    /bin/echo "Specified user \"${TargetUser}\" is invalid"
    exit 1
fi

# Install Homebrew | strip out all interactive prompts
/bin/bash -c "$(curl -fsSL \
    https://raw.githubusercontent.com/Homebrew/install/master/install.sh | \
    sed "s/abort \"Don't run this as root\!\"/\
    echo \"WARNING: Running as root...\"/" | \
    sed 's/  wait_for_user/  :/')" 2>&1 | tee "${BREW_INSTALL_LOG}"

# Reset Homebrew permissions for target user
brew_file_paths=$(sed '1,/==> This script will install:/d;/==> /,$d' \
    "${BREW_INSTALL_LOG}")
brew_dir_paths=$(sed '1,/==> The following new directories/d;/==> /,$d' \
    "${BREW_INSTALL_LOG}")
# Get the paths for the installed brew binary
brew_bin=$(echo "${brew_file_paths}" | grep "/bin/brew")
brew_bin_path=${brew_bin%/brew}
# shellcheck disable=SC2086
chown -R "${TargetUser}":admin ${brew_file_paths} ${brew_dir_paths}
chgrp admin ${brew_bin_path}/
chmod g+w ${brew_bin_path}

# Unset home/user environment variables
unset HOME
unset USER

# Finish up Homebrew install as target user
su - "${TargetUser}" -c "${brew_bin} update --force"

# Run cleanup before checking in with the doctor
su - "${TargetUser}" -c "${brew_bin} cleanup"

sleep 1

currentuser=`stat -f "%Su" /dev/console`
chown -R $currentuser /usr/local/lib

exit 0

 

 

Then I have added it to the policy and in the Files and Processes > Execute Command, included this command:

 

thisUser=`stat -f '%u %Su' /dev/console | awk '{ print $2 }'`;su "$thisUser" -c "brew install jq"

 

 

This fully installs jq and JSON parsing with jq will work on that mac.

I suggest to trigger it at Enrollment Complete.

 

Also, if you need to implement this towards the macs in production, I did it this way:

2 extension attributes: 1 for brew presence and 1 for jq presence, 2 smart groups: Group 1 checks if brew is not installed on the mac, which is then scoped to a policy which pushes brew + jq to the affected mac, Group 2 checks if mac has brew present, but jq missing, which is then scoped to a policy which pushes only jq to the afected mac

 

thisUser=`stat -f '%u %Su' /dev/console | awk '{ print $2 }'`;su "$thisUser" -c "brew install jq"

 

 

Here are the 2 Computer Extension Attributes:

1) Brew presence check:

#!/bin/bash

if [ ! -z $(which brew) ];then
  echo "<result>Brew installed</result>"
else
  echo "<result>Brew Not installed</result>"
fi

exit 0

2) jq presence check:

#!/bin/bash

if [ ! -z $(which jq) ];then
  echo "<result>jq installed</result>"
else
  echo "<result>jq Not installed</result>"
fi

exit 0

 

Maybe not the best or cleanest solutions, but it works 🙂

 

Ahoy!

View solution in original post

I have modified the brew installation script, so now it will install brew and jq within 1 single script. You can find it here: https://gist.github.com/shurkin18/62ec34967794a32f9d63615db881ab5c 

Ahoy!

View solution in original post

8 REPLIES 8

sdagley
Esteemed Contributor II

@akamenev47 Are you sure what you packaged is a jq executable? You might also try just packaging the jq-osx-amd64 executable from the jq homepage: https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 You can also put the binary in a directory other than /usr/local/bin and use the full path to it in your script.

not sure, that's the thing 🙂

https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64  - I have seen this one, but unsure how can I "install" it or implement it for jq to work?

Ahoy!

sdagley
Esteemed Contributor II

@akamenev47 You don't need to "install" it, it's an executable binary. You just need the downloaded binary on the target Mac, with the executable flag set, and your script adjusted to call the binary by the full path

akamenev47
Contributor II

So, I was not able to extract jq or install jq by itself, but was able to trim autobrew script so it installs without the policy getting stuck and adding a Files and Processes > Execute Command, which successfully pushes jq and UAPI JSON is working now, whew!

 

Here is the trimmed autobrew script:

I have added to the script the permissions command:

 

currentuser=`stat -f "%Su" /dev/console`
chown -R $currentuser /usr/local/lib
#!/bin/sh
# AutoBrew - Install Homebrew with root
# Source: https://github.com/kennyb-222/AutoBrew/
# Author: Kenny Botelho
# Version: 1.2

# Set environment variables
HOME="$(mktemp -d)"
export HOME
export USER=root
export PATH="/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
BREW_INSTALL_LOG=$(mktemp)

# Get current logged in user
TargetUser=$(echo "show State:/Users/ConsoleUser" | \
    scutil | awk '/Name  && ! /loginwindow/ { print $3 }')

# Check if parameter passed to use pre-defined user
if [ -n "$3" ]; then
    # Supporting running the script in Jamf with no specialization via Self Service
    TargetUser=$3
elif [ -n "$1" ]; then
    # Fallback case for the command line initiated method
    TargetUser=$1
fi

# Ensure TargetUser isn't empty
if [ -z "${TargetUser}" ]; then
    /bin/echo "'TargetUser' is empty. You must specify a user!"
    exit 1
fi

# Verify the TargetUser is valid
if /usr/bin/dscl . -read "/Users/${TargetUser}" 2>&1 >/dev/null; then
    /bin/echo "Validated ${TargetUser}"
else
    /bin/echo "Specified user \"${TargetUser}\" is invalid"
    exit 1
fi

# Install Homebrew | strip out all interactive prompts
/bin/bash -c "$(curl -fsSL \
    https://raw.githubusercontent.com/Homebrew/install/master/install.sh | \
    sed "s/abort \"Don't run this as root\!\"/\
    echo \"WARNING: Running as root...\"/" | \
    sed 's/  wait_for_user/  :/')" 2>&1 | tee "${BREW_INSTALL_LOG}"

# Reset Homebrew permissions for target user
brew_file_paths=$(sed '1,/==> This script will install:/d;/==> /,$d' \
    "${BREW_INSTALL_LOG}")
brew_dir_paths=$(sed '1,/==> The following new directories/d;/==> /,$d' \
    "${BREW_INSTALL_LOG}")
# Get the paths for the installed brew binary
brew_bin=$(echo "${brew_file_paths}" | grep "/bin/brew")
brew_bin_path=${brew_bin%/brew}
# shellcheck disable=SC2086
chown -R "${TargetUser}":admin ${brew_file_paths} ${brew_dir_paths}
chgrp admin ${brew_bin_path}/
chmod g+w ${brew_bin_path}

# Unset home/user environment variables
unset HOME
unset USER

# Finish up Homebrew install as target user
su - "${TargetUser}" -c "${brew_bin} update --force"

# Run cleanup before checking in with the doctor
su - "${TargetUser}" -c "${brew_bin} cleanup"

sleep 1

currentuser=`stat -f "%Su" /dev/console`
chown -R $currentuser /usr/local/lib

exit 0

 

 

Then I have added it to the policy and in the Files and Processes > Execute Command, included this command:

 

thisUser=`stat -f '%u %Su' /dev/console | awk '{ print $2 }'`;su "$thisUser" -c "brew install jq"

 

 

This fully installs jq and JSON parsing with jq will work on that mac.

I suggest to trigger it at Enrollment Complete.

 

Also, if you need to implement this towards the macs in production, I did it this way:

2 extension attributes: 1 for brew presence and 1 for jq presence, 2 smart groups: Group 1 checks if brew is not installed on the mac, which is then scoped to a policy which pushes brew + jq to the affected mac, Group 2 checks if mac has brew present, but jq missing, which is then scoped to a policy which pushes only jq to the afected mac

 

thisUser=`stat -f '%u %Su' /dev/console | awk '{ print $2 }'`;su "$thisUser" -c "brew install jq"

 

 

Here are the 2 Computer Extension Attributes:

1) Brew presence check:

#!/bin/bash

if [ ! -z $(which brew) ];then
  echo "<result>Brew installed</result>"
else
  echo "<result>Brew Not installed</result>"
fi

exit 0

2) jq presence check:

#!/bin/bash

if [ ! -z $(which jq) ];then
  echo "<result>jq installed</result>"
else
  echo "<result>jq Not installed</result>"
fi

exit 0

 

Maybe not the best or cleanest solutions, but it works 🙂

 

Ahoy!

I have modified the brew installation script, so now it will install brew and jq within 1 single script. You can find it here: https://gist.github.com/shurkin18/62ec34967794a32f9d63615db881ab5c 

Ahoy!

sdagley
Esteemed Contributor II

@akamenev47 Installing brew just to get jq seems like overkill, and is your security org ok with brew being installed in your environment? (if they want LAPS it seems likely like they'd have issues with brew). The https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64 link in my earlier message is for the Mac executable version of the jq binary. Just download it, put it in a location that your script can reference (e.g. /Library/Application Support/MyOrg), package it with Composer, and deploy that package to your Macs.

Hmm, well engineers all have brew installed, otherwise everyone is admin and can install it themselves, is brew such a great security issue?

Ahoy!

sdagley
Esteemed Contributor II

@akamenev47 Do you have any sort of security or software standards approval process for software installed on Macs at your org, or are users free to install anything they want? If the answer to the former is yes then the several thousand apps that can be installed by brew casks might be an area of contention for your security & software standards groups