Initial commit

This commit is contained in:
Mustafa Gezen 2023-02-01 22:37:16 +01:00
commit 6d955c9925
Signed by untrusted user who does not match committer: mustafa
GPG Key ID: DCDF010D946438C1
92 changed files with 9005 additions and 0 deletions

1
.bazelignore Normal file
View File

@ -0,0 +1 @@
node_modules

35
.bazelrc Normal file
View File

@ -0,0 +1,35 @@
# Java
test --test_env='LC_ALL=en_US.UTF-8'
test --test_env='LANG=en_US.UTF-8'
test --jvmopt='-Dsun.jnu.encoding=UTF-8'
test --jvmopt='-Dfile.encoding=UTF-8'
build --test_env='LC_ALL=en_US.UTF-8'
build --jvmopt='-Dsun.jnu.encoding=UTF-8'
build --jvmopt='-Dfile.encoding=UTF-8'
build --test_env='LANG=en_US.UTF-8'
test --test_env=PATH
build --java_language_version=11
test --java_language_version=11
# C++
build --client_env=CC=clang
build --copt=-DGRPC_BAZEL_BUILD
build --cxxopt='-std=c++14'
build --action_env=GRPC_BAZEL_RUNTIME=1
build --define=use_fast_cpp_protos=true
# Just build tests when testing
test --build_tests_only
build --incompatible_strict_action_env=true
# Minimize what is downloaded
build:inmemory --experimental_inmemory_jdeps_files
build:inmemory --experimental_inmemory_dotd_files
# Minimize what is downloaded
build:toplevel --config=inmemory
build:toplevel --experimental_remote_download_outputs=toplevel
build --stamp=true

1
.bazelversion Normal file
View File

@ -0,0 +1 @@
5.4.0

1
.clang-format Normal file
View File

@ -0,0 +1 @@
BasedOnStyle: Google

1
.env Normal file
View File

@ -0,0 +1 @@
DATABASE_URL="postgres://postgres:postgres@localhost:5432/apollo2development?sslmode=disable"

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.idea
.ijwb
/.*.venv
.venv
*.pyc
bazel-*
__pycache__
node_modules

1
.npmrc Normal file
View File

@ -0,0 +1 @@
hoist=false

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"tabWidth": 2,
"singleQuote": true
}

432
.pylintrc Normal file
View File

@ -0,0 +1,432 @@
# This Pylint rcfile contains a best-effort configuration to uphold the
# best-practices and style described in the Google Python style guide:
# https://google.github.io/styleguide/pyguide.html
#
# Its canonical open-source location is:
# https://google.github.io/styleguide/pylintrc
[MASTER]
# Files or directories to be skipped. They should be base names, not paths.
ignore-paths=third_party
# Files or directories matching the regex patterns are skipped. The regex
# matches against base names, not paths.
ignore-patterns=^third_party/.*$,
^generated/.*$
# Pickle collected data for later comparisons.
persistent=no
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=tortoise.contrib.pylint
# Use multiple processes to speed up Pylint.
jobs=4
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=abstract-method,
apply-builtin,
arguments-differ,
attribute-defined-outside-init,
backtick,
bad-option-value,
basestring-builtin,
buffer-builtin,
c-extension-no-member,
consider-using-enumerate,
cmp-builtin,
cmp-method,
coerce-builtin,
coerce-method,
delslice-method,
div-method,
duplicate-code,
eq-without-hash,
execfile-builtin,
file-builtin,
filter-builtin-not-iterating,
fixme,
getslice-method,
global-statement,
hex-method,
idiv-method,
implicit-str-concat,
import-error,
import-self,
import-star-module-level,
inconsistent-return-statements,
input-builtin,
intern-builtin,
invalid-str-codec,
locally-disabled,
long-builtin,
long-suffix,
map-builtin-not-iterating,
misplaced-comparison-constant,
missing-function-docstring,
missing-module-docstring,
missing-class-docstring,
metaclass-assignment,
next-method-called,
next-method-defined,
no-absolute-import,
no-else-break,
no-else-continue,
no-else-raise,
no-else-return,
no-init, # added
no-member,
no-name-in-module,
no-self-use,
nonzero-method,
oct-method,
old-division,
old-ne-operator,
old-octal-literal,
old-raise-syntax,
parameter-unpacking,
print-statement,
raising-string,
range-builtin-not-iterating,
raw_input-builtin,
rdiv-method,
reduce-builtin,
relative-import,
reload-builtin,
round-builtin,
setslice-method,
signature-differs,
standarderror-builtin,
suppressed-message,
sys-max-int,
too-few-public-methods,
too-many-ancestors,
too-many-arguments,
too-many-boolean-expressions,
too-many-branches,
too-many-instance-attributes,
too-many-locals,
too-many-nested-blocks,
too-many-public-methods,
too-many-return-statements,
too-many-statements,
trailing-newlines,
unichr-builtin,
unicode-builtin,
unnecessary-pass,
unpacking-in-except,
useless-else-on-loop,
useless-object-inheritance,
useless-suppression,
using-cmp-argument,
wrong-import-order,
xrange-builtin,
zip-builtin-not-iterating,
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
[BASIC]
# Good variable names which should always be accepted, separated by a comma
good-names=main,_
# Bad variable names which should always be refused, separated by a comma
bad-names=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
# Regular expression matching correct function names
function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
# Regular expression matching correct variable names
variable-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct constant names
const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression matching correct attribute names
attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
# Regular expression matching correct argument names
argument-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct class attribute names
class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression matching correct inline iteration names
inlinevar-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct class names
class-rgx=^_?[A-Z][a-zA-Z0-9]*$
# Regular expression matching correct module names
module-rgx=^(_?[a-z][a-z0-9_]*|__init__|__main__)$
# Regular expression matching correct method names
method-rgx=(?x)^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=10
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=160
# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
# lines made too long by directives to pytype.
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=(?x)(
^\s*(\#\ )?<?https?://\S+>?$|
^\s*(from\s+\S+\s+)?import\s+.+$)
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=yes
# Maximum number of lines in a module
max-module-lines=99999
# String used as indentation unit. The internal Google style guide mandates 2
# spaces. Google's externaly-published style guide says 4, consistent with
# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google
# projects (like TensorFlow).
indent-string=' '
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=TODO
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=yes
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging,absl.logging,tensorflow.io.logging
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,
TERMIOS,
Bastion,
rexec,
sets
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant, absl
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls,
class_
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=StandardError,
Exception,
BaseException

3
.style.yapf Normal file
View File

@ -0,0 +1,3 @@
[style]
based_on_style = facebook
indent_width = 4

18
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"python.analysis.extraPaths": [
"bazel-bin",
".venv/lib/python3.9/site-packages"
],
"protoc": {
"options": ["--proto_path=third_party/googleapis"]
},
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.provider": "yapf",
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.formatOnSave": true,
"[python]": {
"editor.tabSize": 4
}
}

2
.yapfignore Normal file
View File

@ -0,0 +1,2 @@
generated/**/*.py
third_party/**/*.py

79
BUILD.bazel Normal file
View File

@ -0,0 +1,79 @@
load("@bazel_gazelle//:def.bzl", "gazelle", "gazelle_binary")
load("@pypi//:requirements.bzl", "all_whl_requirements")
load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS")
load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest")
load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")
load("@rules_python//python:defs.bzl", "py_runtime", "py_runtime_pair")
load("@rules_python//python/pip_install:requirements.bzl", "compile_pip_requirements")
load("@npm//:defs.bzl", "npm_link_all_packages")
# gazelle:prefix github.com/rocky-linux/peridot
# gazelle:go_generate_proto false
# gazelle:python_library_naming_convention $package_name$_lib
# gazelle:python_binary_naming_convention $package_name$
# gazelle:map_kind py_binary py_binary @aspect_rules_py//py:defs.bzl
# gazelle:map_kind py_library py_library @aspect_rules_py//py:defs.bzl
# gazelle:exclude *.venv
# gazelle:exclude third_party/googleapis
# gazelle:resolve py grpc @pypi_grpcio//:pkg
# gazelle:resolve py apollo.proto.v1.apollo_pb2_grpc //apollo/proto/v1:apollopb_py_pb2_grpc
gazelle_python_manifest(
name = "gazelle_python_manifest",
modules_mapping = ":modules_map",
pip_repository_name = "pypi",
requirements = "requirements_lock.txt",
)
gazelle_binary(
name = "gazelle_bin",
languages = [
"@bazel_gazelle//language/go",
"@bazel_gazelle//language/proto",
"@rules_python_gazelle_plugin//python",
],
)
gazelle(
name = "gazelle",
data = GAZELLE_PYTHON_RUNTIME_DEPS,
gazelle = ":gazelle_bin",
)
compile_pip_requirements(
name = "requirements",
extra_args = ["--allow-unsafe"],
requirements_in = "requirements.txt",
requirements_txt = "requirements_lock.txt",
)
modules_mapping(
name = "modules_map",
wheels = all_whl_requirements,
)
py_runtime(
name = "container_py3_runtime",
interpreter_path = "/usr/bin/python3",
python_version = "PY3",
)
py_runtime_pair(
name = "container_py_runtime_pair",
py2_runtime = None,
py3_runtime = ":container_py3_runtime",
)
toolchain(
name = "container_py_toolchain",
exec_compatible_with = [
"@io_bazel_rules_docker//platforms:run_in_container",
],
toolchain = ":container_py_runtime_pair",
toolchain_type = "@bazel_tools//tools/python:toolchain_type",
)
npm_link_all_packages(name = "node_modules")

217
WORKSPACE Normal file
View File

@ -0,0 +1,217 @@
workspace(
name = "depot",
)
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# Aspect Bazel Lib
http_archive(
name = "aspect_bazel_lib",
sha256 = "79623d656aa23ad3fd4692ab99786c613cd36e49f5566469ed97bc9b4c655f03",
strip_prefix = "bazel-lib-1.23.3",
url = "https://github.com/aspect-build/bazel-lib/archive/refs/tags/v1.23.3.tar.gz",
)
load("@aspect_bazel_lib//lib:repositories.bzl", "aspect_bazel_lib_dependencies", "register_copy_directory_toolchains", "register_copy_to_directory_toolchains")
aspect_bazel_lib_dependencies()
# Python
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "aspect_rules_py",
sha256 = "66da30b09cf47ee40f2ae1c46346cc9a412940965d04899bd68d06a9d3380085",
strip_prefix = "rules_py-0.1.0",
url = "https://github.com/aspect-build/rules_py/archive/refs/tags/v0.1.0.tar.gz",
)
# Fetches the rules_py dependencies.
# If you want to have a different version of some dependency,
# you should fetch it *before* calling this.
# Alternatively, you can skip calling this function, so long as you've
# already fetched all the dependencies.
load("@aspect_rules_py//py:repositories.bzl", "rules_py_dependencies")
http_archive(
name = "rules_python",
patch_args = ["-p1"],
patch_cmds = ["""\
cat >> python/BUILD.bazel <<EOF
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
bzl_library(
name = "defs",
srcs = [
":bzl",
"@bazel_tools//tools/python:srcs_version.bzl",
"@bazel_tools//tools/python:utils.bzl",
"@bazel_tools//tools/python:private/defs.bzl",
"@bazel_tools//tools/python:toolchain.bzl",
],
visibility = ["//visibility:public"],
)
EOF
"""],
patches = ["//build/patches:0001-Fix-Quart-and-Hypercorn-failing-to-install-with-rule.patch"],
sha256 = "8c15896f6686beb5c631a4459a3aa8392daccaab805ea899c9d14215074b60ef",
strip_prefix = "rules_python-0.17.3",
url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.17.3.tar.gz",
)
http_archive(
name = "rules_python_gazelle_plugin",
sha256 = "8c15896f6686beb5c631a4459a3aa8392daccaab805ea899c9d14215074b60ef",
strip_prefix = "rules_python-0.17.3/gazelle",
url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.17.3.tar.gz",
)
rules_py_dependencies()
# Load the Python toolchain for rules_docker
register_toolchains("//:container_py_toolchain")
load("@rules_python//python:repositories.bzl", "python_register_toolchains")
python_register_toolchains(
name = "python_toolchain",
python_version = "3.9",
)
load("@rules_python//python:pip.bzl", "pip_parse")
load("@python_toolchain//:defs.bzl", "interpreter")
pip_parse(
name = "pypi",
python_interpreter_target = interpreter,
requirements_lock = "//:requirements_lock.txt",
)
load("@pypi//:requirements.bzl", "install_deps")
install_deps()
# Go
http_archive(
name = "io_bazel_rules_go",
sha256 = "56d8c5a5c91e1af73eca71a6fab2ced959b67c86d12ba37feedb0a2dfea441a6",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.37.0/rules_go-v0.37.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.37.0/rules_go-v0.37.0.zip",
],
)
http_archive(
name = "bazel_gazelle",
sha256 = "448e37e0dbf61d6fa8f00aaa12d191745e14f07c31cabfa731f0c8e8a4f41b97",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.28.0/bazel-gazelle-v0.28.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.28.0/bazel-gazelle-v0.28.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")
go_rules_dependencies()
go_register_toolchains(version = "1.19.5")
gazelle_dependencies()
# Python Gazelle
load("@rules_python//gazelle:deps.bzl", _py_gazelle_deps = "gazelle_deps")
_py_gazelle_deps()
# Docker
http_archive(
name = "io_bazel_rules_docker",
sha256 = "b1e80761a8a8243d03ebca8845e9cc1ba6c82ce7c5179ce2b295cd36f7e394bf",
urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.25.0/rules_docker-v0.25.0.tar.gz"],
)
load(
"@io_bazel_rules_docker//repositories:repositories.bzl",
container_repositories = "repositories",
)
container_repositories()
load("@io_bazel_rules_docker//repositories:deps.bzl", container_deps = "deps")
container_deps()
# esbuild
http_archive(
name = "aspect_rules_esbuild",
sha256 = "f05e9a53ae4b394ca45742ac35f7e658a8ba32cba14b5d531b79466ae86dc7f0",
strip_prefix = "rules_esbuild-0.14.0",
url = "https://github.com/aspect-build/rules_esbuild/archive/refs/tags/v0.14.0.tar.gz",
)
######################
# rules_esbuild setup #
######################
# Fetches the rules_esbuild dependencies.
# If you want to have a different version of some dependency,
# you should fetch it *before* calling this.
# Alternatively, you can skip calling this function, so long as you've
# already fetched all the dependencies.
load("@aspect_rules_esbuild//esbuild:dependencies.bzl", "rules_esbuild_dependencies")
rules_esbuild_dependencies()
# Fetch and register node, if you haven't already
load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains")
nodejs_register_toolchains(
name = "node",
node_version = "18.11.0",
)
load("@aspect_rules_js//npm:npm_import.bzl", "npm_translate_lock")
npm_translate_lock(
name = "npm",
npmrc = "//:.npmrc",
pnpm_lock = "//:pnpm-lock.yaml",
verify_node_modules_ignored = "//:.bazelignore",
)
load("@npm//:repositories.bzl", "npm_repositories")
npm_repositories()
# Register a toolchain containing esbuild npm package and native bindings
load("@aspect_rules_esbuild//esbuild:repositories.bzl", "esbuild_register_toolchains")
esbuild_register_toolchains(
name = "esbuild",
esbuild_version = "0.16.7",
)
register_copy_directory_toolchains()
register_copy_to_directory_toolchains()
# Copybara
http_archive(
name = "com_github_google_copybara",
sha256 = "5ad1e07646025d69818cffd29a6b4869861242a0b4659570a222efe0a018c879",
strip_prefix = "copybara-2fc63380448609af90b5c2a46fd0f8655377cba5",
url = "https://github.com/google/copybara/archive/2fc63380448609af90b5c2a46fd0f8655377cba5.zip",
)
load("@com_github_google_copybara//:repositories.bzl", "copybara_repositories")
copybara_repositories()
load("@com_github_google_copybara//:repositories.maven.bzl", "copybara_maven_repositories")
copybara_maven_repositories()
load("@com_github_google_copybara//:repositories.go.bzl", "copybara_go_repositories")
copybara_go_repositories()

0
apollo/BUILD.bazel Normal file
View File

18
apollo/README.md Normal file
View File

@ -0,0 +1,18 @@
# Apollo
Errata mirroring and publishing system
# Features
* Mirror advisories published by Red Hat
* Supports EUS
* Supports x86_64, aarch64, ppc64, ppc64le and s390x
* Create custom advisories
* CVE indexer and lifecycle tracker (Only Red Hat Security Data API for now)
* Publish updateinfo to RPM repositories
* Support for Peridot and Koji build systems
# Requirements
* Redis
* PostgreSQL
* Gunicorn

View File

@ -0,0 +1,22 @@
load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library")
py_binary(
name = "cveindexer",
srcs = ["__main__.py"],
imports = ["../.."],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":cveindexer_lib",
"//common:common_lib",
"@pypi_click//:pkg",
"@pypi_temporalio//:pkg",
],
)
py_library(
name = "cveindexer_lib",
srcs = ["temporal.py"],
imports = ["../.."],
visibility = ["//:__subpackages__"],
)

View File

@ -0,0 +1,39 @@
"""
Apollo CVE Indexer
Only indexes Red Hat advisory CVEs for now.
"""
import asyncio
from temporalio.worker import Worker
import click
from common.database import Database
from common.info import Info
from common.temporal import Temporal
from apollo.cveindexer.temporal import TASK_QUEUE
async def run():
db = Database(True)
await db.init(["apollo.db"])
temporal = Temporal(True)
await temporal.connect()
worker = Worker(
temporal.client, task_queue=TASK_QUEUE, workflows=[], activities=[]
)
await worker.run()
@click.command()
def main():
Info("apollocveindexer", "apollo2")
asyncio.run(run())
if __name__ == "__main__":
main()

View File

@ -0,0 +1 @@
TASK_QUEUE = "v2-cveindexer"

9
apollo/db/BUILD.bazel Normal file
View File

@ -0,0 +1,9 @@
load("@aspect_rules_py//py:defs.bzl", "py_library")
py_library(
name = "db_lib",
srcs = ["__init__.py"],
imports = ["../.."],
visibility = ["//:__subpackages__"],
deps = ["@pypi_tortoise_orm//:pkg"],
)

356
apollo/db/__init__.py Normal file
View File

