mirror of
https://github.com/resf/distro-tools.git
synced 2024-12-18 09:18:38 +00:00
Add apollo_tree and fix pylint warnings
This commit is contained in:
parent
b498d3b889
commit
5e1fde1027
18
.github/workflows/test.yaml
vendored
Normal file
18
.github/workflows/test.yaml
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
name: Lint and test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Lint
|
||||||
|
run: ./build/scripts/pylint.bash
|
||||||
|
- name: Test
|
||||||
|
run: ./build/scripts/test.bash
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -14,5 +14,8 @@
|
|||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"[python]": {
|
"[python]": {
|
||||||
"editor.tabSize": 4
|
"editor.tabSize": 4
|
||||||
|
},
|
||||||
|
"[xml]": {
|
||||||
|
"editor.formatOnSave": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
346
apollo/publishing_tools/apollo_tree.py
Normal file
346
apollo/publishing_tools/apollo_tree.py
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import hashlib
|
||||||
|
import gzip
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import time
|
||||||
|
from urllib.parse import quote
|
||||||
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger("apollo_tree")
|
||||||
|
|
||||||
|
NS = {
|
||||||
|
"": "http://linux.duke.edu/metadata/repo",
|
||||||
|
"rpm": "http://linux.duke.edu/metadata/rpm"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Repository:
|
||||||
|
base_repomd: str = None
|
||||||
|
source_repomd: str = None
|
||||||
|
debug_repomd: str = None
|
||||||
|
arch: str = None
|
||||||
|
|
||||||
|
|
||||||
|
async def scan_path(
|
||||||
|
base_path: str,
|
||||||
|
fmt: str,
|
||||||
|
ignore_dirs: list[str],
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Scan base path for repositories
|
||||||
|
The format string can contain $reponame and $arch
|
||||||
|
When we reach $reponame, that means we have found a repository
|
||||||
|
Follow the path further into the tree until $arch is found
|
||||||
|
That determines the architecture of the repository
|
||||||
|
"""
|
||||||
|
|
||||||
|
repos = {}
|
||||||
|
|
||||||
|
# First we need to find the root.
|
||||||
|
# Construct root by prepending base_path and all parts until $reponame
|
||||||
|
# Then we can walk the tree from there
|
||||||
|
root = base_path
|
||||||
|
parts = fmt.split("/")
|
||||||
|
repo_first = True
|
||||||
|
if "$reponame" in parts:
|
||||||
|
for part in parts:
|
||||||
|
parts.pop(0)
|
||||||
|
if part == "$reponame":
|
||||||
|
break
|
||||||
|
if part == "$arch":
|
||||||
|
repo_first = False
|
||||||
|
break
|
||||||
|
root = os.path.join(root, part)
|
||||||
|
|
||||||
|
logger.info("Found root: %s", root)
|
||||||
|
|
||||||
|
# Walk the base path
|
||||||
|
for directory in os.listdir(root):
|
||||||
|
if directory in ignore_dirs:
|
||||||
|
continue
|
||||||
|
current_parts = parts
|
||||||
|
if repo_first:
|
||||||
|
repo_name = directory
|
||||||
|
logger.info("Found repo: %s", repo_name)
|
||||||
|
else:
|
||||||
|
arch = directory
|
||||||
|
logger.info("Found arch: %s", arch)
|
||||||
|
repo_base = os.path.join(root, directory)
|
||||||
|
|
||||||
|
if repo_first:
|
||||||
|
repos[repo_name] = []
|
||||||
|
|
||||||
|
# Construct repo base until we reach $arch
|
||||||
|
if "$arch" in current_parts:
|
||||||
|
for part in current_parts:
|
||||||
|
if (part == "$arch" and repo_first) or part == "$reponame":
|
||||||
|
break
|
||||||
|
repo_base = os.path.join(repo_base, part)
|
||||||
|
current_parts.pop(0)
|
||||||
|
|
||||||
|
logger.warning("Searching for arches in %s", repo_base)
|
||||||
|
|
||||||
|
# All dirs in repo_base is an architecture
|
||||||
|
for arch_ in os.listdir(repo_base):
|
||||||
|
if repo_first:
|
||||||
|
arch = arch_
|
||||||
|
else:
|
||||||
|
repo_name = arch_
|
||||||
|
# Now append each combination + rest of parts as repo_info
|
||||||
|
if repo_first:
|
||||||
|
logger.info("Found arch: %s", arch)
|
||||||
|
else:
|
||||||
|
logger.info("Found repo: %s", repo_name)
|
||||||
|
|
||||||
|
if repo_first:
|
||||||
|
found_path = f"{repo_base}/{arch}/{'/'.join(current_parts[1:])}"
|
||||||
|
else:
|
||||||
|
found_path = f"{repo_base}/{repo_name}/{'/'.join(current_parts[1:])}"
|
||||||
|
|
||||||
|
# Verify that the path exists
|
||||||
|
if not os.path.exists(found_path):
|
||||||
|
logger.warning("Path does not exist: %s, skipping", found_path)
|
||||||
|
continue
|
||||||
|
|
||||||
|
repo = {
|
||||||
|
"name": repo_name,
|
||||||
|
"arch": arch,
|
||||||
|
"found_path": found_path,
|
||||||
|
}
|
||||||
|
if repo_name not in repos:
|
||||||
|
repos[repo_name] = []
|
||||||
|
repos[repo_name].append(repo)
|
||||||
|
|
||||||
|
return repos
|
||||||
|
|
||||||
|
|
||||||
|
async def fetch_updateinfo_from_apollo(
|
||||||
|
repo: dict,
|
||||||
|
product_name: str,
|
||||||
|
arch: str = None,
|
||||||
|
api_base: str = None,
|
||||||
|
) -> str:
|
||||||
|
if not api_base:
|
||||||
|
api_base = "https://apollo.build.resf.org/api/v3/updateinfo"
|
||||||
|
api_url = f"{api_base}/{quote(product_name)}/{quote(repo['name'])}/updateinfo.xml"
|
||||||
|
if arch:
|
||||||
|
api_url += f"?req_arch={arch}"
|
||||||
|
|
||||||
|
logger.info("Fetching updateinfo from %s", api_url)
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
async with session.get(api_url) as resp:
|
||||||
|
if resp.status != 200:
|
||||||
|
logger.error("Failed to fetch updateinfo from %s", api_url)
|
||||||
|
return None
|
||||||
|
return await resp.text()
|
||||||
|
|
||||||
|
|
||||||
|
async def gzip_updateinfo(updateinfo: str) -> dict:
|
||||||
|
# Gzip updateinfo, get both open and closed size as
|
||||||
|
# well as the sha256sum for both
|
||||||
|
|
||||||
|
# First get the sha256sum and size of the open updateinfo
|
||||||
|
sha256sum = hashlib.sha256(updateinfo.encode("utf-8")).hexdigest()
|
||||||
|
size = len(updateinfo)
|
||||||
|
|
||||||
|
# Then gzip it and get hash and size
|
||||||
|
gzipped = gzip.compress(updateinfo.encode("utf-8"), mtime=0)
|
||||||
|
gzipped_sha256sum = hashlib.sha256(gzipped).hexdigest()
|
||||||
|
gzipped_size = len(gzipped)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"sha256sum": sha256sum,
|
||||||
|
"size": size,
|
||||||
|
"gzipped_sha256sum": gzipped_sha256sum,
|
||||||
|
"gzipped_size": gzipped_size,
|
||||||
|
"gzipped": gzipped,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def write_updateinfo_to_file(
|
||||||
|
repomd_xml_path: str, updateinfo: dict
|
||||||
|
) -> str:
|
||||||
|
# Write updateinfo to file
|
||||||
|
repomd_dir = os.path.dirname(repomd_xml_path)
|
||||||
|
gzipped_sum = updateinfo["gzipped_sha256sum"]
|
||||||
|
updateinfo_path = os.path.join(
|
||||||
|
repomd_dir, f"{gzipped_sum}-updateinfo.xml.gz"
|
||||||
|
)
|
||||||
|
with open(updateinfo_path, "wb") as f:
|
||||||
|
f.write(updateinfo["gzipped"])
|
||||||
|
|
||||||
|
return updateinfo_path
|
||||||
|
|
||||||
|
|
||||||
|
async def update_repomd_xml(repomd_xml_path: str, updateinfo: dict):
|
||||||
|
# Update repomd.xml with new updateinfo
|
||||||
|
gzipped_sum = updateinfo["gzipped_sha256sum"]
|
||||||
|
updateinfo_path = f"{gzipped_sum}-updateinfo.xml.gz"
|
||||||
|
|
||||||
|
# Parse repomd.xml
|
||||||
|
ET.register_namespace("", NS[""])
|
||||||
|
ET.register_namespace("rpm", NS["rpm"])
|
||||||
|
repomd_xml = ET.parse(repomd_xml_path).getroot()
|
||||||
|
|
||||||
|
# Iterate over data and find type="updateinfo" and delete it
|
||||||
|
existing_updateinfo_path = None
|
||||||
|
for data in repomd_xml.findall("data", NS):
|
||||||
|
data_type = data.attrib["type"]
|
||||||
|
if not data_type:
|
||||||
|
logger.warning("No type found in data, skipping")
|
||||||
|
continue
|
||||||
|
if data_type == "updateinfo":
|
||||||
|
# Delete the data element
|
||||||
|
repomd_xml.remove(data)
|
||||||
|
|
||||||
|
# Get the location of the updateinfo file
|
||||||
|
location = data.find("location", NS)
|
||||||
|
if not location:
|
||||||
|
logger.warning("No location found in data, skipping")
|
||||||
|
continue
|
||||||
|
existing_updateinfo_path = location.attrib["href"]
|
||||||
|
break
|
||||||
|
|
||||||
|
# Create new data element and set type to updateinfo
|
||||||
|
data = ET.Element("data")
|
||||||
|
data.set("type", "updateinfo")
|
||||||
|
|
||||||
|
# Add checksum, open-checksum, location, timestamp, size and open-size
|
||||||
|
checksum = ET.SubElement(data, "checksum")
|
||||||
|
checksum.set("type", "sha256")
|
||||||
|
checksum.text = updateinfo["gzipped_sha256sum"]
|
||||||
|
|
||||||
|
open_checksum = ET.SubElement(data, "open-checksum")
|
||||||
|
open_checksum.set("type", "sha256")
|
||||||
|
open_checksum.text = updateinfo["sha256sum"]
|
||||||
|
|
||||||
|
location = ET.SubElement(data, "location")
|
||||||
|
location.set("href", f"repodata/{updateinfo_path}")
|
||||||
|
|
||||||
|
timestamp = ET.SubElement(data, "timestamp")
|
||||||
|
timestamp.text = str(int(time.time()))
|
||||||
|
|
||||||
|
size = ET.SubElement(data, "size")
|
||||||
|
size.text = str(updateinfo["gzipped_size"])
|
||||||
|
|
||||||
|
open_size = ET.SubElement(data, "open-size")
|
||||||
|
open_size.text = str(updateinfo["size"])
|
||||||
|
|
||||||
|
# Add data to repomd.xml
|
||||||
|
repomd_xml.append(data)
|
||||||
|
|
||||||
|
# Create string
|
||||||
|
ET.indent(repomd_xml)
|
||||||
|
xml_str = ET.tostring(
|
||||||
|
repomd_xml,
|
||||||
|
xml_declaration=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
short_empty_elements=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Prepend declaration with double quotes
|
||||||
|
xml_str = xml_str.decode("utf-8")
|
||||||
|
xml_str = xml_str.replace("'", "\"")
|
||||||
|
xml_str = xml_str.replace("utf-8", "UTF-8")
|
||||||
|
|
||||||
|
# "Fix" closing tags to not have a space
|
||||||
|
xml_str = xml_str.replace(" />", "/>")
|
||||||
|
|
||||||
|
# Add xmlns:rpm
|
||||||
|
xml_str = xml_str.replace(
|
||||||
|
"repo\">",
|
||||||
|
f"repo\" xmlns:rpm=\"{NS['rpm']}\">",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write to repomd.xml
|
||||||
|
with open(repomd_xml_path, "w", encoding="utf-8") as f:
|
||||||
|
f.write(xml_str)
|
||||||
|
|
||||||
|
# Delete old updateinfo file
|
||||||
|
if existing_updateinfo_path:
|
||||||
|
os.remove(existing_updateinfo_path)
|
||||||
|
|
||||||
|
|
||||||
|
async def main(args):
|
||||||
|
base_paths = await scan_path(
|
||||||
|
args.path,
|
||||||
|
args.base_format,
|
||||||
|
args.ignore,
|
||||||
|
)
|
||||||
|
print(args)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
prog="apollo_tree",
|
||||||
|
description="Apollo updateinfo.xml publisher (Local file tree)",
|
||||||
|
epilog="(C) 2023 Rocky Enterprise Software Foundation, Inc.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-b",
|
||||||
|
"--base-format",
|
||||||
|
default="$reponame/$arch/os/repodata/repomd.xml",
|
||||||
|
help="Format for main repo.xml file",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-m",
|
||||||
|
"--manual",
|
||||||
|
action="store_true",
|
||||||
|
help="Manual mode",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-r",
|
||||||
|
"--repos",
|
||||||
|
nargs="+",
|
||||||
|
action="append",
|
||||||
|
default=[],
|
||||||
|
help="Repositories to publish (manual mode), format: <arch>:<repomd>",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--auto-scan",
|
||||||
|
default=True,
|
||||||
|
action="store_true",
|
||||||
|
help="Automatically scan for repos",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-p",
|
||||||
|
"--path",
|
||||||
|
help="Default path to scan for repos",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-i",
|
||||||
|
"--ignore",
|
||||||
|
nargs="+",
|
||||||
|
action="append",
|
||||||
|
default=[],
|
||||||
|
help="Directories in base path to ignore in auto-scan mode",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-n",
|
||||||
|
"--product-name",
|
||||||
|
required=True,
|
||||||
|
help="Product name",
|
||||||
|
)
|
||||||
|
|
||||||
|
p_args = parser.parse_args()
|
||||||
|
if p_args.auto_scan and p_args.manual:
|
||||||
|
parser.error("Cannot use --auto-scan and --manual together")
|
||||||
|
|
||||||
|
if p_args.manual and not p_args.repos:
|
||||||
|
parser.error("Must specify repos to publish in manual mode")
|
||||||
|
|
||||||
|
if p_args.auto_scan and not p_args.path:
|
||||||
|
parser.error("Must specify path to scan for repos in auto-scan mode")
|
||||||
|
|
||||||
|
asyncio.run(main(p_args))
|
@ -126,7 +126,11 @@ class Advisory(JSONWizard):
|
|||||||
Returns whether this advisory affects the given RHEL version and architecture.
|
Returns whether this advisory affects the given RHEL version and architecture.
|
||||||
"""
|
"""
|
||||||
for product in self.get_products():
|
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:
|
is_variant = product.variant == "Red Hat Enterprise Linux"
|
||||||
|
is_major_version = product.major_version == major_version
|
||||||
|
is_minor_version = product.minor_version == minor_version
|
||||||
|
is_arch = product.arch == arch.value
|
||||||
|
if is_variant and is_major_version and is_minor_version and is_arch:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import datetime
|
|
||||||
from __init__ import API, Architecture
|
from __init__ import API, Architecture
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ from os import path
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from common.logger import Logger
|
|
||||||
|
|
||||||
NVRA_RE = re.compile(
|
NVRA_RE = re.compile(
|
||||||
r"^(\S+)-([\w~%.+]+)-(\w+(?:\.[\w~%+]+)+?)(?:\.(\w+))?(?:\.rpm)?$"
|
r"^(\S+)-([\w~%.+]+)-(\w+(?:\.[\w~%+]+)+?)(?:\.(\w+))?(?:\.rpm)?$"
|
||||||
)
|
)
|
||||||
|
@ -111,7 +111,7 @@ async def clone_advisory(
|
|||||||
logger = Logger()
|
logger = Logger()
|
||||||
logger.info("Cloning advisory %s to %s", advisory.name, product.name)
|
logger.info("Cloning advisory %s to %s", advisory.name, product.name)
|
||||||
|
|
||||||
acceptable_arches = list(set([x.match_arch for x in mirrors]))
|
acceptable_arches = list({x.match_arch for x in mirrors})
|
||||||
acceptable_arches.extend(["src", "noarch"])
|
acceptable_arches.extend(["src", "noarch"])
|
||||||
for mirror in mirrors:
|
for mirror in mirrors:
|
||||||
if mirror.match_arch == "x86_64":
|
if mirror.match_arch == "x86_64":
|
||||||
@ -377,14 +377,12 @@ async def clone_advisory(
|
|||||||
|
|
||||||
# Check if topic is empty, if so construct it
|
# Check if topic is empty, if so construct it
|
||||||
if not new_advisory.topic:
|
if not new_advisory.topic:
|
||||||
package_names = list(set([p.package_name for p in new_pkgs]))
|
package_names = list({p.package_name for p in new_pkgs})
|
||||||
affected_products = list(
|
affected_products = list(
|
||||||
set(
|
{
|
||||||
[
|
|
||||||
f"{product.name} {mirror.match_major_version}"
|
f"{product.name} {mirror.match_major_version}"
|
||||||
for mirror in mirrors
|
for mirror in mirrors
|
||||||
]
|
}
|
||||||
)
|
|
||||||
)
|
)
|
||||||
topic = f"""An update is available for {', '.join(package_names)}.
|
topic = f"""An update is available for {', '.join(package_names)}.
|
||||||
This update affects {', '.join(affected_products)}.
|
This update affects {', '.join(affected_products)}.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import TypeVar, Generic
|
from typing import TypeVar, Generic
|
||||||
|
|
||||||
from fastapi import APIRouter, Request
|
from fastapi import APIRouter
|
||||||
from fastapi.exceptions import HTTPException
|
from fastapi.exceptions import HTTPException
|
||||||
from fastapi_pagination.links import Page
|
from fastapi_pagination.links import Page
|
||||||
from fastapi_pagination.ext.tortoise import paginate
|
from fastapi_pagination.ext.tortoise import paginate
|
||||||
|
@ -90,12 +90,10 @@ def v3_advisory_to_v2(
|
|||||||
kind = "TYPE_ENHANCEMENT"
|
kind = "TYPE_ENHANCEMENT"
|
||||||
|
|
||||||
affected_products = list(
|
affected_products = list(
|
||||||
set(
|
{
|
||||||
[
|
|
||||||
f"{ap.variant} {ap.major_version}"
|
f"{ap.variant} {ap.major_version}"
|
||||||
for ap in advisory.affected_products
|
for ap in advisory.affected_products
|
||||||
]
|
}
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
cves = []
|
cves = []
|
||||||
|
@ -67,7 +67,7 @@ async def health():
|
|||||||
|
|
||||||
|
|
||||||
@app.exception_handler(404)
|
@app.exception_handler(404)
|
||||||
async def not_found_handler(request, exc):
|
async def not_found_handler(request, exc): # pylint: disable=unused-argument
|
||||||
if request.url.path.startswith("/api"
|
if request.url.path.startswith("/api"
|
||||||
) or request.url.path.startswith("/v2"):
|
) or request.url.path.startswith("/v2"):
|
||||||
return JSONResponse({"error": "Not found"}, status_code=404)
|
return JSONResponse({"error": "Not found"}, status_code=404)
|
||||||
|
0
apollo/tests/BUILD.bazel
Normal file
0
apollo/tests/BUILD.bazel
Normal file
0
apollo/tests/publishing_tools/BUILD.bazel
Normal file
0
apollo/tests/publishing_tools/BUILD.bazel
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
|
||||||
|
<revision>8.7</revision>
|
||||||
|
<tags>
|
||||||
|
<distro cpeid="cpe:/o:rocky:rocky:8">Rocky Linux 8</distro>
|
||||||
|
</tags>
|
||||||
|
<data type="primary">
|
||||||
|
<checksum type="sha256">602602cc03961da7245740aa32af042c28fa7a4bed01e9f51dcde8326c6240e3</checksum>
|
||||||
|
<open-checksum type="sha256">a69fcb753072006097c806f9f441553e5086b1369180a72ae719fad654246554</open-checksum>
|
||||||
|
<location href="repodata/602602cc03961da7245740aa32af042c28fa7a4bed01e9f51dcde8326c6240e3-primary.xml.gz"/>
|
||||||
|
<timestamp>1674782842</timestamp>
|
||||||
|
<size>1648129</size>
|
||||||
|
<open-size>16701409</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="filelists">
|
||||||
|
<checksum type="sha256">693e2deed8288074851942f71f525bfce865a71734214fa434010dd00a215283</checksum>
|
||||||
|
<open-checksum type="sha256">bc311897f94631363f555ef354525f28613df9effb7e4a0459acffea29bf3ba1</open-checksum>
|
||||||
|
<location href="repodata/693e2deed8288074851942f71f525bfce865a71734214fa434010dd00a215283-filelists.xml.gz"/>
|
||||||
|
<timestamp>1674782842</timestamp>
|
||||||
|
<size>6162410</size>
|
||||||
|
<open-size>87526801</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="other">
|
||||||
|
<checksum type="sha256">fd97455be05a44ffe98685a63031d1ac10661ca0c0bafa747dfae6c479261e6d</checksum>
|
||||||
|
<open-checksum type="sha256">518c3a001a453adb34cf5a70ceecf11aa2d90f0c807c879d76a02f7123f5c22f</open-checksum>
|
||||||
|
<location href="repodata/fd97455be05a44ffe98685a63031d1ac10661ca0c0bafa747dfae6c479261e6d-other.xml.gz"/>
|
||||||
|
<timestamp>1674782842</timestamp>
|
||||||
|
<size>1102970</size>
|
||||||
|
<open-size>12298845</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="primary_db">
|
||||||
|
<checksum type="sha256">ae73143161fda8b62f6b1cc333ee3fcd4100daa0947a5b918e80b4a487ded360</checksum>
|
||||||
|
<open-checksum type="sha256">9f9b5bb6f1772f3f742f66245041246021777015d1d30970d5410b988cdd233a</open-checksum>
|
||||||
|
<location href="repodata/ae73143161fda8b62f6b1cc333ee3fcd4100daa0947a5b918e80b4a487ded360-primary.sqlite.xz"/>
|
||||||
|
<timestamp>1674782850</timestamp>
|
||||||
|
<size>2724240</size>
|
||||||
|
<open-size>17735680</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="filelists_db">
|
||||||
|
<checksum type="sha256">75d9455e941cb3e8a5266980b78eccb26476198bb4a1f3142ee6cda05ed044f9</checksum>
|
||||||
|
<open-checksum type="sha256">23c2249ccb4fe69474b41c1399aac94d4fd1a1d2c6c2cefc46cb23d4dd52e3b0</open-checksum>
|
||||||
|
<location href="repodata/75d9455e941cb3e8a5266980b78eccb26476198bb4a1f3142ee6cda05ed044f9-filelists.sqlite.xz"/>
|
||||||
|
<timestamp>1674782854</timestamp>
|
||||||
|
<size>4556600</size>
|
||||||
|
<open-size>37732352</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="other_db">
|
||||||
|
<checksum type="sha256">f3968e32961df9482a5c265adaeae9a3435c03b81b2c76cfd7c8b1a74337b972</checksum>
|
||||||
|
<open-checksum type="sha256">e84a16aa1bec1a0d6af28ced81aa3a0708d2599b56abbedb858caced501576e9</open-checksum>
|
||||||
|
<location href="repodata/f3968e32961df9482a5c265adaeae9a3435c03b81b2c76cfd7c8b1a74337b972-other.sqlite.xz"/>
|
||||||
|
<timestamp>1674782846</timestamp>
|
||||||
|
<size>1113696</size>
|
||||||
|
<open-size>10711040</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="group">
|
||||||
|
<checksum type="sha256">341f7a33a85d237227c4b814e5ffd57cc7ead34dab6ca79db4feff8520803b22</checksum>
|
||||||
|
<location href="repodata/341f7a33a85d237227c4b814e5ffd57cc7ead34dab6ca79db4feff8520803b22-comps-AppStream.aarch64.xml"/>
|
||||||
|
<timestamp>1674782725</timestamp>
|
||||||
|
<size>428231</size>
|
||||||
|
</data>
|
||||||
|
<data type="group_xz">
|
||||||
|
<checksum type="sha256">c0562df3ad4d3d47bb8076482351eca478a02f4bd15e21b4683456268920154a</checksum>
|
||||||
|
<open-checksum type="sha256">341f7a33a85d237227c4b814e5ffd57cc7ead34dab6ca79db4feff8520803b22</open-checksum>
|
||||||
|
<location href="repodata/c0562df3ad4d3d47bb8076482351eca478a02f4bd15e21b4683456268920154a-comps-AppStream.aarch64.xml.xz"/>
|
||||||
|
<timestamp>1674782842</timestamp>
|
||||||
|
<size>73836</size>
|
||||||
|
<open-size>428231</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="modules">
|
||||||
|
<checksum type="sha256">d53d510b653b6356691a5e9cf5adf2f803c525f0c9f908adf9ccbb6c88a13967</checksum>
|
||||||
|
<open-checksum type="sha256">479622387203132ad97518c6ccdf2a41996f2fddc8a5c9bdf09fcb7407064c09</open-checksum>
|
||||||
|
<location href="repodata/d53d510b653b6356691a5e9cf5adf2f803c525f0c9f908adf9ccbb6c88a13967-modules.yaml.xz"/>
|
||||||
|
<timestamp>1674783016</timestamp>
|
||||||
|
<size>73124</size>
|
||||||
|
<open-size>712620</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="updateinfo">
|
||||||
|
<checksum type="sha256">be8915c2f7ed08fca20532364bd01b12ab51e826d45233f92832f318d1b78c3e</checksum>
|
||||||
|
<open-checksum type="sha256">eec1c28a088aea1719b3ef2edacba8cdc78658fcf65009d2520f76e43ba90566</open-checksum>
|
||||||
|
<location href="repodata/be8915c2f7ed08fca20532364bd01b12ab51e826d45233f92832f318d1b78c3e-updateinfo.xml.gz"/>
|
||||||
|
<timestamp>1674284973</timestamp>
|
||||||
|
<size>233607</size>
|
||||||
|
<open-size>2402781</open-size>
|
||||||
|
</data>
|
||||||
|
</repomd>
|
@ -0,0 +1,88 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
|
||||||
|
<revision>8.7</revision>
|
||||||
|
<tags>
|
||||||
|
<distro cpeid="cpe:/o:rocky:rocky:8">Rocky Linux 8</distro>
|
||||||
|
</tags>
|
||||||
|
<data type="primary">
|
||||||
|
<checksum type="sha256">593ce13bf52aadd58d9da7c2b3fc2149bffd7bc4924c7032946b51cc340fc976</checksum>
|
||||||
|
<open-checksum type="sha256">c808007edc3392c44ac219825b4c73f4ba717721f4df2dc9aba023413d3dfab0</open-checksum>
|
||||||
|
<location href="repodata/593ce13bf52aadd58d9da7c2b3fc2149bffd7bc4924c7032946b51cc340fc976-primary.xml.gz"/>
|
||||||
|
<timestamp>1674781924</timestamp>
|
||||||
|
<size>1962142</size>
|
||||||
|
<open-size>20488457</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="filelists">
|
||||||
|
<checksum type="sha256">bce97b0287c0f9f9d900b5c9681cfe73f69890c26aae9792fffe25429fc2186b</checksum>
|
||||||
|
<open-checksum type="sha256">4e7729a83d7917070277bc630cc8cea6a620fab59d584a12dc7252d33e8c5632</open-checksum>
|
||||||
|
<location href="repodata/bce97b0287c0f9f9d900b5c9681cfe73f69890c26aae9792fffe25429fc2186b-filelists.xml.gz"/>
|
||||||
|
<timestamp>1674781924</timestamp>
|
||||||
|
<size>7066338</size>
|
||||||
|
<open-size>99500723</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="other">
|
||||||
|
<checksum type="sha256">902ea6dea89caac9980c8599cd53ce154a1e8bff3a1d212d70c38d823e08c028</checksum>
|
||||||
|
<open-checksum type="sha256">c5f4414a2cacff80f6c038761e440f61ed4c6bdefeba66e0062f228be408afc9</open-checksum>
|
||||||
|
<location href="repodata/902ea6dea89caac9980c8599cd53ce154a1e8bff3a1d212d70c38d823e08c028-other.xml.gz"/>
|
||||||
|
<timestamp>1674781924</timestamp>
|
||||||
|
<size>1263392</size>
|
||||||
|
<open-size>15731326</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="primary_db">
|
||||||
|
<checksum type="sha256">c1b32bc2fcef5863e3d0ab03263dbee5d645eb5b299d76a6edf23701504544a3</checksum>
|
||||||
|
<open-checksum type="sha256">ef04c60effc3269b15aa41d99713169e1fa0ea9196ce5167c6096d42e9ae8c0a</open-checksum>
|
||||||
|
<location href="repodata/c1b32bc2fcef5863e3d0ab03263dbee5d645eb5b299d76a6edf23701504544a3-primary.sqlite.xz"/>
|
||||||
|
<timestamp>1674781934</timestamp>
|
||||||
|
<size>3321344</size>
|
||||||
|
<open-size>21495808</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="filelists_db">
|
||||||
|
<checksum type="sha256">bcf3f665052787a1f84ce5de17cc05ab0aa526de282ef6dfcdd8c8a75bf2ac26</checksum>
|
||||||
|
<open-checksum type="sha256">8bd4fd292c8b4041acfc0a113f8e457b55bc2ad75755e17c70e116d71f6b6019</open-checksum>
|
||||||
|
<location href="repodata/bcf3f665052787a1f84ce5de17cc05ab0aa526de282ef6dfcdd8c8a75bf2ac26-filelists.sqlite.xz"/>
|
||||||
|
<timestamp>1674781938</timestamp>
|
||||||
|
<size>5256956</size>
|
||||||
|
<open-size>44195840</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="other_db">
|
||||||
|
<checksum type="sha256">5c1e7e3286c934c684bbe451356d9ac31968f4e786faa209f0bb3080fe02d67f</checksum>
|
||||||
|
<open-checksum type="sha256">88246653b636218807ef6f1174590614851df489be10ae8e462bd38e21c6ef2b</open-checksum>
|
||||||
|
<location href="repodata/5c1e7e3286c934c684bbe451356d9ac31968f4e786faa209f0bb3080fe02d67f-other.sqlite.xz"/>
|
||||||
|
<timestamp>1674781929</timestamp>
|
||||||
|
<size>1385640</size>
|
||||||
|
<open-size>13701120</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="group">
|
||||||
|
<checksum type="sha256">ec2fa1982439f4b0ca7dc86f882f18657457a2d42f06ac6718298c7f7528df43</checksum>
|
||||||
|
<location href="repodata/ec2fa1982439f4b0ca7dc86f882f18657457a2d42f06ac6718298c7f7528df43-comps-AppStream.x86_64.xml"/>
|
||||||
|
<timestamp>1674781761</timestamp>
|
||||||
|
<size>486316</size>
|
||||||
|
</data>
|
||||||
|
<data type="group_xz">
|
||||||
|
<checksum type="sha256">7ba43f88671d8107d6603ebff822fc071e73596a1e20779855af577b0e6e343a</checksum>
|
||||||
|
<open-checksum type="sha256">ec2fa1982439f4b0ca7dc86f882f18657457a2d42f06ac6718298c7f7528df43</open-checksum>
|
||||||
|
<location href="repodata/7ba43f88671d8107d6603ebff822fc071e73596a1e20779855af577b0e6e343a-comps-AppStream.x86_64.xml.xz"/>
|
||||||
|
<timestamp>1674781925</timestamp>
|
||||||
|
<size>81840</size>
|
||||||
|
<open-size>486316</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="modules">
|
||||||
|
<checksum type="sha256">7facfc73e398abc34445310a258754aae5ea0add698c4ea039580a43897d0d02</checksum>
|
||||||
|
<open-checksum type="sha256">da557db5bfd41e8949f8c3904f963cd81fcc444aa4fcc9e99a47ed843948140b</open-checksum>
|
||||||
|
<location href="repodata/7facfc73e398abc34445310a258754aae5ea0add698c4ea039580a43897d0d02-modules.yaml.xz"/>
|
||||||
|
<timestamp>1674782139</timestamp>
|
||||||
|
<size>76500</size>
|
||||||
|
<open-size>742747</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="updateinfo">
|
||||||
|
<checksum type="sha256">5c45121e44d7b58060fb9435733d3ac4e03f2e1965cacd5371eb1649e15d5c06</checksum>
|
||||||
|
<open-checksum type="sha256">dda8db3b243e33262f799fb4361bd21a16b1ff22ddd0224bd18070496942cf3d</open-checksum>
|
||||||
|
<location href="repodata/5c45121e44d7b58060fb9435733d3ac4e03f2e1965cacd5371eb1649e15d5c06-updateinfo.xml.gz"/>
|
||||||
|
<timestamp>1674284975</timestamp>
|
||||||
|
<size>276699</size>
|
||||||
|
<open-size>2720880</open-size>
|
||||||
|
</data>
|
||||||
|
</repomd>
|
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
|
||||||
|
<revision>8.7</revision>
|
||||||
|
<tags>
|
||||||
|
<distro cpeid="cpe:/o:rocky:rocky:8">Rocky Linux 8</distro>
|
||||||
|
</tags>
|
||||||
|
<data type="primary">
|
||||||
|
<checksum type="sha256">9f55c0c1cf7cb1fe08bc208f0286d64f274339df4ba857ba978e544a9924fa92</checksum>
|
||||||
|
<open-checksum type="sha256">8a5e972376710cb07fc5eb1f559d0c4456b1b58a36d219474eae66b4d10f7040</open-checksum>
|
||||||
|
<location href="repodata/9f55c0c1cf7cb1fe08bc208f0286d64f274339df4ba857ba978e544a9924fa92-primary.xml.gz"/>
|
||||||
|
<timestamp>1674782716</timestamp>
|
||||||
|
<size>1346598</size>
|
||||||
|
<open-size>9900543</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="filelists">
|
||||||
|
<checksum type="sha256">0457005390605cd3154a88584c7ef6a0e5e37a15c8035dfcde72f9d832ab14e2</checksum>
|
||||||
|
<open-checksum type="sha256">ae8651d8f568994088e3fc576538c6f4638ec29475d6d4c4739fd492028fc0fb</open-checksum>
|
||||||
|
<location href="repodata/0457005390605cd3154a88584c7ef6a0e5e37a15c8035dfcde72f9d832ab14e2-filelists.xml.gz"/>
|
||||||
|
<timestamp>1674782716</timestamp>
|
||||||
|
<size>1523844</size>
|
||||||
|
<open-size>19386269</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="other">
|
||||||
|
<checksum type="sha256">30399987025d0024ccf2d1ee6e1b412361d547cc50813777e42730375a3925dd</checksum>
|
||||||
|
<open-checksum type="sha256">8ea81e1b6d4333cc8553fc4ddd95dc3119e763e7a0c81ea753531fb8f4d7d56a</open-checksum>
|
||||||
|
<location href="repodata/30399987025d0024ccf2d1ee6e1b412361d547cc50813777e42730375a3925dd-other.xml.gz"/>
|
||||||
|
<timestamp>1674782716</timestamp>
|
||||||
|
<size>829148</size>
|
||||||
|
<open-size>5197359</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="primary_db">
|
||||||
|
<checksum type="sha256">5e78af661835050ef33470ed4c00b81ed2e9f8a76629fc7b8f04153ae273eaca</checksum>
|
||||||
|
<open-checksum type="sha256">ced2ee6fd2db2e01b5ba521a2a7815c6ab84c1b1cc95dd41acf55faf90f819c6</open-checksum>
|
||||||
|
<location href="repodata/5e78af661835050ef33470ed4c00b81ed2e9f8a76629fc7b8f04153ae273eaca-primary.sqlite.xz"/>
|
||||||
|
<timestamp>1674782721</timestamp>
|
||||||
|
<size>1663124</size>
|
||||||
|
<open-size>10960896</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="filelists_db">
|
||||||
|
<checksum type="sha256">513e605dd419c53c13f1aa3688ca53338e149dbe6de19b9c8453102bcb9ce882</checksum>
|
||||||
|
<open-checksum type="sha256">3639a0d1ea827449d47564f4330fe8426d37c1cf96308ed13d40fb3460036104</open-checksum>
|
||||||
|
<location href="repodata/513e605dd419c53c13f1aa3688ca53338e149dbe6de19b9c8453102bcb9ce882-filelists.sqlite.xz"/>
|
||||||
|
<timestamp>1674782720</timestamp>
|
||||||
|
<size>1412020</size>
|
||||||
|
<open-size>10305536</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="other_db">
|
||||||
|
<checksum type="sha256">33bddcd2c405ef925318e88662acd38f3a7246e78ebaf88639fe7c43c215095e</checksum>
|
||||||
|
<open-checksum type="sha256">b8d0ffdf150621ecc96e0aa587a895f765e0401937b50ff98e5f2312e3965774</open-checksum>
|
||||||
|
<location href="repodata/33bddcd2c405ef925318e88662acd38f3a7246e78ebaf88639fe7c43c215095e-other.sqlite.xz"/>
|
||||||
|
<timestamp>1674782717</timestamp>
|
||||||
|
<size>356456</size>
|
||||||
|
<open-size>5017600</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="group">
|
||||||
|
<checksum type="sha256">5f2dec3cbb871be9fb6c456740458773b183987275a1d5c93920d4800323fdf9</checksum>
|
||||||
|
<location href="repodata/5f2dec3cbb871be9fb6c456740458773b183987275a1d5c93920d4800323fdf9-comps-BaseOS.aarch64.xml"/>
|
||||||
|
<timestamp>1674782695</timestamp>
|
||||||
|
<size>289214</size>
|
||||||
|
</data>
|
||||||
|
<data type="group_xz">
|
||||||
|
<checksum type="sha256">01f25f36dcb08b5b027ce222dec48e68bcaa6b9e96de863ce60f126897f76faf</checksum>
|
||||||
|
<open-checksum type="sha256">5f2dec3cbb871be9fb6c456740458773b183987275a1d5c93920d4800323fdf9</open-checksum>
|
||||||
|
<location href="repodata/01f25f36dcb08b5b027ce222dec48e68bcaa6b9e96de863ce60f126897f76faf-comps-BaseOS.aarch64.xml.xz"/>
|
||||||
|
<timestamp>1674782716</timestamp>
|
||||||
|
<size>55624</size>
|
||||||
|
<open-size>289214</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="updateinfo">
|
||||||
|
<checksum type="sha256">cb9bb3ef856440c44a70f4f0aa9ee1b3621814c3457f922cdb02d7ed63a2701f</checksum>
|
||||||
|
<open-checksum type="sha256">596fc124c74802371ff879a1ecc3a7560704413bbfb4a5ab9299671baf12c2fb</open-checksum>
|
||||||
|
<location href="repodata/cb9bb3ef856440c44a70f4f0aa9ee1b3621814c3457f922cdb02d7ed63a2701f-updateinfo.xml.gz"/>
|
||||||
|
<timestamp>1674284975</timestamp>
|
||||||
|
<size>45141</size>
|
||||||
|
<open-size>433034</open-size>
|
||||||
|
</data>
|
||||||
|
</repomd>
|
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
|
||||||
|
<revision>8.7</revision>
|
||||||
|
<tags>
|
||||||
|
<distro cpeid="cpe:/o:rocky:rocky:8">Rocky Linux 8</distro>
|
||||||
|
</tags>
|
||||||
|
<data type="primary">
|
||||||
|
<checksum type="sha256">712e4af06a8f9f13766274c3fa83bbdf5572a1014ec77f7cd30d56d492a40db2</checksum>
|
||||||
|
<open-checksum type="sha256">c3ec31964ce06e7dc14a8184ad11d6f1edce3a718bd63e4de8ed18349d27e85e</open-checksum>
|
||||||
|
<location href="repodata/712e4af06a8f9f13766274c3fa83bbdf5572a1014ec77f7cd30d56d492a40db2-primary.xml.gz"/>
|
||||||
|
<timestamp>1674781748</timestamp>
|
||||||
|
<size>1791032</size>
|
||||||
|
<open-size>13677600</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="filelists">
|
||||||
|
<checksum type="sha256">052aea22e07e586ae9383f6da4056599417fc445431c9d0b1136f0316ef4843e</checksum>
|
||||||
|
<open-checksum type="sha256">dd5952122ed4335b799b1853f096f05b9e9ea6ea1a48e344700b7b82f468d61f</open-checksum>
|
||||||
|
<location href="repodata/052aea22e07e586ae9383f6da4056599417fc445431c9d0b1136f0316ef4843e-filelists.xml.gz"/>
|
||||||
|
<timestamp>1674781749</timestamp>
|
||||||
|
<size>1800846</size>
|
||||||
|
<open-size>22806093</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="other">
|
||||||
|
<checksum type="sha256">37421cd13a9594ff7dd3a0f2953aa19a01290e90be43db4ce279fef4394fdcd0</checksum>
|
||||||
|
<open-checksum type="sha256">3be8a12fb7bcd600b178f6b00404d1e4e9196b9f0d5faea460c58b8d07771747</open-checksum>
|
||||||
|
<location href="repodata/37421cd13a9594ff7dd3a0f2953aa19a01290e90be43db4ce279fef4394fdcd0-other.xml.gz"/>
|
||||||
|
<timestamp>1674781749</timestamp>
|
||||||
|
<size>878178</size>
|
||||||
|
<open-size>6343206</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="primary_db">
|
||||||
|
<checksum type="sha256">2b1d2886dec67d493adcf7358e44b7f7fd4886c85bab7fa9854014ad9c404d7a</checksum>
|
||||||
|
<open-checksum type="sha256">a2a2c52ce2b2ce80e936a9488c8799c8508cbfe1ff5dd03187e62f8cf659ca8b</open-checksum>
|
||||||
|
<location href="repodata/2b1d2886dec67d493adcf7358e44b7f7fd4886c85bab7fa9854014ad9c404d7a-primary.sqlite.xz"/>
|
||||||
|
<timestamp>1674781756</timestamp>
|
||||||
|
<size>2230076</size>
|
||||||
|
<open-size>15314944</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="filelists_db">
|
||||||
|
<checksum type="sha256">637abdee51be41d56603a2c031bfaf0dd4fc9da0127c826328d9a527aa3b5aa0</checksum>
|
||||||
|
<open-checksum type="sha256">979021c34ae689ddfdd32f1a37e78da16fdb827e8bb5c0f8818ccfe880906b74</open-checksum>
|
||||||
|
<location href="repodata/637abdee51be41d56603a2c031bfaf0dd4fc9da0127c826328d9a527aa3b5aa0-filelists.sqlite.xz"/>
|
||||||
|
<timestamp>1674781753</timestamp>
|
||||||
|
<size>1689576</size>
|
||||||
|
<open-size>12529664</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="other_db">
|
||||||
|
<checksum type="sha256">45ff5a2543dd16101778346f47e0d2362fe546698f137a05b7b72d638f03904f</checksum>
|
||||||
|
<open-checksum type="sha256">e045ad4b00b3d20c2cd489a89297ed7c7d0efa1b279cd012b1e53dab06efef24</open-checksum>
|
||||||
|
<location href="repodata/45ff5a2543dd16101778346f47e0d2362fe546698f137a05b7b72d638f03904f-other.sqlite.xz"/>
|
||||||
|
<timestamp>1674781750</timestamp>
|
||||||
|
<size>427448</size>
|
||||||
|
<open-size>6021120</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="group">
|
||||||
|
<checksum type="sha256">dae7e104812099a2f632ea4c5ef2769aca18ca1205abdd2c3ba6d171e319df3d</checksum>
|
||||||
|
<location href="repodata/dae7e104812099a2f632ea4c5ef2769aca18ca1205abdd2c3ba6d171e319df3d-comps-BaseOS.x86_64.xml"/>
|
||||||
|
<timestamp>1674781726</timestamp>
|
||||||
|
<size>298889</size>
|
||||||
|
</data>
|
||||||
|
<data type="group_xz">
|
||||||
|
<checksum type="sha256">741d3c80487757df624285f4a107f925abfac16115210486760a3920d8724e38</checksum>
|
||||||
|
<open-checksum type="sha256">dae7e104812099a2f632ea4c5ef2769aca18ca1205abdd2c3ba6d171e319df3d</open-checksum>
|
||||||
|
<location href="repodata/741d3c80487757df624285f4a107f925abfac16115210486760a3920d8724e38-comps-BaseOS.x86_64.xml.xz"/>
|
||||||
|
<timestamp>1674781749</timestamp>
|
||||||
|
<size>57068</size>
|
||||||
|
<open-size>298889</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="updateinfo">
|
||||||
|
<checksum type="sha256">568de83be47822b08ea890ce0f58fd263c61c9a5c5dc500789d25e7020827112</checksum>
|
||||||
|
<open-checksum type="sha256">1be116b93938f8bf96bb27115a63be34b59b36fcb4b2bfd3fc22c4eb3e3ffce5</open-checksum>
|
||||||
|
<location href="repodata/568de83be47822b08ea890ce0f58fd263c61c9a5c5dc500789d25e7020827112-updateinfo.xml.gz"/>
|
||||||
|
<timestamp>1674284973</timestamp>
|
||||||
|
<size>56390</size>
|
||||||
|
<open-size>508695</open-size>
|
||||||
|
</data>
|
||||||
|
</repomd>
|
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<repomd xmlns="http://linux.duke.edu/metadata/repo" xmlns:rpm="http://linux.duke.edu/metadata/rpm">
|
||||||
|
<revision>8.7</revision>
|
||||||
|
<tags>
|
||||||
|
<distro cpeid="cpe:/o:rocky:rocky:8">Rocky Linux 8</distro>
|
||||||
|
</tags>
|
||||||
|
<data type="primary">
|
||||||
|
<checksum type="sha256">712e4af06a8f9f13766274c3fa83bbdf5572a1014ec77f7cd30d56d492a40db2</checksum>
|
||||||
|
<open-checksum type="sha256">c3ec31964ce06e7dc14a8184ad11d6f1edce3a718bd63e4de8ed18349d27e85e</open-checksum>
|
||||||
|
<location href="repodata/712e4af06a8f9f13766274c3fa83bbdf5572a1014ec77f7cd30d56d492a40db2-primary.xml.gz"/>
|
||||||
|
<timestamp>1674781748</timestamp>
|
||||||
|
<size>1791032</size>
|
||||||
|
<open-size>13677600</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="filelists">
|
||||||
|
<checksum type="sha256">052aea22e07e586ae9383f6da4056599417fc445431c9d0b1136f0316ef4843e</checksum>
|
||||||
|
<open-checksum type="sha256">dd5952122ed4335b799b1853f096f05b9e9ea6ea1a48e344700b7b82f468d61f</open-checksum>
|
||||||
|
<location href="repodata/052aea22e07e586ae9383f6da4056599417fc445431c9d0b1136f0316ef4843e-filelists.xml.gz"/>
|
||||||
|
<timestamp>1674781749</timestamp>
|
||||||
|
<size>1800846</size>
|
||||||
|
<open-size>22806093</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="other">
|
||||||
|
<checksum type="sha256">37421cd13a9594ff7dd3a0f2953aa19a01290e90be43db4ce279fef4394fdcd0</checksum>
|
||||||
|
<open-checksum type="sha256">3be8a12fb7bcd600b178f6b00404d1e4e9196b9f0d5faea460c58b8d07771747</open-checksum>
|
||||||
|
<location href="repodata/37421cd13a9594ff7dd3a0f2953aa19a01290e90be43db4ce279fef4394fdcd0-other.xml.gz"/>
|
||||||
|
<timestamp>1674781749</timestamp>
|
||||||
|
<size>878178</size>
|
||||||
|
<open-size>6343206</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="primary_db">
|
||||||
|
<checksum type="sha256">2b1d2886dec67d493adcf7358e44b7f7fd4886c85bab7fa9854014ad9c404d7a</checksum>
|
||||||
|
<open-checksum type="sha256">a2a2c52ce2b2ce80e936a9488c8799c8508cbfe1ff5dd03187e62f8cf659ca8b</open-checksum>
|
||||||
|
<location href="repodata/2b1d2886dec67d493adcf7358e44b7f7fd4886c85bab7fa9854014ad9c404d7a-primary.sqlite.xz"/>
|
||||||
|
<timestamp>1674781756</timestamp>
|
||||||
|
<size>2230076</size>
|
||||||
|
<open-size>15314944</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="filelists_db">
|
||||||
|
<checksum type="sha256">637abdee51be41d56603a2c031bfaf0dd4fc9da0127c826328d9a527aa3b5aa0</checksum>
|
||||||
|
<open-checksum type="sha256">979021c34ae689ddfdd32f1a37e78da16fdb827e8bb5c0f8818ccfe880906b74</open-checksum>
|
||||||
|
<location href="repodata/637abdee51be41d56603a2c031bfaf0dd4fc9da0127c826328d9a527aa3b5aa0-filelists.sqlite.xz"/>
|
||||||
|
<timestamp>1674781753</timestamp>
|
||||||
|
<size>1689576</size>
|
||||||
|
<open-size>12529664</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="other_db">
|
||||||
|
<checksum type="sha256">45ff5a2543dd16101778346f47e0d2362fe546698f137a05b7b72d638f03904f</checksum>
|
||||||
|
<open-checksum type="sha256">e045ad4b00b3d20c2cd489a89297ed7c7d0efa1b279cd012b1e53dab06efef24</open-checksum>
|
||||||
|
<location href="repodata/45ff5a2543dd16101778346f47e0d2362fe546698f137a05b7b72d638f03904f-other.sqlite.xz"/>
|
||||||
|
<timestamp>1674781750</timestamp>
|
||||||
|
<size>427448</size>
|
||||||
|
<open-size>6021120</open-size>
|
||||||
|
<database_version>10</database_version>
|
||||||
|
</data>
|
||||||
|
<data type="group">
|
||||||
|
<checksum type="sha256">dae7e104812099a2f632ea4c5ef2769aca18ca1205abdd2c3ba6d171e319df3d</checksum>
|
||||||
|
<location href="repodata/dae7e104812099a2f632ea4c5ef2769aca18ca1205abdd2c3ba6d171e319df3d-comps-BaseOS.x86_64.xml"/>
|
||||||
|
<timestamp>1674781726</timestamp>
|
||||||
|
<size>298889</size>
|
||||||
|
</data>
|
||||||
|
<data type="group_xz">
|
||||||
|
<checksum type="sha256">741d3c80487757df624285f4a107f925abfac16115210486760a3920d8724e38</checksum>
|
||||||
|
<open-checksum type="sha256">dae7e104812099a2f632ea4c5ef2769aca18ca1205abdd2c3ba6d171e319df3d</open-checksum>
|
||||||
|
<location href="repodata/741d3c80487757df624285f4a107f925abfac16115210486760a3920d8724e38-comps-BaseOS.x86_64.xml.xz"/>
|
||||||
|
<timestamp>1674781749</timestamp>
|
||||||
|
<size>57068</size>
|
||||||
|
<open-size>298889</open-size>
|
||||||
|
</data>
|
||||||
|
<data type="updateinfo">
|
||||||
|
<checksum type="sha256">2242022f6b5935ee22d4ba78d65da0a37873e5a42f00de907795b809d3dadb59</checksum>
|
||||||
|
<open-checksum type="sha256">8ad9b2cab0f009a09fc6ed6f6fb946ce734e1d90d0d2ff6faf878788393ba4d8</open-checksum>
|
||||||
|
<location href="repodata/2242022f6b5935ee22d4ba78d65da0a37873e5a42f00de907795b809d3dadb59-updateinfo.xml.gz"/>
|
||||||
|
<timestamp>1674284973</timestamp>
|
||||||
|
<size>1706</size>
|
||||||
|
<open-size>8335</open-size>
|
||||||
|
</data>
|
||||||
|
</repomd>
|
111
apollo/tests/publishing_tools/data/updateinfo__test__1.xml
Normal file
111
apollo/tests/publishing_tools/data/updateinfo__test__1.xml
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<updates>
|
||||||
|
<update from="releng@rockylinux.org" status="final" type="security" version="2">
|
||||||
|
<id>RLSA-2022:1821</id>
|
||||||
|
<title>Moderate: python27:2.7 security update</title>
|
||||||
|
<description>Python is an interpreted, interactive, object-oriented programming language that supports modules, classes, exceptions, high-level dynamic data types, and dynamic typing. The python27 packages provide a stable release of Python 2.7 with a number of additional utilities and database connectors for MySQL and PostgreSQL.
|
||||||
|
|
||||||
|
Security Fix(es):
|
||||||
|
|
||||||
|
* python: urllib: Regular expression DoS in AbstractBasicAuthHandler (CVE-2021-3733)
|
||||||
|
|
||||||
|
* python: ftplib should not use the host from the PASV response (CVE-2021-4189)
|
||||||
|
|
||||||
|
* python-lxml: HTML Cleaner allows crafted and SVG embedded scripts to pass through (CVE-2021-43818)
|
||||||
|
|
||||||
|
* python: urllib.parse does not sanitize URLs containing ASCII newline and tabs (CVE-2022-0391)
|
||||||
|
|
||||||
|
* python: urllib: HTTP client possible infinite loop on a 100 Continue response (CVE-2021-3737)
|
||||||
|
|
||||||
|
For more details about the security issue(s), including the impact, a CVSS score, acknowledgments, and other related information, refer to the CVE page(s) listed in the References section.
|
||||||
|
|
||||||
|
Additional Changes:
|
||||||
|
|
||||||
|
For detailed information on changes in this release, see the Rocky Linux 8.6 Release Notes linked from the References section.</description>
|
||||||
|
<issued>2022-05-10 08:02:50</issued>
|
||||||
|
<updated>2023-02-02 13:41:28</updated>
|
||||||
|
<rights>Copyright 2023 Rocky Enterprise Software Foundation</rights>
|
||||||
|
<release>Rocky Linux 8</release>
|
||||||
|
<pushcount>1</pushcount>
|
||||||
|
<severity>Moderate</severity>
|
||||||
|
<summary>An update is available for python-pymongo, python2-rpm-macros, python-sqlalchemy, python-backports, python-docutils, pytest, python-psycopg2, python-lxml, python-PyMySQL, python-urllib3, PyYAML, python-pytest-mock, python-attrs, python-jinja2, python-docs, python-requests, python-mock, python-ipaddress, python-funcsigs, python2-six, python-py, python2, python2-pip, python-chardet, python-markupsafe, python-pluggy, python-pygments, python2-setuptools, Cython, python-virtualenv, babel, python-dns, python-wheel, python-pysocks, python-backports-ssl_match_hostname, python-coverage, python-setuptools_scm, pytz, python-nose, scipy, python-idna, numpy.
|
||||||
|
This update affects Rocky Linux 8.
|
||||||
|
A Common Vulnerability Scoring System (CVSS) base score, which gives a detailed severity rating, is available for each vulnerability from the CVE list</summary>
|
||||||
|
<description>Python is an interpreted, interactive, object-oriented programming language that supports modules, classes, exceptions, high-level dynamic data types, and dynamic typing. The python27 packages provide a stable release of Python 2.7 with a number of additional utilities and database connectors for MySQL and PostgreSQL.
|
||||||
|
|
||||||
|
Security Fix(es):
|
||||||
|
|
||||||
|
* python: urllib: Regular expression DoS in AbstractBasicAuthHandler (CVE-2021-3733)
|
||||||
|
|
||||||
|
* python: ftplib should not use the host from the PASV response (CVE-2021-4189)
|
||||||
|
|
||||||
|
* python-lxml: HTML Cleaner allows crafted and SVG embedded scripts to pass through (CVE-2021-43818)
|
||||||
|
|
||||||
|
* python: urllib.parse does not sanitize URLs containing ASCII newline and tabs (CVE-2022-0391)
|
||||||
|
|
||||||
|
* python: urllib: HTTP client possible infinite loop on a 100 Continue response (CVE-2021-3737)
|
||||||
|
|
||||||
|
For more details about the security issue(s), including the impact, a CVSS score, acknowledgments, and other related information, refer to the CVE page(s) listed in the References section.
|
||||||
|
|
||||||
|
Additional Changes:
|
||||||
|
|
||||||
|
For detailed information on changes in this release, see the Rocky Linux 8.6 Release Notes linked from the References section.</description>
|
||||||
|
<solution />
|
||||||
|
<references>
|
||||||
|
<reference href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3733" id="CVE-2021-3733" type="cve" title="CVE-2021-3733" />
|
||||||
|
<reference href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3737" id="CVE-2021-3737" type="cve" title="CVE-2021-3737" />
|
||||||
|
<reference href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-4189" id="CVE-2021-4189" type="cve" title="CVE-2021-4189" />
|
||||||
|
<reference href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-43818" id="CVE-2021-43818" type="cve" title="CVE-2021-43818" />
|
||||||
|
<reference href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0391" id="CVE-2022-0391" type="cve" title="CVE-2022-0391" />
|
||||||
|
<reference href="https://bugzilla.redhat.com/show_bug.cgi?id=1995162" id="1995162" type="bugzilla" title="" />
|
||||||
|
<reference href="https://bugzilla.redhat.com/show_bug.cgi?id=1995234" id="1995234" type="bugzilla" title="" />
|
||||||
|
<reference href="https://bugzilla.redhat.com/show_bug.cgi?id=2006792" id="2006792" type="bugzilla" title="" />
|
||||||
|
<reference href="https://bugzilla.redhat.com/show_bug.cgi?id=2032569" id="2032569" type="bugzilla" title="" />
|
||||||
|
<reference href="https://bugzilla.redhat.com/show_bug.cgi?id=2036020" id="2036020" type="bugzilla" title="" />
|
||||||
|
<reference href="https://bugzilla.redhat.com/show_bug.cgi?id=2047376" id="2047376" type="bugzilla" title="" />
|
||||||
|
<reference href="https://errata.rockylinux.org/RLSA-2022:1821" id="RLSA-2022:1821" type="self" title="RLSA-2022:1821" />
|
||||||
|
</references>
|
||||||
|
<pkglist />
|
||||||
|
</update>
|
||||||
|
<update from="releng@rockylinux.org" status="final" type="security" version="2">
|
||||||
|
<id>RLSA-2022:7593</id>
|
||||||
|
<title>Moderate: python27:2.7 security update</title>
|
||||||
|
<description>Python is an interpreted, interactive, object-oriented programming language that supports modules, classes, exceptions, high-level dynamic data types, and dynamic typing.
|
||||||
|
|
||||||
|
Security Fix(es):
|
||||||
|
|
||||||
|
* python: mailcap: findmatch() function does not sanitize the second argument (CVE-2015-20107).
|
||||||
|
|
||||||
|
For more details about the security issue(s), including the impact, a CVSS score, acknowledgments, and other related information, refer to the CVE page(s) listed in the References section.
|
||||||
|
|
||||||
|
Additional Changes:
|
||||||
|
|
||||||
|
For detailed information on changes in this release, see the Rocky Linux 8.7 Release Notes linked from the References section.</description>
|
||||||
|
<issued>2022-11-08 06:23:47</issued>
|
||||||
|
<updated>2023-02-02 13:52:34</updated>
|
||||||
|
<rights>Copyright 2023 Rocky Enterprise Software Foundation</rights>
|
||||||
|
<release>Rocky Linux 8</release>
|
||||||
|
<pushcount>1</pushcount>
|
||||||
|
<severity>Moderate</severity>
|
||||||
|
<summary>An update is available for python-pymongo, python2-rpm-macros, python-sqlalchemy, python-backports, python-docutils, pytest, python-psycopg2, python-lxml, python-PyMySQL, python-urllib3, PyYAML, python-pytest-mock, python-attrs, python-jinja2, python-docs, python-requests, python-mock, python-ipaddress, python-funcsigs, python2-six, python-py, python2, python2-pip, python-chardet, python-markupsafe, python-pluggy, python-pygments, python2-setuptools, Cython, python-virtualenv, babel, python-dns, python-wheel, python-pysocks, python-backports-ssl_match_hostname, python-coverage, python-setuptools_scm, pytz, python-nose, scipy, python-idna, numpy.
|
||||||
|
This update affects Rocky Linux 8.
|
||||||
|
A Common Vulnerability Scoring System (CVSS) base score, which gives a detailed severity rating, is available for each vulnerability from the CVE list</summary>
|
||||||
|
<description>Python is an interpreted, interactive, object-oriented programming language that supports modules, classes, exceptions, high-level dynamic data types, and dynamic typing.
|
||||||
|
|
||||||
|
Security Fix(es):
|
||||||
|
|
||||||
|
* python: mailcap: findmatch() function does not sanitize the second argument (CVE-2015-20107).
|
||||||
|
|
||||||
|
For more details about the security issue(s), including the impact, a CVSS score, acknowledgments, and other related information, refer to the CVE page(s) listed in the References section.
|
||||||
|
|
||||||
|
Additional Changes:
|
||||||
|
|
||||||
|
For detailed information on changes in this release, see the Rocky Linux 8.7 Release Notes linked from the References section.</description>
|
||||||
|
<solution />
|
||||||
|
<references>
|
||||||
|
<reference href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-20107" id="CVE-2015-20107" type="cve" title="CVE-2015-20107" />
|
||||||
|
<reference href="https://bugzilla.redhat.com/show_bug.cgi?id=2075390" id="2075390" type="bugzilla" title="" />
|
||||||
|
<reference href="https://errata.rockylinux.org/RLSA-2022:7593" id="RLSA-2022:7593" type="self" title="RLSA-2022:7593" />
|
||||||
|
</references>
|
||||||
|
<pkglist />
|
||||||
|
</update>
|
||||||
|
</updates>
|
498
apollo/tests/publishing_tools/test_apollo_tree.py
Normal file
498
apollo/tests/publishing_tools/test_apollo_tree.py
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
import pathlib
|
||||||
|
import hashlib
|
||||||
|
from os import path, environ
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from apollo.publishing_tools import apollo_tree
|
||||||
|
|
||||||
|
from common.testing import MockResponse
|
||||||
|
|
||||||
|
data = [
|
||||||
|
"baseos__base__repomd__x86_64.xml",
|
||||||
|
"baseos__base__repomd__aarch64.xml",
|
||||||
|
"appstream__base__repomd__x86_64.xml",
|
||||||
|
"appstream__base__repomd__aarch64.xml",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def _setup_test_baseos(directory: str):
|
||||||
|
file = data[0]
|
||||||
|
base_dir = path.join(
|
||||||
|
directory,
|
||||||
|
"BaseOS/x86_64/os/repodata",
|
||||||
|
)
|
||||||
|
pathlib.Path(base_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copyfile(
|
||||||
|
path.join(path.dirname(__file__), "data", file),
|
||||||
|
path.join(base_dir, "repomd.xml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run scan_path
|
||||||
|
repos = await apollo_tree.scan_path(
|
||||||
|
directory,
|
||||||
|
"$reponame/$arch/os/repodata/repomd.xml",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
return repos
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_scan_path_valid_structure():
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
# Copy test data to temp dir
|
||||||
|
for file in data:
|
||||||
|
fsplit = file.split("__")
|
||||||
|
base_dir = path.join(
|
||||||
|
directory,
|
||||||
|
fsplit[0],
|
||||||
|
fsplit[-1].removesuffix(".xml"),
|
||||||
|
"os/repodata",
|
||||||
|
)
|
||||||
|
pathlib.Path(base_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copyfile(
|
||||||
|
path.join(path.dirname(__file__), "data", file),
|
||||||
|
path.join(base_dir, "repomd.xml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run scan_path
|
||||||
|
repos = await apollo_tree.scan_path(
|
||||||
|
directory,
|
||||||
|
"$reponame/$arch/os/repodata/repomd.xml",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "baseos" in repos
|
||||||
|
assert "appstream" in repos
|
||||||
|
assert len(repos["baseos"]) == 2
|
||||||
|
assert len(repos["appstream"]) == 2
|
||||||
|
|
||||||
|
for repo in repos["baseos"]:
|
||||||
|
assert repo["name"] == "baseos"
|
||||||
|
assert repo["arch"] in ["x86_64", "aarch64"]
|
||||||
|
assert repo["found_path"] == path.join(
|
||||||
|
directory,
|
||||||
|
"baseos",
|
||||||
|
repo["arch"],
|
||||||
|
"os/repodata/repomd.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
for repo in repos["appstream"]:
|
||||||
|
assert repo["name"] == "appstream"
|
||||||
|
assert repo["arch"] in ["x86_64", "aarch64"]
|
||||||
|
assert repo["found_path"] == path.join(
|
||||||
|
directory,
|
||||||
|
"appstream",
|
||||||
|
repo["arch"],
|
||||||
|
"os/repodata/repomd.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_scan_path_multiple_formats():
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
# Copy test data to temp dir
|
||||||
|
for file in data:
|
||||||
|
fsplit = file.split("__")
|
||||||
|
base_dir = path.join(
|
||||||
|
directory,
|
||||||
|
fsplit[0],
|
||||||
|
fsplit[-1].removesuffix(".xml"),
|
||||||
|
"os/repodata",
|
||||||
|
)
|
||||||
|
pathlib.Path(base_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copyfile(
|
||||||
|
path.join(path.dirname(__file__), "data", file),
|
||||||
|
path.join(base_dir, "repomd.xml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
file = data[0]
|
||||||
|
fsplit = file.split("__")
|
||||||
|
base_dir = path.join(
|
||||||
|
directory,
|
||||||
|
fsplit[0],
|
||||||
|
"source/tree/repodata",
|
||||||
|
)
|
||||||
|
pathlib.Path(base_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copyfile(
|
||||||
|
path.join(path.dirname(__file__), "data", file),
|
||||||
|
path.join(base_dir, "repomd.xml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run scan_path
|
||||||
|
repos = await apollo_tree.scan_path(
|
||||||
|
directory,
|
||||||
|
"$reponame/$arch/os/repodata/repomd.xml",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "baseos" in repos
|
||||||
|
assert "appstream" in repos
|
||||||
|
assert len(repos["baseos"]) == 2
|
||||||
|
assert len(repos["appstream"]) == 2
|
||||||
|
|
||||||
|
for repo in repos["baseos"]:
|
||||||
|
assert repo["name"] == "baseos"
|
||||||
|
assert repo["arch"] in ["source", "x86_64", "aarch64"]
|
||||||
|
assert repo["found_path"] == path.join(
|
||||||
|
directory,
|
||||||
|
"baseos",
|
||||||
|
repo["arch"],
|
||||||
|
"os/repodata/repomd.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
for repo in repos["appstream"]:
|
||||||
|
assert repo["name"] == "appstream"
|
||||||
|
assert repo["arch"] in ["x86_64", "aarch64"]
|
||||||
|
assert repo["found_path"] == path.join(
|
||||||
|
directory,
|
||||||
|
"appstream",
|
||||||
|
repo["arch"],
|
||||||
|
"os/repodata/repomd.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run scan_path for source
|
||||||
|
repos = await apollo_tree.scan_path(
|
||||||
|
directory,
|
||||||
|
"$reponame/source/tree/repodata/repomd.xml",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "baseos" in repos
|
||||||
|
assert len(repos["baseos"]) == 1
|
||||||
|
|
||||||
|
for repo in repos["baseos"]:
|
||||||
|
assert repo["name"] == "baseos"
|
||||||
|
assert repo["arch"] == "source"
|
||||||
|
assert repo["found_path"] == path.join(
|
||||||
|
directory,
|
||||||
|
"baseos",
|
||||||
|
"source",
|
||||||
|
"tree/repodata/repomd.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_scan_path_valid_structure_arch_first():
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
# Copy test data to temp dir
|
||||||
|
for file in data:
|
||||||
|
fsplit = file.split("__")
|
||||||
|
base_dir = path.join(
|
||||||
|
directory,
|
||||||
|
fsplit[-1].removesuffix(".xml"),
|
||||||
|
fsplit[0],
|
||||||
|
"os/repodata",
|
||||||
|
)
|
||||||
|
pathlib.Path(base_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copyfile(
|
||||||
|
path.join(path.dirname(__file__), "data", file),
|
||||||
|
path.join(base_dir, "repomd.xml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run scan_path
|
||||||
|
repos = await apollo_tree.scan_path(
|
||||||
|
directory,
|
||||||
|
"$arch/$reponame/os/repodata/repomd.xml",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "baseos" in repos
|
||||||
|
assert "appstream" in repos
|
||||||
|
assert len(repos["baseos"]) == 2
|
||||||
|
assert len(repos["appstream"]) == 2
|
||||||
|
|
||||||
|
for repo in repos["baseos"]:
|
||||||
|
assert repo["name"] == "baseos"
|
||||||
|
assert repo["arch"] in ["x86_64", "aarch64"]
|
||||||
|
assert repo["found_path"] == path.join(
|
||||||
|
directory,
|
||||||
|
repo["arch"],
|
||||||
|
"baseos",
|
||||||
|
"os/repodata/repomd.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
for repo in repos["appstream"]:
|
||||||
|
assert repo["name"] == "appstream"
|
||||||
|
assert repo["arch"] in ["x86_64", "aarch64"]
|
||||||
|
assert repo["found_path"] == path.join(
|
||||||
|
directory,
|
||||||
|
repo["arch"],
|
||||||
|
"appstream",
|
||||||
|
"os/repodata/repomd.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_fetch_updateinfo_from_apollo_live():
|
||||||
|
# This test is only run if the environment variable
|
||||||
|
# TEST_WITH_SIDE_EFFECTS is set to 1
|
||||||
|
if not environ.get("TEST_WITH_SIDE_EFFECTS"):
|
||||||
|
pytest.skip("Skipping test_fetch_updateinfo_from_apollo_live")
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
file = data[0]
|
||||||
|
base_dir = path.join(
|
||||||
|
directory,
|
||||||
|
"BaseOS/x86_64/os/repodata",
|
||||||
|
)
|
||||||
|
pathlib.Path(base_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copyfile(
|
||||||
|
path.join(path.dirname(__file__), "data", file),
|
||||||
|
path.join(base_dir, "repomd.xml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run scan_path
|
||||||
|
repos = await apollo_tree.scan_path(
|
||||||
|
directory,
|
||||||
|
"$reponame/$arch/os/repodata/repomd.xml",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "BaseOS" in repos
|
||||||
|
assert len(repos["BaseOS"]) == 1
|
||||||
|
|
||||||
|
# Run fetch_updateinfo_from_apollo
|
||||||
|
for _, repo_variants in repos.items():
|
||||||
|
for repo in repo_variants:
|
||||||
|
updateinfo = await apollo_tree.fetch_updateinfo_from_apollo(
|
||||||
|
repo,
|
||||||
|
"Rocky Linux 8 x86_64",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo is not None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_fetch_updateinfo_from_apollo_live_no_updateinfo():
|
||||||
|
# This test is only run if the environment variable
|
||||||
|
# TEST_WITH_SIDE_EFFECTS is set to 1
|
||||||
|
if not environ.get("TEST_WITH_SIDE_EFFECTS"):
|
||||||
|
pytest.skip(
|
||||||
|
"Skipping test_fetch_updateinfo_from_apollo_live_no_updateinfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
file = data[0]
|
||||||
|
base_dir = path.join(
|
||||||
|
directory,
|
||||||
|
"BaseOS/x86_64/os/repodata",
|
||||||
|
)
|
||||||
|
pathlib.Path(base_dir).mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copyfile(
|
||||||
|
path.join(path.dirname(__file__), "data", file),
|
||||||
|
path.join(base_dir, "repomd.xml"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Run scan_path
|
||||||
|
repos = await apollo_tree.scan_path(
|
||||||
|
directory,
|
||||||
|
"$reponame/$arch/os/repodata/repomd.xml",
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "BaseOS" in repos
|
||||||
|
assert len(repos["BaseOS"]) == 1
|
||||||
|
|
||||||
|
# Run fetch_updateinfo_from_apollo
|
||||||
|
for _, repo_variants in repos.items():
|
||||||
|
for repo in repo_variants:
|
||||||
|
updateinfo = await apollo_tree.fetch_updateinfo_from_apollo(
|
||||||
|
repo,
|
||||||
|
"Rocky Linux 8 x86_64 NONEXISTENT",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_fetch_updateinfo_from_apollo_mock(mocker):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
repos = await _setup_test_baseos(directory)
|
||||||
|
|
||||||
|
# Read data/updateinfo__test__1.xml
|
||||||
|
with open(
|
||||||
|
path.join(
|
||||||
|
path.dirname(__file__), "data", "updateinfo__test__1.xml"
|
||||||
|
),
|
||||||
|
"r",
|
||||||
|
encoding="utf-8",
|
||||||
|
) as f:
|
||||||
|
updateinfo_xml = f.read()
|
||||||
|
|
||||||
|
resp = MockResponse(updateinfo_xml, 200)
|
||||||
|
mocker.patch("aiohttp.ClientSession.get", return_value=resp)
|
||||||
|
|
||||||
|
# Run fetch_updateinfo_from_apollo
|
||||||
|
for _, repo_variants in repos.items():
|
||||||
|
for repo in repo_variants:
|
||||||
|
updateinfo = await apollo_tree.fetch_updateinfo_from_apollo(
|
||||||
|
repo,
|
||||||
|
"Rocky Linux 8 x86_64",
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo == updateinfo_xml
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_gzip_updateinfo(mocker):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
repos = await _setup_test_baseos(directory)
|
||||||
|
|
||||||
|
# Read data/updateinfo__test__1.xml
|
||||||
|
with open(
|
||||||
|
path.join(
|
||||||
|
path.dirname(__file__), "data", "updateinfo__test__1.xml"
|
||||||
|
),
|
||||||
|
"r",
|
||||||
|
encoding="utf-8",
|
||||||
|
) as f:
|
||||||
|
updateinfo_xml = f.read()
|
||||||
|
|
||||||
|
resp = MockResponse(updateinfo_xml, 200)
|
||||||
|
mocker.patch("aiohttp.ClientSession.get", return_value=resp)
|
||||||
|
|
||||||
|
# Run fetch_updateinfo_from_apollo
|
||||||
|
updateinfo = None
|
||||||
|
for _, repo_variants in repos.items():
|
||||||
|
for repo in repo_variants:
|
||||||
|
updateinfo = await apollo_tree.fetch_updateinfo_from_apollo(
|
||||||
|
repo,
|
||||||
|
"Rocky Linux 8 x86_64",
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo == updateinfo_xml
|
||||||
|
break
|
||||||
|
|
||||||
|
# Run gzip_updateinfo
|
||||||
|
updateinfo_gz = await apollo_tree.gzip_updateinfo(updateinfo)
|
||||||
|
assert updateinfo_gz is not None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_write_updateinfo_to_file(mocker):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
repos = await _setup_test_baseos(directory)
|
||||||
|
|
||||||
|
# Read data/updateinfo__test__1.xml
|
||||||
|
with open(
|
||||||
|
path.join(
|
||||||
|
path.dirname(__file__), "data", "updateinfo__test__1.xml"
|
||||||
|
),
|
||||||
|
"r",
|
||||||
|
encoding="utf-8",
|
||||||
|
) as f:
|
||||||
|
updateinfo_xml = f.read()
|
||||||
|
|
||||||
|
resp = MockResponse(updateinfo_xml, 200)
|
||||||
|
mocker.patch("aiohttp.ClientSession.get", return_value=resp)
|
||||||
|
|
||||||
|
# Run fetch_updateinfo_from_apollo
|
||||||
|
updateinfo = None
|
||||||
|
for _, repo_variants in repos.items():
|
||||||
|
for repo in repo_variants:
|
||||||
|
updateinfo = await apollo_tree.fetch_updateinfo_from_apollo(
|
||||||
|
repo,
|
||||||
|
"Rocky Linux 8 x86_64",
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo == updateinfo_xml
|
||||||
|
break
|
||||||
|
|
||||||
|
# Gzip first
|
||||||
|
gzipped = await apollo_tree.gzip_updateinfo(updateinfo)
|
||||||
|
|
||||||
|
# Run write_updateinfo_to_file
|
||||||
|
updateinfo_file = await apollo_tree.write_updateinfo_to_file(
|
||||||
|
repos["BaseOS"][0]["found_path"],
|
||||||
|
gzipped,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo_file is not None
|
||||||
|
assert path.exists(updateinfo_file)
|
||||||
|
assert path.isfile(updateinfo_file)
|
||||||
|
|
||||||
|
with open(updateinfo_file, "rb") as f:
|
||||||
|
updateinfo_file_contents = f.read()
|
||||||
|
|
||||||
|
# Check sha256sum against written file
|
||||||
|
actual_hexdigest = hashlib.sha256(updateinfo_file_contents).hexdigest()
|
||||||
|
expected_hexdigest = gzipped["gzipped_sha256sum"]
|
||||||
|
assert actual_hexdigest == expected_hexdigest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_update_repomd_xml(mocker):
|
||||||
|
with tempfile.TemporaryDirectory() as directory:
|
||||||
|
repos = await _setup_test_baseos(directory)
|
||||||
|
|
||||||
|
# Read data/updateinfo__test__1.xml
|
||||||
|
with open(
|
||||||
|
path.join(
|
||||||
|
path.dirname(__file__), "data", "updateinfo__test__1.xml"
|
||||||
|
),
|
||||||
|
"r",
|
||||||
|
encoding="utf-8",
|
||||||
|
) as f:
|
||||||
|
updateinfo_xml = f.read()
|
||||||
|
|
||||||
|
resp = MockResponse(updateinfo_xml, 200)
|
||||||
|
mocker.patch("aiohttp.ClientSession.get", return_value=resp)
|
||||||
|
|
||||||
|
# Run fetch_updateinfo_from_apollo
|
||||||
|
updateinfo = None
|
||||||
|
for _, repo_variants in repos.items():
|
||||||
|
for repo in repo_variants:
|
||||||
|
updateinfo = await apollo_tree.fetch_updateinfo_from_apollo(
|
||||||
|
repo,
|
||||||
|
"Rocky Linux 8 x86_64",
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo == updateinfo_xml
|
||||||
|
break
|
||||||
|
|
||||||
|
# Gzip first
|
||||||
|
gzipped = await apollo_tree.gzip_updateinfo(updateinfo)
|
||||||
|
|
||||||
|
# Run write_updateinfo_to_file
|
||||||
|
updateinfo_file = await apollo_tree.write_updateinfo_to_file(
|
||||||
|
repos["BaseOS"][0]["found_path"],
|
||||||
|
gzipped,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert updateinfo_file is not None
|
||||||
|
assert path.exists(updateinfo_file)
|
||||||
|
assert path.isfile(updateinfo_file)
|
||||||
|
|
||||||
|
# Run update_repomd_xml
|
||||||
|
# This will replace the repomd.xml file with the new one
|
||||||
|
mocker.patch("time.time", return_value=1674284973)
|
||||||
|
repomd_xml_path = repos["BaseOS"][0]["found_path"]
|
||||||
|
await apollo_tree.update_repomd_xml(
|
||||||
|
repomd_xml_path,
|
||||||
|
gzipped,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that the repomd.xml file matches baseos__base__repomd__x86_64_with_updateinfo.xml from data
|
||||||
|
with open(
|
||||||
|
path.join(
|
||||||
|
path.dirname(__file__),
|
||||||
|
"data",
|
||||||
|
"baseos__base__repomd__x86_64_with_updateinfo.xml",
|
||||||
|
),
|
||||||
|
"r",
|
||||||
|
encoding="utf-8",
|
||||||
|
) as f:
|
||||||
|
expected_repomd_xml = f.read()
|
||||||
|
|
||||||
|
with open(repomd_xml_path, "r", encoding="utf-8") as f:
|
||||||
|
actual_repomd_xml = f.read()
|
||||||
|
|
||||||
|
assert actual_repomd_xml == expected_repomd_xml
|
15
build/scripts/pylint.bash
Executable file
15
build/scripts/pylint.bash
Executable file
@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
shopt -s globstar
|
||||||
|
|
||||||
|
python3 -m pylint --rcfile=.pylintrc --ignore-patterns "re.compile(r'bazel-.*|node-modules|.venv')" **/*.py -v | tee /tmp/pytest.txt
|
||||||
|
score=$(sed -n 's/^Your code has been rated at \([-0-9.]*\)\/.*/\1/p' /tmp/pytest.txt)
|
||||||
|
|
||||||
|
echo "===================="
|
||||||
|
if (( $(echo "$score < 9.0" | bc -l) )); then
|
||||||
|
echo "Pylint score is too low: $score"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Pylint score is good: $score"
|
||||||
|
fi
|
||||||
|
echo "===================="
|
5
build/scripts/test.bash
Executable file
5
build/scripts/test.bash
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
shopt -s globstar
|
||||||
|
|
||||||
|
python3 -m pytest --ignore node_modules --ignore .venv --ignore-glob "bazel-*" -v
|
13
common/testing.py
Normal file
13
common/testing.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
class MockResponse:
|
||||||
|
def __init__(self, text, status):
|
||||||
|
self._text = text
|
||||||
|
self.status = status
|
||||||
|
|
||||||
|
async def text(self):
|
||||||
|
return self._text
|
||||||
|
|
||||||
|
async def __aexit__(self, exc_type, exc, tb):
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def __aenter__(self):
|
||||||
|
return self
|
@ -8,7 +8,7 @@ image:
|
|||||||
repository: ghcr.io/resf/apollo-rpmworker
|
repository: ghcr.io/resf/apollo-rpmworker
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
# Overrides the image tag whose default is the chart appVersion.
|
# Overrides the image tag whose default is the chart appVersion.
|
||||||
tag: "0c2e297"
|
tag: "15c4ca5"
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
|
@ -8,7 +8,7 @@ image:
|
|||||||
repository: ghcr.io/resf/apollo-server
|
repository: ghcr.io/resf/apollo-server
|
||||||
pullPolicy: IfNotPresent
|
pullPolicy: IfNotPresent
|
||||||
# Overrides the image tag whose default is the chart appVersion.
|
# Overrides the image tag whose default is the chart appVersion.
|
||||||
tag: "cc92597"
|
tag: "b498d3b"
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
nameOverride: ""
|
nameOverride: ""
|
||||||
@ -44,7 +44,7 @@ istio:
|
|||||||
enabled: true
|
enabled: true
|
||||||
gateway: istio-system/base-gateway-public
|
gateway: istio-system/base-gateway-public
|
||||||
externalDnsTarget: ingress.build.resf.org
|
externalDnsTarget: ingress.build.resf.org
|
||||||
host: apollo-v3-beta.build.resf.org
|
host: apollo.build.resf.org
|
||||||
|
|
||||||
database:
|
database:
|
||||||
host: resf-peridot-dev.ctxqgglmfofx.us-east-2.rds.amazonaws.com
|
host: resf-peridot-dev.ctxqgglmfofx.us-east-2.rds.amazonaws.com
|
||||||
@ -84,9 +84,9 @@ resources: {}
|
|||||||
# memory: 128Mi
|
# memory: 128Mi
|
||||||
|
|
||||||
autoscaling:
|
autoscaling:
|
||||||
enabled: false
|
enabled: true
|
||||||
minReplicas: 1
|
minReplicas: 1
|
||||||
maxReplicas: 100
|
maxReplicas: 10
|
||||||
targetCPUUtilizationPercentage: 80
|
targetCPUUtilizationPercentage: 80
|
||||||
# targetMemoryUtilizationPercentage: 80
|
# targetMemoryUtilizationPercentage: 80
|
||||||
|
|
||||||
|
@ -362,6 +362,7 @@ manifest:
|
|||||||
dill.tests.test_source: dill
|
dill.tests.test_source: dill
|
||||||
dill.tests.test_temp: dill
|
dill.tests.test_temp: dill
|
||||||
dill.tests.test_weakref: dill
|
dill.tests.test_weakref: dill
|
||||||
|
exceptiongroup: exceptiongroup
|
||||||
fastapi: fastapi
|
fastapi: fastapi
|
||||||
fastapi.applications: fastapi
|
fastapi.applications: fastapi
|
||||||
fastapi.background: fastapi
|
fastapi.background: fastapi
|
||||||
@ -594,6 +595,8 @@ manifest:
|
|||||||
idna.intranges: idna
|
idna.intranges: idna
|
||||||
idna.package_data: idna
|
idna.package_data: idna
|
||||||
idna.uts46data: idna
|
idna.uts46data: idna
|
||||||
|
iniconfig: iniconfig
|
||||||
|
iniconfig.exceptions: iniconfig
|
||||||
iso8601: iso8601
|
iso8601: iso8601
|
||||||
iso8601.iso8601: iso8601
|
iso8601.iso8601: iso8601
|
||||||
iso8601.test_iso8601: iso8601
|
iso8601.test_iso8601: iso8601
|
||||||
@ -731,6 +734,13 @@ manifest:
|
|||||||
openapi_python_client.schema.openapi_schema_pydantic.xml: openapi_python_client
|
openapi_python_client.schema.openapi_schema_pydantic.xml: openapi_python_client
|
||||||
openapi_python_client.schema.parameter_location: openapi_python_client
|
openapi_python_client.schema.parameter_location: openapi_python_client
|
||||||
openapi_python_client.utils: openapi_python_client
|
openapi_python_client.utils: openapi_python_client
|
||||||
|
packaging: packaging
|
||||||
|
packaging.markers: packaging
|
||||||
|
packaging.requirements: packaging
|
||||||
|
packaging.specifiers: packaging
|
||||||
|
packaging.tags: packaging
|
||||||
|
packaging.utils: packaging
|
||||||
|
packaging.version: packaging
|
||||||
passlib: passlib
|
passlib: passlib
|
||||||
passlib.apache: passlib
|
passlib.apache: passlib
|
||||||
passlib.apps: passlib
|
passlib.apps: passlib
|
||||||
@ -830,8 +840,10 @@ manifest:
|
|||||||
platformdirs.unix: platformdirs
|
platformdirs.unix: platformdirs
|
||||||
platformdirs.version: platformdirs
|
platformdirs.version: platformdirs
|
||||||
platformdirs.windows: platformdirs
|
platformdirs.windows: platformdirs
|
||||||
|
pluggy: pluggy
|
||||||
priority: priority
|
priority: priority
|
||||||
priority.priority: priority
|
priority.priority: priority
|
||||||
|
py: pytest
|
||||||
pydantic: pydantic
|
pydantic: pydantic
|
||||||
pydantic.annotated_types: pydantic
|
pydantic.annotated_types: pydantic
|
||||||
pydantic.class_validators: pydantic
|
pydantic.class_validators: pydantic
|
||||||
@ -1051,6 +1063,11 @@ manifest:
|
|||||||
pypika.queries: pypika_tortoise
|
pypika.queries: pypika_tortoise
|
||||||
pypika.terms: pypika_tortoise
|
pypika.terms: pypika_tortoise
|
||||||
pypika.utils: pypika_tortoise
|
pypika.utils: pypika_tortoise
|
||||||
|
pytest: pytest
|
||||||
|
pytest_asyncio: pytest_asyncio
|
||||||
|
pytest_asyncio.plugin: pytest_asyncio
|
||||||
|
pytest_mock: pytest_mock
|
||||||
|
pytest_mock.plugin: pytest_mock
|
||||||
pytz: pytz
|
pytz: pytz
|
||||||
pytz.exceptions: pytz
|
pytz.exceptions: pytz
|
||||||
pytz.lazy: pytz
|
pytz.lazy: pytz
|
||||||
@ -1507,4 +1524,4 @@ manifest:
|
|||||||
yarl: yarl
|
yarl: yarl
|
||||||
pip_repository:
|
pip_repository:
|
||||||
name: pypi
|
name: pypi
|
||||||
integrity: 8d848d11c467949c981e296a23211f42a009566f0d2ab5fe11ceb59ade4cb74e
|
integrity: f886dabbf1a9923a165d6ef2ef657ca51f835c91992272bb8c12e9f78c128101
|
||||||
|
@ -19,3 +19,6 @@ PyYAML==6.0
|
|||||||
beautifulsoup4==4.11.2
|
beautifulsoup4==4.11.2
|
||||||
rssgen==0.9.0
|
rssgen==0.9.0
|
||||||
python-slugify==8.0.0
|
python-slugify==8.0.0
|
||||||
|
pytest==7.2.1
|
||||||
|
pytest-asyncio==0.20.3
|
||||||
|
pytest-mock==3.10.0
|
@ -159,6 +159,7 @@ attrs==22.2.0 \
|
|||||||
# via
|
# via
|
||||||
# aiohttp
|
# aiohttp
|
||||||
# openapi-python-client
|
# openapi-python-client
|
||||||
|
# pytest
|
||||||
autoflake==2.0.0 \
|
autoflake==2.0.0 \
|
||||||
--hash=sha256:7185b596e70d8970c6d4106c112ef41921e472bd26abf3613db99eca88cc8c2a \
|
--hash=sha256:7185b596e70d8970c6d4106c112ef41921e472bd26abf3613db99eca88cc8c2a \
|
||||||
--hash=sha256:d58ed4187c6b4f623a942b9a90c43ff84bf6a266f3682f407b42ca52073c9678
|
--hash=sha256:d58ed4187c6b4f623a942b9a90c43ff84bf6a266f3682f407b42ca52073c9678
|
||||||
@ -229,6 +230,10 @@ dill==0.3.6 \
|
|||||||
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
|
--hash=sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0 \
|
||||||
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
|
--hash=sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373
|
||||||
# via pylint
|
# via pylint
|
||||||
|
exceptiongroup==1.1.0 \
|
||||||
|
--hash=sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e \
|
||||||
|
--hash=sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23
|
||||||
|
# via pytest
|
||||||
fastapi==0.89.1 \
|
fastapi==0.89.1 \
|
||||||
--hash=sha256:15d9271ee52b572a015ca2ae5c72e1ce4241dd8532a534ad4f7ec70c376a580f \
|
--hash=sha256:15d9271ee52b572a015ca2ae5c72e1ce4241dd8532a534ad4f7ec70c376a580f \
|
||||||
--hash=sha256:f9773ea22290635b2f48b4275b2bf69a8fa721fda2e38228bed47139839dc877
|
--hash=sha256:f9773ea22290635b2f48b4275b2bf69a8fa721fda2e38228bed47139839dc877
|
||||||
@ -355,6 +360,10 @@ idna==3.4 \
|
|||||||
# anyio
|
# anyio
|
||||||
# rfc3986
|
# rfc3986
|
||||||
# yarl
|
# yarl
|
||||||
|
iniconfig==2.0.0 \
|
||||||
|
--hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
|
||||||
|
--hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
|
||||||
|
# via pytest
|
||||||
iso8601==1.1.0 \
|
iso8601==1.1.0 \
|
||||||
--hash=sha256:32811e7b81deee2063ea6d2e94f8819a86d1f3811e49d23623a41fa832bef03f \
|
--hash=sha256:32811e7b81deee2063ea6d2e94f8819a86d1f3811e49d23623a41fa832bef03f \
|
||||||
--hash=sha256:8400e90141bf792bce2634df533dc57e3bee19ea120a87bebcd3da89a58ad73f
|
--hash=sha256:8400e90141bf792bce2634df533dc57e3bee19ea120a87bebcd3da89a58ad73f
|
||||||
@ -555,6 +564,10 @@ openapi-python-client==0.13.1 \
|
|||||||
--hash=sha256:43bcd2e43e39dc31decba76ec09cbaeb6faad8709ce4684aec9b0228cd1bf3b5 \
|
--hash=sha256:43bcd2e43e39dc31decba76ec09cbaeb6faad8709ce4684aec9b0228cd1bf3b5 \
|
||||||
--hash=sha256:adb5d886946cae2ff654f26396bd4d3f497234d5a9dafee805ee19587acbfdce
|
--hash=sha256:adb5d886946cae2ff654f26396bd4d3f497234d5a9dafee805ee19587acbfdce
|
||||||
# via -r ./requirements.txt
|
# via -r ./requirements.txt
|
||||||
|
packaging==23.0 \
|
||||||
|
--hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \
|
||||||
|
--hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97
|
||||||
|
# via pytest
|
||||||
passlib[bcrypt]==1.7.4 \
|
passlib[bcrypt]==1.7.4 \
|
||||||
--hash=sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1 \
|
--hash=sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1 \
|
||||||
--hash=sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04
|
--hash=sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04
|
||||||
@ -569,6 +582,10 @@ platformdirs==2.6.2 \
|
|||||||
# via
|
# via
|
||||||
# black
|
# black
|
||||||
# pylint
|
# pylint
|
||||||
|
pluggy==1.0.0 \
|
||||||
|
--hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \
|
||||||
|
--hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3
|
||||||
|
# via pytest
|
||||||
priority==2.0.0 \
|
priority==2.0.0 \
|
||||||
--hash=sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa \
|
--hash=sha256:6f8eefce5f3ad59baf2c080a664037bb4725cd0a790d53d59ab4059288faf6aa \
|
||||||
--hash=sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0
|
--hash=sha256:c965d54f1b8d0d0b19479db3924c7c36cf672dbf2aec92d43fbdaf4492ba18c0
|
||||||
@ -643,6 +660,21 @@ pypika-tortoise==0.1.6 \
|
|||||||
--hash=sha256:2d68bbb7e377673743cff42aa1059f3a80228d411fbcae591e4465e173109fd8 \
|
--hash=sha256:2d68bbb7e377673743cff42aa1059f3a80228d411fbcae591e4465e173109fd8 \
|
||||||
--hash=sha256:d802868f479a708e3263724c7b5719a26ad79399b2a70cea065f4a4cadbebf36
|
--hash=sha256:d802868f479a708e3263724c7b5719a26ad79399b2a70cea065f4a4cadbebf36
|
||||||
# via tortoise-orm
|
# via tortoise-orm
|
||||||
|
pytest==7.2.1 \
|
||||||
|
--hash=sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5 \
|
||||||
|
--hash=sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42
|
||||||
|
# via
|
||||||
|
# -r ./requirements.txt
|
||||||
|
# pytest-asyncio
|
||||||
|
# pytest-mock
|
||||||
|
pytest-asyncio==0.20.3 \
|
||||||
|
--hash=sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36 \
|
||||||
|
--hash=sha256:f129998b209d04fcc65c96fc85c11e5316738358909a8399e93be553d7656442
|
||||||
|
# via -r ./requirements.txt
|
||||||
|
pytest-mock==3.10.0 \
|
||||||
|
--hash=sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b \
|
||||||
|
--hash=sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f
|
||||||
|
# via -r ./requirements.txt
|
||||||
python-dateutil==2.8.2 \
|
python-dateutil==2.8.2 \
|
||||||
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
|
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
|
||||||
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
|
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
|
||||||
@ -765,6 +797,7 @@ tomli==2.0.1 \
|
|||||||
# autoflake
|
# autoflake
|
||||||
# black
|
# black
|
||||||
# pylint
|
# pylint
|
||||||
|
# pytest
|
||||||
tomlkit==0.11.6 \
|
tomlkit==0.11.6 \
|
||||||
--hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \
|
--hash=sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b \
|
||||||
--hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73
|
--hash=sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73
|
||||||
|
Loading…
Reference in New Issue
Block a user