fix: authenticate private module bootstrap in CI
This commit is contained in:
@@ -16,15 +16,20 @@ REGISTERED_TRANSPORT = "registered"
|
||||
PUBLIC_HTTPS_TRANSPORT = "public-https"
|
||||
GITEA_SSH_PREFIX = "git@git.add-ideas.de:"
|
||||
GITEA_HTTPS_PREFIX = "https://git.add-ideas.de/"
|
||||
GITEA_REPOSITORY_PATH = re.compile(
|
||||
r"(?:GovOPlaN|add-ideas)/[a-z0-9][a-z0-9-]*[.]git"
|
||||
)
|
||||
GITEA_CHECKOUT_AUTH_KEY = "http.https://git.add-ideas.de/.extraheader"
|
||||
GITEA_REPOSITORY_PATH = re.compile(r"(?:GovOPlaN|add-ideas)/[a-z0-9][a-z0-9-]*[.]git")
|
||||
|
||||
|
||||
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Clone GovOPlaN repositories listed in repositories.json.")
|
||||
parser.add_argument("--check", action="store_true", help="Only report missing repositories.")
|
||||
parser.add_argument("--parent", type=Path, help="Override checkout parent directory.")
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Clone GovOPlaN repositories listed in repositories.json."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--check", action="store_true", help="Only report missing repositories."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--parent", type=Path, help="Override checkout parent directory."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--repo",
|
||||
action="append",
|
||||
@@ -48,6 +53,14 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
|
||||
"git.add-ideas.de SSH remotes to anonymous HTTPS."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--reuse-checkout-auth",
|
||||
action="store_true",
|
||||
help=(
|
||||
"Reuse the checkout repository's short-lived Gitea HTTP auth "
|
||||
"header for child clones without printing or persisting it."
|
||||
),
|
||||
)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
@@ -82,6 +95,45 @@ def clone_remote(remote: str, *, transport: str) -> str:
|
||||
return GITEA_HTTPS_PREFIX + repository_path
|
||||
|
||||
|
||||
def _add_checkout_auth(environment: dict[str, str], *, root: Path) -> None:
|
||||
result = subprocess.run(
|
||||
[
|
||||
"git",
|
||||
"-C",
|
||||
str(root),
|
||||
"config",
|
||||
"--local",
|
||||
"--get",
|
||||
GITEA_CHECKOUT_AUTH_KEY,
|
||||
],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
auth_header = result.stdout.strip()
|
||||
if result.returncode != 0 or not auth_header:
|
||||
raise ValueError(
|
||||
"checkout authentication is unavailable; ensure actions/checkout "
|
||||
"persists the GITEA_TOKEN credentials"
|
||||
)
|
||||
if re.fullmatch(
|
||||
r"authorization: basic [A-Za-z0-9+/=]+",
|
||||
auth_header,
|
||||
flags=re.IGNORECASE,
|
||||
) is None:
|
||||
raise ValueError("checkout authentication has an unsupported format")
|
||||
|
||||
try:
|
||||
config_count = int(environment.get("GIT_CONFIG_COUNT", "0"))
|
||||
except ValueError as exc:
|
||||
raise ValueError("GIT_CONFIG_COUNT must be an integer") from exc
|
||||
if config_count < 0:
|
||||
raise ValueError("GIT_CONFIG_COUNT cannot be negative")
|
||||
environment[f"GIT_CONFIG_KEY_{config_count}"] = GITEA_CHECKOUT_AUTH_KEY
|
||||
environment[f"GIT_CONFIG_VALUE_{config_count}"] = auth_header
|
||||
environment["GIT_CONFIG_COUNT"] = str(config_count + 1)
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(argv)
|
||||
manifest = json.loads((ROOT / "repositories.json").read_text(encoding="utf-8"))
|
||||
@@ -95,7 +147,9 @@ def main(argv: list[str] | None = None) -> int:
|
||||
excluded = set(args.exclude_repo)
|
||||
unknown = (requested | excluded) - set(names)
|
||||
if unknown:
|
||||
raise ValueError(f"unknown registered repositories: {', '.join(sorted(unknown))}")
|
||||
raise ValueError(
|
||||
f"unknown registered repositories: {', '.join(sorted(unknown))}"
|
||||
)
|
||||
overlap = requested & excluded
|
||||
if overlap:
|
||||
raise ValueError(
|
||||
@@ -119,6 +173,8 @@ def main(argv: list[str] | None = None) -> int:
|
||||
"GIT_TERMINAL_PROMPT": "0",
|
||||
}
|
||||
)
|
||||
if args.reuse_checkout_auth and missing and not args.check:
|
||||
_add_checkout_auth(environment, root=ROOT)
|
||||
for entry, repo, remote in missing:
|
||||
print(f"missing: {entry['name']} -> {repo}")
|
||||
if not args.check:
|
||||
|
||||
Reference in New Issue
Block a user