@ -0,0 +1,356 @@
import datetime
from tortoise.models import Model
from tortoise import fields
class Code(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
archived_at = fields.DatetimeField(null=True)
code = fields.CharField(max_length=255, unique=True)
description = fields.TextField()
supported_products: fields.ReverseRelation["SupportedProduct"]
class Meta:
table = "codes"
class SupportedProduct(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
eol_at = fields.DatetimeField(null=True)
name = fields.CharField(max_length=255, unique=True)
variant = fields.CharField(max_length=255)
code = fields.ForeignKeyField(
"models.Code",
related_name="supported_products",
)
vendor = fields.TextField()
rh_mirrors: fields.ReverseRelation["SupportedProductsRhMirror"]
advisory_packages: fields.ReverseRelation["AdvisoryPackage"]
advisory_affected_products: fields.ReverseRelation["AdvisoryAffectedProduct"
]
class Meta:
table = "supported_products"
class RedHatIndexState(Model):
id = fields.BigIntField(pk=True)
last_indexed_at = fields.DatetimeField(null=True)
class Meta:
table = "red_hat_index_state"
class RedHatAdvisory(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
red_hat_issued_at = fields.DatetimeField()
name = fields.CharField(max_length=255, unique=True)
synopsis = fields.TextField()
description = fields.TextField()
kind = fields.CharField(max_length=255)
severity = fields.CharField(max_length=255)
topic = fields.TextField()
packages: fields.ReverseRelation["RedHatAdvisoryPackage"]
cves: fields.ReverseRelation["RedHatAdvisoryCVE"]
bugzilla_tickets: fields.ReverseRelation["RedHatAdvisoryBugzillaBug"]
affected_products: fields.ReverseRelation["RedHatAdvisoryAffectedProduct"]
rpm_rh_overrides: fields.ReverseRelation["SupportedProductsRpmRhOverride"]
rh_blocks: fields.ReverseRelation["SupportedProductsRhBlock"]
published_advisories: fields.ReverseRelation["Advisory"]
class Meta:
table = "red_hat_advisories"
class PydanticMeta:
exclude = ("rpm_rh_overrides", "rh_blocks", "published_advisories")
class RedHatAdvisoryPackage(Model):
id = fields.BigIntField(pk=True)
red_hat_advisory = fields.ForeignKeyField(
"models.RedHatAdvisory",
related_name="packages",
)
nevra = fields.TextField()
class Meta:
table = "red_hat_advisory_packages"
unique_together = ("red_hat_advisory_id", "nevra")
class RedHatAdvisoryCVE(Model):
id = fields.BigIntField(pk=True)
red_hat_advisory = fields.ForeignKeyField(
"models.RedHatAdvisory",
related_name="cves",
)
cve = fields.TextField()
cvss3_scoring_vector = fields.TextField(null=True)
cvss3_base_score = fields.TextField(null=True)
cwe = fields.TextField(null=True)
class Meta:
table = "red_hat_advisory_cves"
unique_together = ("red_hat_advisory_id", "cve")
class RedHatAdvisoryBugzillaBug(Model):
id = fields.BigIntField(pk=True)
red_hat_advisory = fields.ForeignKeyField(
"models.RedHatAdvisory",
related_name="bugzilla_tickets",
)
bugzilla_bug_id = fields.TextField()
description = fields.TextField(null=True)
class Meta:
table = "red_hat_advisory_bugzilla_bugs"
unique_together = ("red_hat_advisory_id", "bugzilla_bug_id")
class RedHatAdvisoryAffectedProduct(Model):
id = fields.BigIntField(pk=True)
red_hat_advisory = fields.ForeignKeyField(
"models.RedHatAdvisory",
related_name="affected_products",
)
variant = fields.TextField()
name = fields.TextField()
major_version = fields.IntField()
minor_version = fields.IntField(null=True)
arch = fields.TextField()
class Meta:
table = "red_hat_advisory_affected_products"
unique_together = (
"red_hat_advisory_id", "variant", "name", "major_version",
"minor_version", "arch"
)
class User(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
archived_at = fields.DatetimeField(null=True)
email = fields.CharField(max_length=255, unique=True)
password = fields.CharField(max_length=255)
name = fields.CharField(max_length=255)
role = fields.CharField(max_length=255)
class Meta:
table = "users"
class PydanticMeta:
exclude = ("password", )
class Settings(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
name = fields.CharField(max_length=255, unique=True)
value = fields.TextField()
class Meta:
table = "settings"
class SupportedProductsRhMirror(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
supported_product = fields.ForeignKeyField(
"models.SupportedProduct",
related_name="rh_mirrors",
)
name = fields.CharField(max_length=255)
match_variant = fields.CharField(max_length=255)
match_major_version = fields.IntField()
match_minor_version = fields.IntField(null=True)
match_arch = fields.CharField(max_length=255)
rpm_repomds: fields.ReverseRelation["SupportedProductsRpmRepomd"]
rpm_rh_overrides: fields.ReverseRelation["SupportedProductsRpmRhOverride"]
rh_blocks: fields.ReverseRelation["SupportedProductsRhBlock"]
advisory_packages: fields.ReverseRelation["AdvisoryPackage"]
class Meta:
table = "supported_products_rh_mirrors"
class SupportedProductsRpmRepomd(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
supported_products_rh_mirror = fields.ForeignKeyField(
"models.SupportedProductsRhMirror",
related_name="rpm_repomds",
)
production = fields.BooleanField()
arch = fields.CharField(max_length=255)
url = fields.TextField()
debug_url = fields.TextField()
source_url = fields.TextField()
repo_name = fields.CharField(max_length=255)
class Meta:
table = "supported_products_rpm_repomds"
class SupportedProductsRpmRhOverride(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
supported_products_rh_mirror = fields.ForeignKeyField(
"models.SupportedProductsRhMirror",
related_name="rpm_rh_overrides",
)
red_hat_advisory = fields.ForeignKeyField(
"models.RedHatAdvisory",
related_name="rpm_rh_overrides",
)
class Meta:
table = "supported_products_rpm_rh_overrides"
class SupportedProductsRhBlock(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
supported_products_rh_mirror = fields.ForeignKeyField(
"models.SupportedProductsRhMirror",
related_name="rh_blocks",
)
red_hat_advisory = fields.ForeignKeyField(
"models.RedHatAdvisory",
related_name="rh_blocks",
)
class Meta:
table = "supported_products_rh_blocks"
class Advisory(Model):
id = fields.BigIntField(pk=True)
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True, null=True)
published_at = fields.DatetimeField()
name = fields.CharField(max_length=255, unique=True)
synopsis = fields.TextField()
description = fields.TextField()
kind = fields.CharField(max_length=255)
severity = fields.CharField(max_length=255)
topic = fields.TextField()
red_hat_advisory = fields.ForeignKeyField(
"models.RedHatAdvisory",
related_name="published_advisories",
)
packages: fields.ReverseRelation["AdvisoryPackage"]
cves: fields.ReverseRelation["AdvisoryCVE"]
fixes: fields.ReverseRelation["AdvisoryFix"]
affected_products: fields.ReverseRelation["AdvisoryAffectedProduct"]
class Meta:
table = "advisories"
class AdvisoryPackage(Model):
id = fields.BigIntField(pk=True)
advisory = fields.ForeignKeyField(
"models.Advisory",
related_name="packages",
)
nevra = fields.TextField()
checksum = fields.TextField()
checksum_type = fields.CharField(max_length=255)
module_context = fields.TextField(null=True)
module_name = fields.TextField(null=True)
module_stream = fields.TextField(null=True)
module_version = fields.TextField(null=True)
repo_name = fields.TextField()
package_name = fields.TextField()
product_name = fields.TextField()
supported_products_rh_mirror = fields.ForeignKeyField(
"models.SupportedProductsRhMirror",
related_name="advisory_packages",
)
supported_product = fields.ForeignKeyField(
"models.SupportedProduct",
related_name="advisory_packages",
)
class Meta:
table = "advisory_packages"
unique_together = ("advisory_id", "nevra")
class AdvisoryCVE(Model):
id = fields.BigIntField(pk=True)
advisory = fields.ForeignKeyField(
"models.Advisory",
related_name="cves",
)
cve = fields.TextField()
cvss3_scoring_vector = fields.TextField(null=True)
cvss3_base_score = fields.TextField(null=True)
cwe = fields.TextField(null=True)
class Meta:
table = "advisory_cves"
unique_together = ("advisory_id", "cve")
class AdvisoryFix(Model):
id = fields.BigIntField(pk=True)
advisory = fields.ForeignKeyField(
"models.Advisory",
related_name="fixes",
)
ticket_id = fields.TextField()
source = fields.TextField()
description = fields.TextField(null=True)
class Meta:
table = "advisory_fixes"
unique_together = ("advisory_id", "ticket_id")
class AdvisoryAffectedProduct(Model):
id = fields.BigIntField(pk=True)
advisory = fields.ForeignKeyField(
"models.Advisory",
related_name="affected_products",
)
variant = fields.TextField()
name = fields.TextField()
major_version = fields.IntField()
minor_version = fields.IntField(null=True)
arch = fields.TextField()
supported_product = fields.ForeignKeyField(
"models.SupportedProduct",
related_name="advisory_affected_products",
)
class Meta:
table = "advisory_affected_products"
unique_together = (
"advisory_id",
"variant",
"name",
"major_version",
"minor_version",
"arch",
)

View File

@ -0,0 +1,13 @@
load("@aspect_rules_py//py:defs.bzl", "py_library")
py_library(
name = "serialize_lib",
srcs = ["__init__.py"],
imports = ["../../.."],
visibility = ["//:__subpackages__"],
deps = [
"//apollo/db:db_lib",
"@pypi_pydantic//:pkg",
"@pypi_tortoise_orm//:pkg",
],
)

View File

@ -0,0 +1,102 @@
import datetime
from typing import Optional
from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator
from pydantic import BaseModel
from apollo import db
RedHatAdvisoryCVE_Pydantic = pydantic_model_creator(
db.RedHatAdvisoryCVE,
name="RedHatAdvisoryCVE",
)
RedHatAdvisoryBugzillaBug_Pydantic = pydantic_model_creator(
db.RedHatAdvisoryBugzillaBug,
name="RedHatAdvisoryBugzillaBug",
)
RedHatAdvisoryAffectedProduct_Pydantic = pydantic_model_creator(
db.RedHatAdvisoryAffectedProduct,
name="RedHatAdvisoryAffectedProduct",
)
RedHatAdvisoryPackage_Pydantic = pydantic_model_creator(
db.RedHatAdvisoryPackage,
name="RedHatAdvisoryPackage",
)
RedHatAdvisory_Pydantic = pydantic_model_creator(
db.RedHatAdvisory,
name="RedHatAdvisory",
)
AdvisoryCVE_Pydantic = pydantic_model_creator(
db.AdvisoryCVE,
name="AdvisoryCVE",
)
AdvisoryFix_Pydantic = pydantic_model_creator(
db.AdvisoryFix,
name="AdvisoryFix",
)
AdvisoryAffectedProduct_Pydantic = pydantic_model_creator(
db.AdvisoryAffectedProduct,
name="AdvisoryAffectedProduct",
)
AdvisoryPackage_Pydantic = pydantic_model_creator(
db.AdvisoryPackage,
name="AdvisoryPackage",
)
Advisory_Pydantic = pydantic_model_creator(
db.Advisory,
name="Advisory",
exclude=(
"red_hat_advisory",
"packages.supported_product",
"packages.supported_product_id",
"packages.supported_products_rh_mirror",
"packages.supported_products_rh_mirror_id",
"cves.advisory",
"cves.advisory_id",
"fixes.advisory",
"fixes.advisory_id",
"affected_products.advisory",
"affected_products.advisory_id",
),
)
# Legacy API models
# pylint: disable=invalid-name
class Advisory_Pydantic_V2_Fix(BaseModel):
ticket: str
sourceBy: str
sourceLink: str
description: str
class Advisory_Pydantic_V2_CVE(BaseModel):
name: str
sourceBy: str
sourceLink: str
cvss3ScoringVector: str
cvss3BaseScore: str
cwe: str
class Advisory_Pydantic_V2(BaseModel):
type: str
shortCode: str
name: str
synopsis: str
severity: str
topic: str
description: str
solution: Optional[str]
affectedProducts: list[str]
fixes: list[Advisory_Pydantic_V2_Fix]
cves: list[Advisory_Pydantic_V2_CVE]
references: list[str]
publishedAt: datetime.datetime
rpms: dict[str, list[str]]
rebootSuggested: bool
buildReferences: list[str]
class Config:
orm_mode = True

View File

@ -0,0 +1,272 @@
-- migrate:up
create table codes (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
archived_at timestamp,
code text not null,
description text not null
);
create table supported_products (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
eol_at timestamptz,
variant text not null,
name text not null unique,
vendor text not null,
code_id bigint references codes(id)
);
create index supported_products_eol_atx on supported_products(eol_at);
create index supported_products_variantx on supported_products(variant);
create index supported_products_namex on supported_products(name);
create table red_hat_index_state (
id bigserial primary key,
last_indexed_at timestamptz
);
create table red_hat_advisories (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
red_hat_issued_at timestamptz not null,
name text not null unique,
synopsis text not null,
description text not null,
kind text not null,
severity text not null,
topic text not null
);
create index red_hat_advisories_red_hat_issued_atx on red_hat_advisories(red_hat_issued_at);
create index red_hat_advisories_namex on red_hat_advisories(name);
create index red_hat_advisories_synopsisx on red_hat_advisories(synopsis);
create index red_hat_advisories_kindx on red_hat_advisories(kind);
create index red_hat_advisories_severityx on red_hat_advisories(severity);
create table red_hat_advisory_packages (
id bigserial primary key,
red_hat_advisory_id bigint references red_hat_advisories(id) on delete cascade,
nevra text not null,
unique (red_hat_advisory_id, nevra)
);
create index red_hat_advisory_packages_nevrax on red_hat_advisory_packages(nevra);
create table red_hat_advisory_cves (
id bigserial primary key,
red_hat_advisory_id bigint references red_hat_advisories(id) on delete cascade,
cve text not null,
cvss3_scoring_vector text,
cvss3_base_score text,
cwe text,
unique (red_hat_advisory_id, cve)
);
create index red_hat_advisory_cvex on red_hat_advisory_cves(cve);
create table red_hat_advisory_bugzilla_bugs (
id bigserial primary key,
red_hat_advisory_id bigint references red_hat_advisories(id) on delete cascade,
bugzilla_bug_id text not null,
description text not null,
unique (red_hat_advisory_id, bugzilla_bug_id)
);
create index red_hat_advisory_bugzilla_bugs_bugzilla_bug_idx on red_hat_advisory_bugzilla_bugs(bugzilla_bug_id);
create table red_hat_advisory_affected_products (
id bigserial primary key,
red_hat_advisory_id bigint references red_hat_advisories(id) on delete cascade,
variant text not null,
name text not null,
major_version numeric not null,
minor_version numeric,
arch text not null,
unique (red_hat_advisory_id, variant, name, major_version, minor_version, arch)
);
create index red_hat_advisory_affected_products_variantx on red_hat_advisory_affected_products(variant);
create index red_hat_advisory_affected_products_namex on red_hat_advisory_affected_products(name);
create index red_hat_advisory_affected_products_major_versionx on red_hat_advisory_affected_products(major_version);
create index red_hat_advisory_affected_products_minor_versionx on red_hat_advisory_affected_products(minor_version);
create index red_hat_advisory_affected_products_archx on red_hat_advisory_affected_products(arch);
create unique index red_hat_advisory_affected_products_variant_namex on red_hat_advisory_affected_products(red_hat_advisory_id, variant, name, major_version, minor_version, arch) where minor_version is not null;
create unique index red_hat_advisory_affected_products_variant_namenx on red_hat_advisory_affected_products(red_hat_advisory_id, variant, name, major_version, minor_version, arch) where minor_version is null;
insert into red_hat_index_state (last_indexed_at) values ('2019-05-06');
create table users (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
archived_at timestamp,
email text not null unique,
password text not null,
name text not null,
role text not null
);
create table settings (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
name text not null unique,
value text not null
);
create index settings_namex on settings(name);
create table events (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
archived_at timestamp,
description text not null,
user_id bigint references users(id) on delete set null
);
create table supported_products_rh_mirrors (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
supported_product_id bigint references supported_products(id) on delete cascade,
name text not null,
match_variant text not null,
match_major_version numeric not null,
match_minor_version numeric,
match_arch text not null
);
create index supported_products_rh_mirrors_supported_product_idx on supported_products_rh_mirrors(supported_product_id);
create index supported_products_rh_mirrors_match_variant_idx on supported_products_rh_mirrors(match_variant);
create index supported_products_rh_mirrors_match_major_version_idx on supported_products_rh_mirrors(match_major_version);
create index supported_products_rh_mirrors_match_minor_version_idx on supported_products_rh_mirrors(match_minor_version);
create index supported_products_rh_mirrors_match_arch_idx on supported_products_rh_mirrors(match_arch);
create table supported_products_rpm_repomds (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
supported_products_rh_mirror_id bigint references supported_products_rh_mirrors(id) on delete cascade,
production boolean not null,
arch text not null,
url text not null,
debug_url text not null,
source_url text not null,
repo_name text not null
);
create index supported_products_rpm_repomds_supporteds_rh_mirror_idx on supported_products_rpm_repomds(supported_products_rh_mirror_id);
create index supported_products_rpm_repomds_production_idx on supported_products_rpm_repomds(production);
create index supported_products_rpm_repomds_arch_idx on supported_products_rpm_repomds(arch);
create table supported_products_rpm_rh_overrides (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
supported_products_rh_mirror_id bigint references supported_products_rh_mirrors(id) on delete cascade,
red_hat_advisory_id bigint references red_hat_advisories(id) on delete cascade
);
create index supported_products_rpm_rh_overrides_supported_products_rh_mirror_idx on supported_products_rpm_rh_overrides(supported_products_rh_mirror_id);
create index supported_products_rpm_rh_overrides_red_hat_advisory_idx on supported_products_rpm_rh_overrides(red_hat_advisory_id);
create table supported_products_rh_blocks (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
supported_products_rh_mirror_id bigint references supported_products_rh_mirrors(id) on delete cascade,
red_hat_advisory_id bigint references red_hat_advisories(id) on delete cascade,
unique (supported_products_rh_mirror_id, red_hat_advisory_id)
);
create index supported_products_rh_blocks_supported_products_rh_mirror_idx on supported_products_rh_blocks(supported_products_rh_mirror_id);
create index supported_products_rh_blocks_red_hat_advisory_idx on supported_products_rh_blocks(red_hat_advisory_id);
create table advisories (
id bigserial primary key,
created_at timestamptz not null default now(),
updated_at timestamptz,
published_at timestamptz,
name text not null unique,
synopsis text not null,
description text not null,
kind text not null,
severity text not null,
topic text not null,
red_hat_advisory_id bigint references red_hat_advisories(id) on delete cascade
);
create index advisories_published_atx on advisories(published_at);
create index advisories_namex on advisories(name);
create index advisories_synopsisx on advisories(synopsis);
create index advisories_kindx on advisories(kind);
create index advisories_severityx on advisories(severity);
create index advisories_red_hat_advisory_id on advisories(red_hat_advisory_id);
create table advisory_packages (
id bigserial primary key,
advisory_id bigint references advisories(id) on delete cascade,
nevra text not null,
checksum text not null,
checksum_type text not null,
module_context text,
module_name text,
module_stream text,
module_version text,
repo_name text not null,
package_name text not null,
supported_products_rh_mirror_id bigint references supported_products_rh_mirrors(id) on delete cascade,
supported_product_id bigint references supported_products(id) on delete cascade,
product_name text not null,
unique (advisory_id, nevra, repo_name, supported_products_rh_mirror_id)
);
create index advisory_packages_advisory_id on advisory_packages(advisory_id);
create index advisory_packages_nevrax on advisory_packages(nevra);
create index advisory_packages_checksumx on advisory_packages(checksum);
create index advisory_packages_supported_products_rh_mirror_idx on advisory_packages(supported_products_rh_mirror_id);
create index advisory_packages_supported_product_idx on advisory_packages(supported_product_id);
create index advisory_packages_product_name_idx on advisory_packages(product_name);
create table advisory_cves (
id bigserial primary key,
advisory_id bigint references advisories(id) on delete cascade,
cve text not null,
cvss3_scoring_vector text,
cvss3_base_score text,
cwe text,
unique (advisory_id, cve)
);
create index advisory_cvex on advisory_cves(cve);
create table advisory_fixes (
id bigserial primary key,
advisory_id bigint references advisories(id) on delete cascade,
ticket_id text not null,
source text not null,
description text,
unique (advisory_id, ticket_id)
);
create index advisory_fixes_advisory_id on advisory_fixes(advisory_id);
create index advisory_fixes_ticket_id on advisory_fixes(ticket_id);
create table advisory_affected_products (
id bigserial primary key,
advisory_id bigint references advisories(id) on delete cascade,
variant text not null,
name text not null,
major_version numeric not null,
minor_version numeric,
arch text not null,
supported_product_id bigint references supported_products(id) on delete cascade,
unique (advisory_id, name)
);
create index advisory_affected_products_variantx on advisory_affected_products(variant);
create index advisory_affected_products_namex on advisory_affected_products(name);
create index advisory_affected_products_major_versionx on advisory_affected_products(major_version);
create index advisory_affected_products_minor_versionx on advisory_affected_products(minor_version);
create index advisory_affected_products_archx on advisory_affected_products(arch);
create index advisory_affected_products_supported_product_idx on advisory_affected_products(supported_product_id);
-- migrate:down

View File

@ -0,0 +1,15 @@
load("@aspect_rules_py//py:defs.bzl", "py_library")
# gazelle:exclude example.py
py_library(
name = "rherrata_lib",
srcs = ["__init__.py"],
imports = ["../.."],
visibility = ["//:__subpackages__"],
deps = [
"@pypi_aiohttp//:pkg",
"@pypi_dataclass_wizard//:pkg",
"@pypi_yarl//:pkg",
],
)

195
apollo/rherrata/__init__.py Normal file
View File

@ -0,0 +1,195 @@
# pylint: disable=invalid-name
"""
This module provides a Python interface to the Red Hat Errata API.
"""
from __future__ import annotations
from enum import Enum
from dataclasses import dataclass
from urllib.parse import quote
import aiohttp
from dataclass_wizard import JSONWizard
from yarl import URL
DEFAULT_URL = "https://access.redhat.com/hydra/rest/search/kcs"
class DocumentKind(str, Enum):
"""
The kind of document.
"""
ERRATA = "Errata"
class Distro(str, Enum):
"""
The distribution.
"""
RHEL = "Red Hat Enterprise Linux"
class Architecture(str, Enum):
"""
The architecture.
"""
X86_64 = "x86_64"
AARCH64 = "aarch64"
PPC64 = "ppc64"
PPC64LE = "ppc64le"
S390X = "s390x"
@dataclass
class PortalProduct:
"""
Red Hat advisory product
"""
variant: str
name: str
major_version: int
minor_version: int
arch: str
@dataclass
class Advisory(JSONWizard):
"""
An advisory.
"""
documentKind: str = None
uri: str = None
view_uri: str = None
language: str = None
id: str = None
portal_description: str = None
abstract: str = None
allTitle: str = None
sortTitle: str = None
portal_title: list[str] = None
lastModifiedDate: str = None
displayDate: str = None
portal_advisory_type: str = None
portal_synopsis: str = None
portal_severity: str = None
portal_type: str = None
portal_package: list[str] = None
portal_CVE: list[str] = None
portal_BZ: list[str] = None
portal_publication_date: str = None
portal_requires_subscription: str = None
portal_product_names: list[str] = None
title: str = None
portal_child_ids: list[str] = None
portal_product_filter: list[str] = None
boostProduct: str = None
boostVersion: int = None
detectedProducts: list[str] = None
caseCount: int = None
caseCount_365: int = None
timestamp: str = None
body: list[str] = None
_version_: int = None
__products: list[PortalProduct] = None
def get_products(self) -> list[PortalProduct]:
if self.__products:
return self.__products
self.__products = []
for product in self.portal_product_filter:
try:
if product.startswith("Red Hat Enterprise Linux"):
variant, name, version, arch = product.split("|")
major_version = version
if "." in version:
version_split = version.split(".")
major_version = int(version_split[0])
minor_version = int(version_split[1])
else:
major_version = int(version)
minor_version = None
self.__products.append(
PortalProduct(
variant, name, major_version, minor_version, arch
)
)
except ValueError:
pass
return self.__products
def affects_rhel_version_arch(
self, major_version: int, minor_version: int | None, arch: Architecture
) -> bool:
"""
Returns whether this advisory affects the given RHEL version and architecture.
"""
for product in self.get_products():
if product.variant == "Red Hat Enterprise Linux" and product.major_version == major_version and product.minor_version == minor_version and product.arch == arch.value:
return True
return False
class API:
"""
The Red Hat Errata API.
"""
url = None
def __init__(self, url=DEFAULT_URL):
if not url:
url = DEFAULT_URL
self.url = url
async def search(
self,
kind: DocumentKind = DocumentKind.ERRATA,
sort_asc: bool = False,
rows: int = 10,
query: str = "*:*",
distro: str = "Red%5C+Hat%5C+Enterprise%5C+Linux%7C%2A%7C%2A%7C%2A",
detected_product: str = "rhel",
from_date: str = None
) -> list[Advisory]:
params = ""
# Set query
params += f"q={query}"
# Set rows
params += f"&rows={rows}"
# Set sorting
sorting = "portal_publication_date+asc" if sort_asc else "portal_publication_date+desc"
params += f"&sort={sorting}"
# Set start
params += "&start=0"
# Set distribution
params += f"&fq=portal_product_filter:{distro}"
# Set from-to
if from_date:
params += f"&fq=portal_publication_date%3A%5B{quote(from_date)}%20TO%20NOW%5D"
# Set document kind
params += f"&fq=documentKind:{kind.value}"
# Set detected product
if detected_product:
params += f"&fq=detectedProducts:{detected_product}"
async with aiohttp.ClientSession() as session:
async with session.get(
URL(f"{self.url}?{params}", encoded=True)
) as response:
body = await response.json()
if response.status != 200:
raise Exception((await response.text()))
elif body.get("response", {}).get("numFound", 0) == 0:
return []
return Advisory.from_list(list(body["response"]["docs"]))

View File

@ -0,0 +1,34 @@
import asyncio
import datetime
from __init__ import API, Architecture
async def main():
api = API()
res = await api.search(
detected_product="rhel",
rows=1000,
from_date="2019-05-05T22:00:00Z",
sort_asc=True
)
contains_9 = 0
contains_8 = 0
contains_90eus = 0
for advisory in res:
if advisory.affects_rhel_version_arch(9, None, Architecture.X86_64):
print(f"{advisory.id} affects RHEL 9 x86_64")
contains_9 += 1
elif advisory.affects_rhel_version_arch(9, 0, Architecture.X86_64):
print(f"{advisory.id} affects RHEL 9.0 EUS x86_64")
contains_90eus += 1
elif advisory.affects_rhel_version_arch(8, None, Architecture.X86_64):
print(f"{advisory.id} affects RHEL 8 x86_64")
contains_8 += 1
print(f"Found {contains_9} advisories that affect RHEL 9 x86_64")
print(f"Found {contains_8} advisories that affect RHEL 8 x86_64")
print(f"Found {contains_90eus} advisories that affect RHEL 9.0 EUS x86_64")
print(f"Found {len(res)} advisories in total")
if __name__ == "__main__":
asyncio.run(main())

View File

@ -0,0 +1,14 @@
load("@aspect_rules_py//py:defs.bzl", "py_library")
# gazelle:exclude example.py
py_library(
name = "rhwebscraper_lib",
srcs = ["__init__.py"],
imports = ["../.."],
visibility = ["//:__subpackages__"],
deps = [
"@pypi_aiohttp//:pkg",
"@pypi_beautifulsoup4//:pkg",
],
)

View File

@ -0,0 +1,50 @@
from typing import Optional
from dataclasses import dataclass
import aiohttp
from bs4 import BeautifulSoup
@dataclass
class RHWebAdvisoryFix:
id: str
description: str
@dataclass
class PartialRHWebAdvisory:
name: str
topic: Optional[str]
fixes: Optional[list[RHWebAdvisoryFix]]
async def get_advisory_topic_and_fixes(
advisory_name: str
) -> Optional[PartialRHWebAdvisory]:
async with aiohttp.ClientSession() as session:
async with session.get(
f"https://access.redhat.com/errata/{advisory_name}"
) as response:
if response.status == 200:
html = await response.text()
soup = BeautifulSoup(html, "html.parser")
topic = soup.select("div#topic > p")
if topic:
topic = "\n\n".join([p.text for p in topic])
parsed_fixes = []
fixes = soup.select("div#fixes > ul > li")
if fixes:
for fix in fixes:
bugzilla_id = fix.find("a").attrs.get("href"
).split("id=")[1]
description = fix.find("a").next_sibling.text.strip(
).removeprefix("- ")
parsed_fixes.append(
RHWebAdvisoryFix(bugzilla_id, description)
)
return PartialRHWebAdvisory(advisory_name, topic, parsed_fixes)
else:
return None

View File

@ -0,0 +1,12 @@
import asyncio
from __init__ import get_advisory_topic_and_fixes
async def main():
advisory = await get_advisory_topic_and_fixes("RHSA-2023:0536")
print(advisory)
if __name__ == "__main__":
asyncio.run(main())

View File

@ -0,0 +1,35 @@
load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library")
py_binary(
name = "rhworker",
srcs = ["__main__.py"],
imports = ["../.."],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":rhworker_lib",
"//common:common_lib",
"@pypi_click//:pkg",
"@pypi_temporalio//:pkg",
],
)
py_library(
name = "rhworker_lib",
srcs = [
"poll_rh_activities.py",
"poll_rh_workflow.py",
"temporal.py",
],
imports = ["../.."],
visibility = ["//:__subpackages__"],
deps = [
"//apollo/db:db_lib",
"//apollo/rherrata:rherrata_lib",
"//apollo/rhwebscraper:rhwebscraper_lib",
"//common:common_lib",
"@pypi_aiohttp//:pkg",
"@pypi_temporalio//:pkg",
"@pypi_tortoise_orm//:pkg",
],
)

View File

@ -0,0 +1,51 @@
"""
Apollo RH Temporal Worker
This worker only executes tasks that are related to Red Hat.
"""
import asyncio
from temporalio.worker import Worker
import click
from common.database import Database
from common.info import Info
from common.logger import Logger
from common.temporal import Temporal
from apollo.rhworker.temporal import TASK_QUEUE
from apollo.rhworker.poll_rh_workflow import PollRHAdvisoriesWorkflow
from apollo.rhworker.poll_rh_activities import get_last_indexed_date, get_rh_advisories
async def run():
db = Database(True)
await db.init(["apollo.db"])
temporal = Temporal(True)
await temporal.connect()
worker = Worker(
temporal.client,
task_queue=TASK_QUEUE,
workflows=[
PollRHAdvisoriesWorkflow,
],
activities=[
get_last_indexed_date,
get_rh_advisories,
]
)
await worker.run()
@click.command()
def main():
Info("apollorhworker", "apollo2")
Logger()
asyncio.run(run())
if __name__ == "__main__":
main()

View File

@ -0,0 +1,230 @@
import datetime
import re
import bz2
from typing import Optional
from xml.etree import ElementTree as ET
import aiohttp
from temporalio import activity
from tortoise.transactions import in_transaction
from apollo.db import RedHatIndexState, RedHatAdvisory, RedHatAdvisoryPackage
from apollo.db import RedHatAdvisoryBugzillaBug, RedHatAdvisoryAffectedProduct, RedHatAdvisoryCVE
from apollo.rherrata import API
from common.logger import Logger
OVAL_NS = {"": "http://oval.mitre.org/XMLSchema/oval-definitions-5"}
bz_re = re.compile(r"BZ#([0-9]+)")
def parse_red_hat_date(rhdate: str) -> datetime.datetime:
return datetime.datetime.fromisoformat(rhdate.removesuffix("Z"))
@activity.defn
async def get_last_indexed_date() -> Optional[str]:
state = await RedHatIndexState.get_or_none()
return re.sub(
r"\+\d\d:\d\d", "",
state.last_indexed_at.isoformat("T") + "Z"
) if state else None
async def fetch_mapped_oval() -> dict[str, ET.ElementTree]:
# Download the oval_url using aiohttp, decompress using bzip and parse
oval_url = "https://access.redhat.com/security/data/oval/com.redhat.rhsa-all.xml.bz2"
async with aiohttp.ClientSession() as session:
async with session.get(oval_url) as response:
if response.status == 200:
data = await response.read()
tree = ET.fromstring(bz2.decompress(data))
# Index by advisory name
def_map = {}
definitions = tree.findall("definitions/definition", OVAL_NS)
for definition in definitions:
def_id = definition.attrib["id"]
id_split = def_id.split(":")
name = f"{id_split[1].split('.')[2].upper()}-{id_split[3][0:4]}:{id_split[3][4:]}"
def_map[name] = definition
return def_map
else:
raise Exception("Failed to fetch OVAL data")
@activity.defn
async def get_rh_advisories(from_timestamp: str = None) -> None:
logger = Logger()
advisories = await API().search(
from_date=from_timestamp, rows=10000, sort_asc=True
)
oval = await fetch_mapped_oval()
for advisory in advisories:
async with in_transaction():
advisory_last_indexed_at = parse_red_hat_date(
advisory.portal_publication_date
)
state = await RedHatIndexState.first()
if state:
state.last_indexed_at = advisory_last_indexed_at
await state.save()
else:
await RedHatIndexState().create(
last_index_at=advisory_last_indexed_at
)
logger.info("Processing advisory %s", advisory.id)
existing_advisory = await RedHatAdvisory.filter(name=advisory.id
).get_or_none()
if existing_advisory:
logger.info("Advisory %s already exists, skipping", advisory.id)
continue
kind = "Security"
if "Enhancement" in advisory.portal_advisory_type:
kind = "Enhancement"
elif "Bug Fix" in advisory.portal_advisory_type:
kind = "Bug Fix"
issued_at = parse_red_hat_date(advisory.portal_publication_date)
severity = advisory.portal_severity
if not severity or severity == "":
severity = "None"
ra = await RedHatAdvisory.create(
name=advisory.id,
red_hat_issued_at=issued_at,
synopsis=advisory.portal_synopsis,
description=advisory.portal_description,
kind=kind,
severity=severity,
topic="",
)
if advisory.portal_package:
await RedHatAdvisoryPackage.bulk_create(
[
RedHatAdvisoryPackage(
**{
"red_hat_advisory_id": ra.id,
"nevra": nevra
}
) for nevra in advisory.portal_package
],
ignore_conflicts=True
)
if advisory.portal_CVE:
cves_to_save = []
definition = oval.get(advisory.id)
if not definition:
# Fill in CVEs from Errata
for advisory_cve in advisory.portal_CVE:
cves_to_save.append(
RedHatAdvisoryCVE(
**{
"red_hat_advisory_id": ra.id,
"cve": advisory_cve,
"cvss3_scoring_vector": "UNKNOWN",
"cvss3_base_score": "UNKNOWN",
"cwe": "UNKNOWN",
}
)
)
else:
# Fetch CVEs from the OVAL
cves = definition.findall("metadata/advisory/cve", OVAL_NS)
for cve in cves:
cvss3_scoring_vector = "UNKNOWN"
cvss3_base_score = "UNKNOWN"
cvss3 = cve.attrib.get("cvss3")
if cvss3:
cvss3_raw = cvss3.split("/", 1)
cvss3_scoring_vector = cvss3_raw[
1] if cvss3_raw else "UNKNOWN"
cvss3_base_score = cvss3_raw[
0] if cvss3_raw else "UNKNOWN"
cwe = cve.attrib.get("cwe")
if not cwe:
cwe = "UNKNOWN"
cves_to_save.append(
RedHatAdvisoryCVE(
**{
"red_hat_advisory_id":
ra.id,
"cve":
cve.text,
"cvss3_scoring_vector":
cvss3_scoring_vector,
"cvss3_base_score":
cvss3_base_score,
"cwe":
cwe,
}
)
)
if not cves_to_save:
raise Exception(f"Failed to find CVEs for {advisory.id}")
await RedHatAdvisoryCVE.bulk_create(
cves_to_save,
ignore_conflicts=True,
)
if advisory.portal_BZ:
bz_map = {}
if advisory.portal_description:
for line in advisory.portal_description.splitlines():
search = bz_re.search(line)
if search:
bz_id = search.group(1)
bz_line = line.removeprefix("* ")
bz_line = line.removeprefix("* ")
bz_line = line.removeprefix("- ")
bz_line = line.replace(f"(BZ#{bz_id})", "")
bz_line = bz_line.strip()
bz_map[bz_id] = bz_line
await RedHatAdvisoryBugzillaBug.bulk_create(
[
RedHatAdvisoryBugzillaBug(
**{
"red_hat_advisory_id": ra.id,
"bugzilla_bug_id": bugzilla_bug_id,
"description": bz_map.get(bugzilla_bug_id, ""),
}
) for bugzilla_bug_id in advisory.portal_BZ
],
ignore_conflicts=True
)
affected_products = advisory.get_products()
if affected_products:
await RedHatAdvisoryAffectedProduct.bulk_create(
[
RedHatAdvisoryAffectedProduct(
**{
"red_hat_advisory_id": ra.id,
"variant": product.variant,
"name": product.name,
"major_version": product.major_version,
"minor_version": product.minor_version,
"arch": product.arch
}
) for product in affected_products
],
ignore_conflicts=True
)
logger.info("Processed advisory %s", advisory.id)
return None

View File

@ -0,0 +1,24 @@
import datetime
from temporalio import workflow
@workflow.defn
class PollRHAdvisoriesWorkflow:
"""
Polls Red Hat Errata for new advisories.
"""
@workflow.run
async def run(self) -> None:
from_timestamp = await workflow.execute_activity(
"get_last_indexed_date",
start_to_close_timeout=datetime.timedelta(seconds=20),
)
await workflow.execute_activity(
"get_rh_advisories",
from_timestamp,
start_to_close_timeout=datetime.timedelta(hours=2),
)
return None

View File

@ -0,0 +1 @@
TASK_QUEUE = "v2-rhworker"

View File

@ -0,0 +1,35 @@
load("@aspect_rules_py//py:defs.bzl", "py_binary", "py_library")
py_library(
name = "rpmworker_lib",
srcs = [
"repomd.py",
"rh_matcher_activities.py",
"rh_matcher_workflows.py",
"temporal.py",
],
imports = ["../.."],
visibility = ["//:__subpackages__"],
deps = [
"//apollo/db:db_lib",
"//common:common_lib",
"@pypi_aiohttp//:pkg",
"@pypi_pyyaml//:pkg",
"@pypi_temporalio//:pkg",
"@pypi_tortoise_orm//:pkg",
],
)
py_binary(
name = "rpmworker",
srcs = ["__main__.py"],
imports = ["../.."],
main = "__main__.py",
visibility = ["//:__subpackages__"],
deps = [
":rpmworker_lib",
"//common:common_lib",
"@pypi_click//:pkg",
"@pypi_temporalio//:pkg",
],
)

View File

@ -0,0 +1,51 @@
"""
Apollo RPM Temporal Worker
This worker only executes tasks that are related to RPMs.
"""
import asyncio
from temporalio.worker import Worker
import click
from apollo.rpmworker.rh_matcher_workflows import RhMatcherWorkflow, RhDefunctWorkflow
from apollo.rpmworker.rh_matcher_activities import get_supported_products_with_rh_mirrors, match_rh_repos, block_remaining_rh_advisories
from apollo.rpmworker.temporal import TASK_QUEUE
from common.database import Database
from common.info import Info
from common.temporal import Temporal
async def run():
db = Database(True)
await db.init(["apollo.db"])
temporal = Temporal(True)
await temporal.connect()
worker = Worker(
temporal.client,
task_queue=TASK_QUEUE,
workflows=[
RhMatcherWorkflow,
RhDefunctWorkflow,
],
activities=[
get_supported_products_with_rh_mirrors,
match_rh_repos,
block_remaining_rh_advisories,
]
)
await worker.run()
@click.command()
def main():
Info("apollorpmworker", "apollo2")
asyncio.run(run())
if __name__ == "__main__":
main()

116
apollo/rpmworker/repomd.py Normal file
View File

@ -0,0 +1,116 @@
import gzip
import lzma
import re
from xml.etree import ElementTree as ET
from urllib.parse import urlparse
from os import path
import aiohttp
import yaml
from common.logger import Logger
NVRA_RE = re.compile(
r"^(\S+)-([\w~%.+]+)-(\w+(?:\.[\w~%+]+)+?)(?:\.(\w+))?(?:\.rpm)?$"
)
DIST_RE = re.compile(r"(\.el\d(?:_\d|))")
MODULE_DIST_RE = re.compile(r"\.module.+$")
def clean_nvra_pkg(matching_pkg: ET.Element) -> str:
name = matching_pkg.find("{http://linux.duke.edu/metadata/common}name").text
version = matching_pkg.find(
"{http://linux.duke.edu/metadata/common}version"
).attrib["ver"]
release = matching_pkg.find(
"{http://linux.duke.edu/metadata/common}version"
).attrib["rel"]
arch = matching_pkg.find("{http://linux.duke.edu/metadata/common}arch").text
clean_release = MODULE_DIST_RE.sub("", DIST_RE.sub("", release))
return f"{name}-{version}-{clean_release}.{arch}"
def clean_nvra(nvra_raw: str) -> str:
nvra = NVRA_RE.search(nvra_raw)
name = nvra.group(1)
version = nvra.group(2)
release = nvra.group(3)
arch = nvra.group(4)
clean_release = MODULE_DIST_RE.sub("", DIST_RE.sub("", release))
return f"{name}-{version}-{clean_release}.{arch}"
async def download_xml(
url: str, gz: bool = False, xz: bool = False
) -> ET.Element:
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
if resp.status != 200:
raise Exception(f"Failed to get {url}: {resp.status}")
# Do an in memory gzip decompression if gz is set
if gz:
return ET.fromstring(
gzip.decompress(await resp.read()).decode("utf-8")
)
elif xz:
return ET.fromstring(
lzma.decompress(await resp.read()).decode("utf-8")
)
return ET.fromstring(await resp.text())
async def download_yaml(url: str, gz: bool = False, xz: bool = False) -> any:
async with aiohttp.ClientSession() as session:
async with session.get(url) as resp:
if resp.status != 200:
raise Exception(f"Failed to get {url}: {resp.status}")
# Do an in memory gzip decompression if gz is set
if gz:
return yaml.full_load_all(
gzip.decompress(await resp.read()).decode("utf-8")
)
elif xz:
return yaml.full_load_all(
lzma.decompress(await resp.read()).decode("utf-8")
)
return yaml.full_load_all(await resp.text())
async def get_data_from_repomd(
url: str,
data_type: str,
el: ET.Element,
is_yaml=False,
):
# There is a top-most repomd element in repomd
# Under there is revision and multiple data elements
# We want the data element with type="data_type"
# Under that is location with href
# That href is the location of the data
for data in el.findall("{http://linux.duke.edu/metadata/repo}data"):
if data.attrib["type"] == data_type:
location = data.find(
"{http://linux.duke.edu/metadata/repo}location"
)
parsed_url = urlparse(url)
new_path = path.abspath(
path.join(parsed_url.path, "../..", location.attrib["href"])
)
data_url = parsed_url._replace(path=new_path).geturl()
if is_yaml:
return await download_yaml(
data_url,
gz=data_url.endswith(".gz"),
xz=data_url.endswith(".xz"),
)
return await download_xml(
data_url,
gz=data_url.endswith(".gz"),
xz=data_url.endswith(".xz"),
)
return None

View File

@ -0,0 +1,562 @@
import datetime
from dataclasses import dataclass
from xml.etree import ElementTree as ET
from temporalio import activity
from tortoise.transactions import in_transaction
from apollo.db import SupportedProduct, SupportedProductsRhMirror, SupportedProductsRpmRepomd, SupportedProductsRpmRhOverride, SupportedProductsRhBlock
from apollo.db import RedHatAdvisory, Advisory, AdvisoryAffectedProduct, AdvisoryCVE, AdvisoryFix, AdvisoryPackage
from apollo.rpmworker import repomd
from common.logger import Logger
@dataclass
class NewPackage:
nevra: str
checksum: str
checksum_type: str
module_context: str
module_name: str
module_stream: str
module_version: str
repo_name: str
package_name: str
mirror_id: int
supported_product_id: int
product_name: str
@activity.defn
async def get_supported_products_with_rh_mirrors() -> list[int]:
"""
Get supported product IDs that has an RH mirror configuration
"""
rh_mirrors = await SupportedProductsRhMirror.all().prefetch_related(
"rpm_repomds",
)
ret = []
for rh_mirror in rh_mirrors:
if rh_mirror.supported_product_id not in ret and rh_mirror.rpm_repomds:
ret.append(rh_mirror.supported_product_id)
return ret
async def get_matching_rh_advisories(
mirror: SupportedProductsRhMirror
) -> list[RedHatAdvisory]:
# First get advisories that matches the mirrored product
# And also the overrides
# Also exclude blocked advisories and advisories without packages
advisories = await RedHatAdvisory.filter(
affected_products__variant=mirror.match_variant,
affected_products__major_version=mirror.match_major_version,
affected_products__minor_version=mirror.match_minor_version,
affected_products__arch=mirror.match_arch,
).order_by("red_hat_issued_at").prefetch_related(
"packages", "cves", "bugzilla_tickets"
)
override_ids = []
overrides = await SupportedProductsRpmRhOverride.filter(
supported_products_rh_mirror_id=mirror.id
).prefetch_related("red_hat_advisory")
for override in overrides:
override_ids.append(override.red_hat_advisory_id)
advisories.append(override.red_hat_advisory)
blocked = await SupportedProductsRhBlock.filter(
supported_products_rh_mirror_id=mirror.id,
).all()
blocked_ids = []
now = datetime.datetime.now(datetime.timezone.utc)
for b in blocked:
delta = now - b.created_at
if delta.days >= 14:
blocked_ids.append(b.red_hat_advisory_id)
# Remove all advisories without packages and blocked advisories
final = []
for advisory in advisories:
if advisory.packages and (
advisory.id not in blocked_ids and advisory.id not in override_ids
):
final.append(advisory)
return final
async def clone_advisory(
product: SupportedProduct,
mirrors: list[SupportedProductsRhMirror],
advisory: RedHatAdvisory,
all_pkgs: list[ET.ElementTree],
module_pkgs: dict,
published_at: datetime.datetime,
):
logger = Logger()
logger.info("Cloning advisory %s to %s", advisory.name, product.name)
acceptable_arches = list(set([x.match_arch for x in mirrors]))
acceptable_arches.extend(["src", "noarch"])
for mirror in mirrors:
if mirror.match_arch == "x86_64":
acceptable_arches.append("i686")
break
clean_advisory_nvras = {}
for advisory_pkg in advisory.packages:
nvra = repomd.NVRA_RE.search(advisory_pkg.nevra)
if nvra.group(4) not in acceptable_arches:
continue
cleaned = repomd.clean_nvra(advisory_pkg.nevra)
if cleaned not in clean_advisory_nvras:
clean_advisory_nvras[cleaned] = True
if not clean_advisory_nvras:
logger.info(
"Blocking advisory %s, no packages match arches",
advisory.name,
)
await SupportedProductsRhBlock.bulk_create(
[
SupportedProductsRhBlock(
**{
"supported_products_rh_mirror_id": mirror.id,
"red_hat_advisory_id": advisory.id,
}
) for mirror in mirrors
],
ignore_conflicts=True,
)
overrides = await SupportedProductsRpmRhOverride.filter(
supported_products_rh_mirror_id__in=[x.id for x in mirrors],
red_hat_advisory_id=advisory.id,
).all()
if overrides:
for override in overrides:
await override.delete()
return
pkg_nvras = {}
for pkgs in all_pkgs:
for pkg in pkgs:
cleaned = repomd.clean_nvra_pkg(pkg)
if cleaned not in pkg_nvras:
pkg_nvras[cleaned] = [pkg]
else:
pkg_nvras[cleaned].append(pkg)
async with in_transaction():
# Create advisory
name = f"{product.code.code}{advisory.name.removeprefix('RH')}"
synopsis = advisory.synopsis.replace(
"Red Hat Enterprise Linux", product.name
)
synopsis = synopsis.replace("RHEL", product.name)
synopsis = synopsis.replace("Red Hat", product.vendor)
synopsis = synopsis.replace(advisory.name, name)
description = advisory.description.replace(
"Red Hat Enterprise Linux", product.name
)
description = description.replace("RHEL", product.name)
description = description.replace("Red Hat", product.vendor)
description = description.replace(advisory.name, name)
existing_advisory = await Advisory.filter(name=name).get_or_none()
if not existing_advisory:
new_advisory = await Advisory.create(
name=name,
synopsis=synopsis,
description=description,
kind=advisory.kind,
severity=advisory.severity,
red_hat_advisory_id=advisory.id,
published_at=published_at,
topic=advisory.topic,
)
else:
new_advisory = existing_advisory
# Clone packages
new_pkgs = []
for advisory_nvra, _ in clean_advisory_nvras.items():
if advisory_nvra not in pkg_nvras:
continue
pkgs_to_process = pkg_nvras[advisory_nvra]
for pkg in pkgs_to_process:
pkg_name = pkg.find(
"{http://linux.duke.edu/metadata/common}name"
).text
version_tree = pkg.find(
"{http://linux.duke.edu/metadata/common}version"
)
version = version_tree.attrib["ver"]
release = version_tree.attrib["rel"]
epoch = version_tree.attrib["epoch"]
arch = pkg.find(
"{http://linux.duke.edu/metadata/common}arch"
).text
nevra = f"{pkg_name}-{epoch}:{version}-{release}.{arch}.rpm"
source_rpm = pkg.find(
"{http://linux.duke.edu/metadata/common}format"
).find("{http://linux.duke.edu/metadata/rpm}sourcerpm")
# This means we're checking a source RPM
if advisory_nvra.endswith(".src.rpm"
) or advisory_nvra.endswith(".src"):
source_nvra = repomd.NVRA_RE.search(advisory_nvra)
package_name = source_nvra.group(1)
else:
source_nvra = repomd.NVRA_RE.search(source_rpm.text)
package_name = source_nvra.group(1)
checksum_tree = pkg.find(
"{http://linux.duke.edu/metadata/common}checksum"
)
checksum = checksum_tree.text
checksum_type = checksum_tree.attrib["type"]
module_context = None
module_name = None
module_stream = None
module_version = None
if ".module+" in release:
for module_pkg, data in module_pkgs.items():
if module_pkg == nevra.removesuffix(".rpm"):
module_name = data[0]
module_stream = data[1]
module_version = data[2]
module_context = data[3]
for mirror in mirrors:
if pkg.attrib["mirror_id"] != str(mirror.id):
continue
new_pkgs.append(
NewPackage(
nevra=nevra,
checksum=checksum,
checksum_type=checksum_type,
module_context=module_context,
module_name=module_name,
module_stream=module_stream,
module_version=module_version,
repo_name=pkg.attrib["repo_name"],
package_name=package_name,
mirror_id=mirror.id,
supported_product_id=mirror.supported_product_id,
product_name=mirror.name,
)
)
if not new_pkgs:
logger.info(
"Blocking advisory %s, no packages",
advisory.name,
)
if not existing_advisory:
await new_advisory.delete()
await SupportedProductsRhBlock.bulk_create(
[
SupportedProductsRhBlock(
**{
"supported_products_rh_mirror_id": mirror.id,
"red_hat_advisory_id": advisory.id,
}
) for mirror in mirrors
],
ignore_conflicts=True,
)
overrides = await SupportedProductsRpmRhOverride.filter(
supported_products_rh_mirror_id__in=[x.id for x in mirrors],
red_hat_advisory_id=advisory.id,
).all()
if overrides:
for override in overrides:
await override.delete()
return
await AdvisoryPackage.bulk_create(
[
AdvisoryPackage(
**{
"advisory_id": new_advisory.id,
"nevra": pkg.nevra,
"checksum": pkg.checksum,
"checksum_type": pkg.checksum_type,
"module_context": pkg.module_context,
"module_name": pkg.module_name,
"module_stream": pkg.module_stream,
"module_version": pkg.module_version,
"repo_name": pkg.repo_name,
"package_name": pkg.package_name,
"supported_products_rh_mirror_id": pkg.mirror_id,
"supported_product_id": pkg.supported_product_id,
"product_name": pkg.product_name,
}
) for pkg in new_pkgs
],
ignore_conflicts=True,
)
# Clone CVEs
if advisory.cves:
await AdvisoryCVE.bulk_create(
[
AdvisoryCVE(
**{
"advisory_id": new_advisory.id,
"cve": cve.cve,
"cvss3_scoring_vector": cve.cvss3_scoring_vector,
"cvss3_base_score": cve.cvss3_base_score,
"cwe": cve.cwe,
}
) for cve in advisory.cves
],
ignore_conflicts=True,
)
# Clone fixes
if advisory.bugzilla_tickets:
await AdvisoryFix.bulk_create(
[
AdvisoryFix(
**{
"advisory_id":
new_advisory.id,
"ticket_id":
fix.bugzilla_bug_id,
"source":
f"https://bugzilla.redhat.com/show_bug.cgi?id={fix.bugzilla_bug_id}",
"description":
fix.description,
}
) for fix in advisory.bugzilla_tickets
],
ignore_conflicts=True,
)
# Add affected products
await AdvisoryAffectedProduct.bulk_create(
[
AdvisoryAffectedProduct(
**{
"advisory_id": new_advisory.id,
"variant": product.name,
"name": mirror.name,
"major_version": mirror.match_major_version,
"minor_version": mirror.match_minor_version,
"arch": mirror.match_arch,
"supported_product_id": mirror.supported_product_id,
}
) for mirror in mirrors
],
ignore_conflicts=True,
)
# Check if topic is empty, if so construct it
if not new_advisory.topic:
package_names = list(set([p.package_name for p in new_pkgs]))
affected_products = list(
set(
[
f"{product.name} {mirror.match_major_version}"
for mirror in mirrors
]
)
)
topic = f"""An update is available for {', '.join(package_names)}.
This update affects {', '.join(affected_products)}.
A Common Vulnerability Scoring System (CVSS) base score, which gives a detailed severity rating, is available for each vulnerability from the CVE list"""
new_advisory.topic = topic
await new_advisory.save()
# Block advisory from being attempted to be mirrored again
await SupportedProductsRhBlock.bulk_create(
[
SupportedProductsRhBlock(
**{
"supported_products_rh_mirror_id": mirror.id,
"red_hat_advisory_id": advisory.id,
}
) for mirror in mirrors
],
ignore_conflicts=True,
)
async def process_repomd(
mirror: SupportedProductsRhMirror,
rpm_repomd: SupportedProductsRpmRepomd,
advisories: list[RedHatAdvisory],
):
logger = Logger()
all_pkgs = []
urls_to_fetch = [
rpm_repomd.url, rpm_repomd.debug_url, rpm_repomd.source_url
]
module_packages = {}
for url in urls_to_fetch:
logger.info("Fetching %s", url)
repomd_xml = await repomd.download_xml(url)
primary_xml = await repomd.get_data_from_repomd(
url, "primary", repomd_xml
)
pkgs = primary_xml.findall(
"{http://linux.duke.edu/metadata/common}package"
)
all_pkgs.extend(pkgs)
module_yaml_data = await repomd.get_data_from_repomd(
url,
"modules",
repomd_xml,
is_yaml=True,
)
if module_yaml_data:
logger.info("Found modules.yaml")
for module_data in module_yaml_data:
if module_data.get("document") != "modulemd":
continue
data = module_data.get("data")
if not data.get("artifacts"):
continue
for nevra in data.get("artifacts").get("rpms"):
module_packages[nevra] = (
data.get("name"),
data.get("stream"),
data.get("version"),
data.get("context"),
)
ret = {}
pkg_nvras = {}
for pkg in all_pkgs:
cleaned = repomd.clean_nvra_pkg(pkg)
if cleaned not in pkg_nvras:
pkg_nvras[cleaned] = pkg
check_pkgs = []
# Now check against advisories, and see if we're matching any
# If we match, that means we can start creating the supporting
# mirror advisories
for advisory in advisories:
clean_advisory_nvras = {}
for advisory_pkg in advisory.packages:
cleaned = repomd.clean_nvra(advisory_pkg.nevra)
if cleaned not in clean_advisory_nvras:
clean_advisory_nvras[cleaned] = True
if not clean_advisory_nvras:
continue
did_match_any = False
for nevra, _ in clean_advisory_nvras.items():
if nevra in pkg_nvras:
pkg = pkg_nvras[nevra]
# Set repo name as an attribute to packages
pkg.set("repo_name", rpm_repomd.repo_name)
pkg.set("mirror_id", str(mirror.id))
check_pkgs.append(pkg)
did_match_any = True
if did_match_any:
ret.update(
{
advisory.name:
{
"advisory": advisory,
"packages": [check_pkgs],
"module_packages": module_packages,
}
}
)
return ret
@activity.defn
async def match_rh_repos(supported_product_id: int) -> None:
"""
Process the repomd files for the supported product
"""
logger = Logger()
supported_product = await SupportedProduct.filter(
id=supported_product_id
).first().prefetch_related("rh_mirrors", "rh_mirrors__rpm_repomds", "code")
all_advisories = {}
for mirror in supported_product.rh_mirrors:
logger.info("Processing mirror: %s", mirror.name)
advisories = await get_matching_rh_advisories(mirror)
for rpm_repomd in mirror.rpm_repomds:
if rpm_repomd.arch != mirror.match_arch:
continue
published_at = None
if rpm_repomd.production:
published_at = datetime.datetime.now()
advisory_map = await process_repomd(mirror, rpm_repomd, advisories)
if advisory_map:
for advisory_name, obj in advisory_map.items():
if advisory_name in all_advisories:
all_advisories[advisory_name]["packages"].extend(
obj["packages"]
)
all_advisories[advisory_name]["mirrors"].append(mirror)
for key, val in obj["module_packages"].items():
all_advisories[advisory_name]["module_packages"][
key] = val
else:
new_obj = dict(obj)
new_obj["published_at"] = published_at
new_obj["mirrors"] = [mirror]
all_advisories.update({advisory_name: new_obj})
for advisory_name, obj in all_advisories.items():
await clone_advisory(
supported_product,
list(set(obj["mirrors"])),
obj["advisory"],
obj["packages"],
obj["module_packages"],
obj["published_at"],
)
@activity.defn
async def block_remaining_rh_advisories(supported_product_id: int) -> None:
supported_product = await SupportedProduct.filter(
id=supported_product_id
).first().prefetch_related("rh_mirrors")
for mirror in supported_product.rh_mirrors:
mirrors = await SupportedProductsRhMirror.filter(
supported_product_id=supported_product_id
)
for mirror in mirrors:
advisories = await get_matching_rh_advisories(mirror)
await SupportedProductsRhBlock.bulk_create(
[
SupportedProductsRhBlock(
**{
"supported_products_rh_mirror_id": mirror.id,
"red_hat_advsiory_id": advisory.id,
}
) for advisory in advisories
],
ignore_conflicts=True
)

View File

@ -0,0 +1,39 @@
import datetime
from dataclasses import dataclass
from temporalio import workflow
@dataclass
class RhDefunctWorkflowInput:
supported_product_id: int
@workflow.defn
class RhMatcherWorkflow:
@workflow.run
async def run(self) -> list[int]:
supported_product_ids = await workflow.execute_activity(
"get_supported_products_with_rh_mirrors",
start_to_close_timeout=datetime.timedelta(seconds=20),
)
for supported_product_id in supported_product_ids:
await workflow.execute_activity(
"match_rh_repos",
supported_product_id,
start_to_close_timeout=datetime.timedelta(hours=12),
)
return supported_product_ids
@workflow.defn
class RhDefunctWorkflow:
@workflow.run
async def run(self, wf_in: RhDefunctWorkflowInput) -> None:
await workflow.execute_activity(
"block_remaining_rh_advisories",
wf_in.supported_product_id,
start_to_close_timeout=datetime.timedelta(hours=12),
)

View File

@ -0,0 +1,49 @@
insert into supported_products_rpm_repomds
(supported_products_rh_mirror_id, production, arch, url, debug_url, source_url, repo_name)
values
(2, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/8/BaseOS/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/BaseOS/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(2, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/8/AppStream/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/AppStream/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(2, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/8/HighAvailability/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/HighAvailability/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(2, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/8/NFV/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/NFV/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(2, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/8/PowerTools/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/PowerTools/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(2, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/8/RT/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/RT/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/RT/source/tree/repodata/repomd.xml', 'RT'),
(2, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/8/ResilientStorage/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/ResilientStorage/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(3, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/8/BaseOS/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/BaseOS/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(3, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/8/AppStream/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/AppStream/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(3, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/8/HighAvailability/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/HighAvailability/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(3, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/8/NFV/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/NFV/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(3, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/8/PowerTools/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/PowerTools/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(3, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/8/ResilientStorage/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/ResilientStorage/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/8/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/NFV/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/CRB/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/RT/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/RT/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/RT/source/tree/repodata/repomd.xml', 'RT'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(4, true, 'x86_64', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/NFV/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/CRB/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(5, true, 'aarch64', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/NFV/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/CRB/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(6, true, 's390x', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/NFV/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/CRB/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(7, true, 'ppc64le', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/pub/rocky/9/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA');

View File

@ -0,0 +1,75 @@
insert into supported_products_rpm_repomds
(supported_products_rh_mirror_id, production, arch, url, debug_url, source_url, repo_name)
values
(8, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.4/BaseOS/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/BaseOS/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(8, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.4/AppStream/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/AppStream/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(8, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.4/HighAvailability/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/HighAvailability/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(8, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.4/nfv/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/nfv/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/nfv/source/tree/repodata/repomd.xml', 'NFV'),
(8, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.4/PowerTools/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/PowerTools/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(8, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.4/RT/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/RT/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/RT/source/tree/repodata/repomd.xml', 'RT'),
(8, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.4/ResilientStorage/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/ResilientStorage/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(9, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.4/BaseOS/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/BaseOS/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(9, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.4/AppStream/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/AppStream/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(9, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.4/HighAvailability/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/HighAvailability/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(9, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.4/nfv/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/nfv/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/nfv/source/tree/repodata/repomd.xml', 'NFV'),
(9, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.4/PowerTools/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/PowerTools/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(9, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.4/ResilientStorage/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/ResilientStorage/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.4/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(10, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.5/BaseOS/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/BaseOS/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(10, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.5/AppStream/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/AppStream/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(10, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.5/HighAvailability/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/HighAvailability/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(10, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.5/nfv/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/nfv/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/nfv/source/tree/repodata/repomd.xml', 'NFV'),
(10, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.5/PowerTools/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/PowerTools/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(10, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.5/RT/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/RT/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/RT/source/tree/repodata/repomd.xml', 'RT'),
(10, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.5/ResilientStorage/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/ResilientStorage/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(11, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.5/BaseOS/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/BaseOS/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(11, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.5/AppStream/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/AppStream/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(11, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.5/HighAvailability/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/HighAvailability/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(11, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.5/nfv/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/nfv/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/nfv/source/tree/repodata/repomd.xml', 'NFV'),
(11, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.5/PowerTools/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/PowerTools/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(11, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.5/ResilientStorage/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/ResilientStorage/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.5/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(12, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.6/BaseOS/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/BaseOS/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(12, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.6/AppStream/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/AppStream/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(12, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.6/HighAvailability/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/HighAvailability/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(12, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.6/NFV/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/NFV/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(12, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.6/PowerTools/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/PowerTools/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(12, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.6/RT/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/RT/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/RT/source/tree/repodata/repomd.xml', 'RT'),
(12, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/8.6/ResilientStorage/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/ResilientStorage/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(13, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.6/BaseOS/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/BaseOS/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(13, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.6/AppStream/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/AppStream/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(13, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.6/HighAvailability/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/HighAvailability/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(13, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.6/NFV/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/NFV/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(13, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.6/PowerTools/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/PowerTools/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/PowerTools/source/tree/repodata/repomd.xml', 'PowerTools'),
(13, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/8.6/ResilientStorage/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/ResilientStorage/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/8.6/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/RT/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/RT/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/RT/source/tree/repodata/repomd.xml', 'RT'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(14, true, 'x86_64', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/x86_64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/x86_64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(15, true, 'aarch64', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/aarch64/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/aarch64/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(16, true, 's390x', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/s390x/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/s390x/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/BaseOS/source/tree/repodata/repomd.xml', 'BaseOS'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/AppStream/source/tree/repodata/repomd.xml', 'AppStream'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/HighAvailability/source/tree/repodata/repomd.xml', 'HighAvailability'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/NFV/source/tree/repodata/repomd.xml', 'NFV'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/CRB/source/tree/repodata/repomd.xml', 'CRB'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/ResilientStorage/source/tree/repodata/repomd.xml', 'ResilientStorage'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAP/source/tree/repodata/repomd.xml', 'SAP'),
(17, true, 'ppc64le', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/ppc64le/os/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/ppc64le/debug/tree/repodata/repomd.xml', 'http://dl.rockylinux.org/vault/rocky/9.0/SAPHANA/source/tree/repodata/repomd.xml', 'SAPHANA');

View File

@ -0,0 +1 @@
TASK_QUEUE = "v2-rpmworker"

591
apollo/schema.sql Normal file
View File

@ -0,0 +1,591 @@
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: codes; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.codes (
id text NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone,
archived_at timestamp without time zone,
description text NOT NULL
);
--
-- Name: red_hat_advisories; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.red_hat_advisories (
id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone,
red_hat_issued_at timestamp with time zone NOT NULL,
name text NOT NULL,
synopsis text NOT NULL,
description text NOT NULL,
kind text NOT NULL,
severity text NOT NULL
);
--
-- Name: red_hat_advisories_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.red_hat_advisories_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: red_hat_advisories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.red_hat_advisories_id_seq OWNED BY public.red_hat_advisories.id;
--
-- Name: red_hat_advisory_affected_products; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.red_hat_advisory_affected_products (
id bigint NOT NULL,
red_hat_advisory_id bigint,
variant text NOT NULL,
name text NOT NULL,
major_version numeric NOT NULL,
minor_version numeric,
arch text NOT NULL
);
--
-- Name: red_hat_advisory_affected_products_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.red_hat_advisory_affected_products_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: red_hat_advisory_affected_products_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.red_hat_advisory_affected_products_id_seq OWNED BY public.red_hat_advisory_affected_products.id;
--
-- Name: red_hat_advisory_bugzilla_bugs; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.red_hat_advisory_bugzilla_bugs (
id bigint NOT NULL,
red_hat_advisory_id bigint,
bugzilla_bug_id text NOT NULL
);
--
-- Name: red_hat_advisory_bugzilla_bugs_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.red_hat_advisory_bugzilla_bugs_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: red_hat_advisory_bugzilla_bugs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.red_hat_advisory_bugzilla_bugs_id_seq OWNED BY public.red_hat_advisory_bugzilla_bugs.id;
--
-- Name: red_hat_advisory_cves; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.red_hat_advisory_cves (
id bigint NOT NULL,
red_hat_advisory_id bigint,
cve text NOT NULL
);
--
-- Name: red_hat_advisory_cves_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.red_hat_advisory_cves_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: red_hat_advisory_cves_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.red_hat_advisory_cves_id_seq OWNED BY public.red_hat_advisory_cves.id;
--
-- Name: red_hat_advisory_packages; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.red_hat_advisory_packages (
id bigint NOT NULL,
red_hat_advisory_id bigint,
nevra text NOT NULL
);
--
-- Name: red_hat_advisory_packages_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.red_hat_advisory_packages_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: red_hat_advisory_packages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.red_hat_advisory_packages_id_seq OWNED BY public.red_hat_advisory_packages.id;
--
-- Name: red_hat_index_state; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.red_hat_index_state (
id bigint NOT NULL,
last_indexed_at timestamp with time zone
);
--
-- Name: red_hat_index_state_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.red_hat_index_state_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: red_hat_index_state_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.red_hat_index_state_id_seq OWNED BY public.red_hat_index_state.id;
--
-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.schema_migrations (
version character varying(255) NOT NULL
);
--
-- Name: supported_products; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.supported_products (
id bigint NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone,
eol_at timestamp with time zone,
name text NOT NULL,
rhel_major_version numeric,
rhel_minor_version numeric
);
--
-- Name: supported_products_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.supported_products_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: supported_products_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.supported_products_id_seq OWNED BY public.supported_products.id;
--
-- Name: red_hat_advisories id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisories ALTER COLUMN id SET DEFAULT nextval('public.red_hat_advisories_id_seq'::regclass);
--
-- Name: red_hat_advisory_affected_products id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_affected_products ALTER COLUMN id SET DEFAULT nextval('public.red_hat_advisory_affected_products_id_seq'::regclass);
--
-- Name: red_hat_advisory_bugzilla_bugs id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_bugzilla_bugs ALTER COLUMN id SET DEFAULT nextval('public.red_hat_advisory_bugzilla_bugs_id_seq'::regclass);
--
-- Name: red_hat_advisory_cves id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_cves ALTER COLUMN id SET DEFAULT nextval('public.red_hat_advisory_cves_id_seq'::regclass);
--
-- Name: red_hat_advisory_packages id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_packages ALTER COLUMN id SET DEFAULT nextval('public.red_hat_advisory_packages_id_seq'::regclass);
--
-- Name: red_hat_index_state id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_index_state ALTER COLUMN id SET DEFAULT nextval('public.red_hat_index_state_id_seq'::regclass);
--
-- Name: supported_products id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.supported_products ALTER COLUMN id SET DEFAULT nextval('public.supported_products_id_seq'::regclass);
--
-- Name: codes codes_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.codes
ADD CONSTRAINT codes_pkey PRIMARY KEY (id);
--
-- Name: red_hat_advisories red_hat_advisories_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisories
ADD CONSTRAINT red_hat_advisories_name_key UNIQUE (name);
--
-- Name: red_hat_advisories red_hat_advisories_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisories
ADD CONSTRAINT red_hat_advisories_pkey PRIMARY KEY (id);
--
-- Name: red_hat_advisory_affected_products red_hat_advisory_affected_pro_red_hat_advisory_id_variant_n_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_affected_products
ADD CONSTRAINT red_hat_advisory_affected_pro_red_hat_advisory_id_variant_n_key UNIQUE (red_hat_advisory_id, variant, name, major_version, minor_version, arch);
--
-- Name: red_hat_advisory_affected_products red_hat_advisory_affected_products_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_affected_products
ADD CONSTRAINT red_hat_advisory_affected_products_pkey PRIMARY KEY (id);
--
-- Name: red_hat_advisory_bugzilla_bugs red_hat_advisory_bugzilla_bug_red_hat_advisory_id_bugzilla__key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_bugzilla_bugs
ADD CONSTRAINT red_hat_advisory_bugzilla_bug_red_hat_advisory_id_bugzilla__key UNIQUE (red_hat_advisory_id, bugzilla_bug_id);
--
-- Name: red_hat_advisory_bugzilla_bugs red_hat_advisory_bugzilla_bugs_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_bugzilla_bugs
ADD CONSTRAINT red_hat_advisory_bugzilla_bugs_pkey PRIMARY KEY (id);
--
-- Name: red_hat_advisory_cves red_hat_advisory_cves_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_cves
ADD CONSTRAINT red_hat_advisory_cves_pkey PRIMARY KEY (id);
--
-- Name: red_hat_advisory_cves red_hat_advisory_cves_red_hat_advisory_id_cve_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_cves
ADD CONSTRAINT red_hat_advisory_cves_red_hat_advisory_id_cve_key UNIQUE (red_hat_advisory_id, cve);
--
-- Name: red_hat_advisory_packages red_hat_advisory_packages_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_packages
ADD CONSTRAINT red_hat_advisory_packages_pkey PRIMARY KEY (id);
--
-- Name: red_hat_advisory_packages red_hat_advisory_packages_red_hat_advisory_id_nevra_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_packages
ADD CONSTRAINT red_hat_advisory_packages_red_hat_advisory_id_nevra_key UNIQUE (red_hat_advisory_id, nevra);
--
-- Name: red_hat_index_state red_hat_index_state_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_index_state
ADD CONSTRAINT red_hat_index_state_pkey PRIMARY KEY (id);
--
-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.schema_migrations
ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version);
--
-- Name: supported_products supported_products_name_key; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.supported_products
ADD CONSTRAINT supported_products_name_key UNIQUE (name);
--
-- Name: supported_products supported_products_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.supported_products
ADD CONSTRAINT supported_products_pkey PRIMARY KEY (id);
--
-- Name: red_hat_advisories_kindx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisories_kindx ON public.red_hat_advisories USING btree (kind);
--
-- Name: red_hat_advisories_namex; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisories_namex ON public.red_hat_advisories USING btree (name);
--
-- Name: red_hat_advisories_red_hat_issued_atx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisories_red_hat_issued_atx ON public.red_hat_advisories USING btree (red_hat_issued_at);
--
-- Name: red_hat_advisories_severityx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisories_severityx ON public.red_hat_advisories USING btree (severity);
--
-- Name: red_hat_advisories_synopsisx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisories_synopsisx ON public.red_hat_advisories USING btree (synopsis);
--
-- Name: red_hat_advisory_affected_products_archx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_affected_products_archx ON public.red_hat_advisory_affected_products USING btree (arch);
--
-- Name: red_hat_advisory_affected_products_major_versionx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_affected_products_major_versionx ON public.red_hat_advisory_affected_products USING btree (major_version);
--
-- Name: red_hat_advisory_affected_products_minor_versionx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_affected_products_minor_versionx ON public.red_hat_advisory_affected_products USING btree (minor_version);
--
-- Name: red_hat_advisory_affected_products_namex; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_affected_products_namex ON public.red_hat_advisory_affected_products USING btree (name);
--
-- Name: red_hat_advisory_affected_products_variantx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_affected_products_variantx ON public.red_hat_advisory_affected_products USING btree (variant);
--
-- Name: red_hat_advisory_bugzilla_bugs_bugzilla_bug_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_bugzilla_bugs_bugzilla_bug_idx ON public.red_hat_advisory_bugzilla_bugs USING btree (bugzilla_bug_id);
--
-- Name: red_hat_advisory_cvex; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_cvex ON public.red_hat_advisory_cves USING btree (cve);
--
-- Name: red_hat_advisory_packages_nevrax; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX red_hat_advisory_packages_nevrax ON public.red_hat_advisory_packages USING btree (nevra);
--
-- Name: supported_products_eol_atx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX supported_products_eol_atx ON public.supported_products USING btree (eol_at);
--
-- Name: supported_products_namex; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX supported_products_namex ON public.supported_products USING btree (name);
--
-- Name: supported_products_rhel_major_versionx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX supported_products_rhel_major_versionx ON public.supported_products USING btree (rhel_major_version);
--
-- Name: supported_products_rhel_minor_versionx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX supported_products_rhel_minor_versionx ON public.supported_products USING btree (rhel_minor_version);
--
-- Name: red_hat_advisory_affected_products red_hat_advisory_affected_products_red_hat_advisory_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_affected_products
ADD CONSTRAINT red_hat_advisory_affected_products_red_hat_advisory_id_fkey FOREIGN KEY (red_hat_advisory_id) REFERENCES public.red_hat_advisories(id) ON DELETE CASCADE;
--
-- Name: red_hat_advisory_bugzilla_bugs red_hat_advisory_bugzilla_bugs_red_hat_advisory_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_bugzilla_bugs
ADD CONSTRAINT red_hat_advisory_bugzilla_bugs_red_hat_advisory_id_fkey FOREIGN KEY (red_hat_advisory_id) REFERENCES public.red_hat_advisories(id) ON DELETE CASCADE;
--
-- Name: red_hat_advisory_cves red_hat_advisory_cves_red_hat_advisory_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_cves
ADD CONSTRAINT red_hat_advisory_cves_red_hat_advisory_id_fkey FOREIGN KEY (red_hat_advisory_id) REFERENCES public.red_hat_advisories(id) ON DELETE CASCADE;
--
-- Name: red_hat_advisory_packages red_hat_advisory_packages_red_hat_advisory_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.red_hat_advisory_packages
ADD CONSTRAINT red_hat_advisory_packages_red_hat_advisory_id_fkey FOREIGN KEY (red_hat_advisory_id) REFERENCES public.red_hat_advisories(id) ON DELETE CASCADE;
--
-- PostgreSQL database dump complete
--
--
-- Dbmate schema migrations
--
INSERT INTO public.schema_migrations (version) VALUES
('20230128201227');

48
apollo/server/BUILD.bazel Normal file
View File

@ -0,0 +1,48 @@
load("@aspect_rules_py//py:defs.bzl", "py_library")
load("//build/macros:fastapi.bzl", "fastapi_binary")
py_library(
name = "server_lib",
srcs = [
"roles.py",
"routes/admin_index.py",
"routes/advisories.py",
"routes/api_advisories.py",
"routes/api_compat.py",
"routes/api_red_hat.py",
"routes/login.py",
"routes/logout.py",
"routes/red_hat_advisories.py",
"routes/statistics.py",
"server.py",
"settings.py",
"utils.py",
],
data = [
":assets",
":templates",
"//apollo/server/static",
],
imports = ["../.."],
visibility = ["//:__subpackages__"],
deps = [
"//apollo/db:db_lib",
"//apollo/db/serialize:serialize_lib",
"//common:common_lib",
"@pypi_fastapi//:pkg",
"@pypi_fastapi_pagination//:pkg",
"@pypi_itsdangerous//:pkg",
"@pypi_jinja2//:pkg",
"@pypi_passlib//:pkg",
"@pypi_python_multipart//:pkg",
"@pypi_starlette//:pkg",
"@pypi_tortoise_orm//:pkg",
],
)
fastapi_binary(
name = "server",
imports = ["../.."],
path = "apollo.server.server",
port = "9999",
)

View File

@ -0,0 +1,11 @@
<svg width="369" height="322" viewBox="0 0 369 322" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M270.625 0.000793457H97.7074C93.6888 0.000793457 89.9753 2.1446 87.966 5.62505L1.5072 155.376C-0.502076 158.856 -0.502076 163.144 1.5072 166.624L87.966 316.376C89.9753 319.856 93.6888 322 97.7074 322H270.625C274.643 322 278.357 319.856 280.366 316.376L366.825 166.624C368.834 163.144 368.834 158.856 366.825 155.376L280.366 5.62505C278.357 2.1446 274.643 0.000793457 270.625 0.000793457Z" fill="#FFD45D"/>
<path d="M368.332 161H294.609L239.387 256.646L276.249 320.492C277.931 319.521 279.362 318.115 280.366 316.375L366.825 166.624C367.83 164.884 368.332 162.942 368.332 161Z" fill="#007362"/>
<path d="M239.387 256.646H128.945L92.083 320.492C93.765 321.463 95.698 321.999 97.7073 321.999H270.625C272.634 321.999 274.567 321.463 276.249 320.492L239.387 256.646Z" fill="#00984C"/>
<path d="M128.945 256.646L73.7233 161H0C0 162.942 0.50214 164.884 1.50714 166.624L87.9659 316.376C88.9709 318.116 90.4011 319.522 92.083 320.493L128.945 256.646Z" fill="#41A93D"/>
<path d="M128.945 65.3538L92.083 1.50714C90.4011 2.47833 88.9702 3.88403 87.9659 5.62426L1.50714 155.376C0.50214 157.116 0 159.058 0 161H73.7233L128.945 65.3538Z" fill="#7DB82F"/>
<path d="M128.945 65.3538H239.387L276.249 1.50714C274.567 0.535953 272.634 0 270.625 0H97.7073C95.698 0 93.765 0.535953 92.083 1.50714L128.945 65.3538Z" fill="#41A93D"/>
<path d="M239.387 65.3538L294.609 161H368.332C368.332 159.058 367.83 157.116 366.825 155.376L280.366 5.62426C279.362 3.88403 277.931 2.47833 276.249 1.50714L239.387 65.3538Z" fill="#00984C"/>
<path d="M239.388 65.3538H128.944L73.7231 161L128.944 256.646H239.388L294.609 161L239.388 65.3538Z" fill="#008658"/>
<path d="M130.935 58.6569L137.975 53.3988C139.577 52.2025 141.696 53.9894 140.788 55.7707L136.795 63.5977C136.369 64.4344 136.621 65.4567 137.388 65.9984L144.564 71.0687C146.197 72.2226 145.152 74.7909 143.178 74.4765L134.5 73.0974C133.572 72.9499 132.677 73.506 132.399 74.4031L129.794 82.7949C129.201 84.7042 126.436 84.5042 126.124 82.5294L124.754 73.8506C124.607 72.9233 123.802 72.2442 122.863 72.2564L114.077 72.3722C112.078 72.3989 111.413 69.7069 113.195 68.8004L121.026 64.815C121.863 64.3891 122.26 63.4136 121.958 62.5244L119.132 54.2046C118.489 52.3111 120.844 50.8478 122.258 52.2622L128.467 58.4785C129.132 59.1425 130.182 59.2188 130.935 58.6569Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

2
apollo/server/roles.py Normal file
View File

@ -0,0 +1,2 @@
ADMIN = "admin"
ELEVATED = "elevated"

View File

@ -0,0 +1,15 @@
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from apollo.server.utils import templates
router = APIRouter(tags=["non-api"])
@router.get("/", response_class=HTMLResponse)
async def admin_general(request: Request):
return templates.TemplateResponse(
"admin_index.jinja", {
"request": request,
}
)

View File

@ -0,0 +1,127 @@
from math import ceil
from tortoise import connections
from fastapi import APIRouter, Request, Depends
from fastapi.responses import HTMLResponse
from fastapi_pagination import Params
from fastapi_pagination.ext.tortoise import paginate, create_page
from apollo.db import Advisory
from apollo.server.utils import templates
router = APIRouter(tags=["non-api"])
@router.get(
"/",
response_class=HTMLResponse,
)
async def list_advisories(
request: Request,
params: Params = Depends(),
search: str = None,
):
params.size = 50
if search:
a = """
with vars (search, size, page_offset) as (
values ($1 :: text, $2 :: bigint, $3 :: bigint)
)
select
a.id,
a.created_at,
a.updated_at,
a.published_at,
a.name,
a.synopsis,
a.description,
a.kind,
a.severity,
a.red_hat_advisory_id,
count(a.*) over () as total
from
advisories a
left outer join advisory_affected_products ap on ap.advisory_id = a.id
left outer join advisory_cves c on c.advisory_id = a.id
left outer join advisory_fixes f on f.advisory_id = a.id
where
(select search from vars) is null or
ap.name ilike '%' || (select search from vars) || '%' or
a.synopsis ilike '%' || (select search from vars) || '%' or
a.description ilike '%' || (select search from vars) || '%' or
exists (select cve from advisory_cves where advisory_id = a.id and cve ilike '%' || (select search from vars) || '%') or
exists (select ticket_id from advisory_fixes where advisory_id = a.id and ticket_id ilike '%' || (select search from vars) || '%') or
a.name ilike '%' || (select search from vars) || '%'
group by a.id
order by a.published_at desc
limit (select size from vars) offset (select page_offset from vars)
"""
connection = connections.get("default")
results = await connections.execute_query(
a, [search, params.size, params.size * (params.page - 1)]
)
count = 0
if results:
if results[1]:
count = results[1][0]["total"]
advisories = create_page(
results[1],
count,
params,
)
else:
advisories = await paginate(
Advisory.all().order_by("-published_at"),
params=params,
)
return templates.TemplateResponse(
"advisories.jinja", {
"request": request,
"params": params,
"search": search if search else "",
"advisories": advisories,
"advisories_pages": ceil(advisories.total / advisories.size)
}
)
@router.get(
"/{advisory_name}",
response_class=HTMLResponse,
)
async def get_advisory(request: Request, advisory_name: str):
advisory = await Advisory.get_or_none(name=advisory_name,
).prefetch_related(
"red_hat_advisory",
"packages",
"cves",
"fixes",
"affected_products",
)
if advisory is None:
return templates.TemplateResponse(
"error.jinja", {
"request": request,
"message": "Requested advisory not found",
}
)
package_map = {}
for package in advisory.packages:
name = f"{package.product_name} - {package.repo_name}"
if name not in package_map:
package_map[name] = []
package_map[name].append(package.nevra)
return templates.TemplateResponse(
"advisory.jinja", {
"request": request,
"title": f"Advisory {advisory.id}",
"advisory": advisory,
"package_map": package_map,
}
)

View File

@ -0,0 +1,56 @@
from typing import TypeVar, Generic
from fastapi import APIRouter, Request
from fastapi.exceptions import HTTPException
from fastapi_pagination.links import Page
from fastapi_pagination.ext.tortoise import paginate
from apollo.db import Advisory
from apollo.db.serialize import Advisory_Pydantic
router = APIRouter(tags=["advisories"])
T = TypeVar("T")
class Pagination(Page[T], Generic[T]):
class Config:
allow_population_by_field_name = True
fields = {"items": {"alias": "advisories"}}
@router.get(
"/",
response_model=Pagination[Advisory_Pydantic],
)
async def list_advisories():
advisories = await paginate(
Advisory.all().prefetch_related(
"red_hat_advisory",
"packages",
"cves",
"fixes",
"affected_products",
).order_by("-published_at"),
)
return advisories
@router.get(
"/{advisory_name}",
response_model=Advisory_Pydantic,
)
async def get_advisory(advisory_name: str):
advisory = await Advisory.filter(name=advisory_name).prefetch_related(
"packages",
"cves",
"fixes",
"affected_products",
"red_hat_advisory",
).first()
if advisory is None:
raise HTTPException(404)
return await Advisory_Pydantic.from_tortoise_orm(advisory)

View File

@ -0,0 +1,241 @@
"""
This module implements the compatibility API for Apollo V2 advisories
"""
import datetime
from typing import TypeVar, Generic, Optional
from tortoise import connections
from fastapi import APIRouter, Depends, Query
from fastapi.exceptions import HTTPException
from fastapi_pagination.links import Page
from fastapi_pagination import Params
from fastapi_pagination.ext.tortoise import create_page
from apollo.db import Advisory, RedHatIndexState
from apollo.db.serialize import Advisory_Pydantic_V2, Advisory_Pydantic_V2_CVE, Advisory_Pydantic_V2_Fix
from common.fastapi import RenderErrorTemplateException
router = APIRouter(tags=["v2_compat"])
T = TypeVar("T")
class Pagination(Page[T], Generic[T]):
lastUpdated: Optional[str] # noqa # pylint: disable=invalid-name
class Config:
allow_population_by_field_name = True
fields = {"items": {"alias": "advisories"}}
def v3_advisory_to_v2(
advisory: Advisory,
include_rpms=True,
) -> Advisory_Pydantic_V2:
kind = "TYPE_SECURITY"
if advisory.kind == "Bug Fix":
kind = "TYPE_BUGFIX"
elif advisory.kind == "Enhancement":
kind = "TYPE_ENHANCEMENT"
affected_products = list(
set(
[
f"{ap.variant} {ap.major_version}"
for ap in advisory.affected_products
]
)
)
cves = []
for cve in advisory.cves:
cves.append(
Advisory_Pydantic_V2_CVE(
name=cve.cve,
cvss3ScoringVector=cve.cvss3_scoring_vector,
cvss3BaseScore=cve.cvss3_base_score,
cwe=cve.cwe,
sourceBy="Red Hat",
sourceLink=
f"https://access.redhat.com/hydra/rest/securitydata/cve/{cve.cve}.json",
)
)
fixes = []
for fix in advisory.fixes:
fixes.append(
Advisory_Pydantic_V2_Fix(
ticket=fix.ticket_id,
sourceBy="Red Hat",
sourceLink=fix.source,
description=fix.description,
)
)
rpms = {}
if include_rpms:
for pkg in advisory.packages:
name = f"{pkg.supported_product.variant} {pkg.supported_products_rh_mirror.match_major_version}"
if name not in rpms:
rpms[name] = []
rpms[name].append(pkg.nevra)
return Advisory_Pydantic_V2(
id=advisory.id,
publishedAt=advisory.published_at,
name=advisory.name,
synopsis=advisory.synopsis,
description=advisory.description,
type=kind,
severity=f"SEVERITY_{advisory.severity.upper()}",
shortCode=advisory.name[0:2],
topic=advisory.topic if advisory.topic else "",
solution=None,
rpms=rpms,
affectedProducts=affected_products,
references=[],
rebootSuggested=False,
buildReferences=[],
fixes=fixes,
cves=cves,
)
@router.get(
"/",
response_model=Pagination[Advisory_Pydantic_V2],
)
async def list_advisories_compat_v2(
params: Params = Depends(),
product: str = Query(default=None, alias="filters.product"),
before_raw: str = Query(default=None, alias="filters.before"),
after_raw: str = Query(default=None, alias="filters.after"),
cve: str = Query(default=None, alias="filters.cve"),
synopsis: str = Query(default=None, alias="filters.synopsis"),
keyword: str = Query(default=None, alias="filters.keyword"),
severity: str = Query(default=None, alias="filters.severity"),
kind: str = Query(default=None, alias="filters.type"),
):
before = None
after = None
try:
if before_raw:
before = datetime.datetime.fromisoformat(
before_raw.removesuffix("Z")
)
except:
raise RenderErrorTemplateException("Invalid before date", 400)
try:
if after_raw:
after = datetime.datetime.fromisoformat(after_raw.removesuffix("Z"))
except:
raise RenderErrorTemplateException("Invalid after date", 400)
state = await RedHatIndexState.first()
a = """
with vars (search, size, page_offset, product, before, after, cve, synopsis, severity, kind) as (
values ($1 :: text, $2 :: bigint, $3 :: bigint, $4 :: text, $5 :: timestamp, $6 :: timestamp, $7 :: text, $8 :: text, $9 :: text, $10 :: text)
)
select
a.id,
a.created_at,
a.updated_at,
a.published_at,
a.name,
a.synopsis,
a.description,
a.kind,
a.severity,
a.topic,
a.red_hat_advisory_id,
count(a.*) over () as total
from
advisories a
left outer join advisory_affected_products ap on ap.advisory_id = a.id
left outer join advisory_cves c on c.advisory_id = a.id
left outer join advisory_fixes f on f.advisory_id = a.id
where
((select product from vars) is null or ap.name ilike '%' || (select product from vars) || '%')
and ((select before from vars) is null or a.published_at < (select before from vars))
and ((select after from vars) is null or a.published_at > (select after from vars))
and (a.published_at is not null)
and ((select cve from vars) is null or exists (select cve from advisory_cves where advisory_id = a.id and cve ilike '%' || (select cve from vars) || '%'))
and ((select synopsis from vars) is null or a.synopsis ilike '%' || (select synopsis from vars) || '%')
and ((select severity from vars) is null or a.severity = (select severity from vars))
and ((select kind from vars) is null or a.kind = (select kind from vars))
and ((select search from vars) is null or
ap.name ilike '%' || (select search from vars) || '%' or
a.synopsis ilike '%' || (select search from vars) || '%' or
a.description ilike '%' || (select search from vars) || '%' or
exists (select cve from advisory_cves where advisory_id = a.id and cve ilike '%' || (select search from vars) || '%') or
exists (select ticket_id from advisory_fixes where advisory_id = a.id and ticket_id ilike '%' || (select search from vars) || '%') or
a.name ilike '%' || (select search from vars) || '%')
group by a.id
order by a.published_at desc
limit (select size from vars) offset (select page_offset from vars)
"""
connection = connections.get("default")
results = await connection.execute_query(
a, [
keyword, params.size, params.size * (params.page - 1), product,
before, after, cve, synopsis, severity, kind
]
)
count = 0
if results:
if results[1]:
count = results[1][0]["total"]
advisories = []
for adv in results[1]:
advisory = Advisory(**adv)
await advisory.fetch_related(
"packages",
"cves",
"fixes",
"affected_products",
"packages",
"packages__supported_product",
"packages__supported_products_rh_mirror",
)
advisories.append(advisory)
v2_advisories: list[Advisory_Pydantic_V2] = []
for advisory in advisories:
v2_advisories.append(v3_advisory_to_v2(advisory))
page = create_page(v2_advisories, count, params)
page.lastUpdated = state.last_indexed_at.isoformat("T").replace(
"+00:00", ""
) + "Z"
return page
@router.get(
"/{advisory_name}",
response_model=Advisory_Pydantic_V2,
)
async def get_advisory_compat_v2(advisory_name: str):
advisory = await Advisory.filter(name=advisory_name).prefetch_related(
"packages",
"cves",
"fixes",
"affected_products",
"packages",
"packages__supported_product",
"packages__supported_products_rh_mirror",
).get_or_none()
if not advisory:
raise HTTPException(404)
return Advisory_Pydantic_V2.from_orm(v3_advisory_to_v2(advisory))

View File

@ -0,0 +1,59 @@
from typing import TypeVar, Generic
from fastapi import APIRouter, Request
from fastapi.exceptions import HTTPException
from fastapi_pagination.links import Page
from fastapi_pagination.ext.tortoise import paginate
from apollo.db import RedHatAdvisory
from apollo.db.serialize import RedHatAdvisory_Pydantic
router = APIRouter(tags=["red_hat"])
T = TypeVar("T")
class Pagination(Page[T], Generic[T]):
class Config:
allow_population_by_field_name = True
fields = {"items": {"alias": "advisories"}}
@router.get(
"/advisories",
response_model=Pagination[RedHatAdvisory_Pydantic],
)
async def list_red_hat_advisories(request: Request):
if not request.state.settings.serve_rh_advisories:
raise HTTPException(404)
advisories = await paginate(
RedHatAdvisory.all().prefetch_related(
"packages",
"cves",
"bugzilla_tickets",
"affected_products",
).order_by("-red_hat_issued_at")
)
return advisories
@router.get(
"/advisories/{advisory_name}",
response_model=RedHatAdvisory_Pydantic,
)
async def get_red_hat_advisory(request: Request, advisory_name: str):
if not request.state.settings.serve_rh_advisories:
raise HTTPException(404)
advisory = await RedHatAdvisory.filter(name=advisory_name).prefetch_related(
"packages",
"cves",
"bugzilla_tickets",
"affected_products",
).first()
if advisory is None:
raise HTTPException(404)
return RedHatAdvisory_Pydantic.from_orm(advisory)

View File

@ -0,0 +1,132 @@
from fastapi import APIRouter, Request, Form
from fastapi.responses import HTMLResponse, RedirectResponse
from tortoise.expressions import Q
from apollo.server.utils import templates
from apollo.server.roles import ADMIN
from apollo.server.utils import pwd_context
from apollo.server.settings import OIDC_PROVIDER_NAME, OIDC_PROVIDER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET
from apollo.db import User, Settings
router = APIRouter(tags=["non-api"])
@router.get("/", response_class=HTMLResponse)
async def login_page(request: Request):
if request.session.get("user"):
return RedirectResponse("/", status_code=302)
user_count = await User.all().count()
should_show_setup = user_count == 0
ctx = {
"request": request,
"should_show_setup": should_show_setup,
}
if not should_show_setup:
# Check if we have OIDC_PROVIDER, OIDC_CLIENT_ID and OIDC_CLIENT_SECRET set
# If so, show the OIDC login button
# If OIDC_PROVIDER_NAME is set, use that as the button text
# Otherwise, use "Login with OIDC"
settings = await Settings.filter(
Q(name=OIDC_PROVIDER_NAME) | Q(name=OIDC_PROVIDER) |
Q(name=OIDC_CLIENT_ID) | Q(name=OIDC_CLIENT_SECRET)
).all()
if len(settings) >= 3:
provider_name = "Login with OIDC"
# Check if we have OIDC_PROVIDER_NAME set
for setting in settings:
if setting.name == OIDC_PROVIDER_NAME:
provider_name = setting.value
break
ctx["oidc_provider_name"] = provider_name
return templates.TemplateResponse("login.jinja", ctx)
@router.post("/", response_class=HTMLResponse)
async def do_login(
request: Request,
email: str = Form(default=None),
password: str = Form(default=None)
):
if request.session.get("user"):
return RedirectResponse("/", status_code=302)
if not email or not password:
return templates.TemplateResponse(
"login.jinja", {
"request": request,
"error": "Email and password are required",
}
)
user = await User.get(email=email)
if not user:
return templates.TemplateResponse(
"login.jinja", {
"request": request,
"error": "Invalid email or password",
}
)
if not pwd_context.verify(password, user.password):
return templates.TemplateResponse(
"login.jinja", {
"request": request,
"error": "Invalid email or password",
}
)
request.session["user"] = user.id
request.session["user.name"] = user.name
request.session["user.role"] = user.role
return RedirectResponse("/", status_code=302)
@router.post(
"/setup",
response_class=HTMLResponse,
)
async def setup_page(
request: Request,
name: str = Form(default=None),
email: str = Form(default=None),
password: str = Form(default=None),
confirm_password: str = Form(default=None),
):
user_count = await User.all().count()
if user_count > 0:
return RedirectResponse("/")
error = None
if not name:
error = "Name is required"
elif not email:
error = "Email is required"
elif "@" not in email:
error = "Email is invalid"
elif not password:
error = "Password is required"
elif not confirm_password:
error = "Confirm password is required"
elif password != confirm_password:
error = "Passwords do not match"
if error:
return templates.TemplateResponse(
"login.jinja", {
"request": request,
"should_show_setup": True,
"error": error,
}
)
await User.create(
name=name, email=email, password=pwd_context.hash(password), role=ADMIN
)
return templates.TemplateResponse(
"login.jinja", {
"request": request,
"should_show_setup_success": True,
}
)

View File

@ -0,0 +1,16 @@
from fastapi import APIRouter, Request
from fastapi.responses import RedirectResponse
router = APIRouter(tags=["non-api"])
@router.get("/")
async def logout(request: Request):
if request.session.get("user"):
request.session.pop("user")
if request.session.get("user.name"):
request.session.pop("user.name")
if request.session.get("user.role"):
request.session.pop("user.role")
return RedirectResponse("/", status_code=302)

View File

@ -0,0 +1,85 @@
from math import ceil
from fastapi import APIRouter, Request, Depends, Form
from fastapi.responses import HTMLResponse
from fastapi_pagination import Params
from fastapi_pagination.ext.tortoise import paginate
from apollo.db import RedHatAdvisory
from apollo.server.utils import admin_user_scheme, templates
from common.fastapi import RenderErrorTemplateException
router = APIRouter(tags=["non-api"])
@router.get(
"/advisories",
response_class=HTMLResponse,
)
async def list_red_hat_advisories(request: Request, params: Params = Depends()):
if not request.state.settings.serve_rh_advisories:
raise RenderErrorTemplateException()
params.size = 50
advisories = await paginate(
RedHatAdvisory.all().order_by("-red_hat_issued_at"),
params=params,
)
return templates.TemplateResponse(
"red_hat_advisories.jinja", {
"request": request,
"advisories": advisories,
"advisories_pages": ceil(advisories.total / advisories.size),
}
)
@router.get(
"/advisories/{advisory_name}",
response_class=HTMLResponse,
)
async def get_red_hat_advisory(request: Request, advisory_name: str):
if not request.state.settings.serve_rh_advisories:
raise RenderErrorTemplateException()
advisory = await RedHatAdvisory.get_or_none(
name=advisory_name,
).prefetch_related(
"packages",
"cves",
"bugzilla_tickets",
"affected_products",
"rpm_rh_overrides",
"rpm_rh_overrides__supported_products_rh_mirror",
"published_advisories",
)
if advisory is None:
return templates.TemplateResponse(
"error.jinja", {
"request": request,
"message": "Requested advisory not found",
}
)
return templates.TemplateResponse(
"red_hat_advisory.jinja", {
"request": request,
"advisory": advisory,
"title": f"Red Hat Advisory {advisory.id}",
}
)
@router.post(
"/advisories/{advisory_name}",
response_class=HTMLResponse,
dependencies=[Depends(admin_user_scheme)],
)
async def execute_red_hat_advisory_action(
request: Request,
advisory_name: str,
action: str = Form(),
data: str = Form()
):
pass

View File

@ -0,0 +1,20 @@
from fastapi import APIRouter, Request
from fastapi.responses import HTMLResponse
from apollo.db import RedHatAdvisory, Advisory
from apollo.server.utils import templates
router = APIRouter(tags=["non-api"])
@router.get("/", response_class=HTMLResponse)
async def statistics(request: Request):
rh_advisory_count = await RedHatAdvisory.all().count()
advisory_count = await Advisory.all().count()
return templates.TemplateResponse(
"index.jinja", {
"request": request,
"rh_advisory_count": rh_advisory_count,
"advisory_count": advisory_count,
}
)

103
apollo/server/server.py Normal file
View File

@ -0,0 +1,103 @@
import secrets
from tortoise import Tortoise
Tortoise.init_models(["apollo.db"], "models") # noqa # pylint: disable=wrong-import-position
from fastapi import FastAPI, Request, Depends
from fastapi.responses import JSONResponse
from starlette.middleware.sessions import SessionMiddleware
from fastapi_pagination import add_pagination
from apollo.server.routes.statistics import router as statistics_router
from apollo.server.routes.login import router as login_router
from apollo.server.routes.logout import router as logout_router
from apollo.server.routes.admin_index import router as admin_index_router
from apollo.server.routes.api_advisories import router as api_advisories_router
from apollo.server.routes.api_compat import router as api_compat_router
from apollo.server.routes.api_red_hat import router as api_red_hat_router
from apollo.server.routes.advisories import router as advisories_router
from apollo.server.routes.red_hat_advisories import router as red_hat_advisories_router
from apollo.server.settings import SECRET_KEY, SettingsMiddleware, get_setting
from apollo.server.utils import admin_user_scheme, templates
from apollo.db import Settings
from common.info import Info
from common.logger import Logger
from common.database import Database
from common.fastapi import StaticFilesSym, RenderErrorTemplateException
app = FastAPI()
app.mount(
"/static", StaticFilesSym(directory="apollo/server/static"), name="static"
)
app.mount(
"/assets", StaticFilesSym(directory="apollo/server/assets"), name="assets"
)
app.add_middleware(SettingsMiddleware)
app.include_router(advisories_router)
app.include_router(statistics_router, prefix="/statistics")
app.include_router(login_router, prefix="/login")
app.include_router(logout_router, prefix="/logout")
app.include_router(
admin_index_router,
prefix="/admin",
dependencies=[Depends(admin_user_scheme)]
)
app.include_router(red_hat_advisories_router, prefix="/red_hat")
app.include_router(api_advisories_router, prefix="/api/v3/advisories")
app.include_router(api_compat_router, prefix="/v2/advisories")
app.include_router(api_red_hat_router, prefix="/api/v3/red_hat")
add_pagination(app)
Info("apollo2")
Logger()
Database(True, app, ["apollo.db"])
@app.exception_handler(404)
async def not_found_handler(request, exc):
if request.url.path.startswith("/api"
) or request.url.path.startswith("/v2"):
return JSONResponse({"error": "Not found"}, status_code=404)
return await render_template_exception_handler(request, None)
@app.exception_handler(RenderErrorTemplateException)
async def render_template_exception_handler(
request: Request, exc: RenderErrorTemplateException
):
if request.url.path.startswith("/api"
) or request.url.path.startswith("/v2"):
return JSONResponse(
{"error": exc.msg if exc and exc.msg else "Not found"},
status_code=exc.status_code if exc and exc.status_code else 404,
)
return templates.TemplateResponse(
"error.jinja", {
"request": request,
"message": exc.msg if exc and exc.msg else "Page not found",
},
status_code=exc.status_code if exc and exc.status_code else 404
)
@app.on_event("startup")
async def startup():
# Generate secret-key if it does not exist in the database
secret_key = await get_setting(SECRET_KEY)
if not secret_key:
# Generate random secret key
secret_key = secrets.token_hex(32)
await Settings.create(name=SECRET_KEY, value=secret_key)
# Mount SessionMiddleware
app.add_middleware(
SessionMiddleware,
secret_key=secret_key,
max_age=60 * 60 * 24 * 7, # 1 week
)

64
apollo/server/settings.py Normal file
View File

@ -0,0 +1,64 @@
from typing import Optional
from dataclasses import dataclass
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from apollo.db import Settings
from apollo.server.utils import is_admin_user
SECRET_KEY = "secret-key"
OIDC_PROVIDER_NAME = "oidc-provider-name"
OIDC_PROVIDER = "oidc-provider"
OIDC_CLIENT_ID = "oidc-client-id"
OIDC_CLIENT_SECRET = "oidc-client-secret"
OIDC_ADMIN_ROLE = "oidc-admin-role"
OIDC_ELEVATED_ROLE = "oidc-elevated-role"
RH_MATCH_STALE = "rh-match-stale"
DISABLE_SERVING_RH_ADVISORIES = "disable-serving-rh-advisories"
async def get_setting(name: str) -> Optional[str]:
setting = await Settings.filter(name=name).get_or_none()
if setting is None:
return None
return setting.value
async def get_setting_bool(name: str) -> Optional[bool]:
setting = await Settings.filter(name=name).get_or_none()
if setting is None:
return None
return setting.value == "True"
async def should_serve_red_hat_advisories(request: Request) -> bool:
setting = await get_setting_bool(DISABLE_SERVING_RH_ADVISORIES)
admin_user = await is_admin_user(request)
if setting and not admin_user:
return False
return True
@dataclass
class SettingsContext:
serve_rh_advisories: bool
is_admin: bool
class SettingsMiddleware(BaseHTTPMiddleware):
async def dispatch(
self, request: Request, call_next: RequestResponseEndpoint
) -> Response:
should_serve_rh_advisories = await should_serve_red_hat_advisories(
request
)
request.state.settings = SettingsContext(
serve_rh_advisories=should_serve_rh_advisories,
is_admin=await is_admin_user(request),
)
return await call_next(request)

View File

@ -0,0 +1,20 @@
load("@aspect_rules_esbuild//esbuild:defs.bzl", "esbuild")
srcs = glob([
"*.ts",
"*.scss",
])
esbuild(
name = "static",
srcs = srcs + [
"//:node_modules/@carbon/themes",
"//:node_modules/@carbon/web-components",
"//:node_modules/carbon-components",
"//:node_modules/esbuild-sass-plugin",
],
config = ":esbuild.config.mjs",
entry_point = "index.ts",
output_css = "static.css",
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,11 @@
import { sassPlugin } from 'esbuild-sass-plugin';
export default {
keepNames: true,
resolveExtensions: ['.ts', '.js', '.tsx', '.jsx'],
plugins: [sassPlugin()],
define: {
'process.env.NODE_ENV': '"production"',
'window.process.env.DEBUG': 'undefined',
},
};

View File

@ -0,0 +1,94 @@
import './theme.scss';
import '@carbon/web-components/es/components/ui-shell';
import '@carbon/web-components/es/components/structured-list';
import '@carbon/web-components/es/components/data-table';
import '@carbon/web-components/es/components/pagination';
import '@carbon/web-components/es/components/form';
import '@carbon/web-components/es/components/input';
import '@carbon/web-components/es/components/button';
import '@carbon/web-components/es/components/notification';
import '@carbon/web-components/es/components/tag';
import '@carbon/web-components/es/components/list';
function fixForm() {
const buttons = document.querySelectorAll('bx-btn');
buttons.forEach((button) => {
if (!button.getAttribute('form_id')) {
return;
}
const form: any = document.querySelector(
'form#' + button.getAttribute('form_id')
);
if (form) {
button.addEventListener('click', () => {
form.submit();
});
}
});
// Also do the same for bx-input and enter key
const inputs = document.querySelectorAll('bx-input');
inputs.forEach((input) => {
input.addEventListener('keydown', (evt: any) => {
if (!input.getAttribute('form_id')) {
return;
}
if (evt.key === 'Enter') {
const form: any = document.querySelector(
'form#' + input.getAttribute('form_id')
);
if (form) {
form.submit();
}
}
});
});
}
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('bx-pagination').forEach((el) => {
el.addEventListener('bx-pagination-changed-current', function (evt: any) {
const pageSize = parseInt(el.getAttribute('page-size') || '0');
const newPage = Math.ceil(evt.detail.start / pageSize) + 1;
const searchParams = new URLSearchParams(window.location.search);
searchParams.set('page', newPage.toString());
window.location.search = searchParams.toString();
});
});
// Add "active" if location has prefix, e.g. /admin/ -> /admin
// For / only we need to check if the location is exactly /
const pathname = window.location.pathname;
document.querySelectorAll('bx-side-nav-link').forEach((el) => {
const href = el.getAttribute('href');
if (href === '/') {
if (pathname === '/') {
el.setAttribute('active', '');
}
} else if (pathname.startsWith(href || '')) {
el.setAttribute('active', '');
}
});
// Change "search" query parameter when the search field encounters Enter
const searchToolbar: any = document.querySelector('bx-table-toolbar-search');
if (searchToolbar) {
const searchBar: any =
searchToolbar.shadowRoot.querySelector('.bx--search-input');
if (searchBar) {
searchBar.addEventListener('keydown', (evt: any) => {
if (evt.key === 'Enter') {
const searchParams = new URLSearchParams(window.location.search);
searchParams.set('search', searchBar.value);
searchParams.set('page', '1');
window.location.search = searchParams.toString();
}
});
}
}
fixForm();
});

View File

@ -0,0 +1,19 @@
$feature-flags: (
enable-css-custom-properties: true,
grid-columns-16: true,
);
@use 'carbon-components/scss/globals/scss/vendor/@carbon/elements/scss/themes/generated/themes';
@import 'carbon-components/scss/globals/scss/styles.scss';
:root {
@include carbon--theme($carbon--theme--g90, true);
}
a {
color: map-get($carbon--theme--g90, 'link-01');
}
.bx--inline-notification__text-wrapper {
width: 100%;
}

View File

View File

@ -0,0 +1,5 @@
{% extends "admin_layout.jinja" %}
{% block admin_content %}
test
{% endblock %}

View File

@ -0,0 +1,53 @@
{% extends "layout.jinja" %}
{% block head %}
<style>
bx-side-nav {
margin-top: 3rem;
height: calc(100% - 3rem);
}
.bx--container {
will-change: margin-left;
transition: margin-left .11s cubic-bezier(0.2, 0, 1, 0.9)
}
@media(min-width: 66rem) {
.bx--container {
margin-left: 16rem
}
}
.bx--with-rail .bx--container {
margin-left: 3rem
}
@media(min-width: 66rem) {
.bx--rail-expanded .bx--container {
margin-left: 16rem
}
}
@media(min-width: 66rem) {
.bx--with-side-nav-for-header .bx--container {
margin-left: 0
}
}
.bx--main {
height: 100%;
}
</style>
{% endblock %}
{% block content %}
<bx-side-nav aria-label="Side navigation" expanded>
<bx-side-nav-items>
<bx-side-nav-link href="/admin">General</bx-side-nav-link>
<bx-side-nav-link href="/admin/users">Users</bx-side-nav-link>
<bx-side-nav-link href="/admin/oidc">OIDC</bx-side-nav-link>
</bx-side-nav-items>
</bx-side-nav>
{% block admin_content %}{% endblock %}
{% endblock %}

View File

@ -0,0 +1,45 @@
{% extends "layout.jinja" %}
{% block content %}
<h2 style="margin-bottom:1rem;">Advisories</h2>
<bx-pagination page-size="{{ advisories.size }}" start="{{ (advisories.page-1) * advisories.size }}"
total="{{ advisories.total }}">
<bx-page-sizes-select slot="page-sizes-select">
<option value="50">50</option>
</bx-page-sizes-select>
<bx-pages-select value="{{ advisories.page - 1 }}" total="{{ advisories_pages }}"></bx-pages-select>
</bx-pagination>
<bx-data-table>
<bx-table-toolbar>
<bx-table-toolbar-content>
<bx-table-toolbar-search expanded value="{{ search }}">
</bx-table-toolbar-search>
</bx-table-toolbar-content>
</bx-table-toolbar>
<bx-table>
<bx-table-head>
<bx-table-header-row>
<bx-table-header-cell>Name</bx-table-header-cell>
<bx-table-header-cell>Synopsis</bx-table-header-cell>
<bx-table-header-cell>Created at</bx-table-header-cell>
<bx-table-header-cell>Issued at</bx-table-header-cell>
<bx-table-header-cell>Kind</bx-table-header-cell>
<bx-table-header-cell>Severity</bx-table-header-cell>
</bx-table-header-row>
</bx-table-head>
<bx-table-body>
{% for advisory in advisories.items -%}
<bx-table-row>
<bx-table-cell><a href="/{{ advisory.name }}">{{ advisory.name }}</a></bx-table-cell>
<bx-table-cell>{{ advisory.synopsis }}</bx-table-cell>
<bx-table-cell>{{ advisory.created_at.date() }}</bx-table-cell>
<bx-table-cell>{{ advisory.published_at.date() }}</bx-table-cell>
<bx-table-cell>{{ advisory.kind }}</bx-table-cell>
<bx-table-cell>{{ advisory.severity }}</bx-table-cell>
</bx-table-row>
{% endfor %}
</bx-table-body>
</bx-table>
</bx-data-table>
{% endblock %}

View File

@ -0,0 +1,103 @@
{% extends "layout.jinja" %}
{% block content %}
<div class="bx--grid bx--grid--full-width">
<div style="display:flex;align-items:center;padding-top:0.3rem;">
<h1 style="padding-right:0.4rem;">{{ advisory.name }}</h1>
{% if advisory.kind == "Security" %}
{% set advisory_tag_type = "red" %}
{% elif advisory.kind == "Bug Fix" %}
{% set advisory_tag_type = "purple" %}
{% elif advisory.kind == "Enhancement" %}
{% set advisory_tag_type = "teal" %}
{% endif %}
<bx-tag type="{{ advisory_tag_type }}">{{ advisory.kind }}</bx-tag>
{% if advisory.red_hat_advisory_id %}
<bx-tag type="blue">
Mirrored from
{% if request.state.settings.serve_rh_advisories %}
<a href="/red_hat/advisories/{{ advisory.red_hat_advisory.name}}"
style="color:var(--cds-tag-color-blue);margin-left:0.2rem;">
{{advisory.red_hat_advisory.name }}
</a>
{% else %}
<a target="_blank" href="https://access.redhat.com/errata/{{ advisory.red_hat_advisory.name }}"
style="color:var(--cds-tag-color-blue);margin-left:0.2rem;">
{{ advisory.red_hat_advisory.name }}
</a>
{% endif %}
</bx-tag>
{% endif %}
</div>
<div style="display:flex;align-items:center;padding-top:0.3rem;">
<h5 style="font-weight:500;margin-right:1rem;">
Issued at: <span style="font-weight:400;">{{ advisory.published_at.date() }}</span>
</h5>
<h5 style="font-weight:500">Updated at: <span style="font-weight:400;">{{ advisory.updated_at.date() }}</span></h5>
</div>
</div>
<div class="bx--grid bx--grid--full-width" style="margin:3rem 0;">
<div class="bx--row">
<div class="bx--col-lg-10">
<div style="background:var(--cds-ui-02);color:var(--cds-text-01);padding:2rem;">
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Synopsis</h3>
<p>{{ advisory.synopsis }}</p>
<br /><br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Description</h3>
{% set description = advisory.description.split("\n") %}
{% for line in description %}
<p>{{ line }}</p>
{% endfor %}
<br /><br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Affected products</h3>
<bx-ordered-list>
{% for product in advisory.affected_products %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">{{ product.name }}</bx-list-item>
{% endfor %}
</bx-ordered-list>
<br /> <br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Fixes</h3>
<bx-ordered-list>
{% for fix in advisory.fixes %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">
<a target="_blank" href="{{ fix.source }}">{{ fix.ticket_id }}</a>
</bx-list-item>
{% endfor %}
</bx-ordered-list>
<br /> <br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">CVEs</h3>
<bx-ordered-list>
{% for cve in advisory.cves %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">
<a target="_blank" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name={{ cve.cve }}">
{{ cve.cve }}
</a>
</bx-list-item>
{% endfor %}
</bx-ordered-list>
</div>
</div>
<div class="bx--col-lg-6">
<div style="background:var(--cds-ui-02);color:var(--cds-text-01);padding:2rem;">
<h3 style="font-weight:600;color:var(--cds-text-04);">Affected packages</h3>
{% for product_repo_name, nevras in package_map.items() %}
<h4 style="padding-bottom:0.3rem;font-weight:400;padding-top:0.3rem;">{{ product_repo_name }}</h4>
<bx-ordered-list>
{% for nevra in nevras %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">
{{ nevra }}
</bx-list-item>
{% endfor %}
</bx-list-item>
</bx-ordered-list>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,5 @@
{% extends "layout.jinja" %}
{% block content %}
<h1>{{ message }}</h1>
{% endblock %}

View File

@ -0,0 +1,27 @@
{% extends "layout.jinja" %}
{% block content %}
<h2>Statistics</h2>
<bx-structured-list>
<bx-structured-list-head>
<bx-structured-list-header-row>
<bx-structured-list-header-cell>Service</bx-structured-list-header-cell>
<bx-structured-list-header-cell>Resource</bx-structured-list-header-cell>
<bx-structured-list-header-cell>Value</bx-structured-list-header-cell>
</bx-structured-list-header-row>
</bx-structured-list-head>
<bx-structured-list-body>
<bx-structured-list-row>
<bx-structured-list-cell>rpmworker</bx-structured-list-cell>
<bx-structured-list-cell>Advisories</bx-structured-list-cell>
<bx-structured-list-cell>{{ advisory_count }}</bx-structured-list-cell>
</bx-structured-list-row>
<bx-structured-list-row>
<bx-structured-list-cell>rhworker</bx-structured-list-cell>
<bx-structured-list-cell>Red Hat Advisories</bx-structured-list-cell>
<bx-structured-list-cell>{{ rh_advisory_count }}</bx-structured-list-cell>
</bx-structured-list-row>
</bx-structured-list-body>
</bx-structured-list>
{% endblock %}

View File

@ -0,0 +1,12 @@
<svg version="1.1" id="icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
y="0px" width="16px" height="16px" viewBox="0 0 16 16" style="enable-background:new 0 0 16 16;" xml:space="preserve">
<style type="text/css">
.st0 {
fill: none;
}
</style>
<title>launch</title>
<path fill="currentColor" d="M13,14H3c-0.6,0-1-0.4-1-1V3c0-0.6,0.4-1,1-1h5v1H3v10h10V8h1v5C14,13.6,13.6,14,13,14z" />
<polygon fill="currentColor" points="10,1 10,2 13.3,2 9,6.3 9.7,7 14,2.7 14,6 15,6 15,1 " />
<rect id="_Transparent_Rectangle_" class="st0" width="16" height="16" />
</svg>

After

Width:  |  Height:  |  Size: 627 B

View File

@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Peridot Apollo{% endblock %}</title>
<link rel="stylesheet" href="/static/static.css">
<script src="/static/static.js"></script>
<style>
.bx--main {
padding: 2rem 1rem;
}
</style>
<style>
.apollo-outer {
margin-top: 3rem;
padding: 0;
}
.apollo-outer bx-inline-notification {
margin: 0;
color: #ffffff;
--cds-inverse-01: #ffffff;
background: var(--cds-button-separator);
}
.apollo-outer bx-inline-notification:not(.top-notification) {
width: 100%;
max-width: 100% !important;
}
.apollo-outer bx-inline-notification.top-notification {
background: var(--cds-field-01);
border-left: 0;
border-bottom: 1px solid var(--apollo-notification-border-color, var(--apollo-notification-text-color));
max-width: 100%;
margin-top: 4rem;
color: var(--apollo-notification-text-color);
}
.apollo-outer bx-inline-notification~#apollo-notification-wrapper>bx-inline-notification {
margin-top: 2rem;
}
</style>
{% if notification %}
{% if notification.get("kind") == "error" %}
<style>
:root {
--apollo-notification-text-color: var(--cds-danger-02);
}
</style>
{% elif notification.get("kind") == "success" %}
<style>
:root {
--apollo-notification-border-color: var(--cds-inverse-support-02);
}
</style>
{% elif notification.get("kind") == "warning" %}
<style>
:root {
--apollo-notification-text-color: var(--cds-inverse-support-03);
}
</style>
{% else %}
<style>
:root {
--apollo-notification-text-color: #ffffff;
}
</style>
{% endif %}
{% endif %}
{% block head %}{% endblock %}
</head>
<body class="bx--body">
<bx-header aria-label="Apollo">
<bx-header-menu-button button-label-active="Close menu" button-label-inactive="Open menu"></bx-header-menu-button>
<bx-header-name href="/" prefix="Peridot">[Apollo]</bx-header-name>
<bx-header-nav menu-bar-label="Peridot [Apollo]">
<bx-header-nav-item href="/">Advisories</bx-header-nav-item>
{% if request.state.settings.serve_rh_advisories %}
<bx-header-nav-item href="/red_hat/advisories/">Red Hat Advisories</bx-header-nav-item>
{% endif %}
<bx-header-nav-item href="/statistics/">Statistics</bx-header-nav-item>
{% if request.state.settings.is_admin %}
<bx-header-nav-item href="/admin/">Admin</bx-header-nav-item>
{% endif %}
</bx-header-nav>
<bx-header-nav style="margin-left:auto;padding-left:0">
{% if request.session.get("user.name") %}
<bx-header-nav-item>{{ request.session.get("user.name") }}</bx-header-nav-item>
<bx-header-nav-item href="/logout/">Logout</bx-header-nav-item>
{% else %}
<bx-header-nav-item href="/login/">Login</bx-header-nav-item>
{% endif %}
</bx-header-nav>
</bx-header>
<div class="apollo-outer">
{% block outer_content %}{% endblock %}
{% if title %}
<bx-inline-notification kind="info" title="{{ title }}" hide-close-button>
</bx-inline-notification>
{% endif %}
{% if notification %}
<div id="apollo-notification-wrapper" style="margin:0 3.5rem">
<bx-inline-notification class="top-notification" kind="{{ notification.get('kind', 'none') }}"
title="{{ notification['title'] }}" subtitle="{{ notification['subtitle'] }}"
hide-close-button></bx-inline-notification>
</div>
{% endif %}
</div>
<main class="bx--main bx--container">
{% block content %}{% endblock %}
</main>
</body>
</html>

View File

@ -0,0 +1,89 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Peridot Apollo</title>
<link rel="stylesheet" href="/static/static.css">
<script src="/static/static.js"></script>
<style>
body {
font-family: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif
}
</style>
</head>
<body>
<div style="display:flex;flex-flow:column;justify-content:center;align-items:center;width:100vw;height:100vh">
<div style="display:flex;justify-content:center;align-items:center;">
<img alt="Peridot logo " height="80px" src="/assets/pd-logo-np.svg" /><br />
<h3 style="padding-left:1rem;font-weight:600;">Apollo<br />Errata Management</h3>
</div>
{% if error %}
<div style="margin-top:3rem;">
<h5 style="color:#fa4d56;border-left:0;margin:0;">
{{ error }}
</h5>
</div>
{% endif %}
{% if should_show_setup_success %}
<div style="margin-top:3rem;">
<h5 style="color:#198038;border-left:0;margin:0;">
Admin user created successfully. Please login.
</h5>
</div>
{% endif %}
<div style="width:100%;max-width:450px;margin-top:2rem;">
{% if should_show_setup %}
<form id="signup_form" action="/login/setup" method="POST">
<bx-form-item>
<bx-input required name="name" form_id="signup_form">
<span slot="label-text">Name</span>
</bx-input>
<bx-input required name="email" type="email" form_id="signup_form">
<span slot="label-text">Email</span>
</bx-input>
<bx-input required name="password" type="password" form_id="signup_form">
<span slot="label-text">Password</span>
</bx-input>
<bx-input required name="confirm_password" type="password" form_id="signup_form">
<span slot="label-text">Confirm Password</span>
</bx-input>
<div
style="display:flex;justify-content:space-between;align-items:center;flex-direction:row-reverse;margin-top:25px;width:100%">
<bx-btn type="submit" style="margin-left:auto;display:block" form_id="signup_form">Create
admin user</bx-btn>
</div>
</bx-form-item>
</form>
{% else %}
<form id="login_form" action=" /login/" method="POST">
<bx-form-item>
<bx-input required name="email" type="email" form_id="login_form">
<span slot="label-text">Email</span>
</bx-input>
<bx-input required name="password" type="password" form_id="login_form">
<span slot="label-text">Password</span>
</bx-input>
<div
style="display:flex;justify-content:space-between;align-items:center;flex-direction:row-reverse;margin-top:25px;width:100%">
<bx-btn type="submit" style="margin-left:auto;display:block" form_id="login_form">Login</bx-btn>
{% if oidc_provider_name %}
<bx-btn href="/login/oidc" size="sm" kind="ghost" style="display:block;">{{ oidc_provider_name }}</bx-btn>
{% endif %}
</div>
</bx-form-item>
</form>
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,39 @@
{% extends "layout.jinja" %}
{% block content %}
<h2 style="margin-bottom:1rem;">Red Hat Advisories</h2>
<bx-pagination page-size="{{ advisories.size }}" start="{{ (advisories.page-1) * advisories.size }}"
total="{{ advisories.total }}">
<bx-page-sizes-select slot="page-sizes-select">
<option value="50">50</option>
</bx-page-sizes-select>
<bx-pages-select value="{{ advisories.page - 1 }}" total="{{ advisories_pages }}"></bx-pages-select>
</bx-pagination>
<bx-data-table>
<bx-table>
<bx-table-head>
<bx-table-header-row>
<bx-table-header-cell>Name</bx-table-header-cell>
<bx-table-header-cell>Synopsis</bx-table-header-cell>
<bx-table-header-cell>Issued at</bx-table-header-cell>
<bx-table-header-cell>Indexed at</bx-table-header-cell>
<bx-table-header-cell>Kind</bx-table-header-cell>
<bx-table-header-cell>Severity</bx-table-header-cell>
</bx-table-header-row>
</bx-table-head>
<bx-table-body>
{% for advisory in advisories.items -%}
<bx-table-row>
<bx-table-cell><a href="/red_hat/advisories/{{ advisory.name }}">{{ advisory.name }}</a></bx-table-cell>
<bx-table-cell>{{ advisory.synopsis }}</bx-table-cell>
<bx-table-cell>{{ advisory.red_hat_issued_at.date() }}</bx-table-cell>
<bx-table-cell>{{ advisory.created_at.date() }}</bx-table-cell>
<bx-table-cell>{{ advisory.kind }}</bx-table-cell>
<bx-table-cell>{{ advisory.severity }}</bx-table-cell>
</bx-table-row>
{% endfor %}
</bx-table-body>
</bx-table>
</bx-data-table>
{% endblock %}

View File

@ -0,0 +1,146 @@
{% extends "layout.jinja" %}
{% block content %}
<div class="bx--grid bx--grid--full-width" style="margin:0;">
<div class="bx--row">
<div class="bx--col-lg-15">
<div style="display:flex;align-items:center;padding-top:0.3rem;">
<h1 style="padding-right:0.4rem;">{{ advisory.name }}</h1>
{% if advisory.kind == "Security" %}
{% set advisory_tag_type = "red" %}
{% elif advisory.kind == "Bug Fix" %}
{% set advisory_tag_type = "purple" %}
{% elif advisory.kind == "Enhancement" %}
{% set advisory_tag_type = "teal" %}
{% endif %}
<bx-tag type="{{ advisory_tag_type }}">{{ advisory.kind }}</bx-tag>
{% for override in advisory.rpm_rh_overrides %}
<bx-tag type="blue">
Override for {{ override.supported_products_rh_mirror.name }}
</bx-tag>
{% endfor %}
</div>
<div style="display:flex;align-items:center;padding-top:0.3rem;">
<h5 style="font-weight:500;margin-right:1rem;">
Issued at: <span style="font-weight:400;">{{advisory.red_hat_issued_at.date() }}</span>
</h5>
</div>
</div>
</div>
<div class="bx--row" style="margin-top:1rem;">
<div class="bx--col">
<div style="display:flex;align-items:center">
<bx-btn kind="primary" target="_blank" href="https://access.redhat.com/errata/{{ advisory.name }}"
style="margin-right:1rem;">
{% include "launch_icon.jinja" %}
<div style="margin-left:1rem;">
Open original
</div>
</bx-btn>
<form id="override" action="/red_hat/advisories/{{ advisory.name }}" method="POST">
<input type="hidden" name="action" value="override" />
<bx-btn kind="primary" form_id="override">Override</bx-button>
</form>
</div>
</div>
</div>
<!--<div class="bx--row" style="margin-top:1rem;">
<div class="bx--col">
<div style="display:flex;align-items:center;">
{% if advisory.kind == "Security" %}
{% set advisory_tag_type = "red" %}
{% elif advisory.kind == "Bug Fix" %}
{% set advisory_tag_type = "purple" %}
{% elif advisory.kind == "Enhancement" %}
{% set advisory_tag_type = "teal" %}
{% endif %}
<bx-tag type="{{ advisory_tag_type }}">{{ advisory.kind }}</bx-tag>
{% for override in advisory.rpm_rh_overrides %}
<bx-tag type="blue">
Override for {{ override.supported_products_rh_mirror.name }}
</bx-tag>
{% endfor %}
</div>
</div>
</div>-->
</div>
<div class="bx--grid bx--grid--full-width" style="margin:3rem 0;">
<div class="bx--row">
<div class="bx--col-lg-10">
<div style="background:var(--cds-ui-02);color:var(--cds-text-01);padding:2rem;">
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Synopsis</h3>
<p>{{ advisory.synopsis }}</p>
<br /><br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Description</h3>
{% set description = advisory.description.split("\n") %}
{% for line in description %}
<p>{{ line }}</p>
{% endfor %}
<br /><br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Affected products</h3>
<bx-ordered-list>
{% for product in advisory.affected_products %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">
{{ product.name }} - {{ product.major_version }}{% if product.minor_version %}.{{ product.minor_version }}{%
endif %}
</bx-list-item>
{% endfor %}
</bx-ordered-list>
<br /> <br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Fixes</h3>
<bx-ordered-list>
{% for ticket in advisory.bugzilla_tickets %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">
<a target="_blank" href="https://bugzilla.redhat.com/show_bug.cgi?id={{ ticket.bugzilla_bug_id }}">
{{ ticket.bugzilla_bug_id }}
</a>
</bx-list-item>
{% endfor %}
</bx-ordered-list>
<br /> <br />
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">CVEs</h3>
<bx-ordered-list>
{% for cve in advisory.cves %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">
<a target="_blank" href="https://cve.mitre.org/cgi-bin/cvename.cgi?name={{ cve.cve }}">
{{ cve.cve }}
</a>
</bx-list-item>
{% endfor %}
</bx-ordered-list>
</div>
</div>
<div class="bx--col-lg-6">
<div style="background:var(--cds-ui-02);color:var(--cds-text-01);padding:2rem;">
{% set pkg_list = {} %}
{% for pkg in advisory.packages %}
{% if pkg.repo_name in pkg_list %}
{% set x=pkg_list.__getitem__(pkg.repo_name).append(pkg) %}
{% else %}
{% set x=pkg_list.__setitem__(pkg.repo_name, [pkg]) %}
{% endif %}
{% endfor %}
<h3 style="font-weight:600;color:var(--cds-text-04);padding-bottom:0.3rem;">Affected packages</h3>
{% for repo_name, pkg in pkg_list.items() %}
<h4 style="padding-bottom:0.3rem;font-weight:400;">{{ repo_name }}</h4>
<bx-ordered-list>
{% for p in pkg %}
<bx-list-item style="font-size:var(--cds-body-short-02-font-size)">
{{ p.nevra }}
</bx-list-item>
{% endfor %}
</bx-list-item>
</bx-ordered-list>
{% endfor %}
</div>
</div>
</div>
</div>
{% endblock %}

50
apollo/server/utils.py Normal file
View File

@ -0,0 +1,50 @@
from fastapi import Request
from fastapi.templating import Jinja2Templates
from passlib.context import CryptContext
from apollo.db import User
from apollo.server.roles import ADMIN
from common.fastapi import RenderErrorTemplateException
# Do not remove import (for gazelle)
import jinja2 # noqa # pylint: disable=unused-import
import multipart # noqa # pylint: disable=unused-import
import itsdangerous # noqa # pylint: disable=unused-import
templates = Jinja2Templates(directory="apollo/server/templates")
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
async def admin_user_scheme(request: Request) -> User:
user = await user_scheme(request, raise_exc=False)
if not user:
raise RenderErrorTemplateException(
"You need to log in to access this page",
status_code=401,
)
elif user.role != ADMIN:
raise RenderErrorTemplateException(
"You are not authorized to view this page",
status_code=403,
)
return user
async def user_scheme(request: Request, raise_exc=True) -> User:
user_id = request.session.get("user")
if not user_id:
if raise_exc:
raise RenderErrorTemplateException(
"You need to log in to access this page",
status_code=401,
)
else:
return None
return await User.get(id=user_id)
async def is_admin_user(request: Request) -> bool:
user = await user_scheme(request, raise_exc=False)
return user.role == ADMIN if user else False

0
build/BUILD.bazel Normal file
View File

0
build/macros/BUILD.bazel Normal file
View File

32
build/macros/fastapi.bzl Normal file
View File

@ -0,0 +1,32 @@
load("@aspect_rules_py//py:defs.bzl", "py_binary")
def fastapi_binary(name, path, port, deps = [], tags = [], **kwargs):
py_binary(
name = name,
srcs = ["@pypi_hypercorn//:rules_python_wheel_entry_point_hypercorn.py"],
args = ["{}:app".format(path), "--reload", "--bind 127.0.0.1:{}".format(port)],
visibility = ["//:__subpackages__"],
deps = deps + [
":{}_lib".format(name),
"@pypi_hypercorn//:pkg",
],
tags = tags + [
"ibazel_notify_changes",
],
**kwargs
)
py_binary(
name = "{}.prod".format(name),
srcs = ["@pypi_hypercorn//:rules_python_wheel_entry_point_hypercorn.py"],
args = ["{}:app".format(path), "--reload", "--bind 127.0.0.1:{}".format(port)],
visibility = ["//:__subpackages__"],
deps = deps + [
":{}_lib".format(name),
"@pypi_hypercorn//:pkg",
],
tags = tags + [
"ibazel_notify_changes",
],
**kwargs
)

View File

@ -0,0 +1,38 @@
From e0c49b576595abdfa5167fa7726e604701f79cd8 Mon Sep 17 00:00:00 2001
From: Mustafa Gezen <mustafa@ctrliq.com>
Date: Sun, 29 Jan 2023 05:54:58 +0100
Subject: [PATCH] Fix Quart and Hypercorn failing to install with rules_python
---
.../tools/wheel_installer/wheel_installer.py | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/python/pip_install/tools/wheel_installer/wheel_installer.py b/python/pip_install/tools/wheel_installer/wheel_installer.py
index 1f6eaf2..3bbaaaf 100644
--- a/python/pip_install/tools/wheel_installer/wheel_installer.py
+++ b/python/pip_install/tools/wheel_installer/wheel_installer.py
@@ -422,6 +422,21 @@ def main() -> None:
extras = {name: extras_for_pkg} if extras_for_pkg and name else dict()
whl = next(iter(glob.glob("*.whl")))
+
+ # If wheel starts with "Quart" then rename it to "quart"
+ # For some reason the quart package publishes a wheel with a capital Q
+ # but internally it is referenced as "quart".
+ # This leads to the "installer" package failing to read the WHEEL file
+ # Ugly hack, but it is what it is.
+ # The same problem is also present with "Hypercorn".
+ # This developer is definitely doing something weird but whatever.
+ if whl.startswith("Quart"):
+ os.rename(whl, whl.replace("Quart", "quart"))
+ whl = whl.replace("Quart", "quart")
+ if whl.startswith("Hypercorn"):
+ os.rename(whl, whl.replace("Hypercorn", "hypercorn"))
+ whl = whl.replace("Hypercorn", "hypercorn")
+
_extract_wheel(
wheel_file=whl,
extras=extras,
--
2.32.0 (Apple Git-132)

View File

@ -0,0 +1 @@
exports_files(["0001-Fix-Quart-and-Hypercorn-failing-to-install-with-rule.patch"])

20
common/BUILD.bazel Normal file
View File

@ -0,0 +1,20 @@
load("@aspect_rules_py//py:defs.bzl", "py_library")
py_library(
name = "common_lib",
srcs = [
"database.py",
"env.py",
"fastapi.py",
"info.py",
"logger.py",
"temporal.py",
],
imports = [".."],
visibility = ["//:__subpackages__"],
deps = [
"@pypi_fastapi//:pkg",
"@pypi_temporalio//:pkg",
"@pypi_tortoise_orm//:pkg",
],
)

42
common/database.py Normal file
View File

@ -0,0 +1,42 @@
"""
Database helper methods
"""
from tortoise import Tortoise
from tortoise.contrib.fastapi import register_tortoise
from common.info import Info
class Database(object):
"""
Database connection singleton class
"""
initialized = False
def __init__(self, initialize=False, tortoise_app=None, models=None):
if not Database.initialized and not initialize:
raise Exception("Database connection not initialized")
if tortoise_app:
register_tortoise(
tortoise_app,
db_url=self.conn_str(),
modules={"models": models},
add_exception_handlers=True,
)
self.initialized = True
def conn_str(self):
info = Info()
return f"postgres://{info.dbuser()}:{info.dbpassword()}@{info.dbhost()}:{info.dbport()}/{info.dbname()}"
async def init(self, models):
if Database.initialized:
return
await Tortoise.init(
db_url=self.conn_str(), use_tz=True, modules={"models": models}
)
self.initialized = True

16
common/env.py Normal file
View File

@ -0,0 +1,16 @@
"""
Environment variables
"""
import os
def get_env():
return os.environ.get("ENV", "development")
def is_prod():
return get_env() == "1"
def is_k8s():
return os.environ.get("KUBERNETES", "0") == "1"

22
common/fastapi.py Normal file
View File

@ -0,0 +1,22 @@
import os
from fastapi.staticfiles import StaticFiles
class StaticFilesSym(StaticFiles):
"subclass StaticFiles middleware to allow symlinks"
def lookup_path(self, path):
for directory in self.all_directories:
full_path = os.path.realpath(os.path.join(directory, path))
try:
stat_result = os.stat(full_path)
return (full_path, stat_result)
except FileNotFoundError:
pass
return ("", None)
class RenderErrorTemplateException(Exception):
def __init__(self, msg=None, status_code=404):
self.msg = msg
self.status_code = status_code

56
common/info.py Normal file
View File

@ -0,0 +1,56 @@
"""
Application information
"""
import os
from common.env import get_env, is_k8s
class Info:
"""
Application information singleton class
"""
_name = None
_dbname = None
def __init__(self, name=None, dbname=None):
if not self._name and not name:
raise ValueError("Info.name is not set")
if self._name and name:
raise ValueError("Info.name is already set")
if name:
Info._name = name
Info._dbname = dbname if dbname else name
self._name = Info._name
def name(self):
return self._name
def dbname(self):
return f"{self._dbname}{get_env()}"
def dbuser(self):
return os.environ.get("DB_USER", "postgres")
def dbpassword(self):
return os.environ.get("DB_PASSWORD", "postgres")
def dbhost(self):
return os.environ.get("DB_HOST", "localhost")
def dbport(self):
return os.environ.get("DB_PORT", "5432")
def dbsslmode(self):
return os.environ.get("DB_SSLMODE", "disable")
def temporal_host(self):
if is_k8s():
return "workflow-temporal-frontend.workflow.svc.cluster.local:7233"
else:
return os.environ.get("TEMPORAL_HOSTPORT", "localhost:7233")
def temporal_namespace(self):
return os.environ.get("TEMPORAL_NAMESPACE", "default")

52
common/logger.py Normal file
View File

@ -0,0 +1,52 @@
"""
This module provides a logger class that
can be used to log messages to the console.
"""
import logging
from common.env import is_prod
from common.info import Info
class Logger(object):
"""
This class provides a logger that can be used to log messages to the console.
"""
logger = None
def __init__(self):
info = Info()
if Logger.logger is None:
level = logging.INFO
if not is_prod():
level = logging.DEBUG
logging.basicConfig(
level=level,
format="[%(name)s:%(levelname)s:%(asctime)s] %(message)s"
)
Logger.logger = logging.getLogger(info.name())
self.logger = Logger.logger
def warning(self, msg, *args, **kwargs):
self.logger.warning(msg, *args, **kwargs)
def error(self, msg, *args, **kwargs):
self.logger.error(msg, *args, **kwargs)
def info(self, msg, *args, **kwargs):
self.logger.info(msg, *args, **kwargs)
def debug(self, msg, *args, **kwargs):
self.logger.debug(msg, *args, **kwargs)
def exception(self, msg, *args, **kwargs):
self.logger.exception(msg, *args, **kwargs)
def critical(self, msg, *args, **kwargs):
self.logger.critical(msg, *args, **kwargs)
def fatal(self, msg, *args, **kwargs):
self.logger.fatal(msg, *args, **kwargs)

29
common/temporal.py Normal file
View File

@ -0,0 +1,29 @@
"""
Temporal helper methods
"""
from temporalio.client import Client
from common.info import Info
class Temporal(object):
"""
Temporal helper singleton class
"""
client = None
def __init__(self, initialize=False):
if Temporal.client is None and not initialize:
raise Exception("Temporal client not initialized")
self.client = Temporal.client
async def connect(self):
info = Info()
Temporal.client = await Client.connect(
info.temporal_host(),
namespace=info.temporal_namespace(),
)
self.client = Temporal.client

1500
gazelle_python.yaml Normal file

File diff suppressed because it is too large Load Diff

20
package.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "distro-tools",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "BSD-3-Clause",
"dependencies": {
"@carbon/themes": "^11.16.0",
"@carbon/web-components": "^1.23.0",
"carbon-components": "^10.58.3",
"esbuild-sass-plugin": "^2.4.5",
"lit-element": "^3.2.2",
"lit-html": "^2.6.1"
}
}

587
pnpm-lock.yaml generated Normal file
View File

@ -0,0 +1,587 @@
lockfileVersion: 5.4
specifiers:
'@carbon/themes': ^11.16.0
'@carbon/web-components': ^1.23.0
carbon-components: ^10.58.3
esbuild-sass-plugin: ^2.4.5
lit-element: ^3.2.2
lit-html: ^2.6.1
dependencies:
'@carbon/themes': 11.16.0
'@carbon/web-components': 1.23.0
carbon-components: 10.58.3
esbuild-sass-plugin: 2.4.5
lit-element: 3.2.2
lit-html: 2.6.1
packages:
/@babel/runtime/7.20.13:
resolution: {integrity: sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.13.11
dev: false
/@carbon/colors/11.12.0:
resolution: {integrity: sha512-rN/e6EXgS1RM8C/K0qQ/4/zE+En8iMGDE9u6BNLQ9ig2V2KTYncCdhItJW0rAbL7tt8xeP0UrACijS/XCqsm6w==}
dev: false
/@carbon/grid/11.11.0:
resolution: {integrity: sha512-07U2cC5lgvy7gWveUtE0wuYUxu6Dndglnajy1FJAeV7BEd2t6cgU/t7AOaL8RhoXPjE7tarN5tnZImw5nmzQYQ==}
dependencies:
'@carbon/layout': 11.11.0
dev: false
/@carbon/layout/11.11.0:
resolution: {integrity: sha512-0AuBxoJ+4HiYDIou0xR/jRtGDjTZ2ew1qeViQd04aM0GdZDGhjPTwU9u9CLCKAZEK4dYcewqWat1FQI4diYaOA==}
dev: false
/@carbon/telemetry/0.1.0:
resolution: {integrity: sha512-kNWt0bkgPwGW0i5h7HFuljbKRXPvIhsKbB+1tEURAYLXoJg9iJLF1eGvWN5iVoFCS2zje4GR3OGOsvvKVe7Hlg==}
hasBin: true
dev: false
/@carbon/themes/11.16.0:
resolution: {integrity: sha512-t5323D66p5M6ev9HwMo5tQUE5M1zQP+fa2KExOkHzyJXQfbR3rDSL3y8O/ALrnLgYfBKTftQCGOcUnxhR3LOTQ==}
dependencies:
'@carbon/colors': 11.12.0
'@carbon/layout': 11.11.0
'@carbon/type': 11.15.0
color: 4.2.3
dev: false
/@carbon/type/11.15.0:
resolution: {integrity: sha512-oJm8imiLUF5x7AYaiuExhGfhF/aep8STvV4ckQ9VrPCVFwytJ1haJFmyDU2ssYNiTfgjVN0foy6sNbHMZYM0pg==}
dependencies:
'@carbon/grid': 11.11.0
'@carbon/layout': 11.11.0
dev: false
/@carbon/web-components/1.23.0:
resolution: {integrity: sha512-dK28KsVS9pR9YEYCQ5t61imLf1DbcwdykCLcIQX7B1Ak8YZZHYdNEkkcmuiXpbn6Tfd/Rtn1i+5BiJmREN6kKQ==}
dependencies:
'@babel/runtime': 7.20.13
carbon-components: 10.58.3
flatpickr: 4.6.13
lit-element: 2.5.1
lit-html: 1.4.1
lodash-es: 4.17.21
dev: false
/@esbuild/android-arm/0.15.18:
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: false
optional: true
/@esbuild/linux-loong64/0.15.18:
resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/@lit-labs/ssr-dom-shim/1.0.0:
resolution: {integrity: sha512-ic93MBXfApIFTrup4a70M/+ddD8xdt2zxxj9sRwHQzhS9ag/syqkD8JPdTXsc1gUy2K8TTirhlCqyTEM/sifNw==}
dev: false
/@lit/reactive-element/1.6.1:
resolution: {integrity: sha512-va15kYZr7KZNNPZdxONGQzpUr+4sxVu7V/VG7a8mRfPPXUyhEYj5RzXCQmGrlP3tAh0L3HHm5AjBMFYRqlM9SA==}
dependencies:
'@lit-labs/ssr-dom-shim': 1.0.0
dev: false
/@types/trusted-types/2.0.2:
resolution: {integrity: sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==}
dev: false
/anymatch/3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
dev: false
/binary-extensions/2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'}
dev: false
/braces/3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
dev: false
/carbon-components/10.58.3:
resolution: {integrity: sha512-RjTnrWCGStsIZ7nErw97AZI9sQWxQ8oIgo3QMdV0FWFcpTOECA4I9Dy4WPpRRdSMBcQpLetTxqjDGourM4u8Tw==}
requiresBuild: true
dependencies:
'@carbon/telemetry': 0.1.0
flatpickr: 4.6.1
lodash.debounce: 4.0.8
warning: 3.0.0
dev: false
/chokidar/3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
dependencies:
anymatch: 3.1.3
braces: 3.0.2
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.2
dev: false
/color-convert/2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name/1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/color-string/1.9.1:
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: false
/color/4.2.3:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
engines: {node: '>=12.5.0'}
dependencies:
color-convert: 2.0.1
color-string: 1.9.1
dev: false
/esbuild-android-64/0.15.18:
resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: false
optional: true
/esbuild-android-arm64/0.15.18:
resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: false
optional: true
/esbuild-darwin-64/0.15.18:
resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/esbuild-darwin-arm64/0.15.18:
resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: false
optional: true
/esbuild-freebsd-64/0.15.18:
resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: false
optional: true
/esbuild-freebsd-arm64/0.15.18:
resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-32/0.15.18:
resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-64/0.15.18:
resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-arm/0.15.18:
resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-arm64/0.15.18:
resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-mips64le/0.15.18:
resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-ppc64le/0.15.18:
resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-riscv64/0.15.18:
resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-linux-s390x/0.15.18:
resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: false
optional: true
/esbuild-netbsd-64/0.15.18:
resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: false
optional: true
/esbuild-openbsd-64/0.15.18:
resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: false
optional: true
/esbuild-sass-plugin/2.4.5:
resolution: {integrity: sha512-di2hLaIwhRXe513uaPPxv+5bjynxAgrS8R+u38lbBfvp1g1xOki4ACXV2aXip2CRPGTbAVDySSxujd9iArFV0w==}
dependencies:
esbuild: 0.15.18
resolve: 1.22.1
sass: 1.57.1
dev: false
/esbuild-sunos-64/0.15.18:
resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: false
optional: true
/esbuild-windows-32/0.15.18:
resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: false
optional: true
/esbuild-windows-64/0.15.18:
resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/esbuild-windows-arm64/0.15.18:
resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: false
optional: true
/esbuild/0.15.18:
resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.15.18
'@esbuild/linux-loong64': 0.15.18
esbuild-android-64: 0.15.18
esbuild-android-arm64: 0.15.18
esbuild-darwin-64: 0.15.18
esbuild-darwin-arm64: 0.15.18
esbuild-freebsd-64: 0.15.18
esbuild-freebsd-arm64: 0.15.18
esbuild-linux-32: 0.15.18
esbuild-linux-64: 0.15.18
esbuild-linux-arm: 0.15.18
esbuild-linux-arm64: 0.15.18
esbuild-linux-mips64le: 0.15.18
esbuild-linux-ppc64le: 0.15.18
esbuild-linux-riscv64: 0.15.18
esbuild-linux-s390x: 0.15.18
esbuild-netbsd-64: 0.15.18
esbuild-openbsd-64: 0.15.18
esbuild-sunos-64: 0.15.18
esbuild-windows-32: 0.15.18
esbuild-windows-64: 0.15.18
esbuild-windows-arm64: 0.15.18
dev: false
/fill-range/7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
dev: false
/flatpickr/4.6.1:
resolution: {integrity: sha512-3ULSxbXmcMIRzer/2jLNweoqHpwDvsjEawO2FUd9UFR8uPwLM+LruZcPDpuZStcEgbQKhuFOfXo4nYdGladSNw==}
dev: false
/flatpickr/4.6.13:
resolution: {integrity: sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw==}
dev: false
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: false
optional: true
/function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: false
/glob-parent/5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
dev: false
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
dependencies:
function-bind: 1.1.1
dev: false
/immutable/4.2.2:
resolution: {integrity: sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==}
dev: false
/is-arrayish/0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: false
/is-binary-path/2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.2.0
dev: false
/is-core-module/2.11.0:
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
dependencies:
has: 1.0.3
dev: false
/is-extglob/2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: false
/is-glob/4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
dev: false
/is-number/7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
dev: false
/js-tokens/4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: false
/lit-element/2.5.1:
resolution: {integrity: sha512-ogu7PiJTA33bEK0xGu1dmaX5vhcRjBXCFexPja0e7P7jqLhTpNKYRPmE+GmiCaRVAbiQKGkUgkh/i6+bh++dPQ==}
dependencies:
lit-html: 1.4.1
dev: false
/lit-element/3.2.2:
resolution: {integrity: sha512-6ZgxBR9KNroqKb6+htkyBwD90XGRiqKDHVrW/Eh0EZ+l+iC+u+v+w3/BA5NGi4nizAVHGYvQBHUDuSmLjPp7NQ==}
dependencies:
'@lit/reactive-element': 1.6.1
lit-html: 2.6.1
dev: false
/lit-html/1.4.1:
resolution: {integrity: sha512-B9btcSgPYb1q4oSOb/PrOT6Z/H+r6xuNzfH4lFli/AWhYwdtrgQkQWBbIc6mdnf6E2IL3gDXdkkqNktpU0OZQA==}
dev: false
/lit-html/2.6.1:
resolution: {integrity: sha512-Z3iw+E+3KKFn9t2YKNjsXNEu/LRLI98mtH/C6lnFg7kvaqPIzPn124Yd4eT/43lyqrejpc5Wb6BHq3fdv4S8Rw==}
dependencies:
'@types/trusted-types': 2.0.2
dev: false
/lodash-es/4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: false
/lodash.debounce/4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
dev: false
/loose-envify/1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
dependencies:
js-tokens: 4.0.0
dev: false
/normalize-path/3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
dev: false
/path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: false
/picomatch/2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: false
/readdirp/3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.3.1
dev: false
/regenerator-runtime/0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
dev: false
/resolve/1.22.1:
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
hasBin: true
dependencies:
is-core-module: 2.11.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
dev: false
/sass/1.57.1:
resolution: {integrity: sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==}
engines: {node: '>=12.0.0'}
hasBin: true
dependencies:
chokidar: 3.5.3
immutable: 4.2.2
source-map-js: 1.0.2
dev: false
/simple-swizzle/0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
dependencies:
is-arrayish: 0.3.2
dev: false
/source-map-js/1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
dev: false
/supports-preserve-symlinks-flag/1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
dev: false
/to-regex-range/5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
dev: false
/warning/3.0.0:
resolution: {integrity: sha512-jMBt6pUrKn5I+OGgtQ4YZLdhIeJmObddh6CsibPxyQ5yPZm1XExSyzC1LCNX7BzhxWgiHmizBWJTHJIjMjTQYQ==}
dependencies:
loose-envify: 1.4.0
dev: false

19
requirements.txt Normal file
View File

@ -0,0 +1,19 @@
tortoise-orm[asyncpg]==0.19.2
pylint==2.15.10
yapf==0.32.0
temporalio==1.0.0
click==8.1.3
aiohttp==3.8.3
openapi-python-client==0.13.1
dataclass-wizard==0.22.2
fastapi==0.89.1
fastapi-pagination==0.11.2
Jinja2==3.1.2
hypercorn==0.14.3
setuptools==58.2.0
pydantic==1.10.4
passlib[bcrypt]==1.7.4
python-multipart==0.0.5
itsdangerous==2.1.2
PyYAML==6.0
beautifulsoup4==4.11.2

932
requirements_lock.txt Normal file
View File

@ -0,0 +1,932 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# by the following command:
#
# bazel run //:requirements.update
#
aiohttp==3.8.3 \
--hash=sha256:02f9a2c72fc95d59b881cf38a4b2be9381b9527f9d328771e90f72ac76f31ad8 \
--hash=sha256:059a91e88f2c00fe40aed9031b3606c3f311414f86a90d696dd982e7aec48142 \
--hash=sha256:05a3c31c6d7cd08c149e50dc7aa2568317f5844acd745621983380597f027a18 \
--hash=sha256:08c78317e950e0762c2983f4dd58dc5e6c9ff75c8a0efeae299d363d439c8e34 \
--hash=sha256:09e28f572b21642128ef31f4e8372adb6888846f32fecb288c8b0457597ba61a \
--hash=sha256:0d2c6d8c6872df4a6ec37d2ede71eff62395b9e337b4e18efd2177de883a5033 \
--hash=sha256:16c121ba0b1ec2b44b73e3a8a171c4f999b33929cd2397124a8c7fcfc8cd9e06 \
--hash=sha256:1d90043c1882067f1bd26196d5d2db9aa6d268def3293ed5fb317e13c9413ea4 \
--hash=sha256:1e56b9cafcd6531bab5d9b2e890bb4937f4165109fe98e2b98ef0dcfcb06ee9d \
--hash=sha256:20acae4f268317bb975671e375493dbdbc67cddb5f6c71eebdb85b34444ac46b \
--hash=sha256:21b30885a63c3f4ff5b77a5d6caf008b037cb521a5f33eab445dc566f6d092cc \
--hash=sha256:21d69797eb951f155026651f7e9362877334508d39c2fc37bd04ff55b2007091 \
--hash=sha256:256deb4b29fe5e47893fa32e1de2d73c3afe7407738bd3c63829874661d4822d \
--hash=sha256:25892c92bee6d9449ffac82c2fe257f3a6f297792cdb18ad784737d61e7a9a85 \
--hash=sha256:2ca9af5f8f5812d475c5259393f52d712f6d5f0d7fdad9acdb1107dd9e3cb7eb \
--hash=sha256:2d252771fc85e0cf8da0b823157962d70639e63cb9b578b1dec9868dd1f4f937 \
--hash=sha256:2dea10edfa1a54098703cb7acaa665c07b4e7568472a47f4e64e6319d3821ccf \
--hash=sha256:2df5f139233060578d8c2c975128fb231a89ca0a462b35d4b5fcf7c501ebdbe1 \
--hash=sha256:2feebbb6074cdbd1ac276dbd737b40e890a1361b3cc30b74ac2f5e24aab41f7b \
--hash=sha256:309aa21c1d54b8ef0723181d430347d7452daaff93e8e2363db8e75c72c2fb2d \
--hash=sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269 \
--hash=sha256:398701865e7a9565d49189f6c90868efaca21be65c725fc87fc305906be915da \
--hash=sha256:43046a319664a04b146f81b40e1545d4c8ac7b7dd04c47e40bf09f65f2437346 \
--hash=sha256:437399385f2abcd634865705bdc180c8314124b98299d54fe1d4c8990f2f9494 \
--hash=sha256:45d88b016c849d74ebc6f2b6e8bc17cabf26e7e40c0661ddd8fae4c00f015697 \
--hash=sha256:47841407cc89a4b80b0c52276f3cc8138bbbfba4b179ee3acbd7d77ae33f7ac4 \
--hash=sha256:4a4fbc769ea9b6bd97f4ad0b430a6807f92f0e5eb020f1e42ece59f3ecfc4585 \
--hash=sha256:4ab94426ddb1ecc6a0b601d832d5d9d421820989b8caa929114811369673235c \
--hash=sha256:4b0f30372cef3fdc262f33d06e7b411cd59058ce9174ef159ad938c4a34a89da \
--hash=sha256:4e3a23ec214e95c9fe85a58470b660efe6534b83e6cbe38b3ed52b053d7cb6ad \
--hash=sha256:512bd5ab136b8dc0ffe3fdf2dfb0c4b4f49c8577f6cae55dca862cd37a4564e2 \
--hash=sha256:527b3b87b24844ea7865284aabfab08eb0faf599b385b03c2aa91fc6edd6e4b6 \
--hash=sha256:54d107c89a3ebcd13228278d68f1436d3f33f2dd2af5415e3feaeb1156e1a62c \
--hash=sha256:5835f258ca9f7c455493a57ee707b76d2d9634d84d5d7f62e77be984ea80b849 \
--hash=sha256:598adde339d2cf7d67beaccda3f2ce7c57b3b412702f29c946708f69cf8222aa \
--hash=sha256:599418aaaf88a6d02a8c515e656f6faf3d10618d3dd95866eb4436520096c84b \
--hash=sha256:5bf651afd22d5f0c4be16cf39d0482ea494f5c88f03e75e5fef3a85177fecdeb \
--hash=sha256:5c59fcd80b9049b49acd29bd3598cada4afc8d8d69bd4160cd613246912535d7 \
--hash=sha256:653acc3880459f82a65e27bd6526e47ddf19e643457d36a2250b85b41a564715 \
--hash=sha256:66bd5f950344fb2b3dbdd421aaa4e84f4411a1a13fca3aeb2bcbe667f80c9f76 \
--hash=sha256:6f3553510abdbec67c043ca85727396ceed1272eef029b050677046d3387be8d \
--hash=sha256:7018ecc5fe97027214556afbc7c502fbd718d0740e87eb1217b17efd05b3d276 \
--hash=sha256:713d22cd9643ba9025d33c4af43943c7a1eb8547729228de18d3e02e278472b6 \
--hash=sha256:73a4131962e6d91109bca6536416aa067cf6c4efb871975df734f8d2fd821b37 \
--hash=sha256:75880ed07be39beff1881d81e4a907cafb802f306efd6d2d15f2b3c69935f6fb \
--hash=sha256:75e14eac916f024305db517e00a9252714fce0abcb10ad327fb6dcdc0d060f1d \
--hash=sha256:8135fa153a20d82ffb64f70a1b5c2738684afa197839b34cc3e3c72fa88d302c \
--hash=sha256:84b14f36e85295fe69c6b9789b51a0903b774046d5f7df538176516c3e422446 \
--hash=sha256:86fc24e58ecb32aee09f864cb11bb91bc4c1086615001647dbfc4dc8c32f4008 \
--hash=sha256:87f44875f2804bc0511a69ce44a9595d5944837a62caecc8490bbdb0e18b1342 \
--hash=sha256:88c70ed9da9963d5496d38320160e8eb7e5f1886f9290475a881db12f351ab5d \
--hash=sha256:88e5be56c231981428f4f506c68b6a46fa25c4123a2e86d156c58a8369d31ab7 \
--hash=sha256:89d2e02167fa95172c017732ed7725bc8523c598757f08d13c5acca308e1a061 \
--hash=sha256:8d6aaa4e7155afaf994d7924eb290abbe81a6905b303d8cb61310a2aba1c68ba \
--hash=sha256:92a2964319d359f494f16011e23434f6f8ef0434acd3cf154a6b7bec511e2fb7 \
--hash=sha256:96372fc29471646b9b106ee918c8eeb4cca423fcbf9a34daa1b93767a88a2290 \
--hash=sha256:978b046ca728073070e9abc074b6299ebf3501e8dee5e26efacb13cec2b2dea0 \
--hash=sha256:9c7149272fb5834fc186328e2c1fa01dda3e1fa940ce18fded6d412e8f2cf76d \
--hash=sha256:a0239da9fbafd9ff82fd67c16704a7d1bccf0d107a300e790587ad05547681c8 \
--hash=sha256:ad5383a67514e8e76906a06741febd9126fc7c7ff0f599d6fcce3e82b80d026f \
--hash=sha256:ad61a9639792fd790523ba072c0555cd6be5a0baf03a49a5dd8cfcf20d56df48 \
--hash=sha256:b29bfd650ed8e148f9c515474a6ef0ba1090b7a8faeee26b74a8ff3b33617502 \
--hash=sha256:b97decbb3372d4b69e4d4c8117f44632551c692bb1361b356a02b97b69e18a62 \
--hash=sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9 \
--hash=sha256:c37c5cce780349d4d51739ae682dec63573847a2a8dcb44381b174c3d9c8d403 \
--hash=sha256:c971bf3786b5fad82ce5ad570dc6ee420f5b12527157929e830f51c55dc8af77 \
--hash=sha256:d1fde0f44029e02d02d3993ad55ce93ead9bb9b15c6b7ccd580f90bd7e3de476 \
--hash=sha256:d24b8bb40d5c61ef2d9b6a8f4528c2f17f1c5d2d31fed62ec860f6006142e83e \
--hash=sha256:d5ba88df9aa5e2f806650fcbeedbe4f6e8736e92fc0e73b0400538fd25a4dd96 \
--hash=sha256:d6f76310355e9fae637c3162936e9504b4767d5c52ca268331e2756e54fd4ca5 \
--hash=sha256:d737fc67b9a970f3234754974531dc9afeea11c70791dcb7db53b0cf81b79784 \
--hash=sha256:da22885266bbfb3f78218dc40205fed2671909fbd0720aedba39b4515c038091 \
--hash=sha256:da37dcfbf4b7f45d80ee386a5f81122501ec75672f475da34784196690762f4b \
--hash=sha256:db19d60d846283ee275d0416e2a23493f4e6b6028825b51290ac05afc87a6f97 \
--hash=sha256:db4c979b0b3e0fa7e9e69ecd11b2b3174c6963cebadeecfb7ad24532ffcdd11a \
--hash=sha256:e164e0a98e92d06da343d17d4e9c4da4654f4a4588a20d6c73548a29f176abe2 \
--hash=sha256:e168a7560b7c61342ae0412997b069753f27ac4862ec7867eff74f0fe4ea2ad9 \
--hash=sha256:e381581b37db1db7597b62a2e6b8b57c3deec95d93b6d6407c5b61ddc98aca6d \
--hash=sha256:e65bc19919c910127c06759a63747ebe14f386cda573d95bcc62b427ca1afc73 \
--hash=sha256:e7b8813be97cab8cb52b1375f41f8e6804f6507fe4660152e8ca5c48f0436017 \
--hash=sha256:e8a78079d9a39ca9ca99a8b0ac2fdc0c4d25fc80c8a8a82e5c8211509c523363 \
--hash=sha256:ebf909ea0a3fc9596e40d55d8000702a85e27fd578ff41a5500f68f20fd32e6c \
--hash=sha256:ec40170327d4a404b0d91855d41bfe1fe4b699222b2b93e3d833a27330a87a6d \
--hash=sha256:f178d2aadf0166be4df834c4953da2d7eef24719e8aec9a65289483eeea9d618 \
--hash=sha256:f88df3a83cf9df566f171adba39d5bd52814ac0b94778d2448652fc77f9eb491 \
--hash=sha256:f973157ffeab5459eefe7b97a804987876dd0a55570b8fa56b4e1954bf11329b \
--hash=sha256:ff25f48fc8e623d95eca0670b8cc1469a83783c924a602e0fbd47363bb54aaca
# via -r ./requirements.txt
aiosignal==1.3.1 \
--hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \
--hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17
# via aiohttp
aiosqlite==0.17.0 \
--hash=sha256:6c49dc6d3405929b1d08eeccc72306d3677503cc5e5e43771efc1e00232e8231 \
--hash=sha256:f0e6acc24bc4864149267ac82fb46dfb3be4455f99fe21df82609cc6e6baee51
# via tortoise-orm
anyio==3.6.2 \
--hash=sha256:25ea0d673ae30af41a0c442f81cf3b38c7e79fdc7b60335a4c14e05eb0947421 \
--hash=sha256:fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3
# via
# httpcore
# starlette
astroid==2.13.3 \
--hash=sha256:14c1603c41cc61aae731cad1884a073c4645e26f126d13ac8346113c95577f3b \
--hash=sha256:6afc22718a48a689ca24a97981ad377ba7fb78c133f40335dfd16772f29bcfb1
# via pylint
async-timeout==4.0.2 \
--hash=sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15 \
--hash=sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c
# via aiohttp
asyncpg==0.27.0 \
--hash=sha256:16ba8ec2e85d586b4a12bcd03e8d29e3d99e832764d6a1d0b8c27dbbe4a2569d \
--hash=sha256:18f77e8e71e826ba2d0c3ba6764930776719ae2b225ca07e014590545928b576 \
--hash=sha256:1b6499de06fe035cf2fa932ec5617ed3f37d4ebbf663b655922e105a484a6af9 \
--hash=sha256:20b596d8d074f6f695c13ffb8646d0b6bb1ab570ba7b0cfd349b921ff03cfc1e \
--hash=sha256:2232ebae9796d4600a7819fc383da78ab51b32a092795f4555575fc934c1c89d \
--hash=sha256:4750f5cf49ed48a6e49c6e5aed390eee367694636c2dcfaf4a273ca832c5c43c \
--hash=sha256:4bb366ae34af5b5cabc3ac6a5347dfb6013af38c68af8452f27968d49085ecc0 \
--hash=sha256:5710cb0937f696ce303f5eed6d272e3f057339bb4139378ccecafa9ee923a71c \
--hash=sha256:609054a1f47292a905582a1cfcca51a6f3f30ab9d822448693e66fdddde27920 \
--hash=sha256:62932f29cf2433988fcd799770ec64b374a3691e7902ecf85da14d5e0854d1ea \
--hash=sha256:69aa1b443a182b13a17ff926ed6627af2d98f62f2fe5890583270cc4073f63bf \
--hash=sha256:71cca80a056ebe19ec74b7117b09e650990c3ca535ac1c35234a96f65604192f \
--hash=sha256:720986d9a4705dd8a40fdf172036f5ae787225036a7eb46e704c45aa8f62c054 \
--hash=sha256:768e0e7c2898d40b16d4ef7a0b44e8150db3dd8995b4652aa1fe2902e92c7df8 \
--hash=sha256:7a6206210c869ebd3f4eb9e89bea132aefb56ff3d1b7dd7e26b102b17e27bbb1 \
--hash=sha256:7d8585707ecc6661d07367d444bbaa846b4e095d84451340da8df55a3757e152 \
--hash=sha256:8113e17cfe236dc2277ec844ba9b3d5312f61bd2fdae6d3ed1c1cdd75f6cf2d8 \
--hash=sha256:879c29a75969eb2722f94443752f4720d560d1e748474de54ae8dd230bc4956b \
--hash=sha256:88b62164738239f62f4af92567b846a8ef7cf8abf53eddd83650603de4d52163 \
--hash=sha256:8934577e1ed13f7d2d9cea3cc016cc6f95c19faedea2c2b56a6f94f257cea672 \
--hash=sha256:9654085f2b22f66952124de13a8071b54453ff972c25c59b5ce1173a4283ffd9 \
--hash=sha256:975a320baf7020339a67315284a4d3bf7460e664e484672bd3e71dbd881bc692 \
--hash=sha256:9a3a4ff43702d39e3c97a8786314123d314e0f0e4dabc8367db5b665c93914de \
--hash=sha256:a7a94c03386bb95456b12c66026b3a87d1b965f0f1e5733c36e7229f8f137747 \
--hash=sha256:ab0f21c4818d46a60ca789ebc92327d6d874d3b7ccff3963f7af0a21dc6cff52 \
--hash=sha256:bb71211414dd1eeb8d31ec529fe77cff04bf53efc783a5f6f0a32d84923f45cf \
--hash=sha256:bf21ebf023ec67335258e0f3d3ad7b91bb9507985ba2b2206346de488267cad0 \
--hash=sha256:bfc3980b4ba6f97138b04f0d32e8af21d6c9fa1f8e6e140c07d15690a0a99279 \
--hash=sha256:c2232d4625c558f2aa001942cac1d7952aa9f0dbfc212f63bc754277769e1ef2 \
--hash=sha256:ccddb9419ab4e1c48742457d0c0362dbdaeb9b28e6875115abfe319b29ee225d \
--hash=sha256:d20dea7b83651d93b1eb2f353511fe7fd554752844523f17ad30115d8b9c8cd6 \
--hash=sha256:e56ac8a8237ad4adec97c0cd4728596885f908053ab725e22900b5902e7f8e69 \
--hash=sha256:eb4b2fdf88af4fb1cc569781a8f933d2a73ee82cd720e0cb4edabbaecf2a905b \
--hash=sha256:eca01eb112a39d31cc4abb93a5aef2a81514c23f70956729f42fb83b11b3483f \
--hash=sha256:fca608d199ffed4903dce1bcd97ad0fe8260f405c1c225bdf0002709132171c2 \
--hash=sha256:fddcacf695581a8d856654bc4c8cfb73d5c9df26d5f55201722d3e6a699e9629
# via tortoise-orm
attrs==22.2.0 \
--hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \
--hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99
# via
# aiohttp
# openapi-python-client
autoflake==2.0.0 \
--hash=sha256:7185b596e70d8970c6d4106c112ef41921e472bd26abf3613db99eca88cc8c2a \
--hash=sha256:d58ed4187c6b4f623a942b9a90c43ff84bf6a266f3682f407b42ca52073c9678
# via openapi-python-client
bcrypt==4.0.1 \
--hash=sha256:089098effa1bc35dc055366740a067a2fc76987e8ec75349eb9484061c54f535 \
--hash=sha256:08d2947c490093a11416df18043c27abe3921558d2c03e2076ccb28a116cb6d0 \
--hash=sha256:0eaa47d4661c326bfc9d08d16debbc4edf78778e6aaba29c1bc7ce67214d4410 \
--hash=sha256:27d375903ac8261cfe4047f6709d16f7d18d39b1ec92aaf72af989552a650ebd \
--hash=sha256:2b3ac11cf45161628f1f3733263e63194f22664bf4d0c0f3ab34099c02134665 \
--hash=sha256:2caffdae059e06ac23fce178d31b4a702f2a3264c20bfb5ff541b338194d8fab \
--hash=sha256:3100851841186c25f127731b9fa11909ab7b1df6fc4b9f8353f4f1fd952fbf71 \
--hash=sha256:5ad4d32a28b80c5fa6671ccfb43676e8c1cc232887759d1cd7b6f56ea4355215 \
--hash=sha256:67a97e1c405b24f19d08890e7ae0c4f7ce1e56a712a016746c8b2d7732d65d4b \
--hash=sha256:705b2cea8a9ed3d55b4491887ceadb0106acf7c6387699fca771af56b1cdeeda \
--hash=sha256:8a68f4341daf7522fe8d73874de8906f3a339048ba406be6ddc1b3ccb16fc0d9 \
--hash=sha256:a522427293d77e1c29e303fc282e2d71864579527a04ddcfda6d4f8396c6c36a \
--hash=sha256:ae88eca3024bb34bb3430f964beab71226e761f51b912de5133470b649d82344 \
--hash=sha256:b1023030aec778185a6c16cf70f359cbb6e0c289fd564a7cfa29e727a1c38f8f \
--hash=sha256:b3b85202d95dd568efcb35b53936c5e3b3600c7cdcc6115ba461df3a8e89f38d \
--hash=sha256:b57adba8a1444faf784394de3436233728a1ecaeb6e07e8c22c8848f179b893c \
--hash=sha256:bf4fa8b2ca74381bb5442c089350f09a3f17797829d958fad058d6e44d9eb83c \
--hash=sha256:ca3204d00d3cb2dfed07f2d74a25f12fc12f73e606fcaa6975d1f7ae69cacbb2 \
--hash=sha256:cbb03eec97496166b704ed663a53680ab57c5084b2fc98ef23291987b525cb7d \
--hash=sha256:e9a51bbfe7e9802b5f3508687758b564069ba937748ad7b9e890086290d2f79e \
--hash=sha256:fbdaec13c5105f0c4e5c52614d04f0bca5f5af007910daa8b6b12095edaa67b3
# via passlib
beautifulsoup4==4.11.2 \
--hash=sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39 \
--hash=sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106
# via -r ./requirements.txt
black==22.12.0 \
--hash=sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320 \
--hash=sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351 \
--hash=sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350 \
--hash=sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f \
--hash=sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf \
--hash=sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148 \
--hash=sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4 \
--hash=sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d \
--hash=sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc \
--hash=sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d \
--hash=sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2 \
--hash=sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f
# via openapi-python-client
certifi==2022.12.7 \
--hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
--hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
# via
# httpcore
# httpx
charset-normalizer==2.1.1 \
--hash=sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845 \
--hash=sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f
# via aiohttp
click==8.1.3 \
--hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
--hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
# via
# -r ./requirements.txt
# black
# typer
dataclass-wizard==0.22.2 \
--hash=sha256:211f842e5e9a8ace50ba891ef428cd78c82579fb98024f80f3e630ca8d1946f6 \
--hash=sha256:49be36ecc64bc5a1e9a35a6bad1d71d33b6b9b06877404931a17c6a3a6dfbb10
# via -r ./requirements.txt
dill==0.3.6 \
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
# via pylint
fastapi==0.89.1 \
--hash=sha256:15d9271ee52b572a015ca2ae5c72e1ce4241dd8532a534ad4f7ec70c376a580f \
--hash=sha256:f9773ea22290635b2f48b4275b2bf69a8fa721fda2e38228bed47139839dc877
# via
# -r ./requirements.txt
# fastapi-pagination
fastapi-pagination==0.11.2 \
--hash=sha256:55ecf04131c22c9ee9b9c060d42b1555fba1188aa60fac826a9e475bb9246e83 \
--hash=sha256:db4bde1c055a85e3840faa70b2a63d27e45542c0ebd97cba8ca786850bb48c6d
# via -r ./requirements.txt
frozenlist==1.3.3 \
--hash=sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c \
--hash=sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f \
--hash=sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a \
--hash=sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784 \
--hash=sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27 \
--hash=sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d \
--hash=sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3 \
--hash=sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678 \
--hash=sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a \
--hash=sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483 \
--hash=sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8 \
--hash=sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf \
--hash=sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99 \
--hash=sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c \
--hash=sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48 \
--hash=sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5 \
--hash=sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56 \
--hash=sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e \
--hash=sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1 \
--hash=sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401 \
--hash=sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4 \
--hash=sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e \
--hash=sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649 \
--hash=sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a \
--hash=sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d \
--hash=sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0 \
--hash=sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6 \
--hash=sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d \
--hash=sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b \
--hash=sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6 \
--hash=sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf \
--hash=sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef \
--hash=sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7 \
--hash=sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842 \
--hash=sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba \
--hash=sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420 \
--hash=sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b \
--hash=sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d \
--hash=sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332 \
--hash=sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936 \
--hash=sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816 \
--hash=sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91 \
--hash=sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420 \
--hash=sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448 \
--hash=sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411 \
--hash=sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4 \
--hash=sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32 \
--hash=sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b \
--hash=sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0 \
--hash=sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530 \
--hash=sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669 \
--hash=sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7 \
--hash=sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1 \
--hash=sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5 \
--hash=sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce \
--hash=sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4 \
--hash=sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e \
--hash=sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2 \
--hash=sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d \
--hash=sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9 \
--hash=sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642 \
--hash=sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0 \
--hash=sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703 \
--hash=sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb \
--hash=sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1 \
--hash=sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13 \
--hash=sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab \
--hash=sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38 \
--hash=sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb \
--hash=sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb \
--hash=sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81 \
--hash=sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8 \
--hash=sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd \
--hash=sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4
# via
# aiohttp
# aiosignal
h11==0.14.0 \
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
--hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
# via
# httpcore
# hypercorn
# wsproto
h2==4.1.0 \
--hash=sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d \
--hash=sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb
# via hypercorn
hpack==4.0.0 \
--hash=sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c \
--hash=sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095
# via h2
httpcore==0.16.3 \
--hash=sha256:c5d6f04e2fc530f39e0c077e6a30caa53f1451096120f1f38b954afd0b17c0cb \
--hash=sha256:da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0
# via httpx
httpx==0.23.3 \
--hash=sha256:9818458eb565bb54898ccb9b8b251a28785dd4a55afbc23d0eb410754fe7d0f9 \
--hash=sha256:a211fcce9b1254ea24f0cd6af9869b3d29aba40154e947d2a07bb499b3e310d6
# via openapi-python-client
hypercorn==0.14.3 \
--hash=sha256:4a87a0b7bbe9dc75fab06dbe4b301b9b90416e9866c23a377df21a969d6ab8dd \
--hash=sha256:7c491d5184f28ee960dcdc14ab45d14633ca79d72ddd13cf4fcb4cb854d679ab
# via -r ./requirements.txt
hyperframe==6.0.1 \
--hash=sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15 \
--hash=sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914
# via h2
idna==3.4 \
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
# via
# anyio
# rfc3986
# yarl
iso8601==1.1.0 \
--hash=sha256:32811e7b81deee2063ea6d2e94f8819a86d1f3811e49d23623a41fa832bef03f \
--hash=sha256:8400e90141bf792bce2634df533dc57e3bee19ea120a87bebcd3da89a58ad73f
# via tortoise-orm
isort==5.11.4 \
--hash=sha256:6db30c5ded9815d813932c04c2f85a360bcdd35fed496f4d8f35495ef0a261b6 \
--hash=sha256:c033fd0edb91000a7f09527fe5c75321878f98322a77ddcc81adbd83724afb7b
# via
# openapi-python-client
# pylint
itsdangerous==2.1.2 \
--hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
--hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
# via -r ./requirements.txt
jinja2==3.1.2 \
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
# via
# -r ./requirements.txt
# openapi-python-client
lazy-object-proxy==1.9.0 \
--hash=sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382 \
--hash=sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82 \
--hash=sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9 \
--hash=sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494 \
--hash=sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46 \
--hash=sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30 \
--hash=sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63 \
--hash=sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4 \
--hash=sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae \
--hash=sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be \
--hash=sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701 \
--hash=sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd \
--hash=sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006 \
--hash=sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a \
--hash=sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586 \
--hash=sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8 \
--hash=sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821 \
--hash=sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07 \
--hash=sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b \
--hash=sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171 \
--hash=sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b \
--hash=sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2 \
--hash=sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7 \
--hash=sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4 \
--hash=sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8 \
--hash=sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e \
--hash=sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f \
--hash=sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda \
--hash=sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4 \
--hash=sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e \
--hash=sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671 \
--hash=sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11 \
--hash=sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455 \
--hash=sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734 \
--hash=sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb \
--hash=sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59
# via astroid
markupsafe==2.1.2 \
--hash=sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed \
--hash=sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc \
--hash=sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2 \
--hash=sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460 \
--hash=sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7 \
--hash=sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0 \
--hash=sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1 \
--hash=sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa \
--hash=sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03 \
--hash=sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323 \
--hash=sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65 \
--hash=sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013 \
--hash=sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036 \
--hash=sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f \
--hash=sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4 \
--hash=sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419 \
--hash=sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2 \
--hash=sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619 \
--hash=sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a \
--hash=sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a \
--hash=sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd \
--hash=sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7 \
--hash=sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666 \
--hash=sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65 \
--hash=sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859 \
--hash=sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625 \
--hash=sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff \
--hash=sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156 \
--hash=sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd \
--hash=sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba \
--hash=sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f \
--hash=sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1 \
--hash=sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094 \
--hash=sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a \
--hash=sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513 \
--hash=sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed \
--hash=sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d \
--hash=sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3 \
--hash=sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147 \
--hash=sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c \
--hash=sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603 \
--hash=sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601 \
--hash=sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a \
--hash=sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1 \
--hash=sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d \
--hash=sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3 \
--hash=sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54 \
--hash=sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2 \
--hash=sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6 \
--hash=sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58
# via jinja2
mccabe==0.7.0 \
--hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
--hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
# via pylint
multidict==6.0.4 \
--hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \
--hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \
--hash=sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03 \
--hash=sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710 \
--hash=sha256:1502e24330eb681bdaa3eb70d6358e818e8e8f908a22a1851dfd4e15bc2f8161 \
--hash=sha256:16ab77bbeb596e14212e7bab8429f24c1579234a3a462105cda4a66904998664 \
--hash=sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569 \
--hash=sha256:21a12c4eb6ddc9952c415f24eef97e3e55ba3af61f67c7bc388dcdec1404a067 \
--hash=sha256:27c523fbfbdfd19c6867af7346332b62b586eed663887392cff78d614f9ec313 \
--hash=sha256:281af09f488903fde97923c7744bb001a9b23b039a909460d0f14edc7bf59706 \
--hash=sha256:33029f5734336aa0d4c0384525da0387ef89148dc7191aae00ca5fb23d7aafc2 \
--hash=sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636 \
--hash=sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49 \
--hash=sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93 \
--hash=sha256:39ff62e7d0f26c248b15e364517a72932a611a9b75f35b45be078d81bdb86603 \
--hash=sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0 \
--hash=sha256:4372381634485bec7e46718edc71528024fcdc6f835baefe517b34a33c731d60 \
--hash=sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4 \
--hash=sha256:45e1ecb0379bfaab5eef059f50115b54571acfbe422a14f668fc8c27ba410e7e \
--hash=sha256:4b9d9e4e2b37daddb5c23ea33a3417901fa7c7b3dee2d855f63ee67a0b21e5b1 \
--hash=sha256:4ceef517eca3e03c1cceb22030a3e39cb399ac86bff4e426d4fc6ae49052cc60 \
--hash=sha256:4d1a3d7ef5e96b1c9e92f973e43aa5e5b96c659c9bc3124acbbd81b0b9c8a951 \
--hash=sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc \
--hash=sha256:509eac6cf09c794aa27bcacfd4d62c885cce62bef7b2c3e8b2e49d365b5003fe \
--hash=sha256:52509b5be062d9eafc8170e53026fbc54cf3b32759a23d07fd935fb04fc22d95 \
--hash=sha256:52f2dffc8acaba9a2f27174c41c9e57f60b907bb9f096b36b1a1f3be71c6284d \
--hash=sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8 \
--hash=sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed \
--hash=sha256:59d43b61c59d82f2effb39a93c48b845efe23a3852d201ed2d24ba830d0b4cf2 \
--hash=sha256:5a4dcf02b908c3b8b17a45fb0f15b695bf117a67b76b7ad18b73cf8e92608775 \
--hash=sha256:5cad9430ab3e2e4fa4a2ef4450f548768400a2ac635841bc2a56a2052cdbeb87 \
--hash=sha256:5fc1b16f586f049820c5c5b17bb4ee7583092fa0d1c4e28b5239181ff9532e0c \
--hash=sha256:62501642008a8b9871ddfccbf83e4222cf8ac0d5aeedf73da36153ef2ec222d2 \
--hash=sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98 \
--hash=sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3 \
--hash=sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe \
--hash=sha256:67040058f37a2a51ed8ea8f6b0e6ee5bd78ca67f169ce6122f3e2ec80dfe9b78 \
--hash=sha256:6748717bb10339c4760c1e63da040f5f29f5ed6e59d76daee30305894069a660 \
--hash=sha256:6b181d8c23da913d4ff585afd1155a0e1194c0b50c54fcfe286f70cdaf2b7176 \
--hash=sha256:6ed5f161328b7df384d71b07317f4d8656434e34591f20552c7bcef27b0ab88e \
--hash=sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988 \
--hash=sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c \
--hash=sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c \
--hash=sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0 \
--hash=sha256:8316a77808c501004802f9beebde51c9f857054a0c871bd6da8280e718444449 \
--hash=sha256:853888594621e6604c978ce2a0444a1e6e70c8d253ab65ba11657659dcc9100f \
--hash=sha256:99b76c052e9f1bc0721f7541e5e8c05db3941eb9ebe7b8553c625ef88d6eefde \
--hash=sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5 \
--hash=sha256:ab55edc2e84460694295f401215f4a58597f8f7c9466faec545093045476327d \
--hash=sha256:af048912e045a2dc732847d33821a9d84ba553f5c5f028adbd364dd4765092ac \
--hash=sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a \
--hash=sha256:b1e8b901e607795ec06c9e42530788c45ac21ef3aaa11dbd0c69de543bfb79a9 \
--hash=sha256:b41156839806aecb3641f3208c0dafd3ac7775b9c4c422d82ee2a45c34ba81ca \
--hash=sha256:b692f419760c0e65d060959df05f2a531945af31fda0c8a3b3195d4efd06de11 \
--hash=sha256:bc779e9e6f7fda81b3f9aa58e3a6091d49ad528b11ed19f6621408806204ad35 \
--hash=sha256:bf6774e60d67a9efe02b3616fee22441d86fab4c6d335f9d2051d19d90a40063 \
--hash=sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b \
--hash=sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982 \
--hash=sha256:cc8e1d0c705233c5dd0c5e6460fbad7827d5d36f310a0fadfd45cc3029762258 \
--hash=sha256:d5e3fc56f88cc98ef8139255cf8cd63eb2c586531e43310ff859d6bb3a6b51f1 \
--hash=sha256:d6aa0418fcc838522256761b3415822626f866758ee0bc6632c9486b179d0b52 \
--hash=sha256:d6c254ba6e45d8e72739281ebc46ea5eb5f101234f3ce171f0e9f5cc86991480 \
--hash=sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7 \
--hash=sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461 \
--hash=sha256:ddd3915998d93fbcd2566ddf9cf62cdb35c9e093075f862935573d265cf8f65d \
--hash=sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc \
--hash=sha256:e41b7e2b59679edfa309e8db64fdf22399eec4b0b24694e1b2104fb789207779 \
--hash=sha256:e69924bfcdda39b722ef4d9aa762b2dd38e4632b3641b1d9a57ca9cd18f2f83a \
--hash=sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547 \
--hash=sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0 \
--hash=sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171 \
--hash=sha256:f70b98cd94886b49d91170ef23ec5c0e8ebb6f242d734ed7ed677b24d50c82cf \
--hash=sha256:fc35cb4676846ef752816d5be2193a1e8367b4c1397b74a565a9d0389c433a1d \
--hash=sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba
# via
# aiohttp
# yarl
mypy-extensions==0.4.3 \
--hash=sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d \
--hash=sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8
# via black
openapi-python-client==0.13.1 \
--hash=sha256:43bcd2e43e39dc31decba76ec09cbaeb6faad8709ce4684aec9b0228cd1bf3b5 \
--hash=sha256:adb5d886946cae2ff654f26396bd4d3f497234d5a9dafee805ee19587acbfdce
# via -r ./requirements.txt
passlib[bcrypt]==1.7.4 \
--hash=sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1 \
--hash=sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04
# via -r ./requirements.txt
pathspec==0.11.0 \
--hash=sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229 \
--hash=sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc
# via black
platformdirs==2.6.2 \
--hash=sha256:83c8f6d04389165de7c9b6f0c682439697887bca0aa2f1c87ef1826be3584490 \
--hash=sha256:e1fea1fe471b9ff8332e229df3cb7de4f53eeea4998d3b6bfff542115e998bd2
# via
# black
# pylint
priority==2.0.0 \
--hash=sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa \
--hash=sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0
# via hypercorn
protobuf==4.21.12 \
--hash=sha256:1f22ac0ca65bb70a876060d96d914dae09ac98d114294f77584b0d2644fa9c30 \
--hash=sha256:237216c3326d46808a9f7c26fd1bd4b20015fb6867dc5d263a493ef9a539293b \
--hash=sha256:27f4d15021da6d2b706ddc3860fac0a5ddaba34ab679dc182b60a8bb4e1121cc \
--hash=sha256:299ea899484ee6f44604deb71f424234f654606b983cb496ea2a53e3c63ab791 \
--hash=sha256:3d164928ff0727d97022957c2b849250ca0e64777ee31efd7d6de2e07c494717 \
--hash=sha256:6ab80df09e3208f742c98443b6166bcb70d65f52cfeb67357d52032ea1ae9bec \
--hash=sha256:78a28c9fa223998472886c77042e9b9afb6fe4242bd2a2a5aced88e3f4422aa7 \
--hash=sha256:7cd532c4566d0e6feafecc1059d04c7915aec8e182d1cf7adee8b24ef1e2e6ab \
--hash=sha256:89f9149e4a0169cddfc44c74f230d7743002e3aa0b9472d8c28f0388102fc4c2 \
--hash=sha256:a53fd3f03e578553623272dc46ac2f189de23862e68565e83dde203d41b76fc5 \
--hash=sha256:b135410244ebe777db80298297a97fbb4c862c881b4403b71bac9d4107d61fd1 \
--hash=sha256:b98d0148f84e3a3c569e19f52103ca1feacdac0d2df8d6533cf983d1fda28462 \
--hash=sha256:d1736130bce8cf131ac7957fa26880ca19227d4ad68b4888b3be0dea1f95df97 \
--hash=sha256:f45460f9ee70a0ec1b6694c6e4e348ad2019275680bd68a1d9314b8c7e01e574
# via temporalio
pydantic==1.10.4 \
--hash=sha256:05a81b006be15655b2a1bae5faa4280cf7c81d0e09fcb49b342ebf826abe5a72 \
--hash=sha256:0b53e1d41e97063d51a02821b80538053ee4608b9a181c1005441f1673c55423 \
--hash=sha256:2b3ce5f16deb45c472dde1a0ee05619298c864a20cded09c4edd820e1454129f \
--hash=sha256:2e82a6d37a95e0b1b42b82ab340ada3963aea1317fd7f888bb6b9dfbf4fff57c \
--hash=sha256:301d626a59edbe5dfb48fcae245896379a450d04baeed50ef40d8199f2733b06 \
--hash=sha256:39f4a73e5342b25c2959529f07f026ef58147249f9b7431e1ba8414a36761f53 \
--hash=sha256:4948f264678c703f3877d1c8877c4e3b2e12e549c57795107f08cf70c6ec7774 \
--hash=sha256:4b05697738e7d2040696b0a66d9f0a10bec0efa1883ca75ee9e55baf511909d6 \
--hash=sha256:51bdeb10d2db0f288e71d49c9cefa609bca271720ecd0c58009bd7504a0c464c \
--hash=sha256:55b1625899acd33229c4352ce0ae54038529b412bd51c4915349b49ca575258f \
--hash=sha256:572066051eeac73d23f95ba9a71349c42a3e05999d0ee1572b7860235b850cc6 \
--hash=sha256:6a05a9db1ef5be0fe63e988f9617ca2551013f55000289c671f71ec16f4985e3 \
--hash=sha256:6dc1cc241440ed7ca9ab59d9929075445da6b7c94ced281b3dd4cfe6c8cff817 \
--hash=sha256:6e7124d6855b2780611d9f5e1e145e86667eaa3bd9459192c8dc1a097f5e9903 \
--hash=sha256:75d52162fe6b2b55964fbb0af2ee58e99791a3138588c482572bb6087953113a \
--hash=sha256:78cec42b95dbb500a1f7120bdf95c401f6abb616bbe8785ef09887306792e66e \
--hash=sha256:7feb6a2d401f4d6863050f58325b8d99c1e56f4512d98b11ac64ad1751dc647d \
--hash=sha256:8775d4ef5e7299a2f4699501077a0defdaac5b6c4321173bcb0f3c496fbadf85 \
--hash=sha256:887ca463c3bc47103c123bc06919c86720e80e1214aab79e9b779cda0ff92a00 \
--hash=sha256:9193d4f4ee8feca58bc56c8306bcb820f5c7905fd919e0750acdeeeef0615b28 \
--hash=sha256:983e720704431a6573d626b00662eb78a07148c9115129f9b4351091ec95ecc3 \
--hash=sha256:990406d226dea0e8f25f643b370224771878142155b879784ce89f633541a024 \
--hash=sha256:9cbdc268a62d9a98c56e2452d6c41c0263d64a2009aac69246486f01b4f594c4 \
--hash=sha256:a48f1953c4a1d9bd0b5167ac50da9a79f6072c63c4cef4cf2a3736994903583e \
--hash=sha256:a9a6747cac06c2beb466064dda999a13176b23535e4c496c9d48e6406f92d42d \
--hash=sha256:a9f2de23bec87ff306aef658384b02aa7c32389766af3c5dee9ce33e80222dfa \
--hash=sha256:b5635de53e6686fe7a44b5cf25fcc419a0d5e5c1a1efe73d49d48fe7586db854 \
--hash=sha256:b6f9d649892a6f54a39ed56b8dfd5e08b5f3be5f893da430bed76975f3735d15 \
--hash=sha256:b9a3859f24eb4e097502a3be1fb4b2abb79b6103dd9e2e0edb70613a4459a648 \
--hash=sha256:cd8702c5142afda03dc2b1ee6bc358b62b3735b2cce53fc77b31ca9f728e4bc8 \
--hash=sha256:d7b5a3821225f5c43496c324b0d6875fde910a1c2933d726a743ce328fbb2a8c \
--hash=sha256:d88c4c0e5c5dfd05092a4b271282ef0588e5f4aaf345778056fc5259ba098857 \
--hash=sha256:eb992a1ef739cc7b543576337bebfc62c0e6567434e522e97291b251a41dad7f \
--hash=sha256:f2f7eb6273dd12472d7f218e1fef6f7c7c2f00ac2e1ecde4db8824c457300416 \
--hash=sha256:fdf88ab63c3ee282c76d652fc86518aacb737ff35796023fae56a65ced1a5978 \
--hash=sha256:fdf8d759ef326962b4678d89e275ffc55b7ce59d917d9f72233762061fd04a2d
# via
# -r ./requirements.txt
# fastapi
# fastapi-pagination
# openapi-python-client
pyflakes==3.0.1 \
--hash=sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf \
--hash=sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd
# via autoflake
pylint==2.15.10 \
--hash=sha256:9df0d07e8948a1c3ffa3b6e2d7e6e63d9fb457c5da5b961ed63106594780cc7e \
--hash=sha256:b3dc5ef7d33858f297ac0d06cc73862f01e4f2e74025ec3eff347ce0bc60baf5
# via -r ./requirements.txt
pypika-tortoise==0.1.6 \
--hash=sha256:2d68bbb7e377673743cff42aa1059f3a80228d411fbcae591e4465e173109fd8 \
--hash=sha256:d802868f479a708e3263724c7b5719a26ad79399b2a70cea065f4a4cadbebf36
# via tortoise-orm
python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
# via
# openapi-python-client
# temporalio
python-multipart==0.0.5 \
--hash=sha256:f7bb5f611fc600d15fa47b3974c8aa16e93724513b49b5f95c81e6624c83fa43
# via -r ./requirements.txt
pytz==2022.7.1 \
--hash=sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0 \
--hash=sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a
# via tortoise-orm
pyyaml==6.0 \
--hash=sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf \
--hash=sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293 \
--hash=sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b \
--hash=sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57 \
--hash=sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b \
--hash=sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4 \
--hash=sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07 \
--hash=sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba \
--hash=sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9 \
--hash=sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287 \
--hash=sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513 \
--hash=sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0 \
--hash=sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782 \
--hash=sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0 \
--hash=sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92 \
--hash=sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f \
--hash=sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2 \
--hash=sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc \
--hash=sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1 \
--hash=sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c \
--hash=sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86 \
--hash=sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4 \
--hash=sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c \
--hash=sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34 \
--hash=sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b \
--hash=sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d \
--hash=sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c \
--hash=sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb \
--hash=sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7 \
--hash=sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737 \
--hash=sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3 \
--hash=sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d \
--hash=sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358 \
--hash=sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53 \
--hash=sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78 \
--hash=sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803 \
--hash=sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a \
--hash=sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f \
--hash=sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174 \
--hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
# via
# -r ./requirements.txt
# openapi-python-client
rfc3986[idna2008]==1.5.0 \
--hash=sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835 \
--hash=sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97
# via httpx
setuptools==58.2.0 \
--hash=sha256:2551203ae6955b9876741a26ab3e767bb3242dafe86a32a749ea0d78b6792f11 \
--hash=sha256:2c55bdb85d5bb460bd2e3b12052b677879cffcf46c0c688f2e5bf51d36001145
# via -r ./requirements.txt
shellingham==1.5.0.post1 \
--hash=sha256:368bf8c00754fd4f55afb7bbb86e272df77e4dc76ac29dbcbb81a59e9fc15744 \
--hash=sha256:823bc5fb5c34d60f285b624e7264f4dda254bc803a3774a147bf99c0e3004a28
# via openapi-python-client
six==1.16.0 \
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
# via
# python-dateutil
# python-multipart
sniffio==1.3.0 \
--hash=sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101 \
--hash=sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384
# via
# anyio
# httpcore
# httpx
soupsieve==2.3.2.post1 \
--hash=sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759 \
--hash=sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d
# via beautifulsoup4
starlette==0.22.0 \
--hash=sha256:b092cbc365bea34dd6840b42861bdabb2f507f8671e642e8272d2442e08ea4ff \
--hash=sha256:b5eda991ad5f0ee5d8ce4c4540202a573bb6691ecd0c712262d0bc85cf8f2c50
# via fastapi
temporalio==1.0.0 \
--hash=sha256:06126178cbb98d44667914ac57876f24fc3e3532384374cae8b38a6ac59ad8fe \
--hash=sha256:4d17e953e93241162133cd6e9581bc8a3804a6e2e3aee8ac3c1d503536d7d8c9 \
--hash=sha256:5efbdad3e409b2f2169c34167a5219ca9abd6ebd694fc52ae974f04b2d7c8d79 \
--hash=sha256:7c18030d63f178c6c6d958d26c136e77888b7bd1d6db67b129de1bea9a1bd463 \
--hash=sha256:7c82a875c3db9ab2c8492ddc01498dbb2636cad34cf8bc985a6f0f17bd627f99 \
--hash=sha256:b2454ef6b68335a554adca1e4f14831b5c3ea33ef8adb25742dd91652bd38a82
# via -r ./requirements.txt
toml==0.10.2 \
--hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \
--hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f
# via hypercorn
tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
# via
# autoflake
# black
# pylint
tomlkit==0.11.6 \
--hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \
--hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73
# via pylint
tortoise-orm[asyncpg]==0.19.2 \
--hash=sha256:a99b8c9f42d5cd49493c70471b5c9a5df8ecf49cc624f2f41b9dc75bba993ac5 \
--hash=sha256:bff4d79abfca7fb805972bb2438e8e0cd2e6590bc2cfd7593a803518a027bbf0
# via -r ./requirements.txt
typer==0.7.0 \
--hash=sha256:b5e704f4e48ec263de1c0b3a2387cd405a13767d2f907f44c1a08cbad96f606d \
--hash=sha256:ff797846578a9f2a201b53442aedeb543319466870fbe1c701eab66dd7681165
# via openapi-python-client
types-protobuf==3.20.4.6 \
--hash=sha256:ab2d315ba82246b83d28f8797c98dc0fe1dd5cfd187909e56faf87239aedaae3 \
--hash=sha256:ba27443c592bbec1629dd69494a24c84461c63f0d3b7d648ce258aaae9680965
# via temporalio
typing-extensions==4.4.0 \
--hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \
--hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e
# via
# aiosqlite
# astroid
# black
# dataclass-wizard
# pydantic
# pylint
# starlette
# temporalio
wrapt==1.14.1 \
--hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \
--hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \
--hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \
--hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \
--hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \
--hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \
--hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \
--hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \
--hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \
--hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \
--hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \
--hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \
--hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \
--hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \
--hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \
--hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \
--hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \
--hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \
--hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \
--hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \
--hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \
--hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \
--hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \
--hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \
--hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \
--hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \
--hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \
--hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \
--hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \
--hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \
--hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \
--hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \
--hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \
--hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \
--hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \
--hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \
--hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \
--hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \
--hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \
--hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \
--hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \
--hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \
--hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \
--hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \
--hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \
--hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \
--hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \
--hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \
--hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \
--hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \
--hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \
--hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \
--hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \
--hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \
--hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \
--hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \
--hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \
--hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \
--hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \
--hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \
--hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \
--hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \
--hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \
--hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af
# via astroid
wsproto==1.2.0 \
--hash=sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065 \
--hash=sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736
# via hypercorn
yapf==0.32.0 \
--hash=sha256:8fea849025584e486fd06d6ba2bed717f396080fd3cc236ba10cb97c4c51cf32 \
--hash=sha256:a3f5085d37ef7e3e004c4ba9f9b3e40c54ff1901cd111f05145ae313a7c67d1b
# via -r ./requirements.txt
yarl==1.8.2 \
--hash=sha256:009a028127e0a1755c38b03244c0bea9d5565630db9c4cf9572496e947137a87 \
--hash=sha256:0414fd91ce0b763d4eadb4456795b307a71524dbacd015c657bb2a39db2eab89 \
--hash=sha256:0978f29222e649c351b173da2b9b4665ad1feb8d1daa9d971eb90df08702668a \
--hash=sha256:0ef8fb25e52663a1c85d608f6dd72e19bd390e2ecaf29c17fb08f730226e3a08 \
--hash=sha256:10b08293cda921157f1e7c2790999d903b3fd28cd5c208cf8826b3b508026996 \
--hash=sha256:1684a9bd9077e922300ecd48003ddae7a7474e0412bea38d4631443a91d61077 \
--hash=sha256:1b372aad2b5f81db66ee7ec085cbad72c4da660d994e8e590c997e9b01e44901 \
--hash=sha256:1e21fb44e1eff06dd6ef971d4bdc611807d6bd3691223d9c01a18cec3677939e \
--hash=sha256:2305517e332a862ef75be8fad3606ea10108662bc6fe08509d5ca99503ac2aee \
--hash=sha256:24ad1d10c9db1953291f56b5fe76203977f1ed05f82d09ec97acb623a7976574 \
--hash=sha256:272b4f1599f1b621bf2aabe4e5b54f39a933971f4e7c9aa311d6d7dc06965165 \
--hash=sha256:2a1fca9588f360036242f379bfea2b8b44cae2721859b1c56d033adfd5893634 \
--hash=sha256:2b4fa2606adf392051d990c3b3877d768771adc3faf2e117b9de7eb977741229 \
--hash=sha256:3150078118f62371375e1e69b13b48288e44f6691c1069340081c3fd12c94d5b \
--hash=sha256:326dd1d3caf910cd26a26ccbfb84c03b608ba32499b5d6eeb09252c920bcbe4f \
--hash=sha256:34c09b43bd538bf6c4b891ecce94b6fa4f1f10663a8d4ca589a079a5018f6ed7 \
--hash=sha256:388a45dc77198b2460eac0aca1efd6a7c09e976ee768b0d5109173e521a19daf \
--hash=sha256:3adeef150d528ded2a8e734ebf9ae2e658f4c49bf413f5f157a470e17a4a2e89 \
--hash=sha256:3edac5d74bb3209c418805bda77f973117836e1de7c000e9755e572c1f7850d0 \
--hash=sha256:3f6b4aca43b602ba0f1459de647af954769919c4714706be36af670a5f44c9c1 \
--hash=sha256:3fc056e35fa6fba63248d93ff6e672c096f95f7836938241ebc8260e062832fe \
--hash=sha256:418857f837347e8aaef682679f41e36c24250097f9e2f315d39bae3a99a34cbf \
--hash=sha256:42430ff511571940d51e75cf42f1e4dbdded477e71c1b7a17f4da76c1da8ea76 \
--hash=sha256:44ceac0450e648de86da8e42674f9b7077d763ea80c8ceb9d1c3e41f0f0a9951 \
--hash=sha256:47d49ac96156f0928f002e2424299b2c91d9db73e08c4cd6742923a086f1c863 \
--hash=sha256:48dd18adcf98ea9cd721a25313aef49d70d413a999d7d89df44f469edfb38a06 \
--hash=sha256:49d43402c6e3013ad0978602bf6bf5328535c48d192304b91b97a3c6790b1562 \
--hash=sha256:4d04acba75c72e6eb90745447d69f84e6c9056390f7a9724605ca9c56b4afcc6 \
--hash=sha256:57a7c87927a468e5a1dc60c17caf9597161d66457a34273ab1760219953f7f4c \
--hash=sha256:58a3c13d1c3005dbbac5c9f0d3210b60220a65a999b1833aa46bd6677c69b08e \
--hash=sha256:5df5e3d04101c1e5c3b1d69710b0574171cc02fddc4b23d1b2813e75f35a30b1 \
--hash=sha256:63243b21c6e28ec2375f932a10ce7eda65139b5b854c0f6b82ed945ba526bff3 \
--hash=sha256:64dd68a92cab699a233641f5929a40f02a4ede8c009068ca8aa1fe87b8c20ae3 \
--hash=sha256:6604711362f2dbf7160df21c416f81fac0de6dbcf0b5445a2ef25478ecc4c778 \
--hash=sha256:6c4fcfa71e2c6a3cb568cf81aadc12768b9995323186a10827beccf5fa23d4f8 \
--hash=sha256:6d88056a04860a98341a0cf53e950e3ac9f4e51d1b6f61a53b0609df342cc8b2 \
--hash=sha256:705227dccbe96ab02c7cb2c43e1228e2826e7ead880bb19ec94ef279e9555b5b \
--hash=sha256:728be34f70a190566d20aa13dc1f01dc44b6aa74580e10a3fb159691bc76909d \
--hash=sha256:74dece2bfc60f0f70907c34b857ee98f2c6dd0f75185db133770cd67300d505f \
--hash=sha256:75c16b2a900b3536dfc7014905a128a2bea8fb01f9ee26d2d7d8db0a08e7cb2c \
--hash=sha256:77e913b846a6b9c5f767b14dc1e759e5aff05502fe73079f6f4176359d832581 \
--hash=sha256:7a66c506ec67eb3159eea5096acd05f5e788ceec7b96087d30c7d2865a243918 \
--hash=sha256:8c46d3d89902c393a1d1e243ac847e0442d0196bbd81aecc94fcebbc2fd5857c \
--hash=sha256:93202666046d9edadfe9f2e7bf5e0782ea0d497b6d63da322e541665d65a044e \
--hash=sha256:97209cc91189b48e7cfe777237c04af8e7cc51eb369004e061809bcdf4e55220 \
--hash=sha256:a48f4f7fea9a51098b02209d90297ac324241bf37ff6be6d2b0149ab2bd51b37 \
--hash=sha256:a783cd344113cb88c5ff7ca32f1f16532a6f2142185147822187913eb989f739 \
--hash=sha256:ae0eec05ab49e91a78700761777f284c2df119376e391db42c38ab46fd662b77 \
--hash=sha256:ae4d7ff1049f36accde9e1ef7301912a751e5bae0a9d142459646114c70ecba6 \
--hash=sha256:b05df9ea7496df11b710081bd90ecc3a3db6adb4fee36f6a411e7bc91a18aa42 \
--hash=sha256:baf211dcad448a87a0d9047dc8282d7de59473ade7d7fdf22150b1d23859f946 \
--hash=sha256:bb81f753c815f6b8e2ddd2eef3c855cf7da193b82396ac013c661aaa6cc6b0a5 \
--hash=sha256:bcd7bb1e5c45274af9a1dd7494d3c52b2be5e6bd8d7e49c612705fd45420b12d \
--hash=sha256:bf071f797aec5b96abfc735ab97da9fd8f8768b43ce2abd85356a3127909d146 \
--hash=sha256:c15163b6125db87c8f53c98baa5e785782078fbd2dbeaa04c6141935eb6dab7a \
--hash=sha256:cb6d48d80a41f68de41212f3dfd1a9d9898d7841c8f7ce6696cf2fd9cb57ef83 \
--hash=sha256:ceff9722e0df2e0a9e8a79c610842004fa54e5b309fe6d218e47cd52f791d7ef \
--hash=sha256:cfa2bbca929aa742b5084fd4663dd4b87c191c844326fcb21c3afd2d11497f80 \
--hash=sha256:d617c241c8c3ad5c4e78a08429fa49e4b04bedfc507b34b4d8dceb83b4af3588 \
--hash=sha256:d881d152ae0007809c2c02e22aa534e702f12071e6b285e90945aa3c376463c5 \
--hash=sha256:da65c3f263729e47351261351b8679c6429151ef9649bba08ef2528ff2c423b2 \
--hash=sha256:de986979bbd87272fe557e0a8fcb66fd40ae2ddfe28a8b1ce4eae22681728fef \
--hash=sha256:df60a94d332158b444301c7f569659c926168e4d4aad2cfbf4bce0e8fb8be826 \
--hash=sha256:dfef7350ee369197106805e193d420b75467b6cceac646ea5ed3049fcc950a05 \
--hash=sha256:e59399dda559688461762800d7fb34d9e8a6a7444fd76ec33220a926c8be1516 \
--hash=sha256:e6f3515aafe0209dd17fb9bdd3b4e892963370b3de781f53e1746a521fb39fc0 \
--hash=sha256:e7fd20d6576c10306dea2d6a5765f46f0ac5d6f53436217913e952d19237efc4 \
--hash=sha256:ebb78745273e51b9832ef90c0898501006670d6e059f2cdb0e999494eb1450c2 \
--hash=sha256:efff27bd8cbe1f9bd127e7894942ccc20c857aa8b5a0327874f30201e5ce83d0 \
--hash=sha256:f37db05c6051eff17bc832914fe46869f8849de5b92dc4a3466cd63095d23dfd \
--hash=sha256:f8ca8ad414c85bbc50f49c0a106f951613dfa5f948ab69c10ce9b128d368baf8 \
--hash=sha256:fb742dcdd5eec9f26b61224c23baea46c9055cf16f62475e11b9b15dfd5c117b \
--hash=sha256:fc77086ce244453e074e445104f0ecb27530d6fd3a46698e33f6c38951d5a0f1 \
--hash=sha256:ff205b58dc2929191f68162633d5e10e8044398d7a45265f90a0f1d51f85f72c
# via aiohttp