diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 229920c..3af99ba 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,22 +3,22 @@ # These owners will be the default owners for everything in the # repo. Unless a later match takes precedence, these owners will be # requested for review when someone opens a pull request. -* @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj +* @dav3r @felddy @jsf9k @mcdonnnj # These folks own any files in the .github directory at the root of # the repository and any of its subdirectories. -/.github/ @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj +/.github/ @dav3r @felddy @jsf9k @mcdonnnj # These folks own all linting configuration files. -/.ansible-lint @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/.bandit.yml @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/.flake8 @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/.isort.cfg @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/.mdl_config.yaml @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/.pre-commit-config.yaml @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/.prettierignore @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/.yamllint @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/requirements.txt @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/requirements-dev.txt @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/requirements-test.txt @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj -/setup-env @dav3r @felddy @jasonodoom @jsf9k @mcdonnnj +/.ansible-lint @dav3r @felddy @jsf9k @mcdonnnj +/.bandit.yml @dav3r @felddy @jsf9k @mcdonnnj +/.flake8 @dav3r @felddy @jsf9k @mcdonnnj +/.isort.cfg @dav3r @felddy @jsf9k @mcdonnnj +/.mdl_config.yaml @dav3r @felddy @jsf9k @mcdonnnj +/.pre-commit-config.yaml @dav3r @felddy @jsf9k @mcdonnnj +/.prettierignore @dav3r @felddy @jsf9k @mcdonnnj +/.yamllint @dav3r @felddy @jsf9k @mcdonnnj +/requirements.txt @dav3r @felddy @jsf9k @mcdonnnj +/requirements-dev.txt @dav3r @felddy @jsf9k @mcdonnnj +/requirements-test.txt @dav3r @felddy @jsf9k @mcdonnnj +/setup-env @dav3r @felddy @jsf9k @mcdonnnj diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2398344..acc83fa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,17 +11,25 @@ updates: # Managed by cisagov/skeleton-generic - dependency-name: actions/cache - dependency-name: actions/checkout + - dependency-name: actions/dependency-review-action + - dependency-name: actions/labeler - dependency-name: actions/setup-go - dependency-name: actions/setup-python - - dependency-name: crazy-max/ghaction-dump-context + - dependency-name: cisagov/action-job-preamble + - dependency-name: cisagov/setup-env-github-action - dependency-name: crazy-max/ghaction-github-labeler - - dependency-name: crazy-max/ghaction-github-status + - dependency-name: github/codeql-action + - dependency-name: hashicorp/setup-packer - dependency-name: hashicorp/setup-terraform - dependency-name: mxschmitt/action-tmate - - dependency-name: step-security/harden-runner # # Managed by cisagov/skeleton-aws-lambda-python # - dependency-name: actions/upload-artifact - # - dependency-name: github/codeql-action + labels: + # dependabot default we need to replicate + - dependencies + # This matches our label definition in .github/labels.yml as opposed to + # dependabot's default of `github_actions`. + - github-actions package-ecosystem: github-actions schedule: interval: weekly diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..b67a39d --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,75 @@ +--- +# Each entry in this file is a label that will be applied to pull requests +# if there is a match based on the matching rules for the entry. Please see +# the actions/labeler documentation for more information: +# https://github.com/actions/labeler#match-object +# +# Note: Verify that the label you want to use is defined in the +# crazy-max/ghaction-github-labeler configuration file located at +# .github/labels.yml. + +ansible: + - changed-files: + - any-glob-to-any-file: + - "**/ansible/**" +dependencies: + - changed-files: + - any-glob-to-any-file: + # Add any dependency files used. + - .pre-commit-config.yaml + - requirements*.txt +docker: + - changed-files: + - any-glob-to-any-file: + - "**/compose*.yml" + - "**/docker-compose*.yml" + - "**/Dockerfile*" +documentation: + - changed-files: + - any-glob-to-any-file: + - "**/*.md" +github-actions: + - changed-files: + - any-glob-to-any-file: + - .github/workflows/** +javascript: + - changed-files: + - any-glob-to-any-file: + - "**/*.js" +packer: + - changed-files: + - any-glob-to-any-file: + - "**/*.pkr.hcl" +python: + - changed-files: + - any-glob-to-any-file: + - "**/*.py" +terraform: + - changed-files: + - any-glob-to-any-file: + - "**/*.tf" +test: + - changed-files: + - any-glob-to-any-file: + # Add any test-related files or paths. + - .ansible-lint + - .bandit.yml + - .flake8 + - .isort.cfg + - .mdl_config.yaml + - .yamllint + - pytest.ini + - tests/** +typescript: + - changed-files: + - any-glob-to-any-file: + - "**/*.ts" +upstream update: + - head-branch: + # Any Lineage pull requests should use this branch. + - lineage/skeleton +version bump: + - changed-files: + - any-glob-to-any-file: + # Ensure this matches your version tracking file(s). + - src/version.txt diff --git a/.github/labels.yml b/.github/labels.yml index 40e41cd..650ed7c 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -2,72 +2,90 @@ # Rather than breaking up descriptions into multiline strings we disable that # specific rule in yamllint for this file. # yamllint disable rule:line-length -- color: "eb6420" +- color: f15a53 + description: Pull requests that update Ansible code + name: ansible +- color: eb6420 description: This issue or pull request is awaiting the outcome of another issue or pull request name: blocked - color: "000000" description: This issue or pull request involves changes to existing functionality name: breaking change -- color: "d73a4a" +- color: d73a4a description: This issue or pull request addresses broken functionality name: bug -- color: "07648d" +- color: 07648d description: This issue will be advertised on code.gov's Open Tasks page (https://code.gov/open-tasks) name: code.gov -- color: "0366d6" +- color: 0366d6 description: Pull requests that update a dependency file name: dependencies -- color: "5319e7" +- color: 2497ed + description: Pull requests that update Docker code + name: docker +- color: 5319e7 description: This issue or pull request improves or adds to documentation name: documentation -- color: "cfd3d7" +- color: cfd3d7 description: This issue or pull request already exists or is covered in another issue or pull request name: duplicate -- color: "b005bc" +- color: b005bc description: A high-level objective issue encompassing multiple issues instead of a specific unit of work name: epic - color: "000000" description: Pull requests that update GitHub Actions code name: github-actions -- color: "0e8a16" +- color: 0e8a16 description: This issue or pull request is well-defined and good for newcomers name: good first issue -- color: "ff7518" +- color: ff7518 description: Pull request that should count toward Hacktoberfest participation name: hacktoberfest-accepted -- color: "a2eeef" +- color: a2eeef description: This issue or pull request will add or improve functionality, maintainability, or ease of use name: improvement -- color: "fef2c0" +- color: fef2c0 description: This issue or pull request is not applicable, incorrect, or obsolete name: invalid -- color: "ce099a" +- color: f1d642 + description: Pull requests that update JavaScript code + name: javascript +- color: ce099a description: This pull request is ready to merge during the next Lineage Kraken release name: kraken 🐙 -- color: "a4fc5d" +- color: a4fc5d description: This issue or pull request requires further information name: need info -- color: "fcdb45" +- color: fcdb45 description: This pull request is awaiting an action or decision to move forward name: on hold -- color: "3772a4" +- color: 02a8ef + description: Pull requests that update Packer code + name: packer +- color: 3772a4 description: Pull requests that update Python code name: python -- color: "ef476c" +- color: ef476c description: This issue is a request for information or needs discussion name: question -- color: "d73a4a" +- color: d73a4a description: This issue or pull request addresses a security issue name: security -- color: "00008b" +- color: 7b42bc + description: Pull requests that update Terraform code + name: terraform +- color: 00008b description: This issue or pull request adds or otherwise modifies test code name: test -- color: "1d76db" +- color: 2b6ebf + description: Pull requests that update TypeScript code + name: typescript +- color: 1d76db description: This issue or pull request pulls in upstream updates name: upstream update -- color: "d4c5f9" +- color: d4c5f9 description: This issue or pull request increments the version number name: version bump -- color: "ffffff" +- color: ffffff description: This issue will not be incorporated name: wontfix diff --git a/.github/lineage.yml b/.github/lineage.yml index 49f9c4f..46d3224 100644 --- a/.github/lineage.yml +++ b/.github/lineage.yml @@ -2,4 +2,4 @@ lineage: skeleton: remote-url: https://github.com/cisagov/skeleton-generic.git -version: '1' +version: "1" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f15c98..1dbf140 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ --- name: build -on: +on: # yamllint disable-line rule:truthy merge_group: types: - checks_requested @@ -20,7 +20,6 @@ defaults: shell: bash -Eueo pipefail -x {0} env: - CURL_CACHE_DIR: ~/.cache/curl DEFAULT_ARTIFACT_NAME: lambda_build.zip PIP_CACHE_DIR: ~/.cache/pip PRE_COMMIT_CACHE_DIR: ~/.cache/pre-commit @@ -32,42 +31,85 @@ env: jobs: diagnostics: name: Run diagnostics + # This job does not need any permissions + permissions: {} runs-on: ubuntu-latest steps: # Note that a duplicate of this step must be added at the top of # each job. - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit - - id: github-status - name: Check GitHub status - uses: crazy-max/ghaction-github-status@v4 - - id: dump-context - name: Dump context - uses: crazy-max/ghaction-dump-context@v2 + check_github_status: "true" + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + output_workflow_context: "true" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} lint: needs: - diagnostics + permissions: + # actions/checkout needs this to fetch code + contents: read runs-on: ubuntu-latest steps: - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} - id: setup-env - uses: cisagov/setup-env-github-action@develop - - uses: actions/checkout@v4 + uses: cisagov/setup-env-github-action@v1 + - uses: actions/checkout@v5 - id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ steps.setup-env.outputs.python-version }} # We need the Go version and Go cache location for the actions/cache step, # so the Go installation must happen before that. - id: setup-go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: # There is no expectation for actual Go code so we disable caching as # it relies on the existence of a go.sum file. @@ -77,18 +119,18 @@ jobs: name: Lookup Go cache directory run: | echo "dir=$(go env GOCACHE)" >> $GITHUB_OUTPUT - - uses: actions/cache@v3 + - uses: actions/cache@v4 env: - BASE_CACHE_KEY: "${{ github.job }}-${{ runner.os }}-\ + BASE_CACHE_KEY: ${{ github.job }}-${{ runner.os }}-\ py${{ steps.setup-python.outputs.python-version }}-\ go${{ steps.setup-go.outputs.go-version }}-\ packer${{ steps.setup-env.outputs.packer-version }}-\ - tf${{ steps.setup-env.outputs.terraform-version }}-" + tf${{ steps.setup-env.outputs.terraform-version }}- with: - key: "${{ env.BASE_CACHE_KEY }}\ + key: ${{ env.BASE_CACHE_KEY }}\ ${{ hashFiles('**/requirements-test.txt') }}-\ ${{ hashFiles('**/requirements.txt') }}-\ - ${{ hashFiles('**/.pre-commit-config.yaml') }}" + ${{ hashFiles('**/.pre-commit-config.yaml') }} # Note that the .terraform directory IS NOT included in the # cache because if we were caching, then we would need to use # the `-upgrade=true` option. This option blindly pulls down the @@ -98,25 +140,12 @@ jobs: path: | ${{ env.PIP_CACHE_DIR }} ${{ env.PRE_COMMIT_CACHE_DIR }} - ${{ env.CURL_CACHE_DIR }} ${{ steps.go-cache.outputs.dir }} restore-keys: | ${{ env.BASE_CACHE_KEY }} - - name: Setup curl cache - run: mkdir -p ${{ env.CURL_CACHE_DIR }} - - name: Install Packer - env: - PACKER_VERSION: ${{ steps.setup-env.outputs.packer-version }} - run: | - PACKER_ZIP="packer_${PACKER_VERSION}_linux_amd64.zip" - curl --output ${{ env.CURL_CACHE_DIR }}/"${PACKER_ZIP}" \ - --time-cond ${{ env.CURL_CACHE_DIR }}/"${PACKER_ZIP}" \ - --location \ - "https://releases.hashicorp.com/packer/${PACKER_VERSION}/${PACKER_ZIP}" - sudo unzip -d /opt/packer \ - ${{ env.CURL_CACHE_DIR }}/"${PACKER_ZIP}" - sudo mv /usr/local/bin/packer /usr/local/bin/packer-default - sudo ln -s /opt/packer/packer /usr/local/bin/packer + - uses: hashicorp/setup-packer@v3 + with: + version: ${{ steps.setup-env.outputs.packer-version }} - uses: hashicorp/setup-terraform@v3 with: terraform_version: ${{ steps.setup-env.outputs.terraform-version }} @@ -174,16 +203,37 @@ jobs: - diagnostics - lint steps: - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} - id: setup-env - uses: cisagov/setup-env-github-action@develop - - uses: actions/checkout@v4 + uses: cisagov/setup-env-github-action@v1 + - uses: actions/checkout@v5 - id: setup-python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ steps.setup-env.outputs.python-version }} - uses: actions/cache@v3 @@ -223,12 +273,33 @@ jobs: - "3.8" - "3.9" steps: - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit - - uses: actions/checkout@v4 + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + - uses: actions/checkout@v5 - name: Get the short SHA for the commit being used run: | echo "GH_SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV @@ -242,10 +313,9 @@ jobs: - name: Upload the generated Lambda deployment package as an artifact uses: actions/upload-artifact@v4 with: - name: "${{ github.event.repository.name }}-\ - py${{ matrix.python-version }}-\ - ${{ env.GH_SHORT_SHA }}" - path: "${{ env.DEFAULT_ARTIFACT_NAME }}" + name: ${{ github.event.repository.name }}-py${{ + matrix.python-version }}-${{ env.GH_SHORT_SHA }} + path: ${{ env.DEFAULT_ARTIFACT_NAME }} - name: Setup tmate debug session uses: mxschmitt/action-tmate@v3 if: env.RUN_TMATE diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d029a34..e868cd3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -6,64 +6,115 @@ # or to provide custom queries or build logic. name: CodeQL +# The use of on here as a key is part of the GitHub actions syntax. +# yamllint disable-line rule:truthy on: + merge_group: + types: + - checks_requested + pull_request: + # The branches here must be a subset of the ones in the push key + branches: + - develop push: - # Dependabot triggered push events have read-only access, but uploading code + # Dependabot-triggered push events have read-only access, but uploading code # scanning requires write access. branches-ignore: - dependabot/** - pull_request: - # The branches below must be a subset of the branches above - branches: - - develop schedule: - - cron: '0 14 * * 6' + - cron: 0 14 * * 6 jobs: diagnostics: name: Run diagnostics + # This job does not need any permissions + permissions: {} runs-on: ubuntu-latest steps: # Note that a duplicate of this step must be added at the top of # each job. - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit - - id: github-status - name: Check GitHub status - uses: crazy-max/ghaction-github-status@v4 - - id: dump-context - name: Dump context - uses: crazy-max/ghaction-dump-context@v2 + check_github_status: "true" + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + output_workflow_context: "true" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} analyze: name: Analyze needs: - diagnostics runs-on: ubuntu-latest permissions: + # actions/checkout needs this to fetch code + contents: read # required for all workflows security-events: write strategy: fail-fast: false matrix: - # Override automatic language detection by changing the below list - # Supported options are go, javascript, csharp, python, cpp, and java + # Override automatic language detection by changing the below + # list + # + # Supported options are actions, c-cpp, csharp, go, + # java-kotlin, javascript-typescript, python, ruby, and swift. language: + - actions - python # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..bc859d1 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,95 @@ +--- +name: Dependency review + +on: # yamllint disable-line rule:truthy + merge_group: + types: + - checks_requested + pull_request: + +# Set a default shell for any run steps. The `-Eueo pipefail` sets errtrace, +# nounset, errexit, and pipefail. The `-x` will print all commands as they are +# run. Please see the GitHub Actions documentation for more information: +# https://docs.github.com/en/actions/using-jobs/setting-default-values-for-jobs +defaults: + run: + shell: bash -Eueo pipefail -x {0} + +jobs: + diagnostics: + name: Run diagnostics + # This job does not need any permissions + permissions: {} + runs-on: ubuntu-latest + steps: + # Note that a duplicate of this step must be added at the top of + # each job. + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 + with: + check_github_status: "true" + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + output_workflow_context: "true" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + dependency-review: + name: Dependency review + needs: + - diagnostics + permissions: + # actions/checkout needs this to fetch code + contents: read + runs-on: ubuntu-latest + steps: + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 + with: + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + - id: checkout-repo + name: Checkout the repository + uses: actions/checkout@v5 + - id: dependency-review + name: Review dependency changes for vulnerabilities and license changes + uses: actions/dependency-review-action@v4 diff --git a/.github/workflows/label-prs.yml b/.github/workflows/label-prs.yml new file mode 100644 index 0000000..9d78e39 --- /dev/null +++ b/.github/workflows/label-prs.yml @@ -0,0 +1,93 @@ +--- +name: Label pull requests + +on: # yamllint disable-line rule:truthy + pull_request: + types: + - edited + - opened + - synchronize + +# Set a default shell for any run steps. The `-Eueo pipefail` sets errtrace, +# nounset, errexit, and pipefail. The `-x` will print all commands as they are +# run. Please see the GitHub Actions documentation for more information: +# https://docs.github.com/en/actions/using-jobs/setting-default-values-for-jobs +defaults: + run: + shell: bash -Eueo pipefail -x {0} + +jobs: + diagnostics: + name: Run diagnostics + # This job does not need any permissions + permissions: {} + runs-on: ubuntu-latest + steps: + # Note that a duplicate of this step must be added at the top of + # each job. + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 + with: + check_github_status: "true" + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + output_workflow_context: "true" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + label: + needs: + - diagnostics + permissions: + # Permissions required by actions/labeler + contents: read + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 + with: + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + - name: Apply suitable labels to a pull request + uses: actions/labeler@v6 diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml index 5a20438..19e0129 100644 --- a/.github/workflows/sync-labels.yml +++ b/.github/workflows/sync-labels.yml @@ -1,11 +1,12 @@ --- name: sync-labels -on: +on: # yamllint disable-line rule:truthy push: paths: - - '.github/labels.yml' - - '.github/workflows/sync-labels.yml' + - .github/labels.yml + - .github/workflows/sync-labels.yml + workflow_dispatch: permissions: contents: read @@ -13,21 +14,40 @@ permissions: jobs: diagnostics: name: Run diagnostics + # This job does not need any permissions + permissions: {} runs-on: ubuntu-latest steps: # Note that a duplicate of this step must be added at the top of # each job. - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit - - id: github-status - name: Check GitHub status - uses: crazy-max/ghaction-github-status@v3 - - id: dump-context - name: Dump context - uses: crazy-max/ghaction-dump-context@v2 + check_github_status: "true" + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + output_workflow_context: "true" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} labeler: needs: - diagnostics @@ -38,12 +58,33 @@ jobs: issues: write runs-on: ubuntu-latest steps: - - id: harden-runner - name: Harden the runner - uses: step-security/harden-runner@v2 + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 with: - egress-policy: audit - - uses: actions/checkout@v4 + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-generic#207 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + - uses: actions/checkout@v5 - name: Sync repository labels if: success() uses: crazy-max/ghaction-github-labeler@v5 diff --git a/.mdl_config.yaml b/.mdl_config.yaml index 4a650c1..1b48994 100644 --- a/.mdl_config.yaml +++ b/.mdl_config.yaml @@ -6,12 +6,12 @@ default: true # MD003/heading-style/header-style - Heading style MD003: # Enforce the ATX-closed style of header - style: "atx_closed" + style: atx_closed # MD004/ul-style - Unordered list style MD004: # Enforce dashes for unordered lists - style: "dash" + style: dash # MD013/line-length - Line length MD013: @@ -30,7 +30,7 @@ MD024: # MD029/ol-prefix - Ordered list item prefix MD029: # Enforce the `1.` style for ordered lists - style: "one" + style: one # MD033/no-inline-html - Inline HTML MD033: @@ -42,19 +42,19 @@ MD033: # MD035/hr-style - Horizontal rule style MD035: # Enforce dashes for horizontal rules - style: "---" + style: --- # MD046/code-block-style - Code block style MD046: # Enforce the fenced style for code blocks - style: "fenced" + style: fenced # MD049/emphasis-style - Emphasis style should be consistent MD049: # Enforce asterisks as the style to use for emphasis - style: "asterisk" + style: asterisk # MD050/strong-style - Strong style should be consistent MD050: # Enforce asterisks as the style to use for strong - style: "asterisk" + style: asterisk diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c3e888e..630f743 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,25 +1,39 @@ --- +ci: + # Do not commit changes from running pre-commit for pull requests. + autofix_prs: false + # Autoupdate hooks weekly (this is the default). + autoupdate_schedule: weekly + default_language_version: # force all unspecified python hooks to run python3 python: python3 repos: + # Check the pre-commit configuration + - repo: meta + hooks: + - id: check-useless-excludes + - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v6.0.0 hooks: - id: check-case-conflict - id: check-executables-have-shebangs - id: check-json - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks - id: check-toml + - id: check-vcs-permalinks - id: check-xml - id: debug-statements + - id: destroyed-symlinks - id: detect-aws-credentials args: - --allow-missing-credentials - id: detect-private-key - id: end-of-file-fixer - exclude: files/(issue|motd) - id: mixed-line-ending args: - --fix=lf @@ -31,24 +45,17 @@ repos: # Text file hooks - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.39.0 + rev: v0.45.0 hooks: - id: markdownlint args: - --config=.mdl_config.yaml - - repo: https://github.com/pre-commit/mirrors-prettier - # This is the last version of v3 available from the mirror. We should hold - # here until v4, which is currently in alpha, is more stable. - rev: v3.1.0 + - repo: https://github.com/rbubley/mirrors-prettier + rev: v3.6.2 hooks: - id: prettier - # This is the latest version of v3 available from NPM. The pre-commit - # mirror does not pull tags for old major versions once a new major - # version tag is published. - additional_dependencies: - - prettier@3.2.5 - repo: https://github.com/adrienverge/yamllint - rev: v1.35.1 + rev: v1.37.1 hooks: - id: yamllint args: @@ -56,40 +63,40 @@ repos: # GitHub Actions hooks - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.28.0 + rev: 0.33.3 hooks: - id: check-github-actions - id: check-github-workflows # pre-commit hooks - repo: https://github.com/pre-commit/pre-commit - rev: v3.6.2 + rev: v4.3.0 hooks: - id: validate_manifest # Go hooks - repo: https://github.com/TekWizely/pre-commit-golang - rev: v1.0.0-rc.1 + rev: v1.0.0-rc.2 hooks: - # Style Checkers - - id: go-critic - # StaticCheck - - id: go-staticcheck-repo-mod # Go Build - id: go-build-repo-mod + # Style Checkers + - id: go-critic + # goimports + - id: go-imports-repo + args: + # Write changes to files + - -w # Go Mod Tidy - id: go-mod-tidy-repo + # GoSec + - id: go-sec-repo-mod + # StaticCheck + - id: go-staticcheck-repo-mod # Go Test - id: go-test-repo-mod # Go Vet - id: go-vet-repo-mod - # GoSec - - id: go-sec-repo-mod - # goimports - - id: go-imports-repo - args: - # Write changes to files - - -w # Nix hooks - repo: https://github.com/nix-community/nixpkgs-fmt rev: v1.3.0 @@ -98,7 +105,7 @@ repos: # Shell script hooks - repo: https://github.com/scop/pre-commit-shfmt - rev: v3.7.0-4 + rev: v3.12.0-2 hooks: - id: shfmt args: @@ -116,14 +123,14 @@ repos: # Redirect operators are followed by a space - --space-redirects - repo: https://github.com/shellcheck-py/shellcheck-py - rev: v0.9.0.6 + rev: v0.11.0.1 hooks: - id: shellcheck # Python hooks # Run bandit on the tests directory with a custom configuration - repo: https://github.com/PyCQA/bandit - rev: 1.7.7 + rev: 1.8.6 hooks: - id: bandit name: bandit (tests directory) @@ -132,44 +139,93 @@ repos: - --config=.bandit.yml # Run bandit on everything but the tests directory - repo: https://github.com/PyCQA/bandit - rev: 1.7.4 + rev: 1.8.6 hooks: - id: bandit name: bandit (everything but the tests directory) exclude: tests - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.2.0 + rev: 25.1.0 hooks: - id: black - repo: https://github.com/PyCQA/flake8 - rev: 7.0.0 + rev: 7.3.0 hooks: - id: flake8 additional_dependencies: - - flake8-docstrings + - flake8-docstrings==1.7.0 - repo: https://github.com/PyCQA/isort - rev: 5.13.2 + rev: 6.0.1 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 + rev: v1.18.1 hooks: - id: mypy + - repo: https://github.com/pypa/pip-audit + rev: v2.9.0 + hooks: + - id: pip-audit + args: + # Add any pip requirements files to scan + - --requirement + - requirements-dev.txt + - --requirement + - requirements-test.txt + - --requirement + - requirements.txt - repo: https://github.com/asottile/pyupgrade - rev: v3.15.1 + rev: v3.20.0 hooks: - id: pyupgrade # Ansible hooks - repo: https://github.com/ansible/ansible-lint - rev: v24.2.0 + rev: v25.9.0 hooks: - id: ansible-lint - # files: molecule/default/playbook.yml + additional_dependencies: + # On its own ansible-lint does not pull in ansible, only + # ansible-core. Therefore, if an Ansible module lives in + # ansible instead of ansible-core, the linter will complain + # that the module is unknown. In these cases it is + # necessary to add the ansible package itself as an + # additional dependency, with the same pinning as is done in + # requirements-test.txt of cisagov/skeleton-ansible-role. + # + # Version 10 is required because the pip-audit pre-commit + # hook identifies a vulnerability in ansible-core 2.16.13, + # but all versions of ansible 9 have a dependency on + # ~=2.16.X. + # + # It is also a good idea to go ahead and upgrade to version + # 10 since version 9 is going EOL at the end of November: + # https://endoflife.date/ansible + # - ansible>=10,<11 + # ansible-core 2.16.3 through 2.16.6 suffer from the bug + # discussed in ansible/ansible#82702, which breaks any + # symlinked files in vars, tasks, etc. for any Ansible role + # installed via ansible-galaxy. Hence we never want to + # install those versions. + # + # Note that the pip-audit pre-commit hook identifies a + # vulnerability in ansible-core 2.16.13. The pin of + # ansible-core to >=2.17 effectively also pins ansible to + # >=10. + # + # It is also a good idea to go ahead and upgrade to + # ansible-core 2.17 since security support for ansible-core + # 2.16 ends this month: + # https://docs.ansible.com/ansible/devel/reference_appendices/release_and_maintenance.html#ansible-core-support-matrix + # + # Note that any changes made to this dependency must also be + # made in requirements.txt in cisagov/skeleton-packer and + # requirements-test.txt in cisagov/skeleton-ansible-role. + - ansible-core>=2.17 # Terraform hooks - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.88.0 + rev: v1.100.0 hooks: - id: terraform_fmt - id: terraform_validate @@ -182,7 +238,7 @@ repos: # Packer hooks - repo: https://github.com/cisagov/pre-commit-packer - rev: v0.0.2 + rev: v0.3.1 hooks: - - id: packer_validate - id: packer_fmt + - id: packer_validate diff --git a/.yamllint b/.yamllint index 2a119a6..00e85a6 100644 --- a/.yamllint +++ b/.yamllint @@ -2,12 +2,33 @@ extends: default rules: + braces: + # Do not allow non-empty flow mappings + forbid: non-empty + # Allow up to one space inside braces. This is required for Ansible compatibility. + max-spaces-inside: 1 + + brackets: + # Do not allow non-empty flow sequences + forbid: non-empty + + comments: + # Ensure that inline comments have at least one space before the preceding content. + # This is required for Ansible compatibility. + min-spaces-from-content: 1 + # yamllint does not like it when you comment out different parts of # dictionaries in a list. You can see # https://github.com/adrienverge/yamllint/issues/384 for some examples of # this behavior. comments-indentation: disable + indentation: + # Ensure that block sequences inside of a mapping are indented + indent-sequences: true + # Enforce a specific number of spaces + spaces: 2 + # yamllint does not allow inline mappings that exceed the line length by # default. There are many scenarios where the inline mapping may be a key, # hash, or other long value that would exceed the line length but cannot @@ -18,6 +39,24 @@ rules: # Allows a 10% overage from the default limit of 80 max: 88 - # yamllint doesn't like when we use yes and no for true and false, - # but that's pretty standard in Ansible. - truthy: disable + # Using anything other than strings to express octal values can lead to unexpected + # and potentially unsafe behavior. Ansible strongly recommends against such practices + # and these rules are needed for Ansible compatibility. Please see the following for + # more information: + # https://ansible.readthedocs.io/projects/lint/rules/risky-octal/ + octal-values: + # Do not allow explicit octal values (those beginning with a leading 0o). + forbid-explicit-octal: true + # Do not allow implicit octal values (those beginning with a leading 0). + forbid-implicit-octal: true + + quoted-strings: + # Allow disallowed quotes (single quotes) for strings that contain allowed quotes + # (double quotes). + allow-quoted-quotes: true + # Apply these rules to keys in mappings as well + check-keys: true + # We prefer double quotes for strings when they are needed + quote-type: double + # Only require quotes when they are necessary for proper processing + required: only-when-needed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b05b4e6..3032d99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -132,11 +132,10 @@ you can begin to use `pyenv`. For a list of Python versions that are already installed and ready to use with `pyenv`, use the command `pyenv versions`. To see a list of the Python versions available to be installed and used with `pyenv` -use the command `pyenv install --list`. You can read more -[here](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md) about -the many things that `pyenv` can do. See -[here](https://github.com/pyenv/pyenv-virtualenv#usage) for the -additional capabilities that pyenv-virtualenv adds to the `pyenv` +use the command `pyenv install --list`. You can read more about +the [many things that `pyenv` can do](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md). +See the [usage information](https://github.com/pyenv/pyenv-virtualenv#usage) +for the additional capabilities that pyenv-virtualenv adds to the `pyenv` command. #### Creating the Python virtual environment #### diff --git a/README.md b/README.md index 02ae4a4..94b279b 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,15 @@ docker compose down ## How to update Python dependencies ## -The Python dependencies are maintained using a [Pipenv](https://github.com/pypa/pipenv) -configuration for each supported Python version. Changes to requirements -should be made to the respective `src/py/Pipfile`. More -information about the `Pipfile` format can be found [here](https://pipenv.pypa.io/en/latest/basics/#example-pipfile-pipfile-lock). -The accompanying `Pipfile.lock` files contain the specific dependency versions -that will be installed. These files can be updated like so (using the Python -3.9 configuration as an example): +The Python dependencies are maintained using a +[Pipenv](https://github.com/pypa/pipenv) configuration for each +supported Python version. Changes to requirements should be made to +the respective `src/py/Pipfile`. More information +about the `Pipfile` format can be found in the [`pipenv` +documentation](https://pipenv.pypa.io/en/latest/basics/#example-pipfile-pipfile-lock). +The accompanying `Pipfile.lock` files contain the specific dependency +versions that will be installed. These files can be updated like so +(using the Python 3.9 configuration as an example): ```console cd src/py3.9 diff --git a/bump-version b/bump-version new file mode 100755 index 0000000..e6e6fa7 --- /dev/null +++ b/bump-version @@ -0,0 +1,172 @@ +#!/usr/bin/env bash + +# bump-version [--push] [--label LABEL] (major | minor | patch | prerelease | build | finalize | show) +# bump-version --list-files + +set -o nounset +set -o errexit +set -o pipefail + +# Stores the canonical version for the project. +VERSION_FILE=src/version.txt +# Files that should be updated with the new version. +VERSION_FILES=("$VERSION_FILE") + +USAGE=$( + cat << END_OF_LINE +Update the version of the project. + +Usage: + ${0##*/} [--push] [--label LABEL] (major | minor | patch | prerelease | build | finalize | show) + ${0##*/} --list-files + ${0##*/} (-h | --help) + +Options: + -h | --help Show this message. + --push Perform a \`git push\` after updating the version. + --label LABEL Specify the label to use when updating the build or prerelease version. + --list-files List the files that will be updated when the version is bumped. +END_OF_LINE +) + +old_version=$(< "$VERSION_FILE") +# Comment out periods so they are interpreted as periods and don't +# just match any character +old_version_regex=${old_version//\./\\\.} +new_version="$old_version" + +bump_part="" +label="" +commit_prefix="Bump" +with_push=false +commands_with_label=("build" "prerelease") +commands_with_prerelease=("major" "minor" "patch") +with_prerelease=false + +####################################### +# Display an error message, the help information, and exit with a non-zero status. +# Arguments: +# Error message. +####################################### +function invalid_option() { + echo "$1" + echo "$USAGE" + exit 1 +} + +####################################### +# Bump the version using the provided command. +# Arguments: +# The version to bump. +# The command to bump the version. +# Returns: +# The new version. +####################################### +function bump_version() { + local temp_version + temp_version=$(python -c "import semver; print(semver.parse_version_info('$1').${2})") + echo "$temp_version" +} + +if [ $# -eq 0 ]; then + echo "$USAGE" + exit 1 +else + while [ $# -gt 0 ]; do + case $1 in + --push) + if [ "$with_push" = true ]; then + invalid_option "Push has already been set." + fi + + with_push=true + shift + ;; + --label) + if [ -n "$label" ]; then + invalid_option "Label has already been set." + fi + + label="$2" + shift 2 + ;; + build | finalize | major | minor | patch) + if [ -n "$bump_part" ]; then + invalid_option "Only one version part should be bumped at a time." + fi + + bump_part="$1" + shift + ;; + prerelease) + with_prerelease=true + shift + ;; + show) + echo "$old_version" + exit 0 + ;; + -h | --help) + echo "$USAGE" + exit 0 + ;; + --list-files) + printf '%s\n' "${VERSION_FILES[@]}" + exit 0 + ;; + *) + invalid_option "Invalid option: $1" + ;; + esac + done +fi + +if [ -n "$label" ] && [ "$with_prerelease" = false ] && [[ ! " ${commands_with_label[*]} " =~ [[:space:]]${bump_part}[[:space:]] ]]; then + invalid_option "Setting the label is only allowed for the following commands: ${commands_with_label[*]}" +fi + +if [ "$with_prerelease" = true ] && [ -n "$bump_part" ] && [[ ! " ${commands_with_prerelease[*]} " =~ [[:space:]]${bump_part}[[:space:]] ]]; then + invalid_option "Changing the prerelease is only allowed in conjunction with the following commands: ${commands_with_prerelease[*]}" +fi + +label_option="" +if [ -n "$label" ]; then + label_option="token='$label'" +fi + +if [ -n "$bump_part" ]; then + if [ "$bump_part" = "finalize" ]; then + commit_prefix="Finalize" + bump_command="finalize_version()" + elif [ "$bump_part" = "build" ]; then + bump_command="bump_${bump_part}($label_option)" + else + bump_command="bump_${bump_part}()" + fi + new_version=$(bump_version "$old_version" "$bump_command") + echo Changing version from "$old_version" to "$new_version" +fi + +if [ "$with_prerelease" = true ]; then + bump_command="bump_prerelease($label_option)" + temp_version=$(bump_version "$new_version" "$bump_command") + echo Changing version from "$new_version" to "$temp_version" + new_version="$temp_version" +fi + +tmp_file=/tmp/version.$$ +for version_file in "${VERSION_FILES[@]}"; do + if [ ! -f "$version_file" ]; then + echo Missing expected file: "$version_file" + exit 1 + fi + sed "s/$old_version_regex/$new_version/" "$version_file" > $tmp_file + mv $tmp_file "$version_file" +done + +git add "${VERSION_FILES[@]}" +git commit --message "$commit_prefix version from $old_version to $new_version" + +if [ "$with_push" = true ]; then + git push +fi diff --git a/docker-compose.yml b/docker-compose.yml index 6e46434..0f91d02 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ --- -version: '3.2' +version: "3.2" services: build_deployment_package: @@ -21,4 +21,4 @@ services: # the invoking environment but falls back to a default value. image: cisagov/example_lambda:${LAMBDA_TAG:-latest} ports: - - "9000:8080" + - 9000:8080 diff --git a/requirements-dev.txt b/requirements-dev.txt index bdc1615..0561d0a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,5 @@ --requirement requirements-test.txt ipython pipenv -semver +# The bump-version script requires at least version 3 of semver. +semver>=3 diff --git a/setup-env b/setup-env index 3a22d43..89c7603 100755 --- a/setup-env +++ b/setup-env @@ -39,6 +39,53 @@ python_versions() { pyenv versions --bare --skip-aliases --skip-envs } +check_python_version() { + local version=$1 + + # This is a valid regex for semantically correct Python version strings. + # For more information see here: + # https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string + # Break down the regex into readable parts major.minor.patch + local major="0|[1-9]\d*" + local minor="0|[1-9]\d*" + local patch="0|[1-9]\d*" + + # Splitting the prerelease part for readability + # Start of the prerelease + local prerelease="(?:-" + # Numeric or alphanumeric identifiers + local prerelease+="(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)" + # Additional dot-separated identifiers + local prerelease+="(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*" + # End of the prerelease, making it optional + local prerelease+=")?" + # Optional build metadata + local build="(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?" + + # Final regex composed of parts + local regex="^($major)\.($minor)\.($patch)$prerelease$build$" + + # This checks if the Python version does not match the regex pattern specified in $regex, + # using Perl for regex matching. If the pattern is not found, then prompt the user with + # the invalid version message. + if ! echo "$version" | perl -ne "exit(!/$regex/)"; then + echo "Invalid version of Python: Python follows semantic versioning," \ + "so any version string that is not a valid semantic version is an" \ + "invalid version of Python." + exit 1 + # Else if the Python version isn't installed then notify the user. + # grep -E is used for searching through text lines that match the + # specific version. + elif ! python_versions | grep -E "^${version}$" > /dev/null; then + echo "Error: Python version $version is not installed." + echo "Installed Python versions are:" + python_versions + exit 1 + else + echo "Using Python version $version" + fi +} + # Flag to force deletion and creation of virtual environment FORCE=0 @@ -54,10 +101,10 @@ LONGOPTS="force,help,install-hooks,list-versions,python-version:,venv-name:" # Define short options for getopt SHORTOPTS="fhilp:v:" -# Check for GNU getopt by matching a specific pattern ("getopt from util-linux") -# in its version output. This approach presumes the output format remains stable. -# Be aware that format changes could invalidate this check. -if [[ $(getopt --version 2> /dev/null) != *"getopt from util-linux"* ]]; then +# Check for GNU getopt by testing for long option support. GNU getopt supports +# the "--test" option and will return exit code 4 while POSIX/BSD getopt does +# not and will return exit code 0. +if getopt --test > /dev/null 2>&1; then cat << 'END_OF_LINE' Please note, this script requires GNU getopt due to its enhanced @@ -144,17 +191,8 @@ while true; do -p | --python-version) PYTHON_VERSION="$2" shift 2 - # Check the Python versions being passed in. - if [ -n "${PYTHON_VERSION+x}" ]; then - if python_versions | grep -E "^${PYTHON_VERSION}$" > /dev/null; then - echo Using Python version "$PYTHON_VERSION" - else - echo Error: Python version "$PYTHON_VERSION" is not installed. - echo Installed Python versions are: - python_versions - exit 1 - fi - fi + # Check the Python version being passed in. + check_python_version "$PYTHON_VERSION" ;; -v | --venv-name) VENV_NAME="$2" @@ -188,15 +226,8 @@ if [ $LIST_VERSIONS -ne 0 ]; then # Read the user's desired Python version. # -r: treat backslashes as literal, -p: display prompt before input. read -r -p "Enter the desired Python version: " PYTHON_VERSION - # Check the Python versions being passed in. - if [ -n "${PYTHON_VERSION+x}" ]; then - if python_versions | grep -E "^${PYTHON_VERSION}$" > /dev/null; then - echo Using Python version "$PYTHON_VERSION" - else - echo Error: Python version "$PYTHON_VERSION" is not installed. - exit 1 - fi - fi + # Check the Python version being passed in. + check_python_version "$PYTHON_VERSION" fi # Remove any lingering local configuration. diff --git a/src/version.txt b/src/version.txt index 3b93d0b..4e379d2 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -__version__ = "0.0.2" +0.0.2 diff --git a/tests/conftest.py b/tests/conftest.py index cb1cac7..428b0d4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,6 +6,16 @@ # Third-Party Libraries import pytest +VERSION_FILE = "src/version.txt" + + +@pytest.fixture(scope="session") +def project_version(): + """Return the version of the project.""" + with open(VERSION_FILE) as f: + project_version = f.read().strip() + return project_version + def pytest_addoption(parser): """Add new commandline options to pytest.""" diff --git a/tests/test_version.py b/tests/test_version.py index b9f8251..bed07f6 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -1,4 +1,3 @@ -#!/usr/bin/env pytest -vs """Version tests for AWS Lambda Python skeleton project.""" # Standard Python Libraries @@ -8,19 +7,14 @@ import pytest GITHUB_RELEASE_TAG = os.getenv("GITHUB_RELEASE_TAG") -VERSION_FILE = "src/version.txt" @pytest.mark.skipif( GITHUB_RELEASE_TAG in [None, ""], reason="this is not a release (GITHUB_RELEASE_TAG not set)", ) -def test_release_version(): +def test_release_version(project_version): """Verify that release tag version agrees with the module version.""" - pkg_vars = {} - with open(VERSION_FILE) as f: - exec(f.read(), pkg_vars) # nosec - project_version = pkg_vars["__version__"] assert ( GITHUB_RELEASE_TAG == f"v{project_version}" ), "GITHUB_RELEASE_TAG does not match the project version"