├── config
└── version.txt
├── requirements.txt
├── requirements-test.txt
├── .github
├── lineage.yml
├── CODEOWNERS
├── dependabot.yml
├── labeler.yml
├── labels.yml
└── workflows
│ ├── label-prs.yml
│ ├── sync-labels.yml
│ ├── dependency-review.yml
│ ├── codeql-analysis.yml
│ └── build.yml
├── requirements-dev.txt
├── .prettierignore
├── tag.sh
├── .gitignore
├── .isort.cfg
├── .bandit.yml
├── .ansible-lint
├── hooks
├── packer_fmt.sh
└── packer_validate.sh
├── .pre-commit-hooks.yaml
├── lib
└── util.sh
├── .flake8
├── .mdl_config.yaml
├── README.md
├── .yamllint
├── bump-version
├── LICENSE
├── CONTRIBUTING.md
├── .pre-commit-config.yaml
└── setup-env
/config/version.txt:
--------------------------------------------------------------------------------
1 | 0.3.1
2 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | setuptools
2 | wheel
3 |
--------------------------------------------------------------------------------
/requirements-test.txt:
--------------------------------------------------------------------------------
1 | --requirement requirements.txt
2 | pre-commit
3 |
--------------------------------------------------------------------------------
/.github/lineage.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: "1"
3 |
4 | lineage:
5 | skeleton:
6 | remote-url: https://github.com/cisagov/skeleton-generic.git
7 |
--------------------------------------------------------------------------------
/requirements-dev.txt:
--------------------------------------------------------------------------------
1 | --requirement requirements-test.txt
2 | ipython
3 | # The bump-version script requires at least version 3 of semver.
4 | semver>=3
5 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Already being linted by pretty-format-json
2 | *.json
3 | # Already being linted by mdl
4 | *.md
5 | # Already being linted by yamllint
6 | *.yaml
7 | *.yml
8 |
--------------------------------------------------------------------------------
/tag.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | version=$(./bump_version.sh show)
8 |
9 | git tag "v$version" && git push --tags
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # This file specifies intentionally untracked files that Git should ignore.
2 | # Files already tracked by Git are not affected.
3 | # See: https://git-scm.com/docs/gitignore
4 |
5 | ## Python ##
6 | __pycache__
7 | .mypy_cache
8 | .python-version
9 |
--------------------------------------------------------------------------------
/.isort.cfg:
--------------------------------------------------------------------------------
1 | [settings]
2 | combine_star=true
3 | force_sort_within_sections=true
4 |
5 | import_heading_stdlib=Standard Python Libraries
6 | import_heading_thirdparty=Third-Party Libraries
7 | import_heading_firstparty=cisagov Libraries
8 |
9 | # Run isort under the black profile to align with our other Python linting
10 | profile=black
11 |
--------------------------------------------------------------------------------
/.bandit.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Configuration file for the Bandit python security scanner
3 | # https://bandit.readthedocs.io/en/latest/config.html
4 |
5 | # Tests are first included by `tests`, and then excluded by `skips`.
6 | # If `tests` is empty, all tests are considered included.
7 |
8 | tests:
9 | # - B101
10 | # - B102
11 |
12 | skips:
13 | # - B101 # skip "assert used" check since assertions are required in pytests
14 |
--------------------------------------------------------------------------------
/.ansible-lint:
--------------------------------------------------------------------------------
1 | ---
2 | # See https://ansible-lint.readthedocs.io/configuring/ for a list of
3 | # the configuration elements that can exist in this file.
4 | enable_list:
5 | # Useful checks that one must opt-into. See here for more details:
6 | # https://ansible-lint.readthedocs.io/rules/
7 | - fcqn-builtins
8 | - no-log-password
9 | - no-same-owner
10 | exclude_paths:
11 | # This exclusion is implicit, unless exclude_paths is defined
12 | - .cache
13 | # Seems wise to ignore this too
14 | - .github
15 | kinds:
16 | # This will force our systemd specific molecule configurations to be treated
17 | # as plain yaml files by ansible-lint. This mirrors the default kind
18 | # configuration in ansible-lint for molecule configurations:
19 | # yaml: "**/molecule/*/{base,molecule}.{yaml,yml}"
20 | - yaml: "**/molecule/*/molecule-{no,with}-systemd.yml"
21 | use_default_rules: true
22 |
--------------------------------------------------------------------------------
/hooks/packer_fmt.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | if [ -z "$(command -v packer)" ]; then
8 | echo "packer is required"
9 | exit 1
10 | fi
11 |
12 | # The version of readlink on macOS does not support long options
13 | SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
14 | readonly SCRIPT_DIR
15 | # shellcheck source=lib/util.sh
16 | source "$SCRIPT_DIR/../lib/util.sh"
17 |
18 | util::parse_cmdline "$@"
19 |
20 | util::get_unique_directory_paths "${FILES[@]}"
21 |
22 | pids=()
23 | for path in "${UNIQUE_PATHS[@]}"; do
24 | # Check each path in parallel
25 | {
26 | packer fmt "${ARGS[@]}" -- "$path"
27 | } &
28 | pids+=("$!")
29 | done
30 |
31 | error=0
32 | exit_code=0
33 | for pid in "${pids[@]}"; do
34 | wait "$pid" || exit_code=$?
35 | if [[ $exit_code -ne 0 ]]; then
36 | error=1
37 | fi
38 | done
39 |
40 | if [[ $error -ne 0 ]]; then
41 | exit 1
42 | fi
43 |
--------------------------------------------------------------------------------
/.pre-commit-hooks.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # Hooks should be listed alphabetically by id.
3 | - description: This hook runs `packer fmt` on appropriate files.
4 | entry: hooks/packer_fmt.sh
5 | files: \.pkr(?:vars)?\.hcl$
6 | id: packer_fmt
7 | language: script
8 | name: Packer Format
9 |
10 | - description: This hook runs `packer validate` on appropriate files.
11 | entry: hooks/packer_validate.sh
12 | files: \.pkr\.hcl$
13 | id: packer_validate
14 | language: script
15 | name: Packer Validate
16 | # This is necessary because Packer's plugin cache is not safe for concurrent access
17 | # per https://github.com/hashicorp/terraform/issues/32915#issuecomment-1485061999. If
18 | # this is not set to true then pre-commit itself will perform some level of
19 | # parallelization across the files to run this hook against. Since we only care about
20 | # unique directory paths it should not impact performance and it will help prevent
21 | # issues arising from concurrent attempts to perform `packer init` on a particular
22 | # directory path.
23 | require_serial: true
24 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Each line is a file pattern followed by one or more owners.
2 |
3 | # These owners will be the default owners for everything in the
4 | # repo. Unless a later match takes precedence, these owners will be
5 | # requested for review when someone opens a pull request.
6 | * @dav3r @felddy @jsf9k @mcdonnnj
7 |
8 | # These folks own any files in the .github directory at the root of
9 | # the repository and any of its subdirectories.
10 | /.github/ @dav3r @felddy @jsf9k @mcdonnnj
11 |
12 | # These folks own all linting configuration files.
13 | /.ansible-lint @dav3r @felddy @jsf9k @mcdonnnj
14 | /.bandit.yml @dav3r @felddy @jsf9k @mcdonnnj
15 | /.flake8 @dav3r @felddy @jsf9k @mcdonnnj
16 | /.isort.cfg @dav3r @felddy @jsf9k @mcdonnnj
17 | /.mdl_config.yaml @dav3r @felddy @jsf9k @mcdonnnj
18 | /.pre-commit-config.yaml @dav3r @felddy @jsf9k @mcdonnnj
19 | /.prettierignore @dav3r @felddy @jsf9k @mcdonnnj
20 | /.yamllint @dav3r @felddy @jsf9k @mcdonnnj
21 | /requirements.txt @dav3r @felddy @jsf9k @mcdonnnj
22 | /requirements-dev.txt @dav3r @felddy @jsf9k @mcdonnnj
23 | /requirements-test.txt @dav3r @felddy @jsf9k @mcdonnnj
24 | /setup-env @dav3r @felddy @jsf9k @mcdonnnj
25 |
--------------------------------------------------------------------------------
/lib/util.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | #######################################
8 | # Process the command line and separate arguments from files
9 | # Globals:
10 | # ARGS
11 | # FILES
12 | #######################################
13 | function util::parse_cmdline() {
14 | # Global variable arrays
15 | ARGS=()
16 | FILES=()
17 |
18 | while (("$#")); do
19 | case "$1" in
20 | -*)
21 | if [ -f "$1" ]; then
22 | FILES+=("$1")
23 | else
24 | ARGS+=("$1")
25 | fi
26 | shift
27 | ;;
28 | *)
29 | FILES+=("$1")
30 | shift
31 | ;;
32 | esac
33 | done
34 | }
35 |
36 | #######################################
37 | # Create a list of unique directory paths from a list of file paths
38 | # Globals:
39 | # UNIQUE_PATHS
40 | #######################################
41 | function util::get_unique_directory_paths() {
42 | # Global variable arrays
43 | UNIQUE_PATHS=()
44 |
45 | local -a paths
46 |
47 | index=0
48 | for file in "$@"; do
49 | paths[index]=$(dirname -- "$file")
50 | ((++index))
51 | done
52 |
53 | UNIQUE_PATHS=()
54 | while IFS='' read -r line; do UNIQUE_PATHS+=("$line"); done < <(printf '%s\n' "${paths[@]}" | sort --unique)
55 | }
56 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 80
3 | # Select (turn on)
4 | # * Complexity violations reported by mccabe (C) -
5 | # http://flake8.pycqa.org/en/latest/user/error-codes.html#error-violation-codes
6 | # * Documentation conventions compliance reported by pydocstyle (D) -
7 | # http://www.pydocstyle.org/en/stable/error_codes.html
8 | # * Default errors and warnings reported by pycodestyle (E and W) -
9 | # https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes
10 | # * Default errors reported by pyflakes (F) -
11 | # http://flake8.pycqa.org/en/latest/glossary.html#term-pyflakes
12 | # * Default warnings reported by flake8-bugbear (B) -
13 | # https://github.com/PyCQA/flake8-bugbear#list-of-warnings
14 | # * The B950 flake8-bugbear opinionated warning -
15 | # https://github.com/PyCQA/flake8-bugbear#opinionated-warnings
16 | select = C,D,E,F,W,B,B950
17 | # Ignore flake8's default warning about maximum line length, which has
18 | # a hard stop at the configured value. Instead we use
19 | # flake8-bugbear's B950, which allows up to 10% overage.
20 | #
21 | # Also ignore flake8's warning about line breaks before binary
22 | # operators. It no longer agrees with PEP8. See, for example, here:
23 | # https://github.com/ambv/black/issues/21. Guido agrees here:
24 | # https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b.
25 | ignore = E501,W503
26 |
--------------------------------------------------------------------------------
/hooks/packer_validate.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | function packer_validate() {
8 | local exit_code=0
9 |
10 | packer init . > /dev/null
11 |
12 | # Allow us to get output if the validation fails
13 | set +o errexit
14 | validate_output=$(packer validate "${ARGS[@]}" . 2>&1)
15 | exit_code=$?
16 | set -o errexit
17 |
18 | if [[ $exit_code -ne 0 ]]; then
19 | echo "Validation failed in $path"
20 | echo -e "$validate_output\n\n"
21 | fi
22 |
23 | return $exit_code
24 | }
25 |
26 | if [ -z "$(command -v packer)" ]; then
27 | echo "packer is required"
28 | exit 1
29 | fi
30 |
31 | # The version of readlink on macOS does not support long options
32 | SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
33 | readonly SCRIPT_DIR
34 | # shellcheck source=lib/util.sh
35 | source "$SCRIPT_DIR/../lib/util.sh"
36 |
37 | util::parse_cmdline "$@"
38 |
39 | util::get_unique_directory_paths "${FILES[@]}"
40 |
41 | pids=()
42 | for path in "${UNIQUE_PATHS[@]}"; do
43 | # Check each path in parallel
44 | {
45 | pushd "$path" > /dev/null
46 | packer_validate
47 | } &
48 | pids+=("$!")
49 | done
50 |
51 | error=0
52 | exit_code=0
53 | for pid in "${pids[@]}"; do
54 | wait "$pid" || exit_code=$?
55 | if [[ $exit_code -ne 0 ]]; then
56 | error=1
57 | fi
58 | done
59 |
60 | if [[ $error -ne 0 ]]; then
61 | exit 1
62 | fi
63 |
--------------------------------------------------------------------------------
/.mdl_config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | # Default state for all rules
4 | default: true
5 |
6 | # MD003/heading-style/header-style - Heading style
7 | MD003:
8 | # Enforce the ATX-closed style of header
9 | style: atx_closed
10 |
11 | # MD004/ul-style - Unordered list style
12 | MD004:
13 | # Enforce dashes for unordered lists
14 | style: dash
15 |
16 | # MD013/line-length - Line length
17 | MD013:
18 | # Do not enforce for code blocks
19 | code_blocks: false
20 | # Do not enforce for tables
21 | tables: false
22 |
23 | # MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the
24 | # same content
25 | MD024:
26 | # Allow headers with the same content as long as they are not in the same
27 | # parent heading
28 | allow_different_nesting: true
29 |
30 | # MD029/ol-prefix - Ordered list item prefix
31 | MD029:
32 | # Enforce the `1.` style for ordered lists
33 | style: one
34 |
35 | # MD033/no-inline-html - Inline HTML
36 | MD033:
37 | # The h1 and img elements are allowed to permit header images
38 | allowed_elements:
39 | - h1
40 | - img
41 |
42 | # MD035/hr-style - Horizontal rule style
43 | MD035:
44 | # Enforce dashes for horizontal rules
45 | style: ---
46 |
47 | # MD046/code-block-style - Code block style
48 | MD046:
49 | # Enforce the fenced style for code blocks
50 | style: fenced
51 |
52 | # MD049/emphasis-style - Emphasis style should be consistent
53 | MD049:
54 | # Enforce asterisks as the style to use for emphasis
55 | style: asterisk
56 |
57 | # MD050/strong-style - Strong style should be consistent
58 | MD050:
59 | # Enforce asterisks as the style to use for strong
60 | style: asterisk
61 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | # Any ignore directives should be uncommented in downstream projects to disable
4 | # Dependabot updates for the given dependency. Downstream projects will get
5 | # these updates when the pull request(s) in the appropriate skeleton are merged
6 | # and Lineage processes these changes.
7 |
8 | updates:
9 | - directory: /
10 | ignore:
11 | # Managed by cisagov/skeleton-generic
12 | - dependency-name: actions/cache
13 | - dependency-name: actions/checkout
14 | - dependency-name: actions/dependency-review-action
15 | - dependency-name: actions/labeler
16 | - dependency-name: actions/setup-go
17 | - dependency-name: actions/setup-python
18 | - dependency-name: cisagov/action-job-preamble
19 | - dependency-name: cisagov/setup-env-github-action
20 | - dependency-name: crazy-max/ghaction-github-labeler
21 | - dependency-name: github/codeql-action
22 | - dependency-name: hashicorp/setup-packer
23 | - dependency-name: hashicorp/setup-terraform
24 | - dependency-name: mxschmitt/action-tmate
25 | labels:
26 | # dependabot default we need to replicate
27 | - dependencies
28 | # This matches our label definition in .github/labels.yml as opposed to
29 | # dependabot's default of `github_actions`.
30 | - github-actions
31 | package-ecosystem: github-actions
32 | schedule:
33 | interval: weekly
34 |
35 | - directory: /
36 | package-ecosystem: pip
37 | schedule:
38 | interval: weekly
39 |
40 | - directory: /
41 | package-ecosystem: terraform
42 | schedule:
43 | interval: weekly
44 | version: 2
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # pre-commit-packer #
2 |
3 | [](https://github.com/cisagov/pre-commit-packer/actions)
4 | [](https://spdx.org/licenses/)
5 | [](https://github.com/cisagov/pre-commit-packer/actions/workflows/codeql-analysis.yml)
6 |
7 | This is a set of [pre-commit](https://pre-commit.com) hooks intended for
8 | projects using [Packer](https://www.packer.io/).
9 |
10 | ## Available Hooks ##
11 |
12 | > [!NOTE]
13 | > You can pass arguments to these hooks through the normal use of the `args` block
14 | > in your pre-commit configuration. These arguments should align with whatever options
15 | > you wish to pass to the underlying `packer` command. However, any arguments that
16 | > take values must be in the form `-argument=value` rather than `-argument value`
17 | > to ensure proper processing.
18 |
19 | ### `packer_fmt` ###
20 |
21 | This hook ensures that any `.pkr.hcl` or `.pkrvars.hcl` files are properly formatted
22 | using the `packer fmt` command. The hook will update files by default, but that
23 | behavior can be overridden by changing the arguments passed to the hook.
24 |
25 | ### `packer_validate` ###
26 |
27 | This hook checks that a Packer configuration is valid by running `packer validate`
28 | against any directory that houses `.pkr.hcl` files.
29 |
30 | > [!NOTE]
31 | > The hook will change to each directory and run `packer init` before running
32 | > `packer validate`.
33 |
34 | ## Usage ##
35 |
36 | ```yaml
37 | repos:
38 | - repo: https://github.com/cisagov/pre-commit-packer
39 | rev: v0.3.1
40 | hooks:
41 | - id: packer_fmt
42 | - id: packer_validate
43 | ```
44 |
45 | ## Contributing ##
46 |
47 | We welcome contributions! Please see [`CONTRIBUTING.md`](CONTRIBUTING.md) for
48 | details.
49 |
50 | ## License ##
51 |
52 | This project is in the worldwide [public domain](LICENSE).
53 |
54 | This project is in the public domain within the United States, and
55 | copyright and related rights in the work worldwide are waived through
56 | the [CC0 1.0 Universal public domain
57 | dedication](https://creativecommons.org/publicdomain/zero/1.0/).
58 |
59 | All contributions to this project will be released under the CC0
60 | dedication. By submitting a pull request, you are agreeing to comply
61 | with this waiver of copyright interest.
62 |
--------------------------------------------------------------------------------
/.github/labeler.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Each entry in this file is a label that will be applied to pull requests
3 | # if there is a match based on the matching rules for the entry. Please see
4 | # the actions/labeler documentation for more information:
5 | # https://github.com/actions/labeler#match-object
6 | #
7 | # Note: Verify that the label you want to use is defined in the
8 | # crazy-max/ghaction-github-labeler configuration file located at
9 | # .github/labels.yml.
10 |
11 | ansible:
12 | - changed-files:
13 | - any-glob-to-any-file:
14 | - "**/ansible/**"
15 | dependencies:
16 | - changed-files:
17 | - any-glob-to-any-file:
18 | # Add any dependency files used.
19 | - .pre-commit-config.yaml
20 | - requirements*.txt
21 | docker:
22 | - changed-files:
23 | - any-glob-to-any-file:
24 | - "**/compose*.yml"
25 | - "**/docker-compose*.yml"
26 | - "**/Dockerfile*"
27 | documentation:
28 | - changed-files:
29 | - any-glob-to-any-file:
30 | - "**/*.md"
31 | github-actions:
32 | - changed-files:
33 | - any-glob-to-any-file:
34 | - .github/workflows/**
35 | javascript:
36 | - changed-files:
37 | - any-glob-to-any-file:
38 | - "**/*.js"
39 | packer:
40 | - changed-files:
41 | - any-glob-to-any-file:
42 | - "**/*.pkr.hcl"
43 | python:
44 | - changed-files:
45 | - any-glob-to-any-file:
46 | - "**/*.py"
47 | shell script:
48 | - changed-files:
49 | - any-glob-to-any-file:
50 | # If this project has any shell scripts that do not end in the ".sh"
51 | # extension, add them below.
52 | - "**/*.sh"
53 | - bump-version
54 | - setup-env
55 | terraform:
56 | - changed-files:
57 | - any-glob-to-any-file:
58 | - "**/*.tf"
59 | test:
60 | - changed-files:
61 | - any-glob-to-any-file:
62 | # Add any test-related files or paths.
63 | - .ansible-lint
64 | - .bandit.yml
65 | - .flake8
66 | - .isort.cfg
67 | - .mdl_config.yaml
68 | - .yamllint
69 | typescript:
70 | - changed-files:
71 | - any-glob-to-any-file:
72 | - "**/*.ts"
73 | upstream update:
74 | - head-branch:
75 | # Any Lineage pull requests should use this branch.
76 | - lineage/skeleton
77 | version bump:
78 | - changed-files:
79 | - any-glob-to-any-file:
80 | # Ensure this matches your version tracking file(s).
81 | - version.txt
82 |
--------------------------------------------------------------------------------
/.yamllint:
--------------------------------------------------------------------------------
1 | ---
2 | extends: default
3 |
4 | rules:
5 | braces:
6 | # Do not allow non-empty flow mappings
7 | forbid: non-empty
8 | # Allow up to one space inside braces. This is required for Ansible compatibility.
9 | max-spaces-inside: 1
10 |
11 | brackets:
12 | # Do not allow non-empty flow sequences
13 | forbid: non-empty
14 |
15 | comments:
16 | # Ensure that inline comments have at least one space before the preceding content.
17 | # This is required for Ansible compatibility.
18 | min-spaces-from-content: 1
19 |
20 | # yamllint does not like it when you comment out different parts of
21 | # dictionaries in a list. You can see
22 | # https://github.com/adrienverge/yamllint/issues/384 for some examples of
23 | # this behavior.
24 | comments-indentation: disable
25 |
26 | indentation:
27 | # Ensure that block sequences inside of a mapping are indented
28 | indent-sequences: true
29 | # Enforce a specific number of spaces
30 | spaces: 2
31 |
32 | # yamllint does not allow inline mappings that exceed the line length by
33 | # default. There are many scenarios where the inline mapping may be a key,
34 | # hash, or other long value that would exceed the line length but cannot
35 | # reasonably be broken across lines.
36 | line-length:
37 | # This rule implies the allow-non-breakable-words rule
38 | allow-non-breakable-inline-mappings: true
39 | # Allows a 10% overage from the default limit of 80
40 | max: 88
41 |
42 | # Using anything other than strings to express octal values can lead to unexpected
43 | # and potentially unsafe behavior. Ansible strongly recommends against such practices
44 | # and these rules are needed for Ansible compatibility. Please see the following for
45 | # more information:
46 | # https://ansible.readthedocs.io/projects/lint/rules/risky-octal/
47 | octal-values:
48 | # Do not allow explicit octal values (those beginning with a leading 0o).
49 | forbid-explicit-octal: true
50 | # Do not allow implicit octal values (those beginning with a leading 0).
51 | forbid-implicit-octal: true
52 |
53 | quoted-strings:
54 | # Allow disallowed quotes (single quotes) for strings that contain allowed quotes
55 | # (double quotes).
56 | allow-quoted-quotes: true
57 | # Apply these rules to keys in mappings as well
58 | check-keys: true
59 | # We prefer double quotes for strings when they are needed
60 | quote-type: double
61 | # Only require quotes when they are necessary for proper processing
62 | required: only-when-needed
63 |
--------------------------------------------------------------------------------
/.github/labels.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Rather than breaking up descriptions into multiline strings we disable that
3 | # specific rule in yamllint for this file.
4 | # yamllint disable rule:line-length
5 | - color: ff5850
6 | description: Pull requests that update Ansible code
7 | name: ansible
8 | - color: eb6420
9 | description: This issue or pull request is awaiting the outcome of another issue or pull request
10 | name: blocked
11 | - color: "000000"
12 | description: This issue or pull request involves changes to existing functionality
13 | name: breaking change
14 | - color: d73a4a
15 | description: This issue or pull request addresses broken functionality
16 | name: bug
17 | - color: 07648d
18 | description: This issue will be advertised on code.gov's Open Tasks page (https://code.gov/open-tasks)
19 | name: code.gov
20 | - color: 0366d6
21 | description: Pull requests that update a dependency file
22 | name: dependencies
23 | - color: 1d63ed
24 | description: Pull requests that update Docker code
25 | name: docker
26 | - color: 5319e7
27 | description: This issue or pull request improves or adds to documentation
28 | name: documentation
29 | - color: cfd3d7
30 | description: This issue or pull request already exists or is covered in another issue or pull request
31 | name: duplicate
32 | - color: b005bc
33 | description: A high-level objective issue encompassing multiple issues instead of a specific unit of work
34 | name: epic
35 | - color: "000000"
36 | description: Pull requests that update GitHub Actions code
37 | name: github-actions
38 | - color: 0e8a16
39 | description: This issue or pull request is well-defined and good for newcomers
40 | name: good first issue
41 | - color: ff7518
42 | description: Pull request that should count toward Hacktoberfest participation
43 | name: hacktoberfest-accepted
44 | - color: a2eeef
45 | description: This issue or pull request will add or improve functionality, maintainability, or ease of use
46 | name: improvement
47 | - color: fef2c0
48 | description: This issue or pull request is not applicable, incorrect, or obsolete
49 | name: invalid
50 | - color: f0db4f
51 | description: Pull requests that update JavaScript code
52 | name: javascript
53 | - color: ce099a
54 | description: This pull request is ready to merge during the next Lineage Kraken release
55 | name: kraken 🐙
56 | - color: a4fc5d
57 | description: This issue or pull request requires further information
58 | name: need info
59 | - color: fcdb45
60 | description: This pull request is awaiting an action or decision to move forward
61 | name: on hold
62 | - color: 02a8ef
63 | description: Pull requests that update Packer code
64 | name: packer
65 | - color: 3776ab
66 | description: Pull requests that update Python code
67 | name: python
68 | - color: ef476c
69 | description: This issue is a request for information or needs discussion
70 | name: question
71 | - color: d73a4a
72 | description: This issue or pull request addresses a security issue
73 | name: security
74 | - color: 4eaa25
75 | description: Pull requests that update shell scripts
76 | name: shell script
77 | - color: 7b42bc
78 | description: Pull requests that update Terraform code
79 | name: terraform
80 | - color: 00008b
81 | description: This issue or pull request adds or otherwise modifies test code
82 | name: test
83 | - color: 2678c5
84 | description: Pull requests that update TypeScript code
85 | name: typescript
86 | - color: 1d76db
87 | description: This issue or pull request pulls in upstream updates
88 | name: upstream update
89 | - color: d4c5f9
90 | description: This issue or pull request increments the version number
91 | name: version bump
92 | - color: ffffff
93 | description: This issue will not be incorporated
94 | name: wontfix
95 |
--------------------------------------------------------------------------------
/.github/workflows/label-prs.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Label pull requests
3 |
4 | on: # yamllint disable-line rule:truthy
5 | pull_request:
6 | types:
7 | - edited
8 | - opened
9 | - synchronize
10 |
11 | # Set a default shell for any run steps. The `-Eueo pipefail` sets errtrace,
12 | # nounset, errexit, and pipefail. The `-x` will print all commands as they are
13 | # run. Please see the GitHub Actions documentation for more information:
14 | # https://docs.github.com/en/actions/using-jobs/setting-default-values-for-jobs
15 | defaults:
16 | run:
17 | shell: bash -Eueo pipefail -x {0}
18 |
19 | jobs:
20 | diagnostics:
21 | name: Run diagnostics
22 | # This job does not need any permissions
23 | permissions: {}
24 | runs-on: ubuntu-latest
25 | steps:
26 | # Note that a duplicate of this step must be added at the top of
27 | # each job.
28 | - name: Apply standard cisagov job preamble
29 | uses: cisagov/action-job-preamble@v1
30 | with:
31 | check_github_status: "true"
32 | # This functionality is poorly implemented and has been
33 | # causing problems due to the MITM implementation hogging or
34 | # leaking memory. As a result we disable it by default. If
35 | # you want to temporarily enable it, simply set
36 | # monitor_permissions equal to "true".
37 | #
38 | # TODO: Re-enable this functionality when practical. See
39 | # cisagov/skeleton-generic#207 for more details.
40 | monitor_permissions: "false"
41 | output_workflow_context: "true"
42 | # Use a variable to specify the permissions monitoring
43 | # configuration. By default this will yield the
44 | # configuration stored in the cisagov organization-level
45 | # variable, but if you want to use a different configuration
46 | # then simply:
47 | # 1. Create a repository-level variable with the name
48 | # ACTIONS_PERMISSIONS_CONFIG.
49 | # 2. Set this new variable's value to the configuration you
50 | # want to use for this repository.
51 | #
52 | # Note in particular that changing the permissions
53 | # monitoring configuration *does not* require you to modify
54 | # this workflow.
55 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
56 | label:
57 | needs:
58 | - diagnostics
59 | permissions:
60 | # Permissions required by actions/labeler
61 | contents: read
62 | pull-requests: write
63 | runs-on: ubuntu-latest
64 | steps:
65 | - name: Apply standard cisagov job preamble
66 | uses: cisagov/action-job-preamble@v1
67 | with:
68 | # This functionality is poorly implemented and has been
69 | # causing problems due to the MITM implementation hogging or
70 | # leaking memory. As a result we disable it by default. If
71 | # you want to temporarily enable it, simply set
72 | # monitor_permissions equal to "true".
73 | #
74 | # TODO: Re-enable this functionality when practical. See
75 | # cisagov/skeleton-generic#207 for more details.
76 | monitor_permissions: "false"
77 | # Use a variable to specify the permissions monitoring
78 | # configuration. By default this will yield the
79 | # configuration stored in the cisagov organization-level
80 | # variable, but if you want to use a different configuration
81 | # then simply:
82 | # 1. Create a repository-level variable with the name
83 | # ACTIONS_PERMISSIONS_CONFIG.
84 | # 2. Set this new variable's value to the configuration you
85 | # want to use for this repository.
86 | #
87 | # Note in particular that changing the permissions
88 | # monitoring configuration *does not* require you to modify
89 | # this workflow.
90 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
91 | - name: Apply suitable labels to a pull request
92 | uses: actions/labeler@v6
93 |
--------------------------------------------------------------------------------
/.github/workflows/sync-labels.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: sync-labels
3 |
4 | on: # yamllint disable-line rule:truthy
5 | push:
6 | paths:
7 | - .github/labels.yml
8 | - .github/workflows/sync-labels.yml
9 | workflow_dispatch:
10 |
11 | permissions:
12 | contents: read
13 |
14 | jobs:
15 | diagnostics:
16 | name: Run diagnostics
17 | # This job does not need any permissions
18 | permissions: {}
19 | runs-on: ubuntu-latest
20 | steps:
21 | # Note that a duplicate of this step must be added at the top of
22 | # each job.
23 | - name: Apply standard cisagov job preamble
24 | uses: cisagov/action-job-preamble@v1
25 | with:
26 | check_github_status: "true"
27 | # This functionality is poorly implemented and has been
28 | # causing problems due to the MITM implementation hogging or
29 | # leaking memory. As a result we disable it by default. If
30 | # you want to temporarily enable it, simply set
31 | # monitor_permissions equal to "true".
32 | #
33 | # TODO: Re-enable this functionality when practical. See
34 | # cisagov/skeleton-generic#207 for more details.
35 | monitor_permissions: "false"
36 | output_workflow_context: "true"
37 | # Use a variable to specify the permissions monitoring
38 | # configuration. By default this will yield the
39 | # configuration stored in the cisagov organization-level
40 | # variable, but if you want to use a different configuration
41 | # then simply:
42 | # 1. Create a repository-level variable with the name
43 | # ACTIONS_PERMISSIONS_CONFIG.
44 | # 2. Set this new variable's value to the configuration you
45 | # want to use for this repository.
46 | #
47 | # Note in particular that changing the permissions
48 | # monitoring configuration *does not* require you to modify
49 | # this workflow.
50 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
51 | labeler:
52 | needs:
53 | - diagnostics
54 | permissions:
55 | # actions/checkout needs this to fetch code
56 | contents: read
57 | # crazy-max/ghaction-github-labeler needs this to manage repository labels
58 | issues: write
59 | runs-on: ubuntu-latest
60 | steps:
61 | - name: Apply standard cisagov job preamble
62 | uses: cisagov/action-job-preamble@v1
63 | with:
64 | # This functionality is poorly implemented and has been
65 | # causing problems due to the MITM implementation hogging or
66 | # leaking memory. As a result we disable it by default. If
67 | # you want to temporarily enable it, simply set
68 | # monitor_permissions equal to "true".
69 | #
70 | # TODO: Re-enable this functionality when practical. See
71 | # cisagov/skeleton-generic#207 for more details.
72 | monitor_permissions: "false"
73 | # Use a variable to specify the permissions monitoring
74 | # configuration. By default this will yield the
75 | # configuration stored in the cisagov organization-level
76 | # variable, but if you want to use a different configuration
77 | # then simply:
78 | # 1. Create a repository-level variable with the name
79 | # ACTIONS_PERMISSIONS_CONFIG.
80 | # 2. Set this new variable's value to the configuration you
81 | # want to use for this repository.
82 | #
83 | # Note in particular that changing the permissions
84 | # monitoring configuration *does not* require you to modify
85 | # this workflow.
86 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
87 | - uses: actions/checkout@v6
88 | - name: Sync repository labels
89 | if: success()
90 | uses: crazy-max/ghaction-github-labeler@v5
91 | with:
92 | # This is a hideous ternary equivalent so we only do a dry run unless
93 | # this workflow is triggered by the develop branch.
94 | dry-run: ${{ github.ref_name == 'develop' && 'false' || 'true' }}
95 |
--------------------------------------------------------------------------------
/.github/workflows/dependency-review.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Dependency review
3 |
4 | on: # yamllint disable-line rule:truthy
5 | merge_group:
6 | types:
7 | - checks_requested
8 | pull_request:
9 |
10 | # Set a default shell for any run steps. The `-Eueo pipefail` sets errtrace,
11 | # nounset, errexit, and pipefail. The `-x` will print all commands as they are
12 | # run. Please see the GitHub Actions documentation for more information:
13 | # https://docs.github.com/en/actions/using-jobs/setting-default-values-for-jobs
14 | defaults:
15 | run:
16 | shell: bash -Eueo pipefail -x {0}
17 |
18 | jobs:
19 | diagnostics:
20 | name: Run diagnostics
21 | # This job does not need any permissions
22 | permissions: {}
23 | runs-on: ubuntu-latest
24 | steps:
25 | # Note that a duplicate of this step must be added at the top of
26 | # each job.
27 | - name: Apply standard cisagov job preamble
28 | uses: cisagov/action-job-preamble@v1
29 | with:
30 | check_github_status: "true"
31 | # This functionality is poorly implemented and has been
32 | # causing problems due to the MITM implementation hogging or
33 | # leaking memory. As a result we disable it by default. If
34 | # you want to temporarily enable it, simply set
35 | # monitor_permissions equal to "true".
36 | #
37 | # TODO: Re-enable this functionality when practical. See
38 | # cisagov/skeleton-generic#207 for more details.
39 | monitor_permissions: "false"
40 | output_workflow_context: "true"
41 | # Use a variable to specify the permissions monitoring
42 | # configuration. By default this will yield the
43 | # configuration stored in the cisagov organization-level
44 | # variable, but if you want to use a different configuration
45 | # then simply:
46 | # 1. Create a repository-level variable with the name
47 | # ACTIONS_PERMISSIONS_CONFIG.
48 | # 2. Set this new variable's value to the configuration you
49 | # want to use for this repository.
50 | #
51 | # Note in particular that changing the permissions
52 | # monitoring configuration *does not* require you to modify
53 | # this workflow.
54 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
55 | dependency-review:
56 | name: Dependency review
57 | needs:
58 | - diagnostics
59 | permissions:
60 | # actions/checkout needs this to fetch code
61 | contents: read
62 | runs-on: ubuntu-latest
63 | steps:
64 | - name: Apply standard cisagov job preamble
65 | uses: cisagov/action-job-preamble@v1
66 | with:
67 | # This functionality is poorly implemented and has been
68 | # causing problems due to the MITM implementation hogging or
69 | # leaking memory. As a result we disable it by default. If
70 | # you want to temporarily enable it, simply set
71 | # monitor_permissions equal to "true".
72 | #
73 | # TODO: Re-enable this functionality when practical. See
74 | # cisagov/skeleton-generic#207 for more details.
75 | monitor_permissions: "false"
76 | # Use a variable to specify the permissions monitoring
77 | # configuration. By default this will yield the
78 | # configuration stored in the cisagov organization-level
79 | # variable, but if you want to use a different configuration
80 | # then simply:
81 | # 1. Create a repository-level variable with the name
82 | # ACTIONS_PERMISSIONS_CONFIG.
83 | # 2. Set this new variable's value to the configuration you
84 | # want to use for this repository.
85 | #
86 | # Note in particular that changing the permissions
87 | # monitoring configuration *does not* require you to modify
88 | # this workflow.
89 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
90 | - id: checkout-repo
91 | name: Checkout the repository
92 | uses: actions/checkout@v6
93 | - id: dependency-review
94 | name: Review dependency changes for vulnerabilities and license changes
95 | uses: actions/dependency-review-action@v4
96 |
--------------------------------------------------------------------------------
/bump-version:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # bump-version [--push] [--label LABEL] (major | minor | patch | prerelease | build | finalize | show)
4 | # bump-version --list-files
5 |
6 | set -o nounset
7 | set -o errexit
8 | set -o pipefail
9 |
10 | # Stores the canonical version for the project.
11 | VERSION_FILE=config/version.txt
12 | # Files that should be updated with the new version.
13 | VERSION_FILES=("$VERSION_FILE" README.md)
14 |
15 | USAGE=$(
16 | cat << END_OF_LINE
17 | Update the version of the project.
18 |
19 | Usage:
20 | ${0##*/} [--push] [--label LABEL] (major | minor | patch | prerelease | build | finalize | show)
21 | ${0##*/} --list-files
22 | ${0##*/} (-h | --help)
23 |
24 | Options:
25 | -h | --help Show this message.
26 | --push Perform a \`git push\` after updating the version.
27 | --label LABEL Specify the label to use when updating the build or prerelease version.
28 | --list-files List the files that will be updated when the version is bumped.
29 | END_OF_LINE
30 | )
31 |
32 | old_version=$(< "$VERSION_FILE")
33 | # Comment out periods so they are interpreted as periods and don't
34 | # just match any character
35 | old_version_regex=${old_version//\./\\\.}
36 | new_version="$old_version"
37 |
38 | bump_part=""
39 | label=""
40 | commit_prefix="Bump"
41 | with_push=false
42 | commands_with_label=("build" "prerelease")
43 | commands_with_prerelease=("major" "minor" "patch")
44 | with_prerelease=false
45 |
46 | #######################################
47 | # Display an error message, the help information, and exit with a non-zero status.
48 | # Arguments:
49 | # Error message.
50 | #######################################
51 | function invalid_option() {
52 | echo "$1"
53 | echo "$USAGE"
54 | exit 1
55 | }
56 |
57 | #######################################
58 | # Bump the version using the provided command.
59 | # Arguments:
60 | # The version to bump.
61 | # The command to bump the version.
62 | # Returns:
63 | # The new version.
64 | #######################################
65 | function bump_version() {
66 | local temp_version
67 | temp_version=$(python -c "import semver; print(semver.parse_version_info('$1').${2})")
68 | echo "$temp_version"
69 | }
70 |
71 | if [ $# -eq 0 ]; then
72 | echo "$USAGE"
73 | exit 1
74 | else
75 | while [ $# -gt 0 ]; do
76 | case $1 in
77 | --push)
78 | if [ "$with_push" = true ]; then
79 | invalid_option "Push has already been set."
80 | fi
81 |
82 | with_push=true
83 | shift
84 | ;;
85 | --label)
86 | if [ -n "$label" ]; then
87 | invalid_option "Label has already been set."
88 | fi
89 |
90 | label="$2"
91 | shift 2
92 | ;;
93 | build | finalize | major | minor | patch)
94 | if [ -n "$bump_part" ]; then
95 | invalid_option "Only one version part should be bumped at a time."
96 | fi
97 |
98 | bump_part="$1"
99 | shift
100 | ;;
101 | prerelease)
102 | with_prerelease=true
103 | shift
104 | ;;
105 | show)
106 | echo "$old_version"
107 | exit 0
108 | ;;
109 | -h | --help)
110 | echo "$USAGE"
111 | exit 0
112 | ;;
113 | --list-files)
114 | printf '%s\n' "${VERSION_FILES[@]}"
115 | exit 0
116 | ;;
117 | *)
118 | invalid_option "Invalid option: $1"
119 | ;;
120 | esac
121 | done
122 | fi
123 |
124 | if [ -n "$label" ] && [ "$with_prerelease" = false ] && [[ ! " ${commands_with_label[*]} " =~ [[:space:]]${bump_part}[[:space:]] ]]; then
125 | invalid_option "Setting the label is only allowed for the following commands: ${commands_with_label[*]}"
126 | fi
127 |
128 | if [ "$with_prerelease" = true ] && [ -n "$bump_part" ] && [[ ! " ${commands_with_prerelease[*]} " =~ [[:space:]]${bump_part}[[:space:]] ]]; then
129 | invalid_option "Changing the prerelease is only allowed in conjunction with the following commands: ${commands_with_prerelease[*]}"
130 | fi
131 |
132 | label_option=""
133 | if [ -n "$label" ]; then
134 | label_option="token='$label'"
135 | fi
136 |
137 | if [ -n "$bump_part" ]; then
138 | if [ "$bump_part" = "finalize" ]; then
139 | commit_prefix="Finalize"
140 | bump_command="finalize_version()"
141 | elif [ "$bump_part" = "build" ]; then
142 | bump_command="bump_${bump_part}($label_option)"
143 | else
144 | bump_command="bump_${bump_part}()"
145 | fi
146 | new_version=$(bump_version "$old_version" "$bump_command")
147 | echo Changing version from "$old_version" to "$new_version"
148 | fi
149 |
150 | if [ "$with_prerelease" = true ]; then
151 | bump_command="bump_prerelease($label_option)"
152 | temp_version=$(bump_version "$new_version" "$bump_command")
153 | echo Changing version from "$new_version" to "$temp_version"
154 | new_version="$temp_version"
155 | fi
156 |
157 | tmp_file=/tmp/version.$$
158 | for version_file in "${VERSION_FILES[@]}"; do
159 | if [ ! -f "$version_file" ]; then
160 | echo Missing expected file: "$version_file"
161 | exit 1
162 | fi
163 | sed "s/$old_version_regex/$new_version/" "$version_file" > $tmp_file
164 | mv $tmp_file "$version_file"
165 | done
166 |
167 | git add "${VERSION_FILES[@]}"
168 | git commit --message "$commit_prefix version from $old_version to $new_version"
169 |
170 | if [ "$with_push" = true ]; then
171 | git push
172 | fi
173 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # For most projects, this workflow file will not need changing; you simply need
3 | # to commit it to your repository.
4 | #
5 | # You may wish to alter this file to override the set of languages analyzed,
6 | # or to provide custom queries or build logic.
7 | name: CodeQL
8 |
9 | # The use of on here as a key is part of the GitHub actions syntax.
10 | # yamllint disable-line rule:truthy
11 | on:
12 | merge_group:
13 | types:
14 | - checks_requested
15 | pull_request:
16 | # The branches here must be a subset of the ones in the push key
17 | branches:
18 | - develop
19 | push:
20 | # Dependabot-triggered push events have read-only access, but uploading code
21 | # scanning requires write access.
22 | branches-ignore:
23 | - dependabot/**
24 | schedule:
25 | - cron: 0 2 * * 6
26 |
27 | jobs:
28 | diagnostics:
29 | name: Run diagnostics
30 | # This job does not need any permissions
31 | permissions: {}
32 | runs-on: ubuntu-latest
33 | steps:
34 | # Note that a duplicate of this step must be added at the top of
35 | # each job.
36 | - name: Apply standard cisagov job preamble
37 | uses: cisagov/action-job-preamble@v1
38 | with:
39 | check_github_status: "true"
40 | # This functionality is poorly implemented and has been
41 | # causing problems due to the MITM implementation hogging or
42 | # leaking memory. As a result we disable it by default. If
43 | # you want to temporarily enable it, simply set
44 | # monitor_permissions equal to "true".
45 | #
46 | # TODO: Re-enable this functionality when practical. See
47 | # cisagov/skeleton-generic#207 for more details.
48 | monitor_permissions: "false"
49 | output_workflow_context: "true"
50 | # Use a variable to specify the permissions monitoring
51 | # configuration. By default this will yield the
52 | # configuration stored in the cisagov organization-level
53 | # variable, but if you want to use a different configuration
54 | # then simply:
55 | # 1. Create a repository-level variable with the name
56 | # ACTIONS_PERMISSIONS_CONFIG.
57 | # 2. Set this new variable's value to the configuration you
58 | # want to use for this repository.
59 | #
60 | # Note in particular that changing the permissions
61 | # monitoring configuration *does not* require you to modify
62 | # this workflow.
63 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
64 | analyze:
65 | name: Analyze
66 | needs:
67 | - diagnostics
68 | runs-on: ubuntu-latest
69 | permissions:
70 | # actions/checkout needs this to fetch code
71 | contents: read
72 | # required for all workflows
73 | security-events: write
74 | strategy:
75 | fail-fast: false
76 | matrix:
77 | # Override automatic language detection by changing the below
78 | # list
79 | #
80 | # Supported options are actions, c-cpp, csharp, go,
81 | # java-kotlin, javascript-typescript, python, ruby, and swift.
82 | language:
83 | - actions
84 | # Learn more...
85 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
86 |
87 | steps:
88 | - name: Apply standard cisagov job preamble
89 | uses: cisagov/action-job-preamble@v1
90 | with:
91 | # This functionality is poorly implemented and has been
92 | # causing problems due to the MITM implementation hogging or
93 | # leaking memory. As a result we disable it by default. If
94 | # you want to temporarily enable it, simply set
95 | # monitor_permissions equal to "true".
96 | #
97 | # TODO: Re-enable this functionality when practical. See
98 | # cisagov/skeleton-generic#207 for more details.
99 | monitor_permissions: "false"
100 | # Use a variable to specify the permissions monitoring
101 | # configuration. By default this will yield the
102 | # configuration stored in the cisagov organization-level
103 | # variable, but if you want to use a different configuration
104 | # then simply:
105 | # 1. Create a repository-level variable with the name
106 | # ACTIONS_PERMISSIONS_CONFIG.
107 | # 2. Set this new variable's value to the configuration you
108 | # want to use for this repository.
109 | #
110 | # Note in particular that changing the permissions
111 | # monitoring configuration *does not* require you to modify
112 | # this workflow.
113 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
114 |
115 | - name: Checkout repository
116 | uses: actions/checkout@v6
117 |
118 | # Initializes the CodeQL tools for scanning.
119 | - name: Initialize CodeQL
120 | uses: github/codeql-action/init@v4
121 | with:
122 | languages: ${{ matrix.language }}
123 |
124 | # Autobuild attempts to build any compiled languages (C/C++, C#, or
125 | # Java). If this step fails, then you should remove it and run the build
126 | # manually (see below).
127 | - name: Autobuild
128 | uses: github/codeql-action/autobuild@v4
129 |
130 | # ℹ️ Command-line programs to run using the OS shell.
131 | # 📚 https://git.io/JvXDl
132 |
133 | # ✏️ If the Autobuild fails above, remove it and uncomment the following
134 | # three lines and modify them (or add more) to build your code if your
135 | # project uses a compiled language
136 |
137 | # - run: |
138 | # make bootstrap
139 | # make release
140 |
141 | - name: Perform CodeQL Analysis
142 | uses: github/codeql-action/analyze@v4
143 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
117 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Welcome #
2 |
3 | We're so glad you're thinking about contributing to this open source
4 | project! If you're unsure or afraid of anything, just ask or submit
5 | the issue or pull request anyway. The worst that can happen is that
6 | you'll be politely asked to change something. We appreciate any sort
7 | of contribution, and don't want a wall of rules to get in the way of
8 | that.
9 |
10 | Before contributing, we encourage you to read our CONTRIBUTING policy
11 | (you are here), our [LICENSE](LICENSE), and our [README](README.md),
12 | all of which should be in this repository.
13 |
14 | ## Issues ##
15 |
16 | If you want to report a bug or request a new feature, the most direct
17 | method is to [create an
18 | issue](https://github.com/cisagov/pre-commit-packer/issues) in this
19 | repository. We recommend that you first search through existing
20 | issues (both open and closed) to check if your particular issue has
21 | already been reported. If it has then you might want to add a comment
22 | to the existing issue. If it hasn't then feel free to create a new
23 | one.
24 |
25 | ## Pull requests ##
26 |
27 | If you choose to [submit a pull
28 | request](https://github.com/cisagov/pre-commit-packer/pulls), you will
29 | notice that our continuous integration (CI) system runs a fairly
30 | extensive set of linters and syntax checkers. Your pull request may
31 | fail these checks, and that's OK. If you want you can stop there and
32 | wait for us to make the necessary corrections to ensure your code
33 | passes the CI checks.
34 |
35 | If you want to make the changes yourself, or if you want to become a
36 | regular contributor, then you will want to set up
37 | [pre-commit](https://pre-commit.com/) on your local machine. Once you
38 | do that, the CI checks will run locally before you even write your
39 | commit message. This speeds up your development cycle considerably.
40 |
41 | ### Setting up pre-commit ###
42 |
43 | There are a few ways to do this, but we prefer to use
44 | [`pyenv`](https://github.com/pyenv/pyenv) and
45 | [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv) to
46 | create and manage a Python virtual environment specific to this
47 | project.
48 |
49 | We recommend using the `setup-env` script located in this repository,
50 | as it automates the entire environment configuration process. The
51 | dependencies required to run this script are
52 | [GNU `getopt`](https://github.com/util-linux/util-linux/blob/master/misc-utils/getopt.1.adoc),
53 | [`pyenv`](https://github.com/pyenv/pyenv), and [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv).
54 | If these tools are already configured on your system, you can simply run the
55 | following command:
56 |
57 | ```console
58 | ./setup-env
59 | ```
60 |
61 | Otherwise, follow the steps below to manually configure your
62 | environment.
63 |
64 | #### Installing and using GNU `getopt`, `pyenv`, and `pyenv-virtualenv` ####
65 |
66 | On macOS, we recommend installing [brew](https://brew.sh/). Then
67 | installation is as simple as `brew install gnu-getopt pyenv pyenv-virtualenv` and
68 | adding this to your profile:
69 |
70 | ```bash
71 | # GNU getopt must be explicitly added to the path since it is
72 | # keg-only (https://docs.brew.sh/FAQ#what-does-keg-only-mean)
73 | export PATH="$(brew --prefix)/opt/gnu-getopt/bin:$PATH"
74 |
75 | # Setup pyenv
76 | export PYENV_ROOT="$HOME/.pyenv"
77 | export PATH="$PYENV_ROOT/bin:$PATH"
78 | eval "$(pyenv init --path)"
79 | eval "$(pyenv init -)"
80 | eval "$(pyenv virtualenv-init -)"
81 | ```
82 |
83 | For Linux, Windows Subsystem for Linux (WSL), or macOS (if you
84 | don't want to use `brew`) you can use
85 | [pyenv/pyenv-installer](https://github.com/pyenv/pyenv-installer) to
86 | install the necessary tools. Before running this ensure that you have
87 | installed the prerequisites for your platform according to the
88 | [`pyenv` wiki
89 | page](https://github.com/pyenv/pyenv/wiki/common-build-problems).
90 | GNU `getopt` is included in most Linux distributions as part of the
91 | [`util-linux`](https://github.com/util-linux/util-linux) package.
92 |
93 | On WSL you should treat your platform as whatever Linux distribution
94 | you've chosen to install.
95 |
96 | Once you have installed `pyenv` you will need to add the following
97 | lines to your `.bash_profile` (or `.profile`):
98 |
99 | ```bash
100 | export PYENV_ROOT="$HOME/.pyenv"
101 | export PATH="$PYENV_ROOT/bin:$PATH"
102 | eval "$(pyenv init --path)"
103 | ```
104 |
105 | and then add the following lines to your `.bashrc`:
106 |
107 | ```bash
108 | eval "$(pyenv init -)"
109 | eval "$(pyenv virtualenv-init -)"
110 | ```
111 |
112 | If you want more information about setting up `pyenv` once installed, please run
113 |
114 | ```console
115 | pyenv init
116 | ```
117 |
118 | and
119 |
120 | ```console
121 | pyenv virtualenv-init
122 | ```
123 |
124 | for the current configuration instructions.
125 |
126 | If you are using a shell other than `bash` you should follow the
127 | instructions that the `pyenv-installer` script outputs.
128 |
129 | You will need to reload your shell for these changes to take effect so
130 | you can begin to use `pyenv`.
131 |
132 | For a list of Python versions that are already installed and ready to
133 | use with `pyenv`, use the command `pyenv versions`. To see a list of
134 | the Python versions available to be installed and used with `pyenv`
135 | use the command `pyenv install --list`. You can read more about
136 | the [many things that `pyenv` can do](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md).
137 | See the [usage information](https://github.com/pyenv/pyenv-virtualenv#usage)
138 | for the additional capabilities that pyenv-virtualenv adds to the `pyenv`
139 | command.
140 |
141 | #### Creating the Python virtual environment ####
142 |
143 | Once `pyenv` and `pyenv-virtualenv` are installed on your system, you
144 | can create and configure the Python virtual environment with these
145 | commands:
146 |
147 | ```console
148 | cd pre-commit-packer
149 | pyenv virtualenv pre-commit-packer
150 | pyenv local pre-commit-packer
151 | pip install --requirement requirements-dev.txt
152 | ```
153 |
154 | #### Installing the pre-commit hook ####
155 |
156 | Now setting up pre-commit is as simple as:
157 |
158 | ```console
159 | pre-commit install
160 | ```
161 |
162 | At this point the pre-commit checks will run against any files that
163 | you attempt to commit. If you want to run the checks against the
164 | entire repo, just execute `pre-commit run --all-files`.
165 |
166 | ## Public domain ##
167 |
168 | This project is in the public domain within the United States, and
169 | copyright and related rights in the work worldwide are waived through
170 | the [CC0 1.0 Universal public domain
171 | dedication](https://creativecommons.org/publicdomain/zero/1.0/).
172 |
173 | All contributions to this project will be released under the CC0
174 | dedication. By submitting a pull request, you are agreeing to comply
175 | with this waiver of copyright interest.
176 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | ci:
3 | # Do not commit changes from running pre-commit for pull requests.
4 | autofix_prs: false
5 | # Autoupdate hooks weekly (this is the default).
6 | autoupdate_schedule: weekly
7 |
8 | default_language_version:
9 | # force all unspecified python hooks to run python3
10 | python: python3
11 |
12 | repos:
13 | # Check the pre-commit configuration
14 | - repo: meta
15 | hooks:
16 | - id: check-useless-excludes
17 |
18 | - repo: https://github.com/pre-commit/pre-commit-hooks
19 | rev: v6.0.0
20 | hooks:
21 | - id: check-case-conflict
22 | - id: check-executables-have-shebangs
23 | - id: check-json
24 | - id: check-merge-conflict
25 | - id: check-shebang-scripts-are-executable
26 | - id: check-symlinks
27 | - id: check-toml
28 | - id: check-vcs-permalinks
29 | - id: check-xml
30 | - id: debug-statements
31 | - id: destroyed-symlinks
32 | - id: detect-aws-credentials
33 | args:
34 | - --allow-missing-credentials
35 | - id: detect-private-key
36 | - id: end-of-file-fixer
37 | - id: mixed-line-ending
38 | args:
39 | - --fix=lf
40 | - id: pretty-format-json
41 | args:
42 | - --autofix
43 | - id: requirements-txt-fixer
44 | - id: trailing-whitespace
45 |
46 | # Text file hooks
47 | - repo: https://github.com/igorshubovych/markdownlint-cli
48 | rev: v0.45.0
49 | hooks:
50 | - id: markdownlint
51 | args:
52 | - --config=.mdl_config.yaml
53 | - repo: https://github.com/rbubley/mirrors-prettier
54 | rev: v3.6.2
55 | hooks:
56 | - id: prettier
57 | - repo: https://github.com/adrienverge/yamllint
58 | rev: v1.37.1
59 | hooks:
60 | - id: yamllint
61 | args:
62 | - --strict
63 |
64 | # GitHub Actions hooks
65 | - repo: https://github.com/python-jsonschema/check-jsonschema
66 | rev: 0.35.0
67 | hooks:
68 | - id: check-github-actions
69 | - id: check-github-workflows
70 |
71 | # pre-commit hooks
72 | - repo: https://github.com/pre-commit/pre-commit
73 | rev: v4.4.0
74 | hooks:
75 | - id: validate_manifest
76 |
77 | # Go hooks
78 | - repo: https://github.com/TekWizely/pre-commit-golang
79 | rev: v1.0.0-rc.4
80 | hooks:
81 | # Go Build
82 | - id: go-build-repo-mod
83 | # Style Checkers
84 | - id: go-critic
85 | # goimports
86 | - id: go-imports-repo
87 | args:
88 | # Write changes to files
89 | - -w
90 | # Go Mod Tidy
91 | - id: go-mod-tidy-repo
92 | # GoSec
93 | - id: go-sec-repo-mod
94 | # StaticCheck
95 | - id: go-staticcheck-repo-mod
96 | # Go Test
97 | - id: go-test-repo-mod
98 | # Go Vet
99 | - id: go-vet-repo-mod
100 | # Nix hooks
101 | - repo: https://github.com/nix-community/nixpkgs-fmt
102 | rev: v1.3.0
103 | hooks:
104 | - id: nixpkgs-fmt
105 |
106 | # Shell script hooks
107 | - repo: https://github.com/scop/pre-commit-shfmt
108 | rev: v3.12.0-2
109 | hooks:
110 | - id: shfmt
111 | args:
112 | # List files that will be formatted
113 | - --list
114 | # Write result to file instead of stdout
115 | - --write
116 | # Indent by two spaces
117 | - --indent
118 | - "2"
119 | # Binary operators may start a line
120 | - --binary-next-line
121 | # Switch cases are indented
122 | - --case-indent
123 | # Redirect operators are followed by a space
124 | - --space-redirects
125 | - repo: https://github.com/shellcheck-py/shellcheck-py
126 | rev: v0.11.0.1
127 | hooks:
128 | - id: shellcheck
129 |
130 | # Python hooks
131 | - repo: https://github.com/PyCQA/bandit
132 | rev: 1.9.1
133 | hooks:
134 | - id: bandit
135 | args:
136 | - --config=.bandit.yml
137 | - repo: https://github.com/psf/black-pre-commit-mirror
138 | rev: 25.11.0
139 | hooks:
140 | - id: black
141 | - repo: https://github.com/PyCQA/flake8
142 | rev: 7.3.0
143 | hooks:
144 | - id: flake8
145 | additional_dependencies:
146 | - flake8-docstrings==1.7.0
147 | - repo: https://github.com/PyCQA/isort
148 | rev: 7.0.0
149 | hooks:
150 | - id: isort
151 | - repo: https://github.com/pre-commit/mirrors-mypy
152 | rev: v1.18.2
153 | hooks:
154 | - id: mypy
155 | - repo: https://github.com/pypa/pip-audit
156 | rev: v2.9.0
157 | hooks:
158 | - id: pip-audit
159 | args:
160 | # Add any pip requirements files to scan
161 | - --requirement
162 | - requirements-dev.txt
163 | - --requirement
164 | - requirements-test.txt
165 | - --requirement
166 | - requirements.txt
167 | - repo: https://github.com/asottile/pyupgrade
168 | rev: v3.21.1
169 | hooks:
170 | - id: pyupgrade
171 | args:
172 | # Python 3.10 is currently the oldest non-EOL version of
173 | # Python, so we want to apply all rules that apply to this
174 | # version or later. See here for more details:
175 | # https://www.gyford.com/phil/writing/2025/08/26/how-to-use-pyupgrade/
176 | - --py310-plus
177 |
178 | # Ansible hooks
179 | - repo: https://github.com/ansible/ansible-lint
180 | rev: v25.11.1
181 | hooks:
182 | - id: ansible-lint
183 | additional_dependencies:
184 | # On its own ansible-lint does not pull in ansible, only
185 | # ansible-core. Therefore, if an Ansible module lives in
186 | # ansible instead of ansible-core, the linter will complain
187 | # that the module is unknown. In these cases it is
188 | # necessary to add the ansible package itself as an
189 | # additional dependency, with the same pinning as is done in
190 | # requirements-test.txt of cisagov/skeleton-ansible-role.
191 | #
192 | # Version 10 is required because the pip-audit pre-commit
193 | # hook identifies a vulnerability in ansible-core 2.16.13,
194 | # but all versions of ansible 9 have a dependency on
195 | # ~=2.16.X.
196 | # - ansible>=10,<11
197 | # ansible-core<2.17.7 suffers from GHSA-99w6-3xph-cx78.
198 | #
199 | # Note that any changes made to this dependency must also be
200 | # made in requirements.txt in cisagov/skeleton-packer and
201 | # requirements-test.txt in cisagov/skeleton-ansible-role.
202 | - ansible-core>=2.17.7
203 |
204 | # Terraform hooks
205 | - repo: https://github.com/antonbabenko/pre-commit-terraform
206 | rev: v1.103.0
207 | hooks:
208 | - id: terraform_fmt
209 | - id: terraform_validate
210 |
211 | # Docker hooks
212 | - repo: https://github.com/IamTheFij/docker-pre-commit
213 | rev: v3.0.1
214 | hooks:
215 | - id: docker-compose-check
216 |
217 | # Packer hooks
218 | - repo: https://github.com/cisagov/pre-commit-packer
219 | rev: v0.3.1
220 | hooks:
221 | - id: packer_fmt
222 | - id: packer_validate
223 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: build
3 |
4 | on: # yamllint disable-line rule:truthy
5 | merge_group:
6 | types:
7 | - checks_requested
8 | pull_request:
9 | push:
10 | repository_dispatch:
11 | types:
12 | - apb
13 |
14 | # Set a default shell for any run steps. The `-Eueo pipefail` sets errtrace,
15 | # nounset, errexit, and pipefail. The `-x` will print all commands as they are
16 | # run. Please see the GitHub Actions documentation for more information:
17 | # https://docs.github.com/en/actions/using-jobs/setting-default-values-for-jobs
18 | defaults:
19 | run:
20 | shell: bash -Eueo pipefail -x {0}
21 |
22 | env:
23 | PIP_CACHE_DIR: ~/.cache/pip
24 | PRE_COMMIT_CACHE_DIR: ~/.cache/pre-commit
25 | RUN_TMATE: ${{ secrets.RUN_TMATE }}
26 | TERRAFORM_DOCS_REPO_BRANCH_NAME: improvement/support_atx_closed_markdown_headers
27 | TERRAFORM_DOCS_REPO_DEPTH: 1
28 | TERRAFORM_DOCS_REPO_URL: https://github.com/mcdonnnj/terraform-docs.git
29 |
30 | jobs:
31 | diagnostics:
32 | name: Run diagnostics
33 | # This job does not need any permissions
34 | permissions: {}
35 | runs-on: ubuntu-latest
36 | steps:
37 | # Note that a duplicate of this step must be added at the top of
38 | # each job.
39 | - name: Apply standard cisagov job preamble
40 | uses: cisagov/action-job-preamble@v1
41 | with:
42 | check_github_status: "true"
43 | # This functionality is poorly implemented and has been
44 | # causing problems due to the MITM implementation hogging or
45 | # leaking memory. As a result we disable it by default. If
46 | # you want to temporarily enable it, simply set
47 | # monitor_permissions equal to "true".
48 | #
49 | # TODO: Re-enable this functionality when practical. See
50 | # cisagov/skeleton-generic#207 for more details.
51 | monitor_permissions: "false"
52 | output_workflow_context: "true"
53 | # Use a variable to specify the permissions monitoring
54 | # configuration. By default this will yield the
55 | # configuration stored in the cisagov organization-level
56 | # variable, but if you want to use a different configuration
57 | # then simply:
58 | # 1. Create a repository-level variable with the name
59 | # ACTIONS_PERMISSIONS_CONFIG.
60 | # 2. Set this new variable's value to the configuration you
61 | # want to use for this repository.
62 | #
63 | # Note in particular that changing the permissions
64 | # monitoring configuration *does not* require you to modify
65 | # this workflow.
66 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
67 | lint:
68 | needs:
69 | - diagnostics
70 | permissions:
71 | # actions/checkout needs this to fetch code
72 | contents: read
73 | runs-on: ubuntu-latest
74 | steps:
75 | - name: Apply standard cisagov job preamble
76 | uses: cisagov/action-job-preamble@v1
77 | with:
78 | # This functionality is poorly implemented and has been
79 | # causing problems due to the MITM implementation hogging or
80 | # leaking memory. As a result we disable it by default. If
81 | # you want to temporarily enable it, simply set
82 | # monitor_permissions equal to "true".
83 | #
84 | # TODO: Re-enable this functionality when practical. See
85 | # cisagov/skeleton-generic#207 for more details.
86 | monitor_permissions: "false"
87 | # Use a variable to specify the permissions monitoring
88 | # configuration. By default this will yield the
89 | # configuration stored in the cisagov organization-level
90 | # variable, but if you want to use a different configuration
91 | # then simply:
92 | # 1. Create a repository-level variable with the name
93 | # ACTIONS_PERMISSIONS_CONFIG.
94 | # 2. Set this new variable's value to the configuration you
95 | # want to use for this repository.
96 | #
97 | # Note in particular that changing the permissions
98 | # monitoring configuration *does not* require you to modify
99 | # this workflow.
100 | permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }}
101 | - id: setup-env
102 | uses: cisagov/setup-env-github-action@v1
103 | - uses: actions/checkout@v6
104 | - id: setup-python
105 | uses: actions/setup-python@v6
106 | with:
107 | python-version: ${{ steps.setup-env.outputs.python-version }}
108 | # We need the Go version and Go cache location for the actions/cache step,
109 | # so the Go installation must happen before that.
110 | - id: setup-go
111 | uses: actions/setup-go@v6
112 | with:
113 | # There is no expectation for actual Go code so we disable caching as
114 | # it relies on the existence of a go.sum file.
115 | cache: false
116 | go-version: ${{ steps.setup-env.outputs.go-version }}
117 | - id: go-cache
118 | name: Lookup Go cache directory
119 | run: |
120 | echo "dir=$(go env GOCACHE)" >> $GITHUB_OUTPUT
121 | - uses: actions/cache@v4
122 | env:
123 | BASE_CACHE_KEY: ${{ github.job }}-${{ runner.os }}-\
124 | py${{ steps.setup-python.outputs.python-version }}-\
125 | go${{ steps.setup-go.outputs.go-version }}-\
126 | packer${{ steps.setup-env.outputs.packer-version }}-\
127 | tf${{ steps.setup-env.outputs.terraform-version }}-
128 | with:
129 | key: ${{ env.BASE_CACHE_KEY }}\
130 | ${{ hashFiles('**/requirements-test.txt') }}-\
131 | ${{ hashFiles('**/requirements.txt') }}-\
132 | ${{ hashFiles('**/.pre-commit-config.yaml') }}
133 | # Note that the .terraform directory IS NOT included in the
134 | # cache because if we were caching, then we would need to use
135 | # the `-upgrade=true` option. This option blindly pulls down the
136 | # latest modules and providers instead of checking to see if an
137 | # update is required. That behavior defeats the benefits of caching.
138 | # so there is no point in doing it for the .terraform directory.
139 | path: |
140 | ${{ env.PIP_CACHE_DIR }}
141 | ${{ env.PRE_COMMIT_CACHE_DIR }}
142 | ${{ steps.go-cache.outputs.dir }}
143 | restore-keys: |
144 | ${{ env.BASE_CACHE_KEY }}
145 | - uses: hashicorp/setup-packer@v3
146 | with:
147 | version: ${{ steps.setup-env.outputs.packer-version }}
148 | - uses: hashicorp/setup-terraform@v3
149 | with:
150 | terraform_version: ${{ steps.setup-env.outputs.terraform-version }}
151 | - name: Install go-critic
152 | env:
153 | PACKAGE_URL: github.com/go-critic/go-critic/cmd/gocritic
154 | PACKAGE_VERSION: ${{ steps.setup-env.outputs.go-critic-version }}
155 | run: go install ${PACKAGE_URL}@${PACKAGE_VERSION}
156 | - name: Install goimports
157 | env:
158 | PACKAGE_URL: golang.org/x/tools/cmd/goimports
159 | PACKAGE_VERSION: ${{ steps.setup-env.outputs.goimports-version }}
160 | run: go install ${PACKAGE_URL}@${PACKAGE_VERSION}
161 | - name: Install gosec
162 | env:
163 | PACKAGE_URL: github.com/securego/gosec/v2/cmd/gosec
164 | PACKAGE_VERSION: ${{ steps.setup-env.outputs.gosec-version }}
165 | run: go install ${PACKAGE_URL}@${PACKAGE_VERSION}
166 | - name: Install staticcheck
167 | env:
168 | PACKAGE_URL: honnef.co/go/tools/cmd/staticcheck
169 | PACKAGE_VERSION: ${{ steps.setup-env.outputs.staticcheck-version }}
170 | run: go install ${PACKAGE_URL}@${PACKAGE_VERSION}
171 | # TODO: https://github.com/cisagov/skeleton-generic/issues/165
172 | # We are temporarily using @mcdonnnj's forked branch of terraform-docs
173 | # until his PR: https://github.com/terraform-docs/terraform-docs/pull/745
174 | # is approved. This temporary fix will allow for ATX header support when
175 | # terraform-docs is run during linting.
176 | - name: Clone ATX headers branch from terraform-docs fork
177 | run: |
178 | git clone \
179 | --branch $TERRAFORM_DOCS_REPO_BRANCH_NAME \
180 | --depth $TERRAFORM_DOCS_REPO_DEPTH \
181 | --single-branch \
182 | $TERRAFORM_DOCS_REPO_URL /tmp/terraform-docs
183 | - name: Build and install terraform-docs binary
184 | run: |
185 | go build \
186 | -C /tmp/terraform-docs \
187 | -o $(go env GOPATH)/bin/terraform-docs
188 | - name: Install dependencies
189 | run: |
190 | python -m pip install --upgrade pip setuptools wheel
191 | pip install --upgrade --requirement requirements-test.txt
192 | - name: Set up pre-commit hook environments
193 | run: pre-commit install-hooks
194 | - name: Run pre-commit on all files
195 | run: pre-commit run --all-files
196 | - name: Setup tmate debug session
197 | uses: mxschmitt/action-tmate@v3
198 | if: env.RUN_TMATE
199 |
--------------------------------------------------------------------------------
/setup-env:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -o nounset
4 | set -o errexit
5 | set -o pipefail
6 |
7 | USAGE=$(
8 | cat << 'END_OF_LINE'
9 | Configure a development environment for this repository.
10 |
11 | It does the following:
12 | - Allows the user to specify the Python version to use for the virtual environment.
13 | - Allows the user to specify a name for the virtual environment.
14 | - Verifies pyenv and pyenv-virtualenv are installed.
15 | - Creates the Python virtual environment.
16 | - Configures the activation of the virtual enviroment for the repo directory.
17 | - Installs the requirements needed for development.
18 | - Installs git pre-commit hooks.
19 | - Configures git remotes for upstream "lineage" repositories.
20 |
21 | Usage:
22 | setup-env [--venv-name venv_name] [--python-version python_version]
23 | setup-env (-h | --help)
24 |
25 | Options:
26 | -f | --force Delete virtual enviroment if it already exists.
27 | -h | --help Show this message.
28 | -i | --install-hooks Install hook environments for all environments in the
29 | pre-commit config file.
30 | -l | --list-versions List available Python versions and select one interactively.
31 | -v | --venv-name Specify the name of the virtual environment.
32 | -p | --python-version Specify the Python version for the virtual environment.
33 |
34 | END_OF_LINE
35 | )
36 |
37 | # Display pyenv's installed Python versions
38 | python_versions() {
39 | pyenv versions --bare --skip-aliases --skip-envs
40 | }
41 |
42 | check_python_version() {
43 | local version=$1
44 |
45 | # This is a valid regex for semantically correct Python version strings.
46 | # For more information see here:
47 | # https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
48 | # Break down the regex into readable parts major.minor.patch
49 | local major="0|[1-9]\d*"
50 | local minor="0|[1-9]\d*"
51 | local patch="0|[1-9]\d*"
52 |
53 | # Splitting the prerelease part for readability
54 | # Start of the prerelease
55 | local prerelease="(?:-"
56 | # Numeric or alphanumeric identifiers
57 | local prerelease+="(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)"
58 | # Additional dot-separated identifiers
59 | local prerelease+="(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*"
60 | # End of the prerelease, making it optional
61 | local prerelease+=")?"
62 | # Optional build metadata
63 | local build="(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?"
64 |
65 | # Final regex composed of parts
66 | local regex="^($major)\.($minor)\.($patch)$prerelease$build$"
67 |
68 | # This checks if the Python version does not match the regex pattern specified in $regex,
69 | # using Perl for regex matching. If the pattern is not found, then prompt the user with
70 | # the invalid version message.
71 | if ! echo "$version" | perl -ne "exit(!/$regex/)"; then
72 | echo "Invalid version of Python: Python follows semantic versioning," \
73 | "so any version string that is not a valid semantic version is an" \
74 | "invalid version of Python."
75 | exit 1
76 | # Else if the Python version isn't installed then notify the user.
77 | # grep -E is used for searching through text lines that match the
78 | # specific version.
79 | elif ! python_versions | grep -E "^${version}$" > /dev/null; then
80 | echo "Error: Python version $version is not installed."
81 | echo "Installed Python versions are:"
82 | python_versions
83 | exit 1
84 | else
85 | echo "Using Python version $version"
86 | fi
87 | }
88 |
89 | # Flag to force deletion and creation of virtual environment
90 | FORCE=0
91 |
92 | # Initialize the other flags
93 | INSTALL_HOOKS=0
94 | LIST_VERSIONS=0
95 | PYTHON_VERSION=""
96 | VENV_NAME=""
97 |
98 | # Define long options
99 | LONGOPTS="force,help,install-hooks,list-versions,python-version:,venv-name:"
100 |
101 | # Define short options for getopt
102 | SHORTOPTS="fhilp:v:"
103 |
104 | # Check for GNU getopt by testing for long option support. GNU getopt supports
105 | # the "--test" option and will return exit code 4 while POSIX/BSD getopt does
106 | # not and will return exit code 0.
107 | if getopt --test > /dev/null 2>&1; then
108 | cat << 'END_OF_LINE'
109 |
110 | Please note, this script requires GNU getopt due to its enhanced
111 | functionality and compatibility with certain script features that
112 | are not supported by the POSIX getopt found in some systems, particularly
113 | those with a non-GNU version of getopt. This distinction is crucial
114 | as a system might have a non-GNU version of getopt installed by default,
115 | which could lead to unexpected behavior.
116 |
117 | On macOS, we recommend installing brew (https://brew.sh/). Then installation
118 | is as simple as `brew install gnu-getopt` and adding this to your
119 | profile:
120 |
121 | export PATH="$(brew --prefix)/opt/gnu-getopt/bin:$PATH"
122 |
123 | GNU getopt must be explicitly added to the PATH since it
124 | is keg-only (https://docs.brew.sh/FAQ#what-does-keg-only-mean).
125 |
126 | END_OF_LINE
127 | exit 1
128 | fi
129 |
130 | # Check to see if pyenv is installed
131 | if [ -z "$(command -v pyenv)" ] || { [ -z "$(command -v pyenv-virtualenv)" ] && [ ! -f "$(pyenv root)/plugins/pyenv-virtualenv/bin/pyenv-virtualenv" ]; }; then
132 | echo "pyenv and pyenv-virtualenv are required."
133 | if [[ "$OSTYPE" == "darwin"* ]]; then
134 | cat << 'END_OF_LINE'
135 |
136 | On macOS, we recommend installing brew, https://brew.sh/. Then installation
137 | is as simple as `brew install pyenv pyenv-virtualenv` and adding this to your
138 | profile:
139 |
140 | eval "$(pyenv init -)"
141 | eval "$(pyenv virtualenv-init -)"
142 |
143 | END_OF_LINE
144 |
145 | fi
146 | cat << 'END_OF_LINE'
147 | For Linux, Windows Subsystem for Linux (WSL), or macOS (if you don't want
148 | to use "brew") you can use https://github.com/pyenv/pyenv-installer to install
149 | the necessary tools. Before running this ensure that you have installed the
150 | prerequisites for your platform according to the pyenv wiki page,
151 | https://github.com/pyenv/pyenv/wiki/common-build-problems.
152 |
153 | On WSL you should treat your platform as whatever Linux distribution you've
154 | chosen to install.
155 |
156 | Once you have installed "pyenv" you will need to add the following lines to
157 | your ".bashrc":
158 |
159 | export PATH="$PATH:$HOME/.pyenv/bin"
160 | eval "$(pyenv init -)"
161 | eval "$(pyenv virtualenv-init -)"
162 | END_OF_LINE
163 | exit 1
164 | fi
165 |
166 | # Use GNU getopt to parse options
167 | if ! PARSED=$(getopt --options $SHORTOPTS --longoptions $LONGOPTS --name "$0" -- "$@"); then
168 | echo "Error parsing options"
169 | exit 1
170 | fi
171 | eval set -- "$PARSED"
172 |
173 | while true; do
174 | case "$1" in
175 | -f | --force)
176 | FORCE=1
177 | shift
178 | ;;
179 | -h | --help)
180 | echo "$USAGE"
181 | exit 0
182 | ;;
183 | -i | --install-hooks)
184 | INSTALL_HOOKS=1
185 | shift
186 | ;;
187 | -l | --list-versions)
188 | LIST_VERSIONS=1
189 | shift
190 | ;;
191 | -p | --python-version)
192 | PYTHON_VERSION="$2"
193 | shift 2
194 | # Check the Python version being passed in.
195 | check_python_version "$PYTHON_VERSION"
196 | ;;
197 | -v | --venv-name)
198 | VENV_NAME="$2"
199 | shift 2
200 | ;;
201 | --)
202 | shift
203 | break
204 | ;;
205 | *)
206 | # Unreachable due to GNU getopt handling all options
207 | echo "Programming error"
208 | exit 64
209 | ;;
210 | esac
211 | done
212 |
213 | # Determine the virtual environment name
214 | if [ -n "$VENV_NAME" ]; then
215 | # Use the user-provided environment name
216 | env_name="$VENV_NAME"
217 | else
218 | # Set the environment name to the last part of the working directory.
219 | env_name=${PWD##*/}
220 | fi
221 |
222 | # List Python versions and select one interactively.
223 | if [ $LIST_VERSIONS -ne 0 ]; then
224 | echo Available Python versions:
225 | python_versions
226 | # Read the user's desired Python version.
227 | # -r: treat backslashes as literal, -p: display prompt before input.
228 | read -r -p "Enter the desired Python version: " PYTHON_VERSION
229 | # Check the Python version being passed in.
230 | check_python_version "$PYTHON_VERSION"
231 | fi
232 |
233 | # Remove any lingering local configuration.
234 | if [ $FORCE -ne 0 ]; then
235 | rm -f .python-version
236 | pyenv virtualenv-delete --force "${env_name}" || true
237 | elif [[ -f .python-version ]]; then
238 | cat << 'END_OF_LINE'
239 | An existing .python-version file was found. Either remove this file yourself
240 | or re-run with the --force option to have it deleted along with the associated
241 | virtual environment.
242 |
243 | rm .python-version
244 |
245 | END_OF_LINE
246 | exit 1
247 | fi
248 |
249 | # Create a new virtual environment for this project
250 | #
251 | # If $PYTHON_VERSION is undefined then the current pyenv Python version will be used.
252 | #
253 | # We can't quote ${PYTHON_VERSION:=} below since if the variable is
254 | # undefined then we want nothing to appear; this is the reason for the
255 | # "shellcheck disable" line below.
256 | #
257 | # shellcheck disable=SC2086
258 | if ! pyenv virtualenv ${PYTHON_VERSION:=} "${env_name}"; then
259 | cat << END_OF_LINE
260 | An existing virtual environment named $env_name was found. Either delete this
261 | environment yourself or re-run with the --force option to have it deleted.
262 |
263 | pyenv virtualenv-delete ${env_name}
264 |
265 | END_OF_LINE
266 | exit 1
267 | fi
268 |
269 | # Set the local application-specific Python version(s) by writing the
270 | # version name to a file named `.python-version'.
271 | pyenv local "${env_name}"
272 |
273 | # Upgrade pip and friends
274 | python3 -m pip install --upgrade pip setuptools wheel
275 |
276 | # Find a requirements file (if possible) and install
277 | for req_file in "requirements-dev.txt" "requirements-test.txt" "requirements.txt"; do
278 | if [[ -f $req_file ]]; then
279 | pip install --requirement $req_file
280 | break
281 | fi
282 | done
283 |
284 | # Install git pre-commit hooks now or later.
285 | pre-commit install ${INSTALL_HOOKS:+"--install-hooks"}
286 |
287 | # Setup git remotes from lineage configuration
288 | # This could fail if the remotes are already setup, but that is ok.
289 | set +o errexit
290 |
291 | eval "$(
292 | python3 << 'END_OF_LINE'
293 | from pathlib import Path
294 | import yaml
295 | import sys
296 |
297 | LINEAGE_CONFIG = Path(".github/lineage.yml")
298 |
299 | if not LINEAGE_CONFIG.exists():
300 | print("No lineage configuration found.", file=sys.stderr)
301 | sys.exit(0)
302 |
303 | with LINEAGE_CONFIG.open("r") as f:
304 | lineage = yaml.safe_load(stream=f)
305 |
306 | if lineage["version"] == "1":
307 | for parent_name, v in lineage["lineage"].items():
308 | remote_url = v["remote-url"]
309 | print(f"git remote add {parent_name} {remote_url};")
310 | print(f"git remote set-url --push {parent_name} no_push;")
311 | else:
312 | print(f'Unsupported lineage version: {lineage["version"]}', file=sys.stderr)
313 | END_OF_LINE
314 | )"
315 |
316 | # Qapla'
317 | echo "Success!"
318 |
--------------------------------------------------------------------------------