├── .ansible-lint ├── .codespellignore ├── .github ├── dependabot.yml ├── stale.yml └── workflows │ ├── default-bare.yml │ ├── galaxy-release.yml │ ├── lint.yml │ └── stale.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .secrets.baseline ├── .yamllint ├── LICENSE ├── README.md ├── defaults └── main.yml ├── meta └── main.yml ├── tasks ├── archive-install.yml ├── darwin.yml ├── install-app.yml ├── macos-apps-version.yml ├── main.yml └── travis.yml └── test └── integration ├── default-target-user ├── bats │ └── idempotency.bats ├── default.yml └── serverspec │ ├── Gemfile │ ├── Rakefile │ └── run-local-tests.sh └── default ├── bats └── idempotency.bats ├── default.yml └── serverspec ├── Gemfile ├── Rakefile └── run-local-tests.sh /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | warn_list: 3 | - experimental 4 | exclude_paths: 5 | - .github/workflows/galaxy.yml 6 | -------------------------------------------------------------------------------- /.codespellignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/juju4/ansible-macos-apps-install/79e0850965b4aa1426cb212583401ca5165dbce8/.codespellignore -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot 3 | # Set update schedule for GitHub Actions 4 | 5 | version: 2 6 | updates: 7 | 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | # Check for updates to GitHub Actions every week 12 | interval: "weekly" 13 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Configuration for probot-stale - https://github.com/probot/stale 3 | 4 | # Number of days of inactivity before an Issue or Pull Request becomes stale 5 | daysUntilStale: 60 6 | 7 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 8 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 9 | daysUntilClose: 30 10 | 11 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 12 | onlyLabels: [] 13 | 14 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 15 | exemptLabels: 16 | - pinned 17 | - security 18 | - "[Status] Maybe Later" 19 | 20 | # Set to true to ignore issues in a project (defaults to false) 21 | exemptProjects: false 22 | 23 | # Set to true to ignore issues in a milestone (defaults to false) 24 | exemptMilestones: false 25 | 26 | # Set to true to ignore issues with an assignee (defaults to false) 27 | exemptAssignees: false 28 | 29 | # Label to use when marking as stale 30 | staleLabel: wontfix 31 | 32 | # Comment to post when marking as stale. Set to `false` to disable 33 | markComment: > 34 | This issue has been automatically marked as stale because it has not had 35 | recent activity. It will be closed if no further activity occurs. Thank you 36 | for your contributions. 37 | 38 | # Comment to post when removing the stale label. 39 | # unmarkComment: > 40 | # Your comment here. 41 | 42 | # Comment to post when closing a stale Issue or Pull Request. 43 | # closeComment: > 44 | # Your comment here. 45 | 46 | # Limit the number of actions per hour, from 1-30. Default is 30 47 | limitPerRun: 30 48 | 49 | # Limit to only `issues` or `pulls` 50 | # only: issues 51 | 52 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 53 | # pulls: 54 | # daysUntilStale: 30 55 | # markComment: > 56 | # This pull request has been automatically marked as stale because it has not had 57 | # recent activity. It will be closed if no further activity occurs. Thank you 58 | # for your contributions. 59 | 60 | # issues: 61 | # exemptLabels: 62 | # - confirmed 63 | -------------------------------------------------------------------------------- /.github/workflows/default-bare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: default-bare 3 | 4 | on: 5 | push: 6 | pull_request: 7 | workflow_dispatch: 8 | schedule: # run weekly, every monday 04:00 9 | - cron: '0 4 * * 1' 10 | 11 | permissions: {} 12 | 13 | jobs: 14 | build: 15 | 16 | permissions: 17 | contents: read 18 | runs-on: macos-latest 19 | strategy: 20 | fail-fast: false 21 | max-parallel: 4 22 | env: 23 | ANSIBLE_CALLBACKS_ENABLED: profile_tasks 24 | ANSIBLE_ROLE: juju4.macos_apps_install 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | with: 29 | path: ${{ env.ANSIBLE_ROLE }} 30 | - name: Set up Python 31 | uses: actions/setup-python@v5 32 | with: 33 | python-version: '3.x' 34 | - name: Install dependencies 35 | run: | 36 | python3 --version 37 | python3 -c "import ssl; print(ssl.OPENSSL_VERSION)" 38 | python3 -c 'import ssl; ssl.PROTOCOL_TLSv1_2' 39 | python3 -m pip install --upgrade pip 40 | pip3 install ansible-lint flake8 yamllint 41 | set -x 42 | which ansible || true 43 | pip3 install ansible 44 | pip3 show ansible 45 | ls -l $HOME/.local/bin || true 46 | ls -l /opt/hostedtoolcache/Python/3.9.1/x64/bin || true 47 | echo "/opt/hostedtoolcache/Python/3.9.1/x64/bin" >> $GITHUB_PATH 48 | ansible --version 49 | cd $GITHUB_WORKSPACE/$ANSIBLE_ROLE 50 | [ -f get-dependencies.sh ] && sh -x get-dependencies.sh 51 | { echo '[defaults]'; echo 'callbacks_enabled = profile_tasks, timer'; echo 'roles_path = ../'; echo 'ansible_python_interpreter: /usr/bin/python3'; } >> ansible.cfg 52 | - name: Environment 53 | run: | 54 | pwd 55 | env 56 | find . -ls 57 | - name: run test 58 | run: | 59 | cd $GITHUB_WORKSPACE/$ANSIBLE_ROLE && ansible-playbook -i localhost, --connection=local --become -vvv test/integration/default/default.yml 60 | env: 61 | PY_COLORS: '1' 62 | ANSIBLE_FORCE_COLOR: '1' 63 | - name: idempotency run 64 | run: | 65 | cd $GITHUB_WORKSPACE/$ANSIBLE_ROLE && ansible-playbook -i localhost, --connection=local --become -vvv test/integration/default/default.yml | tee /tmp/idempotency.log | grep -q 'changed=0.*failed=0' && (echo 'Idempotence test: pass' && exit 0) || (echo 'Idempotence test: fail' && cat /tmp/idempotency.log && exit 0) 66 | - name: After script 67 | run: | 68 | ls -A $HOME/ 69 | ls -A $HOME/Downloads 70 | ls /Applications 71 | ls -lh /usr/local/bin/ 72 | continue-on-error: true 73 | -------------------------------------------------------------------------------- /.github/workflows/galaxy-release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Galaxy-NG Roles Import 3 | 4 | on: 5 | release: 6 | types: [created, edited, published, released] 7 | push: 8 | tags: 9 | - '*' 10 | 11 | permissions: {} 12 | 13 | jobs: 14 | build: 15 | name: Galaxy Role Importer 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: 'Checkout git repo' 20 | uses: actions/checkout@v4 21 | with: 22 | submodules: true 23 | fetch-depth: 0 24 | 25 | - name: 'Release on galaxy' 26 | uses: ansible-actions/ansible-galaxy-action@388fe24563eb7889730a1c10587a8acd005bd42a 27 | with: 28 | galaxy_api_key: ${{ secrets.galaxy_api_key }} 29 | galaxy_version: 'main' 30 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: lint 3 | 4 | on: 5 | push: 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | permissions: {} 10 | 11 | jobs: 12 | build: 13 | 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: false 17 | max-parallel: 4 18 | env: 19 | ANSIBLE_CALLBACKS_ENABLED: profile_tasks 20 | ANSIBLE_EXTRA_VARS: "" 21 | ANSIBLE_ROLE: juju4.macos_apps_install 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | with: 26 | path: ${{ env.ANSIBLE_ROLE }} 27 | - name: Set up Python 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: '3.x' 31 | - name: Install dependencies 32 | run: | 33 | python3 --version 34 | python3 -c "import ssl; print(ssl.OPENSSL_VERSION)" 35 | python3 -c 'import ssl; ssl.PROTOCOL_TLSv1_2' 36 | python3 -m pip install --upgrade pip 37 | pip3 install ansible-lint flake8 yamllint 38 | set -x 39 | which ansible || true 40 | pip3 install ansible 41 | pip3 show ansible 42 | ls -l $HOME/.local/bin || true 43 | ls -l /opt/hostedtoolcache/Python/3.9.1/x64/bin || true 44 | echo "/opt/hostedtoolcache/Python/3.9.1/x64/bin" >> $GITHUB_PATH 45 | ansible --version 46 | cd $GITHUB_WORKSPACE/$ANSIBLE_ROLE 47 | [ -f molecule/default/requirements.yml ] && ansible-galaxy install -r molecule/default/requirements.yml 48 | { echo '[defaults]'; echo 'callbacks_enabled = profile_tasks, timer'; echo 'roles_path = ../'; echo 'ansible_python_interpreter: /usr/bin/python3'; } >> ansible.cfg 49 | - name: Fetch central settings repository 50 | run: | 51 | export settings_repo="https://raw.githubusercontent.com/juju4/ansible-ci-settings/main" 52 | cd $GITHUB_WORKSPACE/$ANSIBLE_ROLE 53 | set -x 54 | curl -o requirements.txt "$settings_repo/requirements.txt" 55 | curl -o .ansible-lint "$settings_repo/.ansible-lint" 56 | curl -o .yamllint "$settings_repo/.yamllint" 57 | pip install -r requirements.txt 58 | continue-on-error: true 59 | - name: Environment 60 | run: | 61 | pwd 62 | env 63 | find . -ls 64 | - uses: codespell-project/actions-codespell@master 65 | with: 66 | ignore_words_file: ${{ env.ANSIBLE_ROLE }}/.codespellignore 67 | skip: .git 68 | path: ${{ env.ANSIBLE_ROLE }} 69 | if: ${{ always() }} 70 | - name: yamllint 71 | run: | 72 | cd $GITHUB_WORKSPACE/$ANSIBLE_ROLE && yamllint . 73 | if: ${{ always() }} 74 | - name: ansible-lint 75 | run: | 76 | cd $GITHUB_WORKSPACE/$ANSIBLE_ROLE && ansible-lint 77 | if: ${{ always() }} 78 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 'Close stale issues and PRs' 3 | on: 4 | schedule: 5 | - cron: '30 1 * * *' 6 | 7 | jobs: 8 | stale: 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 15 | with: 16 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' 17 | days-before-stale: 30 18 | days-before-close: 5 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # https://github.com/github/gitignore/blob/master/Global/Vagrant.gitignore 2 | .vagrant/ 3 | 4 | # Log files (if you are creating logs in debug mode, uncomment this) 5 | # *.log 6 | 7 | # Ansible 8 | *.retry 9 | # Kitchen 10 | .kitchen 11 | inspec.lock 12 | # https://github.com/github/gitignore/blob/master/Global/Vim.gitignore 13 | # Swap 14 | [._]*.s[a-v][a-z] 15 | [._]*.sw[a-p] 16 | [._]s[a-v][a-z] 17 | [._]sw[a-p] 18 | 19 | # Session 20 | Session.vim 21 | Sessionx.vim 22 | 23 | # Temporary 24 | .netrwhist 25 | *~ 26 | # Auto-generated tag files 27 | tags 28 | # Persistent undo 29 | [._]*.un~ 30 | # https://github.com/github/gitignore/blob/master/Python.gitignore 31 | # Byte-compiled / optimized / DLL files 32 | __pycache__/ 33 | *.py[cod] 34 | *$py.class 35 | 36 | # C extensions 37 | *.so 38 | 39 | # Distribution / packaging 40 | .Python 41 | build/ 42 | develop-eggs/ 43 | dist/ 44 | downloads/ 45 | eggs/ 46 | .eggs/ 47 | lib/ 48 | lib64/ 49 | parts/ 50 | sdist/ 51 | var/ 52 | wheels/ 53 | *.egg-info/ 54 | .installed.cfg 55 | *.egg 56 | MANIFEST 57 | 58 | # PyInstaller 59 | # Usually these files are written by a python script from a template 60 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 61 | *.manifest 62 | *.spec 63 | 64 | # Installer logs 65 | pip-log.txt 66 | pip-delete-this-directory.txt 67 | 68 | # Unit test / coverage reports 69 | htmlcov/ 70 | .tox/ 71 | .coverage 72 | .coverage.* 73 | .cache 74 | nosetests.xml 75 | coverage.xml 76 | *.cover 77 | .hypothesis/ 78 | 79 | # Translations 80 | *.mo 81 | *.pot 82 | 83 | # Django stuff: 84 | *.log 85 | .static_storage/ 86 | .media/ 87 | local_settings.py 88 | 89 | # Flask stuff: 90 | instance/ 91 | .webassets-cache 92 | 93 | # Scrapy stuff: 94 | .scrapy 95 | 96 | # Sphinx documentation 97 | docs/_build/ 98 | 99 | # PyBuilder 100 | target/ 101 | 102 | # Jupyter Notebook 103 | .ipynb_checkpoints 104 | 105 | # pyenv 106 | .python-version 107 | 108 | # celery beat schedule file 109 | celerybeat-schedule 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | # https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 136 | # General 137 | .DS_Store 138 | .AppleDouble 139 | .LSOverride 140 | 141 | # Icon must end with two \r 142 | Icon 143 | 144 | # Thumbnails 145 | ._* 146 | 147 | # Files that might appear in the root of a volume 148 | .DocumentRevisions-V100 149 | .fseventsd 150 | .Spotlight-V100 151 | .TemporaryItems 152 | .Trashes 153 | .VolumeIcon.icns 154 | .com.apple.timemachine.donotpresent 155 | 156 | # Directories potentially created on remote AFP share 157 | .AppleDB 158 | .AppleDesktop 159 | Network Trash Folder 160 | Temporary Items 161 | .apdisk 162 | # https://github.com/github/gitignore/blob/master/Global/Linux.gitignore 163 | *~ 164 | 165 | # temporary files which can be created if a process still has a handle open of a deleted file 166 | .fuse_hidden* 167 | 168 | # KDE directory preferences 169 | .directory 170 | 171 | # Linux trash folder which might appear on any partition or disk 172 | .Trash-* 173 | 174 | # .nfs files are created when an open file is removed but is still being accessed 175 | .nfs* 176 | # https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 177 | # Windows thumbnail cache files 178 | Thumbs.db 179 | ehthumbs.db 180 | ehthumbs_vista.db 181 | 182 | # Dump file 183 | *.stackdump 184 | 185 | # Folder config file 186 | [Dd]esktop.ini 187 | 188 | # Recycle Bin used on file shares 189 | $RECYCLE.BIN/ 190 | 191 | # Windows Installer files 192 | *.cab 193 | *.msi 194 | *.msm 195 | *.msp 196 | 197 | # Windows shortcuts 198 | *.lnk 199 | # https://github.com/github/gitignore/blob/master/Global/GPG.gitignore 200 | secring.* 201 | # https://github.com/github/gitignore/blob/master/community/OpenSSL.gitignore 202 | # OpenSSL-related files best not committed 203 | 204 | ## Certificate Authority 205 | *.ca 206 | 207 | ## Certificate 208 | *.crt 209 | 210 | ## Certificate Sign Request 211 | *.csr 212 | 213 | ## Certificate 214 | *.der 215 | 216 | ## Key database file 217 | *.kdb 218 | 219 | ## OSCP request data 220 | *.org 221 | 222 | ## PKCS #12 223 | *.p12 224 | 225 | ## PEM-encoded certificate data 226 | *.pem 227 | 228 | ## Random number seed 229 | *.rnd 230 | 231 | ## SSLeay data 232 | *.ssleay 233 | 234 | ## S/MIME message 235 | *.smime 236 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | repos: 3 | - repo: https://github.com/pre-commit/pre-commit-hooks 4 | rev: v5.0.0 5 | hooks: 6 | - id: check-yaml 7 | - id: end-of-file-fixer 8 | - id: trailing-whitespace 9 | - id: check-added-large-files 10 | - id: check-json 11 | - id: detect-private-key 12 | - id: check-case-conflict 13 | - id: double-quote-string-fixer 14 | - id: requirements-txt-fixer 15 | - repo: https://github.com/ansible-community/ansible-lint.git 16 | rev: v25.1.3 17 | hooks: 18 | - id: ansible-lint 19 | files: \.(yaml|yml)$ 20 | - repo: https://github.com/Yelp/detect-secrets 21 | rev: v1.5.0 22 | hooks: 23 | - id: detect-secrets 24 | args: ['--baseline', '.secrets.baseline'] 25 | # exclude: .*/tests/.* 26 | - repo: https://github.com/codespell-project/codespell 27 | rev: v2.4.1 28 | hooks: 29 | - id: codespell 30 | args: [-I, .codespellignore] 31 | -------------------------------------------------------------------------------- /.secrets.baseline: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.5.0", 3 | "plugins_used": [ 4 | { 5 | "name": "ArtifactoryDetector" 6 | }, 7 | { 8 | "name": "AWSKeyDetector" 9 | }, 10 | { 11 | "name": "AzureStorageKeyDetector" 12 | }, 13 | { 14 | "name": "Base64HighEntropyString", 15 | "limit": 4.5 16 | }, 17 | { 18 | "name": "BasicAuthDetector" 19 | }, 20 | { 21 | "name": "CloudantDetector" 22 | }, 23 | { 24 | "name": "HexHighEntropyString", 25 | "limit": 3.0 26 | }, 27 | { 28 | "name": "IbmCloudIamDetector" 29 | }, 30 | { 31 | "name": "IbmCosHmacDetector" 32 | }, 33 | { 34 | "name": "JwtTokenDetector" 35 | }, 36 | { 37 | "name": "KeywordDetector", 38 | "keyword_exclude": "" 39 | }, 40 | { 41 | "name": "MailchimpDetector" 42 | }, 43 | { 44 | "name": "NpmDetector" 45 | }, 46 | { 47 | "name": "PrivateKeyDetector" 48 | }, 49 | { 50 | "name": "SlackDetector" 51 | }, 52 | { 53 | "name": "SoftlayerDetector" 54 | }, 55 | { 56 | "name": "SquareOAuthDetector" 57 | }, 58 | { 59 | "name": "StripeDetector" 60 | }, 61 | { 62 | "name": "TwilioKeyDetector" 63 | } 64 | ], 65 | "filters_used": [ 66 | { 67 | "path": "detect_secrets.filters.allowlist.is_line_allowlisted" 68 | }, 69 | { 70 | "path": "detect_secrets.filters.common.is_baseline_file", 71 | "filename": ".secrets.baseline" 72 | }, 73 | { 74 | "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", 75 | "min_level": 2 76 | }, 77 | { 78 | "path": "detect_secrets.filters.heuristic.is_indirect_reference" 79 | }, 80 | { 81 | "path": "detect_secrets.filters.heuristic.is_likely_id_string" 82 | }, 83 | { 84 | "path": "detect_secrets.filters.heuristic.is_lock_file" 85 | }, 86 | { 87 | "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" 88 | }, 89 | { 90 | "path": "detect_secrets.filters.heuristic.is_potential_uuid" 91 | }, 92 | { 93 | "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" 94 | }, 95 | { 96 | "path": "detect_secrets.filters.heuristic.is_sequential_string" 97 | }, 98 | { 99 | "path": "detect_secrets.filters.heuristic.is_swagger_file" 100 | }, 101 | { 102 | "path": "detect_secrets.filters.heuristic.is_templated_secret" 103 | } 104 | ], 105 | "results": { 106 | "README.md": [ 107 | { 108 | "type": "Hex High Entropy String", 109 | "filename": "README.md", 110 | "hashed_secret": "31f24a1b71dd8df08fb397147afbc8663f74adb7", 111 | "is_verified": true, 112 | "line_number": 52, 113 | "is_secret": false 114 | } 115 | ], 116 | "test/integration/default-target-user/default.yml": [ 117 | { 118 | "type": "Secret Keyword", 119 | "filename": "test/integration/default-target-user/default.yml", 120 | "hashed_secret": "4068c4dc5fc7878870812f37970d697e0ab440b9", 121 | "is_verified": true, 122 | "line_number": 10, 123 | "is_secret": false 124 | } 125 | ] 126 | }, 127 | "generated_at": "2023-05-06T15:45:37Z" 128 | } 129 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | line-length: disable 6 | braces: disable 7 | truthy: disable 8 | comments: 9 | min-spaces-from-content: 1 10 | comments-indentation: false 11 | octal-values: 12 | forbid-implicit-octal: true 13 | forbid-explicit-octal: true 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, juju4@users.noreply.github.com 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Actions Status - Master](https://github.com/juju4/ansible-macos-apps-install/workflows/AnsibleCI/badge.svg)](https://github.com/juju4/ansible-macos-apps-install/actions?query=branch%3Amaster) 2 | [![Actions Status - Devel](https://github.com/juju4/ansible-macos-apps-install/workflows/AnsibleCI/badge.svg?branch=devel)](https://github.com/juju4/ansible-macos-apps-install/actions?query=branch%3Adevel) 3 | 4 | # MacOS Applications installation ansible role 5 | 6 | Ansible role to setup a list of mac applications be it dmg or pkg format. 7 | It is idempotent and will only update application if version is higher than current one (if relevant fields are present) 8 | 9 | ## Requirements & Dependencies 10 | 11 | ### Ansible 12 | It was tested on the following versions: 13 | 1.9 to 2.11 14 | 15 | ### Operating systems 16 | 17 | Target MacOS 10.11, 10.12 18 | 19 | ### soft requirements 20 | GNUtar (gtar) is necessary instead of BSDtar (tar) if you will download non-zip compressed archives 21 | 22 | ``` 23 | brew install gnu-tar 24 | export PTH="/usr/local/opt/gnu-tar/libexec/gnubin:$PATH" 25 | ``` 26 | 27 | ## Example Playbook 28 | 29 | Just include this role in your list. 30 | For example 31 | 32 | ``` 33 | - host: all 34 | roles: 35 | - juju4.macos-apps-install 36 | ``` 37 | 38 | ## Variables 39 | 40 | See `test/integration/default/default.yml` for examples of applications installation. 41 | 42 | ``` 43 | target_user_id: "username" # the name of the user we want the apps to belong to 44 | verbose: False 45 | install_archives: ~/Downloads 46 | pip_path: /opt/local/bin/pip # Homebrew's pip: /opt/local/bin/pip 47 | 48 | macos_apps_install_list: 49 | - { u: 'https://download.mozilla.org/?product=firefox-50.1.0-SSL&os=osx&lang=fr', 50 | f: 'firefox-50.1.0-SSL-fr.dmg', 51 | v: True, 52 | s: '63c561051b1846f110ea60446a6578991a84d169e07dcfe1f4ea35aa4ca20e2a', 53 | n: 'Firefox', 54 | t: 'app', 55 | version: '50.1.0' 56 | } 57 | - { u: 'http://dl.paragon-software.com/demo/ntfsmac15_trial.dmg', 58 | f: 'ntfsmac15_trial.dmg', 59 | n: 'NTFS for Mac', 60 | m: '/Volumes/ParagonFS.ntfs', 61 | t: 'installer', 62 | exec_name: 'FSInstaller.app' 63 | } 64 | - { u: 'https://some.app.com/download/link', # REQUIRED # Archive Download URL 65 | f: 'archive_file.dmg', # REQUIRED # Archive File Name (how it will be saved with) 66 | n: 'My Fancy App', # REQUIRED # Name of the application also used for the .app file 67 | exec_name: '', # OPTIONAL # Name of the installed file if it is not an .app 68 | env: '', # OPTIONAL # Environment variables required by the installer 69 | version: '1.0.2', # OPTIONAL # Required Application Version 70 | t: 'app', # OPTIONAL # Installer type 71 | m: '/Volumes/My Fancy App', # OPTIONAL # Name of the archive mount point when different than application name or when wanting a custom name 72 | to: '/Applications', # OPTIONAL # Destination name for the application 73 | versioncmd: '', # OPTIONAL # Specific command to retrieve the currently installed application version 74 | plist_tag: '', # OPTIONAL # Plist tag that identify the application version 75 | v: True, # OPTIONAL # Toggle file integrity verification after download 76 | s: '63c5610...a20e2a', # OPTIONAL # Checksum value for file integrity verification 77 | } 78 | 79 | ``` 80 | ## Notes on Variables 81 | ### Installer Types: `t:` 82 | > default: app 83 | 84 | * `app`: .app file contained in a DMG archive 85 | * `installer`: .app/exec interactive installer contained in a DMG file 86 | * requires the use of `exec_name:` to define the name of the installer file 87 | * `pkg`: .pkg installer contained in a DMG file 88 | * `pkgonly`: .pkg installer NOT contained in a DMG or compressed archive 89 | * `zip`|`compressed_archive`: application contained in any kind of compressed archive 90 | 91 | ### Exec Name: `exex_name` 92 | This is the name of the script or binary contained in the archive in case it is not a ".app": 93 | * a script (i.e. `script.sh`) 94 | * a no-extension binary (i.e. `my_executable`) 95 | * an installer packages (i.e. `installer.pkg`). 96 | 97 | ### Version: `version:` 98 | If you do not specify a version number the application will always install and overwrite any existing version. 99 | 100 | When a specify a version number is specified: 101 | * the application will be installed if the currently installed version is older 102 | * the application will NOT be installed if the currently installed version is newer 103 | 104 | ### Version Command: `versioncmd:` 105 | > default: /usr/libexec/PlistBuddy -c 'print :' '/path/to/App/Contents/Info.plist' 106 | 107 | This is a command specific to the application to retrieve the currently installed version in case the default command will not be adequate. 108 | 109 | ### Plist Tag: `plist_tag:` 110 | > default: CFBundleShortVersionString 111 | 112 | This is the tag that identify the application version inside the its `.plist` file 113 | 114 | ### Environments: `env` 115 | Allows to pass environment variables (i.e. API_key ) required for the installer customisations. 116 | 117 | ``` 118 | Example: 119 | 120 | env: "env API_KEY={{ prey_apikey | default('') }}" 121 | ``` 122 | 123 | See: http://help.preyproject.com/article/188-prey-unattended-install-for-computers 124 | 125 | 126 | 127 | ## Continuous integration 128 | 129 | This role has a GitHub Action pipeline. 130 | 131 | ## Troubleshooting & Known issues 132 | 133 | ## Alternatives 134 | 135 | * [geerlingguy.mac.homebrew](https://github.com/geerlingguy/ansible-collection-mac/blob/master/roles/homebrew/README.md) 136 | * [geerlingguy.mac.mas](https://github.com/geerlingguy/ansible-collection-mac/blob/master/roles/mas/README.md) 137 | * Enterprise Mobile Device Management (Jamf, Intune...) 138 | 139 | ## License 140 | 141 | BSD 2-clause 142 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | verbose: False 4 | target_user_id: "{{ ansible_user_id }}" 5 | install_archives: /private/var/_install 6 | remove_archives_after_install: False 7 | pip_path: /opt/local/bin/pip ## macports 8 | # pip_path: /usr/local/bin/pip ## homebrew 9 | 10 | macos_apps_install_list: 11 | - { u: 'https://download.mozilla.org/?product=firefox-50.1.0-SSL&os=osx&lang=fr', 12 | f: 'firefox-50.1.0-SSL-fr.dmg', 13 | v: True, 14 | s: 'sha256:63c561051b1846f110ea60446a6578991a84d169e07dcfe1f4ea35aa4ca20e2a', 15 | n: 'Firefox', 16 | t: 'app', 17 | version: '50.1.0' 18 | } 19 | - { u: "https://download.documentfoundation.org/libreoffice/stable/5.2.3/mac/x86_64/LibreOffice_5.2.3_MacOS_x86-64.dmg", 20 | v: True, 21 | s: 'sha256:7f842a38e00312b6283341af3323433558bc155495cf54206dc88a5dd3abe277', 22 | n: 'LibreOffice', 23 | t: 'app', 24 | version: '5.2.3' 25 | } 26 | - { u: 'http://download.virtualbox.org/virtualbox/5.1.10/VirtualBox-5.1.10-112026-OSX.dmg', 27 | v: False, 28 | s: 'sha256:3500f07be9f5e27a08c00cc626981230bdaf639f6fad0b82ecf731a0580cccef', 29 | n: 'VirtualBox', 30 | t: 'pkg', 31 | version: '5.1.10' 32 | } 33 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: macos_apps_install 4 | author: juju4 5 | description: setup a list of mac applications be it dmg or pkg format, upgrade if necessary 6 | license: BSD 7 | min_ansible_version: '2.0' 8 | platforms: 9 | - name: MacOSX 10 | versions: 11 | - '10.9' 12 | - '10.10' 13 | - '10.11' 14 | - '10.12' 15 | - '10.13' 16 | - '10.14' 17 | - '10.15' 18 | galaxy_tags: 19 | - system 20 | dependencies: [] 21 | -------------------------------------------------------------------------------- /tasks/archive-install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ## inspired from https://github.com/MWGriffin/ansible-playbooks/blob/master/install/dmg.yaml 3 | ## MIT License, Copyright (c) 2013 Michael Griffin, http://mwgriffin.com 4 | 5 | - name: Debug | archive path 6 | ansible.builtin.debug: 7 | msg: "Archive Path {{ pkg_path }}" 8 | when: verbose | bool 9 | 10 | - name: Debug | archive extension 11 | ansible.builtin.debug: 12 | msg: "Archive extension '{{ archive_extension }}'" 13 | 14 | - name: Check if dmg file app_archive is mounted as mount_path 15 | ansible.builtin.stat: 16 | path: "{{ mount_path }}" 17 | register: mounted 18 | when: archive_extension == '.dmg' 19 | 20 | # 'yes qy| hdiutil attach' ...is used to accept EULA in DMGs that require license acceptance 21 | - name: Mount dmg image app_archive 22 | # ansible.builtin.shell: "yes qy | hdiutil attach '{{ pkg_path | expanduser }}'" 23 | ansible.builtin.shell: "yes qy | hdiutil attach '{{ pkg_path }}' -mountpoint '{{ mount_path }}'" # noqa risky-shell-pipe 24 | when: archive_extension == '.dmg' and mounted is defined and not mounted.stat.exists 25 | changed_when: False 26 | 27 | # we want the super-user to remove the existing app in case it was installed by another user 28 | - name: Remove existing app if present 29 | ansible.builtin.file: 30 | path: "{{ dest }}/{{ app_basename }}" 31 | state: absent 32 | when: > 33 | (installer_type == 'app' or installer_type == 'zip' or installer_type == 'compressed_archive') 34 | and (dest != '/Applications' or app_basename | string) 35 | become: True 36 | 37 | - name: Installer type 38 | when: installer_type == 'installer' 39 | block: 40 | # Actions for `installer` type 41 | - name: Fatal - exec_name/installer path not provided 42 | ansible.builtin.fail: 43 | msg: "'exec_name' (installer name), must be set to the installer path" 44 | when: not installer_name | string 45 | 46 | - name: Define Installer path 47 | ansible.builtin.set_fact: 48 | pkg_path: "{{ mount_path }}/{{ installer_name }}" 49 | when: installer_name | string 50 | 51 | - name: Pkg type 52 | when: installer_type == 'pkg' 53 | block: 54 | # Actions for `pkg` installers contained in DMG archives 55 | - name: Define package path inside the mountpoint 56 | ansible.builtin.set_fact: 57 | pkg_path: "{{ mount_path }}/{{ app_name }}.pkg" 58 | when: not installer_name | string 59 | 60 | - name: Define exec path 61 | ansible.builtin.set_fact: 62 | pkg_path: "{{ mount_path }}/{{ installer_name }}" 63 | when: installer_name | string 64 | 65 | - name: App/zip/compressed_archive type 66 | when: installer_type == 'app' or installer_type == 'zip' or installer_type == 'compressed_archive' 67 | block: 68 | - name: INFO 69 | ansible.builtin.debug: 70 | msg: "This app will be installed as the user `{{ target_user_id }}`" 71 | 72 | - name: Copy app_name app to dest 73 | ansible.builtin.copy: 74 | src: "{{ mount_path }}/{{ app_basename }}" 75 | dest: "{{ dest }}/" 76 | mode: preserve 77 | owner: "{{ target_user_id }}" 78 | remote_src: True 79 | when: 80 | - archive_extension == '.dmg' 81 | - installer_type == 'app' 82 | become: True 83 | # become_user: "{{ target_user_id }}" 84 | 85 | # if the archive is a compressed file the app will be extracted directly to it's destination 86 | - name: Extract app_name to dest 87 | ansible.builtin.unarchive: 88 | src: "{{ pkg_path }}" 89 | dest: "{{ dest }}" 90 | owner: "{{ target_user_id }}" 91 | mode: preserve 92 | when: 93 | - archive_extension != '.dmg' 94 | - (installer_type == 'zip' or installer_type == 'compressed_archive') 95 | failed_when: false 96 | become: True 97 | 98 | - name: Pkg/pkgonly type 99 | when: installer_type == 'pkg' or installer_type == 'pkgonly' 100 | become: True 101 | block: 102 | # This block is run as super-user because pkg installation frequently contain 103 | # system components that require the higher privileges to be installed in system paths 104 | - name: INFO 105 | ansible.builtin.debug: 106 | msg: "This app will be installed with super-user privileges" 107 | ## Note: env allow to pass variables like API_key for 108 | ## http://help.preyproject.com/article/188-prey-unattended-install-for-computers 109 | - name: Run install of app_name.pkg # noqa no-changed-when 110 | ansible.builtin.command: "{{ env }} installer -package '{{ pkg_path | expanduser }}' -target /" 111 | failed_when: false 112 | 113 | # this task cannot be escalated to super-user or target-user because it will trigger a GUI interactive installation process 114 | # so it is valid only if the role is used to install apps on behalf of the same user that is running the deployment 115 | - name: Installer type 116 | when: installer_type == 'installer' 117 | block: 118 | - name: INFO 119 | ansible.builtin.debug: 120 | msg: "This app will be installed as the user `{{ ansible_user_id }}`" 121 | 122 | - name: Run interactive install of app_name # noqa no-changed-when 123 | ansible.builtin.command: "{{ env }} open '{{ pkg_path | expanduser }}'" 124 | failed_when: false 125 | 126 | # this task is run asynchronously and retried various times 127 | # because somethims some volumes are still locked by some processes 128 | # for a little while after an installation 129 | - name: Unmount dmg image 130 | ansible.builtin.command: "hdiutil detach '{{ mount_path | expanduser }}'" 131 | when: archive_extension == '.dmg' 132 | register: unmount_result 133 | changed_when: False 134 | retries: 20 135 | delay: 10 136 | until: unmount_result is not failed 137 | async: 1000 138 | poll: 0 139 | -------------------------------------------------------------------------------- /tasks/darwin.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Debug | macos_apps_install_list 4 | ansible.builtin.debug: 5 | var: macos_apps_install_list 6 | when: verbose | bool 7 | 8 | - name: Ensure user download directory exists 9 | ansible.builtin.file: 10 | dest: "{{ install_archives | expanduser }}" 11 | state: directory 12 | mode: '0755' 13 | when: 14 | - install_archives != '/tmp' 15 | - install_archives != '/private/tmp' 16 | - install_archives != '/Users/Shared' 17 | 18 | ## https://github.com/ansible/ansible/issues/18894 19 | - name: Check if pip available 20 | ansible.builtin.stat: 21 | path: "{{ pip_path }}" 22 | register: has_pip 23 | 24 | - name: Bug workaround - https://github.com/ansible/ansible/issues/18894 25 | ansible.builtin.pip: 26 | name: 27 | - requests>=2.12 28 | - urllib3>=1.19 29 | - pyOpenSSL>=16.0 30 | - pyasn1>=0.1.9 31 | - ndg-httpsclient>=0.4.2 32 | state: present 33 | executable: "{{ pip_path }}" 34 | when: has_pip.stat.exists and ansible_distribution_version.split('.')[1] | int <= 11 35 | register: pkg_result 36 | until: pkg_result is success 37 | 38 | - name: Install macOS applications 39 | ansible.builtin.include_tasks: install-app.yml 40 | vars: 41 | app_url: "{{ item.u }}" 42 | app_archive: "{{ item.f | default(item.u | basename) }}" 43 | archive_extension: "{{ app_archive | default('') | splitext | last }}" 44 | validate_certs: "{{ item.v | default(True) }}" 45 | checksum: "{{ item.s | default('') }}" 46 | app_name: "{{ item.n }}" 47 | installer_type: "{{ item.t | default('app') }}" 48 | mount_path: "{{ item.m | default('/Volumes/' + item.n) }}" 49 | version: "{{ item.version | default('') }}" 50 | versioncmd: "{{ item.versioncmd | default('') }}" 51 | dest: "{{ item.to | default('/Applications') }}" 52 | installer_name: "{{ item.exec_name | default('') }}" 53 | env: "{{ item.env | default('') }}" 54 | plist_tag: "{{ item.plist_tag | default('CFBundleShortVersionString') }}" 55 | # pkg_path={{ install_archives | expanduser }}/{{ app_archive }} 56 | with_items: "{{ macos_apps_install_list }}" 57 | -------------------------------------------------------------------------------- /tasks/install-app.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ## inspired from https://github.com/MWGriffin/ansible-playbooks/blob/master/install/dmg.yaml 3 | ## MIT License, Copyright (c) 2013 Michael Griffin, http://mwgriffin.com 4 | 5 | ## Note: some app are not installing here 6 | 7 | - name: Define app name to 8 | ansible.builtin.set_fact: 9 | app_basename: "{{ app_name }}.app" 10 | when: app_name is defined and app_name | string 11 | 12 | - name: Define Package Path 13 | ansible.builtin.set_fact: 14 | pkg_path: "{{ install_archives | expanduser }}/{{ app_archive }}" 15 | 16 | - name: Define installer name 17 | ansible.builtin.set_fact: 18 | app_basename: "{{ installer_name }}" 19 | when: installer_name is defined and installer_name | string 20 | 21 | - name: Get properties of destination 22 | ansible.builtin.stat: 23 | path: "{{ dest }}" 24 | register: dest_properties 25 | - name: Check if app_name exists in dest 26 | ansible.builtin.stat: 27 | path: "{{ dest }}/{{ app_name }}.app" 28 | register: app 29 | when: version | string and (dest_properties.stat.isdir is defined and dest_properties.stat.isdir) 30 | - name: Check if dest exists - custom to' 31 | ansible.builtin.stat: 32 | path: "{{ dest }}" 33 | register: app2 34 | when: version | string and dest != '/Applications' 35 | - name: Debug | app2 36 | ansible.builtin.debug: 37 | var: app2 38 | verbosity: 1 39 | 40 | - name: Debug | archives path 41 | ansible.builtin.debug: 42 | msg: "Archives Path: {{ install_archives }}'" 43 | when: verbose | bool 44 | - name: Debug | package name 45 | ansible.builtin.debug: 46 | msg: "Package Name: {{ app_archive }}'" 47 | when: verbose | bool 48 | - name: Debug | package path 49 | ansible.builtin.debug: 50 | msg: "Package Path: {{ pkg_path }}'" 51 | when: verbose | bool 52 | 53 | - name: INFO 54 | ansible.builtin.debug: 55 | msg: "The desired version for '{{ app_name }}' is '{{ version }}'" 56 | when: version | string 57 | 58 | - name: INFO 59 | ansible.builtin.debug: 60 | msg: "The desired version for '{{ app_name }}' was not specified. Will overwrite any existing version" 61 | when: not version | string 62 | 63 | - name: INFO 64 | ansible.builtin.debug: 65 | msg: "'{{ app_basename }}' does not exist in '{{ dest }}'. '{{ app_name }}' will be installed" 66 | when: > 67 | version | string and 68 | app.stat.exists is defined and not app.stat.exists and 69 | ( 70 | app2.stat.exists is not defined or (app2.stat.exists is defined and not app2.stat.exists) 71 | ) 72 | 73 | - name: Import macos-apps-version 74 | ansible.builtin.include_tasks: macos-apps-version.yml 75 | vars: 76 | version_app_path: "{{ dest }}/{{ app_basename }}" 77 | version_app_cmd: "{{ versioncmd }}" 78 | version_app_default: "0.01" 79 | version_app_plist_tag: "{{ plist_tag }}" 80 | when: > 81 | version|string and 82 | ((app.stat.exists is defined and app.stat.exists) or (app.skipped is defined and app.skipped)) and 83 | ( 84 | app2.stat.exists is not defined or (app2.stat.exists is defined and not app2.stat.exists) 85 | ) 86 | 87 | - name: Debug | verbose 88 | when: 89 | - verbose | bool 90 | - version | string and ( 91 | app is defined and app.stat is defined and app.stat.exists 92 | ) 93 | block: 94 | - name: Required version 95 | ansible.builtin.debug: 96 | var: version 97 | 98 | - name: Current version 99 | ansible.builtin.debug: 100 | var: currentversion|default('') 101 | 102 | - name: Versions comparison 103 | ansible.builtin.debug: 104 | var: "{{ version is version(currentversion, '>') }}" 105 | 106 | - name: Already up-to-date! 107 | ansible.builtin.debug: 108 | msg: "Application {{ app_name }} already up-to-date (Current {{ currentversion }} >= Desired {{ version }})" 109 | when: > 110 | app.stat.exists is defined and app.stat.exists and 111 | version|string and version is version( currentversion, '<=') 112 | 113 | - name: Download macOS App archive {{ app_archive }} 114 | ansible.builtin.get_url: 115 | url: "{{ app_url }}" 116 | dest: "{{ pkg_path }}" 117 | mode: '0644' 118 | validate_certs: "{{ validate_certs }}" 119 | checksum: "{{ checksum | default(omit) }}" 120 | tmp_dest: /tmp/ 121 | vars: 122 | ansible_python_interpreter: python3 123 | register: dl_result 124 | until: dl_result is success 125 | when: > 126 | ( 127 | app.stat.exists is defined and not app.stat.exists and 128 | ( 129 | app2.stat.exists is not defined or (app2.stat.exists is defined and not app2.stat.exists) 130 | ) 131 | ) 132 | or not (version | string) 133 | or (currentversion is defined and version is version( currentversion, '>')) 134 | 135 | - name: Import archive-install 136 | ansible.builtin.import_tasks: archive-install.yml 137 | when: > 138 | ( 139 | app.stat.exists is defined and not app.stat.exists and 140 | ( 141 | app2.stat.exists is not defined or (app2.stat.exists is defined and not app2.stat.exists) 142 | ) 143 | ) 144 | or not version|string 145 | or (currentversion is defined and version is version( currentversion, '>')) 146 | -------------------------------------------------------------------------------- /tasks/macos-apps-version.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Debug | verbose 4 | when: verbose is defined and verbose 5 | block: 6 | - name: Debug | version_app_cmd 7 | ansible.builtin.debug: 8 | var: version_app_cmd 9 | - name: Debug | version_app_default 10 | ansible.builtin.debug: 11 | var: version_app_default 12 | - name: Debug | version_app_plist_tag 13 | ansible.builtin.debug: 14 | var: version_app_plist_tag 15 | 16 | - name: INFO 17 | ansible.builtin.debug: 18 | msg: "Using custom command to retrieve App version for '{{ version_app_path }}' from Info.plist" 19 | when: version_app_cmd is defined and version_app_cmd | string 20 | 21 | - name: Version_app_cmd 22 | when: version_app_cmd is not defined or not version_app_cmd | string 23 | block: 24 | - name: Check if Contents/Info.plist exists 25 | ansible.builtin.stat: 26 | path: "{{ version_app_path }}/Contents/Info.plist" 27 | register: infoplist 28 | 29 | - name: Define command to retrieve App version from Info.plist for {{ version_app_path }} 30 | ansible.builtin.set_fact: 31 | version_app_cmd: "/usr/libexec/PlistBuddy -c 'print :{{ version_app_plist_tag }}' '{{ version_app_path }}/Contents/Info.plist'" 32 | when: infoplist.stat.exists 33 | 34 | - name: Force update/install if no App command version 35 | ansible.builtin.set_fact: 36 | version_app_cmd: "echo {{ version_app_default }}" 37 | when: not infoplist.stat.exists 38 | 39 | - name: Get current App version of {{ version_app_path }} 40 | ansible.builtin.command: "{{ version_app_cmd }}" 41 | register: version_app_shell 42 | changed_when: False 43 | ignore_errors: True 44 | when: app.stat.exists and version_app_cmd | string 45 | 46 | - name: The current App version is {{ version_app_shell.stdout }} 47 | ansible.builtin.set_fact: 48 | currentversion: "{{ version_app_shell.stdout }}" 49 | when: version_app_shell.stdout is defined and version_app_shell.stdout 50 | 51 | - name: The current App version is {{ version_app_default }} 52 | ansible.builtin.set_fact: 53 | currentversion: "{{ version_app_default }}" 54 | when: not (version_app_shell.stdout is defined and version_app_shell.stdout) 55 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: FATAL 4 | ansible.builtin.fail: 5 | msg: "This role is only compatible with Darwin/MacOS" 6 | when: ansible_os_family != 'Darwin' 7 | 8 | - name: Import travis 9 | ansible.builtin.import_tasks: travis.yml 10 | 11 | - name: Import darwin 12 | ansible.builtin.import_tasks: darwin.yml 13 | -------------------------------------------------------------------------------- /tasks/travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ## Travis configuration 3 | 4 | - name: Set fact pip_path for travis 5 | ansible.builtin.set_fact: 6 | pip_path: /usr/local/bin/pip 7 | ## this is not passed into ansible on osx 8 | # when: ansible_env['TRAVIS'] is defined and ansible_env['TRAVIS'] == 'True' 9 | when: ansible_env['SUDO_USER'] is defined and ansible_env['SUDO_USER'] == 'travis' 10 | -------------------------------------------------------------------------------- /test/integration/default-target-user/bats/idempotency.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | # 3 | 4 | # 5 | # Idempotence test 6 | # from https://github.com/neillturner/kitchen-ansible/issues/92 7 | # 8 | 9 | @test "Second run should change nothing" { 10 | # skip 11 | run bash -c "ansible-playbook -i /tmp/kitchen/hosts /tmp/kitchen/default.yml -c local 2>&1 | tee /tmp/idempotency.test | grep -q 'changed=0.*failed=0' && exit 0 || exit 1" 12 | [ "$status" -eq 0 ] 13 | } 14 | -------------------------------------------------------------------------------- /test/integration/default-target-user/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Test integration playbook 4 | hosts: all 5 | vars: 6 | verbose: True 7 | new_user_username: 'targetuser' 8 | new_user_fullname: 'Target User' 9 | new_user_shell: '/bin/zsh' 10 | new_user_password_cleartext: 'target-user-password' 11 | target_user_id: "{{ new_user_username }}" 12 | macos_apps_install_list: 13 | # https://www.mozilla.org/en-US/firefox/all/ 14 | - { u: 'https://download.mozilla.org/?product=firefox-80.0-SSL&os=osx&lang=en-US', 15 | f: 'firefox-80.0-SSL-en-US.dmg', 16 | v: True, 17 | s: 'sha256:c5234f44f7b4102debdbd0a5af56e9414d0f6d99a38eb1cbd99b43f186b28a85', 18 | n: 'Firefox', 19 | t: 'app', 20 | version: '80.0' 21 | } 22 | # https://www.thunderbird.net/en-US/thunderbird/all/ 23 | - { u: 'https://download.mozilla.org/?product=thunderbird-78.2.1-SSL&os=osx&lang=en-US', 24 | f: 'thunderbird-78.2.1-SSL-fr.dmg', 25 | v: True, 26 | s: 'sha256:6b54919e06f5e60f9e7a559f6cbea49bc4a73d263bbcd156a13a7b6ff4ba626f', 27 | n: 'Thunderbird', 28 | t: 'app', 29 | version: '78.2.1' 30 | } 31 | # https://www.google.com/chrome/, https://chromereleases.googleblog.com/ 32 | # - { u: 'https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg', 33 | # v: True, s: 'sha256:xxx', 34 | # n: 'Google Chrome', 35 | # t: 'app', 36 | # version: '86.0' 37 | # } 38 | # https://www.libreoffice.org/download/download/ 39 | # - { u: "https://www.libreoffice.org/donate/dl/mac-x86_64/7.0.0/en-US/LibreOffice_7.0.0_MacOS_x86-64.dmg", 40 | # v: True, 41 | # s: 'sha256:xxx', 42 | # n: 'LibreOffice', 43 | # t: 'app', 44 | # version: '7.0.0' 45 | # } 46 | # https://www.videolan.org/vlc/download-macosx.html 47 | # - { u: 'http://get.videolan.org/vlc/3.0.11.1/macosx/vlc-3.0.11.1.dmg', 48 | # v: False, 49 | # s: 'sha256:xxx', 50 | # n: 'VLC', 51 | # t: 'app', 52 | # m: '/Volumes/vlc-3.0.11.1', 53 | # version: '3.0.11.1' 54 | # } 55 | # - { u: 'https://dl.dropbox.com/u/1140644/clipmenu/ClipMenu_0.4.3.dmg', 56 | # v: True, s: 'sha256:d0d7ca6c23f51b2dfe78c7bb40bf2f212c21b3304b3eacde86112d8ef3e6bfb9', 57 | # n: 'ClipMenu', 58 | # t: 'app', 59 | # version: '0.4.3' 60 | # } 61 | # https://www.virtualbox.org/wiki/Downloads 62 | # - { u: 'https://download.virtualbox.org/virtualbox/6.1.12/VirtualBox-6.1.12-139181-OSX.dmg', 63 | # v: False, 64 | # s: 'sha256:xxx', 65 | # n: 'VirtualBox', 66 | # t: 'pkg', 67 | # version: '6.1.12' 68 | # } 69 | # https://www.vagrantup.com/downloads.html 70 | ## FIXME! requires recent apple/openssl to support tls1.2 only server 71 | ## https://github.com/jhaals/ansible-vault/issues/15 72 | # - { u: 'https://releases.hashicorp.com/vagrant/2.2.10/vagrant_2.2.10_x86_64.dmg', 73 | # v: False, 74 | # s: 'sha256:xxx', 75 | # n: 'Vagrant', 76 | # t: 'pkg', 77 | # version: '2.2.10', 78 | # versioncmd: '/opt/vagrant/bin/vagrant --version | sed "s@Vagrant @@;"', 79 | # to: '/opt/vagrant/bin/vagrant' 80 | # } 81 | # https://www.parallels.com/products/desktop/download/ 82 | # - { u: 'https://download.parallels.com/desktop/v16/16.0.0-48916/ParallelsDesktop-16.0.0-48916.dmg', 83 | # f: 'ParallelsDesktop-16.0.0-48916.dmg', 84 | # v: True, 85 | # s: 'sha256:xxx', 86 | # n: 'Parallels Desktop', 87 | # t: 'app', 88 | # m: '/Volumes/Parallels Desktop 16', 89 | # version: '16.0.0', 90 | # versioncmd: '', 91 | # to: '/Applications/Parallels Desktop.app' 92 | # } 93 | # - { u: 'https://dl.bintray.com/xquartz/downloads/XQuartz-2.7.11.dmg', 94 | # v: True, 95 | # s: 'sha256:32e50e8f1e21542b847041711039fa78d44febfed466f834a9281c44d75cd6c3', 96 | # n: 'XQuartz', 97 | # t: 'pkg', 98 | # m: '/Volumes/XQuartz-2.7.11', 99 | # version: '2.7.11', 100 | # to: '/Applications/Utilities/XQuartz.app' 101 | # } 102 | # https://www.wireshark.org/download.html 103 | # - { u: 'https://1.na.dl.wireshark.org/osx/Wireshark%203.2.6%20Intel%2064.dmg', 104 | # f: 'Wireshark-3.2.6-Intel-64.dmg', 105 | # v: True, 106 | # s: 'sha256:xxx', 107 | # n: 'Wireshark', 108 | # t: 'pkg', 109 | # version: '3.2.6', 110 | # exec_name: 'Wireshark 3.2.6 Intel 64.pkg' 111 | # } 112 | # - { u: 'https://download.docker.com/mac/stable/Docker.dmg', 113 | # v: True, 114 | # s: 'sha256:xxx', 115 | # n: 'Docker', 116 | # t: 'app', 117 | # m: '/Volumes/Docker', 118 | # version: '17.09.1', 119 | # versioncmd: '/usr/libexec/PlistBuddy -c "print :CFBundleShortVersionString" /Applications/Docker.app/Contents/Info.plist', 120 | # to: '/Applications/Docker.app' 121 | # } 122 | # https://preyproject.com/download/ 123 | ## http://help.preyproject.com/article/188-prey-unattended-install-for-computers 124 | - { u: 'https://downloads.preyproject.com/prey-client-releases/node-client/1.9.5/prey-mac-1.9.5-x64.pkg', 125 | v: False, 126 | s: 'sha256:84e00adf58f85d634f921f5bb9224d22f68789b1e0bff64d3fd2d154c85ce06c', 127 | n: 'Prey', 128 | t: 'pkgonly', 129 | version: '1.9.5', 130 | env: "env API_KEY={{ prey_apikey | default('') }}", 131 | to: '/usr/local/lib/prey/current/bin/prey', 132 | versioncmd: '/usr/local/lib/prey/current/bin/prey --version' 133 | } 134 | # https://github.com/osxfuse/osxfuse/releases/ 135 | ## osxfuse is required for veracrypt 136 | - { u: 'https://github.com/osxfuse/osxfuse/releases/download/macfuse-4.2.1/macfuse-4.2.1.dmg', 137 | v: True, 138 | s: 'sha256:bd3abba91a8c16005eb3937ad492e49275e60db429bbecd30d54769c191e0699 ', 139 | n: 'FUSE', 140 | t: 'pkg', 141 | m: '/Volumes/FUSE for macOS', 142 | version: '4.2.1', 143 | to: '/Library/Filesystems/osxfuse.fs', 144 | exec_name: 'FUSE for macOS.pkg', 145 | versioncmd: '/usr/libexec/PlistBuddy -c "print :CFBundleVersion" "/Library/Filesystems/osxfuse.fs/Contents/Info.plist"' 146 | } 147 | - { u: 'https://launchpad.net/veracrypt/trunk/1.24-update8/+download/VeraCrypt_1.24-Update8.dmg', 148 | v: true, 149 | s: 'sha256:9edeae9fbf7f1b2eb91ce55ff82481bfd4c099e85c3c88cb6d6dd91b460a3a6b', 150 | n: 'VeraCrypt', 151 | t: 'pkg', 152 | m: '/Volumes/VeraCrypt for OSX', 153 | version: '1.24', 154 | exec_name: 'VeraCrypt_Installer.pkg' 155 | } 156 | - { u: 'https://github.com/google/santa/releases/download/2021.7/santa-2021.7.dmg', 157 | v: false, 158 | s: 'sha256:7682a855aa2517011fe08eb5c1f420c1dbe2ab6ea3a732bbf915267fda203754', 159 | n: 'santa-2021.7', 160 | t: 'pkg', 161 | version: '2021.7', 162 | versioncmd: '/usr/local/bin/santactl version | sed "1 s/.*| //;q"', 163 | to: '/usr/local/bin/santactl' 164 | } 165 | - { u: 'https://pkg.osquery.io/darwin/osquery-5.0.1.pkg', 166 | v: true, 167 | s: 'sha256:ec58996e64637d861ccead8dc6bc8865662728f6e5bc2694a3c92f0f4a371095', 168 | n: 'osquery', 169 | t: 'pkgonly', 170 | version: '5.0.1', 171 | versioncmd: '/usr/local/bin/osqueryi --version | sed "s/osqueryi version //"', 172 | to: '/usr/local/bin/osqueryi' 173 | } 174 | # https://gpgtools.org/ 175 | # - { u: 'https://releases.gpgtools.org/GPG_Suite-2020.1.dmg', 176 | # v: False, 177 | # s: 'sha256:xxx' 178 | # } 179 | # https://downloads.chef.io/products/inspec 180 | - { u: 'https://packages.chef.io/files/stable/inspec/4.46.13/mac_os_x/11/inspec-4.46.13-1.x86_64.dmg', 181 | v: true, 182 | s: 'sha256:cf117764cd1e67ef4d161d6ad8bd0e713d25d2e6afaaea0d734e6707eccd2e58', 183 | n: 'inspec', 184 | t: 'pkg', 185 | m: '/Volumes/InSpec', 186 | version: '4.46.13', 187 | exec_name: 'inspec-4.46.13-1.pkg', 188 | versioncmd: 'inspec --version 2>&1 | tail -1' 189 | } 190 | # - { u: '', 191 | # f: '', 192 | # v: True, 193 | # s: 'sha256:aaaa', 194 | # n: '', 195 | # t: 'app', 196 | # m: '/Volumes/app', 197 | # version: '', 198 | # versioncmd: '', 199 | # to: '/Applications/example.app' 200 | # } 201 | pre_tasks: 202 | - name: Macos 11 | set fact 203 | ansible.builtin.set_fact: 204 | macos_apps_install_list: 205 | - "{{ macos_apps_install_list }}" 206 | - { u: 'https://github.com/macports/macports-base/releases/download/v2.7.1/MacPorts-2.7.1-11-BigSur.pkg', 207 | v: false, 208 | s: 'sha256:72189c01f8a21f33869636061dc95b51b20428fa3937518e375fb6e8dd7e4fe3', 209 | n: 'MacPorts', 210 | t: 'pkgonly', 211 | version: '2.7.1', 212 | to: '/opt/local/bin/ports' 213 | } 214 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[0] == '11' 215 | - name: Macos 10.15 | set fact 216 | ansible.builtin.set_fact: 217 | macos_apps_install_list: 218 | - "{{ macos_apps_install_list }}" 219 | - { u: 'https://github.com/macports/macports-base/releases/download/v2.7.1/MacPorts-2.7.1-10.15-Catalina.pkg', 220 | v: false, 221 | s: 'sha256:cd312d9755ec822630e4c26c6bb863f87fdac2e4d71d5d5f24cea2b20a7bc0f1', 222 | n: 'MacPorts', 223 | t: 'pkgonly', 224 | version: '2.7.1', 225 | to: '/opt/local/bin/ports' 226 | } 227 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '15' 228 | - name: Macos 10.14 | set fact 229 | ansible.builtin.set_fact: 230 | macos_apps_install_list: 231 | - "{{ macos_apps_install_list }}" 232 | - { u: 'https://github.com/macports/macports-base/releases/download/v2.7.1/MacPorts-2.7.1-10.14-Mojave.pkg', 233 | v: false, 234 | s: 'sha256:29e2ff54749819dbdb8a6fd2f6f5ba56f467dc554f4fc2c145fd64b607d84272', 235 | n: 'MacPorts', 236 | t: 'pkgonly', 237 | version: '2.7.1', 238 | to: '/opt/local/bin/ports' 239 | } 240 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '14' 241 | - name: Macos 10.13 | set fact 242 | ansible.builtin.set_fact: 243 | macos_apps_install_list: 244 | - "{{ macos_apps_install_list }}" 245 | - { u: 'https://distfiles.macports.org/MacPorts/MacPorts-2.6.3-10.13-HighSierra.pkg', 246 | v: false, 247 | s: 'sha256:218a64116b429140bab5cd795379d814a40f42bc0d45c7e96a1ea4b35be58776', 248 | n: 'MacPorts', 249 | t: 'pkgonly', 250 | version: '2.6.3', 251 | to: '/opt/local/bin/ports' 252 | } 253 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '13' 254 | - name: Macos 10.12 | set fact 255 | ansible.builtin.set_fact: 256 | macos_apps_install_list: 257 | - "{{ macos_apps_install_list }}" 258 | - { u: 'https://distfiles.macports.org/MacPorts/MacPorts-2.6.3-10.12-Sierra.pkg', 259 | v: true, 260 | s: 'sha256:6414963aef281c6a50145afcbc2eab4bc6eda3678df059c772e048524d4491a0', 261 | n: 'MacPorts', 262 | t: 'pkgonly', 263 | version: '2.6.3', 264 | to: '/opt/local/bin/ports' 265 | } 266 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '12' 267 | - name: Macos 10.11 | set fact 268 | ansible.builtin.set_fact: 269 | macos_apps_install_list: 270 | - "{{ macos_apps_install_list }}" 271 | - { u: 'https://distfiles.macports.org/MacPorts/MacPorts-2.6.3-10.11-ElCapitan.pkg', 272 | v: true, 273 | s: 'sha256:174e3203362f4ddf2cd1ad55c1d050768dd38d8efff1e2e215163cd71cdfec93', 274 | n: 'MacPorts', 275 | t: 'pkgonly', 276 | version: '2.6.3', 277 | versioncmd: '', 278 | to: '/opt/local/bin/ports' 279 | } 280 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '11' 281 | - name: Creating user "{{ new_user_username }}". 282 | ansible.builtin.user: 283 | name: "{{ new_user_username }}" 284 | comment: "{{ new_user_fullname }}" 285 | password: "{{ new_user_password_cleartext }}" 286 | shell: '/bin/zsh' 287 | home: "/Users/{{ new_user_username }}" 288 | create_home: True 289 | group: 'staff' 290 | groups: 'admin' 291 | append: True 292 | register: new_user_created 293 | become: yes 294 | 295 | roles: 296 | - juju4.macos_apps_install 297 | -------------------------------------------------------------------------------- /test/integration/default-target-user/serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'serverspec' 4 | gem 'rake' 5 | ## for junit output and jenkins support 6 | ## FIXME! travis: 'Could not find gem 'yarjuf' in any of the gem sources listed in your Gemfile or available on this machine.' 7 | #gem 'yarjuf' 8 | -------------------------------------------------------------------------------- /test/integration/default-target-user/serverspec/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rspec/core/rake_task' 3 | 4 | RSpec::Core::RakeTask.new(:spec) do |t| 5 | t.pattern = '*_spec.rb' 6 | end 7 | 8 | task :default => :spec 9 | -------------------------------------------------------------------------------- /test/integration/default-target-user/serverspec/run-local-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | ## get consistent ruby2+bundler env on each distribution 3 | 4 | location=`dirname "$0"` 5 | cd $location 6 | v=2.3 7 | 8 | ## docker environment in travis missing few utils 9 | [ -f /etc/debian_version ] && apt-get install -y curl 10 | [ -f /etc/redhat-release ] && yum -y install which 11 | 12 | curl -sSL https://get.rvm.io | bash 13 | #[ -f $HOME/.rvm/scripts/rvm ] && . $HOME/.rvm/scripts/rvm 14 | #[ -d /usr/local/rvm ] && . /etc/profile.d/rvm.sh 15 | 16 | ## troubleshoot 17 | type rvm | head -1 18 | env 19 | 20 | #export PATH=/usr/local/rvm/bin:$PATH 21 | 22 | bash -l -c "rvm install $v" 23 | bash -l -c "rvm use $v" 24 | bash -l -c "rvm use $v --default" 25 | bash -l -c "gem install bundler" 26 | bash -l -c "bundle install --path ./gems" 27 | if [ "X$USER" != "Xroot" -a "X$USER" != "X" ]; then 28 | bash -l -c "env rvmsudo_secure_path=1 rvmsudo bundle exec rake spec" 29 | else 30 | bash -l -c "bundle exec rake spec" 31 | fi 32 | -------------------------------------------------------------------------------- /test/integration/default/bats/idempotency.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | # 3 | 4 | # 5 | # Idempotence test 6 | # from https://github.com/neillturner/kitchen-ansible/issues/92 7 | # 8 | 9 | @test "Second run should change nothing" { 10 | # skip 11 | run bash -c "ansible-playbook -i /tmp/kitchen/hosts /tmp/kitchen/default.yml -c local 2>&1 | tee /tmp/idempotency.test | grep -q 'changed=0.*failed=0' && exit 0 || exit 1" 12 | [ "$status" -eq 0 ] 13 | } 14 | -------------------------------------------------------------------------------- /test/integration/default/default.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Test integration playbook 4 | hosts: all 5 | vars: 6 | verbose: True 7 | version: True 8 | macos_apps_install_list: 9 | # https://www.mozilla.org/en-US/firefox/all/ 10 | - { u: 'https://download.mozilla.org/?product=firefox-80.0-SSL&os=osx&lang=en-US', 11 | f: 'firefox-80.0-SSL-en-US.dmg', 12 | v: True, 13 | s: 'sha256:c5234f44f7b4102debdbd0a5af56e9414d0f6d99a38eb1cbd99b43f186b28a85', 14 | n: 'Firefox', 15 | t: 'app', 16 | version: '80.0' 17 | } 18 | # https://www.thunderbird.net/en-US/thunderbird/all/ 19 | - { u: 'https://download.mozilla.org/?product=thunderbird-78.2.1-SSL&os=osx&lang=en-US', 20 | f: 'thunderbird-78.2.1-SSL-fr.dmg', 21 | v: True, 22 | s: 'sha256:6b54919e06f5e60f9e7a559f6cbea49bc4a73d263bbcd156a13a7b6ff4ba626f', 23 | n: 'Thunderbird', 24 | t: 'app', 25 | version: '78.2.1' 26 | } 27 | # https://www.google.com/chrome/, https://chromereleases.googleblog.com/ 28 | # - { u: 'https://dl.google.com/chrome/mac/stable/GGRO/googlechrome.dmg', 29 | # v: True, s: 'sha256:xxx', 30 | # n: 'Google Chrome', 31 | # t: 'app', 32 | # version: '86.0' 33 | # } 34 | # https://www.libreoffice.org/download/download/ 35 | # - { u: "https://www.libreoffice.org/donate/dl/mac-x86_64/7.0.0/en-US/LibreOffice_7.0.0_MacOS_x86-64.dmg", 36 | # v: True, 37 | # s: 'sha256:xxx', 38 | # n: 'LibreOffice', 39 | # t: 'app', 40 | # version: '7.0.0' 41 | # } 42 | # https://www.videolan.org/vlc/download-macosx.html 43 | # - { u: 'http://get.videolan.org/vlc/3.0.11.1/macosx/vlc-3.0.11.1.dmg', 44 | # v: False, 45 | # s: 'sha256:xxx', 46 | # n: 'VLC', 47 | # t: 'app', 48 | # m: '/Volumes/vlc-3.0.11.1', 49 | # version: '3.0.11.1' 50 | # } 51 | # - { u: 'https://dl.dropbox.com/u/1140644/clipmenu/ClipMenu_0.4.3.dmg', 52 | # v: True, s: 'sha256:d0d7ca6c23f51b2dfe78c7bb40bf2f212c21b3304b3eacde86112d8ef3e6bfb9', 53 | # n: 'ClipMenu', 54 | # t: 'app', 55 | # version: '0.4.3' 56 | # } 57 | # https://www.virtualbox.org/wiki/Downloads 58 | # - { u: 'https://download.virtualbox.org/virtualbox/6.1.12/VirtualBox-6.1.12-139181-OSX.dmg', 59 | # v: False, 60 | # s: 'sha256:xxx', 61 | # n: 'VirtualBox', 62 | # t: 'pkg', 63 | # version: '6.1.12' 64 | # } 65 | # https://www.vagrantup.com/downloads.html 66 | ## FIXME! requires recent apple/openssl to support tls1.2 only server 67 | ## https://github.com/jhaals/ansible-vault/issues/15 68 | # - { u: 'https://releases.hashicorp.com/vagrant/2.2.10/vagrant_2.2.10_x86_64.dmg', 69 | # v: False, 70 | # s: 'sha256:xxx', 71 | # n: 'Vagrant', 72 | # t: 'pkg', 73 | # version: '2.2.10', 74 | # versioncmd: '/opt/vagrant/bin/vagrant --version | sed "s@Vagrant @@;"', 75 | # to: '/opt/vagrant/bin/vagrant' 76 | # } 77 | # https://www.parallels.com/products/desktop/download/ 78 | # - { u: 'https://download.parallels.com/desktop/v16/16.0.0-48916/ParallelsDesktop-16.0.0-48916.dmg', 79 | # f: 'ParallelsDesktop-16.0.0-48916.dmg', 80 | # v: True, 81 | # s: 'sha256:xxx', 82 | # n: 'Parallels Desktop', 83 | # t: 'app', 84 | # m: '/Volumes/Parallels Desktop 16', 85 | # version: '16.0.0', 86 | # versioncmd: '', 87 | # to: '/Applications/Parallels Desktop.app' 88 | # } 89 | # - { u: 'https://dl.bintray.com/xquartz/downloads/XQuartz-2.7.11.dmg', 90 | # v: True, 91 | # s: 'sha256:32e50e8f1e21542b847041711039fa78d44febfed466f834a9281c44d75cd6c3', 92 | # n: 'XQuartz', 93 | # t: 'pkg', 94 | # m: '/Volumes/XQuartz-2.7.11', 95 | # version: '2.7.11', 96 | # to: '/Applications/Utilities/XQuartz.app' 97 | # } 98 | # https://www.wireshark.org/download.html 99 | # - { u: 'https://1.na.dl.wireshark.org/osx/Wireshark%203.2.6%20Intel%2064.dmg', 100 | # f: 'Wireshark-3.2.6-Intel-64.dmg', 101 | # v: True, 102 | # s: 'sha256:xxx', 103 | # n: 'Wireshark', 104 | # t: 'pkg', 105 | # version: '3.2.6', 106 | # exec_name: 'Wireshark 3.2.6 Intel 64.pkg' 107 | # } 108 | # - { u: 'https://download.docker.com/mac/stable/Docker.dmg', 109 | # v: True, 110 | # s: 'sha256:xxx', 111 | # n: 'Docker', 112 | # t: 'app', 113 | # m: '/Volumes/Docker', 114 | # version: '17.09.1', 115 | # versioncmd: '/usr/libexec/PlistBuddy -c "print :CFBundleShortVersionString" /Applications/Docker.app/Contents/Info.plist', 116 | # to: '/Applications/Docker.app' 117 | # } 118 | # https://preyproject.com/download/ 119 | ## http://help.preyproject.com/article/188-prey-unattended-install-for-computers 120 | - { u: 'https://downloads.preyproject.com/prey-client-releases/node-client/1.9.5/prey-mac-1.9.5-x64.pkg', 121 | v: False, 122 | s: 'sha256:84e00adf58f85d634f921f5bb9224d22f68789b1e0bff64d3fd2d154c85ce06c', 123 | n: 'Prey', 124 | t: 'pkgonly', 125 | version: '1.9.5', 126 | env: "env API_KEY={{ prey_apikey | default('') }}", 127 | to: '/usr/local/lib/prey/current/bin/prey', 128 | versioncmd: '/usr/local/lib/prey/current/bin/prey --version' 129 | } 130 | # https://github.com/osxfuse/osxfuse/releases/ 131 | ## osxfuse is required for veracrypt 132 | - { u: 'https://github.com/osxfuse/osxfuse/releases/download/macfuse-4.2.1/macfuse-4.2.1.dmg', 133 | v: True, 134 | s: 'sha256:bd3abba91a8c16005eb3937ad492e49275e60db429bbecd30d54769c191e0699 ', 135 | n: 'FUSE', 136 | t: 'pkg', 137 | m: '/Volumes/FUSE for macOS', 138 | version: '4.2.1', 139 | to: '/Library/Filesystems/osxfuse.fs', 140 | exec_name: 'FUSE for macOS.pkg', 141 | versioncmd: '/usr/libexec/PlistBuddy -c "print :CFBundleVersion" "/Library/Filesystems/osxfuse.fs/Contents/Info.plist"' 142 | } 143 | - { u: 'https://launchpad.net/veracrypt/trunk/1.24-update8/+download/VeraCrypt_1.24-Update8.dmg', 144 | v: true, 145 | s: 'sha256:9edeae9fbf7f1b2eb91ce55ff82481bfd4c099e85c3c88cb6d6dd91b460a3a6b', 146 | n: 'VeraCrypt', 147 | t: 'pkg', 148 | m: '/Volumes/VeraCrypt for OSX', 149 | version: '1.24', 150 | exec_name: 'VeraCrypt_Installer.pkg' 151 | } 152 | - { u: 'https://github.com/google/santa/releases/download/2021.7/santa-2021.7.dmg', 153 | v: false, 154 | s: 'sha256:7682a855aa2517011fe08eb5c1f420c1dbe2ab6ea3a732bbf915267fda203754', 155 | n: 'santa-2021.7', 156 | t: 'pkg', 157 | version: '2021.7', 158 | versioncmd: '/usr/local/bin/santactl version | sed "1 s/.*| //;q"', 159 | to: '/usr/local/bin/santactl' 160 | } 161 | - { u: 'https://pkg.osquery.io/darwin/osquery-5.0.1.pkg', 162 | v: true, 163 | s: 'sha256:ec58996e64637d861ccead8dc6bc8865662728f6e5bc2694a3c92f0f4a371095', 164 | n: 'osquery', 165 | t: 'pkgonly', 166 | version: '5.0.1', 167 | versioncmd: '/usr/local/bin/osqueryi --version | sed "s/osqueryi version //"', 168 | to: '/usr/local/bin/osqueryi' 169 | } 170 | # https://gpgtools.org/ 171 | # - { u: 'https://releases.gpgtools.org/GPG_Suite-2020.1.dmg', 172 | # v: False, 173 | # s: 'sha256:xxx' 174 | # } 175 | # https://downloads.chef.io/products/inspec 176 | - { u: 'https://packages.chef.io/files/stable/inspec/4.46.13/mac_os_x/11/inspec-4.46.13-1.x86_64.dmg', 177 | v: true, 178 | s: 'sha256:cf117764cd1e67ef4d161d6ad8bd0e713d25d2e6afaaea0d734e6707eccd2e58', 179 | n: 'inspec', 180 | t: 'pkg', 181 | m: '/Volumes/InSpec', 182 | version: '4.46.13', 183 | exec_name: 'inspec-4.46.13-1.pkg', 184 | versioncmd: 'inspec --version 2>&1 | tail -1' 185 | } 186 | # - { u: '', 187 | # f: '', 188 | # v: True, 189 | # s: 'sha256:aaaa', 190 | # n: '', 191 | # t: 'app', 192 | # m: '/Volumes/app', 193 | # version: '', 194 | # versioncmd: '', 195 | # to: '/Applications/example.app' 196 | # } 197 | pre_tasks: 198 | - name: Macos 11 | set fact 199 | ansible.builtin.set_fact: 200 | macos_apps_install_list: 201 | - "{{ macos_apps_install_list }}" 202 | - { u: 'https://github.com/macports/macports-base/releases/download/v2.7.1/MacPorts-2.7.1-11-BigSur.pkg', 203 | v: false, 204 | s: 'sha256:72189c01f8a21f33869636061dc95b51b20428fa3937518e375fb6e8dd7e4fe3', 205 | n: 'MacPorts', 206 | t: 'pkgonly', 207 | version: '2.7.1', 208 | to: '/opt/local/bin/ports' 209 | } 210 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[0] == '11' 211 | - name: Macos 10.15 | set fact 212 | ansible.builtin.set_fact: 213 | macos_apps_install_list: 214 | - "{{ macos_apps_install_list }}" 215 | - { u: 'https://github.com/macports/macports-base/releases/download/v2.7.1/MacPorts-2.7.1-10.15-Catalina.pkg', 216 | v: false, 217 | s: 'sha256:cd312d9755ec822630e4c26c6bb863f87fdac2e4d71d5d5f24cea2b20a7bc0f1', 218 | n: 'MacPorts', 219 | t: 'pkgonly', 220 | version: '2.7.1', 221 | to: '/opt/local/bin/ports' 222 | } 223 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '15' 224 | - name: Macos 10.14 | set fact 225 | ansible.builtin.set_fact: 226 | macos_apps_install_list: 227 | - "{{ macos_apps_install_list }}" 228 | - { u: 'https://github.com/macports/macports-base/releases/download/v2.7.1/MacPorts-2.7.1-10.14-Mojave.pkg', 229 | v: false, 230 | s: 'sha256:29e2ff54749819dbdb8a6fd2f6f5ba56f467dc554f4fc2c145fd64b607d84272', 231 | n: 'MacPorts', 232 | t: 'pkgonly', 233 | version: '2.7.1', 234 | to: '/opt/local/bin/ports' 235 | } 236 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '14' 237 | - name: Macos 10.13 | set fact 238 | ansible.builtin.set_fact: 239 | macos_apps_install_list: 240 | - "{{ macos_apps_install_list }}" 241 | - { u: 'https://distfiles.macports.org/MacPorts/MacPorts-2.6.3-10.13-HighSierra.pkg', 242 | v: false, 243 | s: 'sha256:218a64116b429140bab5cd795379d814a40f42bc0d45c7e96a1ea4b35be58776', 244 | n: 'MacPorts', 245 | t: 'pkgonly', 246 | version: '2.6.3', 247 | to: '/opt/local/bin/ports' 248 | } 249 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '13' 250 | - name: Macos 10.12 | set fact 251 | ansible.builtin.set_fact: 252 | macos_apps_install_list: 253 | - "{{ macos_apps_install_list }}" 254 | - { u: 'https://distfiles.macports.org/MacPorts/MacPorts-2.6.3-10.12-Sierra.pkg', 255 | v: true, 256 | s: 'sha256:6414963aef281c6a50145afcbc2eab4bc6eda3678df059c772e048524d4491a0', 257 | n: 'MacPorts', 258 | t: 'pkgonly', 259 | version: '2.6.3', 260 | to: '/opt/local/bin/ports' 261 | } 262 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '12' 263 | - name: Macos 10.11 | set fact 264 | ansible.builtin.set_fact: 265 | macos_apps_install_list: 266 | - "{{ macos_apps_install_list }}" 267 | - { u: 'https://distfiles.macports.org/MacPorts/MacPorts-2.6.3-10.11-ElCapitan.pkg', 268 | v: true, 269 | s: 'sha256:174e3203362f4ddf2cd1ad55c1d050768dd38d8efff1e2e215163cd71cdfec93', 270 | n: 'MacPorts', 271 | t: 'pkgonly', 272 | version: '2.6.3', 273 | versioncmd: '', 274 | to: '/opt/local/bin/ports' 275 | } 276 | when: ansible_distribution == 'MacOSX' and ansible_distribution_version.split('.')[1] == '11' 277 | roles: 278 | - juju4.macos_apps_install 279 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'serverspec' 4 | gem 'rake' 5 | ## for junit output and jenkins support 6 | ## FIXME! travis: 'Could not find gem 'yarjuf' in any of the gem sources listed in your Gemfile or available on this machine.' 7 | #gem 'yarjuf' 8 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake' 2 | require 'rspec/core/rake_task' 3 | 4 | RSpec::Core::RakeTask.new(:spec) do |t| 5 | t.pattern = '*_spec.rb' 6 | end 7 | 8 | task :default => :spec 9 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/run-local-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | ## get consistent ruby2+bundler env on each distribution 3 | 4 | location=`dirname "$0"` 5 | cd $location 6 | v=2.3 7 | 8 | ## docker environment in travis missing few utils 9 | [ -f /etc/debian_version ] && apt-get install -y curl 10 | [ -f /etc/redhat-release ] && yum -y install which 11 | 12 | curl -sSL https://get.rvm.io | bash 13 | #[ -f $HOME/.rvm/scripts/rvm ] && . $HOME/.rvm/scripts/rvm 14 | #[ -d /usr/local/rvm ] && . /etc/profile.d/rvm.sh 15 | 16 | ## troubleshoot 17 | type rvm | head -1 18 | env 19 | 20 | #export PATH=/usr/local/rvm/bin:$PATH 21 | 22 | bash -l -c "rvm install $v" 23 | bash -l -c "rvm use $v" 24 | bash -l -c "rvm use $v --default" 25 | bash -l -c "gem install bundler" 26 | bash -l -c "bundle install --path ./gems" 27 | if [ "X$USER" != "Xroot" -a "X$USER" != "X" ]; then 28 | bash -l -c "env rvmsudo_secure_path=1 rvmsudo bundle exec rake spec" 29 | else 30 | bash -l -c "bundle exec rake spec" 31 | fi 32 | --------------------------------------------------------------------------------