Skills › Scientific Agent Skills › protocolsio-integration › validate_auth_config.py
validate_auth_config.py
128 lines · skills/protocolsio-integration/scripts/validate_auth_config.py at 5f2bc03
1#!/usr/bin/env python3
2"""Validate named protocols.io credential/configuration variables locally."""
4from __future__ import annotations
6import argparse
7import os
8from typing import Mapping, Sequence
10try:
11 from ._common import (
12 ACCESS_TOKEN_ENV,
13 DEFAULT_ORIGIN,
14 SafetyError,
15 credential_status,
16 emit_error,
17 emit_json,
18 validate_origin,
19 )
20except ImportError:
21 from _common import ( # type: ignore
22 ACCESS_TOKEN_ENV,
23 DEFAULT_ORIGIN,
24 SafetyError,
25 credential_status,
26 emit_error,
27 emit_json,
28 validate_origin,
29 )
32def build_parser() -> argparse.ArgumentParser:
33 parser = argparse.ArgumentParser(
34 description=(
35 "Validate protocols.io named environment variables without network "
36 "access, .env loading, or secret output."
37 )
38 )
39 parser.add_argument(
40 "--origin",
41 default=DEFAULT_ORIGIN,
42 help="HTTPS API origin (default: %(default)s).",
43 )
44 parser.add_argument(
45 "--tenant-origin",
46 help=("Optional organization/VPC origin such as https://tenant.protocols.io."),
47 )
48 parser.add_argument(
49 "--require",
50 choices=("none", "read"),
51 default="none",
52 help="Credential readiness level to require (default: %(default)s).",
53 )
54 return parser
57def _validate_secret_value(name: str, value: str | None) -> None:
58 if value is None:
59 return
60 if (
61 not value
62 or any(character.isspace() or ord(character) < 32 for character in value)
63 or "\x7f" in value
64 ):
65 raise SafetyError(
66 f"{name} must be non-empty and contain no whitespace or control characters"
67 )
70def validate_config(
71 *,
72 origin: str,
73 tenant_origin: str | None,
74 requirement: str,
75 environ: Mapping[str, str],
76) -> tuple[int, dict[str, object]]:
77 normalized_origin = validate_origin(origin)
78 normalized_tenant = (
79 validate_origin(tenant_origin, allow_tenant=True) if tenant_origin else None
80 )
81 _validate_secret_value(ACCESS_TOKEN_ENV, environ.get(ACCESS_TOKEN_ENV))
83 status = credential_status(environ)
85 readiness = {
86 "none": True,
87 "read": bool(status["rest_bearer_ready"]),
88 }
89 problems: list[str] = []
90 if not readiness[requirement]:
91 problems.append(f"credential requirement {requirement!r} is not satisfied")
93 report: dict[str, object] = {
94 "ok": not problems,
95 "network_accessed": False,
96 "dotenv_loaded": False,
97 "origin": normalized_origin,
98 "tenant_origin": normalized_tenant,
99 "requirement": requirement,
100 "credential_status": status,
101 "problems": problems,
102 "security": {
103 "values_emitted": False,
104 "accepted_secret_sources": [ACCESS_TOKEN_ENV],
105 "command_line_secrets_accepted": False,
106 "oauth_secrets_consumed": False,
107 },
108 }
109 return (0 if report["ok"] else 3), report
112def main(argv: Sequence[str] | None = None) -> int:
113 args = build_parser().parse_args(argv)
114 try:
115 code, report = validate_config(
116 origin=args.origin,
117 tenant_origin=args.tenant_origin,
118 requirement=args.require,
119 environ=os.environ,
120 )
121 emit_json(report)
122 return code
123 except (SafetyError, ValueError) as exc:
124 return emit_error(exc)
127if __name__ == "__main__":
128 raise SystemExit(main())