Add EE support (#440)
* Add EE files.
* Install cryptography and PyOpenSSL from PyPi.
* Revert "Install cryptography and PyOpenSSL from PyPi."
This reverts commit 6b90a1efae
.
* Only run test when cryptography has a new enough version.
* And another one.
* Extend changelog.
pull/452/head
parent
c16d9f78b8
commit
640bdbc066
|
@ -0,0 +1,109 @@
|
||||||
|
---
|
||||||
|
name: execution environment
|
||||||
|
on:
|
||||||
|
# Run CI against all pushes (direct commits, also merged PRs), Pull Requests
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
- stable-*
|
||||||
|
pull_request:
|
||||||
|
# Run CI once per day (at 04:45 UTC)
|
||||||
|
# This ensures that even if there haven't been commits that we are still testing against latest version of ansible-builder
|
||||||
|
schedule:
|
||||||
|
- cron: '45 4 * * *'
|
||||||
|
|
||||||
|
env:
|
||||||
|
NAMESPACE: community
|
||||||
|
COLLECTION_NAME: crypto
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build and test EE (Ⓐ${{ matrix.runner_tag }})
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
runner_tag:
|
||||||
|
- devel
|
||||||
|
- stable-2.12-latest
|
||||||
|
- stable-2.11-latest
|
||||||
|
- stable-2.9-latest
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
path: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v3
|
||||||
|
with:
|
||||||
|
python-version: '3.10'
|
||||||
|
|
||||||
|
- name: Install ansible-builder and ansible-navigator
|
||||||
|
run: pip install ansible-builder ansible-navigator
|
||||||
|
|
||||||
|
- name: Verify requirements
|
||||||
|
run: ansible-builder introspect --sanitize .
|
||||||
|
|
||||||
|
- name: Make sure galaxy.yml has version entry
|
||||||
|
run: >-
|
||||||
|
python -c
|
||||||
|
'import yaml ;
|
||||||
|
f = open("galaxy.yml", "rb") ;
|
||||||
|
data = yaml.safe_load(f) ;
|
||||||
|
f.close() ;
|
||||||
|
data["version"] = data.get("version") or "0.0.1" ;
|
||||||
|
f = open("galaxy.yml", "wb") ;
|
||||||
|
f.write(yaml.dump(data).encode("utf-8")) ;
|
||||||
|
f.close() ;
|
||||||
|
'
|
||||||
|
working-directory: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
|
||||||
|
|
||||||
|
- name: Build collection
|
||||||
|
run: |
|
||||||
|
ansible-galaxy collection build --output-path ../../../
|
||||||
|
working-directory: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}
|
||||||
|
|
||||||
|
- name: Create files for building execution environment
|
||||||
|
run: |
|
||||||
|
COLLECTION_FILENAME="$(ls "${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}"-*.tar.gz)"
|
||||||
|
|
||||||
|
# EE config
|
||||||
|
cat > execution-environment.yml <<EOF
|
||||||
|
---
|
||||||
|
version: 1
|
||||||
|
build_arg_defaults:
|
||||||
|
EE_BASE_IMAGE: 'quay.io/ansible/ansible-runner:${{ matrix.runner_tag }}'
|
||||||
|
dependencies:
|
||||||
|
galaxy: requirements.yml
|
||||||
|
EOF
|
||||||
|
echo "::group::execution-environment.yml"
|
||||||
|
cat execution-environment.yml
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
# Requirements
|
||||||
|
cat > requirements.yml <<EOF
|
||||||
|
---
|
||||||
|
collections:
|
||||||
|
- name: ${COLLECTION_FILENAME}
|
||||||
|
type: file
|
||||||
|
EOF
|
||||||
|
echo "::group::requirements.yml"
|
||||||
|
cat requirements.yml
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
- name: Build image based on ${{ matrix.runner_tag }}
|
||||||
|
run: |
|
||||||
|
mkdir -p context/_build/
|
||||||
|
cp "${{ env.NAMESPACE }}-${{ env.COLLECTION_NAME }}"-*.tar.gz context/_build/
|
||||||
|
ansible-builder build -v 3 -t test-ee:latest --container-runtime=podman
|
||||||
|
|
||||||
|
- name: Run basic tests
|
||||||
|
run: >
|
||||||
|
ansible-navigator run
|
||||||
|
--mode stdout
|
||||||
|
--pull-policy never
|
||||||
|
--set-environment-variable ANSIBLE_PRIVATE_ROLE_VARS=true
|
||||||
|
--execution-environment-image test-ee:latest
|
||||||
|
-v
|
||||||
|
all.yml
|
||||||
|
working-directory: ansible_collections/${{ env.NAMESPACE }}/${{ env.COLLECTION_NAME }}/tests/ee
|
|
@ -0,0 +1,7 @@
|
||||||
|
minor_changes:
|
||||||
|
- "Prepare collection for inclusion in an Execution Environment by declaring its dependencies.
|
||||||
|
Please note that system packages are used for cryptography and PyOpenSSL, which can be
|
||||||
|
rather limited. If you need features from newer cryptography versions, you will have to
|
||||||
|
manually force a newer version to be installed by pip by specifying something like
|
||||||
|
``cryptography >= 37.0.0`` in your Execution Environment's Python dependencies file
|
||||||
|
(https://github.com/ansible-collections/community.crypto/pull/440)."
|
|
@ -0,0 +1,10 @@
|
||||||
|
cryptsetup [platform:dpkg]
|
||||||
|
cryptsetup [platform:rpm]
|
||||||
|
openssh-client [platform:dpkg]
|
||||||
|
openssh-clients [platform:rpm]
|
||||||
|
openssl [platform:dpkg]
|
||||||
|
openssl [platform:rpm]
|
||||||
|
python3-cryptography [platform:dpkg]
|
||||||
|
python3-cryptography [platform:rpm]
|
||||||
|
python3-openssl [platform:dpkg]
|
||||||
|
python3-pyOpenSSL [platform:rpm]
|
|
@ -0,0 +1 @@
|
||||||
|
PyYAML
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
version: 1
|
||||||
|
dependencies:
|
||||||
|
python: meta/ee-requirements.txt
|
||||||
|
system: meta/ee-bindep.txt
|
|
@ -0,0 +1,34 @@
|
||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Register cryptography version
|
||||||
|
command: "{{ ansible_python.executable }} -c 'import cryptography; print(cryptography.__version__)'"
|
||||||
|
register: cryptography_version
|
||||||
|
|
||||||
|
- name: Determine output directory
|
||||||
|
set_fact:
|
||||||
|
output_path: "{{ 'output-%0x' % ((2**32) | random) }}"
|
||||||
|
|
||||||
|
- name: Find all roles
|
||||||
|
ansible.builtin.find:
|
||||||
|
paths:
|
||||||
|
- "{{ (playbook_dir | default('.')) ~ '/roles' }}"
|
||||||
|
file_type: directory
|
||||||
|
depth: 1
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Create output directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ output_path }}"
|
||||||
|
state: directory
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Include all roles
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: "{{ item }}"
|
||||||
|
loop: "{{ result.files | map(attribute='path') | map('regex_replace', '.*/', '') | sort }}"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Remove output directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ output_path }}"
|
||||||
|
state: absent
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
- name: Run crypto_info
|
||||||
|
community.crypto.crypto_info:
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Dump result
|
||||||
|
debug:
|
||||||
|
var: result
|
||||||
|
|
||||||
|
- name: Validate result
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.openssl_present
|
||||||
|
- result.python_cryptography_installed
|
||||||
|
- result.python_cryptography_capabilities.has_dsa
|
||||||
|
- result.python_cryptography_capabilities.has_dsa_sign
|
||||||
|
- result.python_cryptography_capabilities.has_ec
|
||||||
|
- result.python_cryptography_capabilities.has_ec_sign
|
||||||
|
- result.python_cryptography_capabilities.has_ed25519
|
||||||
|
- result.python_cryptography_capabilities.has_ed25519_sign
|
||||||
|
- result.python_cryptography_capabilities.has_ed448
|
||||||
|
- result.python_cryptography_capabilities.has_ed448_sign
|
||||||
|
- result.python_cryptography_capabilities.has_rsa
|
||||||
|
- result.python_cryptography_capabilities.has_rsa_sign
|
||||||
|
- result.python_cryptography_capabilities.has_x25519
|
||||||
|
- result.python_cryptography_capabilities.has_x25519_serialization
|
||||||
|
- result.python_cryptography_capabilities.has_x448
|
|
@ -0,0 +1,45 @@
|
||||||
|
---
|
||||||
|
- name: Run cryptsetup (smoke test)
|
||||||
|
ansible.builtin.command: cryptsetup --version
|
||||||
|
|
||||||
|
- name: Determine cryptfile path
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
cryptfile_path: "{{ output_path }}/cryptfile"
|
||||||
|
keyfile_path: "{{ output_path }}/keyfile"
|
||||||
|
|
||||||
|
- name: Create cryptfile
|
||||||
|
ansible.builtin.command: dd if=/dev/zero of={{ cryptfile_path }} bs=1M count=32
|
||||||
|
|
||||||
|
- name: Create keyfile
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: "{{ keyfile_path }}"
|
||||||
|
content: hunter2
|
||||||
|
|
||||||
|
- # Creating devices doesn't work well. We will have to try this again when luks_device
|
||||||
|
# supports working with container files directly.
|
||||||
|
when: false
|
||||||
|
block:
|
||||||
|
- name: Create lookback device
|
||||||
|
command: losetup -f {{ cryptfile_path }}
|
||||||
|
|
||||||
|
- name: Determine loop device name
|
||||||
|
command: losetup -j {{ cryptfile_path }} --output name
|
||||||
|
register: cryptfile_device_output
|
||||||
|
|
||||||
|
- set_fact:
|
||||||
|
cryptfile_device: "{{ cryptfile_device_output.stdout_lines[1] }}"
|
||||||
|
|
||||||
|
- name: Create LUKS container
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
# device: "{{ cryptfile_path }}"
|
||||||
|
state: present
|
||||||
|
keyfile: "{{ keyfile_path }}"
|
||||||
|
pbkdf:
|
||||||
|
iteration_time: 0.1
|
||||||
|
|
||||||
|
- name: Destroy LUKS container
|
||||||
|
community.crypto.luks_device:
|
||||||
|
device: "{{ cryptfile_device }}"
|
||||||
|
# device: "{{ cryptfile_path }}"
|
||||||
|
state: absent
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
- name: Generate key with OpenSSH binary backend
|
||||||
|
community.crypto.openssh_keypair:
|
||||||
|
path: "{{ output_path }}/openssh-key-1"
|
||||||
|
size: 2048
|
||||||
|
backend: opensshbin
|
||||||
|
|
||||||
|
- name: Generate key with cryptography backend
|
||||||
|
community.crypto.openssh_keypair:
|
||||||
|
path: "{{ output_path }}/openssh-key-2"
|
||||||
|
size: 2048
|
||||||
|
backend: cryptography
|
||||||
|
when: cryptography_version.stdout is ansible.builtin.version('3.0', '>=')
|
|
@ -0,0 +1,41 @@
|
||||||
|
---
|
||||||
|
- name: Create private key
|
||||||
|
community.crypto.openssl_privatekey:
|
||||||
|
path: "{{ output_path }}/pkcs12-cert.key"
|
||||||
|
type: ECC
|
||||||
|
curve: secp256r1
|
||||||
|
|
||||||
|
- name: Create CSR
|
||||||
|
community.crypto.openssl_csr:
|
||||||
|
path: "{{ output_path }}/pkcs12-cert.csr"
|
||||||
|
privatekey_path: "{{ output_path }}/pkcs12-cert.key"
|
||||||
|
|
||||||
|
- name: Create certificate
|
||||||
|
community.crypto.x509_certificate:
|
||||||
|
path: "{{ output_path }}/pkcs12-cert.pem"
|
||||||
|
csr_path: "{{ output_path }}/pkcs12-cert.csr"
|
||||||
|
privatekey_path: "{{ output_path }}/pkcs12-cert.key"
|
||||||
|
provider: selfsigned
|
||||||
|
|
||||||
|
- name: Create PKCS#12 with cryptography backend
|
||||||
|
community.crypto.openssl_pkcs12:
|
||||||
|
action: export
|
||||||
|
path: "{{ output_path }}/pkcs12-1.p12"
|
||||||
|
mode: '0644'
|
||||||
|
friendly_name: foo
|
||||||
|
privatekey_path: "{{ output_path }}/pkcs12-cert.key"
|
||||||
|
certificate_path: "{{ output_path }}/pkcs12-cert.pem"
|
||||||
|
state: present
|
||||||
|
select_crypto_backend: cryptography
|
||||||
|
when: cryptography_version.stdout is ansible.builtin.version('3.0', '>=')
|
||||||
|
|
||||||
|
- name: Create PKCS#12 with PyOpenSSL backend
|
||||||
|
community.crypto.openssl_pkcs12:
|
||||||
|
action: export
|
||||||
|
path: "{{ output_path }}/pkcs12-2.p12"
|
||||||
|
mode: '0644'
|
||||||
|
friendly_name: foo
|
||||||
|
privatekey_path: "{{ output_path }}/pkcs12-cert.key"
|
||||||
|
certificate_path: "{{ output_path }}/pkcs12-cert.pem"
|
||||||
|
state: present
|
||||||
|
select_crypto_backend: pyopenssl
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
- name: Create RSA private key
|
||||||
|
community.crypto.openssl_privatekey:
|
||||||
|
path: "{{ output_path }}/privatekey-1"
|
||||||
|
size: 2048
|
||||||
|
|
||||||
|
- name: Create ECC private key
|
||||||
|
community.crypto.openssl_privatekey:
|
||||||
|
path: "{{ output_path }}/privatekey-2"
|
||||||
|
type: ECC
|
||||||
|
curve: secp256r1
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# (c) 2022 Felix Fontein <felix@fontein.de>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: smoke_ipaddress
|
||||||
|
short_description: Check whether ipaddress is present
|
||||||
|
author:
|
||||||
|
- Felix Fontein (@felixfontein)
|
||||||
|
description:
|
||||||
|
- Check whether C(ipaddress) is present.
|
||||||
|
options: {}
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r''' # '''
|
||||||
|
|
||||||
|
RETURN = r''' # '''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ipaddress
|
||||||
|
HAS_IPADDRESS = True
|
||||||
|
except ImportError as exc:
|
||||||
|
IPADDRESS_IMP_ERR = traceback.format_exc()
|
||||||
|
HAS_IPADDRESS = False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(argument_spec=dict(), supports_check_mode=True)
|
||||||
|
|
||||||
|
if not HAS_IPADDRESS:
|
||||||
|
module.fail_json(msg=missing_required_lib('ipaddress'), exception=IPADDRESS_IMP_ERR)
|
||||||
|
|
||||||
|
module.exit_json(msg='Everything is ok')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': # pragma: no cover
|
||||||
|
main() # pragma: no cover
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# (c) 2022 Felix Fontein <felix@fontein.de>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = r'''
|
||||||
|
---
|
||||||
|
module: smoke_pyyaml
|
||||||
|
short_description: Check whether PyYAML is present
|
||||||
|
author:
|
||||||
|
- Felix Fontein (@felixfontein)
|
||||||
|
description:
|
||||||
|
- Check whether C(yaml) is present.
|
||||||
|
options: {}
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = r''' # '''
|
||||||
|
|
||||||
|
RETURN = r''' # '''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||||
|
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
HAS_PYYAML = True
|
||||||
|
except ImportError as exc:
|
||||||
|
PYYAML_IMP_ERR = traceback.format_exc()
|
||||||
|
HAS_PYYAML = False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(argument_spec=dict(), supports_check_mode=True)
|
||||||
|
|
||||||
|
if not HAS_PYYAML:
|
||||||
|
module.fail_json(msg=missing_required_lib('PyYAML'), exception=PYYAML_IMP_ERR)
|
||||||
|
|
||||||
|
module.exit_json(msg='Everything is ok')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': # pragma: no cover
|
||||||
|
main() # pragma: no cover
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
- name: Check whether ipaddress is present
|
||||||
|
smoke_ipaddress:
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Validate result
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.msg == 'Everything is ok'
|
||||||
|
|
||||||
|
- name: Check whether PyYAML is present
|
||||||
|
smoke_pyyaml:
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Validate result
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.msg == 'Everything is ok'
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
- name: Create private key
|
||||||
|
community.crypto.openssl_privatekey:
|
||||||
|
path: "{{ output_path }}/cert.key"
|
||||||
|
type: ECC
|
||||||
|
curve: secp256r1
|
||||||
|
|
||||||
|
- name: Create CSR
|
||||||
|
community.crypto.openssl_csr:
|
||||||
|
path: "{{ output_path }}/cert.csr"
|
||||||
|
privatekey_path: "{{ output_path }}/cert.key"
|
||||||
|
|
||||||
|
- name: Create certificate
|
||||||
|
community.crypto.x509_certificate:
|
||||||
|
path: "{{ output_path }}/cert.pem"
|
||||||
|
csr_path: "{{ output_path }}/cert.csr"
|
||||||
|
privatekey_path: "{{ output_path }}/cert.key"
|
||||||
|
provider: selfsigned
|
|
@ -5,3 +5,5 @@
|
||||||
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
|
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
|
||||||
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
|
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
|
||||||
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
|
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
|
||||||
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
|
||||||
|
|
|
@ -5,3 +5,5 @@
|
||||||
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
|
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
|
||||||
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
|
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
|
||||||
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
|
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
|
||||||
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
||||||
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
|
plugins/modules/acme_account_info.py validate-modules:return-syntax-error
|
||||||
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
||||||
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
.azure-pipelines/scripts/publish-codecov.py replace-urlopen
|
||||||
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
|
||||||
|
|
|
@ -4,3 +4,5 @@
|
||||||
.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
|
.azure-pipelines/scripts/publish-codecov.py compile-3.5!skip # Uses Python 3.6+ syntax
|
||||||
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
|
.azure-pipelines/scripts/publish-codecov.py future-import-boilerplate
|
||||||
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
|
.azure-pipelines/scripts/publish-codecov.py metaclass-boilerplate
|
||||||
|
tests/ee/roles/smoke/library/smoke_ipaddress.py shebang
|
||||||
|
tests/ee/roles/smoke/library/smoke_pyyaml.py shebang
|
||||||
|
|
Loading…
Reference in New Issue