diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 443cf3be..b1659a53 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,3 +6,5 @@ updates: schedule: # Check for updates to GitHub Actions every weekday interval: "daily" + cooldown: + default-days: 7 diff --git a/.github/workflows/ansible-test-windows.yml b/.github/workflows/ansible-test-windows.yml index f922edc1..e9e79e8c 100644 --- a/.github/workflows/ansible-test-windows.yml +++ b/.github/workflows/ansible-test-windows.yml @@ -24,9 +24,12 @@ on: # Cancel existing runs on new commits to a branch concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +# Deny all permissions at workflow level - scope per job +permissions: {} + env: NAMESPACE: lowlydba COLLECTION_NAME: sqlserver @@ -62,13 +65,29 @@ jobs: run: shell: wsl-bash {0} + permissions: + # Required for uploading coverage reports + contents: write # Required for uploading coverage reports + # Required for OIDC token authentication + id-token: write # Required for OIDC token authentication + env: + NAMESPACE: lowlydba # zizmor: ignore[template-injection] -- Static value + COLLECTION_NAME: sqlserver # zizmor: ignore[template-injection] -- Static value + GHWS: ${{ env.GHWS }} # zizmor: ignore[template-injection] -- Dynamically computed in earlier step + GROUP: ${{ matrix.group }} # zizmor: ignore[template-injection] -- Matrix value from controlled environment + ANSIBLE: ${{ matrix.ansible }} # zizmor: ignore[template-injection] -- Matrix value from controlled environment + PYTHON: python3 + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # zizmor: ignore[secrets-outside-env] -- Codecov token needed for coverage uploads; environment protection would block PR-triggered runs + WORKSPACE: ${{ github.workspace }} + steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + persist-credentials: false - - name: Create an admin user + - name: Create an admin user # zizmor: ignore[misfeature] -- Windows-specific cmd required for net user commands; pwsh cannot create local users shell: cmd run: | net user admin pass123@ /add /y @@ -90,11 +109,11 @@ jobs: run: | Get-Service -Name MongoDB | Where-Object Status -eq 'Running' | Stop-Service -Force - - name: Add a hosts entry + - name: Add a hosts entry # zizmor: ignore[misfeature] -- Windows-specific cmd required for hosts file modification shell: cmd run: echo 127.0.0.1 sqlserver >> "%WinDir%\System32\Drivers\etc\hosts" - - uses: Vampire/setup-wsl@v6.0.0 + - uses: Vampire/setup-wsl@887f39deb6c0976365e546926fe66f41b77d65ff # v6.1.0 with: distribution: ${{ matrix.wsl }} update: "false" @@ -109,7 +128,7 @@ jobs: - name: Get Linux workspace path shell: pwsh run: | - # $ws = & wslpath --% -u -a "${{ github.workspace }}"" + # $ws = & wslpath --% -u -a "$env:WORKSPACE"" # seems wslpath is not available on server 2019 function ConvertTo-LinuxPathCrappy { @@ -129,23 +148,27 @@ jobs: '/mnt/{0}/{1}' -f $drive, $rooted } } - $ws = ConvertTo-LinuxPathCrappy -LiteralPath "${{ github.workspace }}" + $ws = ConvertTo-LinuxPathCrappy -LiteralPath "$env:WORKSPACE" Add-Content -LiteralPath $env:GITHUB_ENV -Value "GHWS=$ws" # Override break-sys-pkg defaults, because we don't need to bother with python venv for CI - - name: Install ansible-base (${{ matrix.ansible }}) + - name: Install ansible-base + env: + ANSIBLE: ${{ matrix.ansible }} run: | - ${{ matrix.python }} -m pip config set global.break-system-packages true - ${{ matrix.python }} -m pip install --upgrade setuptools pypsrp --disable-pip-version-check --retries 10 - ${{ matrix.python }} -m pip install https://github.com/ansible/ansible/archive/${{ matrix.ansible }}.tar.gz --disable-pip-version-check --retries 10 + python3 -m pip config set global.break-system-packages true + python3 -m pip install --upgrade setuptools pypsrp --disable-pip-version-check --retries 10 + python3 -m pip install "https://github.com/ansible/ansible/archive/$ANSIBLE.tar.gz" --disable-pip-version-check --retries 10 - name: Install collection dependencies id: collection-dependency + # zizmor: ignore[template-injection] -- GHWS is dynamically computed earlier in the workflow run: ansible-galaxy collection install ansible.windows -p "${{ env.GHWS }}" continue-on-error: true - name: Retry install collection dependencies if: steps.collection-dependency.outcome == 'failure' + # zizmor: ignore[template-injection] -- GHWS is dynamically computed earlier in the workflow run: ansible-galaxy collection install ansible.windows -p "${{ env.GHWS }}" - name: Set integration test options @@ -157,7 +180,7 @@ jobs: - name: Install SQL Server continue-on-error: true id: mssqlsuite - uses: potatoqualitee/mssqlsuite@v1.12 + uses: potatoqualitee/mssqlsuite@2291d923e83859edd871679c05b379037376761f # v1.12 with: install: sqlengine sa-password: L0wlydb4 @@ -166,25 +189,32 @@ jobs: - name: Retry SQL Server install id: retry1 if: steps.mssqlsuite.outcome == 'failure' - uses: potatoqualitee/mssqlsuite@v1.12 + uses: potatoqualitee/mssqlsuite@2291d923e83859edd871679c05b379037376761f # v1.12 with: install: sqlengine sa-password: L0wlydb4 version: 2022 - name: Run integration test + env: + GHWS: ${{ env.GHWS }} + NAMESPACE: ${{ env.NAMESPACE }} + COLLECTION_NAME: ${{ env.COLLECTION_NAME }} + GROUP: ${{ env.GROUP }} run: | - pushd "${{ env.GHWS }}/ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}" - ansible-test windows-integration -v --color --retry-on-error --continue-on-error --diff --coverage --requirements windows/group/${{ matrix.group }}/ + pushd "$GHWS/ansible_collections/$NAMESPACE/$COLLECTION_NAME" + ansible-test windows-integration -v --color --retry-on-error --continue-on-error --diff --coverage --requirements windows/group/$GROUP/ - name: Generate coverage report + env: + GHWS: ${{ env.GHWS }} + NAMESPACE: ${{ env.NAMESPACE }} + COLLECTION_NAME: ${{ env.COLLECTION_NAME }} run: | - pushd "${{ env.GHWS }}/ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}" + pushd "$GHWS/ansible_collections/$NAMESPACE/$COLLECTION_NAME" ansible-test coverage xml -v --requirements # See the reports at https://codecov.io/gh/lowlydba/lowlydba.sqlserver - - uses: codecov/codecov-action@v6.0.0 + - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: fail_ci_if_error: false - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/ansible-test.yml b/.github/workflows/ansible-test.yml index 933a53c1..a329b305 100644 --- a/.github/workflows/ansible-test.yml +++ b/.github/workflows/ansible-test.yml @@ -32,9 +32,12 @@ on: # Cancel existing runs on new commits to a branch concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true +# Deny all permissions at workflow level - scope per job +permissions: {} + env: NAMESPACE: lowlydba COLLECTION_NAME: sqlserver @@ -47,6 +50,8 @@ jobs: sanity: name: Sanity (Ⓐ${{ matrix.ansible }}) + permissions: + contents: write # Required for uploading coverage reports strategy: matrix: # https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix @@ -62,12 +67,13 @@ jobs: # .../ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}/ - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + persist-credentials: false - name: Run confidence tests - uses: ansible-community/ansible-test-gh-action@v1.17.0 + uses: ansible-community/ansible-test-gh-action@d3a8ec7a59694e25e210fcd44738910149537f0e # v1.17.0 with: ansible-core-version: ${{ matrix.ansible }} testing-type: sanity @@ -78,11 +84,11 @@ jobs: working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} # See the reports at https://codecov.io/gh/lowlydba/lowlydba.sqlserver - - uses: codecov/codecov-action@v6.0.0 + - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: fail_ci_if_error: false env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # zizmor: ignore[secrets-outside-env] -- Codecov token needed for uploading coverage; workflow_dispatch only ### # Integration tests (RECOMMENDED) @@ -96,9 +102,11 @@ jobs: integration: runs-on: ubuntu-latest name: I (Ⓐ${{ matrix.ansible }}+py${{ matrix.python }}) + permissions: + contents: write # Required for uploading coverage reports services: sqlserver: - image: mcr.microsoft.com/mssql/server:2022-latest + image: mcr.microsoft.com/mssql/server:2022-latest # zizmor: ignore[unpinned-images] -- Trusted publisher for this CI use case ports: - 1433:1433 env: @@ -116,16 +124,17 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} + persist-credentials: false - name: Set integration test options working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}}/tests/integration run: cp integration_config.sample.yml integration_config.yml - name: Run integration tests - uses: ansible-community/ansible-test-gh-action@v1.17.0 + uses: ansible-community/ansible-test-gh-action@d3a8ec7a59694e25e210fcd44738910149537f0e # v1.17.0 with: ansible-core-version: ${{ matrix.ansible }} testing-type: integration @@ -138,8 +147,8 @@ jobs: working-directory: ./ansible_collections/${{env.NAMESPACE}}/${{env.COLLECTION_NAME}} # See the reports at https://codecov.io/gh/lowlydba/lowlydba.sqlserver - - uses: codecov/codecov-action@v6.0.0 + - uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: fail_ci_if_error: false env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} # zizmor: ignore[secrets-outside-env] -- Codecov token needed for uploading coverage; workflow_dispatch only diff --git a/.github/workflows/docs-pr.yml b/.github/workflows/docs-pr.yml index d7c06ba5..6c1fb02c 100644 --- a/.github/workflows/docs-pr.yml +++ b/.github/workflows/docs-pr.yml @@ -1,17 +1,16 @@ name: Collection Docs concurrency: - group: docs-pr-${{ github.head_ref }} + group: docs-pr-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true on: - pull_request_target: + pull_request_target: # zizmor: ignore[dangerous-triggers] -- pull_request_target is required to have permissions to comment on PRs from forks types: [opened, synchronize, reopened, closed] env: GHP_BASE_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }} permissions: - pages: write - id-token: write + contents: read jobs: validate-docs: @@ -19,7 +18,7 @@ jobs: contents: read name: Validate Ansible Docs if: github.event.action != 'closed' - uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@main + uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@50bb8f670ad5ff11443bd94e51369debb8d34775 # main with: artifact-upload: false init-lenient: false @@ -28,11 +27,11 @@ jobs: build-docs: permissions: - contents: read - pages: write - id-token: write + contents: read # Required for reading collection content + pages: write # Required for publishing docs to GitHub Pages + id-token: write # Required for OIDC authentication name: Build Ansible Docs - uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-pr.yml@main + uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-pr.yml@50bb8f670ad5ff11443bd94e51369debb8d34775 # main with: init-lenient: true init-fail-on-error: false @@ -42,12 +41,12 @@ jobs: # for now we won't run this on forks if: github.repository == 'lowlydba/lowlydba.sqlserver' permissions: - contents: write - pages: write - id-token: write + contents: write # Required for writing release/tag artifacts + pages: write # Required for publishing docs to GitHub Pages + id-token: write # Required for OIDC authentication needs: [build-docs] name: Publish Ansible Docs - uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-gh-pages.yml@main + uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-gh-pages.yml@50bb8f670ad5ff11443bd94e51369debb8d34775 # main with: artifact-name: ${{ needs.build-docs.outputs.artifact-name }} action: ${{ (github.event.action == 'closed' || needs.build-docs.outputs.changed != 'true') && 'teardown' || 'publish' }} @@ -56,13 +55,13 @@ jobs: comment: permissions: - pull-requests: write - runs-on: ubuntu-latest + pull-requests: write # Required for commenting on PRs + runs-on: ubuntu-slim needs: [publish-docs-gh-pages, build-docs] name: PR comments steps: - name: PR comment - uses: ansible-community/github-docs-build/actions/ansible-docs-build-comment@main + uses: ansible-community/github-docs-build/actions/ansible-docs-build-comment@50bb8f670ad5ff11443bd94e51369debb8d34775 # zizmor: ignore[stale-action-refs] -- Using main branch SHA of ansible-community maintained action; branch is stable with: body-includes: '## Docs Build' reactions: heart diff --git a/.github/workflows/docs-push.yml b/.github/workflows/docs-push.yml index 05829255..3c7c6324 100644 --- a/.github/workflows/docs-push.yml +++ b/.github/workflows/docs-push.yml @@ -12,15 +12,14 @@ on: - cron: '0 13 * * *' permissions: - pages: write - id-token: write + contents: read # Required for reading collection content jobs: build-docs: permissions: - contents: read + contents: read # Required for reading collection content name: Build Ansible Docs - uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@main + uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-push.yml@50bb8f670ad5ff11443bd94e51369debb8d34775 # main with: init-lenient: false init-fail-on-error: true @@ -29,12 +28,12 @@ jobs: # for now we won't run this on forks if: github.repository == 'lowlydba/lowlydba.sqlserver' permissions: - contents: write - pages: write - id-token: write + contents: write # Required for writing release/tag artifacts + pages: write # Required for publishing docs to GitHub Pages + id-token: write # Required for OIDC authentication needs: [build-docs] name: Publish Ansible Docs - uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-gh-pages.yml@main + uses: ansible-community/github-docs-build/.github/workflows/_shared-docs-build-publish-gh-pages.yml@50bb8f670ad5ff11443bd94e51369debb8d34775 # main with: artifact-name: ${{ needs.build-docs.outputs.artifact-name }} secrets: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b5dfbeaa..dd0ff752 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,13 @@ on: description: "Version number to release" required: true +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: true + +# Deny all permissions at workflow level - scope per job +permissions: {} + env: GHP_BASE_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }} @@ -13,12 +20,21 @@ jobs: release: name: Create GitHub Release runs-on: ubuntu-latest + permissions: + contents: write # Required for creating releases and tags + env: + VERSION: ${{ github.event.inputs.version }} # zizmor: ignore[template-injection] -- User input is required for this workflow + GHP_BASE_URL: ${{ env.GHP_BASE_URL }} # zizmor: ignore[template-injection] -- Set at workflow level + GALAXY_API_KEY: ${{ secrets.GALAXY_API_KEY }} # zizmor: ignore[secrets-outside-env] -- Galaxy API key needed for publishing; workflow_dispatch only + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # zizmor: ignore[secrets-outside-env] -- GitHub token needed for release creation; workflow_dispatch only steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false - name: Set up Python - uses: actions/setup-python@v6 + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: python-version: 3.8 @@ -26,20 +42,23 @@ jobs: run: pip install pyyaml - name: Publish to Galaxy - uses: artis3n/ansible_galaxy_collection@v3.0.0 + uses: artis3n/ansible_galaxy_collection@ffbca2460a5a1c600b941bbf1536bd61de1c2227 # v3.0.0 with: - api_key: ${{ secrets.GALAXY_API_KEY }} + api_key: ${{ env.GALAXY_API_KEY }} - name: Validate version is published to Galaxy - run: curl --head -s -f -o /dev/null https://galaxy.ansible.com/download/lowlydba-sqlserver-${{ github.event.inputs.version }}.tar.gz + run: curl --head -s -f -o /dev/null "https://galaxy.ansible.com/download/lowlydba-sqlserver-${VERSION}.tar.gz" - name: Build release description shell: python + env: + VERSION: ${{ env.VERSION }} + GHP_BASE_URL: ${{ env.GHP_BASE_URL }} run: | import os import yaml - ver = '${{ github.event.inputs.version }}' + ver = '$VERSION' ver_anchor = str.replace(ver, '.', '-') with open('changelogs/changelog.yaml', 'r') as s: @@ -61,19 +80,17 @@ jobs: View the [complete changelog](https://github.com/lowlydba/lowlydba.sqlserver/blob/main/CHANGELOG.rst#v%s) to see all changes. - View the [full documentation for release ${{ github.event.inputs.version }}](${{ env.GHP_BASE_URL }}/tag/${{ github.event.inputs.version }}). - ''' % (reldate, summary, ver_anchor) + View the [full documentation for release %s](%s/tag/%s). + ''' % (reldate, summary, ver_anchor, ver, os.environ['GHP_BASE_URL'], ver) with open(os.environ['GITHUB_ENV'], 'a') as e: e.write("RELEASE_DESCRIPTION<