This repository has been archived on 2026-11-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
platform-ci/platform_ci/source_tools.py
forge-recoveryandClaude Sonnet 5.5 76dd2b0394
KofTwentyTwo/ci-policy: ci / fork-guard (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / go-nix-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / gradle-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-docker-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / java-maven-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / manifests-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / nix-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / node-8 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / python-9 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-10 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-11 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / rust-12 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-13 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-14 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / image-build-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / not-enrolled (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / content-validate-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / standards-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / node-matrix-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: ci / source-config-15 (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / verify (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / secrets (pull_request) Blocked by required conditions
KofTwentyTwo/ci-policy: Shared source and config CI / gate (pull_request) Waiting for needed jobs
KofTwentyTwo/ci-policy: ci / ci-result (pull_request) Waiting for needed jobs
KofTwentyTwo/ci-policy: native / fork-deny (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-0 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-1 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-2 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-macos-3 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-4 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-5 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-6 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / build-windows-7 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-8 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-9 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-10 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / dotnet-11 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-12 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-13 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-14 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-15 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-16 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-17 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-18 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / swift-19 (pull_request) Skipped
KofTwentyTwo/ci-policy: native / native-result (pull_request) Canceled after 4s
feat(ci): advance shared pipeline capabilities
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 05:29:30 +00:00

87 lines
4.6 KiB
Python

"""Validate and start the receipted native helpers of the `source-tools` build tool.
A `source-tools` command is a subcommand name (`actionlint`, `shellcheck-orb`, `make-bats`, `kustomize-render`, `blueprint-lint`, `policy`) and,
for the two that read directories, validated relative paths. The plan carries exactly that list. At run time this module requires the
vendored helpers in the platform checkout to match `source_tools/receipt.json`, then starts the helper unchanged with `bash`. The only
inputs the helpers read are variables derived here from validated data: the path list, the fixed check name and `INSTALL_TOOL`, which
points at `require-installed-tool.sh`, so no pinned tool is ever downloaded: a missing tool fails the run.
"""
import re
from collections.abc import Sequence
from pathlib import Path, PurePosixPath
from typing import Final
from platform_ci.build_tools import BUILD_TOOLS, HelperSubcommand
from platform_ci.source_helpers import SourceHelperError, verify_source_helpers
SOURCE_TOOLS_TOOL: Final = "source-tools"
RECEIPT_PATH: Final = Path(__file__).resolve().parent.parent / "source_tools" / "receipt.json"
HELPER_DIRECTORY: Final = ".platform-ci/source_tools"
"""Where the platform checkout's `source_tools/` sits relative to the repository root, which is the component directory."""
RESOLVER_SCRIPT: Final = "require-installed-tool.sh"
# The helpers' own rule (manifest-verify.sh, blueprint-lint.sh): only these characters, relative, inside the workspace.
_PATH_PATTERN: Final = re.compile(r"[A-Za-z0-9._/-]+")
def subcommand_named(name: str) -> HelperSubcommand | None:
"""Return the `source-tools` subcommand with this name, or None when it is not in the closed vocabulary."""
return next((subcommand for subcommand in BUILD_TOOLS[SOURCE_TOOLS_TOOL].helper_subcommands if subcommand.name == name), None)
def validate_helper_command(command: Sequence[str], location: str) -> str | None:
"""Return a description of what is wrong with a declared `source-tools` command, or None when it is acceptable."""
if not command:
return f"{location}: expected a subcommand name"
subcommand = subcommand_named(command[0])
known = ", ".join(entry.name for entry in BUILD_TOOLS[SOURCE_TOOLS_TOOL].helper_subcommands)
if subcommand is None:
return f"{location}: expected one subcommand of {SOURCE_TOOLS_TOOL!r} ({known}), got {command[0]!r}"
paths = list(command[1:])
if not subcommand.path_variable:
return f"{location}: {subcommand.name!r} takes no arguments, got {paths!r}" if paths else None
if not paths:
return f"{location}: {subcommand.name!r} needs at least one relative directory"
for path in paths:
problem = _path_problem(path)
if problem:
return f"{location}: {path!r} {problem}"
return None
def _path_problem(path: str) -> str:
"""Return why a path argument is unsafe, or an empty string; the same rule the helpers enforce on their own input."""
if _PATH_PATTERN.fullmatch(path) is None:
return "may only use letters, digits, '.', '_', '-' and '/'"
if path.startswith("/"):
return "must be relative to the repository root"
parts = PurePosixPath(path).parts
if ".." in parts:
return "must stay inside the repository"
if all(part == "." for part in parts):
return "must name a directory below the repository root"
return ""
def helper_invocation(command: Sequence[str], working_directory: Path) -> tuple[list[str], dict[str, str]]:
"""Verify the receipted helpers, then return the helper's argument list and the validated variables it reads.
Raises `SourceHelperError` when the helpers differ from the receipt or the command is not in the closed vocabulary.
"""
subcommand = subcommand_named(command[0]) if command else None
if subcommand is None:
raise SourceHelperError(f"{list(command)!r} is not a source-tools subcommand")
problem = validate_helper_command(command, "command")
if problem:
raise SourceHelperError(problem)
root = working_directory.resolve()
helpers = (root / HELPER_DIRECTORY).resolve()
if not helpers.is_relative_to(root) or not helpers.is_dir():
raise SourceHelperError(f"{HELPER_DIRECTORY} is not a directory inside the repository root")
verify_source_helpers(helpers, RECEIPT_PATH)
scripts = helpers / "scripts"
environment = {"INSTALL_TOOL": str(scripts / RESOLVER_SCRIPT), **dict(subcommand.fixed_environment)}
if subcommand.path_variable:
environment[subcommand.path_variable] = ",".join(command[1:])
return [BUILD_TOOLS[SOURCE_TOOLS_TOOL].executable, str(scripts / subcommand.script)], environment