From dc51d75a8e5dde975181baf0f702da8827fdba39 Mon Sep 17 00:00:00 2001 From: Archit Aggarwal Date: Tue, 27 Jul 2021 23:54:57 +0000 Subject: [PATCH 1/5] Add GitHub Action for verifying manifest.yml --- README.md | 4 +- verify-manifest/action.yml | 21 ++++++ verify-manifest/requirements.txt | 2 + verify-manifest/verify_manifest.py | 116 +++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 verify-manifest/action.yml create mode 100644 verify-manifest/requirements.txt create mode 100644 verify-manifest/verify_manifest.py diff --git a/README.md b/README.md index 9cefbb88..11ed14cb 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,6 @@ FreeRTOS libraries. library documentation. The memory estimates are generated by building the library with the ARM GCC toolchain. * **Link Verifier** - Verifies links present in source and Markdown files. Links verified include HTTP -URLs, and - for Markdown files - relative file path links and section anchors. +* **Manifest.yml Verifier** - Verifies that information of `manifest.yml` file matches the state of a repository for the presence of submodules and their commit IDs. + +URLs, and - for Markdown files - relative file path links and section anchors. \ No newline at end of file diff --git a/verify-manifest/action.yml b/verify-manifest/action.yml new file mode 100644 index 00000000..f718a8be --- /dev/null +++ b/verify-manifest/action.yml @@ -0,0 +1,21 @@ +name: 'verify-manifest' +description: 'Verifies manifest.yml against missing submodule entires and stale version information' +inputs: + path: + description: 'Path to repository folder containing manifest.yml to verify.' + required: false + default: ./ + exclude-submodules: + description: 'List of comma-separated relative path to submodules that should not be present in manifest.yml. Eg libraries/thirdparty/tinycbor,libraries/thirdparty/mbedtls' + required: false + default: '' +runs: + using: "composite" + steps: + - name: Install dependencies + run: pip install -r $GITHUB_ACTION_PATH/requirements.txt + shell: bash + - name: Run verifier script + working-directory: ${{ inputs.path }} + run: python3 $GITHUB_ACTION_PATH/verify_manifest.py --ignore-submodule-path=${{ inputs.exclude-submodules }} + shell: bash diff --git a/verify-manifest/requirements.txt b/verify-manifest/requirements.txt new file mode 100644 index 00000000..f83cdd5a --- /dev/null +++ b/verify-manifest/requirements.txt @@ -0,0 +1,2 @@ +pyyaml +gitpython \ No newline at end of file diff --git a/verify-manifest/verify_manifest.py b/verify-manifest/verify_manifest.py new file mode 100644 index 00000000..7f1481eb --- /dev/null +++ b/verify-manifest/verify_manifest.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +import os, sys +from yaml import load +from yaml import CLoader as Loader + +from git import Repo +from argparse import ArgumentParser + +REPO_PATH='' + +# List of submodules excluded from manifest.yml file +IGNORE_SUBMODULES_LIST = [] + +# Obtain submodule path of all entries in manifest.yml file. +def read_manifest(): + dict = {} + + # Read YML file + path_manifest = os.path.join(REPO_PATH, 'manifest.yml') + assert os.path.exists(path_manifest), 'Missing manifest.yml' + with open(path_manifest, 'r') as fp: + manifest_data = fp.read() + yml = load(manifest_data, Loader=Loader) + assert 'dependencies' in yml, 'Manifest YML parsing error' + + # Iterate over all the "dependencies" entries, verify that + # each contains entries for the following hierarchy: + # name: "" + # version: "" + # repository: + # type: "git" + # url: + # path: + # + for dep in yml['dependencies']: + assert 'version' in dep, "Failed to parse 'version/tag' for submodule" + assert 'repository' in dep and 'path' in dep['repository'] and 'url' in dep['repository'], "Failed to parse 'repository' object for submodule" + dict[dep['name']] = (dep['repository']['path'], dep['version']) + + return dict + +# Generate list of submodules path in repository, excluding the +# path in IGNORES_SUBMODULES_LIST. +def get_all_submodules(): + info_dict = {} + repo = Repo(REPO_PATH) + for submodule in repo.submodules: + path = submodule.abspath.replace(REPO_PATH+'/', '') + if path not in IGNORE_SUBMODULES_LIST: + #print(path,':',submodule.module().head.commit) + info_dict[path] = submodule.module().head.commit + + return info_dict + +if __name__ == '__main__': + parser = ArgumentParser(description='manifest.yml verifier') + parser.add_argument('--repo-root-path', + type=str, + required=None, + default=os.getcwd(), + help='Path to the repository root.') + parser.add_argument('--ignore-submodule-path', + type=str, + required=None, + default=os.getcwd(), + help='Comma-separated list of submodules path to ignore.') + + args = parser.parse_args() + + if args.ignore_submodule_path != None: + IGNORE_SUBMODULES_LIST = args.ignore_submodule_path.split(',') + + # Convert any relative path (like './') in passed argument to absolute path. + REPO_PATH = os.path.abspath(args.repo_root_path) + + submodules_info_from_manifest = read_manifest() + submodule_path_from_manifest = [pair[0] for pair in submodules_info_from_manifest.values()] + submodule_path_from_manifest = sorted(submodule_path_from_manifest) + + submodules_info_from_git = get_all_submodules() + submodule_path_from_git = sorted(submodules_info_from_git.keys()) + + print(REPO_PATH) + print('\nList of submoduled libraries being verified:', submodule_path_from_git) + + # Check that manifest.yml contains entries for all submodules + # present in repository. + if submodule_path_from_manifest != submodule_path_from_git: + print('manifest.yml is missing entries for:') + # Find list of library submodules missing in manifest.yml + for git_path in submodule_path_from_git: + if git_path not in submodule_path_from_manifest: + print(git_path) + sys.exit(1) + + # Verify that manifest contains correct versions of submodules pointers. + mismatch_flag = False + print('\nVerifying that manifest.yml versions are up-to-date.....') + for submodule_name, submodule_info in submodules_info_from_manifest.items(): + relative_path = submodule_info[0] + manifest_commit = submodule_info[1] + submodule = Repo(REPO_PATH+'/'+relative_path) + submodule.remote('origin').fetch() + submodule.git.checkout(manifest_commit) + if (submodules_info_from_git[relative_path] != submodule.head.commit): + print('manifest.yml does not have correct commit ID for', submodule_name,'manifest Commit=(',manifest_commit, submodule.head.commit,') Actual Commit=',submodules_info_from_git[relative_path]) + mismatch_flag = True + + if mismatch_flag: + sys.exit(1) + + print('\nmanifest.yml file has been verified!') + sys.exit(0) + + From e150c88fc6282ed2e4fa325475cfd7f4e202c577 Mon Sep 17 00:00:00 2001 From: Archit Aggarwal Date: Wed, 28 Jul 2021 00:28:32 +0000 Subject: [PATCH 2/5] Add test for manifest-verifier in CI job --- .github/workflows/test.yml | 25 +++++++++++++++++-- .../action.yml | 0 .../requirements.txt | 0 .../verify_manifest.py | 0 4 files changed, 23 insertions(+), 2 deletions(-) rename {verify-manifest => manifest-verifier}/action.yml (100%) rename {verify-manifest => manifest-verifier}/requirements.txt (100%) rename {verify-manifest => manifest-verifier}/verify_manifest.py (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ca119789..fedd52cf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,7 +37,7 @@ jobs: with: path: coreMQTT test-doxygen-zip-check: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 @@ -56,7 +56,7 @@ jobs: libs_parent_dir_path: libraries/standard,libraries/aws generate_zip: true test-doxygen-non-zip-check: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/checkout@v2 @@ -141,3 +141,24 @@ jobs: path: ./ exclude-dirs: complexity,formatting include-file-types: .c,.html + test-manifest-verifier: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Setup python environment + uses: actions/setup-python@v2 + with: + python-version: '3.7.x' + - name: Checkout the FreeRTOS/FreeRTOS repository for testing action on. + uses: actions/checkout@v2 + with: + repository: FreeRTOS/FreeRTOS + ref: '202107.00' + path: FreeRTOS + submodules: recursive + - name: Test manifest verifier + uses: ./manifest-verifier + with: + path: ./FreeRTOS + exclude-submodules: FreeRTOS-Plus/Test/CMock,FreeRTOS/Test/CMock/CMock,FreeRTOS/Test/litani + diff --git a/verify-manifest/action.yml b/manifest-verifier/action.yml similarity index 100% rename from verify-manifest/action.yml rename to manifest-verifier/action.yml diff --git a/verify-manifest/requirements.txt b/manifest-verifier/requirements.txt similarity index 100% rename from verify-manifest/requirements.txt rename to manifest-verifier/requirements.txt diff --git a/verify-manifest/verify_manifest.py b/manifest-verifier/verify_manifest.py similarity index 100% rename from verify-manifest/verify_manifest.py rename to manifest-verifier/verify_manifest.py From 0af6a297ffc3f9a8a3bf482dddab096f0423bfb2 Mon Sep 17 00:00:00 2001 From: Archit Aggarwal Date: Wed, 28 Jul 2021 01:20:43 +0000 Subject: [PATCH 3/5] Use latest python version supported by GH Action --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fedd52cf..4996bf8a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -148,7 +148,7 @@ jobs: - name: Setup python environment uses: actions/setup-python@v2 with: - python-version: '3.7.x' + python-version: '3.x' - name: Checkout the FreeRTOS/FreeRTOS repository for testing action on. uses: actions/checkout@v2 with: From 3cc6655a7a0bc2b38bc00382ccaf1a71bad9cff0 Mon Sep 17 00:00:00 2001 From: Archit Aggarwal Date: Wed, 28 Jul 2021 07:39:55 +0000 Subject: [PATCH 4/5] Make update of verions in manifest.yml optional --- manifest-verifier/action.yml | 11 ++++++++++- manifest-verifier/verify_manifest.py | 6 ++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/manifest-verifier/action.yml b/manifest-verifier/action.yml index f718a8be..e04c003f 100644 --- a/manifest-verifier/action.yml +++ b/manifest-verifier/action.yml @@ -9,6 +9,10 @@ inputs: description: 'List of comma-separated relative path to submodules that should not be present in manifest.yml. Eg libraries/thirdparty/tinycbor,libraries/thirdparty/mbedtls' required: false default: '' + fail-on-incorrect-version: + description: 'Boolean flag to indicate if verification should fail if any submodule version in manifest.yml file is incorrect or stale.' + required: false + default: 'false' runs: using: "composite" steps: @@ -17,5 +21,10 @@ runs: shell: bash - name: Run verifier script working-directory: ${{ inputs.path }} - run: python3 $GITHUB_ACTION_PATH/verify_manifest.py --ignore-submodule-path=${{ inputs.exclude-submodules }} + run: | + if [[ "${{ inputs.fail-on-incorrect-version }}" == "true" ]]; then + python3 $GITHUB_ACTION_PATH/verify_manifest.py --ignore-submodule-path=${{ inputs.exclude-submodules }} --fail-on-incorrect-version + else + python3 $GITHUB_ACTION_PATH/verify_manifest.py --ignore-submodule-path=${{ inputs.exclude-submodules }} + fi shell: bash diff --git a/manifest-verifier/verify_manifest.py b/manifest-verifier/verify_manifest.py index 7f1481eb..5ffbd0e0 100644 --- a/manifest-verifier/verify_manifest.py +++ b/manifest-verifier/verify_manifest.py @@ -63,8 +63,10 @@ def get_all_submodules(): parser.add_argument('--ignore-submodule-path', type=str, required=None, - default=os.getcwd(), help='Comma-separated list of submodules path to ignore.') + parser.add_argument('--fail-on-incorrect-versions', + action='store_true', + help='Flag to indicate script to fail for incorrect submodules versions in manifest.yml') args = parser.parse_args() @@ -107,7 +109,7 @@ def get_all_submodules(): print('manifest.yml does not have correct commit ID for', submodule_name,'manifest Commit=(',manifest_commit, submodule.head.commit,') Actual Commit=',submodules_info_from_git[relative_path]) mismatch_flag = True - if mismatch_flag: + if mismatch_flag and args.fail_on_incorrect_versions: sys.exit(1) print('\nmanifest.yml file has been verified!') From 407bad97aa1e373c1380d7d205fe69ac587e4fa7 Mon Sep 17 00:00:00 2001 From: Archit Aggarwal Date: Wed, 28 Jul 2021 18:41:23 +0000 Subject: [PATCH 5/5] Update CI check to use flag to fail verification for version mismatch --- .github/workflows/test.yml | 1 + manifest-verifier/action.yml | 1 + manifest-verifier/verify_manifest.py | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4996bf8a..57b4a944 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -161,4 +161,5 @@ jobs: with: path: ./FreeRTOS exclude-submodules: FreeRTOS-Plus/Test/CMock,FreeRTOS/Test/CMock/CMock,FreeRTOS/Test/litani + fail-on-incorrect-version: true diff --git a/manifest-verifier/action.yml b/manifest-verifier/action.yml index e04c003f..acbb98e7 100644 --- a/manifest-verifier/action.yml +++ b/manifest-verifier/action.yml @@ -23,6 +23,7 @@ runs: working-directory: ${{ inputs.path }} run: | if [[ "${{ inputs.fail-on-incorrect-version }}" == "true" ]]; then + echo 'Value of flag is ${{ inputs.fail-on-incorrect-version }}' python3 $GITHUB_ACTION_PATH/verify_manifest.py --ignore-submodule-path=${{ inputs.exclude-submodules }} --fail-on-incorrect-version else python3 $GITHUB_ACTION_PATH/verify_manifest.py --ignore-submodule-path=${{ inputs.exclude-submodules }} diff --git a/manifest-verifier/verify_manifest.py b/manifest-verifier/verify_manifest.py index 5ffbd0e0..0389ed21 100644 --- a/manifest-verifier/verify_manifest.py +++ b/manifest-verifier/verify_manifest.py @@ -64,7 +64,7 @@ def get_all_submodules(): type=str, required=None, help='Comma-separated list of submodules path to ignore.') - parser.add_argument('--fail-on-incorrect-versions', + parser.add_argument('--fail-on-incorrect-version', action='store_true', help='Flag to indicate script to fail for incorrect submodules versions in manifest.yml') @@ -109,7 +109,7 @@ def get_all_submodules(): print('manifest.yml does not have correct commit ID for', submodule_name,'manifest Commit=(',manifest_commit, submodule.head.commit,') Actual Commit=',submodules_info_from_git[relative_path]) mismatch_flag = True - if mismatch_flag and args.fail_on_incorrect_versions: + if mismatch_flag and args.fail_on_incorrect_version: sys.exit(1) print('\nmanifest.yml file has been verified!')