blob: 26916d81d64e5076d947bd8db7cc0443beaf484a [file]
#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Fetch GPG public keys used during Docker image builds and store them in scripts/docker/keys/."""
from __future__ import annotations
import os
import subprocess
import sys
import tempfile
from common_prek_utils import AIRFLOW_ROOT_PATH
KEYS_DIR = AIRFLOW_ROOT_PATH / "scripts" / "docker" / "keys"
KEYSERVERS = [
"hkps://keyserver.ubuntu.com",
"hkps://pgp.surf.nl",
"hkps://keys.openpgp.org",
]
KEYS: dict[str, str] = {
# MariaDB APT repository signing key
"mariadb": "0xF1656F24C74CD1D8",
# PostgreSQL PGDG APT repository signing key
"postgres": "7FCC7D46ACCC4CF8",
# Microsoft APT repository signing key (MSSQL ODBC)
"microsoft": "EB3E94ADBE1229CF",
# Python 3.10 release manager (Pablo Galindo Salgado)
"python-3.10": "A035C8C19219BA821ECEA86B64E628F8D684696D",
}
def _recv_key(key_id: str, gpg_env: dict[str, str]) -> bool:
"""Try to receive a GPG key from keyservers, trying each in order."""
for keyserver in KEYSERVERS:
result = subprocess.run(
["gpg", "--batch", "--keyserver", keyserver, "--recv-keys", key_id],
env=gpg_env,
capture_output=True,
text=True,
check=False,
)
if result.returncode == 0:
return True
print(f" Warning: {keyserver} failed for {key_id}: {result.stderr.strip()}", file=sys.stderr)
return False
def fetch_and_export_keys() -> bool:
"""Fetch all keys from keyservers and export as ASCII-armored files. Returns True if any changed."""
changed = False
KEYS_DIR.mkdir(parents=True, exist_ok=True)
with tempfile.TemporaryDirectory() as gnupghome:
gpg_env = {**os.environ, "GNUPGHOME": gnupghome}
for name, key_id in KEYS.items():
if not _recv_key(key_id, gpg_env):
print(f"ERROR: All keyservers failed for {key_id} ({name})", file=sys.stderr)
return False
result = subprocess.run(
["gpg", "--export", "--armor", key_id],
env=gpg_env,
capture_output=True,
check=False,
)
if result.returncode != 0 or not result.stdout:
print(f"ERROR: Failed to export key {key_id} ({name})", file=sys.stderr)
return False
key_file = KEYS_DIR / f"{name}.asc"
new_content = result.stdout
if key_file.exists() and key_file.read_bytes() == new_content:
continue
key_file.write_bytes(new_content)
print(f"Updated {key_file.relative_to(AIRFLOW_ROOT_PATH)}")
changed = True
return changed
if __name__ == "__main__":
changed = fetch_and_export_keys()
if changed:
print("\nGPG key files updated. Please review and commit the changes.")
sys.exit(1)