flutter_flutter/engine/src/flutter/ci/deps_parser_tests.py
sealesj 4220be6c72 Vulnerability Scanning on Third Party Deps (flutter/engine#36506)
* initial flatten deps scan

* move 3rd party scan to separate action

* allow fork to run

* install requests

* use packages

* pip install

* rename

* conditional vuln report

* trailing whitespace

* trailing whitespace

* detailed print

* add testing file

* add upload test sarif

* results sarif

* move sarif

* upload modified sarif

* test flow

* test with results.sarif

* formatting

* test naming convention

* description with text in artifactLocation

* don't use locations

* use template sarif

* just use template

* add one field mod

* add another field mod

* use actual osvReport

* add field

* add field

* test

* no information uri

* no information uri

* add name

* template NA data for results

* back to minimal template

* dynamic rules

* template update

* no results

* only use template

* test

* new test

* new test

* add back locations

* descriptive fields

* test

* use package name

* variable commit hash

* add chromium accessibility readme support

* use batch query test

* clean up

* use variables for sarif template

* initial automating ancestor commit

* allow for workflow on testing

* install gitpython in workflow

* wrap in try

* expand try

* check commit is not none

* quiet clone

* fix commit newline

* proper print for failed deps

* remove gitpython

* remove import

* fix origin source

* remove .dart from dep names

* update dep

* typo

* update

* clone into controlled name repo now

* fix github upstream clone url

* test CVE finding

* use templated rule and result

* typo

* remove test CVE

* add link straight to OSV DB

* comments

* use os mkdir

* check time of pinned commit

* quiet git

* print osv api query results if vulns found

* move upstream mapping into DEPS file

* add testing for DEPS file

* add khronos exception

* add basic ancestor commit test

* no vulns message

* do not produce empty sarif

* add yaml

* remove unused python dep

* no change?

* no more print, causing recipe issues

* string test

* string test

* no more fstrings

* convert to .format

* syntax

* remove unused dep

* test

* switch test script

* no encoding

* add back test

* typo

* remove scan flat deps tests again

* update

* fix tests

* typo

* newline

* use checkout dir

* prefix

* update to use prefix

* lint

* runhook attempt

* lint

* lint

* lint

* lint

* no license blurb

* cleanup

* enable for main

* do not raise error

* run on branch

* data indentation

* check file existence

* workflow updates

* add push for testing

* syntax

* workflow test

* test github action

* syntax

* allow empty report

* update cron

* pin hash

* newline

* sort by key with prefix omitted

* alphabetize, copyright header

* pylint tests

* lint

* lint

* trailing whitespace?

* lint

* update

* get error types

* allow test

* use output

* only main branch

* licenses check

* results.sarif

* revert

* license updates

* add upstream

* replace Requests library with urllib, remove pylint wrapper

* lint

* undo license

* clone test nit

* isinstance

* DEPS formatting

Co-authored-by: Zachary Anderson <zanderso@users.noreply.github.com>

* use subprocess.check_output

* lint

* lint

* review syntax from comments

* remove line

* more description in error

* lint

* fix checkout path

* remove duplicate eval

* lint

* lint

* lint

* clone-test mkdir and cleanup

* use shutil.rmtree for non-empty dir

* lint

* linting

* linting

* var name

* Update ci/deps_parser_tests.py

Co-authored-by: Zachary Anderson <zanderso@users.noreply.github.com>

* Update ci/deps_parser_tests.py

Co-authored-by: Zachary Anderson <zanderso@users.noreply.github.com>

* more description

* lint

* refactor deps file parsing

* early return

* lint

Co-authored-by: Zachary Anderson <zanderso@users.noreply.github.com>
2022-11-23 15:07:43 -05:00

89 lines
3.2 KiB
Python

#!/usr/bin/env python3
#
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
import sys
import unittest
from deps_parser import VarImpl
SCRIPT_DIR = os.path.dirname(sys.argv[0])
CHECKOUT_ROOT = os.path.realpath(os.path.join(SCRIPT_DIR, '..'))
DEPS = os.path.join(CHECKOUT_ROOT, 'DEPS')
UPSTREAM_PREFIX = 'upstream_'
class TestDepsParserMethods(unittest.TestCase):
# Extract both mirrored dep names and URLs &
# upstream names and URLs from DEPs file.
def setUp(self): # lower-camel-case for the python unittest framework
# Read the content.
with open(DEPS, 'r') as file:
deps_content = file.read()
local_scope_mirror = {}
var = VarImpl(local_scope_mirror)
global_scope_mirror = {
'Var': var.lookup,
'deps_os': {},
}
# Eval the content.
exec(deps_content, global_scope_mirror, local_scope_mirror)
# Extract the upstream URLs
# vars contains more than just upstream URLs
# however the upstream URLs are prefixed with 'upstream_'
upstream = local_scope_mirror.get('vars')
self.upstream_urls = upstream
# Extract the deps and filter.
deps = local_scope_mirror.get('deps', {})
filtered_deps = []
for _, dep in deps.items():
# We currently do not support packages or cipd which are represented
# as dictionaries.
if isinstance(dep, str):
filtered_deps.append(dep)
self.deps = filtered_deps
def test_each_dep_has_upstream_url(self):
# For each DEP in the deps file, check for an associated upstream URL in deps file.
for dep in self.deps:
dep_repo = dep.split('@')[0]
dep_name = dep_repo.split('/')[-1].split('.')[0]
# vulkan-deps and khronos do not have one upstream URL
# all other deps should have an associated upstream URL for vuln scanning purposes
if dep_name not in ('vulkan-deps', 'khronos'):
# Add the prefix on the dep name when searching for the upstream entry.
self.assertTrue(
UPSTREAM_PREFIX + dep_name in self.upstream_urls,
msg=dep_name + ' not found in upstream URL list. ' +
'Each dep in the "deps" section of DEPS file must have associated upstream URL'
)
def test_each_upstream_url_has_dep(self):
# Parse DEPS into dependency names.
deps_names = []
for dep in self.deps:
dep_repo = dep.split('@')[0]
dep_name = dep_repo.split('/')[-1].split('.')[0]
deps_names.append(dep_name)
# For each upstream URL dep, check it exists as in DEPS.
for upsream_dep in self.upstream_urls:
# Only test on upstream deps in vars section which start with the upstream prefix
if upsream_dep.startswith(UPSTREAM_PREFIX):
# Strip the prefix to check that it has a corresponding dependency in the DEPS file
self.assertTrue(
upsream_dep[len(UPSTREAM_PREFIX):] in deps_names,
msg=upsream_dep + ' from upstream list not found in DEPS. ' +
'Each upstream URL in DEPS file must have an associated dep in the "deps" section'
)
if __name__ == '__main__':
unittest.main()