Activate Policy Nexus source credential lane
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
This commit is contained in:
parent
a6d47c51cc
commit
62423fd092
3 changed files with 207 additions and 7 deletions
|
|
@ -4,10 +4,12 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import base64
|
||||
import datetime as dt
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import secrets
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -52,6 +54,33 @@ def write_diagnostic(stage: str, error: Exception | None = None) -> None:
|
|||
DIAGNOSTIC_PATH.chmod(0o600)
|
||||
|
||||
|
||||
def classify_warden_failure(result: subprocess.CompletedProcess[bytes]) -> str:
|
||||
output = (result.stdout or b"") + b"\n" + (result.stderr or b"")
|
||||
text = output.decode("utf-8", errors="replace").lower()
|
||||
checks = (
|
||||
("routing catalog", "routing-catalog"),
|
||||
("caller auth", "caller-auth"),
|
||||
("permission denied", "owner-permission"),
|
||||
("fetch failed", "owner-fetch"),
|
||||
("policy denied", "policy-denied"),
|
||||
("founder_required", "founder-required"),
|
||||
("not valid", "invalid-invocation"),
|
||||
("requires --", "missing-argument"),
|
||||
)
|
||||
for needle, classification in checks:
|
||||
if needle in text:
|
||||
return classification
|
||||
return "unclassified"
|
||||
|
||||
|
||||
def sanitize_warden_failure(result: subprocess.CompletedProcess[bytes]) -> str:
|
||||
output = (result.stdout or b"") + b"\n" + (result.stderr or b"")
|
||||
text = output.decode("utf-8", errors="replace")
|
||||
text = re.sub(r"[A-Za-z0-9_=.:-]{20,}", "<redacted>", text)
|
||||
lines = [line.strip() for line in text.splitlines() if line.strip()]
|
||||
return " | ".join(lines[-8:])[:600] or f"nested Warden exit {result.returncode}"
|
||||
|
||||
|
||||
def api_request(
|
||||
token: str,
|
||||
method: str,
|
||||
|
|
@ -60,6 +89,8 @@ def api_request(
|
|||
payload: dict[str, object] | None = None,
|
||||
expected: tuple[int, ...] = (200,),
|
||||
read_body: bool = True,
|
||||
extra_headers: dict[str, str] | None = None,
|
||||
authorization: str | None = None,
|
||||
) -> tuple[int, object | None]:
|
||||
data = None if payload is None else json.dumps(payload).encode()
|
||||
request = urllib.request.Request(
|
||||
|
|
@ -67,9 +98,10 @@ def api_request(
|
|||
data=data,
|
||||
method=method,
|
||||
headers={
|
||||
"Authorization": f"token {token}",
|
||||
"Authorization": authorization or f"token {token}",
|
||||
"Accept": "application/json",
|
||||
**({"Content-Type": "application/json"} if data is not None else {}),
|
||||
**(extra_headers or {}),
|
||||
},
|
||||
)
|
||||
try:
|
||||
|
|
@ -267,15 +299,41 @@ def provision(admin_token: str) -> None:
|
|||
token_name = TOKEN_PREFIX + timestamp
|
||||
token_id: int | None = None
|
||||
source_token = ""
|
||||
service_password = ""
|
||||
basic_authorization = ""
|
||||
bao_written = False
|
||||
activated = False
|
||||
try:
|
||||
_, created = api_request(
|
||||
service_password = secrets.token_urlsafe(48)
|
||||
api_request(
|
||||
admin_token,
|
||||
"PATCH",
|
||||
f"/admin/users/{USER}",
|
||||
payload={
|
||||
"password": service_password,
|
||||
"must_change_password": False,
|
||||
"restricted": True,
|
||||
"admin": False,
|
||||
"allow_create_organization": False,
|
||||
"allow_git_hook": False,
|
||||
"allow_import_local": False,
|
||||
"max_repo_creation": 0,
|
||||
"prohibit_login": False,
|
||||
"active": True,
|
||||
"visibility": "private",
|
||||
},
|
||||
expected=(200,),
|
||||
)
|
||||
basic = base64.b64encode(f"{USER}:{service_password}".encode()).decode()
|
||||
basic_authorization = f"Basic {basic}"
|
||||
basic = ""
|
||||
_, created = api_request(
|
||||
"",
|
||||
"POST",
|
||||
f"/users/{USER}/tokens",
|
||||
payload={"name": token_name, "scopes": SCOPES},
|
||||
expected=(201,),
|
||||
authorization=basic_authorization,
|
||||
)
|
||||
if not isinstance(created, dict) or not isinstance(created.get("id"), int):
|
||||
raise ProvisionError("Forgejo returned an invalid access-token record")
|
||||
|
|
@ -326,10 +384,11 @@ def provision(admin_token: str) -> None:
|
|||
if not activated and token_id is not None:
|
||||
try:
|
||||
api_request(
|
||||
admin_token,
|
||||
"",
|
||||
"DELETE",
|
||||
f"/users/{USER}/tokens/{token_id}",
|
||||
expected=(204, 404),
|
||||
authorization=basic_authorization,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
|
@ -338,6 +397,8 @@ def provision(admin_token: str) -> None:
|
|||
raise
|
||||
finally:
|
||||
source_token = ""
|
||||
service_password = ""
|
||||
basic_authorization = ""
|
||||
|
||||
|
||||
def outer() -> int:
|
||||
|
|
@ -361,7 +422,10 @@ def outer() -> int:
|
|||
timeout=900,
|
||||
)
|
||||
if result.returncode != 0 and not DIAGNOSTIC_PATH.exists():
|
||||
write_diagnostic("forgejo-admin-route")
|
||||
write_diagnostic(
|
||||
f"forgejo-admin-route:{classify_warden_failure(result)}",
|
||||
ProvisionError(sanitize_warden_failure(result)),
|
||||
)
|
||||
return result.returncode
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue